Merge tag 'virtio-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[firefly-linux-kernel-4.4.55.git] / net / ipv4 / tcp.c
index e457c7ab2e28daf5607e93ef0c31e667f1cec216..1ca253635f7acdda23624c28ae1ead4645bd0dd5 100644 (file)
@@ -536,13 +536,14 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        int answ;
+       bool slow;
 
        switch (cmd) {
        case SIOCINQ:
                if (sk->sk_state == TCP_LISTEN)
                        return -EINVAL;
 
-               lock_sock(sk);
+               slow = lock_sock_fast(sk);
                if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV))
                        answ = 0;
                else if (sock_flag(sk, SOCK_URGINLINE) ||
@@ -557,7 +558,7 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
                                answ--;
                } else
                        answ = tp->urg_seq - tp->copied_seq;
-               release_sock(sk);
+               unlock_sock_fast(sk, slow);
                break;
        case SIOCATMARK:
                answ = tp->urg_data && tp->urg_seq == tp->copied_seq;
@@ -1490,15 +1491,19 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
                                copied += used;
                                offset += used;
                        }
-                       /*
-                        * If recv_actor drops the lock (e.g. TCP splice
+                       /* If recv_actor drops the lock (e.g. TCP splice
                         * receive) the skb pointer might be invalid when
                         * getting here: tcp_collapse might have deleted it
                         * while aggregating skbs from the socket queue.
                         */
-                       skb = tcp_recv_skb(sk, seq-1, &offset);
-                       if (!skb || (offset+1 != skb->len))
+                       skb = tcp_recv_skb(sk, seq - 1, &offset);
+                       if (!skb)
                                break;
+                       /* TCP coalescing might have appended data to the skb.
+                        * Try to splice more frags
+                        */
+                       if (offset + 1 != skb->len)
+                               continue;
                }
                if (tcp_hdr(skb)->fin) {
                        sk_eat_skb(sk, skb, false);
@@ -2300,7 +2305,7 @@ void tcp_sock_destruct(struct sock *sk)
 
 static inline bool tcp_can_repair_sock(const struct sock *sk)
 {
-       return capable(CAP_NET_ADMIN) &&
+       return ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN) &&
                ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_ESTABLISHED));
 }
 
@@ -3586,8 +3591,7 @@ void __init tcp_init(void)
                alloc_large_system_hash("TCP established",
                                        sizeof(struct inet_ehash_bucket),
                                        thash_entries,
-                                       (totalram_pages >= 128 * 1024) ?
-                                       13 : 15,
+                                       17, /* one slot per 128 KB of memory */
                                        0,
                                        NULL,
                                        &tcp_hashinfo.ehash_mask,
@@ -3603,8 +3607,7 @@ void __init tcp_init(void)
                alloc_large_system_hash("TCP bind",
                                        sizeof(struct inet_bind_hashbucket),
                                        tcp_hashinfo.ehash_mask + 1,
-                                       (totalram_pages >= 128 * 1024) ?
-                                       13 : 15,
+                                       17, /* one slot per 128 KB of memory */
                                        0,
                                        &tcp_hashinfo.bhash_size,
                                        NULL,