mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH-next 0/6] cgroup/cpuset: Miscellaneous bug fixes
@ 2026-10-22  3:16 Waiman Long
  2026-10-22  3:16 ` [PATCH-next 1/6] cgroup/cpuset: Find furthest isolated ancestor for invalidated isolated partition Waiman Long
                   ` (5 more replies)
  0 siblings, 6 replies; 16+ messages in thread
From: Waiman Long @ 2026-10-22  3:16 UTC (permalink / raw)
  To: Ridong Chen, Tejun Heo, Johannes Weiner, Michal Koutný, Shuah Khan
  Cc: cgroups, linux-kernel, linux-kselftest, Guopeng Zhang, Waiman Long

This patch series includes a number of fixes for bugs or issues reported
by sashiko (patches 1-5) and Guopeng Zhang (patch 6).

Waiman Long (6):
  cgroup/cpuset: Find furthest isolated ancestor for invalidated
    isolated partition
  cgroup/cpuset: Properly compute effective xcpus in
    update_parent_effective_cpumask()
  cgroup/cpuset: Fix incorrect effective_cpus bug in
    update_cpumasks_hier()
  cgroup/cpuset: Minor fixes to prstate_housekeeping_conflict()
  selftests/cgroup: Check for a single range nohz_full CPUs before
    running test matrix
  cgroup/cpuset: Prevent recursive call of remote_cpus_update() via
    update_cpumasks_hier()

 kernel/cgroup/cpuset-internal.h               |   5 +
 kernel/cgroup/cpuset.c                        | 140 ++++++++++--------
 .../selftests/cgroup/test_cpuset_prs.sh       |  18 ++-
 3 files changed, 100 insertions(+), 63 deletions(-)

-- 
2.55.0


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

* [PATCH-next 1/6] cgroup/cpuset: Find furthest isolated ancestor for invalidated isolated partition
  2026-10-22  3:16 [PATCH-next 0/6] cgroup/cpuset: Miscellaneous bug fixes Waiman Long
@ 2026-10-22  3:16 ` Waiman Long
  2026-10-22 13:25   ` Guopeng Zhang
  2026-10-22  3:16 ` [PATCH-next 2/6] cgroup/cpuset: Properly compute effective xcpus in update_parent_effective_cpumask() Waiman Long
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 16+ messages in thread
From: Waiman Long @ 2026-10-22  3:16 UTC (permalink / raw)
  To: Ridong Chen, Tejun Heo, Johannes Weiner, Michal Koutný, Shuah Khan
  Cc: cgroups, linux-kernel, linux-kselftest, Guopeng Zhang, Waiman Long

Commit 46b885416c27 ("cgroup/cpuset: Fix a missing isolated_cpus
update in update_cpumasks_hier()") searches for the closet partition
root ancestor to determine if the isolated CPUs in a to be invalidated
isolation partition should be removed from isolated_cpus or not.

As reported by sashiko, this method may not work when there is a deeply
nested isolated partition hierarchy. For instance, Consider a nested
hierarchy A0 -> A1 -> A2 -> A3 where all four are PRS_ISOLATED:

  A0: effective_xcpus = 0-4
  A1: effective_xcpus = 1-4
  A2: effective_xcpus = 2-4
  A3: effective_xcpus = 3-4

When A1 shrinks its exclusive_cpus from 1-4 to 1-2, A2 will update it
effective_xcpus to 2. A3 will find its closet partition root ancestor
A2 and decides that its effective_xcpus 3-4 should be removed from
isolated_cpus which is incorrect.

Address this corner case by searching for the furthest isolated partition
root ancestor instead to decide if its isolated CPUs should be returned
to isolated_cpus.

Fixes: 46b885416c27 ("cgroup/cpuset: Fix a missing isolated_cpus update in update_cpumasks_hier()")
Signed-off-by: Waiman Long <longman@redhat.com>
---
 kernel/cgroup/cpuset.c | 36 +++++++++++++++++-------------------
 1 file changed, 17 insertions(+), 19 deletions(-)

diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 585a982249ad..7ead8c3b7974 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -2156,22 +2156,20 @@ static void compute_partition_effective_cpumask(struct cpuset *cs,
 }
 
 /*
- * ancestor_partition - Find and return the closest valid partition root ancestor
+ * iancestor_partition - Return furthest isolated partition root ancestor available
  * @cs: the current cpuset
- *
- * Return: The closet partition root ancestor cpuset
+ * Return: The furthest isolated partition root ancestor available or NULL if
+ *	   not found.
  */
-static struct cpuset *ancestor_partition(struct cpuset *cs)
+static struct cpuset *iancestor_partition(struct cpuset *cs)
 {
 	struct cpuset *ancestor = parent_cs(cs);
+	struct cpuset *iancestor = NULL;
 
-	/*
-	 * 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;
+	for (; ancestor; ancestor = parent_cs(ancestor))
+		if (ancestor->partition_root_state == PRS_ISOLATED)
+			iancestor = ancestor;
+	return iancestor;
 }
 
 /*
@@ -2283,23 +2281,23 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp,
 				 * 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.
+				 * there is a furthest isolated partition root
+				 * ancestor available. When such a PRS_ISOLATED
+				 * ancestor is available, 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 = -old_prs;
 
 				if (old_prs == PRS_ISOLATED) {
-					struct cpuset *ancestor = ancestor_partition(cp);
+					struct cpuset *iancestor = iancestor_partition(cp);
 
-					if (ancestor->partition_root_state == PRS_ROOT)
+					if (!iancestor)
 						del_cpus = cp->effective_xcpus;
 					else if (cpumask_andnot(tmp->delmask,
 								cp->effective_xcpus,
-								ancestor->effective_xcpus))
+								iancestor->effective_xcpus))
 						del_cpus = tmp->delmask;
 
 					if (del_cpus) {
-- 
2.55.0


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

* [PATCH-next 2/6] cgroup/cpuset: Properly compute effective xcpus in update_parent_effective_cpumask()
  2026-10-22  3:16 [PATCH-next 0/6] cgroup/cpuset: Miscellaneous bug fixes Waiman Long
  2026-10-22  3:16 ` [PATCH-next 1/6] cgroup/cpuset: Find furthest isolated ancestor for invalidated isolated partition Waiman Long
@ 2026-10-22  3:16 ` Waiman Long
  2026-10-22 13:45   ` Guopeng Zhang
  2026-10-22  3:16 ` [PATCH-next 3/6] cgroup/cpuset: Fix incorrect effective_cpus bug in update_cpumasks_hier() Waiman Long
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 16+ messages in thread
From: Waiman Long @ 2026-10-22  3:16 UTC (permalink / raw)
  To: Ridong Chen, Tejun Heo, Johannes Weiner, Michal Koutný, Shuah Khan
  Cc: cgroups, linux-kernel, linux-kselftest, Guopeng Zhang, Waiman Long

Since the introduction of cpuset.cpus.exclusive in commit
e2ffe502ba45 ("cgroup/cpuset: Add cpuset.cpus.exclusive for v2"), a
compute_effective_exclusive_cpumask() helper which is later renamed to
compute_excpus() is added to compute the effective xcpus of a partition
root. However update_parent_effective_cpumask() is not updated in all
proper places to use the new helper to check if a given cpuset should
remain a valid partition root. This can cause a cpuset to incorrectly
remain a valid partition root even if no effective xcpus is left.

Fix that problem by using compute_excpus() to compute the effective xcpus
into delmask in all cases except partcmd_disable and partcmd_invalidate
and use it for tasks_nocpu_error() check as well as checking its
emptiness. This enables us to catch invalid partition root more
accurately in update_parent_effective_cpumask().

Some test case are added to test_cpuset_prs.sh for invalidating a
partition root due to its effective xcpus becoming empty as well as
making sure that an invalid partition can only be revived when exclusive
CPUs are available agin.

Fixes: e2ffe502ba45 ("cgroup/cpuset: Add cpuset.cpus.exclusive for v2")
Signed-off-by: Waiman Long <longman@redhat.com>
---
 kernel/cgroup/cpuset.c                        | 36 +++++++++----------
 .../selftests/cgroup/test_cpuset_prs.sh       |  6 ++++
 2 files changed, 22 insertions(+), 20 deletions(-)

diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 7ead8c3b7974..db6e4663f4be 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -1798,7 +1798,6 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
 	int deleting;	/* Deleting cpus from parent's effective_cpus	*/
 	int old_prs, new_prs;
 	int part_error = PERR_NONE;	/* Partition error? */
-	struct cpumask *xcpus = user_xcpus(cs);
 	int parent_prs = parent->partition_root_state;
 	bool nocpu;
 
@@ -1841,30 +1840,29 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
 	if (!newmask && xcpus_empty(cs))
 		return PERR_CPUSEMPTY;
 
-	nocpu = tasks_nocpu_error(parent, cs, xcpus);
+	/*
+	 * Except for partcmd_disable, use delmask to compute the current
+	 * effective xcpus value and use it for tasks_nocpu_error check.
+	 */
+	if (cmd != partcmd_disable) {
+		compute_excpus(cs, tmp->delmask);
+		nocpu = tasks_nocpu_error(parent, cs, tmp->delmask);
+	}
 
 	if ((cmd == partcmd_enable) || (cmd == partcmd_enablei)) {
-		/*
-		 * Need to call compute_excpus() in case
-		 * exclusive_cpus not set. Sibling conflict should only happen
-		 * if exclusive_cpus isn't set.
-		 */
-		xcpus = tmp->delmask;
-		if (compute_excpus(cs, xcpus))
-			WARN_ON_ONCE(!cpumask_empty(cs->exclusive_cpus));
 		new_prs = (cmd == partcmd_enable) ? PRS_ROOT : PRS_ISOLATED;
 
 		/*
 		 * Enabling partition root is not allowed if its
 		 * effective_xcpus is empty.
 		 */
-		if (cpumask_empty(xcpus))
+		if (cpumask_empty(tmp->delmask))
 			return PERR_INVCPUS;
 
-		if (prstate_housekeeping_conflict(new_prs, parent_prs, xcpus, NULL))
+		if (prstate_housekeeping_conflict(new_prs, parent_prs, tmp->delmask, NULL))
 			return PERR_HKEEPING;
 
-		if (tasks_nocpu_error(parent, cs, xcpus))
+		if (nocpu)
 			return PERR_NOCPUS;
 
 		/*
@@ -1876,9 +1874,8 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
 		 *
 		 * Warn if it is not the case.
 		 */
-		cpumask_and(tmp->new_cpus, xcpus, cpu_active_mask);
+		cpumask_and(tmp->new_cpus, tmp->delmask, cpu_active_mask);
 		WARN_ON_ONCE(!cpumask_subset(tmp->new_cpus, parent->effective_cpus));
-
 		deleting = true;
 	} else if (cmd == partcmd_disable) {
 		/*
@@ -1973,7 +1970,7 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
 		 * A partition error happens when parent has tasks and all
 		 * its effective CPUs will have to be distributed out.
 		 */
-		if (nocpu) {
+		if (nocpu || cpumask_empty(tmp->delmask)) {
 			part_error = PERR_NOCPUS;
 			if (is_partition_valid(cs))
 				adding = cpumask_and(tmp->addmask,
@@ -1986,8 +1983,7 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
 				cpumask_copy(tmp->addmask, cs->effective_xcpus);
 				adding = true;
 			}
-		} else if (is_partition_invalid(cs) && !cpumask_empty(xcpus) &&
-			   cpumask_subset(xcpus, parent->effective_xcpus)) {
+		} else if (is_partition_invalid(cs)) {
 			struct cgroup_subsys_state *css;
 			struct cpuset *child;
 			bool exclusive = true;
@@ -1998,7 +1994,7 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
 			 * check.
 			 */
 			if (prstate_housekeeping_conflict(cs->partition_root_state,
-							  parent_prs, xcpus, NULL)) {
+							  parent_prs, tmp->delmask, NULL)) {
 				part_error = PERR_HKEEPING;
 				goto write_error;
 			}
@@ -2014,7 +2010,7 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
 			rcu_read_unlock();
 			if (exclusive)
 				deleting = cpumask_and(tmp->delmask,
-						xcpus, parent->effective_cpus);
+						tmp->delmask, parent->effective_cpus);
 			else
 				part_error = PERR_NOTEXCL;
 		}
diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
index d04aad697b96..47791591002f 100755
--- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh
+++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
@@ -359,6 +359,8 @@ TEST_MATRIX=(
 								       A1:P0|A2:P1|A3:P2|B1:P1 2-4|3"
 	"  C1-6:P1 C3-6:P1 C5-6:P1 .      .      P2      .      .    0 A1:1-2|A2:3-6|A3:5-6 \
 								       A1:P1|A2:P2|A3:P-1 3-6"
+	"  C1-6:P2 C3-6:P2 C3-4:P2 .      .     C5-6     .      .    0 A1:1-4|A2:5-6|A3:5-6 \
+								       A1:P2|A2:P2|A3:P-2 1-6"
 	" 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 ."
@@ -427,6 +429,10 @@ TEST_MATRIX=(
 	# cpuset.cpus is allowed, but those extra CPUs are ignored.
 	"  C2-3:P1   C3:P1  .      .      .     C2-4    .      .     0 A1:|A2:2-3 A1:P1|A2:P1"
 
+	# A child cannot recover until its exclusive CPUs are available again.
+	" CX1-4:P1 CX3-4:P1 .     .     X1-2     .      .      .     0 A1:1-2|A2:1-2|XA2: A1:P1|A2:P-1"
+	" CX1-4:P1 CX3-4:P1 .     .  X1-2:X1-4   .      .      .     0 A1:1-2|A2:3-4|XA2:3-4 A1:P1|A2:P1"
+
 	# Taking away all CPUs from parent or itself if there are tasks
 	# will make the partition invalid.
 	"  C2-3:P1   C3:P1  .      .      T     C2-3    .      .     0 A1:2-3|A2:2-3 A1:P1|A2:P-1"
-- 
2.55.0


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

* [PATCH-next 3/6] cgroup/cpuset: Fix incorrect effective_cpus bug in update_cpumasks_hier()
  2026-10-22  3:16 [PATCH-next 0/6] cgroup/cpuset: Miscellaneous bug fixes Waiman Long
  2026-10-22  3:16 ` [PATCH-next 1/6] cgroup/cpuset: Find furthest isolated ancestor for invalidated isolated partition Waiman Long
  2026-10-22  3:16 ` [PATCH-next 2/6] cgroup/cpuset: Properly compute effective xcpus in update_parent_effective_cpumask() Waiman Long
@ 2026-10-22  3:16 ` Waiman Long
  2026-10-22  3:16 ` [PATCH-next 4/6] cgroup/cpuset: Minor fixes to prstate_housekeeping_conflict() Waiman Long
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: Waiman Long @ 2026-10-22  3:16 UTC (permalink / raw)
  To: Ridong Chen, Tejun Heo, Johannes Weiner, Michal Koutný, Shuah Khan
  Cc: cgroups, linux-kernel, linux-kselftest, Guopeng Zhang, Waiman Long

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@redhat.com>
---
 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);
+			}
 		}
 
 		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 ."
-- 
2.55.0


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

* [PATCH-next 4/6] cgroup/cpuset: Minor fixes to prstate_housekeeping_conflict()
  2026-10-22  3:16 [PATCH-next 0/6] cgroup/cpuset: Miscellaneous bug fixes Waiman Long
                   ` (2 preceding siblings ...)
  2026-10-22  3:16 ` [PATCH-next 3/6] cgroup/cpuset: Fix incorrect effective_cpus bug in update_cpumasks_hier() Waiman Long
@ 2026-10-22  3:16 ` Waiman Long
  2026-10-22 14:15   ` Guopeng Zhang
  2026-10-22  3:16 ` [PATCH-next 5/6] selftests/cgroup: Check for a single range nohz_full CPUs before running test matrix Waiman Long
  2026-10-22  3:16 ` [PATCH-next 6/6] cgroup/cpuset: Prevent recursive call of remote_cpus_update() via update_cpumasks_hier() Waiman Long
  5 siblings, 1 reply; 16+ messages in thread
From: Waiman Long @ 2026-10-22  3:16 UTC (permalink / raw)
  To: Ridong Chen, Tejun Heo, Johannes Weiner, Michal Koutný, Shuah Khan
  Cc: cgroups, linux-kernel, linux-kselftest, Guopeng Zhang, Waiman Long

Commit 9527ff78a413 ("group/cpuset: Consider all the exclusive CPUs when
doing housekeeping check") changes the way prstate_housekeeping_conflict()
is being used by considering all the exclusive xcpus to be owned by the
partition when doing housekeeping check. However there are two minor
issues reported by sashiko with that patch:

 1) In partition_cpus_change(), prstate_housekeeping_conflict() can
 be called with an invalid partition root. In that case, there are
 no isolated CPUs that are going to be returned back to the system to
 become housekeeping CPUs, so the calculation of the del_cpus cpumask
 is meaningless.

 2) The checking of del_cpus in prstate_housekeeping_conflict() to see
 if it can contain an active housekeeping CPU that can be returned to the
 system ignores the fact that an active CPU not in HK_TYPE_DOMAIN_BOOT HK
 cpumask will not become an active housekeeping CPU when it is released
 by an isolated partition.

Update the existing code to handle these two issues properly to make
prstate_housekeeping_conflict() produce more accurate result.

Fixes: 9527ff78a413 ("group/cpuset: Consider all the exclusive CPUs when doing housekeeping check")
Signed-off-by: Waiman Long <longman@redhat.com>
---
 kernel/cgroup/cpuset.c | 45 +++++++++++++++++++++++++++++-------------
 1 file changed, 31 insertions(+), 14 deletions(-)

diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 7b9062326f35..6e1bef12f86d 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -1397,6 +1397,9 @@ static bool prstate_housekeeping_conflict(int new_prs, int parent_prs,
 	    !cpumask_subset(new_cpus, housekeeping_cpumask(HK_TYPE_DOMAIN_BOOT)))
 		return true;
 
+	if (del_cpus && cpumask_empty(del_cpus))
+		del_cpus = NULL;
+
 	/*
 	 * Exit 2nd check early and return false if
 	 * 1) there is no boot time isolated nohz_full CPU
@@ -1405,8 +1408,7 @@ static bool prstate_housekeeping_conflict(int new_prs, int parent_prs,
 	 *    be returned back to the parent.
 	 */
 	if (!housekeeping_enabled(HK_TYPE_KERNEL_NOISE) ||
-	    (new_prs == parent_prs) ||
-	    ((new_prs == PRS_ROOT) && (!del_cpus || cpumask_empty(del_cpus))))
+	    (new_prs == parent_prs) || (!del_cpus && (new_prs == PRS_ROOT)))
 		return false;
 
 	/*
@@ -1417,20 +1419,29 @@ static bool prstate_housekeeping_conflict(int new_prs, int parent_prs,
 	if (parent_prs == PRS_ISOLATED)
 		swap(new_cpus, del_cpus);
 
-	if (del_cpus &&
-	   (cpumask_first_and_and(del_cpus, housekeeping_cpumask(HK_TYPE_KERNEL_NOISE),
-				   cpu_active_mask) < nr_cpu_ids))
-		return false;
-
 	if (!alloc_cpumask_var(&full_hk_cpus, GFP_KERNEL))
 		return true;
 
+	/*
+	 * Check if del_cpus may contain a CPU that can become an active
+	 * housekeeping CPU again.
+	 */
+	if (del_cpus) {
+		cpumask_and(full_hk_cpus, housekeeping_cpumask(HK_TYPE_KERNEL_NOISE),
+			    housekeeping_cpumask(HK_TYPE_DOMAIN_BOOT));
+		if (cpumask_first_and_and(del_cpus, full_hk_cpus,
+					  cpu_active_mask) < nr_cpu_ids) {
+			res = false;
+			goto out;
+		}
+	}
+
 	cpumask_and(full_hk_cpus, housekeeping_cpumask(HK_TYPE_KERNEL_NOISE),
 		    housekeeping_cpumask(HK_TYPE_DOMAIN));
 	cpumask_andnot(full_hk_cpus, full_hk_cpus, isolated_cpus);
 	cpumask_and(full_hk_cpus, full_hk_cpus, cpu_active_mask);
 	res = !cpumask_weight_andnot(full_hk_cpus, new_cpus);
-
+out:
 	free_cpumask_var(full_hk_cpus);
 	return res;
 }
@@ -2475,23 +2486,29 @@ static void partition_cpus_change(struct cpuset *cs, struct cpuset *trialcs,
 				  struct tmpmasks *tmp)
 {
 	enum prs_errcode prs_err;
+	int parent_prs = is_remote_partition(cs)
+		       ? PRS_ROOT : parent_cs(cs)->partition_root_state;
 
 	if (cs_is_member(cs))
 		return;
 
 	prs_err = validate_partition(cs, trialcs);
-	if (!prs_err && !cpumask_empty(trialcs->effective_xcpus)) {
+	if (!prs_err && (parent_prs > 0) &&
+	    !cpumask_empty(trialcs->effective_xcpus)) {
 		int prs = cs->partition_root_state;
-		int parent_prs = is_remote_partition(cs)
-			       ? PRS_ROOT : parent_cs(cs)->partition_root_state;
+
 		/*
 		 * Check for housekeeping conflict by passing the whole
 		 * effective_xcpus as well as those CPUs that are to be
 		 * removed from cs as delmask.
 		 */
-		cpumask_andnot(tmp->delmask, cs->effective_xcpus, trialcs->effective_xcpus);
-		if (parent_prs > 0 &&
-		    prstate_housekeeping_conflict(prs, parent_prs,
+		if (prs > 0)
+			cpumask_andnot(tmp->delmask, cs->effective_xcpus,
+				       trialcs->effective_xcpus);
+		else
+			cpumask_clear(tmp->delmask);
+
+		if (prstate_housekeeping_conflict(prs, parent_prs,
 						  trialcs->effective_xcpus, tmp->delmask))
 			prs_err = PERR_HKEEPING;
 	}
-- 
2.55.0


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

* [PATCH-next 5/6] selftests/cgroup: Check for a single range nohz_full CPUs before running test matrix
  2026-10-22  3:16 [PATCH-next 0/6] cgroup/cpuset: Miscellaneous bug fixes Waiman Long
                   ` (3 preceding siblings ...)
  2026-10-22  3:16 ` [PATCH-next 4/6] cgroup/cpuset: Minor fixes to prstate_housekeeping_conflict() Waiman Long
@ 2026-10-22  3:16 ` Waiman Long
  2026-10-22 14:09   ` Guopeng Zhang
  2026-10-22  3:16 ` [PATCH-next 6/6] cgroup/cpuset: Prevent recursive call of remote_cpus_update() via update_cpumasks_hier() Waiman Long
  5 siblings, 1 reply; 16+ messages in thread
From: Waiman Long @ 2026-10-22  3:16 UTC (permalink / raw)
  To: Ridong Chen, Tejun Heo, Johannes Weiner, Michal Koutný, Shuah Khan
  Cc: cgroups, linux-kernel, linux-kselftest, Guopeng Zhang, Waiman Long

Commit 989ca25c10ca ("selftests/cgroup: Add tests for nohz_full
housekeeping check") adds a nohz_full test matrix that will only be run
when a nohz_full boot parameter cover all the CPUs beyond CPUs 0-7. The
code looks for the first and last CPU numbers in the nohz_full sysfs
file to determine if that criterion is met. However if there are holes in
the range (i.e. has ",") the test matrix may be incorrectly run leading
to unexpected test failure. Fix that by skipping "," and anything after
that to make sure the first range will cover all the remaining CPUs.

Fixes: 989ca25c10ca ("selftests/cgroup: Add tests for nohz_full housekeeping check")
Signed-off-by: Waiman Long <longman@redhat.com>
---
 tools/testing/selftests/cgroup/test_cpuset_prs.sh | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
index 8595b6b4b7bf..5bc144836bdf 100755
--- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh
+++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
@@ -111,9 +111,9 @@ echo "" > test/cpuset.cpus
 #
 # If nohz_full CPUs have been reserved at boot time, they should not include
 # CPUs 0-7 as that may fail some of the test cases. On the other hand if the
-# set of nohz_full CPUs includes all the CPUs except 0-7, we can run a special
-# set of housekeeping CPUs exhaustion tests to see if the cpuset code will
-# reject them.
+# set of nohz_full CPUs includes all the CPUs except 0-7 in a single range
+# <first>-<last>, we can run a special set of housekeeping CPUs exhaustion
+# tests to see if the cpuset code will reject them.
 #
 FIRST_NOHZ_FULL_CPU=
 LAST_NOHZ_FULL_CPU=
@@ -124,7 +124,7 @@ NOHZ_FULL_CPUS=
 LAST_PRESENT_CPU=$(cat /sys/devices/system/cpu/present | sed -e "s/.*[,-]//")
 [[ -n "$NOHZ_FULL_CPUS" ]] && {
 	FIRST_NOHZ_FULL_CPU=$(echo $NOHZ_FULL_CPUS | sed -e "s/[,-].*//")
-	LAST_NOHZ_FULL_CPU=$(echo $NOHZ_FULL_CPUS | sed -e "s/.*[,-]//")
+	LAST_NOHZ_FULL_CPU=$(echo $NOHZ_FULL_CPUS | sed -e "s/,.*//;s/.*[-]//")
 	echo "Boot nohz_full CPUs: $NOHZ_FULL_CPUS"
 }
 [[ -n "$FIRST_NOHZ_FULL_CPU" && "$FIRST_NOHZ_FULL_CPU" -le 7 ]] &&
-- 
2.55.0


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

* [PATCH-next 6/6] cgroup/cpuset: Prevent recursive call of remote_cpus_update() via update_cpumasks_hier()
  2026-10-22  3:16 [PATCH-next 0/6] cgroup/cpuset: Miscellaneous bug fixes Waiman Long
                   ` (4 preceding siblings ...)
  2026-10-22  3:16 ` [PATCH-next 5/6] selftests/cgroup: Check for a single range nohz_full CPUs before running test matrix Waiman Long
@ 2026-10-22  3:16 ` Waiman Long
  2026-10-22 14:23   ` Guopeng Zhang
  5 siblings, 1 reply; 16+ messages in thread
From: Waiman Long @ 2026-10-22  3:16 UTC (permalink / raw)
  To: Ridong Chen, Tejun Heo, Johannes Weiner, Michal Koutný, Shuah Khan
  Cc: cgroups, linux-kernel, linux-kselftest, Guopeng Zhang,
	Waiman Long, Guopeng Zhang

Guopeng reports that changing the cpumask of a remote partition root
may set the effective_cpus of the top_cpuset incorrectly. It is
due to the following call sequence:

  update_cpumask()
   -> partition_cpus_change()
    -> remote_cpus_update()
     -> update_sibling_cpumasks()
      -> update_cpumasks_hier()
       -> remote_cpus_update()

The second remote_cpus_update() call passes in the cs->effective_xcpus
instead of the trialcs->effective_xcpus of the first remote_cpus_update()
call.  As a result, the second call can revert what has been done in
the first call leading to incorrect effective_cpus of the top_cpuset
as well as subpartitions_cpus.

Fix that by adding a new remote_partition_updating flag into the cpuset
structure to indicate that a remote partition is being updated and
update_cpumasks_hier() should skip the whole subtree as update_cpumask()
or update_exclusive_cpumask() which calls partition_cpus_change()
will eventually calls update_cpumasks_hier() for that subtree anyway.

This new flag is currently set only in remote_cpus_update() to prevent
recursive call of remote_cpus_update() on the same cpuset.

A test case is added to test_cpuset_prs.sh to verify this change.

Reported-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
Link: https://lore.kernel.org/lkml/20261010075947.333549-2-guopeng.zhang@linux.dev
Fixes: f62a5d39368e ("cgroup/cpuset: Remove remote_partition_check() & make update_cpumasks_hier() handle remote partition")
Signed-off-by: Waiman Long <longman@redhat.com>
---
 kernel/cgroup/cpuset-internal.h                   |  5 +++++
 kernel/cgroup/cpuset.c                            | 13 +++++++++----
 tools/testing/selftests/cgroup/test_cpuset_prs.sh |  1 +
 3 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/kernel/cgroup/cpuset-internal.h b/kernel/cgroup/cpuset-internal.h
index 2e44dc8634dc..1ba94ffaff9d 100644
--- a/kernel/cgroup/cpuset-internal.h
+++ b/kernel/cgroup/cpuset-internal.h
@@ -161,6 +161,11 @@ struct cpuset {
 	 */
 	bool remote_partition;
 
+	/*
+	 * Set to true when a remote partition is undergoing update.
+	 */
+	bool remote_partition_updating;
+
 	/*
 	 * number of SCHED_DEADLINE tasks attached to this cpuset, so that we
 	 * know when to rebuild associated root domain bandwidth information.
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 6e1bef12f86d..952b31246d62 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -1736,6 +1736,7 @@ static void remote_cpus_update(struct cpuset *cs, struct cpumask *xcpus,
 			goto invalidate;
 	}
 
+	cs->remote_partition_updating = true;
 	spin_lock_irq(&callback_lock);
 	if (adding)
 		partition_xcpus_add(prs, NULL, tmp->addmask);
@@ -1757,6 +1758,7 @@ static void remote_cpus_update(struct cpuset *cs, struct cpumask *xcpus,
 	 */
 	cpuset_update_tasks_cpumask(&top_cpuset, tmp->new_cpus);
 	update_sibling_cpumasks(&top_cpuset, NULL, tmp);
+	cs->remote_partition_updating = false;
 	return;
 
 invalidate:
@@ -2208,16 +2210,19 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp,
 		old_prs = new_prs = cp->partition_root_state;
 
 		/*
-		 * For child remote partition root (!= cs), we need to call
-		 * remote_cpus_update() if effective_xcpus will be changed.
-		 * Otherwise, we can skip the whole subtree.
+		 * For a child remote partition with remote_partition_updating
+		 * set, we can skip the whole subtree as the this function will
+		 * be called eventually. We can also skip the subtree if the
+		 * effective_xcpus isn't going to be changed. Otherwise, we
+		 * will have to call remote_cpus_update().
 		 *
 		 * remote_cpus_update() will reuse tmp->new_cpus only after
 		 * its value is being processed.
 		 */
 		if (remote && (cp != cs)) {
 			compute_excpus(cp, tmp->new_cpus);
-			if (cpumask_equal(cp->effective_xcpus, tmp->new_cpus)) {
+			if (cp->remote_partition_updating ||
+			    cpumask_equal(cp->effective_xcpus, tmp->new_cpus)) {
 				pos_css = css_rightmost_descendant(pos_css);
 				continue;
 			}
diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
index 5bc144836bdf..19c50819065c 100755
--- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh
+++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
@@ -347,6 +347,7 @@ TEST_MATRIX=(
 	"   C0-3    C1-3  C2-3    C4    X2-3   X2-3  X2-3:P2 P2:C4-5 0 A3:2-3|B1:4-5 A3:P2|B1:P2 2-5"
 	"  C4:X0-3  X1-3  X2-3     .      .      P2     .      .     0 A1:4|A2:1-3|A3:1-3 A2:P2 1-3"
 	"  C4:X0-3  X1-3  X2-3     .      .      .      P2     .     0 A1:4|A2:4|A3:2-3 A3:P2 2-3"
+	"   CX1-6  C1-4:P1  .    C4-5     .    C1-3     .      .     0 A1:4-6|A2:1-3|B1:4-5 A2:P1"
 
 	# Nested remote/local partition tests
 	"   C0-3    C1-3  C2-3   C4-5   X2-3  X2-3:P1   P2     P1    0 A1:0-1|A2:|A3:2-3|B1:4-5 \
-- 
2.55.0


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

* Re: [PATCH-next 1/6] cgroup/cpuset: Find furthest isolated ancestor for invalidated isolated partition
  2026-10-22  3:16 ` [PATCH-next 1/6] cgroup/cpuset: Find furthest isolated ancestor for invalidated isolated partition Waiman Long
@ 2026-10-22 13:25   ` Guopeng Zhang
  2026-10-22 16:19     ` Waiman Long
  0 siblings, 1 reply; 16+ messages in thread
From: Guopeng Zhang @ 2026-10-22 13:25 UTC (permalink / raw)
  To: Waiman Long, Ridong Chen, Tejun Heo, Johannes Weiner,
	Michal Koutný,
	Shuah Khan
  Cc: cgroups, linux-kernel, linux-kselftest



在 2026/10/22 11:16, Waiman Long 写道:
> Commit 46b885416c27 ("cgroup/cpuset: Fix a missing isolated_cpus
> update in update_cpumasks_hier()") searches for the closet partition
> root ancestor to determine if the isolated CPUs in a to be invalidated
> isolation partition should be removed from isolated_cpus or not.
> 
> As reported by sashiko, this method may not work when there is a deeply
> nested isolated partition hierarchy. For instance, Consider a nested
> hierarchy A0 -> A1 -> A2 -> A3 where all four are PRS_ISOLATED:
> 
>   A0: effective_xcpus = 0-4
>   A1: effective_xcpus = 1-4
>   A2: effective_xcpus = 2-4
>   A3: effective_xcpus = 3-4
> 
> When A1 shrinks its exclusive_cpus from 1-4 to 1-2, A2 will update it
> effective_xcpus to 2. A3 will find its closet partition root ancestor
> A2 and decides that its effective_xcpus 3-4 should be removed from
> isolated_cpus which is incorrect.
> 
> Address this corner case by searching for the furthest isolated partition
> root ancestor instead to decide if its isolated CPUs should be returned
> to isolated_cpus.
> 

This looks good to me. Would it be worth adding a test case for the
scenario described above, something like:

    # A middle isolated parent shrunk below coverage: the released
    # CPUs of the invalidated child stay isolated as a higher
    # ancestor still covers them.
    " CX0-4:P2 CX2-4:P2 CX3-4:P2 .      .      X2     .      .     0 A1:0-1,3-4|A2:2|A3:2 A1:P2|A2:P2|A3:P-2 0-4"

Reviewed-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
Tested-by: Guopeng Zhang <zhangguopeng@kylinos.cn>

Thanks,
Guopeng

> Fixes: 46b885416c27 ("cgroup/cpuset: Fix a missing isolated_cpus update in update_cpumasks_hier()")
> Signed-off-by: Waiman Long <longman@redhat.com>
> ---
>  kernel/cgroup/cpuset.c | 36 +++++++++++++++++-------------------
>  1 file changed, 17 insertions(+), 19 deletions(-)
> 
> diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
> index 585a982249ad..7ead8c3b7974 100644
> --- a/kernel/cgroup/cpuset.c
> +++ b/kernel/cgroup/cpuset.c
> @@ -2156,22 +2156,20 @@ static void compute_partition_effective_cpumask(struct cpuset *cs,
>  }
>  
>  /*
> - * ancestor_partition - Find and return the closest valid partition root ancestor
> + * iancestor_partition - Return furthest isolated partition root ancestor available
>   * @cs: the current cpuset
> - *
> - * Return: The closet partition root ancestor cpuset
> + * Return: The furthest isolated partition root ancestor available or NULL if
> + *	   not found.
>   */
> -static struct cpuset *ancestor_partition(struct cpuset *cs)
> +static struct cpuset *iancestor_partition(struct cpuset *cs)
>  {
>  	struct cpuset *ancestor = parent_cs(cs);
> +	struct cpuset *iancestor = NULL;
>  
> -	/*
> -	 * 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;
> +	for (; ancestor; ancestor = parent_cs(ancestor))
> +		if (ancestor->partition_root_state == PRS_ISOLATED)
> +			iancestor = ancestor;
> +	return iancestor;
>  }
>  
>  /*
> @@ -2283,23 +2281,23 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp,
>  				 * 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.
> +				 * there is a furthest isolated partition root
> +				 * ancestor available. When such a PRS_ISOLATED
> +				 * ancestor is available, 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 = -old_prs;
>  
>  				if (old_prs == PRS_ISOLATED) {
> -					struct cpuset *ancestor = ancestor_partition(cp);
> +					struct cpuset *iancestor = iancestor_partition(cp);
>  
> -					if (ancestor->partition_root_state == PRS_ROOT)
> +					if (!iancestor)
>  						del_cpus = cp->effective_xcpus;
>  					else if (cpumask_andnot(tmp->delmask,
>  								cp->effective_xcpus,
> -								ancestor->effective_xcpus))
> +								iancestor->effective_xcpus))
>  						del_cpus = tmp->delmask;
>  
>  					if (del_cpus) {


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

* Re: [PATCH-next 2/6] cgroup/cpuset: Properly compute effective xcpus in update_parent_effective_cpumask()
  2026-10-22  3:16 ` [PATCH-next 2/6] cgroup/cpuset: Properly compute effective xcpus in update_parent_effective_cpumask() Waiman Long
@ 2026-10-22 13:45   ` Guopeng Zhang
  2026-10-22 14:47     ` Waiman Long
  2026-10-22 15:00     ` Waiman Long
  0 siblings, 2 replies; 16+ messages in thread
From: Guopeng Zhang @ 2026-10-22 13:45 UTC (permalink / raw)
  To: Waiman Long, Ridong Chen, Tejun Heo, Johannes Weiner,
	Michal Koutný,
	Shuah Khan
  Cc: cgroups, linux-kernel, linux-kselftest

Hi Longman,

在 2026/10/22 11:16, Waiman Long 写道:
> Since the introduction of cpuset.cpus.exclusive in commit
> e2ffe502ba45 ("cgroup/cpuset: Add cpuset.cpus.exclusive for v2"), a
> compute_effective_exclusive_cpumask() helper which is later renamed to
> compute_excpus() is added to compute the effective xcpus of a partition
> root. However update_parent_effective_cpumask() is not updated in all
> proper places to use the new helper to check if a given cpuset should
> remain a valid partition root. This can cause a cpuset to incorrectly
> remain a valid partition root even if no effective xcpus is left.
> 
> Fix that problem by using compute_excpus() to compute the effective xcpus
> into delmask in all cases except partcmd_disable and partcmd_invalidate
> and use it for tasks_nocpu_error() check as well as checking its
> emptiness. This enables us to catch invalid partition root more
> accurately in update_parent_effective_cpumask().
> 

I re-tested the repro from the link below on top of this series
(applied on cgroup/for-7.4-fixes), and it still fails:

  https://lore.kernel.org/all/20261010075947.333549-3-guopeng.zhang@linux.dev/

  cd /sys/fs/cgroup
  echo +cpuset > cgroup.subtree_control
  mkdir A
  echo 0-7 > A/cpuset.cpus
  echo 0-7 > A/cpuset.cpus.exclusive
  echo root > A/cpuset.cpus.partition
  cat A/cpuset.cpus.partition
  echo 1 > A/cpuset.cpus.exclusive
  cat A/cpuset.cpus.partition

The last command still shows "root invalid (Parent unable to distribute
cpu downstream)".

In this case compute_excpus() returns the stale user mask unchanged.
user_xcpus() is gone from update_parent_effective_cpumask(), but the
dependency just moved one level down: the new code calls
compute_excpus(cs, tmp->delmask), and its first line is

  cpumask_and(excpus, user_xcpus(cs), parent->effective_xcpus)

Here user_xcpus(cs) is cs->exclusive_cpus, which still holds the old
0-7 when compute_excpus() runs: update_exclusive_cpumask() publishes
cs->exclusive_cpus only after partition_cpus_change(). Nothing corrects
it either - the sibling trim is skipped as exclusive_cpus is non-empty,
and for a direct child of the root cpuset the intersection with
parent->effective_xcpus is a no-op. So the stale 0-7 mask still reaches
tasks_nocpu_error() and PERR_NOCPUS is set again. Please point it out
if I got the analysis wrong.

I have rebased my fix on top of this series and the partition recovers
correctly with it applied. Should the fix be folded into this patch,
or is there a better way to fix it? Happy to hear your thoughts.

Also, is the test case below worth adding here as well? Note that it
fails until the fix is in:

    # An invalid local partition that took all the CPUs from its
    # populated parent should recover after its cpuset.cpus.exclusive
    # list is changed to a valid one.
    "C0-7:X0-7:P1  .      .      .     X1      .      .      .     0 A1:1|XA1:1 A1:P1 ."

Thanks,
Guopeng

> Some test case are added to test_cpuset_prs.sh for invalidating a
> partition root due to its effective xcpus becoming empty as well as
> making sure that an invalid partition can only be revived when exclusive
> CPUs are available agin.
> 
> Fixes: e2ffe502ba45 ("cgroup/cpuset: Add cpuset.cpus.exclusive for v2")
> Signed-off-by: Waiman Long <longman@redhat.com>
> ---
>  kernel/cgroup/cpuset.c                        | 36 +++++++++----------
>  .../selftests/cgroup/test_cpuset_prs.sh       |  6 ++++
>  2 files changed, 22 insertions(+), 20 deletions(-)
> 
> diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
> index 7ead8c3b7974..db6e4663f4be 100644
> --- a/kernel/cgroup/cpuset.c
> +++ b/kernel/cgroup/cpuset.c
> @@ -1798,7 +1798,6 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
>  	int deleting;	/* Deleting cpus from parent's effective_cpus	*/
>  	int old_prs, new_prs;
>  	int part_error = PERR_NONE;	/* Partition error? */
> -	struct cpumask *xcpus = user_xcpus(cs);
>  	int parent_prs = parent->partition_root_state;
>  	bool nocpu;
>  
> @@ -1841,30 +1840,29 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
>  	if (!newmask && xcpus_empty(cs))
>  		return PERR_CPUSEMPTY;
>  
> -	nocpu = tasks_nocpu_error(parent, cs, xcpus);
> +	/*
> +	 * Except for partcmd_disable, use delmask to compute the current
> +	 * effective xcpus value and use it for tasks_nocpu_error check.
> +	 */
> +	if (cmd != partcmd_disable) {
> +		compute_excpus(cs, tmp->delmask);
> +		nocpu = tasks_nocpu_error(parent, cs, tmp->delmask);
> +	}
>  
>  	if ((cmd == partcmd_enable) || (cmd == partcmd_enablei)) {
> -		/*
> -		 * Need to call compute_excpus() in case
> -		 * exclusive_cpus not set. Sibling conflict should only happen
> -		 * if exclusive_cpus isn't set.
> -		 */
> -		xcpus = tmp->delmask;
> -		if (compute_excpus(cs, xcpus))
> -			WARN_ON_ONCE(!cpumask_empty(cs->exclusive_cpus));
>  		new_prs = (cmd == partcmd_enable) ? PRS_ROOT : PRS_ISOLATED;
>  
>  		/*
>  		 * Enabling partition root is not allowed if its
>  		 * effective_xcpus is empty.
>  		 */
> -		if (cpumask_empty(xcpus))
> +		if (cpumask_empty(tmp->delmask))
>  			return PERR_INVCPUS;
>  
> -		if (prstate_housekeeping_conflict(new_prs, parent_prs, xcpus, NULL))
> +		if (prstate_housekeeping_conflict(new_prs, parent_prs, tmp->delmask, NULL))
>  			return PERR_HKEEPING;
>  
> -		if (tasks_nocpu_error(parent, cs, xcpus))
> +		if (nocpu)
>  			return PERR_NOCPUS;
>  
>  		/*
> @@ -1876,9 +1874,8 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
>  		 *
>  		 * Warn if it is not the case.
>  		 */
> -		cpumask_and(tmp->new_cpus, xcpus, cpu_active_mask);
> +		cpumask_and(tmp->new_cpus, tmp->delmask, cpu_active_mask);
>  		WARN_ON_ONCE(!cpumask_subset(tmp->new_cpus, parent->effective_cpus));
> -
>  		deleting = true;
>  	} else if (cmd == partcmd_disable) {
>  		/*
> @@ -1973,7 +1970,7 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
>  		 * A partition error happens when parent has tasks and all
>  		 * its effective CPUs will have to be distributed out.
>  		 */
> -		if (nocpu) {
> +		if (nocpu || cpumask_empty(tmp->delmask)) {
>  			part_error = PERR_NOCPUS;
>  			if (is_partition_valid(cs))
>  				adding = cpumask_and(tmp->addmask,
> @@ -1986,8 +1983,7 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
>  				cpumask_copy(tmp->addmask, cs->effective_xcpus);
>  				adding = true;
>  			}
> -		} else if (is_partition_invalid(cs) && !cpumask_empty(xcpus) &&
> -			   cpumask_subset(xcpus, parent->effective_xcpus)) {
> +		} else if (is_partition_invalid(cs)) {
>  			struct cgroup_subsys_state *css;
>  			struct cpuset *child;
>  			bool exclusive = true;
> @@ -1998,7 +1994,7 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
>  			 * check.
>  			 */
>  			if (prstate_housekeeping_conflict(cs->partition_root_state,
> -							  parent_prs, xcpus, NULL)) {
> +							  parent_prs, tmp->delmask, NULL)) {
>  				part_error = PERR_HKEEPING;
>  				goto write_error;
>  			}
> @@ -2014,7 +2010,7 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
>  			rcu_read_unlock();
>  			if (exclusive)
>  				deleting = cpumask_and(tmp->delmask,
> -						xcpus, parent->effective_cpus);
> +						tmp->delmask, parent->effective_cpus);
>  			else
>  				part_error = PERR_NOTEXCL;
>  		}
> diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
> index d04aad697b96..47791591002f 100755
> --- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh
> +++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
> @@ -359,6 +359,8 @@ TEST_MATRIX=(
>  								       A1:P0|A2:P1|A3:P2|B1:P1 2-4|3"
>  	"  C1-6:P1 C3-6:P1 C5-6:P1 .      .      P2      .      .    0 A1:1-2|A2:3-6|A3:5-6 \
>  								       A1:P1|A2:P2|A3:P-1 3-6"
> +	"  C1-6:P2 C3-6:P2 C3-4:P2 .      .     C5-6     .      .    0 A1:1-4|A2:5-6|A3:5-6 \
> +								       A1:P2|A2:P2|A3:P-2 1-6"
>  	" 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 ."
> @@ -427,6 +429,10 @@ TEST_MATRIX=(
>  	# cpuset.cpus is allowed, but those extra CPUs are ignored.
>  	"  C2-3:P1   C3:P1  .      .      .     C2-4    .      .     0 A1:|A2:2-3 A1:P1|A2:P1"
>  
> +	# A child cannot recover until its exclusive CPUs are available again.
> +	" CX1-4:P1 CX3-4:P1 .     .     X1-2     .      .      .     0 A1:1-2|A2:1-2|XA2: A1:P1|A2:P-1"
> +	" CX1-4:P1 CX3-4:P1 .     .  X1-2:X1-4   .      .      .     0 A1:1-2|A2:3-4|XA2:3-4 A1:P1|A2:P1"
> +
>  	# Taking away all CPUs from parent or itself if there are tasks
>  	# will make the partition invalid.
>  	"  C2-3:P1   C3:P1  .      .      T     C2-3    .      .     0 A1:2-3|A2:2-3 A1:P1|A2:P-1"


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

* Re: [PATCH-next 5/6] selftests/cgroup: Check for a single range nohz_full CPUs before running test matrix
  2026-10-22  3:16 ` [PATCH-next 5/6] selftests/cgroup: Check for a single range nohz_full CPUs before running test matrix Waiman Long
@ 2026-10-22 14:09   ` Guopeng Zhang
  0 siblings, 0 replies; 16+ messages in thread
From: Guopeng Zhang @ 2026-10-22 14:09 UTC (permalink / raw)
  To: Waiman Long, Ridong Chen, Tejun Heo, Johannes Weiner,
	Michal Koutný,
	Shuah Khan
  Cc: cgroups, linux-kernel, linux-kselftest



在 2026/10/22 11:16, Waiman Long 写道:
> Commit 989ca25c10ca ("selftests/cgroup: Add tests for nohz_full
> housekeeping check") adds a nohz_full test matrix that will only be run
> when a nohz_full boot parameter cover all the CPUs beyond CPUs 0-7. The
> code looks for the first and last CPU numbers in the nohz_full sysfs
> file to determine if that criterion is met. However if there are holes in
> the range (i.e. has ",") the test matrix may be incorrectly run leading
> to unexpected test failure. Fix that by skipping "," and anything after
> that to make sure the first range will cover all the remaining CPUs.
> 
> Fixes: 989ca25c10ca ("selftests/cgroup: Add tests for nohz_full housekeeping check")
> Signed-off-by: Waiman Long <longman@redhat.com>
> ---
>  tools/testing/selftests/cgroup/test_cpuset_prs.sh | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
> index 8595b6b4b7bf..5bc144836bdf 100755
> --- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh
> +++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
> @@ -111,9 +111,9 @@ echo "" > test/cpuset.cpus
>  #
>  # If nohz_full CPUs have been reserved at boot time, they should not include
>  # CPUs 0-7 as that may fail some of the test cases. On the other hand if the
> -# set of nohz_full CPUs includes all the CPUs except 0-7, we can run a special
> -# set of housekeeping CPUs exhaustion tests to see if the cpuset code will
> -# reject them.
> +# set of nohz_full CPUs includes all the CPUs except 0-7 in a single range
> +# <first>-<last>, we can run a special set of housekeeping CPUs exhaustion
> +# tests to see if the cpuset code will reject them.
>  #
>  FIRST_NOHZ_FULL_CPU=
>  LAST_NOHZ_FULL_CPU=
> @@ -124,7 +124,7 @@ NOHZ_FULL_CPUS=
>  LAST_PRESENT_CPU=$(cat /sys/devices/system/cpu/present | sed -e "s/.*[,-]//")
>  [[ -n "$NOHZ_FULL_CPUS" ]] && {
>  	FIRST_NOHZ_FULL_CPU=$(echo $NOHZ_FULL_CPUS | sed -e "s/[,-].*//")
> -	LAST_NOHZ_FULL_CPU=$(echo $NOHZ_FULL_CPUS | sed -e "s/.*[,-]//")
> +	LAST_NOHZ_FULL_CPU=$(echo $NOHZ_FULL_CPUS | sed -e "s/,.*//;s/.*[-]//")
>  	echo "Boot nohz_full CPUs: $NOHZ_FULL_CPUS"
>  }
>  [[ -n "$FIRST_NOHZ_FULL_CPU" && "$FIRST_NOHZ_FULL_CPU" -le 7 ]] &&

Reviewed-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
Tested-by: Guopeng Zhang <zhangguopeng@kylinos.cn>

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

* Re: [PATCH-next 4/6] cgroup/cpuset: Minor fixes to prstate_housekeeping_conflict()
  2026-10-22  3:16 ` [PATCH-next 4/6] cgroup/cpuset: Minor fixes to prstate_housekeeping_conflict() Waiman Long
@ 2026-10-22 14:15   ` Guopeng Zhang
  2026-10-22 14:35     ` Waiman Long
  0 siblings, 1 reply; 16+ messages in thread
From: Guopeng Zhang @ 2026-10-22 14:15 UTC (permalink / raw)
  To: Waiman Long, Ridong Chen, Tejun Heo, Johannes Weiner,
	Michal Koutný,
	Shuah Khan
  Cc: cgroups, linux-kernel, linux-kselftest



在 2026/10/22 11:16, Waiman Long 写道:
> Commit 9527ff78a413 ("group/cpuset: Consider all the exclusive CPUs when
> doing housekeeping check") changes the way prstate_housekeeping_conflict()
> is being used by considering all the exclusive xcpus to be owned by the
> partition when doing housekeeping check. However there are two minor
> issues reported by sashiko with that patch:
> 
>  1) In partition_cpus_change(), prstate_housekeeping_conflict() can
>  be called with an invalid partition root. In that case, there are
>  no isolated CPUs that are going to be returned back to the system to
>  become housekeeping CPUs, so the calculation of the del_cpus cpumask
>  is meaningless.
> 
>  2) The checking of del_cpus in prstate_housekeeping_conflict() to see
>  if it can contain an active housekeeping CPU that can be returned to the
>  system ignores the fact that an active CPU not in HK_TYPE_DOMAIN_BOOT HK
>  cpumask will not become an active housekeeping CPU when it is released
>  by an isolated partition.
> 
> Update the existing code to handle these two issues properly to make
> prstate_housekeeping_conflict() produce more accurate result.
> 
> Fixes: 9527ff78a413 ("group/cpuset: Consider all the exclusive CPUs when doing housekeeping check")

One trivial nit: the commit message says "group/cpuset" (missing 'c') in
two places, including the Fixes: line.

Thanks,
Guopeng


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

* Re: [PATCH-next 6/6] cgroup/cpuset: Prevent recursive call of remote_cpus_update() via update_cpumasks_hier()
  2026-10-22  3:16 ` [PATCH-next 6/6] cgroup/cpuset: Prevent recursive call of remote_cpus_update() via update_cpumasks_hier() Waiman Long
@ 2026-10-22 14:23   ` Guopeng Zhang
  0 siblings, 0 replies; 16+ messages in thread
From: Guopeng Zhang @ 2026-10-22 14:23 UTC (permalink / raw)
  To: Waiman Long, Ridong Chen, Tejun Heo, Johannes Weiner,
	Michal Koutný,
	Shuah Khan
  Cc: cgroups, linux-kernel, linux-kselftest, Guopeng Zhang



在 2026/10/22 11:16, Waiman Long 写道:
> Guopeng reports that changing the cpumask of a remote partition root
> may set the effective_cpus of the top_cpuset incorrectly. It is
> due to the following call sequence:
> 
>   update_cpumask()
>    -> partition_cpus_change()
>     -> remote_cpus_update()
>      -> update_sibling_cpumasks()
>       -> update_cpumasks_hier()
>        -> remote_cpus_update()
> 
> The second remote_cpus_update() call passes in the cs->effective_xcpus
> instead of the trialcs->effective_xcpus of the first remote_cpus_update()
> call.  As a result, the second call can revert what has been done in
> the first call leading to incorrect effective_cpus of the top_cpuset
> as well as subpartitions_cpus.
> 
> Fix that by adding a new remote_partition_updating flag into the cpuset
> structure to indicate that a remote partition is being updated and
> update_cpumasks_hier() should skip the whole subtree as update_cpumask()
> or update_exclusive_cpumask() which calls partition_cpus_change()
> will eventually calls update_cpumasks_hier() for that subtree anyway.
> 
> This new flag is currently set only in remote_cpus_update() to prevent
> recursive call of remote_cpus_update() on the same cpuset.
> 
> A test case is added to test_cpuset_prs.sh to verify this change.
> 
> Reported-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
> Link: https://lore.kernel.org/lkml/20261010075947.333549-2-guopeng.zhang@linux.dev
> Fixes: f62a5d39368e ("cgroup/cpuset: Remove remote_partition_check() & make update_cpumasks_hier() handle remote partition")
> Signed-off-by: Waiman Long <longman@redhat.com>
> ---
>  kernel/cgroup/cpuset-internal.h                   |  5 +++++
>  kernel/cgroup/cpuset.c                            | 13 +++++++++----
>  tools/testing/selftests/cgroup/test_cpuset_prs.sh |  1 +
>  3 files changed, 15 insertions(+), 4 deletions(-)
> 
> diff --git a/kernel/cgroup/cpuset-internal.h b/kernel/cgroup/cpuset-internal.h
> index 2e44dc8634dc..1ba94ffaff9d 100644
> --- a/kernel/cgroup/cpuset-internal.h
> +++ b/kernel/cgroup/cpuset-internal.h
> @@ -161,6 +161,11 @@ struct cpuset {
>  	 */
>  	bool remote_partition;
>  
> +	/*
> +	 * Set to true when a remote partition is undergoing update.
> +	 */
> +	bool remote_partition_updating;
> +
>  	/*
>  	 * number of SCHED_DEADLINE tasks attached to this cpuset, so that we
>  	 * know when to rebuild associated root domain bandwidth information.
> diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
> index 6e1bef12f86d..952b31246d62 100644
> --- a/kernel/cgroup/cpuset.c
> +++ b/kernel/cgroup/cpuset.c
> @@ -1736,6 +1736,7 @@ static void remote_cpus_update(struct cpuset *cs, struct cpumask *xcpus,
>  			goto invalidate;
>  	}
>  
> +	cs->remote_partition_updating = true;
>  	spin_lock_irq(&callback_lock);
>  	if (adding)
>  		partition_xcpus_add(prs, NULL, tmp->addmask);
> @@ -1757,6 +1758,7 @@ static void remote_cpus_update(struct cpuset *cs, struct cpumask *xcpus,
>  	 */
>  	cpuset_update_tasks_cpumask(&top_cpuset, tmp->new_cpus);
>  	update_sibling_cpumasks(&top_cpuset, NULL, tmp);
> +	cs->remote_partition_updating = false;
>  	return;
>  
>  invalidate:
> @@ -2208,16 +2210,19 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp,
>  		old_prs = new_prs = cp->partition_root_state;
>  
>  		/*
> -		 * For child remote partition root (!= cs), we need to call
> -		 * remote_cpus_update() if effective_xcpus will be changed.
> -		 * Otherwise, we can skip the whole subtree.
> +		 * For a child remote partition with remote_partition_updating
> +		 * set, we can skip the whole subtree as the this function will
> +		 * be called eventually. We can also skip the subtree if the
> +		 * effective_xcpus isn't going to be changed. Otherwise, we
> +		 * will have to call remote_cpus_update().
>  		 *
>  		 * remote_cpus_update() will reuse tmp->new_cpus only after
>  		 * its value is being processed.
>  		 */
>  		if (remote && (cp != cs)) {
>  			compute_excpus(cp, tmp->new_cpus);
> -			if (cpumask_equal(cp->effective_xcpus, tmp->new_cpus)) {
> +			if (cp->remote_partition_updating ||
> +			    cpumask_equal(cp->effective_xcpus, tmp->new_cpus)) {
>  				pos_css = css_rightmost_descendant(pos_css);
>  				continue;
>  			}
> diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
> index 5bc144836bdf..19c50819065c 100755
> --- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh
> +++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
> @@ -347,6 +347,7 @@ TEST_MATRIX=(
>  	"   C0-3    C1-3  C2-3    C4    X2-3   X2-3  X2-3:P2 P2:C4-5 0 A3:2-3|B1:4-5 A3:P2|B1:P2 2-5"
>  	"  C4:X0-3  X1-3  X2-3     .      .      P2     .      .     0 A1:4|A2:1-3|A3:1-3 A2:P2 1-3"
>  	"  C4:X0-3  X1-3  X2-3     .      .      .      P2     .     0 A1:4|A2:4|A3:2-3 A3:P2 2-3"
> +	"   CX1-6  C1-4:P1  .    C4-5     .    C1-3     .      .     0 A1:4-6|A2:1-3|B1:4-5 A2:P1"
>  
>  	# Nested remote/local partition tests
>  	"   C0-3    C1-3  C2-3   C4-5   X2-3  X2-3:P1   P2     P1    0 A1:0-1|A2:|A3:2-3|B1:4-5 \

Reviewed-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
Tested-by: Guopeng Zhang <zhangguopeng@kylinos.cn>

Thanks,
Guopeng

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

* Re: [PATCH-next 4/6] cgroup/cpuset: Minor fixes to prstate_housekeeping_conflict()
  2026-10-22 14:15   ` Guopeng Zhang
@ 2026-10-22 14:35     ` Waiman Long
  0 siblings, 0 replies; 16+ messages in thread
From: Waiman Long @ 2026-10-22 14:35 UTC (permalink / raw)
  To: Guopeng Zhang, Ridong Chen, Tejun Heo, Johannes Weiner,
	Michal Koutný,
	Shuah Khan
  Cc: cgroups, linux-kernel, linux-kselftest


On 10/22/26 10:15 AM, Guopeng Zhang wrote:
>
> 在 2026/10/22 11:16, Waiman Long 写道:
>> Commit 9527ff78a413 ("group/cpuset: Consider all the exclusive CPUs when
>> doing housekeeping check") changes the way prstate_housekeeping_conflict()
>> is being used by considering all the exclusive xcpus to be owned by the
>> partition when doing housekeeping check. However there are two minor
>> issues reported by sashiko with that patch:
>>
>>   1) In partition_cpus_change(), prstate_housekeeping_conflict() can
>>   be called with an invalid partition root. In that case, there are
>>   no isolated CPUs that are going to be returned back to the system to
>>   become housekeeping CPUs, so the calculation of the del_cpus cpumask
>>   is meaningless.
>>
>>   2) The checking of del_cpus in prstate_housekeeping_conflict() to see
>>   if it can contain an active housekeeping CPU that can be returned to the
>>   system ignores the fact that an active CPU not in HK_TYPE_DOMAIN_BOOT HK
>>   cpumask will not become an active housekeeping CPU when it is released
>>   by an isolated partition.
>>
>> Update the existing code to handle these two issues properly to make
>> prstate_housekeeping_conflict() produce more accurate result.
>>
>> Fixes: 9527ff78a413 ("group/cpuset: Consider all the exclusive CPUs when doing housekeeping check")
> One trivial nit: the commit message says "group/cpuset" (missing 'c') in
> two places, including the Fixes: line.

Thanks for spotting the typos. It is caused by a cut & paste mistake. 
Will fix that.

Cheers,
Longman


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

* Re: [PATCH-next 2/6] cgroup/cpuset: Properly compute effective xcpus in update_parent_effective_cpumask()
  2026-10-22 13:45   ` Guopeng Zhang
@ 2026-10-22 14:47     ` Waiman Long
  2026-10-22 15:00     ` Waiman Long
  1 sibling, 0 replies; 16+ messages in thread
From: Waiman Long @ 2026-10-22 14:47 UTC (permalink / raw)
  To: Guopeng Zhang, Ridong Chen, Tejun Heo, Johannes Weiner,
	Michal Koutný,
	Shuah Khan
  Cc: cgroups, linux-kernel, linux-kselftest

On 10/22/26 9:45 AM, Guopeng Zhang wrote:
> Hi Longman,
>
> 在 2026/10/22 11:16, Waiman Long 写道:
>> Since the introduction of cpuset.cpus.exclusive in commit
>> e2ffe502ba45 ("cgroup/cpuset: Add cpuset.cpus.exclusive for v2"), a
>> compute_effective_exclusive_cpumask() helper which is later renamed to
>> compute_excpus() is added to compute the effective xcpus of a partition
>> root. However update_parent_effective_cpumask() is not updated in all
>> proper places to use the new helper to check if a given cpuset should
>> remain a valid partition root. This can cause a cpuset to incorrectly
>> remain a valid partition root even if no effective xcpus is left.
>>
>> Fix that problem by using compute_excpus() to compute the effective xcpus
>> into delmask in all cases except partcmd_disable and partcmd_invalidate
>> and use it for tasks_nocpu_error() check as well as checking its
>> emptiness. This enables us to catch invalid partition root more
>> accurately in update_parent_effective_cpumask().
>>
> I re-tested the repro from the link below on top of this series
> (applied on cgroup/for-7.4-fixes), and it still fails:
>
>    https://lore.kernel.org/all/20261010075947.333549-3-guopeng.zhang@linux.dev/
>
>    cd /sys/fs/cgroup
>    echo +cpuset > cgroup.subtree_control
>    mkdir A
>    echo 0-7 > A/cpuset.cpus
>    echo 0-7 > A/cpuset.cpus.exclusive
>    echo root > A/cpuset.cpus.partition
>    cat A/cpuset.cpus.partition
>    echo 1 > A/cpuset.cpus.exclusive
>    cat A/cpuset.cpus.partition
>
> The last command still shows "root invalid (Parent unable to distribute
> cpu downstream)".
>
> In this case compute_excpus() returns the stale user mask unchanged.
> user_xcpus() is gone from update_parent_effective_cpumask(), but the
> dependency just moved one level down: the new code calls
> compute_excpus(cs, tmp->delmask), and its first line is
>
>    cpumask_and(excpus, user_xcpus(cs), parent->effective_xcpus)
>
> Here user_xcpus(cs) is cs->exclusive_cpus, which still holds the old
> 0-7 when compute_excpus() runs: update_exclusive_cpumask() publishes
> cs->exclusive_cpus only after partition_cpus_change(). Nothing corrects
> it either - the sibling trim is skipped as exclusive_cpus is non-empty,
> and for a direct child of the root cpuset the intersection with
> parent->effective_xcpus is a no-op. So the stale 0-7 mask still reaches
> tasks_nocpu_error() and PERR_NOCPUS is set again. Please point it out
> if I got the analysis wrong.
>
> I have rebased my fix on top of this series and the partition recovers
> correctly with it applied. Should the fix be folded into this patch,
> or is there a better way to fix it? Happy to hear your thoughts.
OK, I will look into that again.
>
> Also, is the test case below worth adding here as well? Note that it
> fails until the fix is in:
>
>      # An invalid local partition that took all the CPUs from its
>      # populated parent should recover after its cpuset.cpus.exclusive
>      # list is changed to a valid one.
>      "C0-7:X0-7:P1  .      .      .     X1      .      .      .     0 A1:1|XA1:1 A1:P1 ."

This test case assumes that there are only 8 CPUs in the test system 
which may not be true in many cases. We need test case that will work no 
matter the system it is running on.

Cheers,
Longman

>
> Thanks,
> Guopeng
>
>> Some test case are added to test_cpuset_prs.sh for invalidating a
>> partition root due to its effective xcpus becoming empty as well as
>> making sure that an invalid partition can only be revived when exclusive
>> CPUs are available agin.
>>
>> Fixes: e2ffe502ba45 ("cgroup/cpuset: Add cpuset.cpus.exclusive for v2")
>> Signed-off-by: Waiman Long <longman@redhat.com>
>> ---
>>   kernel/cgroup/cpuset.c                        | 36 +++++++++----------
>>   .../selftests/cgroup/test_cpuset_prs.sh       |  6 ++++
>>   2 files changed, 22 insertions(+), 20 deletions(-)
>>
>> diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
>> index 7ead8c3b7974..db6e4663f4be 100644
>> --- a/kernel/cgroup/cpuset.c
>> +++ b/kernel/cgroup/cpuset.c
>> @@ -1798,7 +1798,6 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
>>   	int deleting;	/* Deleting cpus from parent's effective_cpus	*/
>>   	int old_prs, new_prs;
>>   	int part_error = PERR_NONE;	/* Partition error? */
>> -	struct cpumask *xcpus = user_xcpus(cs);
>>   	int parent_prs = parent->partition_root_state;
>>   	bool nocpu;
>>   
>> @@ -1841,30 +1840,29 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
>>   	if (!newmask && xcpus_empty(cs))
>>   		return PERR_CPUSEMPTY;
>>   
>> -	nocpu = tasks_nocpu_error(parent, cs, xcpus);
>> +	/*
>> +	 * Except for partcmd_disable, use delmask to compute the current
>> +	 * effective xcpus value and use it for tasks_nocpu_error check.
>> +	 */
>> +	if (cmd != partcmd_disable) {
>> +		compute_excpus(cs, tmp->delmask);
>> +		nocpu = tasks_nocpu_error(parent, cs, tmp->delmask);
>> +	}
>>   
>>   	if ((cmd == partcmd_enable) || (cmd == partcmd_enablei)) {
>> -		/*
>> -		 * Need to call compute_excpus() in case
>> -		 * exclusive_cpus not set. Sibling conflict should only happen
>> -		 * if exclusive_cpus isn't set.
>> -		 */
>> -		xcpus = tmp->delmask;
>> -		if (compute_excpus(cs, xcpus))
>> -			WARN_ON_ONCE(!cpumask_empty(cs->exclusive_cpus));
>>   		new_prs = (cmd == partcmd_enable) ? PRS_ROOT : PRS_ISOLATED;
>>   
>>   		/*
>>   		 * Enabling partition root is not allowed if its
>>   		 * effective_xcpus is empty.
>>   		 */
>> -		if (cpumask_empty(xcpus))
>> +		if (cpumask_empty(tmp->delmask))
>>   			return PERR_INVCPUS;
>>   
>> -		if (prstate_housekeeping_conflict(new_prs, parent_prs, xcpus, NULL))
>> +		if (prstate_housekeeping_conflict(new_prs, parent_prs, tmp->delmask, NULL))
>>   			return PERR_HKEEPING;
>>   
>> -		if (tasks_nocpu_error(parent, cs, xcpus))
>> +		if (nocpu)
>>   			return PERR_NOCPUS;
>>   
>>   		/*
>> @@ -1876,9 +1874,8 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
>>   		 *
>>   		 * Warn if it is not the case.
>>   		 */
>> -		cpumask_and(tmp->new_cpus, xcpus, cpu_active_mask);
>> +		cpumask_and(tmp->new_cpus, tmp->delmask, cpu_active_mask);
>>   		WARN_ON_ONCE(!cpumask_subset(tmp->new_cpus, parent->effective_cpus));
>> -
>>   		deleting = true;
>>   	} else if (cmd == partcmd_disable) {
>>   		/*
>> @@ -1973,7 +1970,7 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
>>   		 * A partition error happens when parent has tasks and all
>>   		 * its effective CPUs will have to be distributed out.
>>   		 */
>> -		if (nocpu) {
>> +		if (nocpu || cpumask_empty(tmp->delmask)) {
>>   			part_error = PERR_NOCPUS;
>>   			if (is_partition_valid(cs))
>>   				adding = cpumask_and(tmp->addmask,
>> @@ -1986,8 +1983,7 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
>>   				cpumask_copy(tmp->addmask, cs->effective_xcpus);
>>   				adding = true;
>>   			}
>> -		} else if (is_partition_invalid(cs) && !cpumask_empty(xcpus) &&
>> -			   cpumask_subset(xcpus, parent->effective_xcpus)) {
>> +		} else if (is_partition_invalid(cs)) {
>>   			struct cgroup_subsys_state *css;
>>   			struct cpuset *child;
>>   			bool exclusive = true;
>> @@ -1998,7 +1994,7 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
>>   			 * check.
>>   			 */
>>   			if (prstate_housekeeping_conflict(cs->partition_root_state,
>> -							  parent_prs, xcpus, NULL)) {
>> +							  parent_prs, tmp->delmask, NULL)) {
>>   				part_error = PERR_HKEEPING;
>>   				goto write_error;
>>   			}
>> @@ -2014,7 +2010,7 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
>>   			rcu_read_unlock();
>>   			if (exclusive)
>>   				deleting = cpumask_and(tmp->delmask,
>> -						xcpus, parent->effective_cpus);
>> +						tmp->delmask, parent->effective_cpus);
>>   			else
>>   				part_error = PERR_NOTEXCL;
>>   		}
>> diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
>> index d04aad697b96..47791591002f 100755
>> --- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh
>> +++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
>> @@ -359,6 +359,8 @@ TEST_MATRIX=(
>>   								       A1:P0|A2:P1|A3:P2|B1:P1 2-4|3"
>>   	"  C1-6:P1 C3-6:P1 C5-6:P1 .      .      P2      .      .    0 A1:1-2|A2:3-6|A3:5-6 \
>>   								       A1:P1|A2:P2|A3:P-1 3-6"
>> +	"  C1-6:P2 C3-6:P2 C3-4:P2 .      .     C5-6     .      .    0 A1:1-4|A2:5-6|A3:5-6 \
>> +								       A1:P2|A2:P2|A3:P-2 1-6"
>>   	" 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 ."
>> @@ -427,6 +429,10 @@ TEST_MATRIX=(
>>   	# cpuset.cpus is allowed, but those extra CPUs are ignored.
>>   	"  C2-3:P1   C3:P1  .      .      .     C2-4    .      .     0 A1:|A2:2-3 A1:P1|A2:P1"
>>   
>> +	# A child cannot recover until its exclusive CPUs are available again.
>> +	" CX1-4:P1 CX3-4:P1 .     .     X1-2     .      .      .     0 A1:1-2|A2:1-2|XA2: A1:P1|A2:P-1"
>> +	" CX1-4:P1 CX3-4:P1 .     .  X1-2:X1-4   .      .      .     0 A1:1-2|A2:3-4|XA2:3-4 A1:P1|A2:P1"
>> +
>>   	# Taking away all CPUs from parent or itself if there are tasks
>>   	# will make the partition invalid.
>>   	"  C2-3:P1   C3:P1  .      .      T     C2-3    .      .     0 A1:2-3|A2:2-3 A1:P1|A2:P-1"


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

* Re: [PATCH-next 2/6] cgroup/cpuset: Properly compute effective xcpus in update_parent_effective_cpumask()
  2026-10-22 13:45   ` Guopeng Zhang
  2026-10-22 14:47     ` Waiman Long
@ 2026-10-22 15:00     ` Waiman Long
  1 sibling, 0 replies; 16+ messages in thread
From: Waiman Long @ 2026-10-22 15:00 UTC (permalink / raw)
  To: Guopeng Zhang, Ridong Chen, Tejun Heo, Johannes Weiner,
	Michal Koutný,
	Shuah Khan
  Cc: cgroups, linux-kernel, linux-kselftest


On 10/22/26 9:45 AM, Guopeng Zhang wrote:
> Hi Longman,
>
> 在 2026/10/22 11:16, Waiman Long 写道:
>> Since the introduction of cpuset.cpus.exclusive in commit
>> e2ffe502ba45 ("cgroup/cpuset: Add cpuset.cpus.exclusive for v2"), a
>> compute_effective_exclusive_cpumask() helper which is later renamed to
>> compute_excpus() is added to compute the effective xcpus of a partition
>> root. However update_parent_effective_cpumask() is not updated in all
>> proper places to use the new helper to check if a given cpuset should
>> remain a valid partition root. This can cause a cpuset to incorrectly
>> remain a valid partition root even if no effective xcpus is left.
>>
>> Fix that problem by using compute_excpus() to compute the effective xcpus
>> into delmask in all cases except partcmd_disable and partcmd_invalidate
>> and use it for tasks_nocpu_error() check as well as checking its
>> emptiness. This enables us to catch invalid partition root more
>> accurately in update_parent_effective_cpumask().
>>
> I re-tested the repro from the link below on top of this series
> (applied on cgroup/for-7.4-fixes), and it still fails:
>
>    https://lore.kernel.org/all/20261010075947.333549-3-guopeng.zhang@linux.dev/
>
>    cd /sys/fs/cgroup
>    echo +cpuset > cgroup.subtree_control
>    mkdir A
>    echo 0-7 > A/cpuset.cpus
>    echo 0-7 > A/cpuset.cpus.exclusive
>    echo root > A/cpuset.cpus.partition
>    cat A/cpuset.cpus.partition
>    echo 1 > A/cpuset.cpus.exclusive
>    cat A/cpuset.cpus.partition
>
> The last command still shows "root invalid (Parent unable to distribute
> cpu downstream)".
>
> In this case compute_excpus() returns the stale user mask unchanged.
> user_xcpus() is gone from update_parent_effective_cpumask(), but the
> dependency just moved one level down: the new code calls
> compute_excpus(cs, tmp->delmask), and its first line is
>
>    cpumask_and(excpus, user_xcpus(cs), parent->effective_xcpus)
>
> Here user_xcpus(cs) is cs->exclusive_cpus, which still holds the old
> 0-7 when compute_excpus() runs: update_exclusive_cpumask() publishes
> cs->exclusive_cpus only after partition_cpus_change(). Nothing corrects
> it either - the sibling trim is skipped as exclusive_cpus is non-empty,
> and for a direct child of the root cpuset the intersection with
> parent->effective_xcpus is a no-op. So the stale 0-7 mask still reaches
> tasks_nocpu_error() and PERR_NOCPUS is set again. Please point it out
> if I got the analysis wrong.
>
> I have rebased my fix on top of this series and the partition recovers
> correctly with it applied. Should the fix be folded into this patch,
> or is there a better way to fix it? Happy to hear your thoughts.

You are right. My patch series won't fix this particular issue. However, 
converting an invalid partition back to a valid one is done on a best 
effort basis. There is no guarantee that it will always happen. Just 
echo "root" to "cpuset.cpus.partition" again will make it valid again. 
So it is not a real bug from my point of view. It is just a nice to have 
feature.

Cheers,
Longman

> Also, is the test case below worth adding here as well? Note that it
> fails until the fix is in:
>
>      # An invalid local partition that took all the CPUs from its
>      # populated parent should recover after its cpuset.cpus.exclusive
>      # list is changed to a valid one.
>      "C0-7:X0-7:P1  .      .      .     X1      .      .      .     0 A1:1|XA1:1 A1:P1 ."
>
> Thanks,
> Guopeng
>
>> Some test case are added to test_cpuset_prs.sh for invalidating a
>> partition root due to its effective xcpus becoming empty as well as
>> making sure that an invalid partition can only be revived when exclusive
>> CPUs are available agin.
>>
>> Fixes: e2ffe502ba45 ("cgroup/cpuset: Add cpuset.cpus.exclusive for v2")
>> Signed-off-by: Waiman Long <longman@redhat.com>
>> ---
>>   kernel/cgroup/cpuset.c                        | 36 +++++++++----------
>>   .../selftests/cgroup/test_cpuset_prs.sh       |  6 ++++
>>   2 files changed, 22 insertions(+), 20 deletions(-)
>>
>> diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
>> index 7ead8c3b7974..db6e4663f4be 100644
>> --- a/kernel/cgroup/cpuset.c
>> +++ b/kernel/cgroup/cpuset.c
>> @@ -1798,7 +1798,6 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
>>   	int deleting;	/* Deleting cpus from parent's effective_cpus	*/
>>   	int old_prs, new_prs;
>>   	int part_error = PERR_NONE;	/* Partition error? */
>> -	struct cpumask *xcpus = user_xcpus(cs);
>>   	int parent_prs = parent->partition_root_state;
>>   	bool nocpu;
>>   
>> @@ -1841,30 +1840,29 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
>>   	if (!newmask && xcpus_empty(cs))
>>   		return PERR_CPUSEMPTY;
>>   
>> -	nocpu = tasks_nocpu_error(parent, cs, xcpus);
>> +	/*
>> +	 * Except for partcmd_disable, use delmask to compute the current
>> +	 * effective xcpus value and use it for tasks_nocpu_error check.
>> +	 */
>> +	if (cmd != partcmd_disable) {
>> +		compute_excpus(cs, tmp->delmask);
>> +		nocpu = tasks_nocpu_error(parent, cs, tmp->delmask);
>> +	}
>>   
>>   	if ((cmd == partcmd_enable) || (cmd == partcmd_enablei)) {
>> -		/*
>> -		 * Need to call compute_excpus() in case
>> -		 * exclusive_cpus not set. Sibling conflict should only happen
>> -		 * if exclusive_cpus isn't set.
>> -		 */
>> -		xcpus = tmp->delmask;
>> -		if (compute_excpus(cs, xcpus))
>> -			WARN_ON_ONCE(!cpumask_empty(cs->exclusive_cpus));
>>   		new_prs = (cmd == partcmd_enable) ? PRS_ROOT : PRS_ISOLATED;
>>   
>>   		/*
>>   		 * Enabling partition root is not allowed if its
>>   		 * effective_xcpus is empty.
>>   		 */
>> -		if (cpumask_empty(xcpus))
>> +		if (cpumask_empty(tmp->delmask))
>>   			return PERR_INVCPUS;
>>   
>> -		if (prstate_housekeeping_conflict(new_prs, parent_prs, xcpus, NULL))
>> +		if (prstate_housekeeping_conflict(new_prs, parent_prs, tmp->delmask, NULL))
>>   			return PERR_HKEEPING;
>>   
>> -		if (tasks_nocpu_error(parent, cs, xcpus))
>> +		if (nocpu)
>>   			return PERR_NOCPUS;
>>   
>>   		/*
>> @@ -1876,9 +1874,8 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
>>   		 *
>>   		 * Warn if it is not the case.
>>   		 */
>> -		cpumask_and(tmp->new_cpus, xcpus, cpu_active_mask);
>> +		cpumask_and(tmp->new_cpus, tmp->delmask, cpu_active_mask);
>>   		WARN_ON_ONCE(!cpumask_subset(tmp->new_cpus, parent->effective_cpus));
>> -
>>   		deleting = true;
>>   	} else if (cmd == partcmd_disable) {
>>   		/*
>> @@ -1973,7 +1970,7 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
>>   		 * A partition error happens when parent has tasks and all
>>   		 * its effective CPUs will have to be distributed out.
>>   		 */
>> -		if (nocpu) {
>> +		if (nocpu || cpumask_empty(tmp->delmask)) {
>>   			part_error = PERR_NOCPUS;
>>   			if (is_partition_valid(cs))
>>   				adding = cpumask_and(tmp->addmask,
>> @@ -1986,8 +1983,7 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
>>   				cpumask_copy(tmp->addmask, cs->effective_xcpus);
>>   				adding = true;
>>   			}
>> -		} else if (is_partition_invalid(cs) && !cpumask_empty(xcpus) &&
>> -			   cpumask_subset(xcpus, parent->effective_xcpus)) {
>> +		} else if (is_partition_invalid(cs)) {
>>   			struct cgroup_subsys_state *css;
>>   			struct cpuset *child;
>>   			bool exclusive = true;
>> @@ -1998,7 +1994,7 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
>>   			 * check.
>>   			 */
>>   			if (prstate_housekeeping_conflict(cs->partition_root_state,
>> -							  parent_prs, xcpus, NULL)) {
>> +							  parent_prs, tmp->delmask, NULL)) {
>>   				part_error = PERR_HKEEPING;
>>   				goto write_error;
>>   			}
>> @@ -2014,7 +2010,7 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
>>   			rcu_read_unlock();
>>   			if (exclusive)
>>   				deleting = cpumask_and(tmp->delmask,
>> -						xcpus, parent->effective_cpus);
>> +						tmp->delmask, parent->effective_cpus);
>>   			else
>>   				part_error = PERR_NOTEXCL;
>>   		}
>> diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
>> index d04aad697b96..47791591002f 100755
>> --- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh
>> +++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
>> @@ -359,6 +359,8 @@ TEST_MATRIX=(
>>   								       A1:P0|A2:P1|A3:P2|B1:P1 2-4|3"
>>   	"  C1-6:P1 C3-6:P1 C5-6:P1 .      .      P2      .      .    0 A1:1-2|A2:3-6|A3:5-6 \
>>   								       A1:P1|A2:P2|A3:P-1 3-6"
>> +	"  C1-6:P2 C3-6:P2 C3-4:P2 .      .     C5-6     .      .    0 A1:1-4|A2:5-6|A3:5-6 \
>> +								       A1:P2|A2:P2|A3:P-2 1-6"
>>   	" 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 ."
>> @@ -427,6 +429,10 @@ TEST_MATRIX=(
>>   	# cpuset.cpus is allowed, but those extra CPUs are ignored.
>>   	"  C2-3:P1   C3:P1  .      .      .     C2-4    .      .     0 A1:|A2:2-3 A1:P1|A2:P1"
>>   
>> +	# A child cannot recover until its exclusive CPUs are available again.
>> +	" CX1-4:P1 CX3-4:P1 .     .     X1-2     .      .      .     0 A1:1-2|A2:1-2|XA2: A1:P1|A2:P-1"
>> +	" CX1-4:P1 CX3-4:P1 .     .  X1-2:X1-4   .      .      .     0 A1:1-2|A2:3-4|XA2:3-4 A1:P1|A2:P1"
>> +
>>   	# Taking away all CPUs from parent or itself if there are tasks
>>   	# will make the partition invalid.
>>   	"  C2-3:P1   C3:P1  .      .      T     C2-3    .      .     0 A1:2-3|A2:2-3 A1:P1|A2:P-1"


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

* Re: [PATCH-next 1/6] cgroup/cpuset: Find furthest isolated ancestor for invalidated isolated partition
  2026-10-22 13:25   ` Guopeng Zhang
@ 2026-10-22 16:19     ` Waiman Long
  0 siblings, 0 replies; 16+ messages in thread
From: Waiman Long @ 2026-10-22 16:19 UTC (permalink / raw)
  To: Guopeng Zhang, Ridong Chen, Tejun Heo, Johannes Weiner,
	Michal Koutný,
	Shuah Khan
  Cc: cgroups, linux-kernel, linux-kselftest

On 10/22/26 9:25 AM, Guopeng Zhang wrote:
>
> 在 2026/10/22 11:16, Waiman Long 写道:
>> Commit 46b885416c27 ("cgroup/cpuset: Fix a missing isolated_cpus
>> update in update_cpumasks_hier()") searches for the closet partition
>> root ancestor to determine if the isolated CPUs in a to be invalidated
>> isolation partition should be removed from isolated_cpus or not.
>>
>> As reported by sashiko, this method may not work when there is a deeply
>> nested isolated partition hierarchy. For instance, Consider a nested
>> hierarchy A0 -> A1 -> A2 -> A3 where all four are PRS_ISOLATED:
>>
>>    A0: effective_xcpus = 0-4
>>    A1: effective_xcpus = 1-4
>>    A2: effective_xcpus = 2-4
>>    A3: effective_xcpus = 3-4
>>
>> When A1 shrinks its exclusive_cpus from 1-4 to 1-2, A2 will update it
>> effective_xcpus to 2. A3 will find its closet partition root ancestor
>> A2 and decides that its effective_xcpus 3-4 should be removed from
>> isolated_cpus which is incorrect.
>>
>> Address this corner case by searching for the furthest isolated partition
>> root ancestor instead to decide if its isolated CPUs should be returned
>> to isolated_cpus.
>>
> This looks good to me. Would it be worth adding a test case for the
> scenario described above, something like:
>
>      # A middle isolated parent shrunk below coverage: the released
>      # CPUs of the invalidated child stay isolated as a higher
>      # ancestor still covers them.
>      " CX0-4:P2 CX2-4:P2 CX3-4:P2 .      .      X2     .      .     0 A1:0-1,3-4|A2:2|A3:2 A1:P2|A2:P2|A3:P-2 0-4"
>
> Reviewed-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
> Tested-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
>
> Thanks,
> Guopeng

Thanks for the review. This patch fixes a specific problem reported by 
sashiko. However, there are other pre-existing problem that will still 
fail test case that you have proposed above. Patches 2 & 3 of this 
series are there to address the other existing problems so that test 
cases like what you have proposed above will work. The first test case 
added in patch 2 was to test this though it is somewhat different from 
yours. I don't add any test case to patch 1 because I don't want to 
break bisection. I can add your test case in patch 2 though.

Cheers,
Longman


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

end of thread, other threads:[~2026-10-22 16:19 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-22  3:16 [PATCH-next 0/6] cgroup/cpuset: Miscellaneous bug fixes Waiman Long
2026-10-22  3:16 ` [PATCH-next 1/6] cgroup/cpuset: Find furthest isolated ancestor for invalidated isolated partition Waiman Long
2026-10-22 13:25   ` Guopeng Zhang
2026-10-22 16:19     ` Waiman Long
2026-10-22  3:16 ` [PATCH-next 2/6] cgroup/cpuset: Properly compute effective xcpus in update_parent_effective_cpumask() Waiman Long
2026-10-22 13:45   ` Guopeng Zhang
2026-10-22 14:47     ` Waiman Long
2026-10-22 15:00     ` Waiman Long
2026-10-22  3:16 ` [PATCH-next 3/6] cgroup/cpuset: Fix incorrect effective_cpus bug in update_cpumasks_hier() Waiman Long
2026-10-22  3:16 ` [PATCH-next 4/6] cgroup/cpuset: Minor fixes to prstate_housekeeping_conflict() Waiman Long
2026-10-22 14:15   ` Guopeng Zhang
2026-10-22 14:35     ` Waiman Long
2026-10-22  3:16 ` [PATCH-next 5/6] selftests/cgroup: Check for a single range nohz_full CPUs before running test matrix Waiman Long
2026-10-22 14:09   ` Guopeng Zhang
2026-10-22  3:16 ` [PATCH-next 6/6] cgroup/cpuset: Prevent recursive call of remote_cpus_update() via update_cpumasks_hier() Waiman Long
2026-10-22 14:23   ` Guopeng Zhang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®