diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/cgroup/cpuset.c | 148 |
1 files changed, 77 insertions, 71 deletions
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c index 2a7a0c579c9a..33b562c241d2 100644 --- a/kernel/cgroup/cpuset.c +++ b/kernel/cgroup/cpuset.c @@ -1353,66 +1353,88 @@ static void partition_xcpus_del(int old_prs, struct cpuset *parent, } /* - * isolated_cpus_can_update - check for isolated & nohz_full conflicts - * @add_cpus: cpu mask for cpus that are going to be isolated - * @del_cpus: cpu mask for cpus that are no longer isolated, can be NULL - * Return: false if there is conflict, true otherwise - * - * If nohz_full is enabled and we have isolated CPUs, their combination must - * still leave housekeeping CPUs. + * prstate_housekeeping_conflict - check for partition & housekeeping conflicts + * @new_prs: new partition root state to be checked + * @parent_prs: Parent partition root state + * @add_cpus: additional CPUs to be added to current cpuset + * @del_cpus: CPUs to be removed from current cpuset, can be NULL + * Return: true if there is conflict, false otherwise * - * TBD: Should consider merging this function into - * prstate_housekeeping_conflict(). + * There are two different housekeeping conflicts to be checked: + * 1) If new_prs is PRS_ROOT, none of the @add_cpus can be a boot-time isolated + * CPU. IOW, the whole @add_cpus must be a subset of HK_TYPE_DOMAIN_BOOT. + * 2) If nohz_full is enabled and we have isolated CPUs, their combination must + * still leave housekeeping CPUs. This check is only needed if new_prs + * differs from parent_prs and one of them is PRS_ISOLATED. */ -static bool isolated_cpus_can_update(struct cpumask *add_cpus, - struct cpumask *del_cpus) +static bool prstate_housekeeping_conflict(int new_prs, int parent_prs, + struct cpumask *add_cpus, + struct cpumask *del_cpus) { cpumask_var_t full_hk_cpus; - int res = true; + int res; - if (!housekeeping_enabled(HK_TYPE_KERNEL_NOISE)) - return true; + WARN_ON_ONCE(parent_prs <= 0); + if (!new_prs) + return false; + + /* + * For a currently invalid partition root state, do the check assuming + * that it may be converted back to valid. + * + * There are code paths where an invalid partition may be reverted back + * to a valid partition but we still need to run the housekeeping check + * before the conversion happens to make sure the switch is valid. We + * can either do the negative to positive PRS switch individually in all + * these code paths or do it here which I think will make the code a bit + * easier to read. + */ + if (new_prs < 0) + new_prs = -new_prs; - if (del_cpus && cpumask_weight_and(del_cpus, - housekeeping_cpumask(HK_TYPE_KERNEL_NOISE))) + if (housekeeping_enabled(HK_TYPE_DOMAIN_BOOT) && (new_prs == PRS_ROOT) && + !cpumask_subset(add_cpus, housekeeping_cpumask(HK_TYPE_DOMAIN_BOOT))) return true; - if (!alloc_cpumask_var(&full_hk_cpus, GFP_KERNEL)) + /* + * Exit 2nd check early and return false if + * 1) there is no boot time isolated nohz_full CPU + * 2) parent and child has the same partition state + * 3) new_prs is PRS_ROOT, parent_prs is PRS_ISOLATED and no CPU will + * 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)))) + return false; + + /* + * Now make sure that @add_cpus contains new CPUs to be isolated and + * @del_cpus contains isolated CPUs to be un-isolated. + * With the guards above, @add_cpus can't be NULL after the swap. + */ + if (parent_prs == PRS_ISOLATED) + swap(add_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; + 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); - if (!cpumask_weight_andnot(full_hk_cpus, add_cpus)) - res = false; + res = !cpumask_weight_andnot(full_hk_cpus, add_cpus); free_cpumask_var(full_hk_cpus); return res; } /* - * prstate_housekeeping_conflict - check for partition & housekeeping conflicts - * @prstate: partition root state to be checked - * @new_cpus: cpu mask - * Return: true if there is conflict, false otherwise - * - * CPUs outside of HK_TYPE_DOMAIN_BOOT, if defined, can only be used in an - * isolated partition. - */ -static bool prstate_housekeeping_conflict(int prstate, struct cpumask *new_cpus) -{ - if (!housekeeping_enabled(HK_TYPE_DOMAIN_BOOT)) - return false; - - if ((prstate != PRS_ISOLATED) && - !cpumask_subset(new_cpus, housekeeping_cpumask(HK_TYPE_DOMAIN_BOOT))) - return true; - - return false; -} - -/* * cpuset_update_sd_hk_unlock - Rebuild sched domains, update HK & unlock * * Update housekeeping cpumasks and rebuild sched domains if necessary and @@ -1593,9 +1615,7 @@ static int remote_partition_enable(struct cpuset *cs, int new_prs, return PERR_INVCPUS; if (cpumask_intersects(tmp->new_cpus, subpartitions_cpus)) return PERR_NOCPUS; - if (((new_prs == PRS_ISOLATED) && - !isolated_cpus_can_update(tmp->new_cpus, NULL)) || - prstate_housekeeping_conflict(new_prs, tmp->new_cpus)) + if (prstate_housekeeping_conflict(new_prs, PRS_ROOT, tmp->new_cpus, NULL)) return PERR_HKEEPING; spin_lock_irq(&callback_lock); @@ -1697,8 +1717,8 @@ 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 ((prs == PRS_ISOLATED) && - !isolated_cpus_can_update(tmp->addmask, tmp->delmask)) + 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; @@ -1840,11 +1860,7 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd, if (cpumask_empty(xcpus)) return PERR_INVCPUS; - if (prstate_housekeeping_conflict(new_prs, xcpus)) - return PERR_HKEEPING; - - if ((new_prs == PRS_ISOLATED) && (new_prs != parent_prs) && - !isolated_cpus_can_update(xcpus, NULL)) + if (prstate_housekeeping_conflict(new_prs, parent_prs, xcpus, NULL)) return PERR_HKEEPING; if (tasks_nocpu_error(parent, cs, xcpus)) @@ -1917,20 +1933,12 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd, } /* - * TBD: Invalidate a currently valid child root partition may - * still break isolated_cpus_can_update() rule if parent is an - * isolated partition. + * Check for housekeeping conflicts */ - if (is_partition_valid(cs) && (old_prs != parent_prs)) { - if ((parent_prs == PRS_ROOT) && - /* Adding to parent means removing isolated CPUs */ - !isolated_cpus_can_update(tmp->delmask, tmp->addmask)) - part_error = PERR_HKEEPING; - if ((parent_prs == PRS_ISOLATED) && - /* Adding to parent means adding isolated CPUs */ - !isolated_cpus_can_update(tmp->addmask, tmp->delmask)) - part_error = PERR_HKEEPING; - } + 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 @@ -2438,10 +2446,6 @@ static enum prs_errcode validate_partition(struct cpuset *cs, struct cpuset *tri if (cpumask_empty(trialcs->effective_xcpus)) return PERR_INVCPUS; - if (prstate_housekeeping_conflict(trialcs->partition_root_state, - trialcs->effective_xcpus)) - return PERR_HKEEPING; - if (tasks_nocpu_error(parent, cs, trialcs->effective_xcpus)) return PERR_NOCPUS; @@ -2458,7 +2462,7 @@ static enum prs_errcode validate_partition(struct cpuset *cs, struct cpuset *tri * CPU modifications may cause a partition to be disabled or require state updates. */ static void partition_cpus_change(struct cpuset *cs, struct cpuset *trialcs, - struct tmpmasks *tmp) + struct tmpmasks *tmp) { enum prs_errcode prs_err; @@ -2958,13 +2962,15 @@ static int update_prstate(struct cpuset *cs, int new_prs) err = remote_partition_enable(cs, new_prs, &tmpmask); } } else if (old_prs && new_prs) { + int parent_prs = is_remote_partition(cs) + ? PRS_ROOT : parent->partition_root_state; + /* * A change in load balance state only, no change in cpumasks. * Need to update isolated_cpus. */ - if (((new_prs == PRS_ISOLATED) && - !isolated_cpus_can_update(cs->effective_xcpus, NULL)) || - prstate_housekeeping_conflict(new_prs, cs->effective_xcpus)) + if (prstate_housekeeping_conflict(new_prs, parent_prs, + cs->effective_xcpus, NULL)) err = PERR_HKEEPING; else isolcpus_updated = true; |
