]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
xdp: double protect netdev->xdp_flags with netdev->lock
authorJakub Kicinski <kuba@kernel.org>
Tue, 8 Apr 2025 19:59:52 +0000 (12:59 -0700)
committerJakub Kicinski <kuba@kernel.org>
Thu, 10 Apr 2025 00:01:52 +0000 (17:01 -0700)
Protect xdp_features with netdev->lock. This way pure readers
no longer have to take rtnl_lock to access the field.

This includes calling NETDEV_XDP_FEAT_CHANGE under the lock.
Looks like that's fine for bonding, the only "real" listener,
it's the same as ethtool feature change.

In terms of normal drivers - only GVE need special consideration
(other drivers don't use instance lock or don't support XDP).
It calls xdp_set_features_flag() helper from gve_init_priv() which
in turn is called from gve_reset_recovery() (locked), or prior
to netdev registration. So switch to _locked.

Reviewed-by: Joe Damato <jdamato@fastly.com>
Acked-by: Stanislav Fomichev <sdf@fomichev.me>
Acked-by: Harshitha Ramamurthy <hramamurthy@google.com>
Acked-by: Martin KaFai Lau <martin.lau@kernel.org>
Link: https://patch.msgid.link/20250408195956.412733-6-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Documentation/networking/netdevices.rst
drivers/net/ethernet/google/gve/gve_main.c
include/linux/netdevice.h
include/net/xdp.h
net/core/lock_debug.c
net/core/xdp.c

index 6c2d8945f5979813b79228b0be5edce57be99377..d6357472d3f197c19916249234314354244435ea 100644 (file)
@@ -354,6 +354,7 @@ For devices with locked ops, currently only the following notifiers are
 running under the lock:
 * ``NETDEV_REGISTER``
 * ``NETDEV_UP``
+* ``NETDEV_XDP_FEAT_CHANGE``
 
 The following notifiers are running without the lock:
 * ``NETDEV_UNREGISTER``
index f9a73c9568614951d8f575bc1ce61aa2b6cf27d1..7a249baee316a2e296a5cb1989d44c7e7da06bed 100644 (file)
@@ -2185,7 +2185,7 @@ static void gve_set_netdev_xdp_features(struct gve_priv *priv)
                xdp_features = 0;
        }
 
-       xdp_set_features_flag(priv->dev, xdp_features);
+       xdp_set_features_flag_locked(priv->dev, xdp_features);
 }
 
 static int gve_init_priv(struct gve_priv *priv, bool skip_describe_device)
index 7242fb8a22fc5aa78c046d600c72248978f9a55e..dece2ae396a1e2086840c0c4b7201f4b31e026f1 100644 (file)
@@ -2526,7 +2526,7 @@ struct net_device {
         *      @net_shaper_hierarchy, @reg_state, @threaded
         *
         * Double protects:
-        *      @up, @moving_ns, @nd_net
+        *      @up, @moving_ns, @nd_net, @xdp_flags
         *
         * Double ops protects:
         *      @real_num_rx_queues, @real_num_tx_queues
index 48efacbaa35da6c4ec76d8d8e78b86e8f7c23e4b..20e41b5ff319a84e0aa2621ad6ba37da13808b73 100644 (file)
@@ -616,6 +616,7 @@ struct xdp_metadata_ops {
 u32 bpf_xdp_metadata_kfunc_id(int id);
 bool bpf_dev_bound_kfunc_id(u32 btf_id);
 void xdp_set_features_flag(struct net_device *dev, xdp_features_t val);
+void xdp_set_features_flag_locked(struct net_device *dev, xdp_features_t val);
 void xdp_features_set_redirect_target(struct net_device *dev, bool support_sg);
 void xdp_features_clear_redirect_target(struct net_device *dev);
 #else
index b7f22dc92a6f30fbb47a6a53f08a2802d9e82ff3..598c443ef2f39ba30feb01e097e87c62275ecda5 100644 (file)
@@ -20,6 +20,7 @@ int netdev_debug_event(struct notifier_block *nb, unsigned long event,
        switch (cmd) {
        case NETDEV_REGISTER:
        case NETDEV_UP:
+       case NETDEV_XDP_FEAT_CHANGE:
                netdev_ops_assert_locked(dev);
                fallthrough;
        case NETDEV_DOWN:
@@ -58,7 +59,6 @@ int netdev_debug_event(struct notifier_block *nb, unsigned long event,
        case NETDEV_OFFLOAD_XSTATS_DISABLE:
        case NETDEV_OFFLOAD_XSTATS_REPORT_USED:
        case NETDEV_OFFLOAD_XSTATS_REPORT_DELTA:
-       case NETDEV_XDP_FEAT_CHANGE:
                ASSERT_RTNL();
                break;
 
index f86eedad586a77eb63a96a85aa6d068d3e94f077..3cd0db9c9d2d3e3e9c21d7e8d298c4f1680a617e 100644 (file)
@@ -17,6 +17,7 @@
 #include <net/page_pool/helpers.h>
 
 #include <net/hotdata.h>
+#include <net/netdev_lock.h>
 #include <net/xdp.h>
 #include <net/xdp_priv.h> /* struct xdp_mem_allocator */
 #include <trace/events/xdp.h>
@@ -991,17 +992,26 @@ static int __init xdp_metadata_init(void)
 }
 late_initcall(xdp_metadata_init);
 
-void xdp_set_features_flag(struct net_device *dev, xdp_features_t val)
+void xdp_set_features_flag_locked(struct net_device *dev, xdp_features_t val)
 {
        val &= NETDEV_XDP_ACT_MASK;
        if (dev->xdp_features == val)
                return;
 
+       netdev_assert_locked_or_invisible(dev);
        dev->xdp_features = val;
 
        if (dev->reg_state == NETREG_REGISTERED)
                call_netdevice_notifiers(NETDEV_XDP_FEAT_CHANGE, dev);
 }
+EXPORT_SYMBOL_GPL(xdp_set_features_flag_locked);
+
+void xdp_set_features_flag(struct net_device *dev, xdp_features_t val)
+{
+       netdev_lock(dev);
+       xdp_set_features_flag_locked(dev, val);
+       netdev_unlock(dev);
+}
 EXPORT_SYMBOL_GPL(xdp_set_features_flag);
 
 void xdp_features_set_redirect_target(struct net_device *dev, bool support_sg)