From 46b885416c27214072272b85adb898ed91801062 Mon Sep 17 00:00:00 2001 From: Waiman Long Date: Mon, 19 Oct 2026 14:10:12 -0400 Subject: [PATCH] cgroup/cpuset: Fix a missing isolated_cpus update in update_cpumasks_hier() It is found that when a local isolated partition is being invalidated because its parent partition is no longer valid, the isolated_cpus cpumask may not be properly updated. Those isolated CPUs may or may not needed to be removed from isolated_cpus depending on if there is a local isolated partition ancestor that will now own those isolated CPUs instead. Fix that by calling a new ancestor_partition() helper to return the closeset valid partition root ancestor. If that ancestor is PRS_ROOT, the isolated CPUs will have to be removed from isolated_cpus. For a PRS_ISOLATED ancestor, the isolated CPUs are checked against the ancestor's ones to see if any of them should be removed as it is possible that the invalidation of the parent may be caused by change in the effective xcpus of that ancestor. If any of the isolated CPUs should be removed, isolated_cpus_update() will be called under callback_lock. An existing test case in test_cpuset_prs.sh is modifed and a new one added to test that. Fixes: 11e5f407b64a ("cgroup/cpuset: Keep track of CPUs in isolated partitions") Signed-off-by: Waiman Long Signed-off-by: Tejun Heo --- kernel/cgroup/cpuset.c | 57 +++++++++++++++++-- .../selftests/cgroup/test_cpuset_prs.sh | 6 +- 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c index c82b805b112b..2a7a0c579c9a 100644 --- a/kernel/cgroup/cpuset.c +++ b/kernel/cgroup/cpuset.c @@ -2137,6 +2137,25 @@ static void compute_partition_effective_cpumask(struct cpuset *cs, rcu_read_unlock(); } +/* + * ancestor_partition - Find and return the closest valid partition root ancestor + * @cs: the current cpuset + * + * Return: The closet partition root ancestor cpuset + */ +static struct cpuset *ancestor_partition(struct cpuset *cs) +{ + struct cpuset *ancestor = parent_cs(cs); + + /* + * The top_cpuset is always a valid partition root which will stop + * the loop if it is reached. + */ + while (!is_partition_valid(ancestor)) + ancestor = parent_cs(ancestor); + return ancestor; +} + /* * update_cpumasks_hier - Update effective cpumasks and tasks in the subtree * @cs: the cpuset to consider @@ -2229,7 +2248,10 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp, * cpuset if the parent's effective_cpus changes. */ if ((cp != cs) && old_prs) { - switch (parent->partition_root_state) { + int parent_prs = parent->partition_root_state; + struct cpumask *del_cpus = NULL; + + switch (parent_prs) { case PRS_ROOT: case PRS_ISOLATED: update_parent = true; @@ -2237,12 +2259,37 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp, default: /* - * When parent is not a partition root or is - * invalid, child partition roots become - * invalid too. + * When parent is not a valid partition root, + * child partition roots become invalid too. + * + * For a to be invalidated isolated partition, + * its isolated CPUs may or may not need to be + * removed from isolated_cpus depending on if + * its closest partition root ancestor is a root + * or isolated partition. With a PRS_ISOLATED + * ancestor, the CPUs are checked against its + * effective xcpus to see if any of them needed + * to be removed. */ if (is_partition_valid(cp)) - new_prs = -cp->partition_root_state; + new_prs = -old_prs; + + if (old_prs == PRS_ISOLATED) { + struct cpuset *ancestor = ancestor_partition(cp); + + if (ancestor->partition_root_state == PRS_ROOT) + del_cpus = cp->effective_xcpus; + else if (cpumask_andnot(tmp->delmask, + cp->effective_xcpus, + ancestor->effective_xcpus)) + del_cpus = tmp->delmask; + + if (del_cpus) { + spin_lock_irq(&callback_lock); + isolated_cpus_update(old_prs, new_prs, del_cpus); + spin_unlock_irq(&callback_lock); + } + } WRITE_ONCE(cp->prs_err, is_partition_invalid(parent) ? PERR_INVPARENT : PERR_NOTPART); diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh index 7efd5e645767..f1dda27b1394 100755 --- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh +++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh @@ -292,9 +292,9 @@ TEST_MATRIX=( A1:P0|A2:P2|A3:P1 2-4|2-3" " C0-4 C1-4 C2-4 . X2-4 X2-4:P2 X3-4:P1 . 0 A1:0-1|A2:2|A3:3-4 \ A1:P0|A2:P2|A3:P1 2" - " C0-4:X2-4 C1-4:X2-4:P2 C2-4:X4:P1 \ - . . X5 . . 0 A1:0-4|A2:1-4|A3:2-4 \ - A1:P0|A2:P-2|A3:P-1 ." + " C1-4:X2-4 C2-4:X3-4:P1 C3-4:X4:P2 \ + . . X5 . . 0 A1:1-4|A2:2-4|A3:3-4 \ + A1:P0|A2:P-1|A3:P-2 ." " C0-4:X2-4 C1-4:X2-4:P2 C2-4:X4:P1 \ . . . X1 . 0 A1:0-1|A2:2-4|A3:2-4 \ A1:P0|A2:P2|A3:P-1 2-4"