On 2026/4/21 11:03, Waiman Long wrote:
> The housekeeping_update() function currently allows update to the
> HK_TYPE_DOMAIN cpumask only. As we are going to enable dynamic
> modification of the other housekeeping cpumasks, we need to extend
> it to support passing in the information about the HK cpumask(s) to
> be updated. In cases where some HK cpumasks happen to be the same,
> it will be more efficient to update multiple HK cpumasks in one single
> call instead of calling it multiple times. Extend housekeeping_update()
> to support that as well.
>
> Also add the restriction that passed in isolated cpumask parameter
> of housekeeping_update() must include all the CPUs isolated at boot
> time. This is currently the case for cpuset anyway.
>
> Signed-off-by: Waiman Long <[email protected]>
> ---
> include/linux/sched/isolation.h | 2 +-
> kernel/cgroup/cpuset.c | 2 +-
> kernel/sched/isolation.c | 99 +++++++++++++++++++++++----------
> 3 files changed, 71 insertions(+), 32 deletions(-)
>
> diff --git a/include/linux/sched/isolation.h b/include/linux/sched/isolation.h
> index d1707f121e20..a17f16e0156e 100644
> --- a/include/linux/sched/isolation.h
> +++ b/include/linux/sched/isolation.h
> @@ -51,7 +51,7 @@ extern const struct cpumask *housekeeping_cpumask(enum
> hk_type type);
> extern bool housekeeping_enabled(enum hk_type type);
> extern void housekeeping_affine(struct task_struct *t, enum hk_type type);
> extern bool housekeeping_test_cpu(int cpu, enum hk_type type);
> -extern int housekeeping_update(struct cpumask *isol_mask);
> +extern int housekeeping_update(struct cpumask *isol_mask, unsigned long
> flags);
> extern void __init housekeeping_init(void);
>
> #else
> diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
> index 1335e437098e..a4eccb0ec0d1 100644
> --- a/kernel/cgroup/cpuset.c
> +++ b/kernel/cgroup/cpuset.c
> @@ -1354,7 +1354,7 @@ static void cpuset_update_sd_hk_unlock(void)
> */
> mutex_unlock(&cpuset_mutex);
> cpus_read_unlock();
> - WARN_ON_ONCE(housekeeping_update(isolated_hk_cpus));
> + WARN_ON_ONCE(housekeeping_update(isolated_hk_cpus,
> BIT(HK_TYPE_DOMAIN)));
> mutex_unlock(&cpuset_top_mutex);
> } else {
> cpuset_full_unlock();
> diff --git a/kernel/sched/isolation.c b/kernel/sched/isolation.c
> index 9ec9ae510dc7..965d6f8fe344 100644
> --- a/kernel/sched/isolation.c
> +++ b/kernel/sched/isolation.c
> @@ -120,48 +120,87 @@ bool housekeeping_test_cpu(int cpu, enum hk_type type)
> }
> EXPORT_SYMBOL_GPL(housekeeping_test_cpu);
>
> -int housekeeping_update(struct cpumask *isol_mask)
> -{
> - struct cpumask *trial, *old = NULL;
> - int err;
> +/* HK type processing table */
> +static struct {
> + int type;
> + int boot_type;
> +} hk_types[] = {
> + { HK_TYPE_DOMAIN, HK_TYPE_DOMAIN_BOOT },
> + { HK_TYPE_MANAGED_IRQ, HK_TYPE_MANAGED_IRQ_BOOT },
> + { HK_TYPE_KERNEL_NOISE, HK_TYPE_KERNEL_NOISE_BOOT }
> +};
>
> - trial = kmalloc(cpumask_size(), GFP_KERNEL);
> - if (!trial)
> - return -ENOMEM;
> +#define HK_TYPE_CNT ARRAY_SIZE(hk_types)
>
> - cpumask_andnot(trial, housekeeping_cpumask(HK_TYPE_DOMAIN_BOOT),
> isol_mask);
> - if (!cpumask_intersects(trial, cpu_online_mask)) {
> - kfree(trial);
> - return -EINVAL;
> +int housekeeping_update(struct cpumask *isol_mask, unsigned long flags)
> +{
> + struct cpumask *trial[HK_TYPE_CNT];
> + int i, err = 0;
> +
> + for (i = 0; i < HK_TYPE_CNT; i++) {
> + int type = hk_types[i].type;
> + int boot = hk_types[i].boot_type;
> +
> + trial[i] = NULL;
> + if (flags & BIT(type)) {
> + trial[i] = kmalloc(cpumask_size(), GFP_KERNEL);
> + if (!trial[i]) {
> + err = -ENOMEM;
> + goto out;
> + }
> + /*
> + * The new HK cpumask must be a subset of its boot
> + * cpumask.
> + */
> + cpumask_andnot(trial[i], cpu_possible_mask, isol_mask);
> + if (!cpumask_intersects(trial[i], cpu_online_mask) ||
> + !cpumask_subset(trial[i],
> housekeeping_cpumask(boot))) {
> + i++;
> + err = -EINVAL;
> + goto out;
> + }
> + }
> }
>
The i++ here is confusing. Wouldn't it be more readable to just use
kfree(trial[i]) and then break out?
> if (!housekeeping.flags)
> static_branch_enable(&housekeeping_overridden);
>
> - if (housekeeping.flags & HK_FLAG_DOMAIN)
> - old = housekeeping_cpumask_dereference(HK_TYPE_DOMAIN);
> - else
> - WRITE_ONCE(housekeeping.flags, housekeeping.flags |
> HK_FLAG_DOMAIN);
> - rcu_assign_pointer(housekeeping.cpumasks[HK_TYPE_DOMAIN], trial);
> -
> - synchronize_rcu();
> -
> - pci_probe_flush_workqueue();
> - mem_cgroup_flush_workqueue();
> - vmstat_flush_workqueue();
> + for (i = 0; i < HK_TYPE_CNT; i++) {
> + int type = hk_types[i].type;
> + struct cpumask *old;
>
> - err =
> workqueue_unbound_housekeeping_update(housekeeping_cpumask(HK_TYPE_DOMAIN));
> - WARN_ON_ONCE(err < 0);
> + if (!trial[i])
> + continue;
> + old = NULL;
> + if (housekeeping.flags & BIT(type))
> + old = housekeeping_cpumask_dereference(type);
> + rcu_assign_pointer(housekeeping.cpumasks[type], trial[i]);
> + trial[i] = old;
> + }
>
> - err = tmigr_isolated_exclude_cpumask(isol_mask);
> - WARN_ON_ONCE(err < 0);
> + if ((housekeeping.flags & flags) != flags)
> + WRITE_ONCE(housekeeping.flags, housekeeping.flags | flags);
>
> - err = kthreads_update_housekeeping();
> - WARN_ON_ONCE(err < 0);
> + synchronize_rcu();
>
> - kfree(old);
> + if (flags & HK_FLAG_DOMAIN) {
> + /*
> + * HK_TYPE_DOMAIN specific callbacks
> + */
> + pci_probe_flush_workqueue();
> + mem_cgroup_flush_workqueue();
> + vmstat_flush_workqueue();
> +
> + WARN_ON_ONCE(workqueue_unbound_housekeeping_update(
> + housekeeping_cpumask(HK_TYPE_DOMAIN)) < 0);
> + WARN_ON_ONCE(tmigr_isolated_exclude_cpumask(isol_mask) < 0);
> + WARN_ON_ONCE(kthreads_update_housekeeping() < 0);
> + }
>
> - return 0;
> +out:
> + while (--i >= 0)
> + kfree(trial[i]);
> + return err;
> }
>
> void __init housekeeping_init(void)
--
Best regards,
Ridong