aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/net_namespace.h2
-rw-r--r--net/core/net_namespace.c66
2 files changed, 59 insertions, 9 deletions
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 0addd45038ac..d69b4796030f 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -42,7 +42,7 @@ struct net {
42 */ 42 */
43#endif 43#endif
44 struct list_head list; /* list of network namespaces */ 44 struct list_head list; /* list of network namespaces */
45 struct work_struct work; /* work struct for freeing */ 45 struct list_head cleanup_list; /* namespaces on death row */
46 46
47 struct proc_dir_entry *proc_net; 47 struct proc_dir_entry *proc_net;
48 struct proc_dir_entry *proc_net_stat; 48 struct proc_dir_entry *proc_net_stat;
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 86ed7f44d083..a42caa2b909b 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -8,8 +8,10 @@
8#include <linux/idr.h> 8#include <linux/idr.h>
9#include <linux/rculist.h> 9#include <linux/rculist.h>
10#include <linux/nsproxy.h> 10#include <linux/nsproxy.h>
11#include <linux/netdevice.h>
11#include <net/net_namespace.h> 12#include <net/net_namespace.h>
12#include <net/netns/generic.h> 13#include <net/netns/generic.h>
14#include <net/rtnetlink.h>
13 15
14/* 16/*
15 * Our network namespace constructor/destructor lists 17 * Our network namespace constructor/destructor lists
@@ -27,6 +29,20 @@ EXPORT_SYMBOL(init_net);
27 29
28#define INITIAL_NET_GEN_PTRS 13 /* +1 for len +2 for rcu_head */ 30#define INITIAL_NET_GEN_PTRS 13 /* +1 for len +2 for rcu_head */
29 31
32static void unregister_netdevices(struct net *net, struct list_head *list)
33{
34 struct net_device *dev;
35 /* At exit all network devices most be removed from a network
36 * namespace. Do this in the reverse order of registeration.
37 */
38 for_each_netdev_reverse(net, dev) {
39 if (dev->rtnl_link_ops)
40 dev->rtnl_link_ops->dellink(dev, list);
41 else
42 unregister_netdevice_queue(dev, list);
43 }
44}
45
30/* 46/*
31 * setup_net runs the initializers for the network namespace object. 47 * setup_net runs the initializers for the network namespace object.
32 */ 48 */
@@ -59,6 +75,13 @@ out_undo:
59 list_for_each_entry_continue_reverse(ops, &pernet_list, list) { 75 list_for_each_entry_continue_reverse(ops, &pernet_list, list) {
60 if (ops->exit) 76 if (ops->exit)
61 ops->exit(net); 77 ops->exit(net);
78 if (&ops->list == first_device) {
79 LIST_HEAD(dev_kill_list);
80 rtnl_lock();
81 unregister_netdevices(net, &dev_kill_list);
82 unregister_netdevice_many(&dev_kill_list);
83 rtnl_unlock();
84 }
62 } 85 }
63 86
64 rcu_barrier(); 87 rcu_barrier();
@@ -147,18 +170,26 @@ struct net *copy_net_ns(unsigned long flags, struct net *old_net)
147 return net_create(); 170 return net_create();
148} 171}
149 172
173static DEFINE_SPINLOCK(cleanup_list_lock);
174static LIST_HEAD(cleanup_list); /* Must hold cleanup_list_lock to touch */
175
150static void cleanup_net(struct work_struct *work) 176static void cleanup_net(struct work_struct *work)
151{ 177{
152 struct pernet_operations *ops; 178 struct pernet_operations *ops;
153 struct net *net; 179 struct net *net, *tmp;
180 LIST_HEAD(net_kill_list);
154 181
155 net = container_of(work, struct net, work); 182 /* Atomically snapshot the list of namespaces to cleanup */
183 spin_lock_irq(&cleanup_list_lock);
184 list_replace_init(&cleanup_list, &net_kill_list);
185 spin_unlock_irq(&cleanup_list_lock);
156 186
157 mutex_lock(&net_mutex); 187 mutex_lock(&net_mutex);
158 188
159 /* Don't let anyone else find us. */ 189 /* Don't let anyone else find us. */
160 rtnl_lock(); 190 rtnl_lock();
161 list_del_rcu(&net->list); 191 list_for_each_entry(net, &net_kill_list, cleanup_list)
192 list_del_rcu(&net->list);
162 rtnl_unlock(); 193 rtnl_unlock();
163 194
164 /* 195 /*
@@ -170,8 +201,18 @@ static void cleanup_net(struct work_struct *work)
170 201
171 /* Run all of the network namespace exit methods */ 202 /* Run all of the network namespace exit methods */
172 list_for_each_entry_reverse(ops, &pernet_list, list) { 203 list_for_each_entry_reverse(ops, &pernet_list, list) {
173 if (ops->exit) 204 if (ops->exit) {
174 ops->exit(net); 205 list_for_each_entry(net, &net_kill_list, cleanup_list)
206 ops->exit(net);
207 }
208 if (&ops->list == first_device) {
209 LIST_HEAD(dev_kill_list);
210 rtnl_lock();
211 list_for_each_entry(net, &net_kill_list, cleanup_list)
212 unregister_netdevices(net, &dev_kill_list);
213 unregister_netdevice_many(&dev_kill_list);
214 rtnl_unlock();
215 }
175 } 216 }
176 217
177 mutex_unlock(&net_mutex); 218 mutex_unlock(&net_mutex);
@@ -182,14 +223,23 @@ static void cleanup_net(struct work_struct *work)
182 rcu_barrier(); 223 rcu_barrier();
183 224
184 /* Finally it is safe to free my network namespace structure */ 225 /* Finally it is safe to free my network namespace structure */
185 net_free(net); 226 list_for_each_entry_safe(net, tmp, &net_kill_list, cleanup_list) {
227 list_del_init(&net->cleanup_list);
228 net_free(net);
229 }
186} 230}
231static DECLARE_WORK(net_cleanup_work, cleanup_net);
187 232
188void __put_net(struct net *net) 233void __put_net(struct net *net)
189{ 234{
190 /* Cleanup the network namespace in process context */ 235 /* Cleanup the network namespace in process context */
191 INIT_WORK(&net->work, cleanup_net); 236 unsigned long flags;
192 queue_work(netns_wq, &net->work); 237
238 spin_lock_irqsave(&cleanup_list_lock, flags);
239 list_add(&net->cleanup_list, &cleanup_list);
240 spin_unlock_irqrestore(&cleanup_list_lock, flags);
241
242 queue_work(netns_wq, &net_cleanup_work);
193} 243}
194EXPORT_SYMBOL_GPL(__put_net); 244EXPORT_SYMBOL_GPL(__put_net);
195 245