]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: shaper: annotate the data races
authorJakub Kicinski <kuba@kernel.org>
Fri, 15 May 2026 22:13:24 +0000 (15:13 -0700)
committerJakub Kicinski <kuba@kernel.org>
Wed, 20 May 2026 23:34:20 +0000 (16:34 -0700)
As previously discussed we don't care about making the shaper
state fully RCU-compliant because the hierarchy itself can't
be dumped in one go over Netlink. Let's annotate the reads
and writes to make that clear.

The field-by-field assignments will also be useful for the
next commit which adds explicit "valid" field (which we don't
want to override with the current full struct assignment).

Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20260515221325.1685455-2-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/shaper/shaper.c

index b1c65110f04d37aa141b3e28b7e11cd6c398cbcb..520cefdc3d9083386f27cc3cbcf5ece5d771f803 100644 (file)
@@ -138,35 +138,58 @@ handle_nest_cancel:
        return -EMSGSIZE;
 }
 
+static void net_shaper_copy(struct net_shaper *dst,
+                           const struct net_shaper *src)
+{
+       WRITE_ONCE(dst->parent.scope, READ_ONCE(src->parent.scope));
+       WRITE_ONCE(dst->parent.id, READ_ONCE(src->parent.id));
+       WRITE_ONCE(dst->handle.scope, READ_ONCE(src->handle.scope));
+       WRITE_ONCE(dst->handle.id, READ_ONCE(src->handle.id));
+
+       WRITE_ONCE(dst->metric, READ_ONCE(src->metric));
+       WRITE_ONCE(dst->bw_min, READ_ONCE(src->bw_min));
+       WRITE_ONCE(dst->bw_max, READ_ONCE(src->bw_max));
+       WRITE_ONCE(dst->burst, READ_ONCE(src->burst));
+       WRITE_ONCE(dst->priority, READ_ONCE(src->priority));
+       WRITE_ONCE(dst->weight, READ_ONCE(src->weight));
+
+       /* private fields are only used on the write path under the lock */
+       data_race(dst->leaves = src->leaves);
+}
+
 static int
 net_shaper_fill_one(struct sk_buff *msg,
                    const struct net_shaper_binding *binding,
                    const struct net_shaper *shaper,
                    const struct genl_info *info)
 {
+       struct net_shaper cur;
        void *hdr;
 
        hdr = genlmsg_iput(msg, info);
        if (!hdr)
                return -EMSGSIZE;
 
+       /* Make a copy to avoid data races */
+       net_shaper_copy(&cur, shaper);
+
        if (net_shaper_fill_binding(msg, binding, NET_SHAPER_A_IFINDEX) ||
-           net_shaper_fill_handle(msg, &shaper->parent,
+           net_shaper_fill_handle(msg, &cur.parent,
                                   NET_SHAPER_A_PARENT) ||
-           net_shaper_fill_handle(msg, &shaper->handle,
+           net_shaper_fill_handle(msg, &cur.handle,
                                   NET_SHAPER_A_HANDLE) ||
-           ((shaper->bw_min || shaper->bw_max || shaper->burst) &&
-            nla_put_u32(msg, NET_SHAPER_A_METRIC, shaper->metric)) ||
-           (shaper->bw_min &&
-            nla_put_uint(msg, NET_SHAPER_A_BW_MIN, shaper->bw_min)) ||
-           (shaper->bw_max &&
-            nla_put_uint(msg, NET_SHAPER_A_BW_MAX, shaper->bw_max)) ||
-           (shaper->burst &&
-            nla_put_uint(msg, NET_SHAPER_A_BURST, shaper->burst)) ||
-           (shaper->priority &&
-            nla_put_u32(msg, NET_SHAPER_A_PRIORITY, shaper->priority)) ||
-           (shaper->weight &&
-            nla_put_u32(msg, NET_SHAPER_A_WEIGHT, shaper->weight)))
+           ((cur.bw_min || cur.bw_max || cur.burst) &&
+            nla_put_u32(msg, NET_SHAPER_A_METRIC, cur.metric)) ||
+           (cur.bw_min &&
+            nla_put_uint(msg, NET_SHAPER_A_BW_MIN, cur.bw_min)) ||
+           (cur.bw_max &&
+            nla_put_uint(msg, NET_SHAPER_A_BW_MAX, cur.bw_max)) ||
+           (cur.burst &&
+            nla_put_uint(msg, NET_SHAPER_A_BURST, cur.burst)) ||
+           (cur.priority &&
+            nla_put_u32(msg, NET_SHAPER_A_PRIORITY, cur.priority)) ||
+           (cur.weight &&
+            nla_put_u32(msg, NET_SHAPER_A_WEIGHT, cur.weight)))
                goto nla_put_failure;
 
        genlmsg_end(msg, hdr);
@@ -424,7 +447,7 @@ static void net_shaper_commit(struct net_shaper_binding *binding,
                /* Successful update: drop the tentative mark
                 * and update the hierarchy container.
                 */
-               *cur = shapers[i];
+               net_shaper_copy(cur, &shapers[i]);
                smp_wmb();
                __xa_set_mark(&hierarchy->shapers, index, NET_SHAPER_VALID);
        }