diff options
author | Serge E. Hallyn <serue@us.ibm.com> | 2006-10-02 05:18:08 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-02 10:57:20 -0400 |
commit | 1651e14e28a2d9f446018ef522882e0709a2ce4f (patch) | |
tree | 401ff78624fdc4b445f3f95174a223acaf6a4ca0 /kernel | |
parent | 0437eb594e6e5e699248f865482e61034be846d0 (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>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/exit.c | 4 | ||||
-rw-r--r-- | kernel/fork.c | 17 | ||||
-rw-r--r-- | kernel/nsproxy.c | 32 |
3 files changed, 37 insertions, 16 deletions
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(¤t->sighand->siglock); | 1213 | spin_unlock(¤t->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 | ||
1266 | bad_fork_cleanup_namespace: | ||
1267 | exit_namespace(p); | ||
1268 | bad_fork_cleanup_namespaces: | 1264 | bad_fork_cleanup_namespaces: |
1269 | exit_task_namespaces(p); | 1265 | exit_task_namespaces(p); |
1270 | bad_fork_cleanup_keys: | 1266 | bad_fork_cleanup_keys: |
@@ -1519,10 +1515,9 @@ static int unshare_fs(unsigned long unshare_flags, struct fs_struct **new_fsp) | |||
1519 | */ | 1515 | */ |
1520 | static int unshare_namespace(unsigned long unshare_flags, struct namespace **new_nsp, struct fs_struct *new_fs) | 1516 | static 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 | ||
17 | struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); | 18 | struct 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) | |||
65 | int copy_namespaces(int flags, struct task_struct *tsk) | 71 | int 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 | |||
100 | out: | ||
101 | put_nsproxy(old_ns); | ||
102 | return err; | ||
75 | } | 103 | } |
76 | 104 | ||
77 | void free_nsproxy(struct nsproxy *ns) | 105 | void free_nsproxy(struct nsproxy *ns) |
78 | { | 106 | { |
107 | if (ns->namespace) | ||
108 | put_namespace(ns->namespace); | ||
79 | kfree(ns); | 109 | kfree(ns); |
80 | } | 110 | } |