diff options
Diffstat (limited to 'net/core/net_namespace.c')
| -rw-r--r-- | net/core/net_namespace.c | 95 |
1 files changed, 47 insertions, 48 deletions
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index bd8c4712ea24..c988e685433a 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c | |||
| @@ -27,6 +27,51 @@ EXPORT_SYMBOL(init_net); | |||
| 27 | 27 | ||
| 28 | #define INITIAL_NET_GEN_PTRS 13 /* +1 for len +2 for rcu_head */ | 28 | #define INITIAL_NET_GEN_PTRS 13 /* +1 for len +2 for rcu_head */ |
| 29 | 29 | ||
| 30 | static void net_generic_release(struct rcu_head *rcu) | ||
| 31 | { | ||
| 32 | struct net_generic *ng; | ||
| 33 | |||
| 34 | ng = container_of(rcu, struct net_generic, rcu); | ||
| 35 | kfree(ng); | ||
| 36 | } | ||
| 37 | |||
| 38 | static int net_assign_generic(struct net *net, int id, void *data) | ||
| 39 | { | ||
| 40 | struct net_generic *ng, *old_ng; | ||
| 41 | |||
| 42 | BUG_ON(!mutex_is_locked(&net_mutex)); | ||
| 43 | BUG_ON(id == 0); | ||
| 44 | |||
| 45 | ng = old_ng = net->gen; | ||
| 46 | if (old_ng->len >= id) | ||
| 47 | goto assign; | ||
| 48 | |||
| 49 | ng = kzalloc(sizeof(struct net_generic) + | ||
| 50 | id * sizeof(void *), GFP_KERNEL); | ||
| 51 | if (ng == NULL) | ||
| 52 | return -ENOMEM; | ||
| 53 | |||
| 54 | /* | ||
| 55 | * Some synchronisation notes: | ||
| 56 | * | ||
| 57 | * The net_generic explores the net->gen array inside rcu | ||
| 58 | * read section. Besides once set the net->gen->ptr[x] | ||
| 59 | * pointer never changes (see rules in netns/generic.h). | ||
| 60 | * | ||
| 61 | * That said, we simply duplicate this array and schedule | ||
| 62 | * the old copy for kfree after a grace period. | ||
| 63 | */ | ||
| 64 | |||
| 65 | ng->len = id; | ||
| 66 | memcpy(&ng->ptr, &old_ng->ptr, old_ng->len * sizeof(void*)); | ||
| 67 | |||
| 68 | rcu_assign_pointer(net->gen, ng); | ||
| 69 | call_rcu(&old_ng->rcu, net_generic_release); | ||
| 70 | assign: | ||
| 71 | ng->ptr[id - 1] = data; | ||
| 72 | return 0; | ||
| 73 | } | ||
| 74 | |||
| 30 | static int ops_init(const struct pernet_operations *ops, struct net *net) | 75 | static int ops_init(const struct pernet_operations *ops, struct net *net) |
| 31 | { | 76 | { |
| 32 | int err; | 77 | int err; |
| @@ -469,10 +514,10 @@ EXPORT_SYMBOL_GPL(register_pernet_subsys); | |||
| 469 | * addition run the exit method for all existing network | 514 | * addition run the exit method for all existing network |
| 470 | * namespaces. | 515 | * namespaces. |
| 471 | */ | 516 | */ |
| 472 | void unregister_pernet_subsys(struct pernet_operations *module) | 517 | void unregister_pernet_subsys(struct pernet_operations *ops) |
| 473 | { | 518 | { |
| 474 | mutex_lock(&net_mutex); | 519 | mutex_lock(&net_mutex); |
| 475 | unregister_pernet_operations(module); | 520 | unregister_pernet_operations(ops); |
| 476 | mutex_unlock(&net_mutex); | 521 | mutex_unlock(&net_mutex); |
| 477 | } | 522 | } |
| 478 | EXPORT_SYMBOL_GPL(unregister_pernet_subsys); | 523 | EXPORT_SYMBOL_GPL(unregister_pernet_subsys); |
| @@ -526,49 +571,3 @@ void unregister_pernet_device(struct pernet_operations *ops) | |||
| 526 | mutex_unlock(&net_mutex); | 571 | mutex_unlock(&net_mutex); |
| 527 | } | 572 | } |
| 528 | EXPORT_SYMBOL_GPL(unregister_pernet_device); | 573 | EXPORT_SYMBOL_GPL(unregister_pernet_device); |
| 529 | |||
| 530 | static void net_generic_release(struct rcu_head *rcu) | ||
| 531 | { | ||
| 532 | struct net_generic *ng; | ||
| 533 | |||
| 534 | ng = container_of(rcu, struct net_generic, rcu); | ||
| 535 | kfree(ng); | ||
| 536 | } | ||
| 537 | |||
| 538 | int net_assign_generic(struct net *net, int id, void *data) | ||
| 539 | { | ||
| 540 | struct net_generic *ng, *old_ng; | ||
| 541 | |||
| 542 | BUG_ON(!mutex_is_locked(&net_mutex)); | ||
| 543 | BUG_ON(id == 0); | ||
| 544 | |||
| 545 | ng = old_ng = net->gen; | ||
| 546 | if (old_ng->len >= id) | ||
| 547 | goto assign; | ||
| 548 | |||
| 549 | ng = kzalloc(sizeof(struct net_generic) + | ||
| 550 | id * sizeof(void *), GFP_KERNEL); | ||
| 551 | if (ng == NULL) | ||
| 552 | return -ENOMEM; | ||
| 553 | |||
| 554 | /* | ||
| 555 | * Some synchronisation notes: | ||
| 556 | * | ||
| 557 | * The net_generic explores the net->gen array inside rcu | ||
| 558 | * read section. Besides once set the net->gen->ptr[x] | ||
| 559 | * pointer never changes (see rules in netns/generic.h). | ||
| 560 | * | ||
| 561 | * That said, we simply duplicate this array and schedule | ||
| 562 | * the old copy for kfree after a grace period. | ||
| 563 | */ | ||
| 564 | |||
| 565 | ng->len = id; | ||
| 566 | memcpy(&ng->ptr, &old_ng->ptr, old_ng->len * sizeof(void*)); | ||
| 567 | |||
| 568 | rcu_assign_pointer(net->gen, ng); | ||
| 569 | call_rcu(&old_ng->rcu, net_generic_release); | ||
| 570 | assign: | ||
| 571 | ng->ptr[id - 1] = data; | ||
| 572 | return 0; | ||
| 573 | } | ||
| 574 | EXPORT_SYMBOL_GPL(net_assign_generic); | ||
