Commit 6da580ec656a ("cgroup/cpuset: Don't allow creation of local
partition over a remote one") updated update_prstate() to prevent creating
a top-level local partition whose exclusive CPUs conflict with an existing
remote partition.
However, if a top-level local partition A1 is created on CPUs 1-3, has a
non-partition member child A1/A2 with cpuset.cpus.exclusive = 1-3, and a
grandchild A1/A2/A3 is then enabled as a partition root on 1-3,
update_prstate() sees !is_partition_valid(parent) (since A1/A2 is a member)
and calls remote_partition_enable(). Because remote_partition_enable() does
not check whether tmp->new_cpus intersects subpartitions_cpus, A1/A2/A3 is
enabled as a remote partition on CPUs already owned by A1, triggering:
WARNING: kernel/cgroup/cpuset.c:1594 at update_prstate+0xbef/0xd70
Return PERR_NOCPUS in remote_partition_enable() when tmp->new_cpus
intersects subpartitions_cpus, matching the error code used by
remote_cpus_update() for subpartitions_cpus conflicts, and add a
corresponding regression test case to
tools/testing/selftests/cgroup/test_cpuset_prs.sh.
Tested in QEMU on Linux 7.3.0-rc3 using
tools/testing/selftests/cgroup/test_cpuset_prs.sh.
Fixes: 6da580ec656a ("cgroup/cpuset: Don't allow creation of local partition
over a remote one")
Suggested-by: Guopeng Zhang <[email protected]>
Cc: [email protected]
Assisted-by: LLM
Signed-off-by: Hui Peng <[email protected]>
---
Changes in v3:
- Split the series into 3 patches (one per logical change and Fixes: tag).
kernel/cgroup/cpuset.c | 4 +++-
tools/testing/selftests/cgroup/test_cpuset_prs.sh | 2 ++
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index c8ab89cfbe3d..7381fa8502e7 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -1678,8 +1678,10 @@ static int remote_partition_enable(struct cpuset *cs,
int new_prs,
* Callers must have validated that effective_xcpus is not empty.
*/
spin_lock_irq(&callback_lock);
- if (cpumask_subset(top_cpuset.effective_cpus, tmp->new_cpus)) {
+ if (cpumask_intersects(tmp->new_cpus, subpartitions_cpus) ||
+ cpumask_subset(top_cpuset.effective_cpus, tmp->new_cpus)) {
spin_unlock_irq(&callback_lock);
+ if (cpumask_intersects(tmp->new_cpus, subpartitions_cpus))
+ return PERR_NOCPUS;
return PERR_HKEEPING;
}
diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh
b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
index a1f42ef64bc1..b732078bf319 100755
--- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh
+++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
@@ -298,6 +298,8 @@ TEST_MATRIX=(
" C0-4:X2-4 C1-4:X2-4:P2 C2-4:X4:P1 \
. . . X1 . 0
A1:0-1|A2:2-4|A3:2-4 \
A1:P0|A2:P2|A3:P-1 2-4"
+ " CX1-3:P1 CX1-3 CX1-3 . . . P1 . 0
A1:1-3|A2:1-3|A3:1-3 \
+
A1:P1|A2:P0|A3:P-1"
# Remote partition offline tests
" C0-3 C1-3 C2-3 . X2-3 X2-3 X2-3:P2:O2=0 . 0
A1:0-1|A2:1|A3:3 A1:P0|A3:P2 2-3"
--
2.49.0