diff options
Diffstat (limited to 'net/core/net_namespace.c')
-rw-r--r-- | net/core/net_namespace.c | 162 |
1 files changed, 84 insertions, 78 deletions
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 662e6ea1cecf..e9f0964ce70b 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -17,74 +17,13 @@ static DEFINE_MUTEX(net_mutex); LIST_HEAD(net_namespace_list); -static struct kmem_cache *net_cachep; - struct net init_net; EXPORT_SYMBOL_GPL(init_net); -static struct net *net_alloc(void) -{ - return kmem_cache_zalloc(net_cachep, GFP_KERNEL); -} - -static void net_free(struct net *net) -{ - if (!net) - return; - - if (unlikely(atomic_read(&net->use_count) != 0)) { - printk(KERN_EMERG "network namespace not free! Usage: %d\n", - atomic_read(&net->use_count)); - return; - } - - kmem_cache_free(net_cachep, net); -} - -static void cleanup_net(struct work_struct *work) -{ - struct pernet_operations *ops; - struct net *net; - - net = container_of(work, struct net, work); - - mutex_lock(&net_mutex); - - /* Don't let anyone else find us. */ - rtnl_lock(); - list_del(&net->list); - rtnl_unlock(); - - /* Run all of the network namespace exit methods */ - list_for_each_entry_reverse(ops, &pernet_list, list) { - if (ops->exit) - ops->exit(net); - } - - mutex_unlock(&net_mutex); - - /* Ensure there are no outstanding rcu callbacks using this - * network namespace. - */ - rcu_barrier(); - - /* Finally it is safe to free my network namespace structure */ - net_free(net); -} - - -void __put_net(struct net *net) -{ - /* Cleanup the network namespace in process context */ - INIT_WORK(&net->work, cleanup_net); - schedule_work(&net->work); -} -EXPORT_SYMBOL_GPL(__put_net); - /* * setup_net runs the initializers for the network namespace object. */ -static int setup_net(struct net *net) +static __net_init int setup_net(struct net *net) { /* Must be called with net_mutex held */ struct pernet_operations *ops; @@ -117,6 +56,14 @@ out_undo: goto out; } +#ifdef CONFIG_NET_NS +static struct kmem_cache *net_cachep; + +static struct net *net_alloc(void) +{ + return kmem_cache_zalloc(net_cachep, GFP_KERNEL); +} + struct net *copy_net_ns(unsigned long flags, struct net *old_net) { struct net *new_net = NULL; @@ -127,10 +74,6 @@ struct net *copy_net_ns(unsigned long flags, struct net *old_net) if (!(flags & CLONE_NEWNET)) return old_net; -#ifndef CONFIG_NET_NS - return ERR_PTR(-EINVAL); -#endif - err = -ENOMEM; new_net = net_alloc(); if (!new_net) @@ -157,14 +100,78 @@ out: return new_net; } +static void net_free(struct net *net) +{ + if (!net) + return; + + if (unlikely(atomic_read(&net->use_count) != 0)) { + printk(KERN_EMERG "network namespace not free! Usage: %d\n", + atomic_read(&net->use_count)); + return; + } + + kmem_cache_free(net_cachep, net); +} + +static void cleanup_net(struct work_struct *work) +{ + struct pernet_operations *ops; + struct net *net; + + net = container_of(work, struct net, work); + + mutex_lock(&net_mutex); + + /* Don't let anyone else find us. */ + rtnl_lock(); + list_del(&net->list); + rtnl_unlock(); + + /* Run all of the network namespace exit methods */ + list_for_each_entry_reverse(ops, &pernet_list, list) { + if (ops->exit) + ops->exit(net); + } + + mutex_unlock(&net_mutex); + + /* Ensure there are no outstanding rcu callbacks using this + * network namespace. + */ + rcu_barrier(); + + /* Finally it is safe to free my network namespace structure */ + net_free(net); +} + +void __put_net(struct net *net) +{ + /* Cleanup the network namespace in process context */ + INIT_WORK(&net->work, cleanup_net); + schedule_work(&net->work); +} +EXPORT_SYMBOL_GPL(__put_net); + +#else +struct net *copy_net_ns(unsigned long flags, struct net *old_net) +{ + if (flags & CLONE_NEWNET) + return ERR_PTR(-EINVAL); + return old_net; +} +#endif + static int __init net_ns_init(void) { int err; printk(KERN_INFO "net_namespace: %zd bytes\n", sizeof(struct net)); +#ifdef CONFIG_NET_NS net_cachep = kmem_cache_create("net_namespace", sizeof(struct net), SMP_CACHE_BYTES, SLAB_PANIC, NULL); +#endif mutex_lock(&net_mutex); err = setup_net(&init_net); @@ -187,29 +194,28 @@ static int register_pernet_operations(struct list_head *list, struct net *net, *undo_net; int error; - error = 0; list_add_tail(&ops->list, list); - for_each_net(net) { - if (ops->init) { + if (ops->init) { + for_each_net(net) { error = ops->init(net); if (error) goto out_undo; } } -out: - return error; + return 0; out_undo: /* If I have an error cleanup all namespaces I initialized */ list_del(&ops->list); - for_each_net(undo_net) { - if (undo_net == net) - goto undone; - if (ops->exit) + if (ops->exit) { + for_each_net(undo_net) { + if (undo_net == net) + goto undone; ops->exit(undo_net); + } } undone: - goto out; + return error; } static void unregister_pernet_operations(struct pernet_operations *ops) @@ -217,8 +223,8 @@ static void unregister_pernet_operations(struct pernet_operations *ops) struct net *net; list_del(&ops->list); - for_each_net(net) - if (ops->exit) + if (ops->exit) + for_each_net(net) ops->exit(net); } |