aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/net_namespace.h28
-rw-r--r--net/core/net_namespace.c188
2 files changed, 126 insertions, 90 deletions
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index d69b4796030f..080774b9dbf3 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -236,6 +236,8 @@ struct pernet_operations {
236 struct list_head list; 236 struct list_head list;
237 int (*init)(struct net *net); 237 int (*init)(struct net *net);
238 void (*exit)(struct net *net); 238 void (*exit)(struct net *net);
239 int *id;
240 size_t size;
239}; 241};
240 242
241/* 243/*
@@ -259,12 +261,30 @@ struct pernet_operations {
259 */ 261 */
260extern int register_pernet_subsys(struct pernet_operations *); 262extern int register_pernet_subsys(struct pernet_operations *);
261extern void unregister_pernet_subsys(struct pernet_operations *); 263extern void unregister_pernet_subsys(struct pernet_operations *);
262extern int register_pernet_gen_subsys(int *id, struct pernet_operations *);
263extern void unregister_pernet_gen_subsys(int id, struct pernet_operations *);
264extern int register_pernet_device(struct pernet_operations *); 264extern int register_pernet_device(struct pernet_operations *);
265extern void unregister_pernet_device(struct pernet_operations *); 265extern void unregister_pernet_device(struct pernet_operations *);
266extern int register_pernet_gen_device(int *id, struct pernet_operations *); 266
267extern void unregister_pernet_gen_device(int id, struct pernet_operations *); 267static inline int register_pernet_gen_subsys(int *id, struct pernet_operations *ops)
268{
269 ops->id = id;
270 return register_pernet_subsys(ops);
271}
272
273static inline void unregister_pernet_gen_subsys(int id, struct pernet_operations *ops)
274{
275 return unregister_pernet_subsys(ops);
276}
277
278static inline int register_pernet_gen_device(int *id, struct pernet_operations *ops)
279{
280 ops->id = id;
281 return register_pernet_device(ops);
282}
283
284static inline void unregister_pernet_gen_device(int id, struct pernet_operations *ops)
285{
286 return unregister_pernet_device(ops);
287}
268 288
269struct ctl_path; 289struct ctl_path;
270struct ctl_table; 290struct ctl_table;
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index a42caa2b909b..9679ad292da9 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -43,13 +43,40 @@ static void unregister_netdevices(struct net *net, struct list_head *list)
43 } 43 }
44} 44}
45 45
46static int ops_init(const struct pernet_operations *ops, struct net *net)
47{
48 int err;
49 if (ops->id && ops->size) {
50 void *data = kzalloc(ops->size, GFP_KERNEL);
51 if (!data)
52 return -ENOMEM;
53
54 err = net_assign_generic(net, *ops->id, data);
55 if (err) {
56 kfree(data);
57 return err;
58 }
59 }
60 if (ops->init)
61 return ops->init(net);
62 return 0;
63}
64
65static void ops_free(const struct pernet_operations *ops, struct net *net)
66{
67 if (ops->id && ops->size) {
68 int id = *ops->id;
69 kfree(net_generic(net, id));
70 }
71}
72
46/* 73/*
47 * setup_net runs the initializers for the network namespace object. 74 * setup_net runs the initializers for the network namespace object.
48 */ 75 */
49static __net_init int setup_net(struct net *net) 76static __net_init int setup_net(struct net *net)
50{ 77{
51 /* Must be called with net_mutex held */ 78 /* Must be called with net_mutex held */
52 struct pernet_operations *ops; 79 const struct pernet_operations *ops, *saved_ops;
53 int error = 0; 80 int error = 0;
54 81
55 atomic_set(&net->count, 1); 82 atomic_set(&net->count, 1);
@@ -59,11 +86,9 @@ static __net_init int setup_net(struct net *net)
59#endif 86#endif
60 87
61 list_for_each_entry(ops, &pernet_list, list) { 88 list_for_each_entry(ops, &pernet_list, list) {
62 if (ops->init) { 89 error = ops_init(ops, net);
63 error = ops->init(net); 90 if (error < 0)
64 if (error < 0) 91 goto out_undo;
65 goto out_undo;
66 }
67 } 92 }
68out: 93out:
69 return error; 94 return error;
@@ -72,6 +97,7 @@ out_undo:
72 /* Walk through the list backwards calling the exit functions 97 /* Walk through the list backwards calling the exit functions
73 * for the pernet modules whose init functions did not fail. 98 * for the pernet modules whose init functions did not fail.
74 */ 99 */
100 saved_ops = ops;
75 list_for_each_entry_continue_reverse(ops, &pernet_list, list) { 101 list_for_each_entry_continue_reverse(ops, &pernet_list, list) {
76 if (ops->exit) 102 if (ops->exit)
77 ops->exit(net); 103 ops->exit(net);
@@ -83,6 +109,9 @@ out_undo:
83 rtnl_unlock(); 109 rtnl_unlock();
84 } 110 }
85 } 111 }
112 ops = saved_ops;
113 list_for_each_entry_continue_reverse(ops, &pernet_list, list)
114 ops_free(ops, net);
86 115
87 rcu_barrier(); 116 rcu_barrier();
88 goto out; 117 goto out;
@@ -175,7 +204,7 @@ static LIST_HEAD(cleanup_list); /* Must hold cleanup_list_lock to touch */
175 204
176static void cleanup_net(struct work_struct *work) 205static void cleanup_net(struct work_struct *work)
177{ 206{
178 struct pernet_operations *ops; 207 const struct pernet_operations *ops;
179 struct net *net, *tmp; 208 struct net *net, *tmp;
180 LIST_HEAD(net_kill_list); 209 LIST_HEAD(net_kill_list);
181 210
@@ -214,6 +243,13 @@ static void cleanup_net(struct work_struct *work)
214 rtnl_unlock(); 243 rtnl_unlock();
215 } 244 }
216 } 245 }
246 /* Free the net generic variables */
247 list_for_each_entry_reverse(ops, &pernet_list, list) {
248 if (ops->size && ops->id) {
249 list_for_each_entry(net, &net_kill_list, cleanup_list)
250 ops_free(ops, net);
251 }
252 }
217 253
218 mutex_unlock(&net_mutex); 254 mutex_unlock(&net_mutex);
219 255
@@ -309,16 +345,16 @@ static int __init net_ns_init(void)
309pure_initcall(net_ns_init); 345pure_initcall(net_ns_init);
310 346
311#ifdef CONFIG_NET_NS 347#ifdef CONFIG_NET_NS
312static int register_pernet_operations(struct list_head *list, 348static int __register_pernet_operations(struct list_head *list,
313 struct pernet_operations *ops) 349 struct pernet_operations *ops)
314{ 350{
315 struct net *net, *undo_net; 351 struct net *net, *undo_net;
316 int error; 352 int error;
317 353
318 list_add_tail(&ops->list, list); 354 list_add_tail(&ops->list, list);
319 if (ops->init) { 355 if (ops->init || (ops->id && ops->size)) {
320 for_each_net(net) { 356 for_each_net(net) {
321 error = ops->init(net); 357 error = ops_init(ops, net);
322 if (error) 358 if (error)
323 goto out_undo; 359 goto out_undo;
324 } 360 }
@@ -336,10 +372,18 @@ out_undo:
336 } 372 }
337 } 373 }
338undone: 374undone:
375 if (ops->size && ops->id) {
376 for_each_net(undo_net) {
377 if (net_eq(undo_net, net))
378 goto freed;
379 ops_free(ops, undo_net);
380 }
381 }
382freed:
339 return error; 383 return error;
340} 384}
341 385
342static void unregister_pernet_operations(struct pernet_operations *ops) 386static void __unregister_pernet_operations(struct pernet_operations *ops)
343{ 387{
344 struct net *net; 388 struct net *net;
345 389
@@ -347,27 +391,66 @@ static void unregister_pernet_operations(struct pernet_operations *ops)
347 if (ops->exit) 391 if (ops->exit)
348 for_each_net(net) 392 for_each_net(net)
349 ops->exit(net); 393 ops->exit(net);
394 if (ops->id && ops->size)
395 for_each_net(net)
396 ops_free(ops, net);
350} 397}
351 398
352#else 399#else
353 400
354static int register_pernet_operations(struct list_head *list, 401static int __register_pernet_operations(struct list_head *list,
355 struct pernet_operations *ops) 402 struct pernet_operations *ops)
356{ 403{
357 if (ops->init == NULL) 404 int err = 0;
358 return 0; 405 err = ops_init(ops, &init_net);
359 return ops->init(&init_net); 406 if (err)
407 ops_free(ops, &init_net);
408 return err;
409
360} 410}
361 411
362static void unregister_pernet_operations(struct pernet_operations *ops) 412static void __unregister_pernet_operations(struct pernet_operations *ops)
363{ 413{
364 if (ops->exit) 414 if (ops->exit)
365 ops->exit(&init_net); 415 ops->exit(&init_net);
416 ops_free(ops, &init_net);
366} 417}
367#endif 418
419#endif /* CONFIG_NET_NS */
368 420
369static DEFINE_IDA(net_generic_ids); 421static DEFINE_IDA(net_generic_ids);
370 422
423static int register_pernet_operations(struct list_head *list,
424 struct pernet_operations *ops)
425{
426 int error;
427
428 if (ops->id) {
429again:
430 error = ida_get_new_above(&net_generic_ids, 1, ops->id);
431 if (error < 0) {
432 if (error == -EAGAIN) {
433 ida_pre_get(&net_generic_ids, GFP_KERNEL);
434 goto again;
435 }
436 return error;
437 }
438 }
439 error = __register_pernet_operations(list, ops);
440 if (error && ops->id)
441 ida_remove(&net_generic_ids, *ops->id);
442
443 return error;
444}
445
446static void unregister_pernet_operations(struct pernet_operations *ops)
447{
448
449 __unregister_pernet_operations(ops);
450 if (ops->id)
451 ida_remove(&net_generic_ids, *ops->id);
452}
453
371/** 454/**
372 * register_pernet_subsys - register a network namespace subsystem 455 * register_pernet_subsys - register a network namespace subsystem
373 * @ops: pernet operations structure for the subsystem 456 * @ops: pernet operations structure for the subsystem
@@ -414,38 +497,6 @@ void unregister_pernet_subsys(struct pernet_operations *module)
414} 497}
415EXPORT_SYMBOL_GPL(unregister_pernet_subsys); 498EXPORT_SYMBOL_GPL(unregister_pernet_subsys);
416 499
417int register_pernet_gen_subsys(int *id, struct pernet_operations *ops)
418{
419 int rv;
420
421 mutex_lock(&net_mutex);
422again:
423 rv = ida_get_new_above(&net_generic_ids, 1, id);
424 if (rv < 0) {
425 if (rv == -EAGAIN) {
426 ida_pre_get(&net_generic_ids, GFP_KERNEL);
427 goto again;
428 }
429 goto out;
430 }
431 rv = register_pernet_operations(first_device, ops);
432 if (rv < 0)
433 ida_remove(&net_generic_ids, *id);
434out:
435 mutex_unlock(&net_mutex);
436 return rv;
437}
438EXPORT_SYMBOL_GPL(register_pernet_gen_subsys);
439
440void unregister_pernet_gen_subsys(int id, struct pernet_operations *ops)
441{
442 mutex_lock(&net_mutex);
443 unregister_pernet_operations(ops);
444 ida_remove(&net_generic_ids, id);
445 mutex_unlock(&net_mutex);
446}
447EXPORT_SYMBOL_GPL(unregister_pernet_gen_subsys);
448
449/** 500/**
450 * register_pernet_device - register a network namespace device 501 * register_pernet_device - register a network namespace device
451 * @ops: pernet operations structure for the subsystem 502 * @ops: pernet operations structure for the subsystem
@@ -477,30 +528,6 @@ int register_pernet_device(struct pernet_operations *ops)
477} 528}
478EXPORT_SYMBOL_GPL(register_pernet_device); 529EXPORT_SYMBOL_GPL(register_pernet_device);
479 530
480int register_pernet_gen_device(int *id, struct pernet_operations *ops)
481{
482 int error;
483 mutex_lock(&net_mutex);
484again:
485 error = ida_get_new_above(&net_generic_ids, 1, id);
486 if (error) {
487 if (error == -EAGAIN) {
488 ida_pre_get(&net_generic_ids, GFP_KERNEL);
489 goto again;
490 }
491 goto out;
492 }
493 error = register_pernet_operations(&pernet_list, ops);
494 if (error)
495 ida_remove(&net_generic_ids, *id);
496 else if (first_device == &pernet_list)
497 first_device = &ops->list;
498out:
499 mutex_unlock(&net_mutex);
500 return error;
501}
502EXPORT_SYMBOL_GPL(register_pernet_gen_device);
503
504/** 531/**
505 * unregister_pernet_device - unregister a network namespace netdevice 532 * unregister_pernet_device - unregister a network namespace netdevice
506 * @ops: pernet operations structure to manipulate 533 * @ops: pernet operations structure to manipulate
@@ -520,17 +547,6 @@ void unregister_pernet_device(struct pernet_operations *ops)
520} 547}
521EXPORT_SYMBOL_GPL(unregister_pernet_device); 548EXPORT_SYMBOL_GPL(unregister_pernet_device);
522 549
523void unregister_pernet_gen_device(int id, struct pernet_operations *ops)
524{
525 mutex_lock(&net_mutex);
526 if (&ops->list == first_device)
527 first_device = first_device->next;
528 unregister_pernet_operations(ops);
529 ida_remove(&net_generic_ids, id);
530 mutex_unlock(&net_mutex);
531}
532EXPORT_SYMBOL_GPL(unregister_pernet_gen_device);
533
534static void net_generic_release(struct rcu_head *rcu) 550static void net_generic_release(struct rcu_head *rcu)
535{ 551{
536 struct net_generic *ng; 552 struct net_generic *ng;