net: annotate data-races around sk->sk_tx_queue_mapping
authorEric Dumazet <edumazet@google.com>
Thu, 21 Sep 2023 20:28:17 +0000 (20:28 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 28 Nov 2023 17:19:38 +0000 (17:19 +0000)
[ Upstream commit 0bb4d124d34044179b42a769a0c76f389ae973b6 ]

This field can be read or written without socket lock being held.

Add annotations to avoid load-store tearing.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
include/net/sock.h

index 92f7ea6..97f7fbc 100644 (file)
@@ -2006,21 +2006,33 @@ static inline void sk_tx_queue_set(struct sock *sk, int tx_queue)
        /* sk_tx_queue_mapping accept only upto a 16-bit value */
        if (WARN_ON_ONCE((unsigned short)tx_queue >= USHRT_MAX))
                return;
-       sk->sk_tx_queue_mapping = tx_queue;
+       /* Paired with READ_ONCE() in sk_tx_queue_get() and
+        * other WRITE_ONCE() because socket lock might be not held.
+        */
+       WRITE_ONCE(sk->sk_tx_queue_mapping, tx_queue);
 }
 
 #define NO_QUEUE_MAPPING       USHRT_MAX
 
 static inline void sk_tx_queue_clear(struct sock *sk)
 {
-       sk->sk_tx_queue_mapping = NO_QUEUE_MAPPING;
+       /* Paired with READ_ONCE() in sk_tx_queue_get() and
+        * other WRITE_ONCE() because socket lock might be not held.
+        */
+       WRITE_ONCE(sk->sk_tx_queue_mapping, NO_QUEUE_MAPPING);
 }
 
 static inline int sk_tx_queue_get(const struct sock *sk)
 {
-       if (sk && sk->sk_tx_queue_mapping != NO_QUEUE_MAPPING)
-               return sk->sk_tx_queue_mapping;
+       if (sk) {
+               /* Paired with WRITE_ONCE() in sk_tx_queue_clear()
+                * and sk_tx_queue_set().
+                */
+               int val = READ_ONCE(sk->sk_tx_queue_mapping);
 
+               if (val != NO_QUEUE_MAPPING)
+                       return val;
+       }
        return -1;
 }