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

Reply via email to