diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c index 954ff6bd11eb..585abff94e8c 100644 --- a/kernel/cgroup/cpuset.c +++ b/kernel/cgroup/cpuset.c @@ -1446,6 +1446,9 @@ static bool prstate_housekeeping_conflict(int new_prs, int parent_prs, !cpumask_subset(new_cpus, housekeeping_cpumask(HK_TYPE_DOMAIN_BOOT))) return true; + if (del_cpus && cpumask_empty(del_cpus)) + del_cpus = NULL; + /* * Exit 2nd check early and return false if * 1) there is no boot time isolated nohz_full CPU @@ -1454,8 +1457,7 @@ static bool prstate_housekeeping_conflict(int new_prs, int parent_prs, * be returned back to the parent. */ if (!housekeeping_enabled(HK_TYPE_KERNEL_NOISE) || - (new_prs == parent_prs) || - ((new_prs == PRS_ROOT) && (!del_cpus || cpumask_empty(del_cpus)))) + (new_prs == parent_prs) || (!del_cpus && (new_prs == PRS_ROOT))) return false; /* @@ -1466,20 +1468,29 @@ static bool prstate_housekeeping_conflict(int new_prs, int parent_prs, if (parent_prs == PRS_ISOLATED) swap(new_cpus, del_cpus); - if (del_cpus && - (cpumask_first_and_and(del_cpus, housekeeping_cpumask(HK_TYPE_KERNEL_NOISE), - cpu_active_mask) < nr_cpu_ids)) - return false; - if (!alloc_cpumask_var(&full_hk_cpus, GFP_KERNEL)) return true; + /* + * Check if del_cpus may contain a CPU that can become an active + * housekeeping CPU again. + */ + if (del_cpus) { + cpumask_and(full_hk_cpus, housekeeping_cpumask(HK_TYPE_KERNEL_NOISE), + housekeeping_cpumask(HK_TYPE_DOMAIN_BOOT)); + if (cpumask_first_and_and(del_cpus, full_hk_cpus, + cpu_active_mask) < nr_cpu_ids) { + res = false; + goto out; + } + } + cpumask_and(full_hk_cpus, housekeeping_cpumask(HK_TYPE_KERNEL_NOISE), housekeeping_cpumask(HK_TYPE_DOMAIN)); cpumask_andnot(full_hk_cpus, full_hk_cpus, isolated_cpus); cpumask_and(full_hk_cpus, full_hk_cpus, cpu_active_mask); res = !cpumask_weight_andnot(full_hk_cpus, new_cpus); - +out: free_cpumask_var(full_hk_cpus); return res; } @@ -2486,23 +2497,29 @@ static void partition_cpus_change(struct cpuset *cs, struct cpuset *trialcs, struct tmpmasks *tmp) { enum prs_errcode prs_err; + int parent_prs = is_remote_partition(cs) + ? PRS_ROOT : parent_cs(cs)->partition_root_state; if (cs_is_member(cs)) return; prs_err = validate_partition(cs, trialcs); - if (!prs_err && !cpumask_empty(trialcs->effective_xcpus)) { + if (!prs_err && (parent_prs > 0) && + !cpumask_empty(trialcs->effective_xcpus)) { int prs = cs->partition_root_state; - int parent_prs = is_remote_partition(cs) - ? PRS_ROOT : parent_cs(cs)->partition_root_state; + /* * Check for housekeeping conflict by passing the whole * effective_xcpus as well as those CPUs that are to be * removed from cs as delmask. */ - cpumask_andnot(tmp->delmask, cs->effective_xcpus, trialcs->effective_xcpus); - if (parent_prs > 0 && - prstate_housekeeping_conflict(prs, parent_prs, + if (prs > 0) + cpumask_andnot(tmp->delmask, cs->effective_xcpus, + trialcs->effective_xcpus); + else + cpumask_clear(tmp->delmask); + + if (prstate_housekeeping_conflict(prs, parent_prs, trialcs->effective_xcpus, tmp->delmask)) prs_err = PERR_HKEEPING; }