net-sysfs: move queue attribute groups outside the default groups
authorAntoine Tenart <atenart@kernel.org>
Tue, 4 Feb 2025 17:03:11 +0000 (18:03 +0100)
committerJakub Kicinski <kuba@kernel.org>
Thu, 6 Feb 2025 01:49:08 +0000 (17:49 -0800)
Rx/tx queues embed their own kobject for registering their per-queue
sysfs files. The issue is they're using the kobject default groups for
this and entirely rely on the kobject refcounting for releasing their
sysfs paths.

In order to remove rtnl_trylock calls we need sysfs files not to rely on
their associated kobject refcounting for their release. Thus we here
move queues sysfs files from the kobject default groups to their own
groups which can be removed separately.

Signed-off-by: Antoine Tenart <atenart@kernel.org>
Link: https://patch.msgid.link/20250204170314.146022-3-atenart@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/linux/netdevice.h
include/net/netdev_rx_queue.h
net/core/net-sysfs.c

index 2a59034a5fa2fb53300657968c2053ab354bb746..1dcc76af752038b445dc65f5971933b662e31000 100644 (file)
@@ -658,6 +658,7 @@ struct netdev_queue {
        struct Qdisc __rcu      *qdisc_sleeping;
 #ifdef CONFIG_SYSFS
        struct kobject          kobj;
+       const struct attribute_group    **groups;
 #endif
        unsigned long           tx_maxrate;
        /*
index 596836abf7bf4ce7e12b2948997d01c2579cddaf..af40842f229d9aa93b2fe4ccf7a985480581894a 100644 (file)
@@ -16,6 +16,7 @@ struct netdev_rx_queue {
        struct rps_dev_flow_table __rcu *rps_flow_table;
 #endif
        struct kobject                  kobj;
+       const struct attribute_group    **groups;
        struct net_device               *dev;
        netdevice_tracker               dev_tracker;
 
index e012234c739a3822bbd1df66801c42928f7218e6..0b7ee260613d597b7d8473ee846a9014567f1990 100644 (file)
@@ -1188,7 +1188,6 @@ static void rx_queue_get_ownership(const struct kobject *kobj,
 static const struct kobj_type rx_queue_ktype = {
        .sysfs_ops = &rx_queue_sysfs_ops,
        .release = rx_queue_release,
-       .default_groups = rx_queue_default_groups,
        .namespace = rx_queue_namespace,
        .get_ownership = rx_queue_get_ownership,
 };
@@ -1222,20 +1221,27 @@ static int rx_queue_add_kobject(struct net_device *dev, int index)
        if (error)
                goto err;
 
+       queue->groups = rx_queue_default_groups;
+       error = sysfs_create_groups(kobj, queue->groups);
+       if (error)
+               goto err;
+
        if (dev->sysfs_rx_queue_group) {
                error = sysfs_create_group(kobj, dev->sysfs_rx_queue_group);
                if (error)
-                       goto err;
+                       goto err_default_groups;
        }
 
        error = rx_queue_default_mask(dev, queue);
        if (error)
-               goto err;
+               goto err_default_groups;
 
        kobject_uevent(kobj, KOBJ_ADD);
 
        return error;
 
+err_default_groups:
+       sysfs_remove_groups(kobj, queue->groups);
 err:
        kobject_put(kobj);
        return error;
@@ -1280,12 +1286,14 @@ net_rx_queue_update_kobjects(struct net_device *dev, int old_num, int new_num)
        }
 
        while (--i >= new_num) {
-               struct kobject *kobj = &dev->_rx[i].kobj;
+               struct netdev_rx_queue *queue = &dev->_rx[i];
+               struct kobject *kobj = &queue->kobj;
 
                if (!refcount_read(&dev_net(dev)->ns.count))
                        kobj->uevent_suppress = 1;
                if (dev->sysfs_rx_queue_group)
                        sysfs_remove_group(kobj, dev->sysfs_rx_queue_group);
+               sysfs_remove_groups(kobj, queue->groups);
                kobject_put(kobj);
        }
 
@@ -1872,7 +1880,6 @@ static void netdev_queue_get_ownership(const struct kobject *kobj,
 static const struct kobj_type netdev_queue_ktype = {
        .sysfs_ops = &netdev_queue_sysfs_ops,
        .release = netdev_queue_release,
-       .default_groups = netdev_queue_default_groups,
        .namespace = netdev_queue_namespace,
        .get_ownership = netdev_queue_get_ownership,
 };
@@ -1902,15 +1909,22 @@ static int netdev_queue_add_kobject(struct net_device *dev, int index)
        if (error)
                goto err;
 
+       queue->groups = netdev_queue_default_groups;
+       error = sysfs_create_groups(kobj, queue->groups);
+       if (error)
+               goto err;
+
        if (netdev_uses_bql(dev)) {
                error = sysfs_create_group(kobj, &dql_group);
                if (error)
-                       goto err;
+                       goto err_default_groups;
        }
 
        kobject_uevent(kobj, KOBJ_ADD);
        return 0;
 
+err_default_groups:
+       sysfs_remove_groups(kobj, queue->groups);
 err:
        kobject_put(kobj);
        return error;
@@ -1965,6 +1979,7 @@ netdev_queue_update_kobjects(struct net_device *dev, int old_num, int new_num)
                if (netdev_uses_bql(dev))
                        sysfs_remove_group(&queue->kobj, &dql_group);
 
+               sysfs_remove_groups(&queue->kobj, queue->groups);
                kobject_put(&queue->kobj);
        }