cgroup: convert cgroupfs_root flag bits to masks and add CGRP_ prefix
[deliverable/linux.git] / kernel / cgroup.c
index 04fa2abf94b25f58c090eff54d9b599f468fe15d..67428d84e38bad75fbfa26b0094672bfb0bb7504 100644 (file)
  * B happens only through cgroup_show_options() and using cgroup_root_mutex
  * breaks it.
  */
+#ifdef CONFIG_PROVE_RCU
+DEFINE_MUTEX(cgroup_mutex);
+EXPORT_SYMBOL_GPL(cgroup_mutex);       /* only for task_subsys_state_check() */
+#else
 static DEFINE_MUTEX(cgroup_mutex);
+#endif
+
 static DEFINE_MUTEX(cgroup_root_mutex);
 
 /*
@@ -251,20 +257,6 @@ static int cgroup_destroy_locked(struct cgroup *cgrp);
 static int cgroup_addrm_files(struct cgroup *cgrp, struct cgroup_subsys *subsys,
                              struct cftype cfts[], bool is_add);
 
-#ifdef CONFIG_PROVE_LOCKING
-int cgroup_lock_is_held(void)
-{
-       return lockdep_is_held(&cgroup_mutex);
-}
-#else /* #ifdef CONFIG_PROVE_LOCKING */
-int cgroup_lock_is_held(void)
-{
-       return mutex_is_locked(&cgroup_mutex);
-}
-#endif /* #else #ifdef CONFIG_PROVE_LOCKING */
-
-EXPORT_SYMBOL_GPL(cgroup_lock_is_held);
-
 static int css_unbias_refcnt(int refcnt)
 {
        return refcnt >= 0 ? refcnt : refcnt - CSS_DEACT_BIAS;
@@ -284,10 +276,30 @@ inline int cgroup_is_removed(const struct cgroup *cgrp)
        return test_bit(CGRP_REMOVED, &cgrp->flags);
 }
 
-/* bits in struct cgroupfs_root flags field */
+/**
+ * cgroup_is_descendant - test ancestry
+ * @cgrp: the cgroup to be tested
+ * @ancestor: possible ancestor of @cgrp
+ *
+ * Test whether @cgrp is a descendant of @ancestor.  It also returns %true
+ * if @cgrp == @ancestor.  This function is safe to call as long as @cgrp
+ * and @ancestor are accessible.
+ */
+bool cgroup_is_descendant(struct cgroup *cgrp, struct cgroup *ancestor)
+{
+       while (cgrp) {
+               if (cgrp == ancestor)
+                       return true;
+               cgrp = cgrp->parent;
+       }
+       return false;
+}
+EXPORT_SYMBOL_GPL(cgroup_is_descendant);
+
+/* cgroupfs_root->flags */
 enum {
-       ROOT_NOPREFIX,  /* mounted subsystems have no named prefix */
-       ROOT_XATTR,     /* supports extended attributes */
+       CGRP_ROOT_NOPREFIX      = (1 << 1), /* mounted subsystems have no named prefix */
+       CGRP_ROOT_XATTR         = (1 << 2), /* supports extended attributes */
 };
 
 static int cgroup_is_releasable(const struct cgroup *cgrp)
@@ -329,6 +341,23 @@ static inline struct cftype *__d_cft(struct dentry *dentry)
        return __d_cfe(dentry)->type;
 }
 
+/**
+ * cgroup_lock_live_group - take cgroup_mutex and check that cgrp is alive.
+ * @cgrp: the cgroup to be checked for liveness
+ *
+ * On success, returns true; the mutex should be later unlocked.  On
+ * failure returns false with no lock held.
+ */
+static bool cgroup_lock_live_group(struct cgroup *cgrp)
+{
+       mutex_lock(&cgroup_mutex);
+       if (cgroup_is_removed(cgrp)) {
+               mutex_unlock(&cgroup_mutex);
+               return false;
+       }
+       return true;
+}
+
 /* the list of cgroups eligible for automatic release. Protected by
  * release_list_lock */
 static LIST_HEAD(release_list);
@@ -802,27 +831,6 @@ static struct cgroup *task_cgroup_from_root(struct task_struct *task,
  * update of a tasks cgroup pointer by cgroup_attach_task()
  */
 
-/**
- * cgroup_lock - lock out any changes to cgroup structures
- *
- */
-void cgroup_lock(void)
-{
-       mutex_lock(&cgroup_mutex);
-}
-EXPORT_SYMBOL_GPL(cgroup_lock);
-
-/**
- * cgroup_unlock - release lock on cgroup changes
- *
- * Undo the lock taken in a previous cgroup_lock() call.
- */
-void cgroup_unlock(void)
-{
-       mutex_unlock(&cgroup_mutex);
-}
-EXPORT_SYMBOL_GPL(cgroup_unlock);
-
 /*
  * A couple of forward declarations required, due to cyclic reference loop:
  * cgroup_mkdir -> cgroup_create -> cgroup_populate_dir ->
@@ -887,6 +895,13 @@ static void cgroup_free_fn(struct work_struct *work)
        cgrp->root->number_of_cgroups--;
        mutex_unlock(&cgroup_mutex);
 
+       /*
+        * We get a ref to the parent's dentry, and put the ref when
+        * this cgroup is being freed, so it's guaranteed that the
+        * parent won't be destroyed before its children.
+        */
+       dput(cgrp->parent->dentry);
+
        /*
         * Drop the active superblock reference that we took when we
         * created the cgroup
@@ -1122,9 +1137,9 @@ static int cgroup_show_options(struct seq_file *seq, struct dentry *dentry)
        mutex_lock(&cgroup_root_mutex);
        for_each_subsys(root, ss)
                seq_printf(seq, ",%s", ss->name);
-       if (test_bit(ROOT_NOPREFIX, &root->flags))
+       if (root->flags & CGRP_ROOT_NOPREFIX)
                seq_puts(seq, ",noprefix");
-       if (test_bit(ROOT_XATTR, &root->flags))
+       if (root->flags & CGRP_ROOT_XATTR)
                seq_puts(seq, ",xattr");
        if (strlen(root->release_agent_path))
                seq_printf(seq, ",release_agent=%s", root->release_agent_path);
@@ -1187,7 +1202,7 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
                        continue;
                }
                if (!strcmp(token, "noprefix")) {
-                       set_bit(ROOT_NOPREFIX, &opts->flags);
+                       opts->flags |= CGRP_ROOT_NOPREFIX;
                        continue;
                }
                if (!strcmp(token, "clone_children")) {
@@ -1195,7 +1210,7 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
                        continue;
                }
                if (!strcmp(token, "xattr")) {
-                       set_bit(ROOT_XATTR, &opts->flags);
+                       opts->flags |= CGRP_ROOT_XATTR;
                        continue;
                }
                if (!strncmp(token, "release_agent=", 14)) {
@@ -1278,8 +1293,7 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
         * with the old cpuset, so we allow noprefix only if mounting just
         * the cpuset subsystem.
         */
-       if (test_bit(ROOT_NOPREFIX, &opts->flags) &&
-           (opts->subsys_mask & mask))
+       if ((opts->flags & CGRP_ROOT_NOPREFIX) && (opts->subsys_mask & mask))
                return -EINVAL;
 
 
@@ -1796,11 +1810,17 @@ int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen)
        int ret = -ENAMETOOLONG;
        char *start;
 
+       if (!cgrp->parent) {
+               if (strlcpy(buf, "/", buflen) >= buflen)
+                       return -ENAMETOOLONG;
+               return 0;
+       }
+
        start = buf + buflen - 1;
        *start = '\0';
 
        rcu_read_lock();
-       while (cgrp) {
+       do {
                const char *name = cgroup_name(cgrp);
                int len;
 
@@ -1809,15 +1829,12 @@ int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen)
                        goto out;
                memcpy(start, name, len);
 
-               if (!cgrp->parent)
-                       break;
-
                if (--start < buf)
                        goto out;
                *start = '/';
 
                cgrp = cgrp->parent;
-       }
+       } while (cgrp->parent);
        ret = 0;
        memmove(buf, start, buf + buflen - start);
 out:
@@ -1911,7 +1928,7 @@ EXPORT_SYMBOL_GPL(cgroup_taskset_size);
  *
  * Must be called with cgroup_mutex and threadgroup locked.
  */
-static void cgroup_task_migrate(struct cgroup *cgrp, struct cgroup *oldcgrp,
+static void cgroup_task_migrate(struct cgroup *oldcgrp,
                                struct task_struct *tsk, struct css_set *newcg)
 {
        struct css_set *oldcg;
@@ -1943,30 +1960,6 @@ static void cgroup_task_migrate(struct cgroup *cgrp, struct cgroup *oldcgrp,
        put_css_set(oldcg);
 }
 
-/**
- * cgroup_attach_task_all - attach task 'tsk' to all cgroups of task 'from'
- * @from: attach to all cgroups of a given task
- * @tsk: the task to be attached
- */
-int cgroup_attach_task_all(struct task_struct *from, struct task_struct *tsk)
-{
-       struct cgroupfs_root *root;
-       int retval = 0;
-
-       cgroup_lock();
-       for_each_active_root(root) {
-               struct cgroup *from_cg = task_cgroup_from_root(from, root);
-
-               retval = cgroup_attach_task(from_cg, tsk, false);
-               if (retval)
-                       break;
-       }
-       cgroup_unlock();
-
-       return retval;
-}
-EXPORT_SYMBOL_GPL(cgroup_attach_task_all);
-
 /**
  * cgroup_attach_task - attach a task or a whole threadgroup to a cgroup
  * @cgrp: the cgroup to attach to
@@ -1976,8 +1969,8 @@ EXPORT_SYMBOL_GPL(cgroup_attach_task_all);
  * Call holding cgroup_mutex and the group_rwsem of the leader. Will take
  * task_lock of @tsk or each thread in the threadgroup individually in turn.
  */
-int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk,
-                      bool threadgroup)
+static int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk,
+                             bool threadgroup)
 {
        int retval, i, group_size;
        struct cgroup_subsys *ss, *failed_ss = NULL;
@@ -2084,7 +2077,7 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk,
         */
        for (i = 0; i < group_size; i++) {
                tc = flex_array_get(group, i);
-               cgroup_task_migrate(cgrp, tc->cgrp, tc->task, tc->cg);
+               cgroup_task_migrate(tc->cgrp, tc->task, tc->cg);
        }
        /* nothing is sensitive to fork() after this point. */
 
@@ -2200,10 +2193,34 @@ retry_find_task:
 
        put_task_struct(tsk);
 out_unlock_cgroup:
-       cgroup_unlock();
+       mutex_unlock(&cgroup_mutex);
        return ret;
 }
 
+/**
+ * cgroup_attach_task_all - attach task 'tsk' to all cgroups of task 'from'
+ * @from: attach to all cgroups of a given task
+ * @tsk: the task to be attached
+ */
+int cgroup_attach_task_all(struct task_struct *from, struct task_struct *tsk)
+{
+       struct cgroupfs_root *root;
+       int retval = 0;
+
+       mutex_lock(&cgroup_mutex);
+       for_each_active_root(root) {
+               struct cgroup *from_cg = task_cgroup_from_root(from, root);
+
+               retval = cgroup_attach_task(from_cg, tsk, false);
+               if (retval)
+                       break;
+       }
+       mutex_unlock(&cgroup_mutex);
+
+       return retval;
+}
+EXPORT_SYMBOL_GPL(cgroup_attach_task_all);
+
 static int cgroup_tasks_write(struct cgroup *cgrp, struct cftype *cft, u64 pid)
 {
        return attach_task_by_pid(cgrp, pid, false);
@@ -2214,24 +2231,6 @@ static int cgroup_procs_write(struct cgroup *cgrp, struct cftype *cft, u64 tgid)
        return attach_task_by_pid(cgrp, tgid, true);
 }
 
-/**
- * cgroup_lock_live_group - take cgroup_mutex and check that cgrp is alive.
- * @cgrp: the cgroup to be checked for liveness
- *
- * On success, returns true; the lock should be later released with
- * cgroup_unlock(). On failure returns false with no lock held.
- */
-bool cgroup_lock_live_group(struct cgroup *cgrp)
-{
-       mutex_lock(&cgroup_mutex);
-       if (cgroup_is_removed(cgrp)) {
-               mutex_unlock(&cgroup_mutex);
-               return false;
-       }
-       return true;
-}
-EXPORT_SYMBOL_GPL(cgroup_lock_live_group);
-
 static int cgroup_release_agent_write(struct cgroup *cgrp, struct cftype *cft,
                                      const char *buffer)
 {
@@ -2243,7 +2242,7 @@ static int cgroup_release_agent_write(struct cgroup *cgrp, struct cftype *cft,
        mutex_lock(&cgroup_root_mutex);
        strcpy(cgrp->root->release_agent_path, buffer);
        mutex_unlock(&cgroup_root_mutex);
-       cgroup_unlock();
+       mutex_unlock(&cgroup_mutex);
        return 0;
 }
 
@@ -2254,7 +2253,7 @@ static int cgroup_release_agent_show(struct cgroup *cgrp, struct cftype *cft,
                return -ENODEV;
        seq_puts(seq, cgrp->root->release_agent_path);
        seq_putc(seq, '\n');
-       cgroup_unlock();
+       mutex_unlock(&cgroup_mutex);
        return 0;
 }
 
@@ -2526,7 +2525,7 @@ static struct simple_xattrs *__d_xattrs(struct dentry *dentry)
 static inline int xattr_enabled(struct dentry *dentry)
 {
        struct cgroupfs_root *root = dentry->d_sb->s_fs_info;
-       return test_bit(ROOT_XATTR, &root->flags);
+       return root->flags & CGRP_ROOT_XATTR;
 }
 
 static bool is_valid_xattr(const char *name)
@@ -2698,7 +2697,7 @@ static int cgroup_add_file(struct cgroup *cgrp, struct cgroup_subsys *subsys,
 
        simple_xattrs_init(&cft->xattrs);
 
-       if (subsys && !test_bit(ROOT_NOPREFIX, &cgrp->root->flags)) {
+       if (subsys && !(cgrp->root->flags & CGRP_ROOT_NOPREFIX)) {
                strcpy(name, subsys->name);
                strcat(name, ".");
        }
@@ -3269,6 +3268,34 @@ int cgroup_scan_tasks(struct cgroup_scanner *scan)
        return 0;
 }
 
+static void cgroup_transfer_one_task(struct task_struct *task,
+                                    struct cgroup_scanner *scan)
+{
+       struct cgroup *new_cgroup = scan->data;
+
+       mutex_lock(&cgroup_mutex);
+       cgroup_attach_task(new_cgroup, task, false);
+       mutex_unlock(&cgroup_mutex);
+}
+
+/**
+ * cgroup_trasnsfer_tasks - move tasks from one cgroup to another
+ * @to: cgroup to which the tasks will be moved
+ * @from: cgroup in which the tasks currently reside
+ */
+int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from)
+{
+       struct cgroup_scanner scan;
+
+       scan.cg = from;
+       scan.test_task = NULL; /* select all tasks in cgroup */
+       scan.process_task = cgroup_transfer_one_task;
+       scan.heap = NULL;
+       scan.data = to;
+
+       return cgroup_scan_tasks(&scan);
+}
+
 /*
  * Stuff for reading the 'tasks'/'procs' files.
  *
@@ -4170,6 +4197,9 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
        for_each_subsys(root, ss)
                dget(dentry);
 
+       /* hold a ref to the parent's dentry */
+       dget(parent->dentry);
+
        /* creation succeeded, notify subsystems */
        for_each_subsys(root, ss) {
                err = online_css(ss, cgrp);
This page took 0.037482 seconds and 5 git commands to generate.