cpuset: Track cpusets that use parent's effective_cpus
In the default hierarchy, a cpuset will use the parent's effective_cpus if none of the requested CPUs can be granted from the parent. That can be a problem if a parent is a partition root with children partition roots. Changes to a parent's effective_cpus list due to changes in a child partition root may not be properly reflected in a child cpuset that use parent's effective_cpus because the cpu_exclusive rule of a partition root will not guard against that. In order to avoid the mismatch, two new tracking variables are added to the cpuset structure to track if a cpuset uses parent's effective_cpus and the number of children cpusets that use its effective_cpus. So whenever cpumask changes are made to a parent, it will also check to see if it has other children cpusets that use its effective_cpus and call update_cpumasks_hier() if that is the case. Signed-off-by: Waiman Long <longman@redhat.com> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Tejun Heo <tj@kernel.org>
This commit is contained in:
Родитель
3881b86128
Коммит
4716909cc5
|
@ -147,6 +147,14 @@ struct cpuset {
|
||||||
|
|
||||||
/* partition root state */
|
/* partition root state */
|
||||||
int partition_root_state;
|
int partition_root_state;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Default hierarchy only:
|
||||||
|
* use_parent_ecpus - set if using parent's effective_cpus
|
||||||
|
* child_ecpus_count - # of children with use_parent_ecpus set
|
||||||
|
*/
|
||||||
|
int use_parent_ecpus;
|
||||||
|
int child_ecpus_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1227,8 +1235,17 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp)
|
||||||
* If it becomes empty, inherit the effective mask of the
|
* If it becomes empty, inherit the effective mask of the
|
||||||
* parent, which is guaranteed to have some CPUs.
|
* parent, which is guaranteed to have some CPUs.
|
||||||
*/
|
*/
|
||||||
if (is_in_v2_mode() && cpumask_empty(tmp->new_cpus))
|
if (is_in_v2_mode() && cpumask_empty(tmp->new_cpus)) {
|
||||||
cpumask_copy(tmp->new_cpus, parent->effective_cpus);
|
cpumask_copy(tmp->new_cpus, parent->effective_cpus);
|
||||||
|
if (!cp->use_parent_ecpus) {
|
||||||
|
cp->use_parent_ecpus = true;
|
||||||
|
parent->child_ecpus_count++;
|
||||||
|
}
|
||||||
|
} else if (cp->use_parent_ecpus) {
|
||||||
|
cp->use_parent_ecpus = false;
|
||||||
|
WARN_ON_ONCE(!parent->child_ecpus_count);
|
||||||
|
parent->child_ecpus_count--;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Skip the whole subtree if the cpumask remains the same
|
* Skip the whole subtree if the cpumask remains the same
|
||||||
|
@ -1345,6 +1362,35 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp)
|
||||||
rebuild_sched_domains_locked();
|
rebuild_sched_domains_locked();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* update_sibling_cpumasks - Update siblings cpumasks
|
||||||
|
* @parent: Parent cpuset
|
||||||
|
* @cs: Current cpuset
|
||||||
|
* @tmp: Temp variables
|
||||||
|
*/
|
||||||
|
static void update_sibling_cpumasks(struct cpuset *parent, struct cpuset *cs,
|
||||||
|
struct tmpmasks *tmp)
|
||||||
|
{
|
||||||
|
struct cpuset *sibling;
|
||||||
|
struct cgroup_subsys_state *pos_css;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check all its siblings and call update_cpumasks_hier()
|
||||||
|
* if their use_parent_ecpus flag is set in order for them
|
||||||
|
* to use the right effective_cpus value.
|
||||||
|
*/
|
||||||
|
rcu_read_lock();
|
||||||
|
cpuset_for_each_child(sibling, pos_css, parent) {
|
||||||
|
if (sibling == cs)
|
||||||
|
continue;
|
||||||
|
if (!sibling->use_parent_ecpus)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
update_cpumasks_hier(sibling, tmp);
|
||||||
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* update_cpumask - update the cpus_allowed mask of a cpuset and all tasks in it
|
* update_cpumask - update the cpus_allowed mask of a cpuset and all tasks in it
|
||||||
* @cs: the cpuset to consider
|
* @cs: the cpuset to consider
|
||||||
|
@ -1420,6 +1466,17 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
|
||||||
spin_unlock_irq(&callback_lock);
|
spin_unlock_irq(&callback_lock);
|
||||||
|
|
||||||
update_cpumasks_hier(cs, &tmp);
|
update_cpumasks_hier(cs, &tmp);
|
||||||
|
|
||||||
|
if (cs->partition_root_state) {
|
||||||
|
struct cpuset *parent = parent_cs(cs);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For partition root, update the cpumasks of sibling
|
||||||
|
* cpusets if they use parent's effective_cpus.
|
||||||
|
*/
|
||||||
|
if (parent->child_ecpus_count)
|
||||||
|
update_sibling_cpumasks(parent, cs, &tmp);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1856,6 +1913,9 @@ static int update_prstate(struct cpuset *cs, int val)
|
||||||
if (parent != &top_cpuset)
|
if (parent != &top_cpuset)
|
||||||
update_tasks_cpumask(parent);
|
update_tasks_cpumask(parent);
|
||||||
|
|
||||||
|
if (parent->child_ecpus_count)
|
||||||
|
update_sibling_cpumasks(parent, cs, &tmp);
|
||||||
|
|
||||||
rebuild_sched_domains_locked();
|
rebuild_sched_domains_locked();
|
||||||
out:
|
out:
|
||||||
free_cpumasks(NULL, &tmp);
|
free_cpumasks(NULL, &tmp);
|
||||||
|
@ -2550,6 +2610,8 @@ static int cpuset_css_online(struct cgroup_subsys_state *css)
|
||||||
if (is_in_v2_mode()) {
|
if (is_in_v2_mode()) {
|
||||||
cpumask_copy(cs->effective_cpus, parent->effective_cpus);
|
cpumask_copy(cs->effective_cpus, parent->effective_cpus);
|
||||||
cs->effective_mems = parent->effective_mems;
|
cs->effective_mems = parent->effective_mems;
|
||||||
|
cs->use_parent_ecpus = true;
|
||||||
|
parent->child_ecpus_count++;
|
||||||
}
|
}
|
||||||
spin_unlock_irq(&callback_lock);
|
spin_unlock_irq(&callback_lock);
|
||||||
|
|
||||||
|
@ -2613,6 +2675,13 @@ static void cpuset_css_offline(struct cgroup_subsys_state *css)
|
||||||
is_sched_load_balance(cs))
|
is_sched_load_balance(cs))
|
||||||
update_flag(CS_SCHED_LOAD_BALANCE, cs, 0);
|
update_flag(CS_SCHED_LOAD_BALANCE, cs, 0);
|
||||||
|
|
||||||
|
if (cs->use_parent_ecpus) {
|
||||||
|
struct cpuset *parent = parent_cs(cs);
|
||||||
|
|
||||||
|
cs->use_parent_ecpus = false;
|
||||||
|
parent->child_ecpus_count--;
|
||||||
|
}
|
||||||
|
|
||||||
cpuset_dec();
|
cpuset_dec();
|
||||||
clear_bit(CS_ONLINE, &cs->flags);
|
clear_bit(CS_ONLINE, &cs->flags);
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче