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: Tejun Heo <tj@kernel.org>
Acked-by: Li Zefan <lizefan@huawei.com>
This commit is contained in:
Tejun Heo 2013-01-07 08:51:07 -08:00
parent efeb77b2f1
commit ae8086ce15

View file

@ -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;
} }