diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 4e52921ade09..d5bf8b28bbf4 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -22,11 +22,84 @@ static struct kmem_cache *net_cachep; struct net init_net; EXPORT_SYMBOL_GPL(init_net); +/* + * setup_net runs the initializers for the network namespace object. + */ +static int setup_net(struct net *net) +{ + /* Must be called with net_mutex held */ + struct pernet_operations *ops; + int error; + + atomic_set(&net->count, 1); + atomic_set(&net->use_count, 0); + + error = 0; + list_for_each_entry(ops, &pernet_list, list) { + if (ops->init) { + error = ops->init(net); + if (error < 0) + goto out_undo; + } + } +out: + return error; + +out_undo: + /* Walk through the list backwards calling the exit functions + * for the pernet modules whose init functions did not fail. + */ + list_for_each_entry_continue_reverse(ops, &pernet_list, list) { + if (ops->exit) + ops->exit(net); + } + + rcu_barrier(); + goto out; +} + +#ifdef CONFIG_NET_NS 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; + int err; + + get_net(old_net); + + if (!(flags & CLONE_NEWNET)) + return old_net; + + err = -ENOMEM; + new_net = net_alloc(); + if (!new_net) + goto out; + + mutex_lock(&net_mutex); + err = setup_net(new_net); + if (err) + goto out_unlock; + + rtnl_lock(); + list_add_tail(&new_net->list, &net_namespace_list); + rtnl_unlock(); + + +out_unlock: + mutex_unlock(&net_mutex); +out: + put_net(old_net); + if (err) { + net_free(new_net); + new_net = ERR_PTR(err); + } + return new_net; +} + static void net_free(struct net *net) { if (!net) @@ -72,7 +145,6 @@ static void cleanup_net(struct work_struct *work) net_free(net); } - void __put_net(struct net *net) { /* Cleanup the network namespace in process context */ @@ -81,81 +153,14 @@ void __put_net(struct net *net) } EXPORT_SYMBOL_GPL(__put_net); -/* - * setup_net runs the initializers for the network namespace object. - */ -static int setup_net(struct net *net) -{ - /* Must be called with net_mutex held */ - struct pernet_operations *ops; - int error; - - atomic_set(&net->count, 1); - atomic_set(&net->use_count, 0); - - error = 0; - list_for_each_entry(ops, &pernet_list, list) { - if (ops->init) { - error = ops->init(net); - if (error < 0) - goto out_undo; - } - } -out: - return error; - -out_undo: - /* Walk through the list backwards calling the exit functions - * for the pernet modules whose init functions did not fail. - */ - list_for_each_entry_continue_reverse(ops, &pernet_list, list) { - if (ops->exit) - ops->exit(net); - } - - rcu_barrier(); - goto out; -} - +#else struct net *copy_net_ns(unsigned long flags, struct net *old_net) { - struct net *new_net = NULL; - int err; - - get_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) - goto out; - - mutex_lock(&net_mutex); - err = setup_net(new_net); - if (err) - goto out_unlock; - - rtnl_lock(); - list_add_tail(&new_net->list, &net_namespace_list); - rtnl_unlock(); - - -out_unlock: - mutex_unlock(&net_mutex); -out: - put_net(old_net); - if (err) { - net_free(new_net); - new_net = ERR_PTR(err); - } - return new_net; + if (flags & CLONE_NEWNET) + return ERR_PTR(-EINVAL); + return old_net; } +#endif static int __init net_ns_init(void) {