mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
cgroup/cpuset: use mems_allowed_seq when checking a policy nodemask
A cpuset update changes the task's mems_allowed and rebinds its
mempolicy in separate steps under mems_allowed_seq, but the check
reads both without it. This can cause a spurious numa placement
miss under some cpuset/mempolicy combinations.
A reader that loads one mask before the update and the other after
it can see a spurious empty intersection and drop the nodemask.
For example, a task with cpuset.mems={0} and MPOL_BIND={0}. If the
cpuset moves to mems={1,2}, the policy is rebound to {1}.
The allocator can race and compare the old mems_allowed {0} against
the new policy {1} - which will result in a dropped nodemask and a
misplaced allocation on node 2.
Simply retry the intersection until mems_allowed_seq is stable.
This covers the task policy, which is rebound under mems_allowed_seq.
VMA policies are rebound afterwards by mpol_rebind_mm(), outside
mems_allowed_seq, and are not covered by this change.
Fixes: cc9a6c8776 ("cpuset: mm: reduce large amounts of memory barrier related damage v3")
Reviewed-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
Reviewed-by: Waiman Long <longman@redhat.com>
Signed-off-by: Gregory Price (Meta) <gourry@gourry.net>
Signed-off-by: Tejun Heo <tj@kernel.org>
This commit is contained in:
parent
1850c66951
commit
b0cec62d28
|
|
@ -4265,10 +4265,21 @@ nodemask_t cpuset_mems_allowed(struct task_struct *tsk)
|
|||
* @nodemask: the nodemask to be checked
|
||||
*
|
||||
* Are any of the nodes in the nodemask allowed in current->mems_allowed?
|
||||
*
|
||||
* A cpuset update rebinds the task's mempolicy and changes mems_allowed in
|
||||
* separate steps, so retry if an update raced with the check.
|
||||
*/
|
||||
int cpuset_nodemask_valid_mems_allowed(const nodemask_t *nodemask)
|
||||
{
|
||||
return nodes_intersects(*nodemask, current->mems_allowed);
|
||||
unsigned int seq;
|
||||
int ret;
|
||||
|
||||
do {
|
||||
seq = read_mems_allowed_begin();
|
||||
ret = nodes_intersects(*nodemask, current->mems_allowed);
|
||||
} while (read_mems_allowed_retry(seq));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user