tcp: annotate tp->snd_nxt lockless reads
authorEric Dumazet <edumazet@google.com>
Fri, 11 Oct 2019 03:17:42 +0000 (20:17 -0700)
committerDavid S. Miller <davem@davemloft.net>
Sun, 13 Oct 2019 17:13:08 +0000 (10:13 -0700)
There are few places where we fetch tp->snd_nxt while
this field can change from IRQ or other cpu.

We need to add READ_ONCE() annotations, and also make
sure write sides use corresponding WRITE_ONCE() to avoid
store-tearing.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/tcp.h
net/ipv4/tcp.c
net/ipv4/tcp_minisocks.c
net/ipv4/tcp_output.c

index 8e7c3f6801a935c2ef4c76e7e3790ce39adcf5cb..e1d08f69fd39f7c06c246a6f871400ad4cda6aed 100644 (file)
@@ -1917,7 +1917,8 @@ static inline u32 tcp_notsent_lowat(const struct tcp_sock *tp)
 static inline bool tcp_stream_memory_free(const struct sock *sk, int wake)
 {
        const struct tcp_sock *tp = tcp_sk(sk);
-       u32 notsent_bytes = READ_ONCE(tp->write_seq) - tp->snd_nxt;
+       u32 notsent_bytes = READ_ONCE(tp->write_seq) -
+                           READ_ONCE(tp->snd_nxt);
 
        return (notsent_bytes << wake) < tcp_notsent_lowat(tp);
 }
index 96dd65cbeb85732cb14dd30b73b97c9aca4e26c3..652568750cb17268509efc83bfa4bae0a23be83d 100644 (file)
@@ -625,7 +625,8 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
                if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV))
                        answ = 0;
                else
-                       answ = READ_ONCE(tp->write_seq) - tp->snd_nxt;
+                       answ = READ_ONCE(tp->write_seq) -
+                              READ_ONCE(tp->snd_nxt);
                break;
        default:
                return -ENOIOCTLCMD;
index 33994469032936bc1ff36bc95bf22fba7cdfa180..c802bc80c4006f82c2e9189ef1fc11b8f321e70d 100644 (file)
@@ -482,8 +482,10 @@ struct sock *tcp_create_openreq_child(const struct sock *sk,
        WRITE_ONCE(newtp->rcv_nxt, seq);
        newtp->segs_in = 1;
 
-       newtp->snd_sml = newtp->snd_una =
-       newtp->snd_nxt = newtp->snd_up = treq->snt_isn + 1;
+       seq = treq->snt_isn + 1;
+       newtp->snd_sml = newtp->snd_una = seq;
+       WRITE_ONCE(newtp->snd_nxt, seq);
+       newtp->snd_up = seq;
 
        INIT_LIST_HEAD(&newtp->tsq_node);
        INIT_LIST_HEAD(&newtp->tsorted_sent_queue);
index c17c2a78809d3daf9a5b44ffe1fa286582729273..a115a991dfb5b36c5b3dafd8c9ad94d07685f3a0 100644 (file)
@@ -67,7 +67,7 @@ static void tcp_event_new_data_sent(struct sock *sk, struct sk_buff *skb)
        struct tcp_sock *tp = tcp_sk(sk);
        unsigned int prior_packets = tp->packets_out;
 
-       tp->snd_nxt = TCP_SKB_CB(skb)->end_seq;
+       WRITE_ONCE(tp->snd_nxt, TCP_SKB_CB(skb)->end_seq);
 
        __skb_unlink(skb, &sk->sk_write_queue);
        tcp_rbtree_insert(&sk->tcp_rtx_queue, skb);
@@ -3142,7 +3142,7 @@ void tcp_send_fin(struct sock *sk)
                         * if FIN had been sent. This is because retransmit path
                         * does not change tp->snd_nxt.
                         */
-                       tp->snd_nxt++;
+                       WRITE_ONCE(tp->snd_nxt, tp->snd_nxt + 1);
                        return;
                }
        } else {
@@ -3426,7 +3426,7 @@ static void tcp_connect_init(struct sock *sk)
        tp->snd_una = tp->write_seq;
        tp->snd_sml = tp->write_seq;
        tp->snd_up = tp->write_seq;
-       tp->snd_nxt = tp->write_seq;
+       WRITE_ONCE(tp->snd_nxt, tp->write_seq);
 
        if (likely(!tp->repair))
                tp->rcv_nxt = 0;
@@ -3586,11 +3586,11 @@ int tcp_connect(struct sock *sk)
        /* We change tp->snd_nxt after the tcp_transmit_skb() call
         * in order to make this packet get counted in tcpOutSegs.
         */
-       tp->snd_nxt = tp->write_seq;
+       WRITE_ONCE(tp->snd_nxt, tp->write_seq);
        tp->pushed_seq = tp->write_seq;
        buff = tcp_send_head(sk);
        if (unlikely(buff)) {
-               tp->snd_nxt     = TCP_SKB_CB(buff)->seq;
+               WRITE_ONCE(tp->snd_nxt, TCP_SKB_CB(buff)->seq);
                tp->pushed_seq  = TCP_SKB_CB(buff)->seq;
        }
        TCP_INC_STATS(sock_net(sk), TCP_MIB_ACTIVEOPENS);