Although it is not typical for real users to create a complicated nested partition hierarchy, it is currently allowed to create nested root and isolated partitions. In addition, disabling or invalidating a partition should always be allowed especially when the cpuset is being deleted.
With a nested root and isolated partition hierarchy, it is possible that all active housekeeping CPUs can be exhausted when disabling or invalidating a root partition and returning its CPUs to the isolated parent. One way to avoid this problem is to disallow the creation of a root partition under an isolated parent. It is indeed a new limitation imposed on the existing cpuset partition functionality. However an isolated partition is usually a left node where scheduling and some other kernel noises are disabled. It doesn't make much sense to create a child root partition under an isolated parent and remove some CPUs from the set of isolated CPUs again. Creation of a child isolated partition under a root or isolated parent is still allowed. The cgroup-v2 documentation is also updated to reflect this new limitation. New test cases are added to test_cpuset_prs.sh to verify this new behavior. Some existing test cases are also updated accordingly. Signed-off-by: Waiman Long <[email protected]> --- Documentation/admin-guide/cgroup-v2.rst | 4 +++- kernel/cgroup/cpuset-internal.h | 1 + kernel/cgroup/cpuset.c | 13 +++++++++++++ tools/testing/selftests/cgroup/test_cpuset_prs.sh | 14 ++++++++------ 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/Documentation/admin-guide/cgroup-v2.rst b/Documentation/admin-guide/cgroup-v2.rst index bd8c80f3bbc9..2c445829e24d 100644 --- a/Documentation/admin-guide/cgroup-v2.rst +++ b/Documentation/admin-guide/cgroup-v2.rst @@ -2767,7 +2767,9 @@ Cpuset Interface Files be retained, but behaves more like a "member". All possible state transitions among "member", "root" and - "isolated" are allowed. + "isolated" are allowed with the exception that a local child + "root" partition is not allowed to be created under an "isolated" + parent partition. On read, the "cpuset.cpus.partition" file can show the following values. diff --git a/kernel/cgroup/cpuset-internal.h b/kernel/cgroup/cpuset-internal.h index 5da9c91295b0..2e44dc8634dc 100644 --- a/kernel/cgroup/cpuset-internal.h +++ b/kernel/cgroup/cpuset-internal.h @@ -35,6 +35,7 @@ enum prs_errcode { PERR_HKEEPING, PERR_ACCESS, PERR_REMOTE, + PERR_ISOPARENT, }; /* bits in struct cpuset flags field */ diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c index 40c004386af0..681701ba46e1 100644 --- a/kernel/cgroup/cpuset.c +++ b/kernel/cgroup/cpuset.c @@ -60,6 +60,7 @@ static const char * const perr_strings[] = { [PERR_HKEEPING] = "partition config conflicts with housekeeping setup", [PERR_ACCESS] = "Enable partition not permitted", [PERR_REMOTE] = "Have remote partition underneath", + [PERR_ISOPARENT] = "Root partition is not allowed with isolated parent", }; /* @@ -2865,6 +2866,7 @@ static int update_prstate(struct cpuset *cs, int new_prs) int err = PERR_NONE, old_prs = cs->partition_root_state; struct cpuset *parent = parent_cs(cs); struct tmpmasks tmpmask; + int parent_prs = parent->partition_root_state; bool isolcpus_updated = false; bool disable_partition = false; @@ -2910,6 +2912,14 @@ static int update_prstate(struct cpuset *cs, int new_prs) enum partition_cmd cmd = (new_prs == PRS_ROOT) ? partcmd_enable : partcmd_enablei; + /* + * It is not allowed to create a root partition under + * an isolated parent partition. + */ + if ((new_prs == PRS_ROOT) && (parent_prs == PRS_ISOLATED)) { + err = PERR_ISOPARENT; + goto out; + } err = update_parent_effective_cpumask(cs, cmd, NULL, &tmpmask); } else { err = remote_partition_enable(cs, new_prs, &tmpmask); @@ -2922,6 +2932,9 @@ static int update_prstate(struct cpuset *cs, int new_prs) if (prstate_housekeeping_conflict(new_prs, cs->effective_xcpus)) { disable_partition = true; err = PERR_HKEEPING; + } else if (parent_prs == PRS_ISOLATED) { + disable_partition = true; + err = PERR_ISOPARENT; } else { isolcpus_updated = true; } diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh index 874a8a161236..85a4f87840b4 100755 --- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh +++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh @@ -288,16 +288,12 @@ TEST_MATRIX=( A1:P0|A2:P1|A3:P0|B1:P1" " C0-3 C1-3 C3 C4 X2-3 X2-3:P1 P2 P1 0 A1:0-1|A2:2|A3:3|B1:4 \ A1:P0|A2:P1|A3:P2|B1:P1 2-4|3" - " C0-4 C1-4 C2-4 . X2-4 X2-4:P2 X4:P1 . 0 A1:0-1|A2:2-3|A3:4 \ - A1:P0|A2:P2|A3:P1 2-4|2-3" - " C0-4 C1-4 C2-4 . X2-4 X2-4:P2 X3-4:P1 . 0 A1:0-1|A2:2|A3:3-4 \ - A1:P0|A2:P2|A3:P1 2" " C0-4:X2-4 C1-4:X2-4:P1 C2-4:X4:P2 \ . . X5 . . 0 A1:0-4|A2:1-4|A3:2-4 \ A1:P0|A2:P-1|A3:P-2 ." - " C0-4:X2-4 C1-4:X2-4:P2 C2-4:X4:P1 \ + " C0-4:X2-4 C1-4:X2-4:P1 C2-4:X4:P2 \ . . . X1 . 0 A1:0-1|A2:2-4|A3:2-4 \ - A1:P0|A2:P2|A3:P-1 2-4" + A1:P0|A2:P1|A3:P-2 ." " 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" @@ -430,6 +426,12 @@ TEST_MATRIX=( # cpuset.cpus can become empty with task in it as it inherits parent's effective CPUs " C1-3 C2 . . . T:C . . 0 A1:1-3|A2:1-3" + # Creation of root partition under an isolated partition is not allowed + " C1-3:P2 C2 . . . P1 . . 0 A1:1-3|A2:2 A1:P2|A2:P-1 1-3" + " C1-3:P2 C2 . . . P2 . . 0 A1:1,3|A2:2 A1:P2|A2:P2 1-3" + " C1-3:P2 C2:P2 . . . P1 . . 0 A1:1-3|A2:2 A1:P2|A2:P-1 1-3" + + # # old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate ISOLCPUS # ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ -------- # Failure cases: -- 2.55.0

