[PATCH v3 2/3] cgroup/cpuset: Allow top-level partition CPU replacement

From: Guopeng Zhang

Date: Tue Nov 10 2026 - 00:12:02 EST


From: Guopeng Zhang <zhangguopeng@xxxxxxxxxx>

When replacing a partition's CPUs, tasks_nocpu_error() checks whether
the parent's current effective_cpus is a subset of the new exclusive
CPU mask. The parent mask does not yet include CPUs being returned by
the update, so this can invalidate an otherwise valid partition.

For example, on an 8-CPU system without boot isolation:

echo 2-7 > A/cpuset.cpus
echo isolated > A/cpuset.cpus.partition
echo 0-4 > A/cpuset.cpus
cat A/cpuset.cpus.partition
isolated invalid (Parent unable to distribute cpu downstream)

The update should return CPUs 5-7 to the parent and leave A as a
valid isolated partition.

Skip this subset check for top_cpuset. top_cpuset_sd_nocpu() already
accounts for returned CPUs and ensures that an active boot domain
housekeeping CPU remains.

Add a regression test for this case.

Fixes: 0c7f293efc87 ("cgroup/cpuset: Add cpuset.cpus.exclusive.effective for v2")
Signed-off-by: Guopeng Zhang <zhangguopeng@xxxxxxxxxx>
---
kernel/cgroup/cpuset.c | 4 +++-
tools/testing/selftests/cgroup/test_cpuset_prs.sh | 3 +++
2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index c405719ccd12..8b6831983803 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -1232,8 +1232,10 @@ static bool tasks_nocpu_error(struct cpuset *parent, struct cpuset *cs,

/*
* A populated partition (cs or parent) can't have empty effective_cpus
+ * The top_cpuset check above also accounts for CPUs being returned.
*/
- return (cpumask_subset(parent->effective_cpus, xcpus) &&
+ return (parent != &top_cpuset &&
+ cpumask_subset(parent->effective_cpus, xcpus) &&
partition_is_populated(parent, cs)) ||
(!cpumask_intersects(xcpus, cpu_active_mask) &&
partition_is_populated(cs, NULL));
diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
index 0288af1c2eb3..ee4d57b7e35b 100755
--- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh
+++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
@@ -554,6 +554,9 @@ TEST_MATRIX=(
" C2-6:X2-5:P1 CX3-6:P2 \
. . T:X4-6 . . . 0 A1:4-6|A2:4-6 A1:P1|A2:P-2 ."

+ # A CPU replacement must account for CPUs returned to the top cpuset.
+ " C2-${CPULIST#0-}:P2 . . . C0-4 . . . 0 A1:0-4 A1:P2 0-4"
+
#
# old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate ISOLCPUS
# ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ --------
--
2.43.0