diff options
| author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2011-07-27 03:54:47 -0400 |
|---|---|---|
| committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2011-07-27 03:54:47 -0400 |
| commit | aa7eb8e78d8ecd6cd0475d86ea8385ff9cb47ece (patch) | |
| tree | 3f9e98fadd5124fb05e8f6f9b06aa23698d4f215 /net/core/net_namespace.c | |
| parent | cca8edfd2ec2a34d9f50f593bc753bb11e1bc1f5 (diff) | |
| parent | 3c6b50141ef9f0a8844bf1357b80c0cdf518bf05 (diff) | |
Merge branch 'next' into for-linus
Diffstat (limited to 'net/core/net_namespace.c')
| -rw-r--r-- | net/core/net_namespace.c | 97 |
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 | ||
| 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) | 32 | static 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); |
| 72 | assign: | 66 | assign: |
| 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 | ||
| 219 | static struct net *net_create(void) | 214 | void 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 | |||
| 221 | struct 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 | ||
| 242 | struct 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 | |||
| 249 | static DEFINE_SPINLOCK(cleanup_list_lock); | 247 | static DEFINE_SPINLOCK(cleanup_list_lock); |
| 250 | static LIST_HEAD(cleanup_list); /* Must hold cleanup_list_lock to touch */ | 248 | static 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 | } |
| 302 | static DECLARE_WORK(net_cleanup_work, cleanup_net); | 300 | static DECLARE_WORK(net_cleanup_work, cleanup_net); |
| @@ -314,6 +312,26 @@ void __put_net(struct net *net) | |||
| 314 | } | 312 | } |
| 315 | EXPORT_SYMBOL_GPL(__put_net); | 313 | EXPORT_SYMBOL_GPL(__put_net); |
| 316 | 314 | ||
| 315 | struct 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 |
| 318 | struct net *copy_net_ns(unsigned long flags, struct net *old_net) | 336 | struct 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 | |||
| 343 | struct net *get_net_ns_by_fd(int fd) | ||
| 344 | { | ||
| 345 | return ERR_PTR(-EINVAL); | ||
| 346 | } | ||
| 324 | #endif | 347 | #endif |
| 325 | 348 | ||
| 326 | struct net *get_net_ns_by_pid(pid_t pid) | 349 | struct 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 | } |
| 575 | EXPORT_SYMBOL_GPL(unregister_pernet_device); | 598 | EXPORT_SYMBOL_GPL(unregister_pernet_device); |
| 599 | |||
| 600 | #ifdef CONFIG_NET_NS | ||
| 601 | static 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 | |||
| 615 | static void netns_put(void *ns) | ||
| 616 | { | ||
| 617 | put_net(ns); | ||
| 618 | } | ||
| 619 | |||
| 620 | static 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 | |||
| 627 | const 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 | ||
