[PATCH net-next 1/2] net: make sk->sk_sndtimeo lockless
From: Eric Dumazet <edumazet@google.com>
Date: 2025-06-20 15:55:53
Subsystem:
bluetooth subsystem, networking [general], networking [sockets], sctp protocol, shared memory communications (smc) sockets, the rest · Maintainers:
Marcel Holtmann, Luiz Augusto von Dentz, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Kuniyuki Iwashima, Willem de Bruijn, Marcelo Ricardo Leitner, Xin Long, D. Wythe, Dust Li, Sidraya Jayagond, Wenjia Zhang, Linus Torvalds
Followup of commit 285975dd6742 ("net: annotate data-races around
sk->sk_{rcv|snd}timeo").
Remove lock_sock()/release_sock() from sock_set_sndtimeo(),
and add READ_ONCE()/WRITE_ONCE() where it is needed.
Also SO_SNDTIMEO_OLD and SO_SNDTIMEO_NEW can call sock_set_timeout()
without holding the socket lock.
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
include/net/sock.h | 2 +-
net/bluetooth/iso.c | 4 ++--
net/bluetooth/l2cap_sock.c | 4 ++--
net/bluetooth/sco.c | 4 ++--
net/core/sock.c | 12 ++++--------
net/sctp/socket.c | 2 +-
net/smc/af_smc.c | 4 ++--
7 files changed, 14 insertions(+), 18 deletions(-)
diff --git a/include/net/sock.h b/include/net/sock.h
index ca532227cbfda1eb51f67532cbbbdc79a41c98d6..337d78bc780ec53947f7bd1f583e3d1e5a3c599f 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h@@ -2595,7 +2595,7 @@ static inline long sock_rcvtimeo(const struct sock *sk, bool noblock) static inline long sock_sndtimeo(const struct sock *sk, bool noblock) { - return noblock ? 0 : sk->sk_sndtimeo; + return noblock ? 0 : READ_ONCE(sk->sk_sndtimeo); } static inline int sock_rcvlowat(const struct sock *sk, int waitall, int len)
diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c
index 3c2c98eecc62675be10161ba40046be871bb3bb7..34e89bb5f3841b67c753a07ec12fe1c5bdd6f646 100644
--- a/net/bluetooth/iso.c
+++ b/net/bluetooth/iso.c@@ -413,7 +413,7 @@ static int iso_connect_bis(struct sock *sk) sk->sk_state = BT_CONNECT; } else { sk->sk_state = BT_CONNECT; - iso_sock_set_timer(sk, sk->sk_sndtimeo); + iso_sock_set_timer(sk, READ_ONCE(sk->sk_sndtimeo)); } release_sock(sk);
@@ -503,7 +503,7 @@ static int iso_connect_cis(struct sock *sk) sk->sk_state = BT_CONNECT; } else { sk->sk_state = BT_CONNECT; - iso_sock_set_timer(sk, sk->sk_sndtimeo); + iso_sock_set_timer(sk, READ_ONCE(sk->sk_sndtimeo)); } release_sock(sk);
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 5aa55fa695943a79bcdd38e5661af9b637fe18ba..113656489db5d8a094d25599506d531b79285036 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c@@ -255,7 +255,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, err = l2cap_chan_connect(chan, la.l2_psm, __le16_to_cpu(la.l2_cid), &la.l2_bdaddr, la.l2_bdaddr_type, - sk->sk_sndtimeo); + READ_ONCE(sk->sk_sndtimeo)); if (err) return err;
@@ -1725,7 +1725,7 @@ static long l2cap_sock_get_sndtimeo_cb(struct l2cap_chan *chan) { struct sock *sk = chan->data; - return sk->sk_sndtimeo; + return READ_ONCE(sk->sk_sndtimeo); } static struct pid *l2cap_sock_get_peer_pid_cb(struct l2cap_chan *chan)
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 2945d27e75dce6839e404906f13eb1765c80249a..d382d980fd9a73bac80f8fd9b2702c2e85d29688 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c@@ -338,7 +338,7 @@ static int sco_connect(struct sock *sk) hcon = hci_connect_sco(hdev, type, &sco_pi(sk)->dst, sco_pi(sk)->setting, &sco_pi(sk)->codec, - sk->sk_sndtimeo); + READ_ONCE(sk->sk_sndtimeo)); if (IS_ERR(hcon)) { err = PTR_ERR(hcon); goto unlock;
@@ -367,7 +367,7 @@ static int sco_connect(struct sock *sk) sk->sk_state = BT_CONNECTED; } else { sk->sk_state = BT_CONNECT; - sco_sock_set_timer(sk, sk->sk_sndtimeo); + sco_sock_set_timer(sk, READ_ONCE(sk->sk_sndtimeo)); } release_sock(sk);
diff --git a/net/core/sock.c b/net/core/sock.c
index 502042a0d3b5f80529ca8be50e9d9d6585091054..3e69f3b970af080e22999f2ce36d85434486fe15 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c@@ -818,12 +818,10 @@ EXPORT_SYMBOL(sock_set_priority); void sock_set_sndtimeo(struct sock *sk, s64 secs) { - lock_sock(sk); if (secs && secs < MAX_SCHEDULE_TIMEOUT / HZ - 1) WRITE_ONCE(sk->sk_sndtimeo, secs * HZ); else WRITE_ONCE(sk->sk_sndtimeo, MAX_SCHEDULE_TIMEOUT); - release_sock(sk); } EXPORT_SYMBOL(sock_set_sndtimeo);
@@ -1287,6 +1285,10 @@ int sk_setsockopt(struct sock *sk, int level, int optname, case SO_DEVMEM_DONTNEED: return sock_devmem_dontneed(sk, optval, optlen); #endif + case SO_SNDTIMEO_OLD: + case SO_SNDTIMEO_NEW: + return sock_set_timeout(&sk->sk_sndtimeo, optval, + optlen, optname == SO_SNDTIMEO_OLD); } sockopt_lock_sock(sk);
@@ -1448,12 +1450,6 @@ int sk_setsockopt(struct sock *sk, int level, int optname, optlen, optname == SO_RCVTIMEO_OLD); break; - case SO_SNDTIMEO_OLD: - case SO_SNDTIMEO_NEW: - ret = sock_set_timeout(&sk->sk_sndtimeo, optval, - optlen, optname == SO_SNDTIMEO_OLD); - break; - case SO_ATTACH_FILTER: { struct sock_fprog fprog;
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 1e5739858c2067381ccc713756ff56e585d152ad..96852ccb6decf714d7a243f83141b7371f7a034d 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c@@ -9493,7 +9493,7 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk, newsk->sk_rcvbuf = sk->sk_rcvbuf; newsk->sk_lingertime = sk->sk_lingertime; newsk->sk_rcvtimeo = sk->sk_rcvtimeo; - newsk->sk_sndtimeo = sk->sk_sndtimeo; + newsk->sk_sndtimeo = READ_ONCE(sk->sk_sndtimeo); newsk->sk_rxhash = sk->sk_rxhash; newinet = inet_sk(newsk);
diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
index 3760131f1484503323b2843fe5304a2283c10c4d..6375a86fe2b5f4e9c5aa9f2a71650e5708692be7 100644
--- a/net/smc/af_smc.c
+++ b/net/smc/af_smc.c@@ -486,7 +486,7 @@ static void smc_copy_sock_settings(struct sock *nsk, struct sock *osk, { /* options we don't get control via setsockopt for */ nsk->sk_type = osk->sk_type; - nsk->sk_sndtimeo = osk->sk_sndtimeo; + nsk->sk_sndtimeo = READ_ONCE(osk->sk_sndtimeo); nsk->sk_rcvtimeo = osk->sk_rcvtimeo; nsk->sk_mark = READ_ONCE(osk->sk_mark); nsk->sk_priority = READ_ONCE(osk->sk_priority);
@@ -1585,7 +1585,7 @@ static void smc_connect_work(struct work_struct *work) { struct smc_sock *smc = container_of(work, struct smc_sock, connect_work); - long timeo = smc->sk.sk_sndtimeo; + long timeo = READ_ONCE(smc->sk.sk_sndtimeo); int rc = 0; if (!timeo)
--
2.50.0.rc2.701.gf1e915cc24-goog