]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Task Control Groups: add cgroup_clone() interface
authorPaul Menage <menage@google.com>
Fri, 19 Oct 2007 06:39:34 +0000 (23:39 -0700)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Fri, 19 Oct 2007 18:53:36 +0000 (11:53 -0700)
Add support for cgroup_clone(), a way to create new cgroups intended to
be used for systems such as namespace unsharing.  A new subsystem callback,
post_clone(), is added to allow subsystems to automatically configure cloned
cgroups.

Signed-off-by: Paul Menage <menage@google.com>
Cc: Serge E. Hallyn <serue@us.ibm.com>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Dave Hansen <haveblue@us.ibm.com>
Cc: Balbir Singh <balbir@in.ibm.com>
Cc: Paul Jackson <pj@sgi.com>
Cc: Kirill Korotaev <dev@openvz.org>
Cc: Herbert Poetzl <herbert@13thfloor.at>
Cc: Srivatsa Vaddagiri <vatsa@in.ibm.com>
Cc: 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>
Documentation/cgroups.txt
include/linux/cgroup.h
kernel/cgroup.c

index 4717887fd75d2f2b758616c1aaef473f20d2f667..553727cc99445f6ea79ac8bdcb63bf47aab046e7 100644 (file)
@@ -504,6 +504,13 @@ include/linux/cgroup.h for details).  Note that although this
 method can return an error code, the error code is currently not
 always handled well.
 
 method can return an error code, the error code is currently not
 always handled well.
 
+void post_clone(struct cgroup_subsys *ss, struct cgroup *cont)
+
+Called at the end of cgroup_clone() to do any paramater
+initialization which might be required before a task could attach.  For
+example in cpusets, no task may attach before 'cpus' and 'mems' are set
+up.
+
 void bind(struct cgroup_subsys *ss, struct cgroup *root)
 LL=callback_mutex
 
 void bind(struct cgroup_subsys *ss, struct cgroup *root)
 LL=callback_mutex
 
index 792ad74be1705fc8667d4fc2a41b2be0f74f5446..b21cf093ac62af42a2a62c19d82822d8fc1c1ad1 100644 (file)
@@ -182,6 +182,7 @@ struct cgroup_subsys {
        void (*exit)(struct cgroup_subsys *ss, struct task_struct *task);
        int (*populate)(struct cgroup_subsys *ss,
                        struct cgroup *cont);
        void (*exit)(struct cgroup_subsys *ss, struct task_struct *task);
        int (*populate)(struct cgroup_subsys *ss,
                        struct cgroup *cont);
+       void (*post_clone)(struct cgroup_subsys *ss, struct cgroup *cont);
        void (*bind)(struct cgroup_subsys *ss, struct cgroup *root);
        int subsys_id;
        int active;
        void (*bind)(struct cgroup_subsys *ss, struct cgroup *root);
        int subsys_id;
        int active;
@@ -221,6 +222,8 @@ static inline struct cgroup* task_cgroup(struct task_struct *task,
 
 int cgroup_path(const struct cgroup *cont, char *buf, int buflen);
 
 
 int cgroup_path(const struct cgroup *cont, char *buf, int buflen);
 
+int cgroup_clone(struct task_struct *tsk, struct cgroup_subsys *ss);
+
 #else /* !CONFIG_CGROUPS */
 
 static inline int cgroup_init_early(void) { return 0; }
 #else /* !CONFIG_CGROUPS */
 
 static inline int cgroup_init_early(void) { return 0; }
index 7bb520aaf0a39bf630bcfc09ca22fde582a3acb3..cc68fe68a60ebdfd4a07dc4d5fa955978b14de73 100644 (file)
@@ -1708,3 +1708,138 @@ void cgroup_exit(struct task_struct *tsk, int run_callbacks)
        tsk->cgroups = init_task.cgroups;
        task_unlock(tsk);
 }
        tsk->cgroups = init_task.cgroups;
        task_unlock(tsk);
 }
+
+/**
+ * cgroup_clone - duplicate the current cgroup in the hierarchy
+ * that the given subsystem is attached to, and move this task into
+ * the new child
+ */
+int cgroup_clone(struct task_struct *tsk, struct cgroup_subsys *subsys)
+{
+       struct dentry *dentry;
+       int ret = 0;
+       char nodename[MAX_CGROUP_TYPE_NAMELEN];
+       struct cgroup *parent, *child;
+       struct inode *inode;
+       struct css_set *cg;
+       struct cgroupfs_root *root;
+       struct cgroup_subsys *ss;
+
+       /* We shouldn't be called by an unregistered subsystem */
+       BUG_ON(!subsys->active);
+
+       /* First figure out what hierarchy and cgroup we're dealing
+        * with, and pin them so we can drop cgroup_mutex */
+       mutex_lock(&cgroup_mutex);
+ again:
+       root = subsys->root;
+       if (root == &rootnode) {
+               printk(KERN_INFO
+                      "Not cloning cgroup for unused subsystem %s\n",
+                      subsys->name);
+               mutex_unlock(&cgroup_mutex);
+               return 0;
+       }
+       cg = &tsk->cgroups;
+       parent = task_cgroup(tsk, subsys->subsys_id);
+
+       snprintf(nodename, MAX_CGROUP_TYPE_NAMELEN, "node_%d", tsk->pid);
+
+       /* Pin the hierarchy */
+       atomic_inc(&parent->root->sb->s_active);
+
+       mutex_unlock(&cgroup_mutex);
+
+       /* Now do the VFS work to create a cgroup */
+       inode = parent->dentry->d_inode;
+
+       /* Hold the parent directory mutex across this operation to
+        * stop anyone else deleting the new cgroup */
+       mutex_lock(&inode->i_mutex);
+       dentry = lookup_one_len(nodename, parent->dentry, strlen(nodename));
+       if (IS_ERR(dentry)) {
+               printk(KERN_INFO
+                      "Couldn't allocate dentry for %s: %ld\n", nodename,
+                      PTR_ERR(dentry));
+               ret = PTR_ERR(dentry);
+               goto out_release;
+       }
+
+       /* Create the cgroup directory, which also creates the cgroup */
+       ret = vfs_mkdir(inode, dentry, S_IFDIR | 0755);
+       child = __d_cont(dentry);
+       dput(dentry);
+       if (ret) {
+               printk(KERN_INFO
+                      "Failed to create cgroup %s: %d\n", nodename,
+                      ret);
+               goto out_release;
+       }
+
+       if (!child) {
+               printk(KERN_INFO
+                      "Couldn't find new cgroup %s\n", nodename);
+               ret = -ENOMEM;
+               goto out_release;
+       }
+
+       /* The cgroup now exists. Retake cgroup_mutex and check
+        * that we're still in the same state that we thought we
+        * were. */
+       mutex_lock(&cgroup_mutex);
+       if ((root != subsys->root) ||
+           (parent != task_cgroup(tsk, subsys->subsys_id))) {
+               /* Aargh, we raced ... */
+               mutex_unlock(&inode->i_mutex);
+
+               deactivate_super(parent->root->sb);
+               /* The cgroup is still accessible in the VFS, but
+                * we're not going to try to rmdir() it at this
+                * point. */
+               printk(KERN_INFO
+                      "Race in cgroup_clone() - leaking cgroup %s\n",
+                      nodename);
+               goto again;
+       }
+
+       /* do any required auto-setup */
+       for_each_subsys(root, ss) {
+               if (ss->post_clone)
+                       ss->post_clone(ss, child);
+       }
+
+       /* All seems fine. Finish by moving the task into the new cgroup */
+       ret = attach_task(child, tsk);
+       mutex_unlock(&cgroup_mutex);
+
+ out_release:
+       mutex_unlock(&inode->i_mutex);
+       deactivate_super(parent->root->sb);
+       return ret;
+}
+
+/*
+ * See if "cont" is a descendant of the current task's cgroup in
+ * the appropriate hierarchy
+ *
+ * If we are sending in dummytop, then presumably we are creating
+ * the top cgroup in the subsystem.
+ *
+ * Called only by the ns (nsproxy) cgroup.
+ */
+int cgroup_is_descendant(const struct cgroup *cont)
+{
+       int ret;
+       struct cgroup *target;
+       int subsys_id;
+
+       if (cont == dummytop)
+               return 1;
+
+       get_first_subsys(cont, NULL, &subsys_id);
+       target = task_cgroup(current, subsys_id);
+       while (cont != target && cont!= cont->top_cgroup)
+               cont = cont->parent;
+       ret = (cont == target);
+       return ret;
+}