aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSerge E. Hallyn <serue@us.ibm.com>2006-10-02 05:18:08 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-02 10:57:20 -0400
commit1651e14e28a2d9f446018ef522882e0709a2ce4f (patch)
tree401ff78624fdc4b445f3f95174a223acaf6a4ca0
parent0437eb594e6e5e699248f865482e61034be846d0 (diff)
[PATCH] namespaces: incorporate fs namespace into nsproxy
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>
-rw-r--r--fs/namespace.c22
-rw-r--r--fs/proc/base.c5
-rw-r--r--include/linux/init_task.h1
-rw-r--r--include/linux/namespace.h6
-rw-r--r--include/linux/nsproxy.h3
-rw-r--r--include/linux/sched.h4
-rw-r--r--kernel/exit.c4
-rw-r--r--kernel/fork.c17
-rw-r--r--kernel/nsproxy.c32
9 files changed, 55 insertions, 39 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index 66d921e14fee..55442a6cf221 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -133,7 +133,7 @@ struct vfsmount *lookup_mnt(struct vfsmount *mnt, struct dentry *dentry)
133 133
134static inline int check_mnt(struct vfsmount *mnt) 134static inline int check_mnt(struct vfsmount *mnt)
135{ 135{
136 return mnt->mnt_namespace == current->namespace; 136 return mnt->mnt_namespace == current->nsproxy->namespace;
137} 137}
138 138
139static void touch_namespace(struct namespace *ns) 139static void touch_namespace(struct namespace *ns)
@@ -830,7 +830,7 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt,
830 if (parent_nd) { 830 if (parent_nd) {
831 detach_mnt(source_mnt, parent_nd); 831 detach_mnt(source_mnt, parent_nd);
832 attach_mnt(source_mnt, nd); 832 attach_mnt(source_mnt, nd);
833 touch_namespace(current->namespace); 833 touch_namespace(current->nsproxy->namespace);
834 } else { 834 } else {
835 mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt); 835 mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt);
836 commit_tree(source_mnt); 836 commit_tree(source_mnt);
@@ -1441,7 +1441,7 @@ dput_out:
1441 */ 1441 */
1442struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs) 1442struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs)
1443{ 1443{
1444 struct namespace *namespace = tsk->namespace; 1444 struct namespace *namespace = tsk->nsproxy->namespace;
1445 struct namespace *new_ns; 1445 struct namespace *new_ns;
1446 struct vfsmount *rootmnt = NULL, *pwdmnt = NULL, *altrootmnt = NULL; 1446 struct vfsmount *rootmnt = NULL, *pwdmnt = NULL, *altrootmnt = NULL;
1447 struct vfsmount *p, *q; 1447 struct vfsmount *p, *q;
@@ -1508,7 +1508,7 @@ struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs)
1508 1508
1509int copy_namespace(int flags, struct task_struct *tsk) 1509int copy_namespace(int flags, struct task_struct *tsk)
1510{ 1510{
1511 struct namespace *namespace = tsk->namespace; 1511 struct namespace *namespace = tsk->nsproxy->namespace;
1512 struct namespace *new_ns; 1512 struct namespace *new_ns;
1513 int err = 0; 1513 int err = 0;
1514 1514
@@ -1531,7 +1531,7 @@ int copy_namespace(int flags, struct task_struct *tsk)
1531 goto out; 1531 goto out;
1532 } 1532 }
1533 1533
1534 tsk->namespace = new_ns; 1534 tsk->nsproxy->namespace = new_ns;
1535 1535
1536out: 1536out:
1537 put_namespace(namespace); 1537 put_namespace(namespace);
@@ -1754,7 +1754,7 @@ asmlinkage long sys_pivot_root(const char __user * new_root,
1754 detach_mnt(user_nd.mnt, &root_parent); 1754 detach_mnt(user_nd.mnt, &root_parent);
1755 attach_mnt(user_nd.mnt, &old_nd); /* mount old root on put_old */ 1755 attach_mnt(user_nd.mnt, &old_nd); /* mount old root on put_old */
1756 attach_mnt(new_nd.mnt, &root_parent); /* mount new_root on / */ 1756 attach_mnt(new_nd.mnt, &root_parent); /* mount new_root on / */
1757 touch_namespace(current->namespace); 1757 touch_namespace(current->nsproxy->namespace);
1758 spin_unlock(&vfsmount_lock); 1758 spin_unlock(&vfsmount_lock);
1759 chroot_fs_refs(&user_nd, &new_nd); 1759 chroot_fs_refs(&user_nd, &new_nd);
1760 security_sb_post_pivotroot(&user_nd, &new_nd); 1760 security_sb_post_pivotroot(&user_nd, &new_nd);
@@ -1780,7 +1780,6 @@ static void __init init_mount_tree(void)
1780{ 1780{
1781 struct vfsmount *mnt; 1781 struct vfsmount *mnt;
1782 struct namespace *namespace; 1782 struct namespace *namespace;
1783 struct task_struct *g, *p;
1784 1783
1785 mnt = do_kern_mount("rootfs", 0, "rootfs", NULL); 1784 mnt = do_kern_mount("rootfs", 0, "rootfs", NULL);
1786 if (IS_ERR(mnt)) 1785 if (IS_ERR(mnt))
@@ -1796,13 +1795,8 @@ static void __init init_mount_tree(void)
1796 namespace->root = mnt; 1795 namespace->root = mnt;
1797 mnt->mnt_namespace = namespace; 1796 mnt->mnt_namespace = namespace;
1798 1797
1799 init_task.namespace = namespace; 1798 init_task.nsproxy->namespace = namespace;
1800 read_lock(&tasklist_lock); 1799 get_namespace(namespace);
1801 do_each_thread(g, p) {
1802 get_namespace(namespace);
1803 p->namespace = namespace;
1804 } while_each_thread(g, p);
1805 read_unlock(&tasklist_lock);
1806 1800
1807 set_fs_pwd(current->fs, namespace->root, namespace->root->mnt_root); 1801 set_fs_pwd(current->fs, namespace->root, namespace->root->mnt_root);
1808 set_fs_root(current->fs, namespace->root, namespace->root->mnt_root); 1802 set_fs_root(current->fs, namespace->root, namespace->root->mnt_root);
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 9c6a809f92b6..6d00ccc48c1c 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -71,6 +71,7 @@
71#include <linux/cpuset.h> 71#include <linux/cpuset.h>
72#include <linux/audit.h> 72#include <linux/audit.h>
73#include <linux/poll.h> 73#include <linux/poll.h>
74#include <linux/nsproxy.h>
74#include "internal.h" 75#include "internal.h"
75 76
76/* NOTE: 77/* NOTE:
@@ -473,7 +474,7 @@ static int mounts_open(struct inode *inode, struct file *file)
473 474
474 if (task) { 475 if (task) {
475 task_lock(task); 476 task_lock(task);
476 namespace = task->namespace; 477 namespace = task->nsproxy->namespace;
477 if (namespace) 478 if (namespace)
478 get_namespace(namespace); 479 get_namespace(namespace);
479 task_unlock(task); 480 task_unlock(task);
@@ -544,7 +545,7 @@ static int mountstats_open(struct inode *inode, struct file *file)
544 545
545 if (task) { 546 if (task) {
546 task_lock(task); 547 task_lock(task);
547 namespace = task->namespace; 548 namespace = task->nsproxy->namespace;
548 if (namespace) 549 if (namespace)
549 get_namespace(namespace); 550 get_namespace(namespace);
550 task_unlock(task); 551 task_unlock(task);
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 8f8bb422a5c7..4865348ca8bd 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -72,6 +72,7 @@ extern struct nsproxy init_nsproxy;
72#define INIT_NSPROXY(nsproxy) { \ 72#define INIT_NSPROXY(nsproxy) { \
73 .count = ATOMIC_INIT(1), \ 73 .count = ATOMIC_INIT(1), \
74 .nslock = SPIN_LOCK_UNLOCKED, \ 74 .nslock = SPIN_LOCK_UNLOCKED, \
75 .namespace = NULL, \
75} 76}
76 77
77#define INIT_SIGHAND(sighand) { \ 78#define INIT_SIGHAND(sighand) { \
diff --git a/include/linux/namespace.h b/include/linux/namespace.h
index 3abc8e3b4879..d137009f0b2b 100644
--- a/include/linux/namespace.h
+++ b/include/linux/namespace.h
@@ -4,6 +4,7 @@
4 4
5#include <linux/mount.h> 5#include <linux/mount.h>
6#include <linux/sched.h> 6#include <linux/sched.h>
7#include <linux/nsproxy.h>
7 8
8struct namespace { 9struct namespace {
9 atomic_t count; 10 atomic_t count;
@@ -26,11 +27,8 @@ static inline void put_namespace(struct namespace *namespace)
26 27
27static inline void exit_namespace(struct task_struct *p) 28static inline void exit_namespace(struct task_struct *p)
28{ 29{
29 struct namespace *namespace = p->namespace; 30 struct namespace *namespace = p->nsproxy->namespace;
30 if (namespace) { 31 if (namespace) {
31 task_lock(p);
32 p->namespace = NULL;
33 task_unlock(p);
34 put_namespace(namespace); 32 put_namespace(namespace);
35 } 33 }
36} 34}
diff --git a/include/linux/nsproxy.h b/include/linux/nsproxy.h
index 7bdebfaab6a5..7ebe66670c59 100644
--- a/include/linux/nsproxy.h
+++ b/include/linux/nsproxy.h
@@ -4,6 +4,8 @@
4#include <linux/spinlock.h> 4#include <linux/spinlock.h>
5#include <linux/sched.h> 5#include <linux/sched.h>
6 6
7struct namespace;
8
7/* 9/*
8 * A structure to contain pointers to all per-process 10 * A structure to contain pointers to all per-process
9 * namespaces - fs (mount), uts, network, sysvipc, etc. 11 * namespaces - fs (mount), uts, network, sysvipc, etc.
@@ -19,6 +21,7 @@
19struct nsproxy { 21struct nsproxy {
20 atomic_t count; 22 atomic_t count;
21 spinlock_t nslock; 23 spinlock_t nslock;
24 struct namespace *namespace;
22}; 25};
23extern struct nsproxy init_nsproxy; 26extern struct nsproxy init_nsproxy;
24 27
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 4fa631fa55e3..670b89a20070 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -238,7 +238,6 @@ extern signed long schedule_timeout_interruptible(signed long timeout);
238extern signed long schedule_timeout_uninterruptible(signed long timeout); 238extern signed long schedule_timeout_uninterruptible(signed long timeout);
239asmlinkage void schedule(void); 239asmlinkage void schedule(void);
240 240
241struct namespace;
242struct nsproxy; 241struct nsproxy;
243 242
244/* Maximum number of active map areas.. This is a random (large) number */ 243/* Maximum number of active map areas.. This is a random (large) number */
@@ -897,8 +896,7 @@ struct task_struct {
897 struct fs_struct *fs; 896 struct fs_struct *fs;
898/* open file information */ 897/* open file information */
899 struct files_struct *files; 898 struct files_struct *files;
900/* namespace */ 899/* namespaces */
901 struct namespace *namespace;
902 struct nsproxy *nsproxy; 900 struct nsproxy *nsproxy;
903/* signal handlers */ 901/* signal handlers */
904 struct signal_struct *signal; 902 struct signal_struct *signal;
diff --git a/kernel/exit.c b/kernel/exit.c
index 1d0e9ea1fa05..741bbe42dfe8 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -399,11 +399,8 @@ void daemonize(const char *name, ...)
399 current->fs = fs; 399 current->fs = fs;
400 atomic_inc(&fs->count); 400 atomic_inc(&fs->count);
401 401
402 exit_namespace(current);
403 exit_task_namespaces(current); 402 exit_task_namespaces(current);
404 current->namespace = init_task.namespace;
405 current->nsproxy = init_task.nsproxy; 403 current->nsproxy = init_task.nsproxy;
406 get_namespace(current->namespace);
407 get_task_namespaces(current); 404 get_task_namespaces(current);
408 405
409 exit_files(current); 406 exit_files(current);
@@ -923,7 +920,6 @@ fastcall NORET_TYPE void do_exit(long code)
923 exit_sem(tsk); 920 exit_sem(tsk);
924 __exit_files(tsk); 921 __exit_files(tsk);
925 __exit_fs(tsk); 922 __exit_fs(tsk);
926 exit_namespace(tsk);
927 exit_task_namespaces(tsk); 923 exit_task_namespaces(tsk);
928 exit_thread(); 924 exit_thread();
929 cpuset_exit(tsk); 925 cpuset_exit(tsk);
diff --git a/kernel/fork.c b/kernel/fork.c
index c9e660ae47aa..33fcf0733ca6 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1119,11 +1119,9 @@ static struct task_struct *copy_process(unsigned long clone_flags,
1119 goto bad_fork_cleanup_mm; 1119 goto bad_fork_cleanup_mm;
1120 if ((retval = copy_namespaces(clone_flags, p))) 1120 if ((retval = copy_namespaces(clone_flags, p)))
1121 goto bad_fork_cleanup_keys; 1121 goto bad_fork_cleanup_keys;
1122 if ((retval = copy_namespace(clone_flags, p)))
1123 goto bad_fork_cleanup_namespaces;
1124 retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs); 1122 retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs);
1125 if (retval) 1123 if (retval)
1126 goto bad_fork_cleanup_namespace; 1124 goto bad_fork_cleanup_namespaces;
1127 1125
1128 p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL; 1126 p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL;
1129 /* 1127 /*
@@ -1215,7 +1213,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
1215 spin_unlock(&current->sighand->siglock); 1213 spin_unlock(&current->sighand->siglock);
1216 write_unlock_irq(&tasklist_lock); 1214 write_unlock_irq(&tasklist_lock);
1217 retval = -ERESTARTNOINTR; 1215 retval = -ERESTARTNOINTR;
1218 goto bad_fork_cleanup_namespace; 1216 goto bad_fork_cleanup_namespaces;
1219 } 1217 }
1220 1218
1221 if (clone_flags & CLONE_THREAD) { 1219 if (clone_flags & CLONE_THREAD) {
@@ -1263,8 +1261,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
1263 proc_fork_connector(p); 1261 proc_fork_connector(p);
1264 return p; 1262 return p;
1265 1263
1266bad_fork_cleanup_namespace:
1267 exit_namespace(p);
1268bad_fork_cleanup_namespaces: 1264bad_fork_cleanup_namespaces:
1269 exit_task_namespaces(p); 1265 exit_task_namespaces(p);
1270bad_fork_cleanup_keys: 1266bad_fork_cleanup_keys:
@@ -1519,10 +1515,9 @@ static int unshare_fs(unsigned long unshare_flags, struct fs_struct **new_fsp)
1519 */ 1515 */
1520static int unshare_namespace(unsigned long unshare_flags, struct namespace **new_nsp, struct fs_struct *new_fs) 1516static int unshare_namespace(unsigned long unshare_flags, struct namespace **new_nsp, struct fs_struct *new_fs)
1521{ 1517{
1522 struct namespace *ns = current->namespace; 1518 struct namespace *ns = current->nsproxy->namespace;
1523 1519
1524 if ((unshare_flags & CLONE_NEWNS) && 1520 if ((unshare_flags & CLONE_NEWNS) && ns) {
1525 (ns && atomic_read(&ns->count) > 1)) {
1526 if (!capable(CAP_SYS_ADMIN)) 1521 if (!capable(CAP_SYS_ADMIN))
1527 return -EPERM; 1522 return -EPERM;
1528 1523
@@ -1655,8 +1650,8 @@ asmlinkage long sys_unshare(unsigned long unshare_flags)
1655 } 1650 }
1656 1651
1657 if (new_ns) { 1652 if (new_ns) {
1658 ns = current->namespace; 1653 ns = current->nsproxy->namespace;
1659 current->namespace = new_ns; 1654 current->nsproxy->namespace = new_ns;
1660 new_ns = ns; 1655 new_ns = ns;
1661 } 1656 }
1662 1657
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c
index a3612f82f187..e10385c17f73 100644
--- a/kernel/nsproxy.c
+++ b/kernel/nsproxy.c
@@ -13,6 +13,7 @@
13#include <linux/version.h> 13#include <linux/version.h>
14#include <linux/nsproxy.h> 14#include <linux/nsproxy.h>
15#include <linux/init_task.h> 15#include <linux/init_task.h>
16#include <linux/namespace.h>
16 17
17struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); 18struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy);
18 19
@@ -55,6 +56,11 @@ struct nsproxy *dup_namespaces(struct nsproxy *orig)
55{ 56{
56 struct nsproxy *ns = clone_namespaces(orig); 57 struct nsproxy *ns = clone_namespaces(orig);
57 58
59 if (ns) {
60 if (ns->namespace)
61 get_namespace(ns->namespace);
62 }
63
58 return ns; 64 return ns;
59} 65}
60 66
@@ -65,16 +71,40 @@ struct nsproxy *dup_namespaces(struct nsproxy *orig)
65int copy_namespaces(int flags, struct task_struct *tsk) 71int copy_namespaces(int flags, struct task_struct *tsk)
66{ 72{
67 struct nsproxy *old_ns = tsk->nsproxy; 73 struct nsproxy *old_ns = tsk->nsproxy;
74 struct nsproxy *new_ns;
75 int err = 0;
68 76
69 if (!old_ns) 77 if (!old_ns)
70 return 0; 78 return 0;
71 79
72 get_nsproxy(old_ns); 80 get_nsproxy(old_ns);
73 81
74 return 0; 82 if (!(flags & CLONE_NEWNS))
83 return 0;
84
85 new_ns = clone_namespaces(old_ns);
86 if (!new_ns) {
87 err = -ENOMEM;
88 goto out;
89 }
90
91 tsk->nsproxy = new_ns;
92
93 err = copy_namespace(flags, tsk);
94 if (err) {
95 tsk->nsproxy = old_ns;
96 put_nsproxy(new_ns);
97 goto out;
98 }
99
100out:
101 put_nsproxy(old_ns);
102 return err;
75} 103}
76 104
77void free_nsproxy(struct nsproxy *ns) 105void free_nsproxy(struct nsproxy *ns)
78{ 106{
107 if (ns->namespace)
108 put_namespace(ns->namespace);
79 kfree(ns); 109 kfree(ns);
80} 110}