]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - net/core/net_namespace.c
Merge branch 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux...
[karo-tx-linux.git] / net / core / net_namespace.c
index 2e2dce6583e14f10c786ecf81b4042cacf3593ae..ea489db1bc2361c20001576a5e909aa22cb689d2 100644 (file)
@@ -8,6 +8,8 @@
 #include <linux/idr.h>
 #include <linux/rculist.h>
 #include <linux/nsproxy.h>
+#include <linux/proc_fs.h>
+#include <linux/file.h>
 #include <net/net_namespace.h>
 #include <net/netns/generic.h>
 
@@ -126,6 +128,7 @@ static __net_init int setup_net(struct net *net)
        LIST_HEAD(net_exit_list);
 
        atomic_set(&net->count, 1);
+       atomic_set(&net->passive, 1);
 
 #ifdef NETNS_REFCNT_DEBUG
        atomic_set(&net->use_count, 0);
@@ -208,6 +211,13 @@ static void net_free(struct net *net)
        kmem_cache_free(net_cachep, net);
 }
 
+void net_drop_ns(void *p)
+{
+       struct net *ns = p;
+       if (ns && atomic_dec_and_test(&ns->passive))
+               net_free(ns);
+}
+
 struct net *copy_net_ns(unsigned long flags, struct net *old_net)
 {
        struct net *net;
@@ -228,7 +238,7 @@ struct net *copy_net_ns(unsigned long flags, struct net *old_net)
        }
        mutex_unlock(&net_mutex);
        if (rv < 0) {
-               net_free(net);
+               net_drop_ns(net);
                return ERR_PTR(rv);
        }
        return net;
@@ -284,7 +294,7 @@ static void cleanup_net(struct work_struct *work)
        /* Finally it is safe to free my network namespace structure */
        list_for_each_entry_safe(net, tmp, &net_exit_list, exit_list) {
                list_del_init(&net->exit_list);
-               net_free(net);
+               net_drop_ns(net);
        }
 }
 static DECLARE_WORK(net_cleanup_work, cleanup_net);
@@ -302,6 +312,26 @@ void __put_net(struct net *net)
 }
 EXPORT_SYMBOL_GPL(__put_net);
 
+struct net *get_net_ns_by_fd(int fd)
+{
+       struct proc_inode *ei;
+       struct file *file;
+       struct net *net;
+
+       file = proc_ns_fget(fd);
+       if (IS_ERR(file))
+               return ERR_CAST(file);
+
+       ei = PROC_I(file->f_dentry->d_inode);
+       if (ei->ns_ops == &netns_operations)
+               net = get_net(ei->ns);
+       else
+               net = ERR_PTR(-EINVAL);
+
+       fput(file);
+       return net;
+}
+
 #else
 struct net *copy_net_ns(unsigned long flags, struct net *old_net)
 {
@@ -309,6 +339,11 @@ struct net *copy_net_ns(unsigned long flags, struct net *old_net)
                return ERR_PTR(-EINVAL);
        return old_net;
 }
+
+struct net *get_net_ns_by_fd(int fd)
+{
+       return ERR_PTR(-EINVAL);
+}
 #endif
 
 struct net *get_net_ns_by_pid(pid_t pid)
@@ -561,3 +596,39 @@ void unregister_pernet_device(struct pernet_operations *ops)
        mutex_unlock(&net_mutex);
 }
 EXPORT_SYMBOL_GPL(unregister_pernet_device);
+
+#ifdef CONFIG_NET_NS
+static void *netns_get(struct task_struct *task)
+{
+       struct net *net = NULL;
+       struct nsproxy *nsproxy;
+
+       rcu_read_lock();
+       nsproxy = task_nsproxy(task);
+       if (nsproxy)
+               net = get_net(nsproxy->net_ns);
+       rcu_read_unlock();
+
+       return net;
+}
+
+static void netns_put(void *ns)
+{
+       put_net(ns);
+}
+
+static int netns_install(struct nsproxy *nsproxy, void *ns)
+{
+       put_net(nsproxy->net_ns);
+       nsproxy->net_ns = get_net(ns);
+       return 0;
+}
+
+const struct proc_ns_operations netns_operations = {
+       .name           = "net",
+       .type           = CLONE_NEWNET,
+       .get            = netns_get,
+       .put            = netns_put,
+       .install        = netns_install,
+};
+#endif