[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <0b918f11-d850-4cdb-b9af-ffa436b8fd1e@redhat.com>
Date: Sun, 24 Aug 2025 13:05:21 -0400
From: Waiman Long <llong@...hat.com>
To: Chen Ridong <chenridong@...weicloud.com>, tj@...nel.org,
hannes@...xchg.org, mkoutny@...e.com
Cc: cgroups@...r.kernel.org, linux-kernel@...r.kernel.org,
lujialin4@...wei.com, chenridong@...wei.com
Subject: Re: [PATCH -next v4 2/3] cpuset: separate tmpmasks and cpuset
allocation logic
On 8/18/25 2:41 AM, Chen Ridong wrote:
> From: Chen Ridong <chenridong@...wei.com>
>
> The original alloc_cpumasks() served dual purposes: allocating cpumasks
> for both temporary masks (tmpmasks) and cpuset structures. This patch:
>
> 1. Decouples these allocation paths for better code clarity
> 2. Introduces dedicated alloc_tmpmasks() and dup_or_alloc_cpuset()
> functions
> 3. Maintains symmetric pairing:
> - alloc_tmpmasks() ↔ free_tmpmasks()
> - dup_or_alloc_cpuset() ↔ free_cpuset()
>
> Signed-off-by: Chen Ridong <chenridong@...wei.com>
> ---
> kernel/cgroup/cpuset.c | 128 ++++++++++++++++++++++-------------------
> 1 file changed, 69 insertions(+), 59 deletions(-)
>
> diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
> index aebda14cc67f..d5588a1fef60 100644
> --- a/kernel/cgroup/cpuset.c
> +++ b/kernel/cgroup/cpuset.c
> @@ -411,51 +411,46 @@ static void guarantee_online_mems(struct cpuset *cs, nodemask_t *pmask)
> }
>
> /**
> - * alloc_cpumasks - allocate three cpumasks for cpuset
> - * @cs: the cpuset that have cpumasks to be allocated.
> - * @tmp: the tmpmasks structure pointer
> - * Return: 0 if successful, -ENOMEM otherwise.
> + * alloc_cpumasks - Allocate an array of cpumask variables
> + * @pmasks: Pointer to array of cpumask_var_t pointers
> + * @size: Number of cpumasks to allocate
> *
> - * Only one of the two input arguments should be non-NULL.
> + * Allocates @size cpumasks and initializes them to empty. Returns 0 on
> + * success, -ENOMEM on allocation failure. On failure, any previously
> + * allocated cpumasks are freed.
The convention for the kernel-doc is to have a "Return:" tag if the
function has a returned value. That "Return:" tag is deleted by this
change. Your description does describe the returned value and no test
robot failure was reported. Other than that, the rest of the patch looks
good to me.
Cheers,
Longman
> */
> -static inline int alloc_cpumasks(struct cpuset *cs, struct tmpmasks *tmp)
> +static inline int alloc_cpumasks(cpumask_var_t *pmasks[], u32 size)
> {
> - cpumask_var_t *pmask1, *pmask2, *pmask3, *pmask4;
> + int i;
>
> - if (cs) {
> - pmask1 = &cs->cpus_allowed;
> - pmask2 = &cs->effective_cpus;
> - pmask3 = &cs->effective_xcpus;
> - pmask4 = &cs->exclusive_cpus;
> - } else {
> - pmask1 = &tmp->new_cpus;
> - pmask2 = &tmp->addmask;
> - pmask3 = &tmp->delmask;
> - pmask4 = NULL;
> + for (i = 0; i < size; i++) {
> + if (!zalloc_cpumask_var(pmasks[i], GFP_KERNEL)) {
> + while (--i >= 0)
> + free_cpumask_var(*pmasks[i]);
> + return -ENOMEM;
> + }
> }
> -
> - if (!zalloc_cpumask_var(pmask1, GFP_KERNEL))
> - return -ENOMEM;
> -
> - if (!zalloc_cpumask_var(pmask2, GFP_KERNEL))
> - goto free_one;
> -
> - if (!zalloc_cpumask_var(pmask3, GFP_KERNEL))
> - goto free_two;
> -
> - if (pmask4 && !zalloc_cpumask_var(pmask4, GFP_KERNEL))
> - goto free_three;
> -
> -
> return 0;
> +}
>
> -free_three:
> - free_cpumask_var(*pmask3);
> -free_two:
> - free_cpumask_var(*pmask2);
> -free_one:
> - free_cpumask_var(*pmask1);
> - return -ENOMEM;
> +/**
> + * alloc_tmpmasks - Allocate temporary cpumasks for cpuset operations.
> + * @tmp: Pointer to tmpmasks structure to populate
> + * Return: 0 on success, -ENOMEM on allocation failure
> + */
> +static inline int alloc_tmpmasks(struct tmpmasks *tmp)
> +{
> + /*
> + * Array of pointers to the three cpumask_var_t fields in tmpmasks.
> + * Note: Array size must match actual number of masks (3)
> + */
> + cpumask_var_t *pmask[3] = {
> + &tmp->new_cpus,
> + &tmp->addmask,
> + &tmp->delmask
> + };
> +
> + return alloc_cpumasks(pmask, ARRAY_SIZE(pmask));
> }
>
> /**
> @@ -470,26 +465,46 @@ static inline void free_tmpmasks(struct tmpmasks *tmp)
> }
>
> /**
> - * alloc_trial_cpuset - allocate a trial cpuset
> - * @cs: the cpuset that the trial cpuset duplicates
> + * dup_or_alloc_cpuset - Duplicate or allocate a new cpuset
> + * @cs: Source cpuset to duplicate (NULL for a fresh allocation)
> + *
> + * Creates a new cpuset by either:
> + * 1. Duplicating an existing cpuset (if @cs is non-NULL), or
> + * 2. Allocating a fresh cpuset with zero-initialized masks (if @cs is NULL)
> + *
> + * Return: Pointer to newly allocated cpuset on success, NULL on failure
> */
> -static struct cpuset *alloc_trial_cpuset(struct cpuset *cs)
> +static struct cpuset *dup_or_alloc_cpuset(struct cpuset *cs)
> {
> struct cpuset *trial;
>
> - trial = kmemdup(cs, sizeof(*cs), GFP_KERNEL);
> + /* Allocate base structure */
> + trial = cs ? kmemdup(cs, sizeof(*cs), GFP_KERNEL) :
> + kzalloc(sizeof(*cs), GFP_KERNEL);
> if (!trial)
> return NULL;
>
> - if (alloc_cpumasks(trial, NULL)) {
> + /* Setup cpumask pointer array */
> + cpumask_var_t *pmask[4] = {
> + &trial->cpus_allowed,
> + &trial->effective_cpus,
> + &trial->effective_xcpus,
> + &trial->exclusive_cpus
> + };
> +
> + if (alloc_cpumasks(pmask, ARRAY_SIZE(pmask))) {
> kfree(trial);
> return NULL;
> }
>
> - cpumask_copy(trial->cpus_allowed, cs->cpus_allowed);
> - cpumask_copy(trial->effective_cpus, cs->effective_cpus);
> - cpumask_copy(trial->effective_xcpus, cs->effective_xcpus);
> - cpumask_copy(trial->exclusive_cpus, cs->exclusive_cpus);
> + /* Copy masks if duplicating */
> + if (cs) {
> + cpumask_copy(trial->cpus_allowed, cs->cpus_allowed);
> + cpumask_copy(trial->effective_cpus, cs->effective_cpus);
> + cpumask_copy(trial->effective_xcpus, cs->effective_xcpus);
> + cpumask_copy(trial->exclusive_cpus, cs->exclusive_cpus);
> + }
> +
> return trial;
> }
>
> @@ -2332,7 +2347,7 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
> if (cpumask_equal(cs->cpus_allowed, trialcs->cpus_allowed))
> return 0;
>
> - if (alloc_cpumasks(NULL, &tmp))
> + if (alloc_tmpmasks(&tmp))
> return -ENOMEM;
>
> if (old_prs) {
> @@ -2476,7 +2491,7 @@ static int update_exclusive_cpumask(struct cpuset *cs, struct cpuset *trialcs,
> if (retval)
> return retval;
>
> - if (alloc_cpumasks(NULL, &tmp))
> + if (alloc_tmpmasks(&tmp))
> return -ENOMEM;
>
> if (old_prs) {
> @@ -2820,7 +2835,7 @@ int cpuset_update_flag(cpuset_flagbits_t bit, struct cpuset *cs,
> int spread_flag_changed;
> int err;
>
> - trialcs = alloc_trial_cpuset(cs);
> + trialcs = dup_or_alloc_cpuset(cs);
> if (!trialcs)
> return -ENOMEM;
>
> @@ -2881,7 +2896,7 @@ static int update_prstate(struct cpuset *cs, int new_prs)
> if (new_prs && is_prs_invalid(old_prs))
> old_prs = PRS_MEMBER;
>
> - if (alloc_cpumasks(NULL, &tmpmask))
> + if (alloc_tmpmasks(&tmpmask))
> return -ENOMEM;
>
> err = update_partition_exclusive_flag(cs, new_prs);
> @@ -3223,7 +3238,7 @@ ssize_t cpuset_write_resmask(struct kernfs_open_file *of,
> if (!is_cpuset_online(cs))
> goto out_unlock;
>
> - trialcs = alloc_trial_cpuset(cs);
> + trialcs = dup_or_alloc_cpuset(cs);
> if (!trialcs) {
> retval = -ENOMEM;
> goto out_unlock;
> @@ -3456,15 +3471,10 @@ cpuset_css_alloc(struct cgroup_subsys_state *parent_css)
> if (!parent_css)
> return &top_cpuset.css;
>
> - cs = kzalloc(sizeof(*cs), GFP_KERNEL);
> + cs = dup_or_alloc_cpuset(NULL);
> if (!cs)
> return ERR_PTR(-ENOMEM);
>
> - if (alloc_cpumasks(cs, NULL)) {
> - kfree(cs);
> - return ERR_PTR(-ENOMEM);
> - }
> -
> __set_bit(CS_SCHED_LOAD_BALANCE, &cs->flags);
> fmeter_init(&cs->fmeter);
> cs->relax_domain_level = -1;
> @@ -3920,7 +3930,7 @@ static void cpuset_handle_hotplug(void)
> bool on_dfl = is_in_v2_mode();
> struct tmpmasks tmp, *ptmp = NULL;
>
> - if (on_dfl && !alloc_cpumasks(NULL, &tmp))
> + if (on_dfl && !alloc_tmpmasks(&tmp))
> ptmp = &tmp;
>
> lockdep_assert_cpus_held();
Powered by blists - more mailing lists