[NETNS]: Simplify the network namespace list locking rules.
[safe/jmp/linux-2.6] / net / core / net_namespace.c
1 #include <linux/workqueue.h>
2 #include <linux/rtnetlink.h>
3 #include <linux/cache.h>
4 #include <linux/slab.h>
5 #include <linux/list.h>
6 #include <linux/delay.h>
7 #include <linux/sched.h>
8 #include <net/net_namespace.h>
9
10 /*
11  *      Our network namespace constructor/destructor lists
12  */
13
14 static LIST_HEAD(pernet_list);
15 static struct list_head *first_device = &pernet_list;
16 static DEFINE_MUTEX(net_mutex);
17
18 LIST_HEAD(net_namespace_list);
19
20 static struct kmem_cache *net_cachep;
21
22 struct net init_net;
23 EXPORT_SYMBOL_GPL(init_net);
24
25 static struct net *net_alloc(void)
26 {
27         return kmem_cache_alloc(net_cachep, GFP_KERNEL);
28 }
29
30 static void net_free(struct net *net)
31 {
32         if (!net)
33                 return;
34
35         if (unlikely(atomic_read(&net->use_count) != 0)) {
36                 printk(KERN_EMERG "network namespace not free! Usage: %d\n",
37                         atomic_read(&net->use_count));
38                 return;
39         }
40
41         kmem_cache_free(net_cachep, net);
42 }
43
44 static void cleanup_net(struct work_struct *work)
45 {
46         struct pernet_operations *ops;
47         struct net *net;
48
49         net = container_of(work, struct net, work);
50
51         mutex_lock(&net_mutex);
52
53         /* Don't let anyone else find us. */
54         rtnl_lock();
55         list_del(&net->list);
56         rtnl_unlock();
57
58         /* Run all of the network namespace exit methods */
59         list_for_each_entry_reverse(ops, &pernet_list, list) {
60                 if (ops->exit)
61                         ops->exit(net);
62         }
63
64         mutex_unlock(&net_mutex);
65
66         /* Ensure there are no outstanding rcu callbacks using this
67          * network namespace.
68          */
69         rcu_barrier();
70
71         /* Finally it is safe to free my network namespace structure */
72         net_free(net);
73 }
74
75
76 void __put_net(struct net *net)
77 {
78         /* Cleanup the network namespace in process context */
79         INIT_WORK(&net->work, cleanup_net);
80         schedule_work(&net->work);
81 }
82 EXPORT_SYMBOL_GPL(__put_net);
83
84 /*
85  * setup_net runs the initializers for the network namespace object.
86  */
87 static int setup_net(struct net *net)
88 {
89         /* Must be called with net_mutex held */
90         struct pernet_operations *ops;
91         int error;
92
93         memset(net, 0, sizeof(struct net));
94         atomic_set(&net->count, 1);
95         atomic_set(&net->use_count, 0);
96
97         error = 0;
98         list_for_each_entry(ops, &pernet_list, list) {
99                 if (ops->init) {
100                         error = ops->init(net);
101                         if (error < 0)
102                                 goto out_undo;
103                 }
104         }
105 out:
106         return error;
107
108 out_undo:
109         /* Walk through the list backwards calling the exit functions
110          * for the pernet modules whose init functions did not fail.
111          */
112         list_for_each_entry_continue_reverse(ops, &pernet_list, list) {
113                 if (ops->exit)
114                         ops->exit(net);
115         }
116         goto out;
117 }
118
119 struct net *copy_net_ns(unsigned long flags, struct net *old_net)
120 {
121         struct net *new_net = NULL;
122         int err;
123
124         get_net(old_net);
125
126         if (!(flags & CLONE_NEWNET))
127                 return old_net;
128
129 #ifndef CONFIG_NET_NS
130         return ERR_PTR(-EINVAL);
131 #endif
132
133         err = -ENOMEM;
134         new_net = net_alloc();
135         if (!new_net)
136                 goto out;
137
138         mutex_lock(&net_mutex);
139         err = setup_net(new_net);
140         if (err)
141                 goto out_unlock;
142
143         rtnl_lock();
144         list_add_tail(&new_net->list, &net_namespace_list);
145         rtnl_unlock();
146
147
148 out_unlock:
149         mutex_unlock(&net_mutex);
150 out:
151         put_net(old_net);
152         if (err) {
153                 net_free(new_net);
154                 new_net = ERR_PTR(err);
155         }
156         return new_net;
157 }
158
159 static int __init net_ns_init(void)
160 {
161         int err;
162
163         printk(KERN_INFO "net_namespace: %zd bytes\n", sizeof(struct net));
164         net_cachep = kmem_cache_create("net_namespace", sizeof(struct net),
165                                         SMP_CACHE_BYTES,
166                                         SLAB_PANIC, NULL);
167         mutex_lock(&net_mutex);
168         err = setup_net(&init_net);
169
170         rtnl_lock();
171         list_add_tail(&init_net.list, &net_namespace_list);
172         rtnl_unlock();
173
174         mutex_unlock(&net_mutex);
175         if (err)
176                 panic("Could not setup the initial network namespace");
177
178         return 0;
179 }
180
181 pure_initcall(net_ns_init);
182
183 static int register_pernet_operations(struct list_head *list,
184                                       struct pernet_operations *ops)
185 {
186         struct net *net, *undo_net;
187         int error;
188
189         error = 0;
190         list_add_tail(&ops->list, list);
191         for_each_net(net) {
192                 if (ops->init) {
193                         error = ops->init(net);
194                         if (error)
195                                 goto out_undo;
196                 }
197         }
198 out:
199         return error;
200
201 out_undo:
202         /* If I have an error cleanup all namespaces I initialized */
203         list_del(&ops->list);
204         for_each_net(undo_net) {
205                 if (undo_net == net)
206                         goto undone;
207                 if (ops->exit)
208                         ops->exit(undo_net);
209         }
210 undone:
211         goto out;
212 }
213
214 static void unregister_pernet_operations(struct pernet_operations *ops)
215 {
216         struct net *net;
217
218         list_del(&ops->list);
219         for_each_net(net)
220                 if (ops->exit)
221                         ops->exit(net);
222 }
223
224 /**
225  *      register_pernet_subsys - register a network namespace subsystem
226  *      @ops:  pernet operations structure for the subsystem
227  *
228  *      Register a subsystem which has init and exit functions
229  *      that are called when network namespaces are created and
230  *      destroyed respectively.
231  *
232  *      When registered all network namespace init functions are
233  *      called for every existing network namespace.  Allowing kernel
234  *      modules to have a race free view of the set of network namespaces.
235  *
236  *      When a new network namespace is created all of the init
237  *      methods are called in the order in which they were registered.
238  *
239  *      When a network namespace is destroyed all of the exit methods
240  *      are called in the reverse of the order with which they were
241  *      registered.
242  */
243 int register_pernet_subsys(struct pernet_operations *ops)
244 {
245         int error;
246         mutex_lock(&net_mutex);
247         error =  register_pernet_operations(first_device, ops);
248         mutex_unlock(&net_mutex);
249         return error;
250 }
251 EXPORT_SYMBOL_GPL(register_pernet_subsys);
252
253 /**
254  *      unregister_pernet_subsys - unregister a network namespace subsystem
255  *      @ops: pernet operations structure to manipulate
256  *
257  *      Remove the pernet operations structure from the list to be
258  *      used when network namespaces are created or destoryed.  In
259  *      addition run the exit method for all existing network
260  *      namespaces.
261  */
262 void unregister_pernet_subsys(struct pernet_operations *module)
263 {
264         mutex_lock(&net_mutex);
265         unregister_pernet_operations(module);
266         mutex_unlock(&net_mutex);
267 }
268 EXPORT_SYMBOL_GPL(unregister_pernet_subsys);
269
270 /**
271  *      register_pernet_device - register a network namespace device
272  *      @ops:  pernet operations structure for the subsystem
273  *
274  *      Register a device which has init and exit functions
275  *      that are called when network namespaces are created and
276  *      destroyed respectively.
277  *
278  *      When registered all network namespace init functions are
279  *      called for every existing network namespace.  Allowing kernel
280  *      modules to have a race free view of the set of network namespaces.
281  *
282  *      When a new network namespace is created all of the init
283  *      methods are called in the order in which they were registered.
284  *
285  *      When a network namespace is destroyed all of the exit methods
286  *      are called in the reverse of the order with which they were
287  *      registered.
288  */
289 int register_pernet_device(struct pernet_operations *ops)
290 {
291         int error;
292         mutex_lock(&net_mutex);
293         error = register_pernet_operations(&pernet_list, ops);
294         if (!error && (first_device == &pernet_list))
295                 first_device = &ops->list;
296         mutex_unlock(&net_mutex);
297         return error;
298 }
299 EXPORT_SYMBOL_GPL(register_pernet_device);
300
301 /**
302  *      unregister_pernet_device - unregister a network namespace netdevice
303  *      @ops: pernet operations structure to manipulate
304  *
305  *      Remove the pernet operations structure from the list to be
306  *      used when network namespaces are created or destoryed.  In
307  *      addition run the exit method for all existing network
308  *      namespaces.
309  */
310 void unregister_pernet_device(struct pernet_operations *ops)
311 {
312         mutex_lock(&net_mutex);
313         if (&ops->list == first_device)
314                 first_device = first_device->next;
315         unregister_pernet_operations(ops);
316         mutex_unlock(&net_mutex);
317 }
318 EXPORT_SYMBOL_GPL(unregister_pernet_device);