aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2009-11-29 17:25:28 -0500
committerDavid S. Miller <davem@davemloft.net>2009-12-01 19:15:51 -0500
commitf875bae065334907796da12523f9df85c89f5712 (patch)
tree6f14819d128e3fa7b4cc8c274c6eff5326622fc8 /net/core
parent2b035b39970740722598f7a9d548835f9bdd730f (diff)
net: Automatically allocate per namespace data.
To get the full benefit of batched network namespace cleanup netowrk device deletion needs to be performed by the generic code. When using register_pernet_gen_device and freeing the data in exit_net it is impossible to delay allocation until after exit_net has called as the device uninit methods are no longer safe. To correct this, and to simplify working with per network namespace data I have moved allocation and deletion of per network namespace data into the network namespace core. The core now frees the data only after all of the network namespace exit routines have run. Now it is only required to set the new fields .id and .size in the pernet_operations structure if you want network namespace data to be managed for you automatically. This makes the current register_pernet_gen_device and register_pernet_gen_subsys routines unnecessary. For the moment I have left them as compatibility wrappers in net_namespace.h They will be removed once all of the users have been updated. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core')
-rw-r--r--net/core/net_namespace.c188
1 files changed, 102 insertions, 86 deletions
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;