diff options
author | Serge E. Hallyn <serue@us.ibm.com> | 2007-10-19 02:39:45 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-19 14:53:37 -0400 |
commit | 858d72ead4864da0fb0b89b919524125ce998e27 (patch) | |
tree | 19ea321ca3b505efecb2053a829daf89a6a22529 /kernel | |
parent | 846c7bb055747989891f5cd2bb6e8d56243ba1e7 (diff) |
cgroups: implement namespace tracking subsystem
When a task enters a new namespace via a clone() or unshare(), a new cgroup
is created and the task moves into it.
This version names cgroups which are automatically created using
cgroup_clone() as "node_<pid>" where pid is the pid of the unsharing or
cloned process. (Thanks Pavel for the idea) This is safe because if the
process unshares again, it will create
/cgroups/(...)/node_<pid>/node_<pid>
The only possibilities (AFAICT) for a -EEXIST on unshare are
1. pid wraparound
2. a process fails an unshare, then tries again.
Case 1 is unlikely enough that I ignore it (at least for now). In case 2, the
node_<pid> will be empty and can be rmdir'ed to make the subsequent unshare()
succeed.
Changelog:
Name cloned cgroups as "node_<pid>".
[clg@fr.ibm.com: fix order of cgroup subsystems in init/Kconfig]
Signed-off-by: Serge E. Hallyn <serue@us.ibm.com>
Cc: Paul Menage <menage@google.com>
Signed-off-by: Cedric Le Goater <clg@fr.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/Makefile | 1 | ||||
-rw-r--r-- | kernel/ns_cgroup.c | 100 | ||||
-rw-r--r-- | kernel/nsproxy.c | 17 |
3 files changed, 117 insertions, 1 deletions
diff --git a/kernel/Makefile b/kernel/Makefile index a50a6debe5fc..32b2d8bdc9f5 100644 --- a/kernel/Makefile +++ b/kernel/Makefile | |||
@@ -40,6 +40,7 @@ obj-$(CONFIG_CGROUPS) += cgroup.o | |||
40 | obj-$(CONFIG_CGROUP_DEBUG) += cgroup_debug.o | 40 | obj-$(CONFIG_CGROUP_DEBUG) += cgroup_debug.o |
41 | obj-$(CONFIG_CPUSETS) += cpuset.o | 41 | obj-$(CONFIG_CPUSETS) += cpuset.o |
42 | obj-$(CONFIG_CGROUP_CPUACCT) += cpu_acct.o | 42 | obj-$(CONFIG_CGROUP_CPUACCT) += cpu_acct.o |
43 | obj-$(CONFIG_CGROUP_NS) += ns_cgroup.o | ||
43 | obj-$(CONFIG_IKCONFIG) += configs.o | 44 | obj-$(CONFIG_IKCONFIG) += configs.o |
44 | obj-$(CONFIG_STOP_MACHINE) += stop_machine.o | 45 | obj-$(CONFIG_STOP_MACHINE) += stop_machine.o |
45 | obj-$(CONFIG_AUDIT) += audit.o auditfilter.o | 46 | obj-$(CONFIG_AUDIT) += audit.o auditfilter.o |
diff --git a/kernel/ns_cgroup.c b/kernel/ns_cgroup.c new file mode 100644 index 000000000000..aead4d69f62b --- /dev/null +++ b/kernel/ns_cgroup.c | |||
@@ -0,0 +1,100 @@ | |||
1 | /* | ||
2 | * ns_cgroup.c - namespace cgroup subsystem | ||
3 | * | ||
4 | * Copyright 2006, 2007 IBM Corp | ||
5 | */ | ||
6 | |||
7 | #include <linux/module.h> | ||
8 | #include <linux/cgroup.h> | ||
9 | #include <linux/fs.h> | ||
10 | |||
11 | struct ns_cgroup { | ||
12 | struct cgroup_subsys_state css; | ||
13 | spinlock_t lock; | ||
14 | }; | ||
15 | |||
16 | struct cgroup_subsys ns_subsys; | ||
17 | |||
18 | static inline struct ns_cgroup *cgroup_to_ns( | ||
19 | struct cgroup *cgroup) | ||
20 | { | ||
21 | return container_of(cgroup_subsys_state(cgroup, ns_subsys_id), | ||
22 | struct ns_cgroup, css); | ||
23 | } | ||
24 | |||
25 | int ns_cgroup_clone(struct task_struct *task) | ||
26 | { | ||
27 | return cgroup_clone(task, &ns_subsys); | ||
28 | } | ||
29 | |||
30 | /* | ||
31 | * Rules: | ||
32 | * 1. you can only enter a cgroup which is a child of your current | ||
33 | * cgroup | ||
34 | * 2. you can only place another process into a cgroup if | ||
35 | * a. you have CAP_SYS_ADMIN | ||
36 | * b. your cgroup is an ancestor of task's destination cgroup | ||
37 | * (hence either you are in the same cgroup as task, or in an | ||
38 | * ancestor cgroup thereof) | ||
39 | */ | ||
40 | static int ns_can_attach(struct cgroup_subsys *ss, | ||
41 | struct cgroup *new_cgroup, struct task_struct *task) | ||
42 | { | ||
43 | struct cgroup *orig; | ||
44 | |||
45 | if (current != task) { | ||
46 | if (!capable(CAP_SYS_ADMIN)) | ||
47 | return -EPERM; | ||
48 | |||
49 | if (!cgroup_is_descendant(new_cgroup)) | ||
50 | return -EPERM; | ||
51 | } | ||
52 | |||
53 | if (atomic_read(&new_cgroup->count) != 0) | ||
54 | return -EPERM; | ||
55 | |||
56 | orig = task_cgroup(task, ns_subsys_id); | ||
57 | if (orig && orig != new_cgroup->parent) | ||
58 | return -EPERM; | ||
59 | |||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | /* | ||
64 | * Rules: you can only create a cgroup if | ||
65 | * 1. you are capable(CAP_SYS_ADMIN) | ||
66 | * 2. the target cgroup is a descendant of your own cgroup | ||
67 | */ | ||
68 | static struct cgroup_subsys_state *ns_create(struct cgroup_subsys *ss, | ||
69 | struct cgroup *cgroup) | ||
70 | { | ||
71 | struct ns_cgroup *ns_cgroup; | ||
72 | |||
73 | if (!capable(CAP_SYS_ADMIN)) | ||
74 | return ERR_PTR(-EPERM); | ||
75 | if (!cgroup_is_descendant(cgroup)) | ||
76 | return ERR_PTR(-EPERM); | ||
77 | |||
78 | ns_cgroup = kzalloc(sizeof(*ns_cgroup), GFP_KERNEL); | ||
79 | if (!ns_cgroup) | ||
80 | return ERR_PTR(-ENOMEM); | ||
81 | spin_lock_init(&ns_cgroup->lock); | ||
82 | return &ns_cgroup->css; | ||
83 | } | ||
84 | |||
85 | static void ns_destroy(struct cgroup_subsys *ss, | ||
86 | struct cgroup *cgroup) | ||
87 | { | ||
88 | struct ns_cgroup *ns_cgroup; | ||
89 | |||
90 | ns_cgroup = cgroup_to_ns(cgroup); | ||
91 | kfree(ns_cgroup); | ||
92 | } | ||
93 | |||
94 | struct cgroup_subsys ns_subsys = { | ||
95 | .name = "ns", | ||
96 | .can_attach = ns_can_attach, | ||
97 | .create = ns_create, | ||
98 | .destroy = ns_destroy, | ||
99 | .subsys_id = ns_subsys_id, | ||
100 | }; | ||
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c index 049e7c0ac566..ac99837e7a04 100644 --- a/kernel/nsproxy.c +++ b/kernel/nsproxy.c | |||
@@ -156,7 +156,14 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk) | |||
156 | goto out; | 156 | goto out; |
157 | } | 157 | } |
158 | 158 | ||
159 | err = ns_cgroup_clone(tsk); | ||
160 | if (err) { | ||
161 | put_nsproxy(new_ns); | ||
162 | goto out; | ||
163 | } | ||
164 | |||
159 | tsk->nsproxy = new_ns; | 165 | tsk->nsproxy = new_ns; |
166 | |||
160 | out: | 167 | out: |
161 | put_nsproxy(old_ns); | 168 | put_nsproxy(old_ns); |
162 | return err; | 169 | return err; |
@@ -196,8 +203,16 @@ int unshare_nsproxy_namespaces(unsigned long unshare_flags, | |||
196 | 203 | ||
197 | *new_nsp = create_new_namespaces(unshare_flags, current, | 204 | *new_nsp = create_new_namespaces(unshare_flags, current, |
198 | new_fs ? new_fs : current->fs); | 205 | new_fs ? new_fs : current->fs); |
199 | if (IS_ERR(*new_nsp)) | 206 | if (IS_ERR(*new_nsp)) { |
200 | err = PTR_ERR(*new_nsp); | 207 | err = PTR_ERR(*new_nsp); |
208 | goto out; | ||
209 | } | ||
210 | |||
211 | err = ns_cgroup_clone(current); | ||
212 | if (err) | ||
213 | put_nsproxy(*new_nsp); | ||
214 | |||
215 | out: | ||
201 | return err; | 216 | return err; |
202 | } | 217 | } |
203 | 218 | ||