When prstate_housekeeping_conflict() is called to perform housekeeping
check with cpumask changes, the exclusive CPUs owned by child partitions
are excluded. If the current cpuset is an isolated partition with root
partition children. It is possible the cpumask change will still leave
active housekeeping CPUs but then no housekeeping CPUs will be left when
the child partitions are disabled or invalidated.
To protect against this possibility, all the exclusive CPUs of the
cpuset should be considered to be owned by the current cpuset when doing
housekeeping check. Do that by calling prstate_housekeeping_conflict()
in partition_cpus_change() and passing in the add_cpus and del_cpus
parameters as if the cpuset owns all the exclusive CPUs. With that
change, we can remove the duplicated prstate_housekeeping_conflict()
calls in update_parent_effective_cpumask() with partcmd_update and
in remote_cpus_update().
In the case of partition state switch from isolated to root and vice
versa, the set of exclusive CPUs are recomputed to include those
transferred to child paritions as well.
Fixes: 4a74e418881f ("cgroup/cpuset: Check partition conflict with housekeeping
setup")
Signed-off-by: Waiman Long <[email protected]>
---
kernel/cgroup/cpuset.c | 29 +++++++++++++++++------------
1 file changed, 17 insertions(+), 12 deletions(-)
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index f3cebb277a68..ce32e7a31c72 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -1692,9 +1692,6 @@ static void remote_cpus_update(struct cpuset *cs, struct
cpumask *xcpus,
else if (cpumask_intersects(tmp->addmask, subpartitions_cpus) ||
cpumask_subset(top_cpuset.effective_cpus,
tmp->addmask))
WRITE_ONCE(cs->prs_err, PERR_NOCPUS);
- else if (prstate_housekeeping_conflict(prs, PRS_ROOT,
- tmp->addmask,
tmp->delmask))
- WRITE_ONCE(cs->prs_err, PERR_HKEEPING);
if (cs->prs_err)
goto invalidate;
}
@@ -1907,14 +1904,6 @@ static int update_parent_effective_cpumask(struct cpuset
*cs, int cmd,
parent->effective_xcpus);
}
- /*
- * Check for housekeeping conflicts
- */
- if (is_partition_valid(cs) &&
- prstate_housekeeping_conflict(old_prs, parent_prs,
- tmp->delmask, tmp->addmask))
- part_error = PERR_HKEEPING;
-
/*
* The new CPUs to be removed from parent's effective CPUs
* must be present.
@@ -2398,6 +2387,21 @@ static void partition_cpus_change(struct cpuset *cs,
struct cpuset *trialcs,
return;
prs_err = validate_partition(cs, trialcs);
+ if (!prs_err) {
+ int parent_prs = is_remote_partition(cs)
+ ? PRS_ROOT : parent_cs(cs)->partition_root_state;
+ /*
+ * Check for housekeeping CPUs conflict assuming that all the
+ * exclusive CPUs belong to the current cpuset.
+ */
+ compute_excpus(trialcs, tmp->new_cpus);
+ cpumask_andnot(tmp->addmask, tmp->new_cpus,
cs->effective_xcpus);
+ cpumask_andnot(tmp->delmask, cs->effective_xcpus,
tmp->new_cpus);
+ if (prstate_housekeeping_conflict(cs->partition_root_state,
+ parent_prs, tmp->addmask,
+ tmp->delmask))
+ prs_err = PERR_HKEEPING;
+ }
if (prs_err) {
WRITE_ONCE(cs->prs_err, prs_err);
trialcs->prs_err = prs_err;
@@ -2897,8 +2901,9 @@ static int update_prstate(struct cpuset *cs, int new_prs)
* A change in load balance state only, no change in cpumasks.
* Need to update isolated_cpus.
*/
+ compute_excpus(cs, tmpmask.new_cpus);
if (prstate_housekeeping_conflict(new_prs, parent_prs,
- cs->effective_xcpus, NULL))
+ tmpmask.new_cpus, NULL))
err = PERR_HKEEPING;
else
isolcpus_updated = true;
--
2.55.0