diff options
author | Eric Dumazet <edumazet@google.com> | 2023-09-21 23:28:15 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2023-10-01 21:09:54 +0300 |
commit | 28b24f90020fed8e8e3e8e20575f08c1cd06e54f (patch) | |
tree | 3fc7b7bd080580d56131a0a3b46468b1b1eea6f2 /net/core/sock.c | |
parent | 2a4319cf3c83fc5d1997466196b99b3e14584e76 (diff) | |
download | linux-28b24f90020fed8e8e3e8e20575f08c1cd06e54f.tar.xz |
net: implement lockless SO_MAX_PACING_RATE
SO_MAX_PACING_RATE setsockopt() does not need to hold
the socket lock, because sk->sk_pacing_rate readers
can run fine if the value is changed by other threads,
after adding READ_ONCE() accessors.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core/sock.c')
-rw-r--r-- | net/core/sock.c | 40 |
1 files changed, 21 insertions, 19 deletions
diff --git a/net/core/sock.c b/net/core/sock.c index 408081549bd7..4254ed0e4817 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1160,6 +1160,27 @@ int sk_setsockopt(struct sock *sk, int level, int optname, WRITE_ONCE(sk->sk_busy_poll_budget, val); return 0; #endif + case SO_MAX_PACING_RATE: + { + unsigned long ulval = (val == ~0U) ? ~0UL : (unsigned int)val; + unsigned long pacing_rate; + + if (sizeof(ulval) != sizeof(val) && + optlen >= sizeof(ulval) && + copy_from_sockptr(&ulval, optval, sizeof(ulval))) { + return -EFAULT; + } + if (ulval != ~0UL) + cmpxchg(&sk->sk_pacing_status, + SK_PACING_NONE, + SK_PACING_NEEDED); + /* Pairs with READ_ONCE() from sk_getsockopt() */ + WRITE_ONCE(sk->sk_max_pacing_rate, ulval); + pacing_rate = READ_ONCE(sk->sk_pacing_rate); + if (ulval < pacing_rate) + WRITE_ONCE(sk->sk_pacing_rate, ulval); + return 0; + } } sockopt_lock_sock(sk); @@ -1423,25 +1444,6 @@ set_sndbuf: break; - case SO_MAX_PACING_RATE: - { - unsigned long ulval = (val == ~0U) ? ~0UL : (unsigned int)val; - - if (sizeof(ulval) != sizeof(val) && - optlen >= sizeof(ulval) && - copy_from_sockptr(&ulval, optval, sizeof(ulval))) { - ret = -EFAULT; - break; - } - if (ulval != ~0UL) - cmpxchg(&sk->sk_pacing_status, - SK_PACING_NONE, - SK_PACING_NEEDED); - /* Pairs with READ_ONCE() from sk_getsockopt() */ - WRITE_ONCE(sk->sk_max_pacing_rate, ulval); - sk->sk_pacing_rate = min(sk->sk_pacing_rate, ulval); - break; - } case SO_INCOMING_CPU: reuseport_update_incoming_cpu(sk, val); break; |