===================================================================
@@ -68,6 +68,8 @@ struct net {
struct hlist_head *dev_name_head;
struct hlist_head *dev_index_head;
unsigned int dev_base_seq; /* protected by rtnl_mutex */
+ int dev_unregistering; /* protected by rtnl_mutex */
+ wait_queue_head_t dev_unregistering_wait;
/* core fib_rules */
struct list_head rules_ops;
===================================================================
@@ -153,6 +153,8 @@ static __net_init int setup_net(struct n
atomic_set(&net->count, 1);
atomic_set(&net->passive, 1);
net->dev_base_seq = 1;
+ net->dev_unregistering = 0;
+ init_waitqueue_head(&net->dev_unregistering_wait);
#ifdef NETNS_REFCNT_DEBUG
atomic_set(&net->use_count, 0);
===================================================================
@@ -5191,6 +5191,7 @@ static LIST_HEAD(net_todo_list);
static void net_set_todo(struct net_device *dev)
{
list_add_tail(&dev->todo_list, &net_todo_list);
+ dev_net(dev)->dev_unregistering++;
}
static void rollback_registered_many(struct list_head *head)
@@ -5815,6 +5816,12 @@ void netdev_run_todo(void)
if (dev->destructor)
dev->destructor(dev);
+ rtnl_lock();
+ BUG_ON(dev_net(dev)->dev_unregistering <= 0);
+ if (--dev_net(dev)->dev_unregistering == 0)
+ wake_up(&dev_net(dev)->dev_unregistering_wait);
+ __rtnl_unlock();
+
/* Free network device */
kobject_put(&dev->dev.kobj);
}
@@ -6478,6 +6485,26 @@ static void __net_exit default_device_ex
rtnl_unlock();
}
+static void netdev_wait_unregistering_and_lock(struct list_head *net_list)
+{
+ struct net *net;
+
+retry:
+ /* Wait until any devices in namespaces in net_list that were
+ unregistered by other processes are destroyed */
+ list_for_each_entry(net, net_list, exit_list) {
+ wait_event(net->dev_unregistering_wait,
+ net->dev_unregistering == 0);
+ }
+ rtnl_lock();
+ list_for_each_entry(net, net_list, exit_list) {
+ if (net->dev_unregistering) {
+ __rtnl_unlock();
+ goto retry;
+ }
+ }
+}
+
static void __net_exit default_device_exit_batch(struct list_head *net_list)
{
/* At exit all network devices most be removed from a network
@@ -6489,7 +6516,7 @@ static void __net_exit default_device_ex
struct net *net;
LIST_HEAD(dev_kill_list);
- rtnl_lock();
+ netdev_wait_unregistering_and_lock(net_list);
list_for_each_entry(net, net_list, exit_list) {
for_each_netdev_reverse(net, dev) {
if (dev->rtnl_link_ops)