diff options
Diffstat (limited to 'kernel/cgroup.c')
| -rw-r--r-- | kernel/cgroup.c | 373 | 
1 files changed, 240 insertions, 133 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 79818507e44..f24f724620d 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -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; @@ -276,7 +277,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) @@ -556,7 +558,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 +826,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; @@ -912,15 +915,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);  } @@ -963,12 +970,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); +	}  }  /* @@ -977,8 +1001,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); @@ -1022,22 +1047,22 @@ void cgroup_release_and_wakeup_rmdir(struct cgroup_subsys_state *css)   * 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: @@ -1062,7 +1087,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]); @@ -1075,7 +1100,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]); @@ -1088,7 +1113,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]); @@ -1105,7 +1130,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; @@ -1121,6 +1146,8 @@ 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)) @@ -1132,7 +1159,7 @@ 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; @@ -1189,6 +1216,10 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)  			opts->clone_children = true;  			continue;  		} +		if (!strcmp(token, "xattr")) { +			set_bit(ROOT_XATTR, &opts->flags); +			continue; +		}  		if (!strncmp(token, "release_agent=", 14)) {  			/* Specifying two release agents is forbidden */  			if (opts->release_agent) @@ -1237,7 +1268,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; @@ -1258,7 +1289,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);  		}  	} @@ -1270,19 +1301,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;  	/* @@ -1291,10 +1322,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; @@ -1307,11 +1338,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);  		} @@ -1321,13 +1352,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);  	} @@ -1339,6 +1370,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); @@ -1350,27 +1382,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); @@ -1401,6 +1437,7 @@ static void init_cgroup_housekeeping(struct cgroup *cgrp)  	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) @@ -1455,8 +1492,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; @@ -1466,7 +1503,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); @@ -1479,7 +1516,7 @@ 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); @@ -1511,7 +1548,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) @@ -1629,7 +1666,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; @@ -1669,7 +1706,7 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,  		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); @@ -1681,7 +1718,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); @@ -1695,7 +1732,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); @@ -1745,6 +1782,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);  } @@ -1923,9 +1962,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);  }  /** @@ -2551,6 +2589,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, @@ -2559,11 +2655,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) @@ -2611,6 +2718,7 @@ static int cgroup_create_file(struct dentry *dentry, umode_t mode,  	} 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 */ @@ -2671,7 +2779,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); @@ -2681,6 +2789,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; @@ -2721,9 +2831,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++) { @@ -2757,7 +2867,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); @@ -2808,7 +2918,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; @@ -2838,7 +2948,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; @@ -3843,18 +3953,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); @@ -3954,8 +4075,9 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,  		set_bit(CGRP_CLONE_CHILDREN, &cgrp->flags);  	for_each_subsys(root, ss) { -		struct cgroup_subsys_state *css = ss->create(cgrp); +		struct cgroup_subsys_state *css; +		css = ss->create(cgrp);  		if (IS_ERR(css)) {  			err = PTR_ERR(css);  			goto err_destroy; @@ -3969,6 +4091,15 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,  		/* At error, ->destroy() callback has to free assigned ID. */  		if (clone_children(parent) && ss->post_clone)  			ss->post_clone(cgrp); + +		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; +		}  	}  	list_add(&cgrp->sibling, &cgrp->parent->children); @@ -3988,7 +4119,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,  	list_add_tail(&cgrp->allcg_node, &root->allcg_list); -	err = cgroup_populate_dir(cgrp); +	err = cgroup_populate_dir(cgrp, true, root->subsys_mask);  	/* If err < 0, we have a half-filled directory - oh well ;) */  	mutex_unlock(&cgroup_mutex); @@ -4321,8 +4452,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;  	} @@ -4330,24 +4460,8 @@ 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 @@ -4356,7 +4470,7 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss)  	css = ss->create(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);  	} @@ -4372,7 +4486,7 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss)  		if (ret) {  			dummytop->subsys[ss->subsys_id] = NULL;  			ss->destroy(dummytop); -			subsys[i] = NULL; +			subsys[ss->subsys_id] = NULL;  			mutex_unlock(&cgroup_mutex);  			return ret;  		} @@ -4439,7 +4553,6 @@ void cgroup_unload_subsys(struct cgroup_subsys *ss)  	mutex_lock(&cgroup_mutex);  	/* 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 */ @@ -4502,10 +4615,13 @@ 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); @@ -4538,9 +4654,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) @@ -4695,31 +4814,20 @@ 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);  } @@ -4735,13 +4843,16 @@ 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++) { +		for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {  			struct cgroup_subsys *ss = subsys[i]; + +			/* +			 * forkexit callbacks are only supported for +			 * builtin subsystems. +			 */ +			if (!ss || ss->module) +				continue; +  			if (ss->fork)  				ss->fork(child);  		} @@ -4772,19 +4883,10 @@ 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)) { -			/* -			 * 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. -			 */ +		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);  	}  } @@ -4846,12 +4948,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; @@ -5037,13 +5140,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"  |