Re: [PATCH-next 3/6] cgroup/cpuset: Fix incorrect effective_cpus bug in update_cpumasks_hier()

From: Ridong Chen

Date: Fri Oct 23 2026 - 03:17:53 EST




On 10/22/2026 11:16 AM, Waiman Long wrote:
With the introduction of cpuset.cpus.exclusive, the computation of
effective_cpus differs depending on if a cpuset is a valid partition
root or not.

In update_cpumasks_hier(), effective_cpus is computed early
to check if the current subtree can be skipped. Later on
update_parent_effective_cpumask() may be called which can change the
partition state from valid to invalid or vice versa. If the partition
state changes, the previously computed effective_cpus may no longer be
valid. Fix that by recomputing effective_cpus again when that happens.

Also add a new test case into test_cpuset_prs.sh to verify this change.

Fixes: e2ffe502ba45 ("cgroup/cpuset: Add cpuset.cpus.exclusive for v2")
Signed-off-by: Waiman Long <longman@xxxxxxxxxx>
---
kernel/cgroup/cpuset.c | 10 ++++++++--
tools/testing/selftests/cgroup/test_cpuset_prs.sh | 3 +++
2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index db6e4663f4be..7b9062326f35 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -2316,10 +2316,16 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp,
if (update_parent) {
update_parent_effective_cpumask(cp, partcmd_update, NULL, tmp);
/*
- * The cpuset partition_root_state may become
- * invalid. Capture it.
+ * Capture current partition_root_state as it may have
+ * changed. Recompute effective cpumask if changed.
*/
new_prs = cp->partition_root_state;
+ if (new_prs != old_prs) {
+ if (new_prs > 0)
+ compute_partition_effective_cpumask(cp, tmp->new_cpus);
+ else
+ compute_effective_cpumask(tmp->new_cpus, cp, parent);
+ }
}

If cs is a partition (remote or local), we call compute_partition_effective_cpumask to compute the effective cpumask; otherwise we should call compute_effective_cpumask. Wouldn't it be better to call compute_partition_effective_cpumask whenever cs is a valid partition, so we can eliminate the branch outside?

```
static void compute_effective_cpumask(struct cpumask *new_cpus,
struct cpuset *cs, struct cpuset *parent)
{
bool has_cpus;

if (is_remote_partition (cs) ||
(is_partition_valid(cs) && is_partition_valid(parent)))
return compute_partition_effective_cpumask(cs, &new_cpus);

has_cpus = cpumask_and(new_cpus, cs->cpus_allowed, parent->effective_cpus);
if (!has_cpus && is_in_v2_mode())
cpumask_copy(new_cpus, parent->effective_cpus);
}
```

spin_lock_irq(&callback_lock);
diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
index 47791591002f..8595b6b4b7bf 100755
--- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh
+++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
@@ -364,6 +364,9 @@ TEST_MATRIX=(
" 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 ."
+ " C1-5:X3-5:P2 C3-5:X4-5:P2 C4-5:X5:P2 \
+ . X1-4 . . . 0 A1:1-3|A2:4|A3:4 \
+ A1:P2|A2:P2|A3:P-2 1-4"
" C1-4:X2-4 C1-4:X3-4:P1 C3-4:X4:P2 \
. . . X1 . 0 A1:1-2|A2:3-4|A3:3-4 \
A1:P0|A2:P1|A3:P-2 ."

--
Best regards
Ridong