Skip to content

Commit ebb3b78

Browse files
edumazetdavem330
authored andcommitted
tcp: annotate sk->sk_rcvbuf lockless reads
For the sake of tcp_poll(), there are few places where we fetch sk->sk_rcvbuf 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. Note that other transports probably need similar fixes. Signed-off-by: Eric Dumazet <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent d9b55bf commit ebb3b78

File tree

7 files changed

+15
-12
lines changed

7 files changed

+15
-12
lines changed

include/net/tcp.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1380,14 +1380,14 @@ static inline int tcp_win_from_space(const struct sock *sk, int space)
13801380
/* Note: caller must be prepared to deal with negative returns */
13811381
static inline int tcp_space(const struct sock *sk)
13821382
{
1383-
return tcp_win_from_space(sk, sk->sk_rcvbuf -
1383+
return tcp_win_from_space(sk, READ_ONCE(sk->sk_rcvbuf) -
13841384
READ_ONCE(sk->sk_backlog.len) -
13851385
atomic_read(&sk->sk_rmem_alloc));
13861386
}
13871387

13881388
static inline int tcp_full_space(const struct sock *sk)
13891389
{
1390-
return tcp_win_from_space(sk, sk->sk_rcvbuf);
1390+
return tcp_win_from_space(sk, READ_ONCE(sk->sk_rcvbuf));
13911391
}
13921392

13931393
extern void tcp_openreq_init_rwin(struct request_sock *req,

include/trace/events/sock.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ TRACE_EVENT(sock_rcvqueue_full,
8282
TP_fast_assign(
8383
__entry->rmem_alloc = atomic_read(&sk->sk_rmem_alloc);
8484
__entry->truesize = skb->truesize;
85-
__entry->sk_rcvbuf = sk->sk_rcvbuf;
85+
__entry->sk_rcvbuf = READ_ONCE(sk->sk_rcvbuf);
8686
),
8787

8888
TP_printk("rmem_alloc=%d truesize=%u sk_rcvbuf=%d",

net/core/filter.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4252,7 +4252,8 @@ BPF_CALL_5(bpf_setsockopt, struct bpf_sock_ops_kern *, bpf_sock,
42524252
case SO_RCVBUF:
42534253
val = min_t(u32, val, sysctl_rmem_max);
42544254
sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
4255-
sk->sk_rcvbuf = max_t(int, val * 2, SOCK_MIN_RCVBUF);
4255+
WRITE_ONCE(sk->sk_rcvbuf,
4256+
max_t(int, val * 2, SOCK_MIN_RCVBUF));
42564257
break;
42574258
case SO_SNDBUF:
42584259
val = min_t(u32, val, sysctl_wmem_max);

net/core/skbuff.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4415,7 +4415,7 @@ static void skb_set_err_queue(struct sk_buff *skb)
44154415
int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb)
44164416
{
44174417
if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
4418-
(unsigned int)sk->sk_rcvbuf)
4418+
(unsigned int)READ_ONCE(sk->sk_rcvbuf))
44194419
return -ENOMEM;
44204420

44214421
skb_orphan(skb);

net/core/sock.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -831,7 +831,8 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
831831
* returning the value we actually used in getsockopt
832832
* is the most desirable behavior.
833833
*/
834-
sk->sk_rcvbuf = max_t(int, val * 2, SOCK_MIN_RCVBUF);
834+
WRITE_ONCE(sk->sk_rcvbuf,
835+
max_t(int, val * 2, SOCK_MIN_RCVBUF));
835836
break;
836837

837838
case SO_RCVBUFFORCE:
@@ -3204,7 +3205,7 @@ void sk_get_meminfo(const struct sock *sk, u32 *mem)
32043205
memset(mem, 0, sizeof(*mem) * SK_MEMINFO_VARS);
32053206

32063207
mem[SK_MEMINFO_RMEM_ALLOC] = sk_rmem_alloc_get(sk);
3207-
mem[SK_MEMINFO_RCVBUF] = sk->sk_rcvbuf;
3208+
mem[SK_MEMINFO_RCVBUF] = READ_ONCE(sk->sk_rcvbuf);
32083209
mem[SK_MEMINFO_WMEM_ALLOC] = sk_wmem_alloc_get(sk);
32093210
mem[SK_MEMINFO_SNDBUF] = sk->sk_sndbuf;
32103211
mem[SK_MEMINFO_FWD_ALLOC] = sk->sk_forward_alloc;

net/ipv4/tcp.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ void tcp_init_sock(struct sock *sk)
451451
icsk->icsk_sync_mss = tcp_sync_mss;
452452

453453
sk->sk_sndbuf = sock_net(sk)->ipv4.sysctl_tcp_wmem[1];
454-
sk->sk_rcvbuf = sock_net(sk)->ipv4.sysctl_tcp_rmem[1];
454+
WRITE_ONCE(sk->sk_rcvbuf, sock_net(sk)->ipv4.sysctl_tcp_rmem[1]);
455455

456456
sk_sockets_allocated_inc(sk);
457457
sk->sk_route_forced_caps = NETIF_F_GSO;
@@ -1711,7 +1711,7 @@ int tcp_set_rcvlowat(struct sock *sk, int val)
17111711

17121712
val <<= 1;
17131713
if (val > sk->sk_rcvbuf) {
1714-
sk->sk_rcvbuf = val;
1714+
WRITE_ONCE(sk->sk_rcvbuf, val);
17151715
tcp_sk(sk)->window_clamp = tcp_win_from_space(sk, val);
17161716
}
17171717
return 0;

net/ipv4/tcp_input.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -483,8 +483,9 @@ static void tcp_clamp_window(struct sock *sk)
483483
!(sk->sk_userlocks & SOCK_RCVBUF_LOCK) &&
484484
!tcp_under_memory_pressure(sk) &&
485485
sk_memory_allocated(sk) < sk_prot_mem_limits(sk, 0)) {
486-
sk->sk_rcvbuf = min(atomic_read(&sk->sk_rmem_alloc),
487-
net->ipv4.sysctl_tcp_rmem[2]);
486+
WRITE_ONCE(sk->sk_rcvbuf,
487+
min(atomic_read(&sk->sk_rmem_alloc),
488+
net->ipv4.sysctl_tcp_rmem[2]));
488489
}
489490
if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf)
490491
tp->rcv_ssthresh = min(tp->window_clamp, 2U * tp->advmss);
@@ -648,7 +649,7 @@ void tcp_rcv_space_adjust(struct sock *sk)
648649
rcvbuf = min_t(u64, rcvwin * rcvmem,
649650
sock_net(sk)->ipv4.sysctl_tcp_rmem[2]);
650651
if (rcvbuf > sk->sk_rcvbuf) {
651-
sk->sk_rcvbuf = rcvbuf;
652+
WRITE_ONCE(sk->sk_rcvbuf, rcvbuf);
652653

653654
/* Make the window clamp follow along. */
654655
tp->window_clamp = tcp_win_from_space(sk, rcvbuf);

0 commit comments

Comments
 (0)