net: make net->dev_unreg_count atomic
authorEric Dumazet <edumazet@google.com>
Thu, 10 Feb 2022 02:59:32 +0000 (18:59 -0800)
committerDavid S. Miller <davem@davemloft.net>
Thu, 10 Feb 2022 15:30:26 +0000 (15:30 +0000)
Having to acquire rtnl from netdev_run_todo() for every dismantled
device is not desirable when/if rtnl is under stress.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/net_namespace.h
net/core/dev.c
net/core/rtnetlink.c

index 374cc7b..c4f5601 100644 (file)
@@ -63,7 +63,7 @@ struct net {
                                                 */
        spinlock_t              rules_mod_lock;
 
-       unsigned int            dev_unreg_count;
+       atomic_t                dev_unreg_count;
 
        unsigned int            dev_base_seq;   /* protected by rtnl_mutex */
        int                     ifindex;
index f5ef516..2c3b874 100644 (file)
@@ -9143,7 +9143,7 @@ DECLARE_WAIT_QUEUE_HEAD(netdev_unregistering_wq);
 static void net_set_todo(struct net_device *dev)
 {
        list_add_tail(&dev->todo_list, &net_todo_list);
-       dev_net(dev)->dev_unreg_count++;
+       atomic_inc(&dev_net(dev)->dev_unreg_count);
 }
 
 static netdev_features_t netdev_sync_upper_features(struct net_device *lower,
@@ -9965,11 +9965,8 @@ void netdev_run_todo(void)
                if (dev->needs_free_netdev)
                        free_netdev(dev);
 
-               /* Report a network device has been unregistered */
-               rtnl_lock();
-               dev_net(dev)->dev_unreg_count--;
-               __rtnl_unlock();
-               wake_up(&netdev_unregistering_wq);
+               if (atomic_dec_and_test(&dev_net(dev)->dev_unreg_count))
+                       wake_up(&netdev_unregistering_wq);
 
                /* Free network device */
                kobject_put(&dev->dev.kobj);
@@ -10898,7 +10895,7 @@ static void __net_exit rtnl_lock_unregistering(struct list_head *net_list)
                unregistering = false;
 
                list_for_each_entry(net, net_list, exit_list) {
-                       if (net->dev_unreg_count > 0) {
+                       if (atomic_read(&net->dev_unreg_count) > 0) {
                                unregistering = true;
                                break;
                        }
index 710da8a..a6fad3d 100644 (file)
@@ -459,7 +459,7 @@ static void rtnl_lock_unregistering_all(void)
                 * setup_net() and cleanup_net() are not possible.
                 */
                for_each_net(net) {
-                       if (net->dev_unreg_count > 0) {
+                       if (atomic_read(&net->dev_unreg_count) > 0) {
                                unregistering = true;
                                break;
                        }