aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/net_namespace.c
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2011-07-27 03:54:47 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2011-07-27 03:54:47 -0400
commitaa7eb8e78d8ecd6cd0475d86ea8385ff9cb47ece (patch)
tree3f9e98fadd5124fb05e8f6f9b06aa23698d4f215 /net/core/net_namespace.c
parentcca8edfd2ec2a34d9f50f593bc753bb11e1bc1f5 (diff)
parent3c6b50141ef9f0a8844bf1357b80c0cdf518bf05 (diff)
Merge branch 'next' into for-linus
Diffstat (limited to 'net/core/net_namespace.c')
-rw-r--r--net/core/net_namespace.c97
1 files changed, 78 insertions, 19 deletions
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 3f860261c5ee..ea489db1bc23 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -8,6 +8,8 @@
8#include <linux/idr.h> 8#include <linux/idr.h>
9#include <linux/rculist.h> 9#include <linux/rculist.h>
10#include <linux/nsproxy.h> 10#include <linux/nsproxy.h>
11#include <linux/proc_fs.h>
12#include <linux/file.h>
11#include <net/net_namespace.h> 13#include <net/net_namespace.h>
12#include <net/netns/generic.h> 14#include <net/netns/generic.h>
13 15
@@ -27,14 +29,6 @@ EXPORT_SYMBOL(init_net);
27 29
28#define INITIAL_NET_GEN_PTRS 13 /* +1 for len +2 for rcu_head */ 30#define INITIAL_NET_GEN_PTRS 13 /* +1 for len +2 for rcu_head */
29 31
30static 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
38static int net_assign_generic(struct net *net, int id, void *data) 32static int net_assign_generic(struct net *net, int id, void *data)
39{ 33{
40 struct net_generic *ng, *old_ng; 34 struct net_generic *ng, *old_ng;
@@ -68,7 +62,7 @@ static int net_assign_generic(struct net *net, int id, void *data)
68 memcpy(&ng->ptr, &old_ng->ptr, old_ng->len * sizeof(void*)); 62 memcpy(&ng->ptr, &old_ng->ptr, old_ng->len * sizeof(void*));
69 63
70 rcu_assign_pointer(net->gen, ng); 64 rcu_assign_pointer(net->gen, ng);
71 call_rcu(&old_ng->rcu, net_generic_release); 65 kfree_rcu(old_ng, rcu);
72assign: 66assign:
73 ng->ptr[id - 1] = data; 67 ng->ptr[id - 1] = data;
74 return 0; 68 return 0;
@@ -134,6 +128,7 @@ static __net_init int setup_net(struct net *net)
134 LIST_HEAD(net_exit_list); 128 LIST_HEAD(net_exit_list);
135 129
136 atomic_set(&net->count, 1); 130 atomic_set(&net->count, 1);
131 atomic_set(&net->passive, 1);
137 132
138#ifdef NETNS_REFCNT_DEBUG 133#ifdef NETNS_REFCNT_DEBUG
139 atomic_set(&net->use_count, 0); 134 atomic_set(&net->use_count, 0);
@@ -216,11 +211,21 @@ static void net_free(struct net *net)
216 kmem_cache_free(net_cachep, net); 211 kmem_cache_free(net_cachep, net);
217} 212}
218 213
219static struct net *net_create(void) 214void net_drop_ns(void *p)
215{
216 struct net *ns = p;
217 if (ns && atomic_dec_and_test(&ns->passive))
218 net_free(ns);
219}
220
221struct net *copy_net_ns(unsigned long flags, struct net *old_net)
220{ 222{
221 struct net *net; 223 struct net *net;
222 int rv; 224 int rv;
223 225
226 if (!(flags & CLONE_NEWNET))
227 return get_net(old_net);
228
224 net = net_alloc(); 229 net = net_alloc();
225 if (!net) 230 if (!net)
226 return ERR_PTR(-ENOMEM); 231 return ERR_PTR(-ENOMEM);
@@ -233,19 +238,12 @@ static struct net *net_create(void)
233 } 238 }
234 mutex_unlock(&net_mutex); 239 mutex_unlock(&net_mutex);
235 if (rv < 0) { 240 if (rv < 0) {
236 net_free(net); 241 net_drop_ns(net);
237 return ERR_PTR(rv); 242 return ERR_PTR(rv);
238 } 243 }
239 return net; 244 return net;
240} 245}
241 246
242struct net *copy_net_ns(unsigned long flags, struct net *old_net)
243{
244 if (!(flags & CLONE_NEWNET))
245 return get_net(old_net);
246 return net_create();
247}
248
249static DEFINE_SPINLOCK(cleanup_list_lock); 247static DEFINE_SPINLOCK(cleanup_list_lock);
250static LIST_HEAD(cleanup_list); /* Must hold cleanup_list_lock to touch */ 248static LIST_HEAD(cleanup_list); /* Must hold cleanup_list_lock to touch */
251 249
@@ -296,7 +294,7 @@ static void cleanup_net(struct work_struct *work)
296 /* Finally it is safe to free my network namespace structure */ 294 /* Finally it is safe to free my network namespace structure */
297 list_for_each_entry_safe(net, tmp, &net_exit_list, exit_list) { 295 list_for_each_entry_safe(net, tmp, &net_exit_list, exit_list) {
298 list_del_init(&net->exit_list); 296 list_del_init(&net->exit_list);
299 net_free(net); 297 net_drop_ns(net);
300 } 298 }
301} 299}
302static DECLARE_WORK(net_cleanup_work, cleanup_net); 300static DECLARE_WORK(net_cleanup_work, cleanup_net);
@@ -314,6 +312,26 @@ void __put_net(struct net *net)
314} 312}
315EXPORT_SYMBOL_GPL(__put_net); 313EXPORT_SYMBOL_GPL(__put_net);
316 314
315struct net *get_net_ns_by_fd(int fd)
316{
317 struct proc_inode *ei;
318 struct file *file;
319 struct net *net;
320
321 file = proc_ns_fget(fd);
322 if (IS_ERR(file))
323 return ERR_CAST(file);
324
325 ei = PROC_I(file->f_dentry->d_inode);
326 if (ei->ns_ops == &netns_operations)
327 net = get_net(ei->ns);
328 else
329 net = ERR_PTR(-EINVAL);
330
331 fput(file);
332 return net;
333}
334
317#else 335#else
318struct net *copy_net_ns(unsigned long flags, struct net *old_net) 336struct net *copy_net_ns(unsigned long flags, struct net *old_net)
319{ 337{
@@ -321,6 +339,11 @@ struct net *copy_net_ns(unsigned long flags, struct net *old_net)
321 return ERR_PTR(-EINVAL); 339 return ERR_PTR(-EINVAL);
322 return old_net; 340 return old_net;
323} 341}
342
343struct net *get_net_ns_by_fd(int fd)
344{
345 return ERR_PTR(-EINVAL);
346}
324#endif 347#endif
325 348
326struct net *get_net_ns_by_pid(pid_t pid) 349struct net *get_net_ns_by_pid(pid_t pid)
@@ -573,3 +596,39 @@ void unregister_pernet_device(struct pernet_operations *ops)
573 mutex_unlock(&net_mutex); 596 mutex_unlock(&net_mutex);
574} 597}
575EXPORT_SYMBOL_GPL(unregister_pernet_device); 598EXPORT_SYMBOL_GPL(unregister_pernet_device);
599
600#ifdef CONFIG_NET_NS
601static void *netns_get(struct task_struct *task)
602{
603 struct net *net = NULL;
604 struct nsproxy *nsproxy;
605
606 rcu_read_lock();
607 nsproxy = task_nsproxy(task);
608 if (nsproxy)
609 net = get_net(nsproxy->net_ns);
610 rcu_read_unlock();
611
612 return net;
613}
614
615static void netns_put(void *ns)
616{
617 put_net(ns);
618}
619
620static int netns_install(struct nsproxy *nsproxy, void *ns)
621{
622 put_net(nsproxy->net_ns);
623 nsproxy->net_ns = get_net(ns);
624 return 0;
625}
626
627const struct proc_ns_operations netns_operations = {
628 .name = "net",
629 .type = CLONE_NEWNET,
630 .get = netns_get,
631 .put = netns_put,
632 .install = netns_install,
633};
634#endif