cgroup: s/CGRP_CLONE_CHILDREN/CGRP_CPUSET_CLONE_CHILDREN/
[pandora-kernel.git] / kernel / cgroup.c
index c5f6fb2..2895880 100644 (file)
@@ -88,11 +88,12 @@ static DEFINE_MUTEX(cgroup_root_mutex);
 
 /*
  * Generate an array of cgroup subsystem pointers. At boot time, this is
- * populated up to CGROUP_BUILTIN_SUBSYS_COUNT, and modular subsystems are
+ * populated with the built in subsystems, and modular subsystems are
  * registered after that. The mutable section of this array is protected by
  * cgroup_mutex.
  */
-#define SUBSYS(_x) &_x ## _subsys,
+#define SUBSYS(_x) [_x ## _subsys_id] = &_x ## _subsys,
+#define IS_SUBSYS_ENABLED(option) IS_BUILTIN(option)
 static struct cgroup_subsys *subsys[CGROUP_SUBSYS_COUNT] = {
 #include <linux/cgroup_subsys.h>
 };
@@ -111,13 +112,13 @@ struct cgroupfs_root {
         * The bitmask of subsystems intended to be attached to this
         * hierarchy
         */
-       unsigned long subsys_bits;
+       unsigned long subsys_mask;
 
        /* Unique id for this hierarchy. */
        int hierarchy_id;
 
        /* The bitmask of subsystems currently attached to this hierarchy */
-       unsigned long actual_subsys_bits;
+       unsigned long actual_subsys_mask;
 
        /* A list running through the attached subsystems */
        struct list_head subsys_list;
@@ -241,6 +242,8 @@ static DEFINE_SPINLOCK(hierarchy_id_lock);
  */
 static int need_forkexit_callback __read_mostly;
 
+static int cgroup_destroy_locked(struct cgroup *cgrp);
+
 #ifdef CONFIG_PROVE_LOCKING
 int cgroup_lock_is_held(void)
 {
@@ -276,7 +279,8 @@ inline int cgroup_is_removed(const struct cgroup *cgrp)
 
 /* bits in struct cgroupfs_root flags field */
 enum {
-       ROOT_NOPREFIX, /* mounted subsystems have no named prefix */
+       ROOT_NOPREFIX,  /* mounted subsystems have no named prefix */
+       ROOT_XATTR,     /* supports extended attributes */
 };
 
 static int cgroup_is_releasable(const struct cgroup *cgrp)
@@ -292,11 +296,6 @@ static int notify_on_release(const struct cgroup *cgrp)
        return test_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags);
 }
 
-static int clone_children(const struct cgroup *cgrp)
-{
-       return test_bit(CGRP_CLONE_CHILDREN, &cgrp->flags);
-}
-
 /*
  * for_each_subsys() allows you to iterate on each subsystem attached to
  * an active hierarchy
@@ -556,7 +555,7 @@ static struct css_set *find_existing_css_set(
         * won't change, so no need for locking.
         */
        for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
-               if (root->subsys_bits & (1UL << i)) {
+               if (root->subsys_mask & (1UL << i)) {
                        /* Subsystem is in this hierarchy. So we want
                         * the subsystem state from the new
                         * cgroup */
@@ -824,7 +823,8 @@ EXPORT_SYMBOL_GPL(cgroup_unlock);
 static int cgroup_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode);
 static struct dentry *cgroup_lookup(struct inode *, struct dentry *, unsigned int);
 static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry);
-static int cgroup_populate_dir(struct cgroup *cgrp);
+static int cgroup_populate_dir(struct cgroup *cgrp, bool base_files,
+                              unsigned long subsys_mask);
 static const struct inode_operations cgroup_dir_inode_operations;
 static const struct file_operations proc_cgroupstats_operations;
 
@@ -871,7 +871,7 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode)
                 * Release the subsystem state objects.
                 */
                for_each_subsys(cgrp->root, ss)
-                       ss->destroy(cgrp);
+                       ss->css_free(cgrp);
 
                cgrp->root->number_of_cgroups--;
                mutex_unlock(&cgroup_mutex);
@@ -888,15 +888,19 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode)
                 */
                BUG_ON(!list_empty(&cgrp->pidlists));
 
+               simple_xattrs_free(&cgrp->xattrs);
+
                kfree_rcu(cgrp, rcu_head);
        } else {
                struct cfent *cfe = __d_cfe(dentry);
                struct cgroup *cgrp = dentry->d_parent->d_fsdata;
+               struct cftype *cft = cfe->type;
 
                WARN_ONCE(!list_empty(&cfe->node) &&
                          cgrp != &cgrp->root->top_cgroup,
                          "cfe still linked for %s\n", cfe->type->name);
                kfree(cfe);
+               simple_xattrs_free(&cft->xattrs);
        }
        iput(inode);
 }
@@ -939,12 +943,29 @@ static int cgroup_rm_file(struct cgroup *cgrp, const struct cftype *cft)
        return -ENOENT;
 }
 
-static void cgroup_clear_directory(struct dentry *dir)
+/**
+ * cgroup_clear_directory - selective removal of base and subsystem files
+ * @dir: directory containing the files
+ * @base_files: true if the base files should be removed
+ * @subsys_mask: mask of the subsystem ids whose files should be removed
+ */
+static void cgroup_clear_directory(struct dentry *dir, bool base_files,
+                                  unsigned long subsys_mask)
 {
        struct cgroup *cgrp = __d_cgrp(dir);
+       struct cgroup_subsys *ss;
 
-       while (!list_empty(&cgrp->files))
-               cgroup_rm_file(cgrp, NULL);
+       for_each_subsys(cgrp->root, ss) {
+               struct cftype_set *set;
+               if (!test_bit(ss->subsys_id, &subsys_mask))
+                       continue;
+               list_for_each_entry(set, &ss->cftsets, node)
+                       cgroup_rm_file(cgrp, set->cfts);
+       }
+       if (base_files) {
+               while (!list_empty(&cgrp->files))
+                       cgroup_rm_file(cgrp, NULL);
+       }
 }
 
 /*
@@ -953,8 +974,9 @@ static void cgroup_clear_directory(struct dentry *dir)
 static void cgroup_d_remove_dir(struct dentry *dentry)
 {
        struct dentry *parent;
+       struct cgroupfs_root *root = dentry->d_sb->s_fs_info;
 
-       cgroup_clear_directory(dentry);
+       cgroup_clear_directory(dentry, true, root->subsys_mask);
 
        parent = dentry->d_parent;
        spin_lock(&parent->d_lock);
@@ -971,22 +993,22 @@ static void cgroup_d_remove_dir(struct dentry *dentry)
  * returns an error, no reference counts are touched.
  */
 static int rebind_subsystems(struct cgroupfs_root *root,
-                             unsigned long final_bits)
+                             unsigned long final_subsys_mask)
 {
-       unsigned long added_bits, removed_bits;
+       unsigned long added_mask, removed_mask;
        struct cgroup *cgrp = &root->top_cgroup;
        int i;
 
        BUG_ON(!mutex_is_locked(&cgroup_mutex));
        BUG_ON(!mutex_is_locked(&cgroup_root_mutex));
 
-       removed_bits = root->actual_subsys_bits & ~final_bits;
-       added_bits = final_bits & ~root->actual_subsys_bits;
+       removed_mask = root->actual_subsys_mask & ~final_subsys_mask;
+       added_mask = final_subsys_mask & ~root->actual_subsys_mask;
        /* Check that any added subsystems are currently free */
        for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
                unsigned long bit = 1UL << i;
                struct cgroup_subsys *ss = subsys[i];
-               if (!(bit & added_bits))
+               if (!(bit & added_mask))
                        continue;
                /*
                 * Nobody should tell us to do a subsys that doesn't exist:
@@ -1011,7 +1033,7 @@ static int rebind_subsystems(struct cgroupfs_root *root,
        for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
                struct cgroup_subsys *ss = subsys[i];
                unsigned long bit = 1UL << i;
-               if (bit & added_bits) {
+               if (bit & added_mask) {
                        /* We're binding this subsystem to this hierarchy */
                        BUG_ON(ss == NULL);
                        BUG_ON(cgrp->subsys[i]);
@@ -1024,7 +1046,7 @@ static int rebind_subsystems(struct cgroupfs_root *root,
                        if (ss->bind)
                                ss->bind(cgrp);
                        /* refcount was already taken, and we're keeping it */
-               } else if (bit & removed_bits) {
+               } else if (bit & removed_mask) {
                        /* We're removing this subsystem */
                        BUG_ON(ss == NULL);
                        BUG_ON(cgrp->subsys[i] != dummytop->subsys[i]);
@@ -1037,7 +1059,7 @@ static int rebind_subsystems(struct cgroupfs_root *root,
                        list_move(&ss->sibling, &rootnode.subsys_list);
                        /* subsystem is now free - drop reference on module */
                        module_put(ss->module);
-               } else if (bit & final_bits) {
+               } else if (bit & final_subsys_mask) {
                        /* Subsystem state should already exist */
                        BUG_ON(ss == NULL);
                        BUG_ON(!cgrp->subsys[i]);
@@ -1054,7 +1076,7 @@ static int rebind_subsystems(struct cgroupfs_root *root,
                        BUG_ON(cgrp->subsys[i]);
                }
        }
-       root->subsys_bits = root->actual_subsys_bits = final_bits;
+       root->subsys_mask = root->actual_subsys_mask = final_subsys_mask;
        synchronize_rcu();
 
        return 0;
@@ -1070,9 +1092,11 @@ static int cgroup_show_options(struct seq_file *seq, struct dentry *dentry)
                seq_printf(seq, ",%s", ss->name);
        if (test_bit(ROOT_NOPREFIX, &root->flags))
                seq_puts(seq, ",noprefix");
+       if (test_bit(ROOT_XATTR, &root->flags))
+               seq_puts(seq, ",xattr");
        if (strlen(root->release_agent_path))
                seq_printf(seq, ",release_agent=%s", root->release_agent_path);
-       if (clone_children(&root->top_cgroup))
+       if (test_bit(CGRP_CPUSET_CLONE_CHILDREN, &root->top_cgroup.flags))
                seq_puts(seq, ",clone_children");
        if (strlen(root->name))
                seq_printf(seq, ",name=%s", root->name);
@@ -1081,10 +1105,10 @@ static int cgroup_show_options(struct seq_file *seq, struct dentry *dentry)
 }
 
 struct cgroup_sb_opts {
-       unsigned long subsys_bits;
+       unsigned long subsys_mask;
        unsigned long flags;
        char *release_agent;
-       bool clone_children;
+       bool cpuset_clone_children;
        char *name;
        /* User explicitly requested empty subsystem */
        bool none;
@@ -1135,7 +1159,11 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
                        continue;
                }
                if (!strcmp(token, "clone_children")) {
-                       opts->clone_children = true;
+                       opts->cpuset_clone_children = true;
+                       continue;
+               }
+               if (!strcmp(token, "xattr")) {
+                       set_bit(ROOT_XATTR, &opts->flags);
                        continue;
                }
                if (!strncmp(token, "release_agent=", 14)) {
@@ -1186,7 +1214,7 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
                        /* Mutually exclusive option 'all' + subsystem name */
                        if (all_ss)
                                return -EINVAL;
-                       set_bit(i, &opts->subsys_bits);
+                       set_bit(i, &opts->subsys_mask);
                        one_ss = true;
 
                        break;
@@ -1207,7 +1235,7 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
                                continue;
                        if (ss->disabled)
                                continue;
-                       set_bit(i, &opts->subsys_bits);
+                       set_bit(i, &opts->subsys_mask);
                }
        }
 
@@ -1219,19 +1247,19 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
         * the cpuset subsystem.
         */
        if (test_bit(ROOT_NOPREFIX, &opts->flags) &&
-           (opts->subsys_bits & mask))
+           (opts->subsys_mask & mask))
                return -EINVAL;
 
 
        /* Can't specify "none" and some subsystems */
-       if (opts->subsys_bits && opts->none)
+       if (opts->subsys_mask && opts->none)
                return -EINVAL;
 
        /*
         * We either have to specify by name or by subsystems. (So all
         * empty hierarchies must have a name).
         */
-       if (!opts->subsys_bits && !opts->name)
+       if (!opts->subsys_mask && !opts->name)
                return -EINVAL;
 
        /*
@@ -1240,10 +1268,10 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
         * take duplicate reference counts on a subsystem that's already used,
         * but rebind_subsystems handles this case.
         */
-       for (i = CGROUP_BUILTIN_SUBSYS_COUNT; i < CGROUP_SUBSYS_COUNT; i++) {
+       for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
                unsigned long bit = 1UL << i;
 
-               if (!(bit & opts->subsys_bits))
+               if (!(bit & opts->subsys_mask))
                        continue;
                if (!try_module_get(subsys[i]->module)) {
                        module_pin_failed = true;
@@ -1256,11 +1284,11 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
                 * raced with a module_delete call, and to the user this is
                 * essentially a "subsystem doesn't exist" case.
                 */
-               for (i--; i >= CGROUP_BUILTIN_SUBSYS_COUNT; i--) {
+               for (i--; i >= 0; i--) {
                        /* drop refcounts only on the ones we took */
                        unsigned long bit = 1UL << i;
 
-                       if (!(bit & opts->subsys_bits))
+                       if (!(bit & opts->subsys_mask))
                                continue;
                        module_put(subsys[i]->module);
                }
@@ -1270,13 +1298,13 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
        return 0;
 }
 
-static void drop_parsed_module_refcounts(unsigned long subsys_bits)
+static void drop_parsed_module_refcounts(unsigned long subsys_mask)
 {
        int i;
-       for (i = CGROUP_BUILTIN_SUBSYS_COUNT; i < CGROUP_SUBSYS_COUNT; i++) {
+       for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
                unsigned long bit = 1UL << i;
 
-               if (!(bit & subsys_bits))
+               if (!(bit & subsys_mask))
                        continue;
                module_put(subsys[i]->module);
        }
@@ -1288,6 +1316,7 @@ static int cgroup_remount(struct super_block *sb, int *flags, char *data)
        struct cgroupfs_root *root = sb->s_fs_info;
        struct cgroup *cgrp = &root->top_cgroup;
        struct cgroup_sb_opts opts;
+       unsigned long added_mask, removed_mask;
 
        mutex_lock(&cgrp->dentry->d_inode->i_mutex);
        mutex_lock(&cgroup_mutex);
@@ -1299,27 +1328,31 @@ static int cgroup_remount(struct super_block *sb, int *flags, char *data)
                goto out_unlock;
 
        /* See feature-removal-schedule.txt */
-       if (opts.subsys_bits != root->actual_subsys_bits || opts.release_agent)
+       if (opts.subsys_mask != root->actual_subsys_mask || opts.release_agent)
                pr_warning("cgroup: option changes via remount are deprecated (pid=%d comm=%s)\n",
                           task_tgid_nr(current), current->comm);
 
+       added_mask = opts.subsys_mask & ~root->subsys_mask;
+       removed_mask = root->subsys_mask & ~opts.subsys_mask;
+
        /* Don't allow flags or name to change at remount */
        if (opts.flags != root->flags ||
            (opts.name && strcmp(opts.name, root->name))) {
                ret = -EINVAL;
-               drop_parsed_module_refcounts(opts.subsys_bits);
+               drop_parsed_module_refcounts(opts.subsys_mask);
                goto out_unlock;
        }
 
-       ret = rebind_subsystems(root, opts.subsys_bits);
+       ret = rebind_subsystems(root, opts.subsys_mask);
        if (ret) {
-               drop_parsed_module_refcounts(opts.subsys_bits);
+               drop_parsed_module_refcounts(opts.subsys_mask);
                goto out_unlock;
        }
 
        /* clear out any existing files and repopulate subsystem files */
-       cgroup_clear_directory(cgrp->dentry);
-       cgroup_populate_dir(cgrp);
+       cgroup_clear_directory(cgrp->dentry, false, removed_mask);
+       /* re-populate subsystem files */
+       cgroup_populate_dir(cgrp, false, added_mask);
 
        if (opts.release_agent)
                strcpy(root->release_agent_path, opts.release_agent);
@@ -1345,11 +1378,13 @@ static void init_cgroup_housekeeping(struct cgroup *cgrp)
        INIT_LIST_HEAD(&cgrp->children);
        INIT_LIST_HEAD(&cgrp->files);
        INIT_LIST_HEAD(&cgrp->css_sets);
+       INIT_LIST_HEAD(&cgrp->allcg_node);
        INIT_LIST_HEAD(&cgrp->release_list);
        INIT_LIST_HEAD(&cgrp->pidlists);
        mutex_init(&cgrp->pidlist_mutex);
        INIT_LIST_HEAD(&cgrp->event_list);
        spin_lock_init(&cgrp->event_list_lock);
+       simple_xattrs_init(&cgrp->xattrs);
 }
 
 static void init_cgroup_root(struct cgroupfs_root *root)
@@ -1404,8 +1439,8 @@ static int cgroup_test_super(struct super_block *sb, void *data)
         * If we asked for subsystems (or explicitly for no
         * subsystems) then they must match
         */
-       if ((opts->subsys_bits || opts->none)
-           && (opts->subsys_bits != root->subsys_bits))
+       if ((opts->subsys_mask || opts->none)
+           && (opts->subsys_mask != root->subsys_mask))
                return 0;
 
        return 1;
@@ -1415,7 +1450,7 @@ static struct cgroupfs_root *cgroup_root_from_opts(struct cgroup_sb_opts *opts)
 {
        struct cgroupfs_root *root;
 
-       if (!opts->subsys_bits && !opts->none)
+       if (!opts->subsys_mask && !opts->none)
                return NULL;
 
        root = kzalloc(sizeof(*root), GFP_KERNEL);
@@ -1428,14 +1463,14 @@ static struct cgroupfs_root *cgroup_root_from_opts(struct cgroup_sb_opts *opts)
        }
        init_cgroup_root(root);
 
-       root->subsys_bits = opts->subsys_bits;
+       root->subsys_mask = opts->subsys_mask;
        root->flags = opts->flags;
        if (opts->release_agent)
                strcpy(root->release_agent_path, opts->release_agent);
        if (opts->name)
                strcpy(root->name, opts->name);
-       if (opts->clone_children)
-               set_bit(CGRP_CLONE_CHILDREN, &root->top_cgroup.flags);
+       if (opts->cpuset_clone_children)
+               set_bit(CGRP_CPUSET_CLONE_CHILDREN, &root->top_cgroup.flags);
        return root;
 }
 
@@ -1460,7 +1495,7 @@ static int cgroup_set_super(struct super_block *sb, void *data)
        if (!opts->new_root)
                return -EINVAL;
 
-       BUG_ON(!opts->subsys_bits && !opts->none);
+       BUG_ON(!opts->subsys_mask && !opts->none);
 
        ret = set_anon_super(sb, NULL);
        if (ret)
@@ -1578,7 +1613,7 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
                if (ret)
                        goto unlock_drop;
 
-               ret = rebind_subsystems(root, root->subsys_bits);
+               ret = rebind_subsystems(root, root->subsys_mask);
                if (ret == -EBUSY) {
                        free_cg_links(&tmp_cg_links);
                        goto unlock_drop;
@@ -1613,12 +1648,11 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
 
                free_cg_links(&tmp_cg_links);
 
-               BUG_ON(!list_empty(&root_cgrp->sibling));
                BUG_ON(!list_empty(&root_cgrp->children));
                BUG_ON(root->number_of_cgroups != 1);
 
                cred = override_creds(&init_cred);
-               cgroup_populate_dir(root_cgrp);
+               cgroup_populate_dir(root_cgrp, true, root->subsys_mask);
                revert_creds(cred);
                mutex_unlock(&cgroup_root_mutex);
                mutex_unlock(&cgroup_mutex);
@@ -1630,7 +1664,7 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
                 */
                cgroup_drop_root(opts.new_root);
                /* no subsys rebinding, so refcounts don't change */
-               drop_parsed_module_refcounts(opts.subsys_bits);
+               drop_parsed_module_refcounts(opts.subsys_mask);
        }
 
        kfree(opts.release_agent);
@@ -1644,7 +1678,7 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
  drop_new_super:
        deactivate_locked_super(sb);
  drop_modules:
-       drop_parsed_module_refcounts(opts.subsys_bits);
+       drop_parsed_module_refcounts(opts.subsys_mask);
  out_err:
        kfree(opts.release_agent);
        kfree(opts.name);
@@ -1662,7 +1696,6 @@ static void cgroup_kill_sb(struct super_block *sb) {
 
        BUG_ON(root->number_of_cgroups != 1);
        BUG_ON(!list_empty(&cgrp->children));
-       BUG_ON(!list_empty(&cgrp->sibling));
 
        mutex_lock(&cgroup_mutex);
        mutex_lock(&cgroup_root_mutex);
@@ -1694,6 +1727,8 @@ static void cgroup_kill_sb(struct super_block *sb) {
        mutex_unlock(&cgroup_root_mutex);
        mutex_unlock(&cgroup_mutex);
 
+       simple_xattrs_free(&cgrp->xattrs);
+
        kill_litter_super(sb);
        cgroup_drop_root(root);
 }
@@ -1718,9 +1753,11 @@ static struct kobject *cgroup_kobj;
  */
 int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen)
 {
+       struct dentry *dentry = cgrp->dentry;
        char *start;
-       struct dentry *dentry = rcu_dereference_check(cgrp->dentry,
-                                                     cgroup_lock_is_held());
+
+       rcu_lockdep_assert(rcu_read_lock_held() || cgroup_lock_is_held(),
+                          "cgroup_path() called without proper locking");
 
        if (!dentry || cgrp == dummytop) {
                /*
@@ -1731,9 +1768,9 @@ int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen)
                return 0;
        }
 
-       start = buf + buflen;
+       start = buf + buflen - 1;
 
-       *--start = '\0';
+       *start = '\0';
        for (;;) {
                int len = dentry->d_name.len;
 
@@ -1744,8 +1781,7 @@ int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen)
                if (!cgrp)
                        break;
 
-               dentry = rcu_dereference_check(cgrp->dentry,
-                                              cgroup_lock_is_held());
+               dentry = cgrp->dentry;
                if (!cgrp->parent)
                        continue;
                if (--start < buf)
@@ -1872,9 +1908,8 @@ static void cgroup_task_migrate(struct cgroup *cgrp, struct cgroup *oldcgrp,
         * trading it for newcg is protected by cgroup_mutex, we're safe to drop
         * it here; it will be freed under RCU.
         */
-       put_css_set(oldcg);
-
        set_bit(CGRP_RELEASABLE, &oldcgrp->flags);
+       put_css_set(oldcg);
 }
 
 /**
@@ -2493,6 +2528,64 @@ static int cgroup_rename(struct inode *old_dir, struct dentry *old_dentry,
        return simple_rename(old_dir, old_dentry, new_dir, new_dentry);
 }
 
+static struct simple_xattrs *__d_xattrs(struct dentry *dentry)
+{
+       if (S_ISDIR(dentry->d_inode->i_mode))
+               return &__d_cgrp(dentry)->xattrs;
+       else
+               return &__d_cft(dentry)->xattrs;
+}
+
+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);
+}
+
+static bool is_valid_xattr(const char *name)
+{
+       if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) ||
+           !strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN))
+               return true;
+       return false;
+}
+
+static int cgroup_setxattr(struct dentry *dentry, const char *name,
+                          const void *val, size_t size, int flags)
+{
+       if (!xattr_enabled(dentry))
+               return -EOPNOTSUPP;
+       if (!is_valid_xattr(name))
+               return -EINVAL;
+       return simple_xattr_set(__d_xattrs(dentry), name, val, size, flags);
+}
+
+static int cgroup_removexattr(struct dentry *dentry, const char *name)
+{
+       if (!xattr_enabled(dentry))
+               return -EOPNOTSUPP;
+       if (!is_valid_xattr(name))
+               return -EINVAL;
+       return simple_xattr_remove(__d_xattrs(dentry), name);
+}
+
+static ssize_t cgroup_getxattr(struct dentry *dentry, const char *name,
+                              void *buf, size_t size)
+{
+       if (!xattr_enabled(dentry))
+               return -EOPNOTSUPP;
+       if (!is_valid_xattr(name))
+               return -EINVAL;
+       return simple_xattr_get(__d_xattrs(dentry), name, buf, size);
+}
+
+static ssize_t cgroup_listxattr(struct dentry *dentry, char *buf, size_t size)
+{
+       if (!xattr_enabled(dentry))
+               return -EOPNOTSUPP;
+       return simple_xattr_list(__d_xattrs(dentry), buf, size);
+}
+
 static const struct file_operations cgroup_file_operations = {
        .read = cgroup_file_read,
        .write = cgroup_file_write,
@@ -2501,11 +2594,22 @@ static const struct file_operations cgroup_file_operations = {
        .release = cgroup_file_release,
 };
 
+static const struct inode_operations cgroup_file_inode_operations = {
+       .setxattr = cgroup_setxattr,
+       .getxattr = cgroup_getxattr,
+       .listxattr = cgroup_listxattr,
+       .removexattr = cgroup_removexattr,
+};
+
 static const struct inode_operations cgroup_dir_inode_operations = {
        .lookup = cgroup_lookup,
        .mkdir = cgroup_mkdir,
        .rmdir = cgroup_rmdir,
        .rename = cgroup_rename,
+       .setxattr = cgroup_setxattr,
+       .getxattr = cgroup_getxattr,
+       .listxattr = cgroup_listxattr,
+       .removexattr = cgroup_removexattr,
 };
 
 static struct dentry *cgroup_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
@@ -2546,45 +2650,27 @@ static int cgroup_create_file(struct dentry *dentry, umode_t mode,
 
                /* start off with i_nlink == 2 (for "." entry) */
                inc_nlink(inode);
+               inc_nlink(dentry->d_parent->d_inode);
 
-               /* start with the directory inode held, so that we can
-                * populate it without racing with another mkdir */
-               mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
+               /*
+                * Control reaches here with cgroup_mutex held.
+                * @inode->i_mutex should nest outside cgroup_mutex but we
+                * want to populate it immediately without releasing
+                * cgroup_mutex.  As @inode isn't visible to anyone else
+                * yet, trylock will always succeed without affecting
+                * lockdep checks.
+                */
+               WARN_ON_ONCE(!mutex_trylock(&inode->i_mutex));
        } else if (S_ISREG(mode)) {
                inode->i_size = 0;
                inode->i_fop = &cgroup_file_operations;
+               inode->i_op = &cgroup_file_inode_operations;
        }
        d_instantiate(dentry, inode);
        dget(dentry);   /* Extra count - pin the dentry in core */
        return 0;
 }
 
-/*
- * cgroup_create_dir - create a directory for an object.
- * @cgrp: the cgroup we create the directory for. It must have a valid
- *        ->parent field. And we are going to fill its ->dentry field.
- * @dentry: dentry of the new cgroup
- * @mode: mode to set on new directory.
- */
-static int cgroup_create_dir(struct cgroup *cgrp, struct dentry *dentry,
-                               umode_t mode)
-{
-       struct dentry *parent;
-       int error = 0;
-
-       parent = cgrp->parent->dentry;
-       error = cgroup_create_file(dentry, S_IFDIR | mode, cgrp->root->sb);
-       if (!error) {
-               dentry->d_fsdata = cgrp;
-               inc_nlink(parent->d_inode);
-               rcu_assign_pointer(cgrp->dentry, dentry);
-               dget(dentry);
-       }
-       dput(dentry);
-
-       return error;
-}
-
 /**
  * cgroup_file_mode - deduce file mode of a control file
  * @cft: the control file in question
@@ -2613,7 +2699,7 @@ static umode_t cgroup_file_mode(const struct cftype *cft)
 }
 
 static int cgroup_add_file(struct cgroup *cgrp, struct cgroup_subsys *subsys,
-                          const struct cftype *cft)
+                          struct cftype *cft)
 {
        struct dentry *dir = cgrp->dentry;
        struct cgroup *parent = __d_cgrp(dir);
@@ -2623,6 +2709,8 @@ static int cgroup_add_file(struct cgroup *cgrp, struct cgroup_subsys *subsys,
        umode_t mode;
        char name[MAX_CGROUP_TYPE_NAMELEN + MAX_CFTYPE_NAME + 2] = { 0 };
 
+       simple_xattrs_init(&cft->xattrs);
+
        /* does @cft->flags tell us to skip creation on @cgrp? */
        if ((cft->flags & CFTYPE_NOT_ON_ROOT) && !cgrp->parent)
                return 0;
@@ -2663,9 +2751,9 @@ out:
 }
 
 static int cgroup_addrm_files(struct cgroup *cgrp, struct cgroup_subsys *subsys,
-                             const struct cftype cfts[], bool is_add)
+                             struct cftype cfts[], bool is_add)
 {
-       const struct cftype *cft;
+       struct cftype *cft;
        int err, ret = 0;
 
        for (cft = cfts; cft->name[0] != '\0'; cft++) {
@@ -2699,7 +2787,7 @@ static void cgroup_cfts_prepare(void)
 }
 
 static void cgroup_cfts_commit(struct cgroup_subsys *ss,
-                              const struct cftype *cfts, bool is_add)
+                              struct cftype *cfts, bool is_add)
        __releases(&cgroup_mutex) __releases(&cgroup_cft_mutex)
 {
        LIST_HEAD(pending);
@@ -2750,7 +2838,7 @@ static void cgroup_cfts_commit(struct cgroup_subsys *ss,
  * function currently returns 0 as long as @cfts registration is successful
  * even if some file creation attempts on existing cgroups fail.
  */
-int cgroup_add_cftypes(struct cgroup_subsys *ss, const struct cftype *cfts)
+int cgroup_add_cftypes(struct cgroup_subsys *ss, struct cftype *cfts)
 {
        struct cftype_set *set;
 
@@ -2780,7 +2868,7 @@ EXPORT_SYMBOL_GPL(cgroup_add_cftypes);
  * Returns 0 on successful unregistration, -ENOENT if @cfts is not
  * registered with @ss.
  */
-int cgroup_rm_cftypes(struct cgroup_subsys *ss, const struct cftype *cfts)
+int cgroup_rm_cftypes(struct cgroup_subsys *ss, struct cftype *cfts)
 {
        struct cftype_set *set;
 
@@ -2876,6 +2964,92 @@ static void cgroup_enable_task_cg_lists(void)
        write_unlock(&css_set_lock);
 }
 
+/**
+ * cgroup_next_descendant_pre - find the next descendant for pre-order walk
+ * @pos: the current position (%NULL to initiate traversal)
+ * @cgroup: cgroup whose descendants to walk
+ *
+ * To be used by cgroup_for_each_descendant_pre().  Find the next
+ * descendant to visit for pre-order traversal of @cgroup's descendants.
+ */
+struct cgroup *cgroup_next_descendant_pre(struct cgroup *pos,
+                                         struct cgroup *cgroup)
+{
+       struct cgroup *next;
+
+       WARN_ON_ONCE(!rcu_read_lock_held());
+
+       /* if first iteration, pretend we just visited @cgroup */
+       if (!pos) {
+               if (list_empty(&cgroup->children))
+                       return NULL;
+               pos = cgroup;
+       }
+
+       /* visit the first child if exists */
+       next = list_first_or_null_rcu(&pos->children, struct cgroup, sibling);
+       if (next)
+               return next;
+
+       /* no child, visit my or the closest ancestor's next sibling */
+       do {
+               next = list_entry_rcu(pos->sibling.next, struct cgroup,
+                                     sibling);
+               if (&next->sibling != &pos->parent->children)
+                       return next;
+
+               pos = pos->parent;
+       } while (pos != cgroup);
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(cgroup_next_descendant_pre);
+
+static struct cgroup *cgroup_leftmost_descendant(struct cgroup *pos)
+{
+       struct cgroup *last;
+
+       do {
+               last = pos;
+               pos = list_first_or_null_rcu(&pos->children, struct cgroup,
+                                            sibling);
+       } while (pos);
+
+       return last;
+}
+
+/**
+ * cgroup_next_descendant_post - find the next descendant for post-order walk
+ * @pos: the current position (%NULL to initiate traversal)
+ * @cgroup: cgroup whose descendants to walk
+ *
+ * To be used by cgroup_for_each_descendant_post().  Find the next
+ * descendant to visit for post-order traversal of @cgroup's descendants.
+ */
+struct cgroup *cgroup_next_descendant_post(struct cgroup *pos,
+                                          struct cgroup *cgroup)
+{
+       struct cgroup *next;
+
+       WARN_ON_ONCE(!rcu_read_lock_held());
+
+       /* if first iteration, visit the leftmost descendant */
+       if (!pos) {
+               next = cgroup_leftmost_descendant(cgroup);
+               return next != cgroup ? next : NULL;
+       }
+
+       /* if there's an unvisited sibling, visit its leftmost descendant */
+       next = list_entry_rcu(pos->sibling.next, struct cgroup, sibling);
+       if (&next->sibling != &pos->parent->children)
+               return cgroup_leftmost_descendant(next);
+
+       /* no sibling left, visit parent */
+       next = pos->parent;
+       return next != cgroup ? next : NULL;
+}
+EXPORT_SYMBOL_GPL(cgroup_next_descendant_post);
+
 void cgroup_iter_start(struct cgroup *cgrp, struct cgroup_iter *it)
        __acquires(css_set_lock)
 {
@@ -3726,7 +3900,7 @@ fail:
 static u64 cgroup_clone_children_read(struct cgroup *cgrp,
                                    struct cftype *cft)
 {
-       return clone_children(cgrp);
+       return test_bit(CGRP_CPUSET_CLONE_CHILDREN, &cgrp->flags);
 }
 
 static int cgroup_clone_children_write(struct cgroup *cgrp,
@@ -3734,9 +3908,9 @@ static int cgroup_clone_children_write(struct cgroup *cgrp,
                                     u64 val)
 {
        if (val)
-               set_bit(CGRP_CLONE_CHILDREN, &cgrp->flags);
+               set_bit(CGRP_CPUSET_CLONE_CHILDREN, &cgrp->flags);
        else
-               clear_bit(CGRP_CLONE_CHILDREN, &cgrp->flags);
+               clear_bit(CGRP_CPUSET_CLONE_CHILDREN, &cgrp->flags);
        return 0;
 }
 
@@ -3785,18 +3959,29 @@ static struct cftype files[] = {
        { }     /* terminate */
 };
 
-static int cgroup_populate_dir(struct cgroup *cgrp)
+/**
+ * cgroup_populate_dir - selectively creation of files in a directory
+ * @cgrp: target cgroup
+ * @base_files: true if the base files should be added
+ * @subsys_mask: mask of the subsystem ids whose files should be added
+ */
+static int cgroup_populate_dir(struct cgroup *cgrp, bool base_files,
+                              unsigned long subsys_mask)
 {
        int err;
        struct cgroup_subsys *ss;
 
-       err = cgroup_addrm_files(cgrp, NULL, files, true);
-       if (err < 0)
-               return err;
+       if (base_files) {
+               err = cgroup_addrm_files(cgrp, NULL, files, true);
+               if (err < 0)
+                       return err;
+       }
 
        /* process cftsets of each subsystem */
        for_each_subsys(cgrp->root, ss) {
                struct cftype_set *set;
+               if (!test_bit(ss->subsys_id, &subsys_mask))
+                       continue;
 
                list_for_each_entry(set, &ss->cftsets, node)
                        cgroup_addrm_files(cgrp, ss, set->cfts, true);
@@ -3838,7 +4023,7 @@ static void init_cgroup_css(struct cgroup_subsys_state *css,
        css->flags = 0;
        css->id = NULL;
        if (cgrp == dummytop)
-               set_bit(CSS_ROOT, &css->flags);
+               css->flags |= CSS_ROOT;
        BUG_ON(cgrp->subsys[ss->subsys_id]);
        cgrp->subsys[ss->subsys_id] = css;
 
@@ -3851,6 +4036,46 @@ static void init_cgroup_css(struct cgroup_subsys_state *css,
        INIT_WORK(&css->dput_work, css_dput_fn);
 }
 
+/* invoke ->post_create() on a new CSS and mark it online if successful */
+static int online_css(struct cgroup_subsys *ss, struct cgroup *cgrp)
+{
+       int ret = 0;
+
+       lockdep_assert_held(&cgroup_mutex);
+
+       if (ss->css_online)
+               ret = ss->css_online(cgrp);
+       if (!ret)
+               cgrp->subsys[ss->subsys_id]->flags |= CSS_ONLINE;
+       return ret;
+}
+
+/* if the CSS is online, invoke ->pre_destory() on it and mark it offline */
+static void offline_css(struct cgroup_subsys *ss, struct cgroup *cgrp)
+       __releases(&cgroup_mutex) __acquires(&cgroup_mutex)
+{
+       struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id];
+
+       lockdep_assert_held(&cgroup_mutex);
+
+       if (!(css->flags & CSS_ONLINE))
+               return;
+
+       /*
+        * css_offline() should be called with cgroup_mutex unlocked.  See
+        * 3fa59dfbc3 ("cgroup: fix potential deadlock in pre_destroy") for
+        * details.  This temporary unlocking should go away once
+        * cgroup_mutex is unexported from controllers.
+        */
+       if (ss->css_offline) {
+               mutex_unlock(&cgroup_mutex);
+               ss->css_offline(cgrp);
+               mutex_lock(&cgroup_mutex);
+       }
+
+       cgrp->subsys[ss->subsys_id]->flags &= ~CSS_ONLINE;
+}
+
 /*
  * cgroup_create - create a cgroup
  * @parent: cgroup that will be parent of the new cgroup
@@ -3881,7 +4106,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
         */
        if (!cgroup_lock_live_group(parent)) {
                err = -ENODEV;
-               goto err_free;
+               goto err_free_cgrp;
        }
 
        /* Grab a reference on the superblock so the hierarchy doesn't
@@ -3900,70 +4125,92 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
        if (notify_on_release(parent))
                set_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags);
 
-       if (clone_children(parent))
-               set_bit(CGRP_CLONE_CHILDREN, &cgrp->flags);
+       if (test_bit(CGRP_CPUSET_CLONE_CHILDREN, &parent->flags))
+               set_bit(CGRP_CPUSET_CLONE_CHILDREN, &cgrp->flags);
 
        for_each_subsys(root, ss) {
-               struct cgroup_subsys_state *css = ss->create(cgrp);
+               struct cgroup_subsys_state *css;
 
+               css = ss->css_alloc(cgrp);
                if (IS_ERR(css)) {
                        err = PTR_ERR(css);
-                       goto err_destroy;
+                       goto err_free_all;
                }
                init_cgroup_css(css, ss, cgrp);
                if (ss->use_id) {
                        err = alloc_css_id(ss, parent, cgrp);
                        if (err)
-                               goto err_destroy;
+                               goto err_free_all;
                }
-               /* At error, ->destroy() callback has to free assigned ID. */
-               if (clone_children(parent) && ss->post_clone)
+               /* At error, ->css_free() callback has to free assigned ID. */
+               if (test_bit(CGRP_CPUSET_CLONE_CHILDREN, &parent->flags) &&
+                   ss->post_clone)
                        ss->post_clone(cgrp);
-       }
 
-       list_add(&cgrp->sibling, &cgrp->parent->children);
-       root->number_of_cgroups++;
+               if (ss->broken_hierarchy && !ss->warned_broken_hierarchy &&
+                   parent->parent) {
+                       pr_warning("cgroup: %s (%d) created nested cgroup for controller \"%s\" which has incomplete hierarchy support. Nested cgroups may change behavior in the future.\n",
+                                  current->comm, current->pid, ss->name);
+                       if (!strcmp(ss->name, "memory"))
+                               pr_warning("cgroup: \"memory\" requires setting use_hierarchy to 1 on the root.\n");
+                       ss->warned_broken_hierarchy = true;
+               }
+       }
 
-       err = cgroup_create_dir(cgrp, dentry, mode);
+       /*
+        * Create directory.  cgroup_create_file() returns with the new
+        * directory locked on success so that it can be populated without
+        * dropping cgroup_mutex.
+        */
+       err = cgroup_create_file(dentry, S_IFDIR | mode, sb);
        if (err < 0)
-               goto err_remove;
+               goto err_free_all;
+       lockdep_assert_held(&dentry->d_inode->i_mutex);
+
+       /* allocation complete, commit to creation */
+       dentry->d_fsdata = cgrp;
+       cgrp->dentry = dentry;
+       list_add_tail(&cgrp->allcg_node, &root->allcg_list);
+       list_add_tail_rcu(&cgrp->sibling, &cgrp->parent->children);
+       root->number_of_cgroups++;
 
        /* each css holds a ref to the cgroup's dentry */
        for_each_subsys(root, ss)
                dget(dentry);
 
-       /* The cgroup directory was pre-locked for us */
-       BUG_ON(!mutex_is_locked(&cgrp->dentry->d_inode->i_mutex));
-
-       list_add_tail(&cgrp->allcg_node, &root->allcg_list);
+       /* creation succeeded, notify subsystems */
+       for_each_subsys(root, ss) {
+               err = online_css(ss, cgrp);
+               if (err)
+                       goto err_destroy;
+       }
 
-       err = cgroup_populate_dir(cgrp);
-       /* If err < 0, we have a half-filled directory - oh well ;) */
+       err = cgroup_populate_dir(cgrp, true, root->subsys_mask);
+       if (err)
+               goto err_destroy;
 
        mutex_unlock(&cgroup_mutex);
        mutex_unlock(&cgrp->dentry->d_inode->i_mutex);
 
        return 0;
 
- err_remove:
-
-       list_del(&cgrp->sibling);
-       root->number_of_cgroups--;
-
- err_destroy:
-
+err_free_all:
        for_each_subsys(root, ss) {
                if (cgrp->subsys[ss->subsys_id])
-                       ss->destroy(cgrp);
+                       ss->css_free(cgrp);
        }
-
        mutex_unlock(&cgroup_mutex);
-
        /* Release the reference count that we took on the superblock */
        deactivate_super(sb);
-err_free:
+err_free_cgrp:
        kfree(cgrp);
        return err;
+
+err_destroy:
+       cgroup_destroy_locked(cgrp);
+       mutex_unlock(&cgroup_mutex);
+       mutex_unlock(&dentry->d_inode->i_mutex);
+       return err;
 }
 
 static int cgroup_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
@@ -4015,22 +4262,20 @@ static int cgroup_has_css_refs(struct cgroup *cgrp)
        return 0;
 }
 
-static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)
+static int cgroup_destroy_locked(struct cgroup *cgrp)
+       __releases(&cgroup_mutex) __acquires(&cgroup_mutex)
 {
-       struct cgroup *cgrp = dentry->d_fsdata;
-       struct dentry *d;
-       struct cgroup *parent;
+       struct dentry *d = cgrp->dentry;
+       struct cgroup *parent = cgrp->parent;
        DEFINE_WAIT(wait);
        struct cgroup_event *event, *tmp;
        struct cgroup_subsys *ss;
 
-       /* the vfs holds both inode->i_mutex already */
-       mutex_lock(&cgroup_mutex);
-       parent = cgrp->parent;
-       if (atomic_read(&cgrp->count) || !list_empty(&cgrp->children)) {
-               mutex_unlock(&cgroup_mutex);
+       lockdep_assert_held(&d->d_inode->i_mutex);
+       lockdep_assert_held(&cgroup_mutex);
+
+       if (atomic_read(&cgrp->count) || !list_empty(&cgrp->children))
                return -EBUSY;
-       }
 
        /*
         * Block new css_tryget() by deactivating refcnt and mark @cgrp
@@ -4046,16 +4291,9 @@ static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)
        }
        set_bit(CGRP_REMOVED, &cgrp->flags);
 
-       /*
-        * Tell subsystems to initate destruction.  pre_destroy() should be
-        * called with cgroup_mutex unlocked.  See 3fa59dfbc3 ("cgroup: fix
-        * potential deadlock in pre_destroy") for details.
-        */
-       mutex_unlock(&cgroup_mutex);
+       /* tell subsystems to initate destruction */
        for_each_subsys(cgrp->root, ss)
-               if (ss->pre_destroy)
-                       WARN_ON_ONCE(ss->pre_destroy(cgrp));
-       mutex_lock(&cgroup_mutex);
+               offline_css(ss, cgrp);
 
        /*
         * Put all the base refs.  Each css holds an extra reference to the
@@ -4073,12 +4311,10 @@ static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)
        raw_spin_unlock(&release_list_lock);
 
        /* delete this cgroup from parent->children */
-       list_del_init(&cgrp->sibling);
-
+       list_del_rcu(&cgrp->sibling);
        list_del_init(&cgrp->allcg_node);
 
-       d = dget(cgrp->dentry);
-
+       dget(d);
        cgroup_d_remove_dir(d);
        dput(d);
 
@@ -4099,10 +4335,20 @@ static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)
        }
        spin_unlock(&cgrp->event_list_lock);
 
-       mutex_unlock(&cgroup_mutex);
        return 0;
 }
 
+static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)
+{
+       int ret;
+
+       mutex_lock(&cgroup_mutex);
+       ret = cgroup_destroy_locked(dentry->d_fsdata);
+       mutex_unlock(&cgroup_mutex);
+
+       return ret;
+}
+
 static void __init_or_module cgroup_init_cftsets(struct cgroup_subsys *ss)
 {
        INIT_LIST_HEAD(&ss->cftsets);
@@ -4123,13 +4369,15 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss)
 
        printk(KERN_INFO "Initializing cgroup subsys %s\n", ss->name);
 
+       mutex_lock(&cgroup_mutex);
+
        /* init base cftset */
        cgroup_init_cftsets(ss);
 
        /* Create the top cgroup state for this subsystem */
        list_add(&ss->sibling, &rootnode.subsys_list);
        ss->root = &rootnode;
-       css = ss->create(dummytop);
+       css = ss->css_alloc(dummytop);
        /* We don't handle early failures gracefully */
        BUG_ON(IS_ERR(css));
        init_cgroup_css(css, ss, dummytop);
@@ -4138,7 +4386,7 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss)
         * pointer to this state - since the subsystem is
         * newly registered, all tasks and hence the
         * init_css_set is in the subsystem's top cgroup. */
-       init_css_set.subsys[ss->subsys_id] = dummytop->subsys[ss->subsys_id];
+       init_css_set.subsys[ss->subsys_id] = css;
 
        need_forkexit_callback |= ss->fork || ss->exit;
 
@@ -4148,6 +4396,9 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss)
        BUG_ON(!list_empty(&init_task.tasks));
 
        ss->active = 1;
+       BUG_ON(online_css(ss, dummytop));
+
+       mutex_unlock(&cgroup_mutex);
 
        /* this function shouldn't be used with modular subsystems, since they
         * need to register a subsys_id, among other things */
@@ -4165,12 +4416,12 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss)
  */
 int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss)
 {
-       int i;
        struct cgroup_subsys_state *css;
+       int i, ret;
 
        /* check name and function validity */
        if (ss->name == NULL || strlen(ss->name) > MAX_CGROUP_TYPE_NAMELEN ||
-           ss->create == NULL || ss->destroy == NULL)
+           ss->css_alloc == NULL || ss->css_free == NULL)
                return -EINVAL;
 
        /*
@@ -4187,8 +4438,7 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss)
         * since cgroup_init_subsys will have already taken care of it.
         */
        if (ss->module == NULL) {
-               /* a few sanity checks */
-               BUG_ON(ss->subsys_id >= CGROUP_BUILTIN_SUBSYS_COUNT);
+               /* a sanity check */
                BUG_ON(subsys[ss->subsys_id] != ss);
                return 0;
        }
@@ -4196,33 +4446,18 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss)
        /* init base cftset */
        cgroup_init_cftsets(ss);
 
-       /*
-        * need to register a subsys id before anything else - for example,
-        * init_cgroup_css needs it.
-        */
        mutex_lock(&cgroup_mutex);
-       /* find the first empty slot in the array */
-       for (i = CGROUP_BUILTIN_SUBSYS_COUNT; i < CGROUP_SUBSYS_COUNT; i++) {
-               if (subsys[i] == NULL)
-                       break;
-       }
-       if (i == CGROUP_SUBSYS_COUNT) {
-               /* maximum number of subsystems already registered! */
-               mutex_unlock(&cgroup_mutex);
-               return -EBUSY;
-       }
-       /* assign ourselves the subsys_id */
-       ss->subsys_id = i;
-       subsys[i] = ss;
+       subsys[ss->subsys_id] = ss;
 
        /*
-        * no ss->create seems to need anything important in the ss struct, so
-        * this can happen first (i.e. before the rootnode attachment).
+        * no ss->css_alloc seems to need anything important in the ss
+        * struct, so this can happen first (i.e. before the rootnode
+        * attachment).
         */
-       css = ss->create(dummytop);
+       css = ss->css_alloc(dummytop);
        if (IS_ERR(css)) {
                /* failure case - need to deassign the subsys[] slot. */
-               subsys[i] = NULL;
+               subsys[ss->subsys_id] = NULL;
                mutex_unlock(&cgroup_mutex);
                return PTR_ERR(css);
        }
@@ -4234,14 +4469,9 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss)
        init_cgroup_css(css, ss, dummytop);
        /* init_idr must be after init_cgroup_css because it sets css->id. */
        if (ss->use_id) {
-               int ret = cgroup_init_idr(ss, css);
-               if (ret) {
-                       dummytop->subsys[ss->subsys_id] = NULL;
-                       ss->destroy(dummytop);
-                       subsys[i] = NULL;
-                       mutex_unlock(&cgroup_mutex);
-                       return ret;
-               }
+               ret = cgroup_init_idr(ss, css);
+               if (ret)
+                       goto err_unload;
        }
 
        /*
@@ -4274,10 +4504,19 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss)
        write_unlock(&css_set_lock);
 
        ss->active = 1;
+       ret = online_css(ss, dummytop);
+       if (ret)
+               goto err_unload;
 
        /* success! */
        mutex_unlock(&cgroup_mutex);
        return 0;
+
+err_unload:
+       mutex_unlock(&cgroup_mutex);
+       /* @ss can't be mounted here as try_module_get() would fail */
+       cgroup_unload_subsys(ss);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(cgroup_load_subsys);
 
@@ -4304,8 +4543,16 @@ void cgroup_unload_subsys(struct cgroup_subsys *ss)
        BUG_ON(ss->root != &rootnode);
 
        mutex_lock(&cgroup_mutex);
+
+       offline_css(ss, dummytop);
+       ss->active = 0;
+
+       if (ss->use_id) {
+               idr_remove_all(&ss->idr);
+               idr_destroy(&ss->idr);
+       }
+
        /* deassign the subsys_id */
-       BUG_ON(ss->subsys_id < CGROUP_BUILTIN_SUBSYS_COUNT);
        subsys[ss->subsys_id] = NULL;
 
        /* remove subsystem from rootnode's list of subsystems */
@@ -4320,7 +4567,6 @@ void cgroup_unload_subsys(struct cgroup_subsys *ss)
                struct css_set *cg = link->cg;
 
                hlist_del(&cg->hlist);
-               BUG_ON(!cg->subsys[ss->subsys_id]);
                cg->subsys[ss->subsys_id] = NULL;
                hhead = css_set_hash(cg->subsys);
                hlist_add_head(&cg->hlist, hhead);
@@ -4328,12 +4574,12 @@ void cgroup_unload_subsys(struct cgroup_subsys *ss)
        write_unlock(&css_set_lock);
 
        /*
-        * remove subsystem's css from the dummytop and free it - need to free
-        * before marking as null because ss->destroy needs the cgrp->subsys
-        * pointer to find their state. note that this also takes care of
-        * freeing the css_id.
+        * remove subsystem's css from the dummytop and free it - need to
+        * free before marking as null because ss->css_free needs the
+        * cgrp->subsys pointer to find their state. note that this also
+        * takes care of freeing the css_id.
         */
-       ss->destroy(dummytop);
+       ss->css_free(dummytop);
        dummytop->subsys[ss->subsys_id] = NULL;
 
        mutex_unlock(&cgroup_mutex);
@@ -4368,14 +4614,17 @@ int __init cgroup_init_early(void)
        for (i = 0; i < CSS_SET_TABLE_SIZE; i++)
                INIT_HLIST_HEAD(&css_set_table[i]);
 
-       /* at bootup time, we don't worry about modular subsystems */
-       for (i = 0; i < CGROUP_BUILTIN_SUBSYS_COUNT; i++) {
+       for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
                struct cgroup_subsys *ss = subsys[i];
 
+               /* at bootup time, we don't worry about modular subsystems */
+               if (!ss || ss->module)
+                       continue;
+
                BUG_ON(!ss->name);
                BUG_ON(strlen(ss->name) > MAX_CGROUP_TYPE_NAMELEN);
-               BUG_ON(!ss->create);
-               BUG_ON(!ss->destroy);
+               BUG_ON(!ss->css_alloc);
+               BUG_ON(!ss->css_free);
                if (ss->subsys_id != i) {
                        printk(KERN_ERR "cgroup: Subsys %s id == %d\n",
                               ss->name, ss->subsys_id);
@@ -4404,9 +4653,12 @@ int __init cgroup_init(void)
        if (err)
                return err;
 
-       /* at bootup time, we don't worry about modular subsystems */
-       for (i = 0; i < CGROUP_BUILTIN_SUBSYS_COUNT; i++) {
+       for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
                struct cgroup_subsys *ss = subsys[i];
+
+               /* at bootup time, we don't worry about modular subsystems */
+               if (!ss || ss->module)
+                       continue;
                if (!ss->early_init)
                        cgroup_init_subsys(ss);
                if (ss->use_id)
@@ -4561,70 +4813,37 @@ static const struct file_operations proc_cgroupstats_operations = {
  *
  * A pointer to the shared css_set was automatically copied in
  * fork.c by dup_task_struct().  However, we ignore that copy, since
- * it was not made under the protection of RCU, cgroup_mutex or
- * threadgroup_change_begin(), so it might no longer be a valid
- * cgroup pointer.  cgroup_attach_task() might have already changed
- * current->cgroups, allowing the previously referenced cgroup
- * group to be removed and freed.
- *
- * Outside the pointer validity we also need to process the css_set
- * inheritance between threadgoup_change_begin() and
- * threadgoup_change_end(), this way there is no leak in any process
- * wide migration performed by cgroup_attach_proc() that could otherwise
- * miss a thread because it is too early or too late in the fork stage.
+ * it was not made under the protection of RCU or cgroup_mutex, so
+ * might no longer be a valid cgroup pointer.  cgroup_attach_task() might
+ * have already changed current->cgroups, allowing the previously
+ * referenced cgroup group to be removed and freed.
  *
  * At the point that cgroup_fork() is called, 'current' is the parent
  * task, and the passed argument 'child' points to the child task.
  */
 void cgroup_fork(struct task_struct *child)
 {
-       /*
-        * We don't need to task_lock() current because current->cgroups
-        * can't be changed concurrently here. The parent obviously hasn't
-        * exited and called cgroup_exit(), and we are synchronized against
-        * cgroup migration through threadgroup_change_begin().
-        */
+       task_lock(current);
        child->cgroups = current->cgroups;
        get_css_set(child->cgroups);
+       task_unlock(current);
        INIT_LIST_HEAD(&child->cg_list);
 }
 
-/**
- * cgroup_fork_callbacks - run fork callbacks
- * @child: the new task
- *
- * Called on a new task very soon before adding it to the
- * tasklist. No need to take any locks since no-one can
- * be operating on this task.
- */
-void cgroup_fork_callbacks(struct task_struct *child)
-{
-       if (need_forkexit_callback) {
-               int i;
-               /*
-                * forkexit callbacks are only supported for builtin
-                * subsystems, and the builtin section of the subsys array is
-                * immutable, so we don't need to lock the subsys array here.
-                */
-               for (i = 0; i < CGROUP_BUILTIN_SUBSYS_COUNT; i++) {
-                       struct cgroup_subsys *ss = subsys[i];
-                       if (ss->fork)
-                               ss->fork(child);
-               }
-       }
-}
-
 /**
  * cgroup_post_fork - called on a new task after adding it to the task list
  * @child: the task in question
  *
- * Adds the task to the list running through its css_set if necessary.
- * Has to be after the task is visible on the task list in case we race
- * with the first call to cgroup_iter_start() - to guarantee that the
- * new task ends up on its list.
+ * Adds the task to the list running through its css_set if necessary and
+ * call the subsystem fork() callbacks.  Has to be after the task is
+ * visible on the task list in case we race with the first call to
+ * cgroup_iter_start() - to guarantee that the new task ends up on its
+ * list.
  */
 void cgroup_post_fork(struct task_struct *child)
 {
+       int i;
+
        /*
         * use_task_css_set_links is set to 1 before we walk the tasklist
         * under the tasklist_lock and we read it here after we added the child
@@ -4638,22 +4857,36 @@ void cgroup_post_fork(struct task_struct *child)
         */
        if (use_task_css_set_links) {
                write_lock(&css_set_lock);
-               if (list_empty(&child->cg_list)) {
+               task_lock(child);
+               if (list_empty(&child->cg_list))
+                       list_add(&child->cg_list, &child->cgroups->tasks);
+               task_unlock(child);
+               write_unlock(&css_set_lock);
+       }
+
+       /*
+        * Call ss->fork().  This must happen after @child is linked on
+        * css_set; otherwise, @child might change state between ->fork()
+        * and addition to css_set.
+        */
+       if (need_forkexit_callback) {
+               for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
+                       struct cgroup_subsys *ss = subsys[i];
+
                        /*
-                        * It's safe to use child->cgroups without task_lock()
-                        * here because we are protected through
-                        * threadgroup_change_begin() against concurrent
-                        * css_set change in cgroup_task_migrate(). Also
-                        * the task can't exit at that point until
-                        * wake_up_new_task() is called, so we are protected
-                        * against cgroup_exit() setting child->cgroup to
-                        * init_css_set.
+                        * fork/exit callbacks are supported only for
+                        * builtin subsystems and we don't need further
+                        * synchronization as they never go away.
                         */
-                       list_add(&child->cg_list, &child->cgroups->tasks);
+                       if (!ss || ss->module)
+                               continue;
+
+                       if (ss->fork)
+                               ss->fork(child);
                }
-               write_unlock(&css_set_lock);
        }
 }
+
 /**
  * cgroup_exit - detach cgroup from exiting task
  * @tsk: pointer to task_struct of exiting process
@@ -4712,12 +4945,13 @@ void cgroup_exit(struct task_struct *tsk, int run_callbacks)
        tsk->cgroups = &init_css_set;
 
        if (run_callbacks && need_forkexit_callback) {
-               /*
-                * modular subsystems can't use callbacks, so no need to lock
-                * the subsys array
-                */
-               for (i = 0; i < CGROUP_BUILTIN_SUBSYS_COUNT; i++) {
+               for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
                        struct cgroup_subsys *ss = subsys[i];
+
+                       /* modular subsystems can't use callbacks */
+                       if (!ss || ss->module)
+                               continue;
+
                        if (ss->exit) {
                                struct cgroup *old_cgrp =
                                        rcu_dereference_raw(cg->subsys[i])->cgroup;
@@ -4903,13 +5137,17 @@ static int __init cgroup_disable(char *str)
        while ((token = strsep(&str, ",")) != NULL) {
                if (!*token)
                        continue;
-               /*
-                * cgroup_disable, being at boot time, can't know about module
-                * subsystems, so we don't worry about them.
-                */
-               for (i = 0; i < CGROUP_BUILTIN_SUBSYS_COUNT; i++) {
+               for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
                        struct cgroup_subsys *ss = subsys[i];
 
+                       /*
+                        * cgroup_disable, being at boot time, can't
+                        * know about module subsystems, so we don't
+                        * worry about them.
+                        */
+                       if (!ss || ss->module)
+                               continue;
+
                        if (!strcmp(token, ss->name)) {
                                ss->disabled = 1;
                                printk(KERN_INFO "Disabling %s control group"
@@ -5198,7 +5436,7 @@ struct cgroup_subsys_state *cgroup_css_from_dir(struct file *f, int id)
 }
 
 #ifdef CONFIG_CGROUP_DEBUG
-static struct cgroup_subsys_state *debug_create(struct cgroup *cont)
+static struct cgroup_subsys_state *debug_css_alloc(struct cgroup *cont)
 {
        struct cgroup_subsys_state *css = kzalloc(sizeof(*css), GFP_KERNEL);
 
@@ -5208,7 +5446,7 @@ static struct cgroup_subsys_state *debug_create(struct cgroup *cont)
        return css;
 }
 
-static void debug_destroy(struct cgroup *cont)
+static void debug_css_free(struct cgroup *cont)
 {
        kfree(cont->subsys[debug_subsys_id]);
 }
@@ -5337,8 +5575,8 @@ static struct cftype debug_files[] =  {
 
 struct cgroup_subsys debug_subsys = {
        .name = "debug",
-       .create = debug_create,
-       .destroy = debug_destroy,
+       .css_alloc = debug_css_alloc,
+       .css_free = debug_css_free,
        .subsys_id = debug_subsys_id,
        .base_cftypes = debug_files,
 };