All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/17] cgroup/cpuset: Fix partition CPU ownership and isolation accounting
@ 2026-08-20 12:41 Guopeng Zhang
  2026-08-20 12:41 ` [PATCH 01/17] selftests/cgroup: Drop invalid boot isolation comparison Guopeng Zhang
                   ` (16 more replies)
  0 siblings, 17 replies; 18+ messages in thread
From: Guopeng Zhang @ 2026-08-20 12:41 UTC (permalink / raw)
  To: longman, cgroups
  Cc: ridong.chen, tj, hannes, mkoutny, shuah, linux-kselftest,
	linux-kernel, Guopeng Zhang

From: Guopeng Zhang <zhangguopeng@kylinos.cn>

update_prstate() uses effective_xcpus for isolation accounting and
housekeeping checks when switching a partition between root and
isolated. The mask also includes CPUs granted to valid child partitions.
Such a type change can alter isolation accounting for child-owned CPUs
or fail a housekeeping check because of a CPU the parent does not own.

A rejected type change can leave CPUs assigned to the invalidated
partition instead of returning them to the partition that owns the
invalidated subtree. When cpuset.cpus changes, child validation can use
the old parent mask, and a remote update can observe stale cpus_allowed
when it revisits a cpuset. Direct and propagated invalidation can leave
isolated_cpus reflecting the released partition's type instead of the
type of the partition receiving its CPUs. Releasing an isolated
partition can clear boot-isolated CPUs from isolated_cpus.

Limit type-change checks and accounting to CPUs owned directly by the
partition. Preserve boot-isolated CPUs when a partition is released,
return CPUs after rejected type changes, validate children against the
new parent mask, and publish cpus_allowed before a partition update can
revisit the cpuset. Fix isolation accounting during direct and
propagated invalidation.

Patch 1 removes an invalid selftest comparison that makes
test_cpuset_prs.sh fail when boot-time domain isolation is configured.
Each kernel fix is followed by a focused selftest update.

Guopeng Zhang (17):
  selftests/cgroup: Drop invalid boot isolation comparison
  cgroup/cpuset: Preserve boot-isolated CPUs on partition release
  selftests/cgroup: Test boot-isolated CPU partition release
  cgroup/cpuset: Limit type-change accounting to owned CPUs
  selftests/cgroup: Test isolated CPU accounting on type changes
  cgroup/cpuset: Validate type changes against owned CPUs
  selftests/cgroup: Test type-change validation with child-owned CPUs
  cgroup/cpuset: Release CPUs when a type change is rejected
  selftests/cgroup: Test rejected partition type changes
  cgroup/cpuset: Fix isolated accounting on direct child invalidation
  selftests/cgroup: Test isolation accounting on direct child
    invalidation
  cgroup/cpuset: Invalidate children outside the new CPU mask
  selftests/cgroup: Test child invalidation after shrinking cpuset.cpus
  cgroup/cpuset: Publish cpus_allowed before partition updates
  selftests/cgroup: Test shrinking cpuset.cpus in a remote partition
  cgroup/cpuset: Fix isolated accounting on propagated invalidation
  selftests/cgroup: Test isolation accounting on propagated invalidation

 kernel/cgroup/cpuset.c                        | 162 ++++++++++--
 .../selftests/cgroup/test_cpuset_prs.sh       | 231 +++++++++++++++++-
 2 files changed, 361 insertions(+), 32 deletions(-)


base-commit: 6a746cd265aed59107ebdaa9ce039bb832922969
-- 
2.43.0

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 01/17] selftests/cgroup: Drop invalid boot isolation comparison
  2026-08-20 12:41 [PATCH 00/17] cgroup/cpuset: Fix partition CPU ownership and isolation accounting Guopeng Zhang
@ 2026-08-20 12:41 ` Guopeng Zhang
  2026-08-20 12:41 ` [PATCH 02/17] cgroup/cpuset: Preserve boot-isolated CPUs on partition release Guopeng Zhang
                   ` (15 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Guopeng Zhang @ 2026-08-20 12:41 UTC (permalink / raw)
  To: longman, cgroups
  Cc: ridong.chen, tj, hannes, mkoutny, shuah, linux-kselftest,
	linux-kernel, Guopeng Zhang

From: Guopeng Zhang <zhangguopeng@kylinos.cn>

check_isolcpus() clears ISOLCPUS before rebuilding it from sched domain
data. Comparing that empty value with
/sys/devices/system/cpu/isolated makes the test fail whenever
isolcpus=domain is present.

The cpuset.cpus.isolated check above and the sched domain check below
already validate their respective interfaces. Remove the comparison and
the unused HKICPUS read.

Fixes: 6df415aa46ec ("cgroup/cpuset: Defer housekeeping_update() calls from CPU hotplug to workqueue")
Signed-off-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
---
 tools/testing/selftests/cgroup/test_cpuset_prs.sh | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
index da8f7b920178..fdb3185570d4 100755
--- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh
+++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
@@ -797,7 +797,6 @@ check_isolcpus()
 	EXPECTED_ISOLCPUS=$1
 	ISCPUS=${CGROUP2}/cpuset.cpus.isolated
 	ISOLCPUS=$(cat $ISCPUS)
-	HKICPUS=$(cat /sys/devices/system/cpu/isolated)
 	LASTISOLCPU=
 	SCHED_DOMAINS=/sys/kernel/debug/sched/domains
 	if [[ $EXPECTED_ISOLCPUS = . ]]
@@ -835,11 +834,6 @@ check_isolcpus()
 	ISOLCPUS=
 	EXPECTED_ISOLCPUS=$EXPECTED_SDOMAIN
 
-	#
-	# The inverse of HK_TYPE_DOMAIN cpumask in $HKICPUS should match $ISOLCPUS
-	#
-	[[ "$ISOLCPUS" != "$HKICPUS" ]] && return 1
-
 	#
 	# Use the sched domain in debugfs to check isolated CPUs, if available
 	#
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 02/17] cgroup/cpuset: Preserve boot-isolated CPUs on partition release
  2026-08-20 12:41 [PATCH 00/17] cgroup/cpuset: Fix partition CPU ownership and isolation accounting Guopeng Zhang
  2026-08-20 12:41 ` [PATCH 01/17] selftests/cgroup: Drop invalid boot isolation comparison Guopeng Zhang
@ 2026-08-20 12:41 ` Guopeng Zhang
  2026-08-20 12:41 ` [PATCH 03/17] selftests/cgroup: Test boot-isolated CPU " Guopeng Zhang
                   ` (14 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Guopeng Zhang @ 2026-08-20 12:41 UTC (permalink / raw)
  To: longman, cgroups
  Cc: ridong.chen, tj, hannes, mkoutny, shuah, linux-kselftest,
	linux-kernel, Guopeng Zhang

From: Guopeng Zhang <zhangguopeng@kylinos.cn>

isolated_cpus tracks CPUs isolated with isolcpus= as well as CPUs in
isolated cpuset partitions. When an isolated partition is released,
isolated_cpus_update() removes its whole CPU mask. This also clears CPUs
which were already isolated at boot.

Update isolated_cpus one CPU at a time and keep CPUs outside the
boot-time domain housekeeping mask isolated.

Fixes: c188f33c864e ("cgroup/cpuset: Account for boot time isolated CPUs")
Signed-off-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
---
 kernel/cgroup/cpuset.c | 39 +++++++++++++++++++++++++++++----------
 1 file changed, 29 insertions(+), 10 deletions(-)

diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index d100634fa12b..2538faac9aba 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -1259,6 +1259,28 @@ static void reset_partition_data(struct cpuset *cs)
 		cpumask_copy(cs->effective_cpus, parent->effective_cpus);
 }
 
+/* Return true if isolated_cpus changes. */
+static bool isolated_cpu_update(int new_prs, int cpu)
+{
+	lockdep_assert_held(&callback_lock);
+	lockdep_assert_held(&cpuset_mutex);
+
+	if (new_prs == PRS_ISOLATED) {
+		if (cpumask_test_cpu(cpu, isolated_cpus))
+			return false;
+		cpumask_set_cpu(cpu, isolated_cpus);
+		return true;
+	}
+
+	/* CPUs isolated at boot must remain isolated. */
+	if (!cpumask_test_cpu(cpu,
+			      housekeeping_cpumask(HK_TYPE_DOMAIN_BOOT)) ||
+	    !cpumask_test_cpu(cpu, isolated_cpus))
+		return false;
+	cpumask_clear_cpu(cpu, isolated_cpus);
+	return true;
+}
+
 /*
  * isolated_cpus_update - Update the isolated_cpus mask
  * @old_prs: old partition_root_state
@@ -1267,19 +1289,16 @@ static void reset_partition_data(struct cpuset *cs)
  */
 static void isolated_cpus_update(int old_prs, int new_prs, struct cpumask *xcpus)
 {
+	bool updated = false;
+	int cpu;
+
 	WARN_ON_ONCE(old_prs == new_prs);
 	lockdep_assert_held(&callback_lock);
 	lockdep_assert_held(&cpuset_mutex);
-	if (new_prs == PRS_ISOLATED) {
-		if (cpumask_subset(xcpus, isolated_cpus))
-			return;
-		cpumask_or(isolated_cpus, isolated_cpus, xcpus);
-	} else {
-		if (!cpumask_intersects(xcpus, isolated_cpus))
-			return;
-		cpumask_andnot(isolated_cpus, isolated_cpus, xcpus);
-	}
-	update_housekeeping = true;
+	for_each_cpu(cpu, xcpus)
+		updated |= isolated_cpu_update(new_prs, cpu);
+	if (updated)
+		update_housekeeping = true;
 }
 
 /*
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 03/17] selftests/cgroup: Test boot-isolated CPU partition release
  2026-08-20 12:41 [PATCH 00/17] cgroup/cpuset: Fix partition CPU ownership and isolation accounting Guopeng Zhang
  2026-08-20 12:41 ` [PATCH 01/17] selftests/cgroup: Drop invalid boot isolation comparison Guopeng Zhang
  2026-08-20 12:41 ` [PATCH 02/17] cgroup/cpuset: Preserve boot-isolated CPUs on partition release Guopeng Zhang
@ 2026-08-20 12:41 ` Guopeng Zhang
  2026-08-20 12:41 ` [PATCH 04/17] cgroup/cpuset: Limit type-change accounting to owned CPUs Guopeng Zhang
                   ` (13 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Guopeng Zhang @ 2026-08-20 12:41 UTC (permalink / raw)
  To: longman, cgroups
  Cc: ridong.chen, tj, hannes, mkoutny, shuah, linux-kselftest,
	linux-kernel, Guopeng Zhang

From: Guopeng Zhang <zhangguopeng@kylinos.cn>

Put a CPU isolated at boot into an isolated partition, change the
partition back to member and check that the CPU remains isolated.

Signed-off-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
---
 .../selftests/cgroup/test_cpuset_prs.sh       | 58 +++++++++++++++++++
 1 file changed, 58 insertions(+)

diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
index fdb3185570d4..131d8b4551ef 100755
--- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh
+++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
@@ -1155,6 +1155,63 @@ test_isolated()
 	pause 0.05
 }
 
+#
+# Select an online CPU isolated from scheduler domains at boot.
+# $1: test name used in the skip message
+#
+get_boot_isolated_cpu()
+{
+	TEST_NAME=$1
+	BOOT_ISOLATED_FILE=/sys/devices/system/cpu/isolated
+
+	[[ -r $BOOT_ISOLATED_FILE ]] || {
+		echo "$TEST_NAME test SKIPPED: boot isolation state unavailable"
+		return 1
+	}
+	BOOT_CPUS=$(cat $BOOT_ISOLATED_FILE)
+	[[ -n "$BOOT_CPUS" ]] || {
+		echo "$TEST_NAME test SKIPPED: no boot-isolated CPU"
+		return 1
+	}
+
+	BOOT_CPU=$(echo "$BOOT_CPUS" | sed -e 's/[,-].*//')
+	CPU_ONLINE=/sys/devices/system/cpu/cpu${BOOT_CPU}/online
+	[[ ! -e $CPU_ONLINE || $(cat $CPU_ONLINE) -eq 1 ]] || {
+		echo "$TEST_NAME test SKIPPED: CPU $BOOT_CPU is offline"
+		return 1
+	}
+}
+
+#
+# A CPU isolated at boot must stay isolated after it is released by a dynamic
+# isolated partition.
+#
+test_boot_isolated()
+{
+	TEST_NAME="Boot-isolated CPU partition release"
+	get_boot_isolated_cpu "$TEST_NAME" || return 0
+	echo "Running $TEST_NAME test ..."
+
+	cd $CGROUP2/test
+	echo member > cpuset.cpus.partition
+	echo $BOOT_CPU > cpuset.cpus
+	[[ $(cat cpuset.cpus.effective) = "$BOOT_CPU" ]] || {
+		echo "$TEST_NAME test SKIPPED: CPU $BOOT_CPU is unavailable"
+		echo "" > cpuset.cpus
+		cd $CGROUP2
+		return 0
+	}
+	test_partition isolated
+	test_partition member
+	check_isolcpus "." || {
+		echo "Boot-isolated CPU $BOOT_CPU was lost after partition release"
+		exit 1
+	}
+	echo "" > cpuset.cpus
+	cd $CGROUP2
+	echo "$TEST_NAME test PASSED."
+}
+
 #
 # Wait for inotify event for the given file and read it
 # $1: cgroup file to wait for
@@ -1226,5 +1283,6 @@ trap cleanup 0 2 3 6
 run_state_test TEST_MATRIX
 run_remote_state_test REMOTE_TEST_MATRIX
 test_isolated
+test_boot_isolated
 test_inotify
 echo "All tests PASSED."
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 04/17] cgroup/cpuset: Limit type-change accounting to owned CPUs
  2026-08-20 12:41 [PATCH 00/17] cgroup/cpuset: Fix partition CPU ownership and isolation accounting Guopeng Zhang
                   ` (2 preceding siblings ...)
  2026-08-20 12:41 ` [PATCH 03/17] selftests/cgroup: Test boot-isolated CPU " Guopeng Zhang
@ 2026-08-20 12:41 ` Guopeng Zhang
  2026-08-20 12:41 ` [PATCH 05/17] selftests/cgroup: Test isolated CPU accounting on type changes Guopeng Zhang
                   ` (12 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Guopeng Zhang @ 2026-08-20 12:41 UTC (permalink / raw)
  To: longman, cgroups
  Cc: ridong.chen, tj, hannes, mkoutny, shuah, linux-kselftest,
	linux-kernel, Guopeng Zhang

From: Guopeng Zhang <zhangguopeng@kylinos.cn>

effective_xcpus includes CPUs granted to valid child partitions. Passing
the whole mask to isolated_cpus_update() during a root-to-isolated or
isolated-to-root change applies the parent's new state to child-owned
CPUs as well.

Build a mask of CPUs owned by the partition by subtracting the
effective_xcpus of valid children. Use this mask when updating
isolated_cpus for a partition type change.

Fixes: 11e5f407b64a ("cgroup/cpuset: Keep track of CPUs in isolated partitions")
Signed-off-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
---
 kernel/cgroup/cpuset.c | 30 ++++++++++++++++++++++++++++--
 1 file changed, 28 insertions(+), 2 deletions(-)

diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 2538faac9aba..468272baadb2 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -2155,6 +2155,30 @@ static void compute_partition_effective_cpumask(struct cpuset *cs,
 	rcu_read_unlock();
 }
 
+/*
+ * Compute CPUs owned directly by a partition.
+ *
+ * effective_xcpus includes CPUs granted to valid child partitions. Exclude
+ * those CPUs when changing only this partition's type.
+ */
+static void compute_partition_owned_cpumask(struct cpuset *cs,
+					    struct cpumask *owned_cpus)
+{
+	struct cgroup_subsys_state *css;
+	struct cpuset *child;
+
+	lockdep_assert_held(&cpuset_mutex);
+	cpumask_copy(owned_cpus, cs->effective_xcpus);
+
+	rcu_read_lock();
+	cpuset_for_each_child(child, css, cs) {
+		if (is_partition_valid(child))
+			cpumask_andnot(owned_cpus, owned_cpus,
+				       child->effective_xcpus);
+	}
+	rcu_read_unlock();
+}
+
 /*
  * update_cpumasks_hier - Update effective cpumasks and tasks in the subtree
  * @cs:  the cpuset to consider
@@ -2990,8 +3014,10 @@ static int update_prstate(struct cpuset *cs, int new_prs)
 	} else if (old_prs && new_prs) {
 		/*
 		 * A change in load balance state only, no change in cpumasks.
-		 * Need to update isolated_cpus.
+		 * Need to update isolated_cpus for CPUs owned by this partition,
+		 * excluding CPUs distributed to valid child partitions.
 		 */
+		compute_partition_owned_cpumask(cs, tmpmask.new_cpus);
 		if (((new_prs == PRS_ISOLATED) &&
 		     !isolated_cpus_can_update(cs->effective_xcpus, NULL)) ||
 		    prstate_housekeeping_conflict(new_prs, cs->effective_xcpus))
@@ -3030,7 +3056,7 @@ static int update_prstate(struct cpuset *cs, int new_prs)
 	if (!is_partition_valid(cs))
 		reset_partition_data(cs);
 	else if (isolcpus_updated)
-		isolated_cpus_update(old_prs, new_prs, cs->effective_xcpus);
+		isolated_cpus_update(old_prs, new_prs, tmpmask.new_cpus);
 	spin_unlock_irq(&callback_lock);
 
 	/* Force update if switching back to member & update effective_xcpus */
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 05/17] selftests/cgroup: Test isolated CPU accounting on type changes
  2026-08-20 12:41 [PATCH 00/17] cgroup/cpuset: Fix partition CPU ownership and isolation accounting Guopeng Zhang
                   ` (3 preceding siblings ...)
  2026-08-20 12:41 ` [PATCH 04/17] cgroup/cpuset: Limit type-change accounting to owned CPUs Guopeng Zhang
@ 2026-08-20 12:41 ` Guopeng Zhang
  2026-08-20 12:41 ` [PATCH 06/17] cgroup/cpuset: Validate type changes against owned CPUs Guopeng Zhang
                   ` (11 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Guopeng Zhang @ 2026-08-20 12:41 UTC (permalink / raw)
  To: longman, cgroups
  Cc: ridong.chen, tj, hannes, mkoutny, shuah, linux-kselftest,
	linux-kernel, Guopeng Zhang

From: Guopeng Zhang <zhangguopeng@kylinos.cn>

Switch a parent between root and isolated while a child has the opposite
type. Check that CPUs owned by the child keep their isolation state.

Signed-off-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
---
 tools/testing/selftests/cgroup/test_cpuset_prs.sh | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
index 131d8b4551ef..9a1cce4807b4 100755
--- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh
+++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
@@ -224,6 +224,8 @@ TEST_MATRIX=(
 	"   C0-1     .      .   C2-3:P1   .      .      .     C2     0 "
 	"   C0-1     .      .   C2-3:P1   .      .      .    C4-5    0 B1:4-5"
 	"  C0-3:P1 C2-3:P1  .      .      .      .      .      .     0 A1:0-1|A2:2-3|XA2:2-3"
+	"  C0-3:P1 C2-3:P1  .      .     P2      .      .      .     0 A1:0-1|A2:2-3 A1:P2|A2:P1 0-1"
+	"  C0-3:P2 C2-3:P2  .      .     P1      .      .      .     0 A1:0-1|A2:2-3 A1:P1|A2:P2 2-3"
 	"  C0-3:P1 C2-3:P1  .      .     C1-3    .      .      .     0 A1:1|A2:2-3|XA2:2-3"
 	"  C2-3:P1  C3:P1   .      .     C3      .      .      .     0 A1:|A2:3|XA2:3 A1:P1|A2:P1"
 	"  C2-3:P1  C3:P1   .      .     C3      P0     .      .     0 A1:3|A2:3 A1:P1|A2:P0"
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 06/17] cgroup/cpuset: Validate type changes against owned CPUs
  2026-08-20 12:41 [PATCH 00/17] cgroup/cpuset: Fix partition CPU ownership and isolation accounting Guopeng Zhang
                   ` (4 preceding siblings ...)
  2026-08-20 12:41 ` [PATCH 05/17] selftests/cgroup: Test isolated CPU accounting on type changes Guopeng Zhang
@ 2026-08-20 12:41 ` Guopeng Zhang
  2026-08-20 12:41 ` [PATCH 07/17] selftests/cgroup: Test type-change validation with child-owned CPUs Guopeng Zhang
                   ` (10 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Guopeng Zhang @ 2026-08-20 12:41 UTC (permalink / raw)
  To: longman, cgroups
  Cc: ridong.chen, tj, hannes, mkoutny, shuah, linux-kselftest,
	linux-kernel, Guopeng Zhang

From: Guopeng Zhang <zhangguopeng@kylinos.cn>

update_prstate() checks effective_xcpus against the housekeeping masks
before changing a partition between root and isolated. effective_xcpus
also contains CPUs granted to valid child partitions, although those
CPUs are not affected by the parent's type change. A child-owned CPU can
therefore reject an otherwise valid change.

Run the nohz_full and boot-domain housekeeping checks against the mask
of CPUs owned by the partition instead.

Fixes: 103b08709e8a ("cgroup/cpuset: Fail if isolated and nohz_full don't leave any housekeeping")
Fixes: b1034a690129 ("cgroup/cpuset: Ensure domain isolated CPUs stay in root or isolated partition")
Signed-off-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
---
 kernel/cgroup/cpuset.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 468272baadb2..853942c1afeb 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -3019,8 +3019,8 @@ static int update_prstate(struct cpuset *cs, int new_prs)
 		 */
 		compute_partition_owned_cpumask(cs, tmpmask.new_cpus);
 		if (((new_prs == PRS_ISOLATED) &&
-		     !isolated_cpus_can_update(cs->effective_xcpus, NULL)) ||
-		    prstate_housekeeping_conflict(new_prs, cs->effective_xcpus))
+		     !isolated_cpus_can_update(tmpmask.new_cpus, NULL)) ||
+		    prstate_housekeeping_conflict(new_prs, tmpmask.new_cpus))
 			err = PERR_HKEEPING;
 		else
 			isolcpus_updated = true;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 07/17] selftests/cgroup: Test type-change validation with child-owned CPUs
  2026-08-20 12:41 [PATCH 00/17] cgroup/cpuset: Fix partition CPU ownership and isolation accounting Guopeng Zhang
                   ` (5 preceding siblings ...)
  2026-08-20 12:41 ` [PATCH 06/17] cgroup/cpuset: Validate type changes against owned CPUs Guopeng Zhang
@ 2026-08-20 12:41 ` Guopeng Zhang
  2026-08-20 12:41 ` [PATCH 08/17] cgroup/cpuset: Release CPUs when a type change is rejected Guopeng Zhang
                   ` (9 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Guopeng Zhang @ 2026-08-20 12:41 UTC (permalink / raw)
  To: longman, cgroups
  Cc: ridong.chen, tj, hannes, mkoutny, shuah, linux-kselftest,
	linux-kernel, Guopeng Zhang

From: Guopeng Zhang <zhangguopeng@kylinos.cn>

Create an isolated child which owns a CPU isolated at boot, then change
its parent from isolated to root. Check that the change succeeds without
altering the child or its isolated CPU.

Signed-off-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
---
 .../selftests/cgroup/test_cpuset_prs.sh       | 47 +++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
index 9a1cce4807b4..bc8dbb724d5c 100755
--- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh
+++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
@@ -1214,6 +1214,52 @@ test_boot_isolated()
 	echo "$TEST_NAME test PASSED."
 }
 
+#
+# A parent's type change must validate only CPUs owned directly by the parent,
+# not a boot-isolated CPU owned by a valid isolated child partition.
+#
+test_owned_cpus_housekeeping()
+{
+	TEST_NAME="Child-owned CPU type change"
+	get_boot_isolated_cpu "$TEST_NAME" || return 0
+	echo "Running $TEST_NAME test ..."
+
+	cd $CGROUP2/test
+	echo member > cpuset.cpus.partition
+	echo +cpuset > cgroup.subtree_control
+	echo 2,$BOOT_CPU > cpuset.cpus
+	[[ $(cat cpuset.cpus.effective) = "2,$BOOT_CPU" ]] || {
+		echo "$TEST_NAME test SKIPPED: CPUs 2,$BOOT_CPU are unavailable"
+		echo "" > cpuset.cpus
+		cd $CGROUP2
+		return 0
+	}
+	test_partition isolated
+	mkdir A1
+	cd A1
+	echo $BOOT_CPU > cpuset.cpus
+	test_partition isolated
+	cd ..
+	test_effective_cpus 2
+	test_partition root
+	[[ $(cat A1/cpuset.cpus.partition) = isolated ]] || {
+		echo "Child partition changed during parent type change"
+		exit 1
+	}
+	check_isolcpus "." || {
+		echo "Parent type change corrupted child isolation"
+		exit 1
+	}
+	cd A1
+	test_partition member
+	cd ..
+	rmdir A1
+	test_partition member
+	echo "" > cpuset.cpus
+	cd $CGROUP2
+	echo "$TEST_NAME test PASSED."
+}
+
 #
 # Wait for inotify event for the given file and read it
 # $1: cgroup file to wait for
@@ -1286,5 +1332,6 @@ run_state_test TEST_MATRIX
 run_remote_state_test REMOTE_TEST_MATRIX
 test_isolated
 test_boot_isolated
+test_owned_cpus_housekeeping
 test_inotify
 echo "All tests PASSED."
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 08/17] cgroup/cpuset: Release CPUs when a type change is rejected
  2026-08-20 12:41 [PATCH 00/17] cgroup/cpuset: Fix partition CPU ownership and isolation accounting Guopeng Zhang
                   ` (6 preceding siblings ...)
  2026-08-20 12:41 ` [PATCH 07/17] selftests/cgroup: Test type-change validation with child-owned CPUs Guopeng Zhang
@ 2026-08-20 12:41 ` Guopeng Zhang
  2026-08-20 12:41 ` [PATCH 09/17] selftests/cgroup: Test rejected partition type changes Guopeng Zhang
                   ` (8 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Guopeng Zhang @ 2026-08-20 12:41 UTC (permalink / raw)
  To: longman, cgroups
  Cc: ridong.chen, tj, hannes, mkoutny, shuah, linux-kselftest,
	linux-kernel, Guopeng Zhang

From: Guopeng Zhang <zhangguopeng@kylinos.cn>

When a housekeeping check rejects a root-to-isolated or isolated-to-root
change, update_prstate() marks the partition invalid but leaves its
effective_xcpus allocated. Those CPUs remain missing from the partition
which owns the invalidated subtree.

Disable a rejected remote partition with remote_partition_disable().
For a local partition, return effective_xcpus to its parent before
recording the invalid state. Use the complete mask because descendants
are invalidated along with the parent and their CPUs return at the same
time.

Fixes: 103b08709e8a ("cgroup/cpuset: Fail if isolated and nohz_full don't leave any housekeeping")
Signed-off-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
---
 kernel/cgroup/cpuset.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 853942c1afeb..a616012927be 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -3020,10 +3020,21 @@ static int update_prstate(struct cpuset *cs, int new_prs)
 		compute_partition_owned_cpumask(cs, tmpmask.new_cpus);
 		if (((new_prs == PRS_ISOLATED) &&
 		     !isolated_cpus_can_update(tmpmask.new_cpus, NULL)) ||
-		    prstate_housekeeping_conflict(new_prs, tmpmask.new_cpus))
+		    prstate_housekeeping_conflict(new_prs, tmpmask.new_cpus)) {
 			err = PERR_HKEEPING;
-		else
+			if (is_remote_partition(cs)) {
+				WRITE_ONCE(cs->prs_err, err);
+				remote_partition_disable(cs, &tmpmask);
+			} else {
+				spin_lock_irq(&callback_lock);
+				partition_xcpus_del(old_prs, parent, cs->effective_xcpus);
+				spin_unlock_irq(&callback_lock);
+				cpuset_update_tasks_cpumask(parent, tmpmask.new_cpus);
+				update_sibling_cpumasks(parent, cs, &tmpmask);
+			}
+		} else {
 			isolcpus_updated = true;
+		}
 	} else {
 		/*
 		 * Switching back to member is always allowed even if it
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 09/17] selftests/cgroup: Test rejected partition type changes
  2026-08-20 12:41 [PATCH 00/17] cgroup/cpuset: Fix partition CPU ownership and isolation accounting Guopeng Zhang
                   ` (7 preceding siblings ...)
  2026-08-20 12:41 ` [PATCH 08/17] cgroup/cpuset: Release CPUs when a type change is rejected Guopeng Zhang
@ 2026-08-20 12:41 ` Guopeng Zhang
  2026-08-20 12:41 ` [PATCH 10/17] cgroup/cpuset: Fix isolated accounting on direct child invalidation Guopeng Zhang
                   ` (7 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Guopeng Zhang @ 2026-08-20 12:41 UTC (permalink / raw)
  To: longman, cgroups
  Cc: ridong.chen, tj, hannes, mkoutny, shuah, linux-kselftest,
	linux-kernel, Guopeng Zhang

From: Guopeng Zhang <zhangguopeng@kylinos.cn>

Exercise housekeeping rejection for local and remote partition type
changes. Check the invalid state, the CPUs returned to the top cpuset and
the boot-time isolation state of those CPUs.

Signed-off-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
---
 .../selftests/cgroup/test_cpuset_prs.sh       | 93 +++++++++++++++++++
 1 file changed, 93 insertions(+)

diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
index bc8dbb724d5c..35c19738aaa4 100755
--- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh
+++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
@@ -1260,6 +1260,97 @@ test_owned_cpus_housekeeping()
 	echo "$TEST_NAME test PASSED."
 }
 
+#
+# A local type change rejected by the boot housekeeping constraint must release
+# the partition CPUs and preserve their boot-isolated state.
+#
+test_partition_type_failure()
+{
+	TEST_NAME="Rejected local partition type change"
+	get_boot_isolated_cpu "$TEST_NAME" || return 0
+	echo "Running $TEST_NAME test ..."
+
+	cd $CGROUP2/test
+	echo member > cpuset.cpus.partition
+	echo $BOOT_CPU > cpuset.cpus
+	[[ $(cat cpuset.cpus.effective) = "$BOOT_CPU" ]] || {
+		echo "$TEST_NAME test SKIPPED: CPU $BOOT_CPU is unavailable"
+		echo "" > cpuset.cpus
+		cd $CGROUP2
+		return 0
+	}
+	test_partition isolated
+	echo root > cpuset.cpus.partition
+	grep -q '^root invalid (partition config conflicts with housekeeping setup)$' \
+		cpuset.cpus.partition || {
+		echo "Partition type failure did not produce the expected state"
+		exit 1
+	}
+	[[ $(cat $CGROUP2/cpuset.cpus.effective) = "$CPULIST" ]] || {
+		echo "Partition type failure did not release CPU $BOOT_CPU"
+		exit 1
+	}
+	check_isolcpus "." || {
+		echo "Partition type failure lost boot-isolated CPU $BOOT_CPU"
+		exit 1
+	}
+	echo member > cpuset.cpus.partition
+	echo "" > cpuset.cpus
+	cd $CGROUP2
+	echo "$TEST_NAME test PASSED."
+}
+
+#
+# Exercise the same rejected type change for a remote partition.
+#
+test_remote_partition_type_failure()
+{
+	TEST_NAME="Rejected remote partition type change"
+	get_boot_isolated_cpu "$TEST_NAME" || return 0
+	echo "Running $TEST_NAME test ..."
+
+	cd $CGROUP2/test
+	echo member > cpuset.cpus.partition
+	echo +cpuset > cgroup.subtree_control
+	echo $BOOT_CPU > cpuset.cpus
+	echo $BOOT_CPU > cpuset.cpus.exclusive
+	[[ $(cat cpuset.cpus.effective) = "$BOOT_CPU" ]] || {
+		echo "$TEST_NAME test SKIPPED: CPU $BOOT_CPU is unavailable"
+		echo "" > cpuset.cpus.exclusive
+		echo "" > cpuset.cpus
+		cd $CGROUP2
+		return 0
+	}
+	mkdir A1
+	cd A1
+	echo $BOOT_CPU > cpuset.cpus
+	echo $BOOT_CPU > cpuset.cpus.exclusive
+	test_partition isolated
+	echo root > cpuset.cpus.partition
+	grep -q '^root invalid (partition config conflicts with housekeeping setup)$' \
+		cpuset.cpus.partition || {
+		echo "Remote type failure did not produce the expected state"
+		exit 1
+	}
+	[[ $(cat $CGROUP2/cpuset.cpus.effective) = "$CPULIST" ]] || {
+		echo "Remote type failure did not release CPU $BOOT_CPU"
+		exit 1
+	}
+	check_isolcpus "." || {
+		echo "Remote type failure lost boot-isolated CPU $BOOT_CPU"
+		exit 1
+	}
+	echo member > cpuset.cpus.partition
+	echo "" > cpuset.cpus.exclusive
+	echo "" > cpuset.cpus
+	cd ..
+	rmdir A1
+	echo "" > cpuset.cpus.exclusive
+	echo "" > cpuset.cpus
+	cd $CGROUP2
+	echo "$TEST_NAME test PASSED."
+}
+
 #
 # Wait for inotify event for the given file and read it
 # $1: cgroup file to wait for
@@ -1333,5 +1424,7 @@ run_remote_state_test REMOTE_TEST_MATRIX
 test_isolated
 test_boot_isolated
 test_owned_cpus_housekeeping
+test_partition_type_failure
+test_remote_partition_type_failure
 test_inotify
 echo "All tests PASSED."
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 10/17] cgroup/cpuset: Fix isolated accounting on direct child invalidation
  2026-08-20 12:41 [PATCH 00/17] cgroup/cpuset: Fix partition CPU ownership and isolation accounting Guopeng Zhang
                   ` (8 preceding siblings ...)
  2026-08-20 12:41 ` [PATCH 09/17] selftests/cgroup: Test rejected partition type changes Guopeng Zhang
@ 2026-08-20 12:41 ` Guopeng Zhang
  2026-08-20 12:41 ` [PATCH 11/17] selftests/cgroup: Test isolation " Guopeng Zhang
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Guopeng Zhang @ 2026-08-20 12:41 UTC (permalink / raw)
  To: longman, cgroups
  Cc: ridong.chen, tj, hannes, mkoutny, shuah, linux-kselftest,
	linux-kernel, Guopeng Zhang

From: Guopeng Zhang <zhangguopeng@kylinos.cn>

compute_partition_effective_cpumask() can invalidate a child whose CPUs
no longer fit in the parent or would leave a populated parent without an
active CPU. make_partition_invalid() changes the child state without
updating isolated_cpus for the CPUs returned by the child.

Keep the unfiltered result of compute_excpus() so that offline CPUs are
included in isolation accounting. For each CPU released by the child, use
the parent's state when the parent remains valid and owns the CPU.
Otherwise use the state of the nearest valid partition ancestor.

Fixes: 11e5f407b64a ("cgroup/cpuset: Keep track of CPUs in isolated partitions")
Signed-off-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
---
 kernel/cgroup/cpuset.c | 43 +++++++++++++++++++++++++++++++++++-------
 1 file changed, 36 insertions(+), 7 deletions(-)

diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index a616012927be..b9faadf4af6d 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -1281,6 +1281,17 @@ static bool isolated_cpu_update(int new_prs, int cpu)
 	return true;
 }
 
+/* Return the valid partition that owns CPUs released by @cs. */
+static struct cpuset *partition_owner(struct cpuset *cs)
+{
+	struct cpuset *owner = parent_cs(cs);
+
+	lockdep_assert_held(&cpuset_mutex);
+	while (!is_partition_valid(owner))
+		owner = parent_cs(owner);
+	return owner;
+}
+
 /*
  * isolated_cpus_update - Update the isolated_cpus mask
  * @old_prs: old partition_root_state
@@ -2089,6 +2100,7 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
  * compute_partition_effective_cpumask - compute effective_cpus for partition
  * @cs: partition root cpuset
  * @new_ecpus: previously computed effective_cpus to be updated
+ * @new_xcpus: scratch mask for the new effective_xcpus
  *
  * Compute the effective_cpus of a partition root by scanning effective_xcpus
  * of child partition roots and excluding their effective_xcpus.
@@ -2102,7 +2114,8 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
  * Note that rcu_read_lock() is assumed to be held.
  */
 static void compute_partition_effective_cpumask(struct cpuset *cs,
-						struct cpumask *new_ecpus)
+						struct cpumask *new_ecpus,
+						struct cpumask *new_xcpus)
 {
 	struct cgroup_subsys_state *css;
 	struct cpuset *child;
@@ -2116,8 +2129,8 @@ static void compute_partition_effective_cpumask(struct cpuset *cs,
 	 *  2) All the effective_cpus will be used up and cp
 	 *     has tasks
 	 */
-	compute_excpus(cs, new_ecpus);
-	cpumask_and(new_ecpus, new_ecpus, cpu_active_mask);
+	compute_excpus(cs, new_xcpus);
+	cpumask_and(new_ecpus, new_xcpus, cpu_active_mask);
 
 	rcu_read_lock();
 	cpuset_for_each_child(child, css, cs) {
@@ -2139,11 +2152,27 @@ static void compute_partition_effective_cpumask(struct cpuset *cs,
 
 		if (child->prs_err) {
 			int old_prs = child->partition_root_state;
+			int parent_prs = cs->partition_root_state;
+			int owner_prs = partition_owner(cs)->partition_root_state;
+			int cpu;
 
 			/*
-			 * Invalidate child partition
+			 * CPUs in the parent's new exclusive mask return to the
+			 * parent. The other CPUs have already been released to the
+			 * partition that owns the parent. Account both destinations
+			 * before invalidating the child.
 			 */
 			spin_lock_irq(&callback_lock);
+			for_each_cpu(cpu, child->effective_xcpus) {
+				int new_prs = parent_prs > 0 &&
+					      cpumask_test_cpu(cpu, new_xcpus)
+					      ? parent_prs : owner_prs;
+
+				if (old_prs == new_prs)
+					continue;
+				if (isolated_cpu_update(new_prs, cpu))
+					update_housekeeping = true;
+			}
 			make_partition_invalid(child);
 			spin_unlock_irq(&callback_lock);
 			notify_partition_change(child, old_prs);
@@ -2231,7 +2260,7 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp,
 		}
 
 		if (remote || (is_partition_valid(parent) && is_partition_valid(cp)))
-			compute_partition_effective_cpumask(cp, tmp->new_cpus);
+			compute_partition_effective_cpumask(cp, tmp->new_cpus, tmp->addmask);
 		else
 			compute_effective_cpumask(tmp->new_cpus, cp, parent);
 
@@ -3996,7 +4025,7 @@ static void cpuset_hotplug_update_tasks(struct cpuset *cs, struct tmpmasks *tmp)
 	 */
 	remote = is_remote_partition(cs);
 	if (remote || (is_partition_valid(cs) && is_partition_valid(parent)))
-		compute_partition_effective_cpumask(cs, &new_cpus);
+		compute_partition_effective_cpumask(cs, &new_cpus, tmp->addmask);
 
 	if (remote && (cpumask_empty(subpartitions_cpus) ||
 			(cpumask_empty(&new_cpus) &&
@@ -4031,7 +4060,7 @@ static void cpuset_hotplug_update_tasks(struct cpuset *cs, struct tmpmasks *tmp)
 	if (partcmd >= 0) {
 		update_parent_effective_cpumask(cs, partcmd, NULL, tmp);
 		if ((partcmd == partcmd_invalidate) || is_partition_valid(cs)) {
-			compute_partition_effective_cpumask(cs, &new_cpus);
+			compute_partition_effective_cpumask(cs, &new_cpus, tmp->addmask);
 			cpuset_force_rebuild();
 		}
 	}
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 11/17] selftests/cgroup: Test isolation accounting on direct child invalidation
  2026-08-20 12:41 [PATCH 00/17] cgroup/cpuset: Fix partition CPU ownership and isolation accounting Guopeng Zhang
                   ` (9 preceding siblings ...)
  2026-08-20 12:41 ` [PATCH 10/17] cgroup/cpuset: Fix isolated accounting on direct child invalidation Guopeng Zhang
@ 2026-08-20 12:41 ` Guopeng Zhang
  2026-08-20 12:41 ` [PATCH 12/17] cgroup/cpuset: Invalidate children outside the new CPU mask Guopeng Zhang
                   ` (5 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Guopeng Zhang @ 2026-08-20 12:41 UTC (permalink / raw)
  To: longman, cgroups
  Cc: ridong.chen, tj, hannes, mkoutny, shuah, linux-kselftest,
	linux-kernel, Guopeng Zhang

From: Guopeng Zhang <zhangguopeng@kylinos.cn>

Offline all but one CPU in a root child below an isolated parent. Check
the invalid child state, the effective CPU masks and isolated accounting
for the released offline CPUs.

Signed-off-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
---
 tools/testing/selftests/cgroup/test_cpuset_prs.sh | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
index 35c19738aaa4..fb11a3ab0f35 100755
--- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh
+++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
@@ -330,6 +330,11 @@ TEST_MATRIX=(
 				   .      .     X4      .      .     0 A1:1-3|A2:1-3|A3:2-3|XA2:|XA3: A1:P2|A2:P-2|A3:P-2 1-3"
 	" C0-3:X1-3:P2 C1-3:X2-3:P2 C2-3:X3:P2 \
 				   .      .    C4:X     .      .     0 A1:1-3|A2:1-3|A3:2-3|XA2:|XA3: A1:P2|A2:P-2|A3:P-2 1-3"
+
+	# Direct invalidation returns child CPUs to the parent or its owner
+	" C1-4:P2  C3-4:P1  .      . T:O1=0:O2=0:O4=0 . .      . \
+					   0 A1:3|A2:3 A1:P2|A2:P-1 1-4"
+
 	# Local partition CPU change tests
 	" C0-5:P2  C4-5:P1  .      .      .    C3-5     .      .     0 A1:0-2|A2:3-5 A1:P2|A2:P1 0-2"
 	" C0-5:P2  C4-5:P1  .      .    C1-5     .      .      .     0 A1:1-3|A2:4-5 A1:P2|A2:P1 1-3"
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 12/17] cgroup/cpuset: Invalidate children outside the new CPU mask
  2026-08-20 12:41 [PATCH 00/17] cgroup/cpuset: Fix partition CPU ownership and isolation accounting Guopeng Zhang
                   ` (10 preceding siblings ...)
  2026-08-20 12:41 ` [PATCH 11/17] selftests/cgroup: Test isolation " Guopeng Zhang
@ 2026-08-20 12:41 ` Guopeng Zhang
  2026-08-20 12:41 ` [PATCH 13/17] selftests/cgroup: Test child invalidation after shrinking cpuset.cpus Guopeng Zhang
                   ` (4 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Guopeng Zhang @ 2026-08-20 12:41 UTC (permalink / raw)
  To: longman, cgroups
  Cc: ridong.chen, tj, hannes, mkoutny, shuah, linux-kselftest,
	linux-kernel, Guopeng Zhang

From: Guopeng Zhang <zhangguopeng@kylinos.cn>

When cpuset.cpus changes, compute_partition_effective_cpumask() builds a
new exclusive mask but checks child partitions against
cs->effective_xcpus. That field still contains the old mask, so a child
that no longer fits can remain valid.

Use new_xcpus for the check. A later partcmd_update() may revisit the
newly invalid child. Report PERR_INVCPUS if the child CPUs are outside
the parent effective exclusive mask so that this visit does not make the
child valid again.

Fixes: 0c7f293efc87 ("cgroup/cpuset: Add cpuset.cpus.exclusive.effective for v2")
Signed-off-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
---
 kernel/cgroup/cpuset.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index b9faadf4af6d..b3e749ede7d1 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -1987,12 +1987,16 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
 				adding = cpumask_and(tmp->addmask,
 						     cs->effective_xcpus,
 						     parent->effective_xcpus);
-		} else if (is_partition_invalid(cs) && !cpumask_empty(xcpus) &&
-			   cpumask_subset(xcpus, parent->effective_xcpus)) {
+		} else if (is_partition_invalid(cs) && !cpumask_empty(xcpus)) {
 			struct cgroup_subsys_state *css;
 			struct cpuset *child;
 			bool exclusive = true;
 
+			if (!cpumask_subset(xcpus, parent->effective_xcpus)) {
+				part_error = PERR_INVCPUS;
+				goto write_error;
+			}
+
 			/*
 			 * Convert invalid partition to valid has to
 			 * pass the cpu exclusivity test.
@@ -2144,7 +2148,7 @@ static void compute_partition_effective_cpumask(struct cpuset *cs,
 		WARN_ON_ONCE(is_remote_partition(child));
 		WRITE_ONCE(child->prs_err, 0);
 		if (!cpumask_subset(child->effective_xcpus,
-				    cs->effective_xcpus))
+				    new_xcpus))
 			WRITE_ONCE(child->prs_err, PERR_INVCPUS);
 		else if (populated &&
 			 cpumask_subset(new_ecpus, child->effective_xcpus))
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 13/17] selftests/cgroup: Test child invalidation after shrinking cpuset.cpus
  2026-08-20 12:41 [PATCH 00/17] cgroup/cpuset: Fix partition CPU ownership and isolation accounting Guopeng Zhang
                   ` (11 preceding siblings ...)
  2026-08-20 12:41 ` [PATCH 12/17] cgroup/cpuset: Invalidate children outside the new CPU mask Guopeng Zhang
@ 2026-08-20 12:41 ` Guopeng Zhang
  2026-08-20 12:41 ` [PATCH 14/17] cgroup/cpuset: Publish cpus_allowed before partition updates Guopeng Zhang
                   ` (3 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Guopeng Zhang @ 2026-08-20 12:41 UTC (permalink / raw)
  To: longman, cgroups
  Cc: ridong.chen, tj, hannes, mkoutny, shuah, linux-kselftest,
	linux-kernel, Guopeng Zhang

From: Guopeng Zhang <zhangguopeng@kylinos.cn>

Shrink a parent CPU mask in root/root, root/isolated and isolated/root
configurations. Check that the child becomes invalid and that effective
and isolated CPU masks reflect the new ownership.

Signed-off-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
---
 tools/testing/selftests/cgroup/test_cpuset_prs.sh | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
index fb11a3ab0f35..7345e89e22b7 100755
--- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh
+++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
@@ -331,6 +331,11 @@ TEST_MATRIX=(
 	" C0-3:X1-3:P2 C1-3:X2-3:P2 C2-3:X3:P2 \
 				   .      .    C4:X     .      .     0 A1:1-3|A2:1-3|A3:2-3|XA2:|XA3: A1:P2|A2:P-2|A3:P-2 1-3"
 
+	# A child outside its parent's new CPU mask becomes invalid
+	" C0-3:P1  C2-3:P1  .      .    C0-2     .      .      .     0 A1:0-2|A2:2 A1:P1|A2:P-1"
+	" C0-3:P1  C2-3:P2  .      .    C0-2     .      .      .     0 A1:0-2|A2:2 A1:P1|A2:P-2 ."
+	" C0-3:P2  C2-3:P1  .      .    C0-2     .      .      .     0 A1:0-2|A2:2 A1:P2|A2:P-1 0-2"
+
 	# Direct invalidation returns child CPUs to the parent or its owner
 	" C1-4:P2  C3-4:P1  .      . T:O1=0:O2=0:O4=0 . .      . \
 					   0 A1:3|A2:3 A1:P2|A2:P-1 1-4"
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 14/17] cgroup/cpuset: Publish cpus_allowed before partition updates
  2026-08-20 12:41 [PATCH 00/17] cgroup/cpuset: Fix partition CPU ownership and isolation accounting Guopeng Zhang
                   ` (12 preceding siblings ...)
  2026-08-20 12:41 ` [PATCH 13/17] selftests/cgroup: Test child invalidation after shrinking cpuset.cpus Guopeng Zhang
@ 2026-08-20 12:41 ` Guopeng Zhang
  2026-08-20 12:42 ` [PATCH 15/17] selftests/cgroup: Test shrinking cpuset.cpus in a remote partition Guopeng Zhang
                   ` (2 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Guopeng Zhang @ 2026-08-20 12:41 UTC (permalink / raw)
  To: longman, cgroups
  Cc: ridong.chen, tj, hannes, mkoutny, shuah, linux-kselftest,
	linux-kernel, Guopeng Zhang

From: Guopeng Zhang <zhangguopeng@kylinos.cn>

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 <zhangguopeng@kylinos.cn>
---
 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


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 15/17] selftests/cgroup: Test shrinking cpuset.cpus in a remote partition
  2026-08-20 12:41 [PATCH 00/17] cgroup/cpuset: Fix partition CPU ownership and isolation accounting Guopeng Zhang
                   ` (13 preceding siblings ...)
  2026-08-20 12:41 ` [PATCH 14/17] cgroup/cpuset: Publish cpus_allowed before partition updates Guopeng Zhang
@ 2026-08-20 12:42 ` Guopeng Zhang
  2026-08-20 12:42 ` [PATCH 16/17] cgroup/cpuset: Fix isolated accounting on propagated invalidation Guopeng Zhang
  2026-08-20 12:42 ` [PATCH 17/17] selftests/cgroup: Test isolation " Guopeng Zhang
  16 siblings, 0 replies; 18+ messages in thread
From: Guopeng Zhang @ 2026-08-20 12:42 UTC (permalink / raw)
  To: longman, cgroups
  Cc: ridong.chen, tj, hannes, mkoutny, shuah, linux-kselftest,
	linux-kernel, Guopeng Zhang

From: Guopeng Zhang <zhangguopeng@kylinos.cn>

Cover remote partition shrink with and without a local isolated child.
Check that removed CPUs return to the top cpuset and that child
invalidation preserves isolated CPU accounting.

Signed-off-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
---
 tools/testing/selftests/cgroup/test_cpuset_prs.sh | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
index 7345e89e22b7..ad01016ddc8d 100755
--- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh
+++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
@@ -520,6 +520,15 @@ REMOTE_TEST_MATRIX=(
 	"  C1-4:P1   .   C1-2:P1  C2-4:P2  .       .  \
 	      .      .     .       C1-2    .       .     p1:3-4|c11:1-2|c12:3-4 \
 							 p1:P1|c11:P1|c12:P-2"
+	# Shrinking a remote partition must return removed CPUs to the top
+	# partition even when it has no child partitions.
+	"  C1-4:P1   .      .       .       .       .  \
+	    C1-3     .      .       .       .       .     p1:1-3 p1:P1 ."
+	# A local child invalidated by a remote parent's CPU change must return
+	# isolated accounting to the remote parent or the top partition.
+	"  C1-4:P1   .   C3-4:P2   .       .       .  \
+	    C1-3     .     .       .       .       .     p1:1-3|c11:3 \
+							 p1:P1|c11:P-2 ."
 	# Cpusets with empty cpuset.cpus should inherit parent's effective_cpus
 	"  C1-4:P1 C5-6   C1-2     .       C5      .  \
 	      .      P1    P1      .       .       .     p1:3-4|p2:5-6|c11:1-2|c12:3-4|c21:5|c22:5-6 \
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 16/17] cgroup/cpuset: Fix isolated accounting on propagated invalidation
  2026-08-20 12:41 [PATCH 00/17] cgroup/cpuset: Fix partition CPU ownership and isolation accounting Guopeng Zhang
                   ` (14 preceding siblings ...)
  2026-08-20 12:42 ` [PATCH 15/17] selftests/cgroup: Test shrinking cpuset.cpus in a remote partition Guopeng Zhang
@ 2026-08-20 12:42 ` Guopeng Zhang
  2026-08-20 12:42 ` [PATCH 17/17] selftests/cgroup: Test isolation " Guopeng Zhang
  16 siblings, 0 replies; 18+ messages in thread
From: Guopeng Zhang @ 2026-08-20 12:42 UTC (permalink / raw)
  To: longman, cgroups
  Cc: ridong.chen, tj, hannes, mkoutny, shuah, linux-kselftest,
	linux-kernel, Guopeng Zhang

From: Guopeng Zhang <zhangguopeng@kylinos.cn>

update_cpumasks_hier() invalidates a local partition when its parent
becomes a member or an invalid partition. Its CPUs return to the nearest
valid partition ancestor, but isolated_cpus still reflects the old
partition type.

Update isolated_cpus before resetting a local partition whose state
changes from valid to invalid below an invalid parent. Remote partitions
are excluded because remote_partition_disable() already updates their
isolated CPU accounting.

Fixes: 11e5f407b64a ("cgroup/cpuset: Keep track of CPUs in isolated partitions")
Signed-off-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
---
 kernel/cgroup/cpuset.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 9e13fc962f41..4af8e348e838 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -2236,9 +2236,12 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp,
 	cpuset_for_each_descendant_pre(cp, pos_css, cs) {
 		struct cpuset *parent = parent_cs(cp);
 		bool remote = is_remote_partition(cp);
+		bool was_remote = remote;
 		bool update_parent = false;
+		int owner_prs;
 
 		old_prs = new_prs = cp->partition_root_state;
+		owner_prs = old_prs;
 
 		/*
 		 * For child remote partition root (!= cs), we need to call
@@ -2338,7 +2341,18 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp,
 			new_prs = cp->partition_root_state;
 		}
 
+		/*
+		 * With no valid parent partition left, this partition's CPUs
+		 * return to the nearest valid partition ancestor.
+		 */
+		if (!was_remote && old_prs > 0 && new_prs < 0 &&
+		    !is_partition_valid(parent))
+			owner_prs = partition_owner(cp)->partition_root_state;
+
 		spin_lock_irq(&callback_lock);
+		if (old_prs != owner_prs)
+			isolated_cpus_update(old_prs, owner_prs,
+					     cp->effective_xcpus);
 		cpumask_copy(cp->effective_cpus, tmp->new_cpus);
 		cp->partition_root_state = new_prs;
 		/*
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 17/17] selftests/cgroup: Test isolation accounting on propagated invalidation
  2026-08-20 12:41 [PATCH 00/17] cgroup/cpuset: Fix partition CPU ownership and isolation accounting Guopeng Zhang
                   ` (15 preceding siblings ...)
  2026-08-20 12:42 ` [PATCH 16/17] cgroup/cpuset: Fix isolated accounting on propagated invalidation Guopeng Zhang
@ 2026-08-20 12:42 ` Guopeng Zhang
  16 siblings, 0 replies; 18+ messages in thread
From: Guopeng Zhang @ 2026-08-20 12:42 UTC (permalink / raw)
  To: longman, cgroups
  Cc: ridong.chen, tj, hannes, mkoutny, shuah, linux-kselftest,
	linux-kernel, Guopeng Zhang

From: Guopeng Zhang <zhangguopeng@kylinos.cn>

State-matrix cases exercise a child invalidated by its parent and a
nested partition invalidated through an already invalid parent.

Signed-off-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
---
 tools/testing/selftests/cgroup/test_cpuset_prs.sh | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
index ad01016ddc8d..89f54c689336 100755
--- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh
+++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
@@ -340,6 +340,12 @@ TEST_MATRIX=(
 	" C1-4:P2  C3-4:P1  .      . T:O1=0:O2=0:O4=0 . .      . \
 					   0 A1:3|A2:3 A1:P2|A2:P-1 1-4"
 
+	# Invalidation propagated from a parent returns all descendant CPUs
+	" C0-3:P1  C2-3:P2  .      .      P0      .      .      . \
+					   0 A1:0-3|A2:2-3 A1:P0|A2:P-2 ."
+	" C0-5:P2  C2-5:P2 C4-5:P1 .      .       P0     .      . \
+					   0 A1:0-5|A2:2-5|A3:4-5 A1:P2|A2:P0|A3:P-1 0-5"
+
 	# Local partition CPU change tests
 	" C0-5:P2  C4-5:P1  .      .      .    C3-5     .      .     0 A1:0-2|A2:3-5 A1:P2|A2:P1 0-2"
 	" C0-5:P2  C4-5:P1  .      .    C1-5     .      .      .     0 A1:1-3|A2:4-5 A1:P2|A2:P1 1-3"
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2026-08-20 12:43 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-20 12:41 [PATCH 00/17] cgroup/cpuset: Fix partition CPU ownership and isolation accounting Guopeng Zhang
2026-08-20 12:41 ` [PATCH 01/17] selftests/cgroup: Drop invalid boot isolation comparison Guopeng Zhang
2026-08-20 12:41 ` [PATCH 02/17] cgroup/cpuset: Preserve boot-isolated CPUs on partition release Guopeng Zhang
2026-08-20 12:41 ` [PATCH 03/17] selftests/cgroup: Test boot-isolated CPU " Guopeng Zhang
2026-08-20 12:41 ` [PATCH 04/17] cgroup/cpuset: Limit type-change accounting to owned CPUs Guopeng Zhang
2026-08-20 12:41 ` [PATCH 05/17] selftests/cgroup: Test isolated CPU accounting on type changes Guopeng Zhang
2026-08-20 12:41 ` [PATCH 06/17] cgroup/cpuset: Validate type changes against owned CPUs Guopeng Zhang
2026-08-20 12:41 ` [PATCH 07/17] selftests/cgroup: Test type-change validation with child-owned CPUs Guopeng Zhang
2026-08-20 12:41 ` [PATCH 08/17] cgroup/cpuset: Release CPUs when a type change is rejected Guopeng Zhang
2026-08-20 12:41 ` [PATCH 09/17] selftests/cgroup: Test rejected partition type changes Guopeng Zhang
2026-08-20 12:41 ` [PATCH 10/17] cgroup/cpuset: Fix isolated accounting on direct child invalidation Guopeng Zhang
2026-08-20 12:41 ` [PATCH 11/17] selftests/cgroup: Test isolation " Guopeng Zhang
2026-08-20 12:41 ` [PATCH 12/17] cgroup/cpuset: Invalidate children outside the new CPU mask Guopeng Zhang
2026-08-20 12:41 ` [PATCH 13/17] selftests/cgroup: Test child invalidation after shrinking cpuset.cpus Guopeng Zhang
2026-08-20 12:41 ` [PATCH 14/17] cgroup/cpuset: Publish cpus_allowed before partition updates Guopeng Zhang
2026-08-20 12:42 ` [PATCH 15/17] selftests/cgroup: Test shrinking cpuset.cpus in a remote partition Guopeng Zhang
2026-08-20 12:42 ` [PATCH 16/17] cgroup/cpuset: Fix isolated accounting on propagated invalidation Guopeng Zhang
2026-08-20 12:42 ` [PATCH 17/17] selftests/cgroup: Test isolation " Guopeng Zhang

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.