From: Guopeng Zhang <[email protected]>

update_cpumask() calls partition_cpus_change() before copying the new
cpus_allowed mask. A remote partition update can propagate through an
ancestor and revisit the cpuset while the old mask is still visible. The
second visit then adds back CPUs that the first visit released, leaving
them allocated after the cpuset is removed.

Copy cpus_allowed before partition_cpus_change(). All checks and
allocations that can fail have completed by this point, and cpuset_mutex
remains held for the rest of the update, so the early copy needs no
rollback. Keep effective_xcpus unchanged until afterward so the partition
code can still calculate the old-to-new difference.

Fixes: f62a5d39368e ("cgroup/cpuset: Remove remote_partition_check() & make 
update_cpumasks_hier() handle remote partition")
Signed-off-by: Guopeng Zhang <[email protected]>
---
 kernel/cgroup/cpuset.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index b3e749ede7d1..9e13fc962f41 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -2555,10 +2555,17 @@ static int update_cpumask(struct cpuset *cs, struct 
cpuset *trialcs,
         */
        force = !cpumask_equal(cs->effective_xcpus, trialcs->effective_xcpus);
 
+       /*
+        * remote_cpus_update() can propagate through an ancestor and revisit
+        * this cpuset. Make sure that it sees the new configured CPU mask.
+        */
+       spin_lock_irq(&callback_lock);
+       cpumask_copy(cs->cpus_allowed, trialcs->cpus_allowed);
+       spin_unlock_irq(&callback_lock);
+
        partition_cpus_change(cs, trialcs, &tmp);
 
        spin_lock_irq(&callback_lock);
-       cpumask_copy(cs->cpus_allowed, trialcs->cpus_allowed);
        cpumask_copy(cs->effective_xcpus, trialcs->effective_xcpus);
        if ((old_prs > 0) && !is_partition_valid(cs))
                reset_partition_data(cs);
-- 
2.43.0


Reply via email to