Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[firefly-linux-kernel-4.4.55.git] / net / ipv4 / tcp.c
index ca1d476c80ef3459701174f2bcdca7ec7e9e7042..7f4056785accb76eec60e22dc0bb19febc98f75f 100644 (file)
@@ -402,6 +402,7 @@ void tcp_init_sock(struct sock *sk)
        tp->snd_ssthresh = TCP_INFINITE_SSTHRESH;
        tp->snd_cwnd_clamp = ~0;
        tp->mss_cache = TCP_MSS_DEFAULT;
+       u64_stats_init(&tp->syncp);
 
        tp->reordering = sysctl_tcp_reordering;
        tcp_enable_early_retrans(tp);
@@ -694,8 +695,9 @@ static int tcp_splice_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb,
        struct tcp_splice_state *tss = rd_desc->arg.data;
        int ret;
 
-       ret = skb_splice_bits(skb, offset, tss->pipe, min(rd_desc->count, len),
-                             tss->flags);
+       ret = skb_splice_bits(skb, skb->sk, offset, tss->pipe,
+                             min(rd_desc->count, len), tss->flags,
+                             skb_socket_splice);
        if (ret > 0)
                rd_desc->count -= ret;
        return ret;
@@ -999,6 +1001,9 @@ do_error:
        if (copied)
                goto out;
 out_err:
+       /* make sure we wake any epoll edge trigger waiter */
+       if (unlikely(skb_queue_len(&sk->sk_write_queue) == 0 && err == -EAGAIN))
+               sk->sk_write_space(sk);
        return sk_stream_error(sk, flags, err);
 }
 
@@ -1288,6 +1293,9 @@ do_error:
                goto out;
 out_err:
        err = sk_stream_error(sk, flags, err);
+       /* make sure we wake any epoll edge trigger waiter */
+       if (unlikely(skb_queue_len(&sk->sk_write_queue) == 0 && err == -EAGAIN))
+               sk->sk_write_space(sk);
        release_sock(sk);
        return err;
 }
@@ -2565,10 +2573,13 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
 
        case TCP_FASTOPEN:
                if (val >= 0 && ((1 << sk->sk_state) & (TCPF_CLOSE |
-                   TCPF_LISTEN)))
+                   TCPF_LISTEN))) {
+                       tcp_fastopen_init_key_once(true);
+
                        err = fastopen_init_queue(sk, val);
-               else
+               } else {
                        err = -EINVAL;
+               }
                break;
        case TCP_TIMESTAMP:
                if (!tp->repair)
@@ -2616,12 +2627,15 @@ EXPORT_SYMBOL(compat_tcp_setsockopt);
 /* Return information about state of tcp endpoint in API format. */
 void tcp_get_info(struct sock *sk, struct tcp_info *info)
 {
-       const struct tcp_sock *tp = tcp_sk(sk);
+       const struct tcp_sock *tp = tcp_sk(sk); /* iff sk_type == SOCK_STREAM */
        const struct inet_connection_sock *icsk = inet_csk(sk);
        u32 now = tcp_time_stamp;
+       unsigned int start;
        u32 rate;
 
        memset(info, 0, sizeof(*info));
+       if (sk->sk_type != SOCK_STREAM)
+               return;
 
        info->tcpi_state = sk->sk_state;
        info->tcpi_ca_state = icsk->icsk_ca_state;
@@ -2686,10 +2700,13 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info)
        rate = READ_ONCE(sk->sk_max_pacing_rate);
        info->tcpi_max_pacing_rate = rate != ~0U ? rate : ~0ULL;
 
-       spin_lock_bh(&sk->sk_lock.slock);
-       info->tcpi_bytes_acked = tp->bytes_acked;
-       info->tcpi_bytes_received = tp->bytes_received;
-       spin_unlock_bh(&sk->sk_lock.slock);
+       do {
+               start = u64_stats_fetch_begin_irq(&tp->syncp);
+               info->tcpi_bytes_acked = tp->bytes_acked;
+               info->tcpi_bytes_received = tp->bytes_received;
+       } while (u64_stats_fetch_retry_irq(&tp->syncp, start));
+       info->tcpi_segs_out = tp->segs_out;
+       info->tcpi_segs_in = tp->segs_in;
 }
 EXPORT_SYMBOL_GPL(tcp_get_info);