net-sysfs: warn if new queue objects are being created during device unregistration
[platform/kernel/linux-starfive.git] / net / core / net-sysfs.c
index addbef5..53ea262 100644 (file)
@@ -488,14 +488,6 @@ static ssize_t proto_down_store(struct device *dev,
                                struct device_attribute *attr,
                                const char *buf, size_t len)
 {
-       struct net_device *netdev = to_net_dev(dev);
-
-       /* The check is also done in change_proto_down; this helps returning
-        * early without hitting the trylock/restart in netdev_store.
-        */
-       if (!netdev->netdev_ops->ndo_change_proto_down)
-               return -EOPNOTSUPP;
-
        return netdev_store(dev, attr, buf, len, change_proto_down);
 }
 NETDEVICE_SHOW_RW(proto_down, fmt_dec);
@@ -1012,7 +1004,7 @@ static void rx_queue_release(struct kobject *kobj)
 #endif
 
        memset(kobj, 0, sizeof(*kobj));
-       dev_put(queue->dev);
+       dev_put_track(queue->dev, &queue->dev_tracker);
 }
 
 static const void *rx_queue_namespace(struct kobject *kobj)
@@ -1052,7 +1044,7 @@ static int rx_queue_add_kobject(struct net_device *dev, int index)
        /* Kobject_put later will trigger rx_queue_release call which
         * decreases dev refcount: Take that reference here
         */
-       dev_hold(queue->dev);
+       dev_hold_track(queue->dev, &queue->dev_tracker, GFP_KERNEL);
 
        kobj->kset = dev->queues_kset;
        error = kobject_init_and_add(kobj, &rx_queue_ktype, NULL,
@@ -1448,7 +1440,7 @@ static ssize_t xps_queue_show(struct net_device *dev, unsigned int index,
 
                for (i = map->len; i--;) {
                        if (map->queues[i] == index) {
-                               set_bit(j, mask);
+                               __set_bit(j, mask);
                                break;
                        }
                }
@@ -1615,7 +1607,7 @@ static void netdev_queue_release(struct kobject *kobj)
        struct netdev_queue *queue = to_netdev_queue(kobj);
 
        memset(kobj, 0, sizeof(*kobj));
-       dev_put(queue->dev);
+       dev_put_track(queue->dev, &queue->dev_tracker);
 }
 
 static const void *netdev_queue_namespace(struct kobject *kobj)
@@ -1655,7 +1647,7 @@ static int netdev_queue_add_kobject(struct net_device *dev, int index)
        /* Kobject_put later will trigger netdev_queue_release call
         * which decreases dev refcount: Take that reference here
         */
-       dev_hold(queue->dev);
+       dev_hold_track(queue->dev, &queue->dev_tracker, GFP_KERNEL);
 
        kobj->kset = dev->queues_kset;
        error = kobject_init_and_add(kobj, &netdev_queue_ktype, NULL,
@@ -1702,6 +1694,13 @@ netdev_queue_update_kobjects(struct net_device *dev, int old_num, int new_num)
        int i;
        int error = 0;
 
+       /* Tx queue kobjects are allowed to be updated when a device is being
+        * unregistered, but solely to remove queues from qdiscs. Any path
+        * adding queues should be fixed.
+        */
+       WARN(dev->reg_state == NETREG_UNREGISTERING && new_num > old_num,
+            "New queues can't be registered after device unregistration.");
+
        for (i = old_num; i < new_num; i++) {
                error = netdev_queue_add_kobject(dev, i);
                if (error) {
@@ -1816,6 +1815,9 @@ static void remove_queue_kobjects(struct net_device *dev)
 
        net_rx_queue_update_kobjects(dev, real_rx, 0);
        netdev_queue_update_kobjects(dev, real_tx, 0);
+
+       dev->real_num_rx_queues = 0;
+       dev->real_num_tx_queues = 0;
 #ifdef CONFIG_SYSFS
        kset_unregister(dev->queues_kset);
 #endif