diff options
Diffstat (limited to 'kernel/cgroup.c')
| -rw-r--r-- | kernel/cgroup.c | 262 | 
1 files changed, 7 insertions, 255 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 2418b6e71a85..e0839bcd48c8 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -125,38 +125,6 @@ struct cfent {  };  /* - * CSS ID -- ID per subsys's Cgroup Subsys State(CSS). used only when - * cgroup_subsys->use_id != 0. - */ -#define CSS_ID_MAX	(65535) -struct css_id { -	/* -	 * The css to which this ID points. This pointer is set to valid value -	 * after cgroup is populated. If cgroup is removed, this will be NULL. -	 * This pointer is expected to be RCU-safe because destroy() -	 * is called after synchronize_rcu(). But for safe use, css_tryget() -	 * should be used for avoiding race. -	 */ -	struct cgroup_subsys_state __rcu *css; -	/* -	 * ID of this css. -	 */ -	unsigned short id; -	/* -	 * Depth in hierarchy which this ID belongs to. -	 */ -	unsigned short depth; -	/* -	 * ID is freed by RCU. (and lookup routine is RCU safe.) -	 */ -	struct rcu_head rcu_head; -	/* -	 * Hierarchy of CSS ID belongs to. -	 */ -	unsigned short stack[0]; /* Array of Length (depth+1) */ -}; - -/*   * cgroup_event represents events which userspace want to receive.   */  struct cgroup_event { @@ -387,9 +355,6 @@ struct cgrp_cset_link {  static struct css_set init_css_set;  static struct cgrp_cset_link init_cgrp_cset_link; -static int cgroup_init_idr(struct cgroup_subsys *ss, -			   struct cgroup_subsys_state *css); -  /*   * css_set_lock protects the list of css_set objects, and the chain of   * tasks off each css_set.  Nests outside task->alloc_lock due to @@ -841,8 +806,6 @@ static struct backing_dev_info cgroup_backing_dev_info = {  	.capabilities	= BDI_CAP_NO_ACCT_AND_WRITEBACK,  }; -static int alloc_css_id(struct cgroup_subsys_state *child_css); -  static struct inode *cgroup_new_inode(umode_t mode, struct super_block *sb)  {  	struct inode *inode = new_inode(sb); @@ -2039,7 +2002,7 @@ static int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk,  		/* @tsk either already exited or can't exit until the end */  		if (tsk->flags & PF_EXITING) -			continue; +			goto next;  		/* as per above, nr_threads may decrease, but not increase. */  		BUG_ON(i >= group_size); @@ -2047,7 +2010,7 @@ static int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk,  		ent.cgrp = task_cgroup_from_root(tsk, root);  		/* nothing to do if this task is already in the cgroup */  		if (ent.cgrp == cgrp) -			continue; +			goto next;  		/*  		 * saying GFP_ATOMIC has no effect here because we did prealloc  		 * earlier, but it's good form to communicate our expectations. @@ -2055,7 +2018,7 @@ static int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk,  		retval = flex_array_put(group, i, &ent, GFP_ATOMIC);  		BUG_ON(retval != 0);  		i++; - +	next:  		if (!threadgroup)  			break;  	} while_each_thread(leader, tsk); @@ -3188,11 +3151,9 @@ css_next_descendant_post(struct cgroup_subsys_state *pos,  	WARN_ON_ONCE(!rcu_read_lock_held()); -	/* if first iteration, visit the leftmost descendant */ -	if (!pos) { -		next = css_leftmost_descendant(root); -		return next != root ? next : NULL; -	} +	/* if first iteration, visit leftmost descendant which may be @root */ +	if (!pos) +		return css_leftmost_descendant(root);  	/* if we visited @root, we're done */  	if (pos == root) @@ -4242,21 +4203,6 @@ static int cgroup_populate_dir(struct cgroup *cgrp, unsigned long subsys_mask)  				goto err;  		}  	} - -	/* This cgroup is ready now */ -	for_each_root_subsys(cgrp->root, ss) { -		struct cgroup_subsys_state *css = cgroup_css(cgrp, ss); -		struct css_id *id = rcu_dereference_protected(css->id, true); - -		/* -		 * Update id->css pointer and make this css visible from -		 * CSS ID functions. This pointer will be dereferened -		 * from RCU-read-side without locks. -		 */ -		if (id) -			rcu_assign_pointer(id->css, css); -	} -  	return 0;  err:  	cgroup_clear_dir(cgrp, subsys_mask); @@ -4325,7 +4271,6 @@ static void init_css(struct cgroup_subsys_state *css, struct cgroup_subsys *ss,  	css->cgroup = cgrp;  	css->ss = ss;  	css->flags = 0; -	css->id = NULL;  	if (cgrp->parent)  		css->parent = cgroup_css(cgrp->parent, ss); @@ -4457,12 +4402,6 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,  			goto err_free_all;  		init_css(css, ss, cgrp); - -		if (ss->use_id) { -			err = alloc_css_id(css); -			if (err) -				goto err_free_all; -		}  	}  	/* @@ -4927,12 +4866,6 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss)  	/* our new subsystem will be attached to the dummy hierarchy. */  	init_css(css, ss, cgroup_dummy_top); -	/* init_idr must be after init_css() because it sets css->id. */ -	if (ss->use_id) { -		ret = cgroup_init_idr(ss, css); -		if (ret) -			goto err_unload; -	}  	/*  	 * Now we need to entangle the css into the existing css_sets. unlike @@ -4998,9 +4931,6 @@ void cgroup_unload_subsys(struct cgroup_subsys *ss)  	offline_css(cgroup_css(cgroup_dummy_top, ss)); -	if (ss->use_id) -		idr_destroy(&ss->idr); -  	/* deassign the subsys_id */  	cgroup_subsys[ss->subsys_id] = NULL; @@ -5027,8 +4957,7 @@ void cgroup_unload_subsys(struct cgroup_subsys *ss)  	/*  	 * remove subsystem's css from the cgroup_dummy_top 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. +	 * the cgrp->subsys pointer to find their state.  	 */  	ss->css_free(cgroup_css(cgroup_dummy_top, ss));  	RCU_INIT_POINTER(cgroup_dummy_top->subsys[ss->subsys_id], NULL); @@ -5099,8 +5028,6 @@ int __init cgroup_init(void)  	for_each_builtin_subsys(ss, i) {  		if (!ss->early_init)  			cgroup_init_subsys(ss); -		if (ss->use_id) -			cgroup_init_idr(ss, init_css_set.subsys[ss->subsys_id]);  	}  	/* allocate id for the dummy hierarchy */ @@ -5520,181 +5447,6 @@ static int __init cgroup_disable(char *str)  }  __setup("cgroup_disable=", cgroup_disable); -/* - * Functons for CSS ID. - */ - -/* to get ID other than 0, this should be called when !cgroup_is_dead() */ -unsigned short css_id(struct cgroup_subsys_state *css) -{ -	struct css_id *cssid; - -	/* -	 * This css_id() can return correct value when somone has refcnt -	 * on this or this is under rcu_read_lock(). Once css->id is allocated, -	 * it's unchanged until freed. -	 */ -	cssid = rcu_dereference_raw(css->id); - -	if (cssid) -		return cssid->id; -	return 0; -} -EXPORT_SYMBOL_GPL(css_id); - -/** - *  css_is_ancestor - test "root" css is an ancestor of "child" - * @child: the css to be tested. - * @root: the css supporsed to be an ancestor of the child. - * - * Returns true if "root" is an ancestor of "child" in its hierarchy. Because - * this function reads css->id, the caller must hold rcu_read_lock(). - * But, considering usual usage, the csses should be valid objects after test. - * Assuming that the caller will do some action to the child if this returns - * returns true, the caller must take "child";s reference count. - * If "child" is valid object and this returns true, "root" is valid, too. - */ - -bool css_is_ancestor(struct cgroup_subsys_state *child, -		    const struct cgroup_subsys_state *root) -{ -	struct css_id *child_id; -	struct css_id *root_id; - -	child_id  = rcu_dereference(child->id); -	if (!child_id) -		return false; -	root_id = rcu_dereference(root->id); -	if (!root_id) -		return false; -	if (child_id->depth < root_id->depth) -		return false; -	if (child_id->stack[root_id->depth] != root_id->id) -		return false; -	return true; -} - -void free_css_id(struct cgroup_subsys *ss, struct cgroup_subsys_state *css) -{ -	struct css_id *id = rcu_dereference_protected(css->id, true); - -	/* When this is called before css_id initialization, id can be NULL */ -	if (!id) -		return; - -	BUG_ON(!ss->use_id); - -	rcu_assign_pointer(id->css, NULL); -	rcu_assign_pointer(css->id, NULL); -	spin_lock(&ss->id_lock); -	idr_remove(&ss->idr, id->id); -	spin_unlock(&ss->id_lock); -	kfree_rcu(id, rcu_head); -} -EXPORT_SYMBOL_GPL(free_css_id); - -/* - * This is called by init or create(). Then, calls to this function are - * always serialized (By cgroup_mutex() at create()). - */ - -static struct css_id *get_new_cssid(struct cgroup_subsys *ss, int depth) -{ -	struct css_id *newid; -	int ret, size; - -	BUG_ON(!ss->use_id); - -	size = sizeof(*newid) + sizeof(unsigned short) * (depth + 1); -	newid = kzalloc(size, GFP_KERNEL); -	if (!newid) -		return ERR_PTR(-ENOMEM); - -	idr_preload(GFP_KERNEL); -	spin_lock(&ss->id_lock); -	/* Don't use 0. allocates an ID of 1-65535 */ -	ret = idr_alloc(&ss->idr, newid, 1, CSS_ID_MAX + 1, GFP_NOWAIT); -	spin_unlock(&ss->id_lock); -	idr_preload_end(); - -	/* Returns error when there are no free spaces for new ID.*/ -	if (ret < 0) -		goto err_out; - -	newid->id = ret; -	newid->depth = depth; -	return newid; -err_out: -	kfree(newid); -	return ERR_PTR(ret); - -} - -static int __init_or_module cgroup_init_idr(struct cgroup_subsys *ss, -					    struct cgroup_subsys_state *rootcss) -{ -	struct css_id *newid; - -	spin_lock_init(&ss->id_lock); -	idr_init(&ss->idr); - -	newid = get_new_cssid(ss, 0); -	if (IS_ERR(newid)) -		return PTR_ERR(newid); - -	newid->stack[0] = newid->id; -	RCU_INIT_POINTER(newid->css, rootcss); -	RCU_INIT_POINTER(rootcss->id, newid); -	return 0; -} - -static int alloc_css_id(struct cgroup_subsys_state *child_css) -{ -	struct cgroup_subsys_state *parent_css = css_parent(child_css); -	struct css_id *child_id, *parent_id; -	int i, depth; - -	parent_id = rcu_dereference_protected(parent_css->id, true); -	depth = parent_id->depth + 1; - -	child_id = get_new_cssid(child_css->ss, depth); -	if (IS_ERR(child_id)) -		return PTR_ERR(child_id); - -	for (i = 0; i < depth; i++) -		child_id->stack[i] = parent_id->stack[i]; -	child_id->stack[depth] = child_id->id; -	/* -	 * child_id->css pointer will be set after this cgroup is available -	 * see cgroup_populate_dir() -	 */ -	rcu_assign_pointer(child_css->id, child_id); - -	return 0; -} - -/** - * css_lookup - lookup css by id - * @ss: cgroup subsys to be looked into. - * @id: the id - * - * Returns pointer to cgroup_subsys_state if there is valid one with id. - * NULL if not. Should be called under rcu_read_lock() - */ -struct cgroup_subsys_state *css_lookup(struct cgroup_subsys *ss, int id) -{ -	struct css_id *cssid = NULL; - -	BUG_ON(!ss->use_id); -	cssid = idr_find(&ss->idr, id); - -	if (unlikely(!cssid)) -		return NULL; - -	return rcu_dereference(cssid->css); -} -EXPORT_SYMBOL_GPL(css_lookup); -  /**   * css_from_dir - get corresponding css from the dentry of a cgroup dir   * @dentry: directory dentry of interest  |