diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c index c82b805b112b..2a7a0c579c9a 100644 --- a/kernel/cgroup/cpuset.c +++ b/kernel/cgroup/cpuset.c @@ -2137,6 +2137,25 @@ static void compute_partition_effective_cpumask(struct cpuset *cs, rcu_read_unlock(); } +/* + * ancestor_partition - Find and return the closest valid partition root ancestor + * @cs: the current cpuset + * + * Return: The closet partition root ancestor cpuset + */ +static struct cpuset *ancestor_partition(struct cpuset *cs) +{ + struct cpuset *ancestor = parent_cs(cs); + + /* + * 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; +} + /* * update_cpumasks_hier - Update effective cpumasks and tasks in the subtree * @cs: the cpuset to consider @@ -2229,7 +2248,10 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp, * cpuset if the parent's effective_cpus changes. */ if ((cp != cs) && old_prs) { - switch (parent->partition_root_state) { + int parent_prs = parent->partition_root_state; + struct cpumask *del_cpus = NULL; + + switch (parent_prs) { case PRS_ROOT: case PRS_ISOLATED: update_parent = true; @@ -2237,12 +2259,37 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp, default: /* - * When parent is not a partition root or is - * invalid, child partition roots become - * invalid too. + * When parent is not a valid partition root, + * child partition roots become invalid too. + * + * 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. */ if (is_partition_valid(cp)) - new_prs = -cp->partition_root_state; + new_prs = -old_prs; + + if (old_prs == PRS_ISOLATED) { + struct cpuset *ancestor = ancestor_partition(cp); + + if (ancestor->partition_root_state == PRS_ROOT) + del_cpus = cp->effective_xcpus; + else if (cpumask_andnot(tmp->delmask, + cp->effective_xcpus, + ancestor->effective_xcpus)) + del_cpus = tmp->delmask; + + if (del_cpus) { + spin_lock_irq(&callback_lock); + isolated_cpus_update(old_prs, new_prs, del_cpus); + spin_unlock_irq(&callback_lock); + } + } WRITE_ONCE(cp->prs_err, is_partition_invalid(parent) ? PERR_INVPARENT : PERR_NOTPART); diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh index 7efd5e645767..f1dda27b1394 100755 --- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh +++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh @@ -292,9 +292,9 @@ TEST_MATRIX=( 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:P2 C2-4:X4:P1 \ - . . X5 . . 0 A1:0-4|A2:1-4|A3:2-4 \ - A1:P0|A2:P-2|A3:P-1 ." + " 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 ." " 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"