From: Eric Dumazet Date: Thu, 19 Dec 2024 15:03:30 +0000 (+0000) Subject: inetpeer: avoid false sharing in inet_peer_xrlim_allow() X-Git-Tag: v6.14-rc1~162^2~170 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=05dd04b218f42c57a14e330fd8583995f141ed6b;p=thirdparty%2Fkernel%2Flinux.git inetpeer: avoid false sharing in inet_peer_xrlim_allow() Under DOS, inet_peer_xrlim_allow() might be called millions of times per second from different cpus. Make sure to write over peer->rate_tokens and peer->rate_last only when really needed. Note the inherent races of this function are still there, we do not care of precise ICMP rate limiting. Signed-off-by: Eric Dumazet Reviewed-by: Willem de Bruijn Link: https://patch.msgid.link/20241219150330.3159027-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c index e02484f4d22b8..b8b23a77ceb4f 100644 --- a/net/ipv4/inetpeer.c +++ b/net/ipv4/inetpeer.c @@ -246,23 +246,27 @@ void inet_putpeer(struct inet_peer *p) #define XRLIM_BURST_FACTOR 6 bool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout) { - unsigned long now, token; + unsigned long now, token, otoken, delta; bool rc = false; if (!peer) return true; - token = peer->rate_tokens; + token = otoken = READ_ONCE(peer->rate_tokens); now = jiffies; - token += now - peer->rate_last; - peer->rate_last = now; - if (token > XRLIM_BURST_FACTOR * timeout) - token = XRLIM_BURST_FACTOR * timeout; + delta = now - READ_ONCE(peer->rate_last); + if (delta) { + WRITE_ONCE(peer->rate_last, now); + token += delta; + if (token > XRLIM_BURST_FACTOR * timeout) + token = XRLIM_BURST_FACTOR * timeout; + } if (token >= timeout) { token -= timeout; rc = true; } - peer->rate_tokens = token; + if (token != otoken) + WRITE_ONCE(peer->rate_tokens, token); return rc; } EXPORT_SYMBOL(inet_peer_xrlim_allow);