diff options
author | Eric Dumazet <edumazet@google.com> | 2019-10-10 23:17:42 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-10-13 13:13:08 -0400 |
commit | e0d694d638dba768b47be31c22e1a9b4f862f561 (patch) | |
tree | c35cd9fe92b9008fda870b5ae83b3971e6632a60 | |
parent | 0f31746452e6793ad6271337438af8f4defb8940 (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.h | 3 | ||||
-rw-r--r-- | net/ipv4/tcp.c | 3 | ||||
-rw-r--r-- | net/ipv4/tcp_minisocks.c | 6 | ||||
-rw-r--r-- | net/ipv4/tcp_output.c | 10 |
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) | |||
1917 | static inline bool tcp_stream_memory_free(const struct sock *sk, int wake) | 1917 | static 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); |