Commit ede6c39c authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

net: make net->dev_unreg_count atomic

Having to acquire rtnl from netdev_run_todo() for every dismantled
device is not desirable when/if rtnl is under stress.
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ca2d5f1f
...@@ -63,7 +63,7 @@ struct net { ...@@ -63,7 +63,7 @@ struct net {
*/ */
spinlock_t rules_mod_lock; spinlock_t rules_mod_lock;
unsigned int dev_unreg_count; atomic_t dev_unreg_count;
unsigned int dev_base_seq; /* protected by rtnl_mutex */ unsigned int dev_base_seq; /* protected by rtnl_mutex */
int ifindex; int ifindex;
......
...@@ -9143,7 +9143,7 @@ DECLARE_WAIT_QUEUE_HEAD(netdev_unregistering_wq); ...@@ -9143,7 +9143,7 @@ DECLARE_WAIT_QUEUE_HEAD(netdev_unregistering_wq);
static void net_set_todo(struct net_device *dev) static void net_set_todo(struct net_device *dev)
{ {
list_add_tail(&dev->todo_list, &net_todo_list); 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, static netdev_features_t netdev_sync_upper_features(struct net_device *lower,
...@@ -9965,11 +9965,8 @@ void netdev_run_todo(void) ...@@ -9965,11 +9965,8 @@ void netdev_run_todo(void)
if (dev->needs_free_netdev) if (dev->needs_free_netdev)
free_netdev(dev); free_netdev(dev);
/* Report a network device has been unregistered */ if (atomic_dec_and_test(&dev_net(dev)->dev_unreg_count))
rtnl_lock(); wake_up(&netdev_unregistering_wq);
dev_net(dev)->dev_unreg_count--;
__rtnl_unlock();
wake_up(&netdev_unregistering_wq);
/* Free network device */ /* Free network device */
kobject_put(&dev->dev.kobj); kobject_put(&dev->dev.kobj);
...@@ -10898,7 +10895,7 @@ static void __net_exit rtnl_lock_unregistering(struct list_head *net_list) ...@@ -10898,7 +10895,7 @@ static void __net_exit rtnl_lock_unregistering(struct list_head *net_list)
unregistering = false; unregistering = false;
list_for_each_entry(net, net_list, exit_list) { 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; unregistering = true;
break; break;
} }
......
...@@ -459,7 +459,7 @@ static void rtnl_lock_unregistering_all(void) ...@@ -459,7 +459,7 @@ static void rtnl_lock_unregistering_all(void)
* setup_net() and cleanup_net() are not possible. * setup_net() and cleanup_net() are not possible.
*/ */
for_each_net(net) { for_each_net(net) {
if (net->dev_unreg_count > 0) { if (atomic_read(&net->dev_unreg_count) > 0) {
unregistering = true; unregistering = true;
break; break;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment