summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2019-10-10 23:17:42 -0400
committerDavid S. Miller <davem@davemloft.net>2019-10-13 13:13:08 -0400
commite0d694d638dba768b47be31c22e1a9b4f862f561 (patch)
treec35cd9fe92b9008fda870b5ae83b3971e6632a60
parent0f31746452e6793ad6271337438af8f4defb8940 (diff)
tcp: annotate tp->snd_nxt lockless reads
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>
-rw-r--r--include/net/tcp.h3
-rw-r--r--net/ipv4/tcp.c3
-rw-r--r--net/ipv4/tcp_minisocks.c6
-rw-r--r--net/ipv4/tcp_output.c10
4 files changed, 13 insertions, 9 deletions
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 8e7c3f6801a9..e1d08f69fd39 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1917,7 +1917,8 @@ static inline u32 tcp_notsent_lowat(const struct tcp_sock *tp)
1917static inline bool tcp_stream_memory_free(const struct sock *sk, int wake) 1917static inline bool tcp_stream_memory_free(const struct sock *sk, int wake)
1918{ 1918{
1919 const struct tcp_sock *tp = tcp_sk(sk); 1919 const struct tcp_sock *tp = tcp_sk(sk);
1920 u32 notsent_bytes = READ_ONCE(tp->write_seq) - tp->snd_nxt; 1920 u32 notsent_bytes = READ_ONCE(tp->write_seq) -
1921 READ_ONCE(tp->snd_nxt);
1921 1922
1922 return (notsent_bytes << wake) < tcp_notsent_lowat(tp); 1923 return (notsent_bytes << wake) < tcp_notsent_lowat(tp);
1923} 1924}
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 96dd65cbeb85..652568750cb1 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -625,7 +625,8 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
625 if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) 625 if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV))
626 answ = 0; 626 answ = 0;
627 else 627 else
628 answ = READ_ONCE(tp->write_seq) - tp->snd_nxt; 628 answ = READ_ONCE(tp->write_seq) -
629 READ_ONCE(tp->snd_nxt);
629 break; 630 break;
630 default: 631 default:
631 return -ENOIOCTLCMD; 632 return -ENOIOCTLCMD;
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 339944690329..c802bc80c400 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -482,8 +482,10 @@ struct sock *tcp_create_openreq_child(const struct sock *sk,
482 WRITE_ONCE(newtp->rcv_nxt, seq); 482 WRITE_ONCE(newtp->rcv_nxt, seq);
483 newtp->segs_in = 1; 483 newtp->segs_in = 1;
484 484
485 newtp->snd_sml = newtp->snd_una = 485 seq = treq->snt_isn + 1;
486 newtp->snd_nxt = newtp->snd_up = treq->snt_isn + 1; 486 newtp->snd_sml = newtp->snd_una = seq;
487 WRITE_ONCE(newtp->snd_nxt, seq);
488 newtp->snd_up = seq;
487 489
488 INIT_LIST_HEAD(&newtp->tsq_node); 490 INIT_LIST_HEAD(&newtp->tsq_node);
489 INIT_LIST_HEAD(&newtp->tsorted_sent_queue); 491 INIT_LIST_HEAD(&newtp->tsorted_sent_queue);
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index c17c2a78809d..a115a991dfb5 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -67,7 +67,7 @@ static void tcp_event_new_data_sent(struct sock *sk, struct sk_buff *skb)
67 struct tcp_sock *tp = tcp_sk(sk); 67 struct tcp_sock *tp = tcp_sk(sk);
68 unsigned int prior_packets = tp->packets_out; 68 unsigned int prior_packets = tp->packets_out;
69 69
70 tp->snd_nxt = TCP_SKB_CB(skb)->end_seq; 70 WRITE_ONCE(tp->snd_nxt, TCP_SKB_CB(skb)->end_seq);
71 71
72 __skb_unlink(skb, &sk->sk_write_queue); 72 __skb_unlink(skb, &sk->sk_write_queue);
73 tcp_rbtree_insert(&sk->tcp_rtx_queue, skb); 73 tcp_rbtree_insert(&sk->tcp_rtx_queue, skb);
@@ -3142,7 +3142,7 @@ void tcp_send_fin(struct sock *sk)
3142 * if FIN had been sent. This is because retransmit path 3142 * if FIN had been sent. This is because retransmit path
3143 * does not change tp->snd_nxt. 3143 * does not change tp->snd_nxt.
3144 */ 3144 */
3145 tp->snd_nxt++; 3145 WRITE_ONCE(tp->snd_nxt, tp->snd_nxt + 1);
3146 return; 3146 return;
3147 } 3147 }
3148 } else { 3148 } else {
@@ -3426,7 +3426,7 @@ static void tcp_connect_init(struct sock *sk)
3426 tp->snd_una = tp->write_seq; 3426 tp->snd_una = tp->write_seq;
3427 tp->snd_sml = tp->write_seq; 3427 tp->snd_sml = tp->write_seq;
3428 tp->snd_up = tp->write_seq; 3428 tp->snd_up = tp->write_seq;
3429 tp->snd_nxt = tp->write_seq; 3429 WRITE_ONCE(tp->snd_nxt, tp->write_seq);
3430 3430
3431 if (likely(!tp->repair)) 3431 if (likely(!tp->repair))
3432 tp->rcv_nxt = 0; 3432 tp->rcv_nxt = 0;
@@ -3586,11 +3586,11 @@ int tcp_connect(struct sock *sk)
3586 /* We change tp->snd_nxt after the tcp_transmit_skb() call 3586 /* We change tp->snd_nxt after the tcp_transmit_skb() call
3587 * in order to make this packet get counted in tcpOutSegs. 3587 * in order to make this packet get counted in tcpOutSegs.
3588 */ 3588 */
3589 tp->snd_nxt = tp->write_seq; 3589 WRITE_ONCE(tp->snd_nxt, tp->write_seq);
3590 tp->pushed_seq = tp->write_seq; 3590 tp->pushed_seq = tp->write_seq;
3591 buff = tcp_send_head(sk); 3591 buff = tcp_send_head(sk);
3592 if (unlikely(buff)) { 3592 if (unlikely(buff)) {
3593 tp->snd_nxt = TCP_SKB_CB(buff)->seq; 3593 WRITE_ONCE(tp->snd_nxt, TCP_SKB_CB(buff)->seq);
3594 tp->pushed_seq = TCP_SKB_CB(buff)->seq; 3594 tp->pushed_seq = TCP_SKB_CB(buff)->seq;
3595 } 3595 }
3596 TCP_INC_STATS(sock_net(sk), TCP_MIB_ACTIVEOPENS); 3596 TCP_INC_STATS(sock_net(sk), TCP_MIB_ACTIVEOPENS);