diff options
Diffstat (limited to 'net/core/dev.c')
| -rw-r--r-- | net/core/dev.c | 25 | 
1 files changed, 15 insertions, 10 deletions
| diff --git a/net/core/dev.c b/net/core/dev.c index 08ce317fcec8..8e6f22961206 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -397,16 +397,18 @@ static void list_netdevice(struct net_device *dev)  /* Device list removal   * caller must respect a RCU grace period before freeing/reusing dev   */ -static void unlist_netdevice(struct net_device *dev) +static void unlist_netdevice(struct net_device *dev, bool lock)  {  	ASSERT_RTNL();  	/* Unlink dev from the device chain */ -	write_lock(&dev_base_lock); +	if (lock) +		write_lock(&dev_base_lock);  	list_del_rcu(&dev->dev_list);  	netdev_name_node_del(dev->name_node);  	hlist_del_rcu(&dev->index_hlist); -	write_unlock(&dev_base_lock); +	if (lock) +		write_unlock(&dev_base_lock);  	dev_base_seq_inc(dev_net(dev));  } @@ -10043,11 +10045,11 @@ int register_netdevice(struct net_device *dev)  		goto err_uninit;  	ret = netdev_register_kobject(dev); -	if (ret) { -		dev->reg_state = NETREG_UNREGISTERED; +	write_lock(&dev_base_lock); +	dev->reg_state = ret ? NETREG_UNREGISTERED : NETREG_REGISTERED; +	write_unlock(&dev_base_lock); +	if (ret)  		goto err_uninit; -	} -	dev->reg_state = NETREG_REGISTERED;  	__netdev_update_features(dev); @@ -10329,7 +10331,9 @@ void netdev_run_todo(void)  			continue;  		} +		write_lock(&dev_base_lock);  		dev->reg_state = NETREG_UNREGISTERED; +		write_unlock(&dev_base_lock);  		linkwatch_forget_dev(dev);  	} @@ -10810,9 +10814,10 @@ void unregister_netdevice_many(struct list_head *head)  	list_for_each_entry(dev, head, unreg_list) {  		/* And unlink it from device chain. */ -		unlist_netdevice(dev); - +		write_lock(&dev_base_lock); +		unlist_netdevice(dev, false);  		dev->reg_state = NETREG_UNREGISTERING; +		write_unlock(&dev_base_lock);  	}  	flush_all_backlogs(); @@ -10959,7 +10964,7 @@ int __dev_change_net_namespace(struct net_device *dev, struct net *net,  	dev_close(dev);  	/* And unlink it from device chain */ -	unlist_netdevice(dev); +	unlist_netdevice(dev, true);  	synchronize_net(); |