* [PATCH-next v2 0/5] More fix patches
@ 2026-11-09 19:09 Waiman Long
2026-11-09 19:09 ` [PATCH-next v2 1/5] selftests/cgroup: Fix "test_cpuset_prs.sh -v" failures Waiman Long
` (5 more replies)
0 siblings, 6 replies; 15+ messages in thread
From: Waiman Long @ 2026-11-09 19:09 UTC (permalink / raw)
To: Ridong Chen, Tejun Heo, Johannes Weiner, Michal Koutný, Shuah Khan
Cc: cgroups, linux-kernel, linux-kselftest, Guopeng Zhang, Waiman Long
[v2]
- Reorder the series by putting the original patch 4 before patch 2.
- Update the Fixes tags in patch 1 and 5 as suggested by sashiko.
- Update the new patch 3 to remove obsolete WARN_ON_ONCE() and update
comment as reported by sashiko.
- Minor fix to the test case in patch 5 as reported by sashiko.
This patch series contains an additional set of cpuset fix patches.
Waiman Long (5):
selftests/cgroup: Fix "test_cpuset_prs.sh -v" failures
cgroup/cpuset: Correctly set cpus_updated in
cpuset_hotplug_update_tasks()
cgroup/cpuset: Fix incorrect partition invalidation logic in
cpuset_hotplug_update_tasks()
cgroup/cpuset: Protect current->mems_allowed read in cpuset_fork()
cgroup/cpuset: Correctly set isolated_cpus when switching partition
state
kernel/cgroup/cpuset.c | 77 ++++++++++++-------
.../selftests/cgroup/test_cpuset_prs.sh | 20 +++--
2 files changed, 64 insertions(+), 33 deletions(-)
--
2.56.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH-next v2 1/5] selftests/cgroup: Fix "test_cpuset_prs.sh -v" failures
2026-11-09 19:09 [PATCH-next v2 0/5] More fix patches Waiman Long
@ 2026-11-09 19:09 ` Waiman Long
2026-11-10 7:56 ` Ridong Chen
2026-11-09 19:09 ` [PATCH-next v2 2/5] cgroup/cpuset: Correctly set cpus_updated in cpuset_hotplug_update_tasks() Waiman Long
` (4 subsequent siblings)
5 siblings, 1 reply; 15+ messages in thread
From: Waiman Long @ 2026-11-09 19:09 UTC (permalink / raw)
To: Ridong Chen, Tejun Heo, Johannes Weiner, Michal Koutný, Shuah Khan
Cc: cgroups, linux-kernel, linux-kselftest, Guopeng Zhang, Waiman Long
When the -v option is used to run test_cpuset_prs.sh, it activates the
use of sched-debug to determine the set of isolated CPUs which will
also consider 1-CPU partition as being isolated though they will not be
reflected in "cpuset.cpus.isolated". As a result, some of the expected
isolated CPUs values have 2 different set of values to correspond to
these two ways of determining isolated CPUs.
Commit 6e4834ba8986 ("cgroup/cpuset: Fix incorrect CPU accounting with
parent's effective_xcpus expansion") introduces some new test cases
which fail when the -v option is used. Update the test cases to make
them pass with the -v option as well.
Also remove an obsolete comment in update_parent_effective_cpumask()
of cpuset.c.
Reported-by: Tejun Heo <tj@kernel.org>
Link: https://lore.kernel.org/lkml/886a562b52b1c5094142d547a8336457@kernel.org
Fixes: 362212853cd0 ("cgroup/cpuset: Fix incorrect CPU accounting with parent's effective_xcpus expansion")
Signed-off-by: Waiman Long <longman@redhat.com>
---
kernel/cgroup/cpuset.c | 6 ------
tools/testing/selftests/cgroup/test_cpuset_prs.sh | 13 ++++++++-----
2 files changed, 8 insertions(+), 11 deletions(-)
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 85e5b529d144..6074327c3477 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -2164,12 +2164,6 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
else
part_error = PERR_NOTEXCL;
}
- /*
- * When both cs and parent remain valid, parent's
- * compute_partition_effective_cpumask() call would have removed
- * cs's effective_xcpus from the parent's effective_cpus. So
- * there is no need to adjust parent's effective_cpus here.
- */
}
write_error:
diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
index 32e1e44fa0b1..2d4744f2d6ac 100755
--- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh
+++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
@@ -540,16 +540,19 @@ TEST_MATRIX=(
# The extra CPUs gained by a child partition when its parent expands the
# exclusive CPUs have to be taken away from the parent.
- " C2-6:X2-5:P1 CX3-6:P1 \
- . . X2-6 . . . 0 A1:2|A2:3-6|XA2:3-6 A1:P1|A2:P1 ."
- " C2-6:X2-5:P1 CX3-6:P2 \
- . . X2-6 . . . 0 A1:2|A2:3-6|XA2:3-6 A1:P1|A2:P2 3-6"
+ " C2-6:X2-5:P1 CX4-6:P1 \
+ . . X2-6 . . . 0 A1:2-3|A2:4-6|XA2:4-6 \
+ A1:P1|A2:P1 ."
+ " C2-6:X2-5:P1 CX4-6:P2 \
+ . . X2-6 . . . 0 A1:2-3|A2:4-6|XA2:4-6 \
+ A1:P1|A2:P2 4-6"
# Both expansion and contraction of parent's effective_xcpus will be
# correctly handled in child partition and the child can be invalidated
# if a populated parent could lose all its effective_cpus.
" C2-6:X2-5:P1 CX3,5-6:P2 \
- . . X4-6 . . . 0 A1:4|A2:5-6|XA2:5-6 A1:P1|A2:P2 5-6"
+ . . X4-6 . . . 0 A1:4|A2:5-6|XA2:5-6 \
+ A1:P1|A2:P2 4-6|5-6"
" C2-6:X2-5:P1 CX3-6:P2 \
. . T:X4-6 . . . 0 A1:4-6|A2:4-6 A1:P1|A2:P-2 ."
--
2.56.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH-next v2 2/5] cgroup/cpuset: Correctly set cpus_updated in cpuset_hotplug_update_tasks()
2026-11-09 19:09 [PATCH-next v2 0/5] More fix patches Waiman Long
2026-11-09 19:09 ` [PATCH-next v2 1/5] selftests/cgroup: Fix "test_cpuset_prs.sh -v" failures Waiman Long
@ 2026-11-09 19:09 ` Waiman Long
2026-11-10 8:40 ` Ridong Chen
2026-11-09 19:09 ` [PATCH-next v2 3/5] cgroup/cpuset: Fix incorrect partition invalidation logic " Waiman Long
` (3 subsequent siblings)
5 siblings, 1 reply; 15+ messages in thread
From: Waiman Long @ 2026-11-09 19:09 UTC (permalink / raw)
To: Ridong Chen, Tejun Heo, Johannes Weiner, Michal Koutný, Shuah Khan
Cc: cgroups, linux-kernel, linux-kselftest, Guopeng Zhang,
Waiman Long, Sashiko
When cpuset_hotplug_update_tasks() is called with the conditions that
either remote_partition_disable() or update_parent_effective_cpumask()
has to be called, the cs->effective_cpus can be updated such that it
matches what is computed in new_cpus. In such case, cpus_updated can
be incorrectly set to false leading to stale CPU afinity remained in the
tasks not matching the new cpuset value. Fix that by forcing cpus_updated
to true whenever one of these partition helpers is being called.
Fixes: 4b842da276a8a ("cpuset: Make CPU hotplug work with partition")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Link: https://sashiko.dev/#/bug/linux-ab90f7e8-0d60-40ca-83e9-e405075b24d2
Signed-off-by: Waiman Long <longman@redhat.com>
---
kernel/cgroup/cpuset.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 6074327c3477..3955d2d574cf 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -4002,7 +4002,7 @@ static void cpuset_hotplug_update_tasks(struct cpuset *cs, struct tmpmasks *tmp)
{
static cpumask_t new_cpus;
static nodemask_t new_mems;
- bool cpus_updated;
+ bool cpus_updated = false;
bool mems_updated;
int partcmd = -1;
struct cpuset *parent;
@@ -4015,12 +4015,18 @@ static void cpuset_hotplug_update_tasks(struct cpuset *cs, struct tmpmasks *tmp)
if (!tmp || !cs->partition_root_state)
goto update_tasks;
+ /*
+ * cpus_updated should be set to true when remote_partition_disable()
+ * or update_parent_effective_cpumask() is called as cs->effective_cpus
+ * may have been updated.
+ */
if (is_remote_partition(cs) && (cpumask_empty(subpartitions_cpus) ||
(cpumask_empty(&new_cpus) &&
partition_is_populated(cs, NULL)))) {
WRITE_ONCE(cs->prs_err, PERR_HOTPLUG);
remote_partition_disable(cs, tmp);
compute_effective_cpumask(&new_cpus, cs, parent);
+ cpus_updated = true;
}
/*
@@ -4045,6 +4051,7 @@ static void cpuset_hotplug_update_tasks(struct cpuset *cs, struct tmpmasks *tmp)
partcmd = partcmd_update;
if (partcmd >= 0) {
+ cpus_updated = true;
update_parent_effective_cpumask(cs, partcmd, NULL, tmp);
if (is_partition_valid(cs) || (partcmd == partcmd_invalidate)) {
compute_effective_cpumask(&new_cpus, cs, parent);
@@ -4053,7 +4060,7 @@ static void cpuset_hotplug_update_tasks(struct cpuset *cs, struct tmpmasks *tmp)
}
update_tasks:
- cpus_updated = !cpumask_equal(&new_cpus, cs->effective_cpus);
+ cpus_updated |= !cpumask_equal(&new_cpus, cs->effective_cpus);
mems_updated = !nodes_equal(new_mems, cs->effective_mems);
if (!cpus_updated && !mems_updated)
goto unlock; /* Hotplug doesn't affect this cpuset */
--
2.56.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH-next v2 3/5] cgroup/cpuset: Fix incorrect partition invalidation logic in cpuset_hotplug_update_tasks()
2026-11-09 19:09 [PATCH-next v2 0/5] More fix patches Waiman Long
2026-11-09 19:09 ` [PATCH-next v2 1/5] selftests/cgroup: Fix "test_cpuset_prs.sh -v" failures Waiman Long
2026-11-09 19:09 ` [PATCH-next v2 2/5] cgroup/cpuset: Correctly set cpus_updated in cpuset_hotplug_update_tasks() Waiman Long
@ 2026-11-09 19:09 ` Waiman Long
2026-11-10 8:51 ` Ridong Chen
2026-11-09 19:09 ` [PATCH-next v2 4/5] cgroup/cpuset: Protect current->mems_allowed read in cpuset_fork() Waiman Long
` (2 subsequent siblings)
5 siblings, 1 reply; 15+ messages in thread
From: Waiman Long @ 2026-11-09 19:09 UTC (permalink / raw)
To: Ridong Chen, Tejun Heo, Johannes Weiner, Michal Koutný, Shuah Khan
Cc: cgroups, linux-kernel, linux-kselftest, Guopeng Zhang,
Waiman Long, Sashiko
When most of the active CPUs of a system are allocated to
sub-partitions below the top_cpuset partition, it is possible that a
CPU offline operation may remove the last active CPU in the top_cpuset
partition. When that really happens, cpuset_handle_hotplug() will clear
the subpartitions_cpus to make sure active CPUs are present in the top
partition and let the other sub-partitions get invalidated and then
competes for their exclusive CPUs again.
In cpuset_hotplug_update_tasks(), the current code use
"cpumask_empty(subpartitions_cpus)" to determine if that partition
should be invalidated. That is fine if there is only one sub-partition.
As reported by sashiko that when there are more than one sub-partitions
and the first sub-partition will get invalidated and then it will
try to acquire the exclusive CPUs and become valid again. When this
happens, the subpartitions_cpus will no longer be empty. The remaining
sub-partitions will assume their exclusive CPUs are safe and proceed
as normal. As a result, active CPUs owned by those sub-partitions
remain in both top_cpuset.effective_cpus and the sub-partitions'
effective_cpus while missing from subpartitions_cpus, breaking partition
CPU exclusivity and triggering WARN_ON_ONCE() in generate_sched_domains()
and remote_partition_disable().
Fix that by checking if the sub-partitions' effective_xcpus are subset
of subpartitions_cpus to determine if they should be invalidated. Also
remove the obsolete WARN_ON_ONCE() call in remote_partition_disable().
Fixes: 0c7f293efc87 ("cgroup/cpuset: Add cpuset.cpus.exclusive.effective for v2")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Link: https://sashiko.dev/#/bug/linux-bf69cd3c-833a-4599-a1f9-8dd9e044cd7c
Signed-off-by: Waiman Long <longman@redhat.com>
---
kernel/cgroup/cpuset.c | 19 +++++--------------
1 file changed, 5 insertions(+), 14 deletions(-)
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 3955d2d574cf..e9b84671af21 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -1766,15 +1766,6 @@ static int remote_partition_enable(struct cpuset *cs, int new_prs,
static void remote_partition_disable(struct cpuset *cs, struct tmpmasks *tmp)
{
WARN_ON_ONCE(!is_remote_partition(cs));
- /*
- * When a CPU is offlined, top_cpuset may end up with no available CPUs,
- * which should clear subpartitions_cpus. We should not emit a warning for this
- * scenario: the hierarchy is updated from top to bottom, so subpartitions_cpus
- * may already be cleared when disabling the partition.
- */
- WARN_ON_ONCE(!cpumask_subset(cs->effective_xcpus, subpartitions_cpus) &&
- !cpumask_empty(subpartitions_cpus));
-
spin_lock_irq(&callback_lock);
cs->remote_partition = false;
partition_xcpus_del(cs->partition_root_state, NULL, cs->effective_xcpus);
@@ -4020,9 +4011,9 @@ static void cpuset_hotplug_update_tasks(struct cpuset *cs, struct tmpmasks *tmp)
* or update_parent_effective_cpumask() is called as cs->effective_cpus
* may have been updated.
*/
- if (is_remote_partition(cs) && (cpumask_empty(subpartitions_cpus) ||
- (cpumask_empty(&new_cpus) &&
- partition_is_populated(cs, NULL)))) {
+ if (is_remote_partition(cs) &&
+ (!cpumask_subset(cs->effective_xcpus, subpartitions_cpus) ||
+ (cpumask_empty(&new_cpus) && partition_is_populated(cs, NULL)))) {
WRITE_ONCE(cs->prs_err, PERR_HOTPLUG);
remote_partition_disable(cs, tmp);
compute_effective_cpumask(&new_cpus, cs, parent);
@@ -4035,12 +4026,12 @@ static void cpuset_hotplug_update_tasks(struct cpuset *cs, struct tmpmasks *tmp)
* 1) empty effective cpus but not valid empty partition.
* 2) parent is invalid or doesn't grant any cpus to child
* partitions.
- * 3) subpartitions_cpus is empty.
+ * 3) effective_xcpus isn't a subset of subpartitions_cpus.
*/
if (is_local_partition(cs) &&
(!is_partition_valid(parent) ||
tasks_nocpu_error(parent, cs, &new_cpus) ||
- cpumask_empty(subpartitions_cpus)))
+ !cpumask_subset(cs->effective_xcpus, subpartitions_cpus)))
partcmd = partcmd_invalidate;
/*
* On the other hand, an invalid partition root may be transitioned
--
2.56.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH-next v2 4/5] cgroup/cpuset: Protect current->mems_allowed read in cpuset_fork()
2026-11-09 19:09 [PATCH-next v2 0/5] More fix patches Waiman Long
` (2 preceding siblings ...)
2026-11-09 19:09 ` [PATCH-next v2 3/5] cgroup/cpuset: Fix incorrect partition invalidation logic " Waiman Long
@ 2026-11-09 19:09 ` Waiman Long
2026-11-10 11:24 ` Ridong Chen
2026-11-09 19:09 ` [PATCH-next v2 5/5] cgroup/cpuset: Correctly set isolated_cpus when switching partition state Waiman Long
2026-11-10 19:27 ` [PATCH-next v2 0/5] More fix patches Tejun Heo
5 siblings, 1 reply; 15+ messages in thread
From: Waiman Long @ 2026-11-09 19:09 UTC (permalink / raw)
To: Ridong Chen, Tejun Heo, Johannes Weiner, Michal Koutný, Shuah Khan
Cc: cgroups, linux-kernel, linux-kselftest, Guopeng Zhang,
Waiman Long, Sashiko
Reading mems_allowed of the current task outside of cpuset_mutex critical
section should be protected by using mems_allowed_seq seqlock as the
nodemask can be updated concurrently leading to a torn read. Such
protection is currently not implemented in cpuset_fork() for the
!CLONE_INTO_CGROUP case. As a result, the child task may inherit an empty
or corrupted mems_allowed nodemask. This violates NUMA memory policy
constraints and causes subsequent page allocations to unconditionally
fail, potentially leading to crashes or spurious OOM killer invocations
for the child task.
Fix that by using a read_mems_allowed_begin/read_mems_allowed_retry()
loop to protect the mems_allowed read.
Fixes: 06f4e9489891 ("cpuset: make sure new tasks conform to the current config of the cpuset")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Link: https://sashiko.dev/#/bug/linux-601100b4-fa77-45fd-99f9-bfbd4385201f
Signed-off-by: Waiman Long <longman@redhat.com>
---
kernel/cgroup/cpuset.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index e9b84671af21..7aa614c6ac4d 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -3868,11 +3868,20 @@ static void cpuset_fork(struct task_struct *task)
rcu_read_unlock();
if (cs == oldcs) {
+ unsigned int seq;
+
if (cs == &top_cpuset)
return;
set_cpus_allowed_ptr(task, current->cpus_ptr);
- task->mems_allowed = current->mems_allowed;
+ /*
+ * A cpuset.mems update can update current->mems_allowed
+ * concurrently, so retry it again if it really happens.
+ */
+ do {
+ seq = read_mems_allowed_begin();
+ task->mems_allowed = current->mems_allowed;
+ } while (read_mems_allowed_retry(seq));
return;
}
--
2.56.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH-next v2 5/5] cgroup/cpuset: Correctly set isolated_cpus when switching partition state
2026-11-09 19:09 [PATCH-next v2 0/5] More fix patches Waiman Long
` (3 preceding siblings ...)
2026-11-09 19:09 ` [PATCH-next v2 4/5] cgroup/cpuset: Protect current->mems_allowed read in cpuset_fork() Waiman Long
@ 2026-11-09 19:09 ` Waiman Long
2026-11-10 2:23 ` Waiman Long
` (2 more replies)
2026-11-10 19:27 ` [PATCH-next v2 0/5] More fix patches Tejun Heo
5 siblings, 3 replies; 15+ messages in thread
From: Waiman Long @ 2026-11-09 19:09 UTC (permalink / raw)
To: Ridong Chen, Tejun Heo, Johannes Weiner, Michal Koutný, Shuah Khan
Cc: cgroups, linux-kernel, linux-kselftest, Guopeng Zhang, Waiman Long
When update_prstate() is called to switch the partition state from
root to isolated or vice versa, the whole effective_xcpus is passed to
isolated_cpus_update(). However, if there are child partitions present,
some of the effective_xcpus are dedicated to those child partitions
and their partition states will remain the same or get invalidated in
the case of child root partition with isolated parent in the latter
update_cpumasks_heir() call. In the latter case, their exclusive CPUs
will be returned to their parent.
Therefore isolated_cpus may be set incorrectly with child partitions
underneath. Fix that by excluding their exclusive CPUs in computing
the correct cpumask of exclusive CPUs used by that partition alone.
Add new test cases into test_cpuset_prs.sh to test for such cases.
Fixes: 11e5f407b64a ("cgroup/cpuset: Keep track of CPUs in isolated partitions")
Signed-off-by: Waiman Long <longman@redhat.com>
---
kernel/cgroup/cpuset.c | 30 +++++++++++++++----
.../selftests/cgroup/test_cpuset_prs.sh | 7 +++++
2 files changed, 32 insertions(+), 5 deletions(-)
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 7aa614c6ac4d..41048997a955 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -3054,12 +3054,32 @@ static int update_prstate(struct cpuset *cs, int new_prs)
cs->effective_xcpus, NULL))
err = PERR_HKEEPING;
else if (parent_prs == PRS_ISOLATED)
- err = PERR_ISOPARENT;
+ err = PERR_ISOPARENT; /* old_prs should be isolated */
- if (!err)
- isolcpus_updated = true;
- else
+ if (err) {
disable_partition = true;
+ } else {
+ struct cgroup_subsys_state *css;
+ struct cpuset *child;
+
+ /*
+ * Need to scan child partitions, if present, and
+ * exclude their effective_xcpus from cs. In the case
+ * of switching to isolated partition with child root
+ * partitions, those child partitions will be
+ * invalidated in update_cpumasks_hier().
+ */
+ isolcpus_updated = true;
+ cpumask_copy(tmpmask.new_cpus, cs->effective_xcpus);
+ rcu_read_lock();
+ cpuset_for_each_child(child, css, cs) {
+ if (!is_partition_valid(child))
+ continue;
+ cpumask_andnot(tmpmask.new_cpus, tmpmask.new_cpus,
+ child->effective_xcpus);
+ }
+ rcu_read_unlock();
+ }
} else {
/*
* Switching back to member is always allowed even if it
@@ -3093,7 +3113,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 partition is disabled & update effective_xcpus */
diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
index 2d4744f2d6ac..741a13bbeda7 100755
--- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh
+++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
@@ -556,6 +556,13 @@ TEST_MATRIX=(
" C2-6:X2-5:P1 CX3-6:P2 \
. . T:X4-6 . . . 0 A1:4-6|A2:4-6 A1:P1|A2:P-2 ."
+ # Switch PRS state (root <=> isolated) will properly update cpuset.cpus.isolated
+ # even if child partitions are present.
+ " C1-6:P1 C3-6:P1 C5-6:P2 . . P2 . . 0 A1:1-2:A2:3-4:A3:5-6
+ A1:P1|A2:P2:A3:P2 3-6"
+ " C1-6:P1 C3-6:P2 C5-6:P2 . . P1 . . 0 A1:1-2:A2:3-4:A3:5-6
+ A1:P1|A2:P1:A3:P2 5-6"
+
#
# old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate ISOLCPUS
# ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ --------
--
2.56.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH-next v2 5/5] cgroup/cpuset: Correctly set isolated_cpus when switching partition state
2026-11-09 19:09 ` [PATCH-next v2 5/5] cgroup/cpuset: Correctly set isolated_cpus when switching partition state Waiman Long
@ 2026-11-10 2:23 ` Waiman Long
2026-11-10 2:24 ` [PATCH-next v2.1 " Waiman Long
2026-11-10 11:40 ` [PATCH-next v2 " Ridong Chen
2 siblings, 0 replies; 15+ messages in thread
From: Waiman Long @ 2026-11-10 2:23 UTC (permalink / raw)
To: Ridong Chen, Tejun Heo, Johannes Weiner, Michal Koutný, Shuah Khan
Cc: cgroups, linux-kernel, linux-kselftest, Guopeng Zhang
On 11/9/26 2:09 PM, Waiman Long wrote:
> When update_prstate() is called to switch the partition state from
> root to isolated or vice versa, the whole effective_xcpus is passed to
> isolated_cpus_update(). However, if there are child partitions present,
> some of the effective_xcpus are dedicated to those child partitions
> and their partition states will remain the same or get invalidated in
> the case of child root partition with isolated parent in the latter
> update_cpumasks_heir() call. In the latter case, their exclusive CPUs
> will be returned to their parent.
>
> Therefore isolated_cpus may be set incorrectly with child partitions
> underneath. Fix that by excluding their exclusive CPUs in computing
> the correct cpumask of exclusive CPUs used by that partition alone.
>
> Add new test cases into test_cpuset_prs.sh to test for such cases.
>
> Fixes: 11e5f407b64a ("cgroup/cpuset: Keep track of CPUs in isolated partitions")
> Signed-off-by: Waiman Long <longman@redhat.com>
> ---
> kernel/cgroup/cpuset.c | 30 +++++++++++++++----
> .../selftests/cgroup/test_cpuset_prs.sh | 7 +++++
> 2 files changed, 32 insertions(+), 5 deletions(-)
>
> diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
> index 7aa614c6ac4d..41048997a955 100644
> --- a/kernel/cgroup/cpuset.c
> +++ b/kernel/cgroup/cpuset.c
> @@ -3054,12 +3054,32 @@ static int update_prstate(struct cpuset *cs, int new_prs)
> cs->effective_xcpus, NULL))
> err = PERR_HKEEPING;
> else if (parent_prs == PRS_ISOLATED)
> - err = PERR_ISOPARENT;
> + err = PERR_ISOPARENT; /* old_prs should be isolated */
>
> - if (!err)
> - isolcpus_updated = true;
> - else
> + if (err) {
> disable_partition = true;
> + } else {
> + struct cgroup_subsys_state *css;
> + struct cpuset *child;
> +
> + /*
> + * Need to scan child partitions, if present, and
> + * exclude their effective_xcpus from cs. In the case
> + * of switching to isolated partition with child root
> + * partitions, those child partitions will be
> + * invalidated in update_cpumasks_hier().
> + */
> + isolcpus_updated = true;
> + cpumask_copy(tmpmask.new_cpus, cs->effective_xcpus);
> + rcu_read_lock();
> + cpuset_for_each_child(child, css, cs) {
> + if (!is_partition_valid(child))
> + continue;
> + cpumask_andnot(tmpmask.new_cpus, tmpmask.new_cpus,
> + child->effective_xcpus);
> + }
> + rcu_read_unlock();
> + }
> } else {
> /*
> * Switching back to member is always allowed even if it
> @@ -3093,7 +3113,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 partition is disabled & update effective_xcpus */
> diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
> index 2d4744f2d6ac..741a13bbeda7 100755
> --- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh
> +++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
> @@ -556,6 +556,13 @@ TEST_MATRIX=(
> " C2-6:X2-5:P1 CX3-6:P2 \
> . . T:X4-6 . . . 0 A1:4-6|A2:4-6 A1:P1|A2:P-2 ."
>
> + # Switch PRS state (root <=> isolated) will properly update cpuset.cpus.isolated
> + # even if child partitions are present.
> + " C1-6:P1 C3-6:P1 C5-6:P2 . . P2 . . 0 A1:1-2:A2:3-4:A3:5-6
> + A1:P1|A2:P2:A3:P2 3-6"
> + " C1-6:P1 C3-6:P2 C5-6:P2 . . P1 . . 0 A1:1-2:A2:3-4:A3:5-6
> + A1:P1|A2:P1:A3:P2 5-6"
> +
> #
> # old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate ISOLCPUS
> # ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ --------
Sorry, I thought I had fixed the test case bug. Apparently I haven't
completely fixed it. I will send a v2.1 with the correct test cases.
Thanks,
Longman
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH-next v2.1 5/5] cgroup/cpuset: Correctly set isolated_cpus when switching partition state
2026-11-09 19:09 ` [PATCH-next v2 5/5] cgroup/cpuset: Correctly set isolated_cpus when switching partition state Waiman Long
2026-11-10 2:23 ` Waiman Long
@ 2026-11-10 2:24 ` Waiman Long
2026-11-10 11:40 ` [PATCH-next v2 " Ridong Chen
2 siblings, 0 replies; 15+ messages in thread
From: Waiman Long @ 2026-11-10 2:24 UTC (permalink / raw)
To: Ridong Chen, Tejun Heo, Johannes Weiner, Michal Koutný, Shuah Khan
Cc: cgroups, linux-kernel, linux-kselftest, Guopeng Zhang, Waiman Long
When update_prstate() is called to switch the partition state from
root to isolated or vice versa, the whole effective_xcpus is passed to
isolated_cpus_update(). However, if there are child partitions present,
some of the effective_xcpus are dedicated to those child partitions
and their partition states will remain the same or get invalidated in
the case of child root partition with isolated parent in the latter
update_cpumasks_heir() call. In the latter case, their exclusive CPUs
will be returned to their parent.
Therefore isolated_cpus may be set incorrectly with child partitions
underneath. Fix that by excluding their exclusive CPUs in computing
the correct cpumask of exclusive CPUs used by that partition alone.
Add new test cases into test_cpuset_prs.sh to test for such cases.
Fixes: 11e5f407b64a ("cgroup/cpuset: Keep track of CPUs in isolated partitions")
Signed-off-by: Waiman Long <longman@redhat.com>
---
kernel/cgroup/cpuset.c | 30 +++++++++++++++----
.../selftests/cgroup/test_cpuset_prs.sh | 7 +++++
2 files changed, 32 insertions(+), 5 deletions(-)
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 7aa614c6ac4d..41048997a955 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -3054,12 +3054,32 @@ static int update_prstate(struct cpuset *cs, int new_prs)
cs->effective_xcpus, NULL))
err = PERR_HKEEPING;
else if (parent_prs == PRS_ISOLATED)
- err = PERR_ISOPARENT;
+ err = PERR_ISOPARENT; /* old_prs should be isolated */
- if (!err)
- isolcpus_updated = true;
- else
+ if (err) {
disable_partition = true;
+ } else {
+ struct cgroup_subsys_state *css;
+ struct cpuset *child;
+
+ /*
+ * Need to scan child partitions, if present, and
+ * exclude their effective_xcpus from cs. In the case
+ * of switching to isolated partition with child root
+ * partitions, those child partitions will be
+ * invalidated in update_cpumasks_hier().
+ */
+ isolcpus_updated = true;
+ cpumask_copy(tmpmask.new_cpus, cs->effective_xcpus);
+ rcu_read_lock();
+ cpuset_for_each_child(child, css, cs) {
+ if (!is_partition_valid(child))
+ continue;
+ cpumask_andnot(tmpmask.new_cpus, tmpmask.new_cpus,
+ child->effective_xcpus);
+ }
+ rcu_read_unlock();
+ }
} else {
/*
* Switching back to member is always allowed even if it
@@ -3093,7 +3113,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 partition is disabled & update effective_xcpus */
diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
index 2d4744f2d6ac..351c8e8e89fa 100755
--- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh
+++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
@@ -556,6 +556,13 @@ TEST_MATRIX=(
" C2-6:X2-5:P1 CX3-6:P2 \
. . T:X4-6 . . . 0 A1:4-6|A2:4-6 A1:P1|A2:P-2 ."
+ # Switch PRS state (root <=> isolated) will properly update cpuset.cpus.isolated
+ # even if child partitions are present.
+ " C1-6:P1 C3-6:P1 C5-6:P2 . . P2 . . 0 A1:1-2|A2:3-4|A3:5-6
+ A1:P1|A2:P2|A3:P2 3-6"
+ " C1-6:P1 C3-6:P2 C5-6:P2 . . P1 . . 0 A1:1-2|A2:3-4|A3:5-6
+ A1:P1|A2:P1|A3:P2 5-6"
+
#
# old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate ISOLCPUS
# ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ --------
--
2.56.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH-next v2 1/5] selftests/cgroup: Fix "test_cpuset_prs.sh -v" failures
2026-11-09 19:09 ` [PATCH-next v2 1/5] selftests/cgroup: Fix "test_cpuset_prs.sh -v" failures Waiman Long
@ 2026-11-10 7:56 ` Ridong Chen
0 siblings, 0 replies; 15+ messages in thread
From: Ridong Chen @ 2026-11-10 7:56 UTC (permalink / raw)
To: Waiman Long, Tejun Heo, Johannes Weiner, Michal Koutný, Shuah Khan
Cc: cgroups, linux-kernel, linux-kselftest, Guopeng Zhang
On 11/10/2026 3:09 AM, Waiman Long wrote:
> When the -v option is used to run test_cpuset_prs.sh, it activates the
> use of sched-debug to determine the set of isolated CPUs which will
> also consider 1-CPU partition as being isolated though they will not be
> reflected in "cpuset.cpus.isolated". As a result, some of the expected
> isolated CPUs values have 2 different set of values to correspond to
> these two ways of determining isolated CPUs.
>
> Commit 6e4834ba8986 ("cgroup/cpuset: Fix incorrect CPU accounting with
> parent's effective_xcpus expansion") introduces some new test cases
> which fail when the -v option is used. Update the test cases to make
> them pass with the -v option as well.
>
> Also remove an obsolete comment in update_parent_effective_cpumask()
> of cpuset.c.
>
> Reported-by: Tejun Heo <tj@kernel.org>
> Link: https://lore.kernel.org/lkml/886a562b52b1c5094142d547a8336457@kernel.org
> Fixes: 362212853cd0 ("cgroup/cpuset: Fix incorrect CPU accounting with parent's effective_xcpus expansion")
> Signed-off-by: Waiman Long <longman@redhat.com>
> ---
> kernel/cgroup/cpuset.c | 6 ------
> tools/testing/selftests/cgroup/test_cpuset_prs.sh | 13 ++++++++-----
> 2 files changed, 8 insertions(+), 11 deletions(-)
>
> diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
> index 85e5b529d144..6074327c3477 100644
> --- a/kernel/cgroup/cpuset.c
> +++ b/kernel/cgroup/cpuset.c
> @@ -2164,12 +2164,6 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
> else
> part_error = PERR_NOTEXCL;
> }
> - /*
> - * When both cs and parent remain valid, parent's
> - * compute_partition_effective_cpumask() call would have removed
> - * cs's effective_xcpus from the parent's effective_cpus. So
> - * there is no need to adjust parent's effective_cpus here.
> - */
> }
>
> write_error:
> diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
> index 32e1e44fa0b1..2d4744f2d6ac 100755
> --- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh
> +++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
> @@ -540,16 +540,19 @@ TEST_MATRIX=(
>
> # The extra CPUs gained by a child partition when its parent expands the
> # exclusive CPUs have to be taken away from the parent.
> - " C2-6:X2-5:P1 CX3-6:P1 \
> - . . X2-6 . . . 0 A1:2|A2:3-6|XA2:3-6 A1:P1|A2:P1 ."
> - " C2-6:X2-5:P1 CX3-6:P2 \
> - . . X2-6 . . . 0 A1:2|A2:3-6|XA2:3-6 A1:P1|A2:P2 3-6"
> + " C2-6:X2-5:P1 CX4-6:P1 \
> + . . X2-6 . . . 0 A1:2-3|A2:4-6|XA2:4-6 \
> + A1:P1|A2:P1 ."
> + " C2-6:X2-5:P1 CX4-6:P2 \
> + . . X2-6 . . . 0 A1:2-3|A2:4-6|XA2:4-6 \
> + A1:P1|A2:P2 4-6"
>
> # Both expansion and contraction of parent's effective_xcpus will be
> # correctly handled in child partition and the child can be invalidated
> # if a populated parent could lose all its effective_cpus.
> " C2-6:X2-5:P1 CX3,5-6:P2 \
> - . . X4-6 . . . 0 A1:4|A2:5-6|XA2:5-6 A1:P1|A2:P2 5-6"
> + . . X4-6 . . . 0 A1:4|A2:5-6|XA2:5-6 \
> + A1:P1|A2:P2 4-6|5-6"
> " C2-6:X2-5:P1 CX3-6:P2 \
> . . T:X4-6 . . . 0 A1:4-6|A2:4-6 A1:P1|A2:P-2 ."
>
The commit message still refers to commit 6e4834ba8986, which isn't in
next tree. It should be 362212853cd0 ?
I applied the whole series on top of next-20261109 and ran
test_cpuset_prs.sh with and without -v as well as test_cpuset on an
8-CPU VM. All tests passed and there is no warning in dmesg.
Reviewed-by: Ridong Chen <ridong.chen@linux.dev>
Tested-by: Ridong Chen <ridong.chen@linux.dev>
--
Best regards
Ridong
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH-next v2 2/5] cgroup/cpuset: Correctly set cpus_updated in cpuset_hotplug_update_tasks()
2026-11-09 19:09 ` [PATCH-next v2 2/5] cgroup/cpuset: Correctly set cpus_updated in cpuset_hotplug_update_tasks() Waiman Long
@ 2026-11-10 8:40 ` Ridong Chen
0 siblings, 0 replies; 15+ messages in thread
From: Ridong Chen @ 2026-11-10 8:40 UTC (permalink / raw)
To: Waiman Long, Tejun Heo, Johannes Weiner, Michal Koutný, Shuah Khan
Cc: cgroups, linux-kernel, linux-kselftest, Guopeng Zhang, Sashiko
On 11/10/2026 3:09 AM, Waiman Long wrote:
> When cpuset_hotplug_update_tasks() is called with the conditions that
> either remote_partition_disable() or update_parent_effective_cpumask()
> has to be called, the cs->effective_cpus can be updated such that it
> matches what is computed in new_cpus. In such case, cpus_updated can
> be incorrectly set to false leading to stale CPU afinity remained in the
> tasks not matching the new cpuset value. Fix that by forcing cpus_updated
> to true whenever one of these partition helpers is being called.
>
> Fixes: 4b842da276a8a ("cpuset: Make CPU hotplug work with partition")
> Reported-by: Sashiko <sashiko-bot@kernel.org>
> Link: https://sashiko.dev/#/bug/linux-ab90f7e8-0d60-40ca-83e9-e405075b24d2
> Signed-off-by: Waiman Long <longman@redhat.com>
> ---
> kernel/cgroup/cpuset.c | 11 +++++++++--
> 1 file changed, 9 insertions(+), 2 deletions(-)
>
> diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
> index 6074327c3477..3955d2d574cf 100644
> --- a/kernel/cgroup/cpuset.c
> +++ b/kernel/cgroup/cpuset.c
> @@ -4002,7 +4002,7 @@ static void cpuset_hotplug_update_tasks(struct cpuset *cs, struct tmpmasks *tmp)
> {
> static cpumask_t new_cpus;
> static nodemask_t new_mems;
> - bool cpus_updated;
> + bool cpus_updated = false;
> bool mems_updated;
> int partcmd = -1;
> struct cpuset *parent;
> @@ -4015,12 +4015,18 @@ static void cpuset_hotplug_update_tasks(struct cpuset *cs, struct tmpmasks *tmp)
> if (!tmp || !cs->partition_root_state)
> goto update_tasks;
>
> + /*
> + * cpus_updated should be set to true when remote_partition_disable()
> + * or update_parent_effective_cpumask() is called as cs->effective_cpus
> + * may have been updated.
> + */
> if (is_remote_partition(cs) && (cpumask_empty(subpartitions_cpus) ||
> (cpumask_empty(&new_cpus) &&
> partition_is_populated(cs, NULL)))) {
> WRITE_ONCE(cs->prs_err, PERR_HOTPLUG);
> remote_partition_disable(cs, tmp);
> compute_effective_cpumask(&new_cpus, cs, parent);
> + cpus_updated = true;
> }
>
> /*
> @@ -4045,6 +4051,7 @@ static void cpuset_hotplug_update_tasks(struct cpuset *cs, struct tmpmasks *tmp)
> partcmd = partcmd_update;
>
> if (partcmd >= 0) {
> + cpus_updated = true;
> update_parent_effective_cpumask(cs, partcmd, NULL, tmp);
> if (is_partition_valid(cs) || (partcmd == partcmd_invalidate)) {
> compute_effective_cpumask(&new_cpus, cs, parent);
> @@ -4053,7 +4060,7 @@ static void cpuset_hotplug_update_tasks(struct cpuset *cs, struct tmpmasks *tmp)
> }
>
> update_tasks:
> - cpus_updated = !cpumask_equal(&new_cpus, cs->effective_cpus);
> + cpus_updated |= !cpumask_equal(&new_cpus, cs->effective_cpus);
> mems_updated = !nodes_equal(new_mems, cs->effective_mems);
> if (!cpus_updated && !mems_updated)
> goto unlock; /* Hotplug doesn't affect this cpuset */
I think the issue only happens in the remote partition case.
remote_partition_disable() calls reset_partition_data(), which sets
cs->effective_cpus to what compute_effective_cpumask() will return
afterwards, so the cpumask_equal() check misses the change while the
tasks still have the old affinity.
update_parent_effective_cpumask() only updates the effective_cpus of
the parent (through partition_xcpus_add/del()), and cs is skipped in
update_sibling_cpumasks(). So cs->effective_cpus isn't changed there and
the original check still works. If new_cpus is the same as
cs->effective_cpus in that case, forcing cpus_updated just walks all the
tasks in cs and calls set_cpus_allowed_ptr() with their current mask.
Should cpus_updated only be set in the remote partition case?
Also, as the problem comes from remote_partition_disable() in the
hotplug path, should the Fixes tag be the following instead?
Fixes: 181c8e091aae ("cgroup/cpuset: Introduce remote partition")
--
Best regards
Ridong
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH-next v2 3/5] cgroup/cpuset: Fix incorrect partition invalidation logic in cpuset_hotplug_update_tasks()
2026-11-09 19:09 ` [PATCH-next v2 3/5] cgroup/cpuset: Fix incorrect partition invalidation logic " Waiman Long
@ 2026-11-10 8:51 ` Ridong Chen
0 siblings, 0 replies; 15+ messages in thread
From: Ridong Chen @ 2026-11-10 8:51 UTC (permalink / raw)
To: Waiman Long, Tejun Heo, Johannes Weiner, Michal Koutný, Shuah Khan
Cc: cgroups, linux-kernel, linux-kselftest, Guopeng Zhang, Sashiko
On 11/10/2026 3:09 AM, Waiman Long wrote:
> When most of the active CPUs of a system are allocated to
> sub-partitions below the top_cpuset partition, it is possible that a
> CPU offline operation may remove the last active CPU in the top_cpuset
> partition. When that really happens, cpuset_handle_hotplug() will clear
> the subpartitions_cpus to make sure active CPUs are present in the top
> partition and let the other sub-partitions get invalidated and then
> competes for their exclusive CPUs again.
>
> In cpuset_hotplug_update_tasks(), the current code use
> "cpumask_empty(subpartitions_cpus)" to determine if that partition
> should be invalidated. That is fine if there is only one sub-partition.
> As reported by sashiko that when there are more than one sub-partitions
> and the first sub-partition will get invalidated and then it will
> try to acquire the exclusive CPUs and become valid again. When this
> happens, the subpartitions_cpus will no longer be empty. The remaining
> sub-partitions will assume their exclusive CPUs are safe and proceed
> as normal. As a result, active CPUs owned by those sub-partitions
> remain in both top_cpuset.effective_cpus and the sub-partitions'
> effective_cpus while missing from subpartitions_cpus, breaking partition
> CPU exclusivity and triggering WARN_ON_ONCE() in generate_sched_domains()
> and remote_partition_disable().
>
> Fix that by checking if the sub-partitions' effective_xcpus are subset
> of subpartitions_cpus to determine if they should be invalidated. Also
> remove the obsolete WARN_ON_ONCE() call in remote_partition_disable().
>
> Fixes: 0c7f293efc87 ("cgroup/cpuset: Add cpuset.cpus.exclusive.effective for v2")
> Reported-by: Sashiko <sashiko-bot@kernel.org>
> Link: https://sashiko.dev/#/bug/linux-bf69cd3c-833a-4599-a1f9-8dd9e044cd7c
> Signed-off-by: Waiman Long <longman@redhat.com>
> ---
> kernel/cgroup/cpuset.c | 19 +++++--------------
> 1 file changed, 5 insertions(+), 14 deletions(-)
>
> diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
> index 3955d2d574cf..e9b84671af21 100644
> --- a/kernel/cgroup/cpuset.c
> +++ b/kernel/cgroup/cpuset.c
> @@ -1766,15 +1766,6 @@ static int remote_partition_enable(struct cpuset *cs, int new_prs,
> static void remote_partition_disable(struct cpuset *cs, struct tmpmasks *tmp)
> {
> WARN_ON_ONCE(!is_remote_partition(cs));
> - /*
> - * When a CPU is offlined, top_cpuset may end up with no available CPUs,
> - * which should clear subpartitions_cpus. We should not emit a warning for this
> - * scenario: the hierarchy is updated from top to bottom, so subpartitions_cpus
> - * may already be cleared when disabling the partition.
> - */
> - WARN_ON_ONCE(!cpumask_subset(cs->effective_xcpus, subpartitions_cpus) &&
> - !cpumask_empty(subpartitions_cpus));
> -
> spin_lock_irq(&callback_lock);
> cs->remote_partition = false;
> partition_xcpus_del(cs->partition_root_state, NULL, cs->effective_xcpus);
> @@ -4020,9 +4011,9 @@ static void cpuset_hotplug_update_tasks(struct cpuset *cs, struct tmpmasks *tmp)
> * or update_parent_effective_cpumask() is called as cs->effective_cpus
> * may have been updated.
> */
> - if (is_remote_partition(cs) && (cpumask_empty(subpartitions_cpus) ||
> - (cpumask_empty(&new_cpus) &&
> - partition_is_populated(cs, NULL)))) {
> + if (is_remote_partition(cs) &&
> + (!cpumask_subset(cs->effective_xcpus, subpartitions_cpus) ||
> + (cpumask_empty(&new_cpus) && partition_is_populated(cs, NULL)))) {
> WRITE_ONCE(cs->prs_err, PERR_HOTPLUG);
> remote_partition_disable(cs, tmp);
> compute_effective_cpumask(&new_cpus, cs, parent);
> @@ -4035,12 +4026,12 @@ static void cpuset_hotplug_update_tasks(struct cpuset *cs, struct tmpmasks *tmp)
> * 1) empty effective cpus but not valid empty partition.
> * 2) parent is invalid or doesn't grant any cpus to child
> * partitions.
> - * 3) subpartitions_cpus is empty.
> + * 3) effective_xcpus isn't a subset of subpartitions_cpus.
> */
> if (is_local_partition(cs) &&
> (!is_partition_valid(parent) ||
> tasks_nocpu_error(parent, cs, &new_cpus) ||
> - cpumask_empty(subpartitions_cpus)))
> + !cpumask_subset(cs->effective_xcpus, subpartitions_cpus)))
> partcmd = partcmd_invalidate;
> /*
> * On the other hand, an invalid partition root may be transitioned
LGTM.
Reviewed-by: Ridong Chen <ridong.chen@linux.dev>
Thanks.
--
Best regards
Ridong
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH-next v2 4/5] cgroup/cpuset: Protect current->mems_allowed read in cpuset_fork()
2026-11-09 19:09 ` [PATCH-next v2 4/5] cgroup/cpuset: Protect current->mems_allowed read in cpuset_fork() Waiman Long
@ 2026-11-10 11:24 ` Ridong Chen
0 siblings, 0 replies; 15+ messages in thread
From: Ridong Chen @ 2026-11-10 11:24 UTC (permalink / raw)
To: Waiman Long, Tejun Heo, Johannes Weiner, Michal Koutný, Shuah Khan
Cc: cgroups, linux-kernel, linux-kselftest, Guopeng Zhang, Sashiko
On 11/10/2026 3:09 AM, Waiman Long wrote:
> Reading mems_allowed of the current task outside of cpuset_mutex critical
> section should be protected by using mems_allowed_seq seqlock as the
> nodemask can be updated concurrently leading to a torn read. Such
> protection is currently not implemented in cpuset_fork() for the
> !CLONE_INTO_CGROUP case. As a result, the child task may inherit an empty
> or corrupted mems_allowed nodemask. This violates NUMA memory policy
> constraints and causes subsequent page allocations to unconditionally
> fail, potentially leading to crashes or spurious OOM killer invocations
> for the child task.
>
> Fix that by using a read_mems_allowed_begin/read_mems_allowed_retry()
> loop to protect the mems_allowed read.
>
> Fixes: 06f4e9489891 ("cpuset: make sure new tasks conform to the current config of the cpuset")
> Reported-by: Sashiko <sashiko-bot@kernel.org>
> Link: https://sashiko.dev/#/bug/linux-601100b4-fa77-45fd-99f9-bfbd4385201f
> Signed-off-by: Waiman Long <longman@redhat.com>
> ---
> kernel/cgroup/cpuset.c | 11 ++++++++++-
> 1 file changed, 10 insertions(+), 1 deletion(-)
>
> diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
> index e9b84671af21..7aa614c6ac4d 100644
> --- a/kernel/cgroup/cpuset.c
> +++ b/kernel/cgroup/cpuset.c
> @@ -3868,11 +3868,20 @@ static void cpuset_fork(struct task_struct *task)
> rcu_read_unlock();
>
> if (cs == oldcs) {
> + unsigned int seq;
> +
> if (cs == &top_cpuset)
> return;
>
> set_cpus_allowed_ptr(task, current->cpus_ptr);
> - task->mems_allowed = current->mems_allowed;
> + /*
> + * A cpuset.mems update can update current->mems_allowed
> + * concurrently, so retry it again if it really happens.
> + */
> + do {
> + seq = read_mems_allowed_begin();
> + task->mems_allowed = current->mems_allowed;
> + } while (read_mems_allowed_retry(seq));
> return;
> }
>
Reviewed-by: Ridong Chen <ridong.chen@linux.dev>
Thanks.
--
Best regards
Ridong
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH-next v2 5/5] cgroup/cpuset: Correctly set isolated_cpus when switching partition state
2026-11-09 19:09 ` [PATCH-next v2 5/5] cgroup/cpuset: Correctly set isolated_cpus when switching partition state Waiman Long
2026-11-10 2:23 ` Waiman Long
2026-11-10 2:24 ` [PATCH-next v2.1 " Waiman Long
@ 2026-11-10 11:40 ` Ridong Chen
2026-11-10 13:02 ` Ridong Chen
2 siblings, 1 reply; 15+ messages in thread
From: Ridong Chen @ 2026-11-10 11:40 UTC (permalink / raw)
To: Waiman Long, Tejun Heo, Johannes Weiner, Michal Koutný, Shuah Khan
Cc: cgroups, linux-kernel, linux-kselftest, Guopeng Zhang
On 11/10/2026 3:09 AM, Waiman Long wrote:
> When update_prstate() is called to switch the partition state from
> root to isolated or vice versa, the whole effective_xcpus is passed to
> isolated_cpus_update(). However, if there are child partitions present,
> some of the effective_xcpus are dedicated to those child partitions
> and their partition states will remain the same or get invalidated in
> the case of child root partition with isolated parent in the latter
> update_cpumasks_heir() call. In the latter case, their exclusive CPUs
update_cpumasks_heir
> will be returned to their parent.
>
> Therefore isolated_cpus may be set incorrectly with child partitions
> underneath. Fix that by excluding their exclusive CPUs in computing
> the correct cpumask of exclusive CPUs used by that partition alone.
>
> Add new test cases into test_cpuset_prs.sh to test for such cases.
>
> Fixes: 11e5f407b64a ("cgroup/cpuset: Keep track of CPUs in isolated partitions")
> Signed-off-by: Waiman Long <longman@redhat.com>
> ---
> kernel/cgroup/cpuset.c | 30 +++++++++++++++----
> .../selftests/cgroup/test_cpuset_prs.sh | 7 +++++
> 2 files changed, 32 insertions(+), 5 deletions(-)
>
> diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
> index 7aa614c6ac4d..41048997a955 100644
> --- a/kernel/cgroup/cpuset.c
> +++ b/kernel/cgroup/cpuset.c
> @@ -3054,12 +3054,32 @@ static int update_prstate(struct cpuset *cs, int new_prs)
> cs->effective_xcpus, NULL))
> err = PERR_HKEEPING;
> else if (parent_prs == PRS_ISOLATED)
> - err = PERR_ISOPARENT;
> + err = PERR_ISOPARENT; /* old_prs should be isolated */
>
> - if (!err)
> - isolcpus_updated = true;
> - else
> + if (err) {
> disable_partition = true;
> + } else {
> + struct cgroup_subsys_state *css;
> + struct cpuset *child;
> +
> + /*
> + * Need to scan child partitions, if present, and
> + * exclude their effective_xcpus from cs. In the case
> + * of switching to isolated partition with child root
> + * partitions, those child partitions will be
> + * invalidated in update_cpumasks_hier().
> + */
> + isolcpus_updated = true;
> + cpumask_copy(tmpmask.new_cpus, cs->effective_xcpus);
> + rcu_read_lock();
> + cpuset_for_each_child(child, css, cs) {
> + if (!is_partition_valid(child))
> + continue;
> + cpumask_andnot(tmpmask.new_cpus, tmpmask.new_cpus,
> + child->effective_xcpus);
> + }
> + rcu_read_unlock();
> + }
> } else {
> /*
> * Switching back to member is always allowed even if it
> @@ -3093,7 +3113,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 partition is disabled & update effective_xcpus */
> diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
> index 2d4744f2d6ac..741a13bbeda7 100755
> --- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh
> +++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
> @@ -556,6 +556,13 @@ TEST_MATRIX=(
> " C2-6:X2-5:P1 CX3-6:P2 \
> . . T:X4-6 . . . 0 A1:4-6|A2:4-6 A1:P1|A2:P-2 ."
>
> + # Switch PRS state (root <=> isolated) will properly update cpuset.cpus.isolated
> + # even if child partitions are present.
> + " C1-6:P1 C3-6:P1 C5-6:P2 . . P2 . . 0 A1:1-2:A2:3-4:A3:5-6
> + A1:P1|A2:P2:A3:P2 3-6"
> + " C1-6:P1 C3-6:P2 C5-6:P2 . . P1 . . 0 A1:1-2:A2:3-4:A3:5-6
> + A1:P1|A2:P1:A3:P2 5-6"
> +
> #
> # old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate ISOLCPUS
> # ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ --------
We hit the same issue in our testing earlier (an isolated child partition
loses its isolation when the parent is switched from isolated to root),
and this is the same fix I had in mind. I also ran a few 3-level nested
cases (root/isolated combinations, switching the parent and the middle
level) on top of this series and cpuset.cpus.isolated is correct in all
of them.
Nits: The first line of the two new test cases lacks
the trailing "\" used by the other multi-line entries. It still works
as the newline is just treated as a field separator, though.
Reviewed-by: Ridong Chen <ridong.chen@linux.dev>
Tested-by: Ridong Chen <ridong.chen@linux.dev>
--
Best regards
Ridong
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH-next v2 5/5] cgroup/cpuset: Correctly set isolated_cpus when switching partition state
2026-11-10 11:40 ` [PATCH-next v2 " Ridong Chen
@ 2026-11-10 13:02 ` Ridong Chen
0 siblings, 0 replies; 15+ messages in thread
From: Ridong Chen @ 2026-11-10 13:02 UTC (permalink / raw)
To: Waiman Long, Tejun Heo, Johannes Weiner, Michal Koutný, Shuah Khan
Cc: cgroups, linux-kernel, linux-kselftest, Guopeng Zhang
On 11/10/2026 7:40 PM, Ridong Chen wrote:
>
>
> On 11/10/2026 3:09 AM, Waiman Long wrote:
>> When update_prstate() is called to switch the partition state from
>> root to isolated or vice versa, the whole effective_xcpus is passed to
>> isolated_cpus_update(). However, if there are child partitions present,
>> some of the effective_xcpus are dedicated to those child partitions
>> and their partition states will remain the same or get invalidated in
>> the case of child root partition with isolated parent in the latter
>> update_cpumasks_heir() call. In the latter case, their exclusive CPUs
>
> update_cpumasks_heir
Sorry, it should be update_cpumasks_hier.
>
>> will be returned to their parent.
>>
>> Therefore isolated_cpus may be set incorrectly with child partitions
>> underneath. Fix that by excluding their exclusive CPUs in computing
>> the correct cpumask of exclusive CPUs used by that partition alone.
>>
>> Add new test cases into test_cpuset_prs.sh to test for such cases.
>>
>> Fixes: 11e5f407b64a ("cgroup/cpuset: Keep track of CPUs in isolated partitions")
>> Signed-off-by: Waiman Long <longman@redhat.com>
>> ---
>> kernel/cgroup/cpuset.c | 30 +++++++++++++++----
>> .../selftests/cgroup/test_cpuset_prs.sh | 7 +++++
>> 2 files changed, 32 insertions(+), 5 deletions(-)
>>
>> diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
>> index 7aa614c6ac4d..41048997a955 100644
>> --- a/kernel/cgroup/cpuset.c
>> +++ b/kernel/cgroup/cpuset.c
>> @@ -3054,12 +3054,32 @@ static int update_prstate(struct cpuset *cs, int new_prs)
>> cs->effective_xcpus, NULL))
>> err = PERR_HKEEPING;
>> else if (parent_prs == PRS_ISOLATED)
>> - err = PERR_ISOPARENT;
>> + err = PERR_ISOPARENT; /* old_prs should be isolated */
>> - if (!err)
>> - isolcpus_updated = true;
>> - else
>> + if (err) {
>> disable_partition = true;
>> + } else {
>> + struct cgroup_subsys_state *css;
>> + struct cpuset *child;
>> +
>> + /*
>> + * Need to scan child partitions, if present, and
>> + * exclude their effective_xcpus from cs. In the case
>> + * of switching to isolated partition with child root
>> + * partitions, those child partitions will be
>> + * invalidated in update_cpumasks_hier().
>> + */
>> + isolcpus_updated = true;
>> + cpumask_copy(tmpmask.new_cpus, cs->effective_xcpus);
>> + rcu_read_lock();
>> + cpuset_for_each_child(child, css, cs) {
>> + if (!is_partition_valid(child))
>> + continue;
>> + cpumask_andnot(tmpmask.new_cpus, tmpmask.new_cpus,
>> + child->effective_xcpus);
>> + }
>> + rcu_read_unlock();
>> + }
>> } else {
>> /*
>> * Switching back to member is always allowed even if it
>> @@ -3093,7 +3113,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 partition is disabled & update effective_xcpus */
>> diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/
>> testing/selftests/cgroup/test_cpuset_prs.sh
>> index 2d4744f2d6ac..741a13bbeda7 100755
>> --- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh
>> +++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
>> @@ -556,6 +556,13 @@ TEST_MATRIX=(
>> " C2-6:X2-5:P1 CX3-6:P2 \
>> . . T:X4-6 . . . 0 A1:4-6|
>> A2:4-6 A1:P1|A2:P-2 ."
>> + # Switch PRS state (root <=> isolated) will properly update
>> cpuset.cpus.isolated
>> + # even if child partitions are present.
>> + " C1-6:P1 C3-6:P1 C5-6:P2 . . P2 . . 0
>> A1:1-2:A2:3-4:A3:5-6
>> + A1:P1|A2:P2:A3:P2 3-6"
>> + " C1-6:P1 C3-6:P2 C5-6:P2 . . P1 . . 0
>> A1:1-2:A2:3-4:A3:5-6
>> + A1:P1|A2:P1:A3:P2 5-6"
>> +
>> #
>> # old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs
>> Pstate ISOLCPUS
>> # ------ ------ ------ ------ ------ ------ ------ ------ ---- -----
>> ------ --------
>
> We hit the same issue in our testing earlier (an isolated child partition
> loses its isolation when the parent is switched from isolated to root),
> and this is the same fix I had in mind. I also ran a few 3-level nested
> cases (root/isolated combinations, switching the parent and the middle
> level) on top of this series and cpuset.cpus.isolated is correct in all
> of them.
>
> Nits: The first line of the two new test cases lacks
> the trailing "\" used by the other multi-line entries. It still works
> as the newline is just treated as a field separator, though.
>
> Reviewed-by: Ridong Chen <ridong.chen@linux.dev>
> Tested-by: Ridong Chen <ridong.chen@linux.dev>
>
--
Best regards
Ridong
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH-next v2 0/5] More fix patches
2026-11-09 19:09 [PATCH-next v2 0/5] More fix patches Waiman Long
` (4 preceding siblings ...)
2026-11-09 19:09 ` [PATCH-next v2 5/5] cgroup/cpuset: Correctly set isolated_cpus when switching partition state Waiman Long
@ 2026-11-10 19:27 ` Tejun Heo
5 siblings, 0 replies; 15+ messages in thread
From: Tejun Heo @ 2026-11-10 19:27 UTC (permalink / raw)
To: Waiman Long
Cc: Ridong Chen, Johannes Weiner, Michal Koutný,
Shuah Khan, cgroups, linux-kernel, linux-kselftest,
Guopeng Zhang, sashiko-bot
> selftests/cgroup: Fix "test_cpuset_prs.sh -v" failures
> cgroup/cpuset: Correctly set cpus_updated in
> cpuset_hotplug_update_tasks()
> cgroup/cpuset: Fix incorrect partition invalidation logic in
> cpuset_hotplug_update_tasks()
> cgroup/cpuset: Protect current->mems_allowed read in cpuset_fork()
> cgroup/cpuset: Correctly set isolated_cpus when switching partition
> state
Applied 1, 4 and 5 (5 as v2.1) to cgroup/for-7.4-fixes with the following
changes:
- 1: Nonexistent commit ID 6e4834ba8986 in the description corrected to
362212853cd0.
- 5: "update_cpumasks_heir()" typo in the description fixed.
- 5: Missing trailing "\" line continuation added to the first line of the
two new TEST_MATRIX entries in test_cpuset_prs.sh.
The following tags were also added:
Reviewed-by: Ridong Chen <ridong.chen@linux.dev> (1, 4, 5)
Tested-by: Ridong Chen <ridong.chen@linux.dev> (1, 5)
Cc: stable@vger.kernel.org # v6.8+ (5)
Thanks.
--
tejun
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2026-11-10 19:27 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-09 19:09 [PATCH-next v2 0/5] More fix patches Waiman Long
2026-11-09 19:09 ` [PATCH-next v2 1/5] selftests/cgroup: Fix "test_cpuset_prs.sh -v" failures Waiman Long
2026-11-10 7:56 ` Ridong Chen
2026-11-09 19:09 ` [PATCH-next v2 2/5] cgroup/cpuset: Correctly set cpus_updated in cpuset_hotplug_update_tasks() Waiman Long
2026-11-10 8:40 ` Ridong Chen
2026-11-09 19:09 ` [PATCH-next v2 3/5] cgroup/cpuset: Fix incorrect partition invalidation logic " Waiman Long
2026-11-10 8:51 ` Ridong Chen
2026-11-09 19:09 ` [PATCH-next v2 4/5] cgroup/cpuset: Protect current->mems_allowed read in cpuset_fork() Waiman Long
2026-11-10 11:24 ` Ridong Chen
2026-11-09 19:09 ` [PATCH-next v2 5/5] cgroup/cpuset: Correctly set isolated_cpus when switching partition state Waiman Long
2026-11-10 2:23 ` Waiman Long
2026-11-10 2:24 ` [PATCH-next v2.1 " Waiman Long
2026-11-10 11:40 ` [PATCH-next v2 " Ridong Chen
2026-11-10 13:02 ` Ridong Chen
2026-11-10 19:27 ` [PATCH-next v2 0/5] More fix patches Tejun Heo
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®