diff options
| author | Eric Dumazet <edumazet@google.com> | 2019-10-10 23:17:46 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2019-10-13 13:13:08 -0400 |
| commit | ab4e846a82d0ae00176de19f2db3c5c64f8eb5f2 (patch) | |
| tree | 7be26ef02ab2f2979be9a3cdeb36ed1bafc51354 | |
| parent | e292f05e0df73f9fcc93329663936e1ded97a988 (diff) | |
tcp: annotate sk->sk_wmem_queued lockless reads
For the sake of tcp_poll(), there are few places where we fetch
sk->sk_wmem_queued 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.
sk_wmem_queued_add() helper is added so that we can in
the future convert to ADD_ONCE() or equivalent if/when
available.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | include/net/sock.h | 15 | ||||
| -rw-r--r-- | include/trace/events/sock.h | 2 | ||||
| -rw-r--r-- | net/core/datagram.c | 2 | ||||
| -rw-r--r-- | net/core/sock.c | 2 | ||||
| -rw-r--r-- | net/ipv4/inet_diag.c | 2 | ||||
| -rw-r--r-- | net/ipv4/tcp.c | 4 | ||||
| -rw-r--r-- | net/ipv4/tcp_output.c | 14 | ||||
| -rw-r--r-- | net/sched/em_meta.c | 2 |
8 files changed, 24 insertions, 19 deletions
diff --git a/include/net/sock.h b/include/net/sock.h index 3d1e7502333e..f69b58bff7e5 100644 --- a/include/net/sock.h +++ b/include/net/sock.h | |||
| @@ -878,12 +878,17 @@ static inline bool sk_acceptq_is_full(const struct sock *sk) | |||
| 878 | */ | 878 | */ |
| 879 | static inline int sk_stream_min_wspace(const struct sock *sk) | 879 | static inline int sk_stream_min_wspace(const struct sock *sk) |
| 880 | { | 880 | { |
| 881 | return sk->sk_wmem_queued >> 1; | 881 | return READ_ONCE(sk->sk_wmem_queued) >> 1; |
| 882 | } | 882 | } |
| 883 | 883 | ||
| 884 | static inline int sk_stream_wspace(const struct sock *sk) | 884 | static inline int sk_stream_wspace(const struct sock *sk) |
| 885 | { | 885 | { |
| 886 | return READ_ONCE(sk->sk_sndbuf) - sk->sk_wmem_queued; | 886 | return READ_ONCE(sk->sk_sndbuf) - READ_ONCE(sk->sk_wmem_queued); |
| 887 | } | ||
| 888 | |||
| 889 | static inline void sk_wmem_queued_add(struct sock *sk, int val) | ||
| 890 | { | ||
| 891 | WRITE_ONCE(sk->sk_wmem_queued, sk->sk_wmem_queued + val); | ||
| 887 | } | 892 | } |
| 888 | 893 | ||
| 889 | void sk_stream_write_space(struct sock *sk); | 894 | void sk_stream_write_space(struct sock *sk); |
| @@ -1207,7 +1212,7 @@ static inline void sk_refcnt_debug_release(const struct sock *sk) | |||
| 1207 | 1212 | ||
| 1208 | static inline bool __sk_stream_memory_free(const struct sock *sk, int wake) | 1213 | static inline bool __sk_stream_memory_free(const struct sock *sk, int wake) |
| 1209 | { | 1214 | { |
| 1210 | if (sk->sk_wmem_queued >= READ_ONCE(sk->sk_sndbuf)) | 1215 | if (READ_ONCE(sk->sk_wmem_queued) >= READ_ONCE(sk->sk_sndbuf)) |
| 1211 | return false; | 1216 | return false; |
| 1212 | 1217 | ||
| 1213 | return sk->sk_prot->stream_memory_free ? | 1218 | return sk->sk_prot->stream_memory_free ? |
| @@ -1467,7 +1472,7 @@ DECLARE_STATIC_KEY_FALSE(tcp_tx_skb_cache_key); | |||
| 1467 | static inline void sk_wmem_free_skb(struct sock *sk, struct sk_buff *skb) | 1472 | static inline void sk_wmem_free_skb(struct sock *sk, struct sk_buff *skb) |
| 1468 | { | 1473 | { |
| 1469 | sock_set_flag(sk, SOCK_QUEUE_SHRUNK); | 1474 | sock_set_flag(sk, SOCK_QUEUE_SHRUNK); |
| 1470 | sk->sk_wmem_queued -= skb->truesize; | 1475 | sk_wmem_queued_add(sk, -skb->truesize); |
| 1471 | sk_mem_uncharge(sk, skb->truesize); | 1476 | sk_mem_uncharge(sk, skb->truesize); |
| 1472 | if (static_branch_unlikely(&tcp_tx_skb_cache_key) && | 1477 | if (static_branch_unlikely(&tcp_tx_skb_cache_key) && |
| 1473 | !sk->sk_tx_skb_cache && !skb_cloned(skb)) { | 1478 | !sk->sk_tx_skb_cache && !skb_cloned(skb)) { |
| @@ -2014,7 +2019,7 @@ static inline int skb_copy_to_page_nocache(struct sock *sk, struct iov_iter *fro | |||
| 2014 | skb->len += copy; | 2019 | skb->len += copy; |
| 2015 | skb->data_len += copy; | 2020 | skb->data_len += copy; |
| 2016 | skb->truesize += copy; | 2021 | skb->truesize += copy; |
| 2017 | sk->sk_wmem_queued += copy; | 2022 | sk_wmem_queued_add(sk, copy); |
| 2018 | sk_mem_charge(sk, copy); | 2023 | sk_mem_charge(sk, copy); |
| 2019 | return 0; | 2024 | return 0; |
| 2020 | } | 2025 | } |
diff --git a/include/trace/events/sock.h b/include/trace/events/sock.h index f720c32e7dfd..51fe9f6719eb 100644 --- a/include/trace/events/sock.h +++ b/include/trace/events/sock.h | |||
| @@ -115,7 +115,7 @@ TRACE_EVENT(sock_exceed_buf_limit, | |||
| 115 | __entry->rmem_alloc = atomic_read(&sk->sk_rmem_alloc); | 115 | __entry->rmem_alloc = atomic_read(&sk->sk_rmem_alloc); |
| 116 | __entry->sysctl_wmem = sk_get_wmem0(sk, prot); | 116 | __entry->sysctl_wmem = sk_get_wmem0(sk, prot); |
| 117 | __entry->wmem_alloc = refcount_read(&sk->sk_wmem_alloc); | 117 | __entry->wmem_alloc = refcount_read(&sk->sk_wmem_alloc); |
| 118 | __entry->wmem_queued = sk->sk_wmem_queued; | 118 | __entry->wmem_queued = READ_ONCE(sk->sk_wmem_queued); |
| 119 | __entry->kind = kind; | 119 | __entry->kind = kind; |
| 120 | ), | 120 | ), |
| 121 | 121 | ||
diff --git a/net/core/datagram.c b/net/core/datagram.c index 4cc8dc5db2b7..c210fc116103 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c | |||
| @@ -640,7 +640,7 @@ int __zerocopy_sg_from_iter(struct sock *sk, struct sk_buff *skb, | |||
| 640 | skb->len += copied; | 640 | skb->len += copied; |
| 641 | skb->truesize += truesize; | 641 | skb->truesize += truesize; |
| 642 | if (sk && sk->sk_type == SOCK_STREAM) { | 642 | if (sk && sk->sk_type == SOCK_STREAM) { |
| 643 | sk->sk_wmem_queued += truesize; | 643 | sk_wmem_queued_add(sk, truesize); |
| 644 | sk_mem_charge(sk, truesize); | 644 | sk_mem_charge(sk, truesize); |
| 645 | } else { | 645 | } else { |
| 646 | refcount_add(truesize, &skb->sk->sk_wmem_alloc); | 646 | refcount_add(truesize, &skb->sk->sk_wmem_alloc); |
diff --git a/net/core/sock.c b/net/core/sock.c index cd075bc86407..a515392ba84b 100644 --- a/net/core/sock.c +++ b/net/core/sock.c | |||
| @@ -3212,7 +3212,7 @@ void sk_get_meminfo(const struct sock *sk, u32 *mem) | |||
| 3212 | mem[SK_MEMINFO_WMEM_ALLOC] = sk_wmem_alloc_get(sk); | 3212 | mem[SK_MEMINFO_WMEM_ALLOC] = sk_wmem_alloc_get(sk); |
| 3213 | mem[SK_MEMINFO_SNDBUF] = READ_ONCE(sk->sk_sndbuf); | 3213 | mem[SK_MEMINFO_SNDBUF] = READ_ONCE(sk->sk_sndbuf); |
| 3214 | mem[SK_MEMINFO_FWD_ALLOC] = sk->sk_forward_alloc; | 3214 | mem[SK_MEMINFO_FWD_ALLOC] = sk->sk_forward_alloc; |
| 3215 | mem[SK_MEMINFO_WMEM_QUEUED] = sk->sk_wmem_queued; | 3215 | mem[SK_MEMINFO_WMEM_QUEUED] = READ_ONCE(sk->sk_wmem_queued); |
| 3216 | mem[SK_MEMINFO_OPTMEM] = atomic_read(&sk->sk_omem_alloc); | 3216 | mem[SK_MEMINFO_OPTMEM] = atomic_read(&sk->sk_omem_alloc); |
| 3217 | mem[SK_MEMINFO_BACKLOG] = READ_ONCE(sk->sk_backlog.len); | 3217 | mem[SK_MEMINFO_BACKLOG] = READ_ONCE(sk->sk_backlog.len); |
| 3218 | mem[SK_MEMINFO_DROPS] = atomic_read(&sk->sk_drops); | 3218 | mem[SK_MEMINFO_DROPS] = atomic_read(&sk->sk_drops); |
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index bbb005eb5218..7dc79b973e6e 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c | |||
| @@ -193,7 +193,7 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk, | |||
| 193 | if (ext & (1 << (INET_DIAG_MEMINFO - 1))) { | 193 | if (ext & (1 << (INET_DIAG_MEMINFO - 1))) { |
| 194 | struct inet_diag_meminfo minfo = { | 194 | struct inet_diag_meminfo minfo = { |
| 195 | .idiag_rmem = sk_rmem_alloc_get(sk), | 195 | .idiag_rmem = sk_rmem_alloc_get(sk), |
| 196 | .idiag_wmem = sk->sk_wmem_queued, | 196 | .idiag_wmem = READ_ONCE(sk->sk_wmem_queued), |
| 197 | .idiag_fmem = sk->sk_forward_alloc, | 197 | .idiag_fmem = sk->sk_forward_alloc, |
| 198 | .idiag_tmem = sk_wmem_alloc_get(sk), | 198 | .idiag_tmem = sk_wmem_alloc_get(sk), |
| 199 | }; | 199 | }; |
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 111853262972..b2ac4f074e2d 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
| @@ -659,7 +659,7 @@ static void skb_entail(struct sock *sk, struct sk_buff *skb) | |||
| 659 | tcb->sacked = 0; | 659 | tcb->sacked = 0; |
| 660 | __skb_header_release(skb); | 660 | __skb_header_release(skb); |
| 661 | tcp_add_write_queue_tail(sk, skb); | 661 | tcp_add_write_queue_tail(sk, skb); |
| 662 | sk->sk_wmem_queued += skb->truesize; | 662 | sk_wmem_queued_add(sk, skb->truesize); |
| 663 | sk_mem_charge(sk, skb->truesize); | 663 | sk_mem_charge(sk, skb->truesize); |
| 664 | if (tp->nonagle & TCP_NAGLE_PUSH) | 664 | if (tp->nonagle & TCP_NAGLE_PUSH) |
| 665 | tp->nonagle &= ~TCP_NAGLE_PUSH; | 665 | tp->nonagle &= ~TCP_NAGLE_PUSH; |
| @@ -1034,7 +1034,7 @@ new_segment: | |||
| 1034 | skb->len += copy; | 1034 | skb->len += copy; |
| 1035 | skb->data_len += copy; | 1035 | skb->data_len += copy; |
| 1036 | skb->truesize += copy; | 1036 | skb->truesize += copy; |
| 1037 | sk->sk_wmem_queued += copy; | 1037 | sk_wmem_queued_add(sk, copy); |
| 1038 | sk_mem_charge(sk, copy); | 1038 | sk_mem_charge(sk, copy); |
| 1039 | skb->ip_summed = CHECKSUM_PARTIAL; | 1039 | skb->ip_summed = CHECKSUM_PARTIAL; |
| 1040 | WRITE_ONCE(tp->write_seq, tp->write_seq + copy); | 1040 | WRITE_ONCE(tp->write_seq, tp->write_seq + copy); |
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index a115a991dfb5..0488607c5cd3 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
| @@ -1199,7 +1199,7 @@ static void tcp_queue_skb(struct sock *sk, struct sk_buff *skb) | |||
| 1199 | WRITE_ONCE(tp->write_seq, TCP_SKB_CB(skb)->end_seq); | 1199 | WRITE_ONCE(tp->write_seq, TCP_SKB_CB(skb)->end_seq); |
| 1200 | __skb_header_release(skb); | 1200 | __skb_header_release(skb); |
| 1201 | tcp_add_write_queue_tail(sk, skb); | 1201 | tcp_add_write_queue_tail(sk, skb); |
| 1202 | sk->sk_wmem_queued += skb->truesize; | 1202 | sk_wmem_queued_add(sk, skb->truesize); |
| 1203 | sk_mem_charge(sk, skb->truesize); | 1203 | sk_mem_charge(sk, skb->truesize); |
| 1204 | } | 1204 | } |
| 1205 | 1205 | ||
| @@ -1333,7 +1333,7 @@ int tcp_fragment(struct sock *sk, enum tcp_queue tcp_queue, | |||
| 1333 | return -ENOMEM; /* We'll just try again later. */ | 1333 | return -ENOMEM; /* We'll just try again later. */ |
| 1334 | skb_copy_decrypted(buff, skb); | 1334 | skb_copy_decrypted(buff, skb); |
| 1335 | 1335 | ||
| 1336 | sk->sk_wmem_queued += buff->truesize; | 1336 | sk_wmem_queued_add(sk, buff->truesize); |
| 1337 | sk_mem_charge(sk, buff->truesize); | 1337 | sk_mem_charge(sk, buff->truesize); |
| 1338 | nlen = skb->len - len - nsize; | 1338 | nlen = skb->len - len - nsize; |
| 1339 | buff->truesize += nlen; | 1339 | buff->truesize += nlen; |
| @@ -1443,7 +1443,7 @@ int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len) | |||
| 1443 | 1443 | ||
| 1444 | if (delta_truesize) { | 1444 | if (delta_truesize) { |
| 1445 | skb->truesize -= delta_truesize; | 1445 | skb->truesize -= delta_truesize; |
| 1446 | sk->sk_wmem_queued -= delta_truesize; | 1446 | sk_wmem_queued_add(sk, -delta_truesize); |
| 1447 | sk_mem_uncharge(sk, delta_truesize); | 1447 | sk_mem_uncharge(sk, delta_truesize); |
| 1448 | sock_set_flag(sk, SOCK_QUEUE_SHRUNK); | 1448 | sock_set_flag(sk, SOCK_QUEUE_SHRUNK); |
| 1449 | } | 1449 | } |
| @@ -1888,7 +1888,7 @@ static int tso_fragment(struct sock *sk, struct sk_buff *skb, unsigned int len, | |||
| 1888 | return -ENOMEM; | 1888 | return -ENOMEM; |
| 1889 | skb_copy_decrypted(buff, skb); | 1889 | skb_copy_decrypted(buff, skb); |
| 1890 | 1890 | ||
| 1891 | sk->sk_wmem_queued += buff->truesize; | 1891 | sk_wmem_queued_add(sk, buff->truesize); |
| 1892 | sk_mem_charge(sk, buff->truesize); | 1892 | sk_mem_charge(sk, buff->truesize); |
| 1893 | buff->truesize += nlen; | 1893 | buff->truesize += nlen; |
| 1894 | skb->truesize -= nlen; | 1894 | skb->truesize -= nlen; |
| @@ -2152,7 +2152,7 @@ static int tcp_mtu_probe(struct sock *sk) | |||
| 2152 | nskb = sk_stream_alloc_skb(sk, probe_size, GFP_ATOMIC, false); | 2152 | nskb = sk_stream_alloc_skb(sk, probe_size, GFP_ATOMIC, false); |
| 2153 | if (!nskb) | 2153 | if (!nskb) |
| 2154 | return -1; | 2154 | return -1; |
| 2155 | |||
