Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ae8086ce authored by Tejun Heo's avatar Tejun Heo
Browse files

cpuset: introduce cpuset_for_each_child()



Instead of iterating cgroup->children directly, introduce and use
cpuset_for_each_child() which wraps cgroup_for_each_child() and
performs online check.  As it uses the generic iterator, it requires
RCU read locking too.

As cpuset is currently protected by cgroup_mutex, non-online cpusets
aren't visible to all the iterations and this patch currently doesn't
make any functional difference.  This will be used to de-couple cpuset
locking from cgroup core.

Signed-off-by: default avatarTejun Heo <tj@kernel.org>
Acked-by: default avatarLi Zefan <lizefan@huawei.com>
parent efeb77b2
Loading
Loading
Loading
Loading
+54 −31
Original line number Original line Diff line number Diff line
@@ -200,6 +200,19 @@ static struct cpuset top_cpuset = {
		  (1 << CS_MEM_EXCLUSIVE)),
		  (1 << CS_MEM_EXCLUSIVE)),
};
};


/**
 * cpuset_for_each_child - traverse online children of a cpuset
 * @child_cs: loop cursor pointing to the current child
 * @pos_cgrp: used for iteration
 * @parent_cs: target cpuset to walk children of
 *
 * Walk @child_cs through the online children of @parent_cs.  Must be used
 * with RCU read locked.
 */
#define cpuset_for_each_child(child_cs, pos_cgrp, parent_cs)		\
	cgroup_for_each_child((pos_cgrp), (parent_cs)->css.cgroup)	\
		if (is_cpuset_online(((child_cs) = cgroup_cs((pos_cgrp)))))

/*
/*
 * There are two global mutexes guarding cpuset structures.  The first
 * There are two global mutexes guarding cpuset structures.  The first
 * is the main control groups cgroup_mutex, accessed via
 * is the main control groups cgroup_mutex, accessed via
@@ -419,48 +432,55 @@ static int validate_change(const struct cpuset *cur, const struct cpuset *trial)
{
{
	struct cgroup *cont;
	struct cgroup *cont;
	struct cpuset *c, *par;
	struct cpuset *c, *par;
	int ret;

	rcu_read_lock();


	/* Each of our child cpusets must be a subset of us */
	/* Each of our child cpusets must be a subset of us */
	list_for_each_entry(cont, &cur->css.cgroup->children, sibling) {
	ret = -EBUSY;
		if (!is_cpuset_subset(cgroup_cs(cont), trial))
	cpuset_for_each_child(c, cont, cur)
			return -EBUSY;
		if (!is_cpuset_subset(c, trial))
	}
			goto out;


	/* Remaining checks don't apply to root cpuset */
	/* Remaining checks don't apply to root cpuset */
	ret = 0;
	if (cur == &top_cpuset)
	if (cur == &top_cpuset)
		return 0;
		goto out;


	par = cur->parent;
	par = cur->parent;


	/* We must be a subset of our parent cpuset */
	/* We must be a subset of our parent cpuset */
	ret = -EACCES;
	if (!is_cpuset_subset(trial, par))
	if (!is_cpuset_subset(trial, par))
		return -EACCES;
		goto out;


	/*
	/*
	 * If either I or some sibling (!= me) is exclusive, we can't
	 * If either I or some sibling (!= me) is exclusive, we can't
	 * overlap
	 * overlap
	 */
	 */
	list_for_each_entry(cont, &par->css.cgroup->children, sibling) {
	ret = -EINVAL;
		c = cgroup_cs(cont);
	cpuset_for_each_child(c, cont, par) {
		if ((is_cpu_exclusive(trial) || is_cpu_exclusive(c)) &&
		if ((is_cpu_exclusive(trial) || is_cpu_exclusive(c)) &&
		    c != cur &&
		    c != cur &&
		    cpumask_intersects(trial->cpus_allowed, c->cpus_allowed))
		    cpumask_intersects(trial->cpus_allowed, c->cpus_allowed))
			return -EINVAL;
			goto out;
		if ((is_mem_exclusive(trial) || is_mem_exclusive(c)) &&
		if ((is_mem_exclusive(trial) || is_mem_exclusive(c)) &&
		    c != cur &&
		    c != cur &&
		    nodes_intersects(trial->mems_allowed, c->mems_allowed))
		    nodes_intersects(trial->mems_allowed, c->mems_allowed))
			return -EINVAL;
			goto out;
	}
	}


	/* Cpusets with tasks can't have empty cpus_allowed or mems_allowed */
	/* Cpusets with tasks can't have empty cpus_allowed or mems_allowed */
	if (cgroup_task_count(cur->css.cgroup)) {
	ret = -ENOSPC;
		if (cpumask_empty(trial->cpus_allowed) ||
	if (cgroup_task_count(cur->css.cgroup) &&
		    nodes_empty(trial->mems_allowed)) {
	    (cpumask_empty(trial->cpus_allowed) ||
			return -ENOSPC;
	     nodes_empty(trial->mems_allowed)))
		}
		goto out;
	}


	return 0;
	ret = 0;
out:
	rcu_read_unlock();
	return ret;
}
}


#ifdef CONFIG_SMP
#ifdef CONFIG_SMP
@@ -501,10 +521,10 @@ update_domain_attr_tree(struct sched_domain_attr *dattr, struct cpuset *c)
		if (is_sched_load_balance(cp))
		if (is_sched_load_balance(cp))
			update_domain_attr(dattr, cp);
			update_domain_attr(dattr, cp);


		list_for_each_entry(cont, &cp->css.cgroup->children, sibling) {
		rcu_read_lock();
			child = cgroup_cs(cont);
		cpuset_for_each_child(child, cont, cp)
			list_add_tail(&child->stack_list, &q);
			list_add_tail(&child->stack_list, &q);
		}
		rcu_read_unlock();
	}
	}
}
}


@@ -623,10 +643,10 @@ static int generate_sched_domains(cpumask_var_t **domains,
			continue;
			continue;
		}
		}


		list_for_each_entry(cont, &cp->css.cgroup->children, sibling) {
		rcu_read_lock();
			child = cgroup_cs(cont);
		cpuset_for_each_child(child, cont, cp)
			list_add_tail(&child->stack_list, &q);
			list_add_tail(&child->stack_list, &q);
		}
		rcu_read_unlock();
  	}
  	}


	for (i = 0; i < csn; i++)
	for (i = 0; i < csn; i++)
@@ -1824,7 +1844,8 @@ static int cpuset_css_online(struct cgroup *cgrp)
{
{
	struct cpuset *cs = cgroup_cs(cgrp);
	struct cpuset *cs = cgroup_cs(cgrp);
	struct cpuset *parent = cs->parent;
	struct cpuset *parent = cs->parent;
	struct cgroup *tmp_cg;
	struct cpuset *tmp_cs;
	struct cgroup *pos_cg;


	if (!parent)
	if (!parent)
		return 0;
		return 0;
@@ -1853,12 +1874,14 @@ static int cpuset_css_online(struct cgroup *cgrp)
	 * changed to grant parent->cpus_allowed-sibling_cpus_exclusive
	 * changed to grant parent->cpus_allowed-sibling_cpus_exclusive
	 * (and likewise for mems) to the new cgroup.
	 * (and likewise for mems) to the new cgroup.
	 */
	 */
	list_for_each_entry(tmp_cg, &cgrp->parent->children, sibling) {
	rcu_read_lock();
		struct cpuset *tmp_cs = cgroup_cs(tmp_cg);
	cpuset_for_each_child(tmp_cs, pos_cg, parent) {

		if (is_mem_exclusive(tmp_cs) || is_cpu_exclusive(tmp_cs)) {
		if (is_mem_exclusive(tmp_cs) || is_cpu_exclusive(tmp_cs))
			rcu_read_unlock();
			return 0;
			return 0;
		}
		}
	}
	rcu_read_unlock();


	mutex_lock(&callback_mutex);
	mutex_lock(&callback_mutex);
	cs->mems_allowed = parent->mems_allowed;
	cs->mems_allowed = parent->mems_allowed;
@@ -2027,10 +2050,10 @@ static struct cpuset *cpuset_next(struct list_head *queue)


	cp = list_first_entry(queue, struct cpuset, stack_list);
	cp = list_first_entry(queue, struct cpuset, stack_list);
	list_del(queue->next);
	list_del(queue->next);
	list_for_each_entry(cont, &cp->css.cgroup->children, sibling) {
	rcu_read_lock();
		child = cgroup_cs(cont);
	cpuset_for_each_child(child, cont, cp)
		list_add_tail(&child->stack_list, queue);
		list_add_tail(&child->stack_list, queue);
	}
	rcu_read_unlock();


	return cp;
	return cp;
}
}