[PATCH] namespaces: incorporate fs namespace into nsproxy
Serge E. Hallyn [Mon, 2 Oct 2006 09:18:08 +0000 (02:18 -0700)]
This moves the mount namespace into the nsproxy.  The mount namespace count
now refers to the number of nsproxies point to it, rather than the number of
tasks.  As a result, the unshare_namespace() function in kernel/fork.c no
longer checks whether it is being shared.

Signed-off-by: Serge Hallyn <serue@us.ibm.com>
Cc: Kirill Korotaev <dev@openvz.org>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Herbert Poetzl <herbert@13thfloor.at>
Cc: Andrey Savochkin <saw@sw.ru>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

fs/namespace.c
fs/proc/base.c
include/linux/init_task.h
include/linux/namespace.h
include/linux/nsproxy.h
include/linux/sched.h
kernel/exit.c
kernel/fork.c
kernel/nsproxy.c

index 66d921e..55442a6 100644 (file)
@@ -133,7 +133,7 @@ struct vfsmount *lookup_mnt(struct vfsmount *mnt, struct dentry *dentry)
 
 static inline int check_mnt(struct vfsmount *mnt)
 {
-       return mnt->mnt_namespace == current->namespace;
+       return mnt->mnt_namespace == current->nsproxy->namespace;
 }
 
 static void touch_namespace(struct namespace *ns)
@@ -830,7 +830,7 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt,
        if (parent_nd) {
                detach_mnt(source_mnt, parent_nd);
                attach_mnt(source_mnt, nd);
-               touch_namespace(current->namespace);
+               touch_namespace(current->nsproxy->namespace);
        } else {
                mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt);
                commit_tree(source_mnt);
@@ -1441,7 +1441,7 @@ dput_out:
  */
 struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs)
 {
-       struct namespace *namespace = tsk->namespace;
+       struct namespace *namespace = tsk->nsproxy->namespace;
        struct namespace *new_ns;
        struct vfsmount *rootmnt = NULL, *pwdmnt = NULL, *altrootmnt = NULL;
        struct vfsmount *p, *q;
@@ -1508,7 +1508,7 @@ struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs)
 
 int copy_namespace(int flags, struct task_struct *tsk)
 {
-       struct namespace *namespace = tsk->namespace;
+       struct namespace *namespace = tsk->nsproxy->namespace;
        struct namespace *new_ns;
        int err = 0;
 
@@ -1531,7 +1531,7 @@ int copy_namespace(int flags, struct task_struct *tsk)
                goto out;
        }
 
-       tsk->namespace = new_ns;
+       tsk->nsproxy->namespace = new_ns;
 
 out:
        put_namespace(namespace);
@@ -1754,7 +1754,7 @@ asmlinkage long sys_pivot_root(const char __user * new_root,
        detach_mnt(user_nd.mnt, &root_parent);
        attach_mnt(user_nd.mnt, &old_nd);     /* mount old root on put_old */
        attach_mnt(new_nd.mnt, &root_parent); /* mount new_root on / */
-       touch_namespace(current->namespace);
+       touch_namespace(current->nsproxy->namespace);
        spin_unlock(&vfsmount_lock);
        chroot_fs_refs(&user_nd, &new_nd);
        security_sb_post_pivotroot(&user_nd, &new_nd);
@@ -1780,7 +1780,6 @@ static void __init init_mount_tree(void)
 {
        struct vfsmount *mnt;
        struct namespace *namespace;
-       struct task_struct *g, *p;
 
        mnt = do_kern_mount("rootfs", 0, "rootfs", NULL);
        if (IS_ERR(mnt))
@@ -1796,13 +1795,8 @@ static void __init init_mount_tree(void)
        namespace->root = mnt;
        mnt->mnt_namespace = namespace;
 
-       init_task.namespace = namespace;
-       read_lock(&tasklist_lock);
-       do_each_thread(g, p) {
-               get_namespace(namespace);
-               p->namespace = namespace;
-       } while_each_thread(g, p);
-       read_unlock(&tasklist_lock);
+       init_task.nsproxy->namespace = namespace;
+       get_namespace(namespace);
 
        set_fs_pwd(current->fs, namespace->root, namespace->root->mnt_root);
        set_fs_root(current->fs, namespace->root, namespace->root->mnt_root);
index 9c6a809..6d00ccc 100644 (file)
@@ -71,6 +71,7 @@
 #include <linux/cpuset.h>
 #include <linux/audit.h>
 #include <linux/poll.h>
+#include <linux/nsproxy.h>
 #include "internal.h"
 
 /* NOTE:
@@ -473,7 +474,7 @@ static int mounts_open(struct inode *inode, struct file *file)
 
        if (task) {
                task_lock(task);
-               namespace = task->namespace;
+               namespace = task->nsproxy->namespace;
                if (namespace)
                        get_namespace(namespace);
                task_unlock(task);
@@ -544,7 +545,7 @@ static int mountstats_open(struct inode *inode, struct file *file)
 
                if (task) {
                        task_lock(task);
-                       namespace = task->namespace;
+                       namespace = task->nsproxy->namespace;
                        if (namespace)
                                get_namespace(namespace);
                        task_unlock(task);
index 8f8bb42..4865348 100644 (file)
@@ -72,6 +72,7 @@ extern struct nsproxy init_nsproxy;
 #define INIT_NSPROXY(nsproxy) {                                                \
        .count          = ATOMIC_INIT(1),                               \
        .nslock         = SPIN_LOCK_UNLOCKED,                           \
+       .namespace      = NULL,                                         \
 }
 
 #define INIT_SIGHAND(sighand) {                                                \
index 3abc8e3..d137009 100644 (file)
@@ -4,6 +4,7 @@
 
 #include <linux/mount.h>
 #include <linux/sched.h>
+#include <linux/nsproxy.h>
 
 struct namespace {
        atomic_t                count;
@@ -26,11 +27,8 @@ static inline void put_namespace(struct namespace *namespace)
 
 static inline void exit_namespace(struct task_struct *p)
 {
-       struct namespace *namespace = p->namespace;
+       struct namespace *namespace = p->nsproxy->namespace;
        if (namespace) {
-               task_lock(p);
-               p->namespace = NULL;
-               task_unlock(p);
                put_namespace(namespace);
        }
 }
index 7bdebfa..7ebe666 100644 (file)
@@ -4,6 +4,8 @@
 #include <linux/spinlock.h>
 #include <linux/sched.h>
 
+struct namespace;
+
 /*
  * A structure to contain pointers to all per-process
  * namespaces - fs (mount), uts, network, sysvipc, etc.
@@ -19,6 +21,7 @@
 struct nsproxy {
        atomic_t count;
        spinlock_t nslock;
+       struct namespace *namespace;
 };
 extern struct nsproxy init_nsproxy;
 
index 4fa631f..670b89a 100644 (file)
@@ -238,7 +238,6 @@ extern signed long schedule_timeout_interruptible(signed long timeout);
 extern signed long schedule_timeout_uninterruptible(signed long timeout);
 asmlinkage void schedule(void);
 
-struct namespace;
 struct nsproxy;
 
 /* Maximum number of active map areas.. This is a random (large) number */
@@ -897,8 +896,7 @@ struct task_struct {
        struct fs_struct *fs;
 /* open file information */
        struct files_struct *files;
-/* namespace */
-       struct namespace *namespace;
+/* namespaces */
        struct nsproxy *nsproxy;
 /* signal handlers */
        struct signal_struct *signal;
index 1d0e9ea..741bbe4 100644 (file)
@@ -399,11 +399,8 @@ void daemonize(const char *name, ...)
        current->fs = fs;
        atomic_inc(&fs->count);
 
-       exit_namespace(current);
        exit_task_namespaces(current);
-       current->namespace = init_task.namespace;
        current->nsproxy = init_task.nsproxy;
-       get_namespace(current->namespace);
        get_task_namespaces(current);
 
        exit_files(current);
@@ -923,7 +920,6 @@ fastcall NORET_TYPE void do_exit(long code)
        exit_sem(tsk);
        __exit_files(tsk);
        __exit_fs(tsk);
-       exit_namespace(tsk);
        exit_task_namespaces(tsk);
        exit_thread();
        cpuset_exit(tsk);
index c9e660a..33fcf07 100644 (file)
@@ -1119,11 +1119,9 @@ static struct task_struct *copy_process(unsigned long clone_flags,
                goto bad_fork_cleanup_mm;
        if ((retval = copy_namespaces(clone_flags, p)))
                goto bad_fork_cleanup_keys;
-       if ((retval = copy_namespace(clone_flags, p)))
-               goto bad_fork_cleanup_namespaces;
        retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs);
        if (retval)
-               goto bad_fork_cleanup_namespace;
+               goto bad_fork_cleanup_namespaces;
 
        p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL;
        /*
@@ -1215,7 +1213,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
                spin_unlock(&current->sighand->siglock);
                write_unlock_irq(&tasklist_lock);
                retval = -ERESTARTNOINTR;
-               goto bad_fork_cleanup_namespace;
+               goto bad_fork_cleanup_namespaces;
        }
 
        if (clone_flags & CLONE_THREAD) {
@@ -1263,8 +1261,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        proc_fork_connector(p);
        return p;
 
-bad_fork_cleanup_namespace:
-       exit_namespace(p);
 bad_fork_cleanup_namespaces:
        exit_task_namespaces(p);
 bad_fork_cleanup_keys:
@@ -1519,10 +1515,9 @@ static int unshare_fs(unsigned long unshare_flags, struct fs_struct **new_fsp)
  */
 static int unshare_namespace(unsigned long unshare_flags, struct namespace **new_nsp, struct fs_struct *new_fs)
 {
-       struct namespace *ns = current->namespace;
+       struct namespace *ns = current->nsproxy->namespace;
 
-       if ((unshare_flags & CLONE_NEWNS) &&
-           (ns && atomic_read(&ns->count) > 1)) {
+       if ((unshare_flags & CLONE_NEWNS) && ns) {
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
 
@@ -1655,8 +1650,8 @@ asmlinkage long sys_unshare(unsigned long unshare_flags)
                }
 
                if (new_ns) {
-                       ns = current->namespace;
-                       current->namespace = new_ns;
+                       ns = current->nsproxy->namespace;
+                       current->nsproxy->namespace = new_ns;
                        new_ns = ns;
                }
 
index a3612f8..e10385c 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/version.h>
 #include <linux/nsproxy.h>
 #include <linux/init_task.h>
+#include <linux/namespace.h>
 
 struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy);
 
@@ -55,6 +56,11 @@ struct nsproxy *dup_namespaces(struct nsproxy *orig)
 {
        struct nsproxy *ns = clone_namespaces(orig);
 
+       if (ns) {
+               if (ns->namespace)
+                       get_namespace(ns->namespace);
+       }
+
        return ns;
 }
 
@@ -65,16 +71,40 @@ struct nsproxy *dup_namespaces(struct nsproxy *orig)
 int copy_namespaces(int flags, struct task_struct *tsk)
 {
        struct nsproxy *old_ns = tsk->nsproxy;
+       struct nsproxy *new_ns;
+       int err = 0;
 
        if (!old_ns)
                return 0;
 
        get_nsproxy(old_ns);
 
-       return 0;
+       if (!(flags & CLONE_NEWNS))
+               return 0;
+
+       new_ns = clone_namespaces(old_ns);
+       if (!new_ns) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       tsk->nsproxy = new_ns;
+
+       err = copy_namespace(flags, tsk);
+       if (err) {
+               tsk->nsproxy = old_ns;
+               put_nsproxy(new_ns);
+               goto out;
+       }
+
+out:
+       put_nsproxy(old_ns);
+       return err;
 }
 
 void free_nsproxy(struct nsproxy *ns)
 {
+               if (ns->namespace)
+                       put_namespace(ns->namespace);
                kfree(ns);
 }