mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Qi Zheng <qi.zheng@linux.dev>
To: Muchun Song <muchun.song@linux.dev>,
	Qi Zheng <zhengqi.arch@bytedance.com>
Cc: linux-mm@kvack.org, linux-kernel@vger.kernel.org,
	david@kernel.org, osalvador@suse.de, akpm@linux-foundation.org,
	azpijr@gmail.com
Subject: Re: [PATCH v2 3/5] mm: hugetlb: track CMA reservations by pool
Date: Fri, 23 Oct 2026 14:35:33 +0800	[thread overview]
Message-ID: <b37a33e2-7dfb-4401-847e-919f0bd61271@linux.dev> (raw)
In-Reply-To: <b5745b31-adec-4158-bba4-2c21dbfe2566@linux.dev>

Hi Muchun,

On 10/22/26 7:21 PM, Muchun Song wrote:
> 
> 
> On 2026/10/22 15:31, Qi Zheng wrote:
>> From: Qi Zheng <zhengqi.arch@bytedance.com>
>>
>> Introduce fixed default and PMD pool slots in preparation for PMD-sized
>> HugeTLB CMA support. Continue accepting only the architecture's existing
>> CMA page size and keep all gigantic sizes sharing the default pool.
>> PMD-sized pool support will be added in a subsequent patch.
>>
>> Select the pool for allocation, CMA-only checks and boot-time accounting.
>> Release folios through the CMA area that owns their physical memory,
>> including after demotion.
>>
>> Record each pool's successfully reserved capacity and remove
>> hugetlb_cma_validate_params(), since the per-pool CMA-only check handles
>> missing or empty reservations.
>>
>> Assisted-by: LLM
>> Signed-off-by: Qi Zheng <zhengqi.arch@bytedance.com>
>> ---
>>   mm/hugetlb.c     |   6 +-
>>   mm/hugetlb_cma.c | 154 ++++++++++++++++++++++++++++++++---------------
>>   mm/hugetlb_cma.h |  11 ++--
>>   3 files changed, 112 insertions(+), 59 deletions(-)
>>
>> diff --git a/mm/hugetlb.c b/mm/hugetlb.c
>> index b37d7d0db7fc9..6b08074d11f52 100644
>> --- a/mm/hugetlb.c
>> +++ b/mm/hugetlb.c
>> @@ -1368,7 +1368,7 @@ static struct folio 
>> *alloc_gigantic_frozen_folio(int order, gfp_t gfp_mask,
>>       if (folio)
>>           return folio;
>> -    if (hugetlb_cma_exclusive_alloc())
>> +    if (hugetlb_cma_exclusive_alloc(order))
>>           return NULL;
>>       folio = (struct folio *)alloc_contig_frozen_pages(1 << order, 
>> gfp_mask,
>> @@ -3635,7 +3635,7 @@ static void __init 
>> hugetlb_hstate_alloc_pages(struct hstate *h)
>>        * Skip gigantic hugepages allocation if early CMA
>>        * reservations are not available.
>>        */
>> -    if (hstate_is_gigantic(h) && hugetlb_cma_total_size() &&
>> +    if (hstate_is_gigantic(h) && hugetlb_cma_size(h) &&
>>           !hugetlb_early_cma(h)) {
>>           pr_warn_once("hugetlb_cma is enabled, skip boot time 
>> allocation\n");
>>           return;
>> @@ -4338,8 +4338,6 @@ static __init void hugetlb_parse_params(void)
>>           hcp->setup(hcp->val);
>>       }
>> -
>> -    hugetlb_cma_validate_params();
>>   }
>>   /*
>> diff --git a/mm/hugetlb_cma.c b/mm/hugetlb_cma.c
>> index 4f27eb242dc3b..c279c3f548705 100644
>> --- a/mm/hugetlb_cma.c
>> +++ b/mm/hugetlb_cma.c
>> @@ -19,6 +19,7 @@
>>   struct hugetlb_cma_pool {
>>       struct cma *cma[MAX_NUMNODES];
>>       unsigned long size;
>> +    unsigned int order;
>>   };
>>   struct hugetlb_cma_config {
>> @@ -27,14 +28,34 @@ struct hugetlb_cma_config {
>>       unsigned int percent_in_node[MAX_NUMNODES];
>>   };
>> -static struct hugetlb_cma_pool hugetlb_cma __ro_after_init;
>> -static struct hugetlb_cma_config hugetlb_cma_config __initdata;
>> +enum {
>> +    HUGETLB_CMA_DEFAULT,
>> +    HUGETLB_CMA_PMD,
>> +    HUGETLB_CMA_POOLS,
>> +};
> 
> Since there are exactly two pool roles, could we make that explicit with
> a typed enum, for example:
> 
>        enum hugetlb_cma_pool_id {
>              HUGETLB_CMA_POOL_DEFAULT,
>              HUGETLB_CMA_POOL_PMD,
>              HUGETLB_CMA_NR_POOLS,
>        };
> 
> and name the array hugetlb_cma_pools[]?

Make sense, will do.

> 
>> +
>> +static struct hugetlb_cma_pool hugetlb_cma[HUGETLB_CMA_POOLS] 
>> __ro_after_init;
>> +static struct hugetlb_cma_config 
>> hugetlb_cma_config[HUGETLB_CMA_POOLS] __initdata;
>>   static bool hugetlb_cma_only __ro_after_init;
>>   static char hugetlb_cma_cmdline[COMMAND_LINE_SIZE] __initdata;
>>   static unsigned int hugetlb_cma_cmdline_len __initdata;
>> +static struct hugetlb_cma_pool *hugetlb_cma_pool(unsigned int order)
> 
> How about order_to_cma_pool()?

will do.

> 
>> +{
>> +    struct hugetlb_cma_pool *pmd_pool = &hugetlb_cma[HUGETLB_CMA_PMD];
>> +
>> +    if (order == PMD_SHIFT - PAGE_SHIFT && pmd_pool->size)
> 
> PMD_ORDER is better.

OK.

> 
> There's another question here: why does PMD-based page allocation
> need to check the pool->size, but gigantic pages don't?

The PMD size pool needs to be checked here. The check for gigantic pool,
is deferred to the caller.

> 
>> +        return pmd_pool;
>> +
>> +    /* Preserve the default pool's use by gigantic sizes. */
>> +    if (order_is_gigantic(order))
>> +        return &hugetlb_cma[HUGETLB_CMA_DEFAULT];
> 
> If we also check size for gigantic pages here, would the code be simpler
> that way for callers?

Yes, will do.

> 
>> +
>> +    return NULL;
>> +}
>> +
>>   #ifdef CONFIG_NUMA
>>   static phys_addr_t __init memblock_node_memory_size(int nid)
>>   {
>> @@ -56,10 +77,16 @@ static phys_addr_t __init 
>> memblock_node_memory_size(int nid)
>>   void hugetlb_cma_free_frozen_folio(struct folio *folio)
>>   {
>> -    struct hugetlb_cma_pool *pool = &hugetlb_cma;
>> +    unsigned int i;
>> +    int nid = folio_nid(folio);
>> +    unsigned long nr_pages = folio_nr_pages(folio);
>> +
> 
> Please add a short comment here explaining why all pools must be searched:
> after demotion, the folio order does not identify the CMA pool that 
> originally
> owns the physical range.

How about the following comment:

      /*
       * Demotion can change the folio order, so search all pools for the
       * CMA area that owns the physical range.
       */

Thanks,
Qi

> 
> Thanks,
> Muchun
> 
>> +    for (i = 0; i < HUGETLB_CMA_POOLS; i++) {
>> +        if (cma_release_frozen(hugetlb_cma[i].cma[nid], &folio->page, 
>> nr_pages))
>> +            return;
>> +    }
>> -    WARN_ON_ONCE(!cma_release_frozen(pool->cma[folio_nid(folio)],
>> -                     &folio->page, folio_nr_pages(folio)));
>> +    WARN_ON_ONCE(1);
>>   }
>>   struct folio *hugetlb_cma_alloc_frozen_folio(int order, gfp_t gfp_mask,
>> @@ -70,9 +97,9 @@ struct folio *hugetlb_cma_alloc_frozen_folio(int 
>> order, gfp_t gfp_mask,
>>       struct page *page = NULL;
>>       const nodemask_t *nmask;
>>       unsigned int cpuset_mems_cookie;
>> -    struct hugetlb_cma_pool *pool = &hugetlb_cma;
>> +    struct hugetlb_cma_pool *pool = hugetlb_cma_pool(order);
>> -    if (!pool->size)
>> +    if (!pool || !pool->size)
>>           return NULL;
>>   retry_cpuset:
>> @@ -111,7 +138,7 @@ struct folio *hugetlb_cma_alloc_frozen_folio(int 
>> order, gfp_t gfp_mask,
>>   void * __init hugetlb_cma_alloc_bootmem(struct hstate *h, int nid, 
>> bool node_exact)
>>   {
>> -    struct hugetlb_cma_pool *pool = &hugetlb_cma;
>> +    struct hugetlb_cma_pool *pool = 
>> hugetlb_cma_pool(huge_page_order(h));
>>       struct cma *cma;
>>       void *m;
>>       int node;
>> @@ -135,15 +162,16 @@ void * __init hugetlb_cma_alloc_bootmem(struct 
>> hstate *h, int nid, bool node_exa
>>   static int __init hugetlb_cma_parse(char *p)
>>   {
>> -    struct hugetlb_cma_pool *pool = &hugetlb_cma;
>> -    struct hugetlb_cma_config *config = &hugetlb_cma_config;
>> +    struct hugetlb_cma_pool *pool;
>> +    struct hugetlb_cma_config *config;
>> +    unsigned int order = hugetlb_cma[HUGETLB_CMA_DEFAULT].order;
>> +    unsigned int i;
>>       int nid, count = 0;
>>       unsigned long tmp;
>>       char *s = p;
>>       char *suffix = strchr(p, '@');
>>       if (suffix) {
>> -        unsigned int order = arch_hugetlb_cma_order();
>>           unsigned long long page_size;
>>           char *end;
>> @@ -159,6 +187,22 @@ static int __init hugetlb_cma_parse(char *p)
>>           }
>>       }
>> +    if (!order) {
>> +        pr_warn("hugetlb_cma: the option isn't supported by current 
>> arch\n");
>> +        return -EINVAL;
>> +    }
>> +
>> +    for (i = 0; i < HUGETLB_CMA_POOLS; i++) {
>> +        if (hugetlb_cma[i].order == order)
>> +            break;
>> +    }
>> +
>> +    if (i == HUGETLB_CMA_POOLS)
>> +        return -EINVAL;
>> +
>> +    pool = &hugetlb_cma[i];
>> +    config = &hugetlb_cma_config[i];
>> +
>>       while (*s) {
>>           if (sscanf(s, "%lu%n", &tmp, &count) != 1)
>>               break;
>> @@ -256,20 +300,14 @@ unsigned int __weak arch_hugetlb_cma_order(void)
>>       return 0;
>>   }
>> -void __init hugetlb_cma_reserve(void)
>> +static void __init hugetlb_cma_reserve_pool(struct hugetlb_cma_pool 
>> *pool,
>> +                        struct hugetlb_cma_config *config)
>>   {
>> -    struct hugetlb_cma_pool *pool = &hugetlb_cma;
>> -    struct hugetlb_cma_config *config = &hugetlb_cma_config;
>> -    unsigned long size, reserved, per_node, order, gigantic_page_size;
>> +    unsigned long size, reserved, per_node, hugepage_size;
>> +    unsigned int order = pool->order;
>>       bool node_specific_cma_alloc = false;
>>       bool has_node_specific_param = false;
>>       int nid;
>> -    char *p;
>> -
>> -    for (p = hugetlb_cma_cmdline;
>> -         p < hugetlb_cma_cmdline + hugetlb_cma_cmdline_len;
>> -         p += strlen(p) + 1)
>> -        hugetlb_cma_parse(p);
>>       for (nid = 0; nid < MAX_NUMNODES; nid++) {
>>           if (config->size_in_node[nid] || config- 
>> >percent_in_node[nid]) {
>> @@ -301,12 +339,6 @@ void __init hugetlb_cma_reserve(void)
>>       if (!pool->size)
>>           return;
>> -    order = arch_hugetlb_cma_order();
>> -    if (!order) {
>> -        pr_warn("hugetlb_cma: the option isn't supported by current 
>> arch\n");
>> -        return;
>> -    }
>> -
>>       /*
>>        * HugeTLB CMA reservation is required for gigantic
>>        * huge pages which could not be allocated via the
>> @@ -314,12 +346,12 @@ void __init hugetlb_cma_reserve(void)
>>        * breaking this assumption.
>>        */
>>       VM_WARN_ON(order <= MAX_PAGE_ORDER);
>> -    gigantic_page_size = PAGE_SIZE << order;
>> +    hugepage_size = PAGE_SIZE << order;
>>       if (config->percent) {
>>           unsigned long orig_size = pool->size;
>> -        pool->size = ALIGN_DOWN(pool->size, PAGE_SIZE << order);
>> +        pool->size = ALIGN_DOWN(pool->size, hugepage_size);
>>           if (orig_size && !pool->size)
>>               pr_warn("hugetlb_cma: reservation size rounded down to 0 
>> from %lu MiB (%u%%)\n",
>>                   orig_size / SZ_1M, config->percent);
>> @@ -331,7 +363,7 @@ void __init hugetlb_cma_reserve(void)
>>                   config->size_in_node[nid] =
>>                       ALIGN_DOWN(config->size_in_node[nid],
>> -                           PAGE_SIZE << order);
>> +                           hugepage_size);
>>                   if (orig_size && !config->size_in_node[nid])
>>                       pr_warn("hugetlb_cma: reservation size rounded 
>> down to 0 from %lu MiB (%u%%) on node %d\n",
>>                           orig_size / SZ_1M,
>> @@ -351,9 +383,9 @@ void __init hugetlb_cma_reserve(void)
>>           if (!node_isset(nid, hugetlb_bootmem_nodes)) {
>>               pr_warn("hugetlb_cma: invalid node %d specified\n", nid);
>> -        } else if (!IS_ALIGNED(size, gigantic_page_size)) {
>> +        } else if (!IS_ALIGNED(size, hugepage_size)) {
>>               pr_warn("hugetlb_cma: cma area of node %d must be a 
>> multiple of %lu MiB\n",
>> -                nid, gigantic_page_size / SZ_1M);
>> +                nid, hugepage_size / SZ_1M);
>>           } else {
>>               node_specific_cma_alloc = true;
>>               continue;
>> @@ -367,9 +399,9 @@ void __init hugetlb_cma_reserve(void)
>>       if (!pool->size)
>>           return;
>> -    if (!IS_ALIGNED(pool->size, gigantic_page_size)) {
>> +    if (!IS_ALIGNED(pool->size, hugepage_size)) {
>>           pr_warn("hugetlb_cma: cma area must be a multiple of %lu 
>> MiB\n",
>> -            gigantic_page_size / SZ_1M);
>> +            hugepage_size / SZ_1M);
>>           pool->size = 0;
>>           return;
>>       }
>> @@ -381,7 +413,7 @@ void __init hugetlb_cma_reserve(void)
>>            */
>>           per_node = DIV_ROUND_UP(pool->size,
>>                       nodes_weight(hugetlb_bootmem_nodes));
>> -        per_node = round_up(per_node, gigantic_page_size);
>> +        per_node = round_up(per_node, hugepage_size);
>>           if (config->percent)
>>               pr_info("hugetlb_cma: reserve %lu MiB (%u%%), up to %lu 
>> MiB per node\n",
>>                   pool->size / SZ_1M, config->percent,
>> @@ -411,7 +443,7 @@ void __init hugetlb_cma_reserve(void)
>>            * may be returned to CMA allocator in the case of
>>            * huge page demotion.
>>            */
>> -        res = cma_declare_contiguous_multi(size, gigantic_page_size,
>> +        res = cma_declare_contiguous_multi(size, hugepage_size,
>>                       HUGETLB_PAGE_ORDER, name,
>>                       &pool->cma[nid], nid);
>>           if (res || !cma_validate_zones(pool->cma[nid])) {
>> @@ -434,28 +466,50 @@ void __init hugetlb_cma_reserve(void)
>>               break;
>>       }
>> -    if (!reserved)
>> -        /*
>> -         * pool->size is used to determine if allocations from
>> -         * cma are possible.  Set to zero if no cma regions are set up.
>> -         */
>> -        pool->size = 0;
>> +    /* Only successfully reserved areas enable CMA allocation for 
>> this size. */
>> +    pool->size = reserved;
>> +}
>> +
>> +void __init hugetlb_cma_reserve(void)
>> +{
>> +    unsigned int i;
>> +    char *p;
>> +
>> +    hugetlb_cma[HUGETLB_CMA_DEFAULT].order = arch_hugetlb_cma_order();
>> +    hugetlb_cma[HUGETLB_CMA_PMD].order = PMD_SHIFT - PAGE_SHIFT;
>> +
>> +    for (p = hugetlb_cma_cmdline;
>> +         p < hugetlb_cma_cmdline + hugetlb_cma_cmdline_len;
>> +         p += strlen(p) + 1)
>> +        hugetlb_cma_parse(p);
>> +
>> +    for (i = 0; i < HUGETLB_CMA_POOLS; i++)
>> +        hugetlb_cma_reserve_pool(&hugetlb_cma[i], 
>> &hugetlb_cma_config[i]);
>>   }
>> -bool hugetlb_cma_exclusive_alloc(void)
>> +bool hugetlb_cma_exclusive_alloc(unsigned int order)
>>   {
>> -    return hugetlb_cma_only;
>> +    struct hugetlb_cma_pool *pool = hugetlb_cma_pool(order);
>> +
>> +    return hugetlb_cma_only && pool && pool->size;
>>   }
>> -unsigned long __init hugetlb_cma_total_size(void)
>> +unsigned long __init hugetlb_cma_size(struct hstate *h)
>>   {
>> -    return hugetlb_cma.size;
>> +    struct hugetlb_cma_pool *pool = 
>> hugetlb_cma_pool(huge_page_order(h));
>> +
>> +    return pool ? pool->size : 0;
>>   }
>> -void __init hugetlb_cma_validate_params(void)
>> +unsigned long __init hugetlb_cma_total_size(void)
>>   {
>> -    if (!hugetlb_cma.size)
>> -        hugetlb_cma_only = false;
>> +    unsigned long size = 0;
>> +    unsigned int i;
>> +
>> +    for (i = 0; i < HUGETLB_CMA_POOLS; i++)
>> +        size += hugetlb_cma[i].size;
>> +
>> +    return size;
>>   }
>>   bool __init hugetlb_early_cma(struct hstate *h)
>> @@ -463,5 +517,5 @@ bool __init hugetlb_early_cma(struct hstate *h)
>>       if (arch_has_huge_bootmem_alloc())
>>           return false;
>> -    return hstate_is_gigantic(h) && hugetlb_cma_only;
>> +    return hstate_is_gigantic(h) && 
>> hugetlb_cma_exclusive_alloc(huge_page_order(h));
>>   }
>> diff --git a/mm/hugetlb_cma.h b/mm/hugetlb_cma.h
>> index 730b2b4965b64..3d829258f6728 100644
>> --- a/mm/hugetlb_cma.h
>> +++ b/mm/hugetlb_cma.h
>> @@ -9,9 +9,9 @@ void hugetlb_cma_free_frozen_folio(struct folio *folio);
>>   struct folio *hugetlb_cma_alloc_frozen_folio(int order, gfp_t gfp_mask,
>>                         int nid, nodemask_t *nodemask);
>>   void *hugetlb_cma_alloc_bootmem(struct hstate *h, int nid, bool 
>> node_exact);
>> -bool hugetlb_cma_exclusive_alloc(void);
>> +bool hugetlb_cma_exclusive_alloc(unsigned int order);
>> +unsigned long hugetlb_cma_size(struct hstate *h);
>>   unsigned long hugetlb_cma_total_size(void);
>> -void hugetlb_cma_validate_params(void);
>>   bool hugetlb_early_cma(struct hstate *h);
>>   #else
>>   static inline void hugetlb_cma_free_frozen_folio(struct folio *folio)
>> @@ -30,18 +30,19 @@ static inline void 
>> *hugetlb_cma_alloc_bootmem(struct hstate *h, int nid,
>>       return NULL;
>>   }
>> -static inline bool hugetlb_cma_exclusive_alloc(void)
>> +static inline bool hugetlb_cma_exclusive_alloc(unsigned int order)
>>   {
>>       return false;
>>   }
>> -static inline unsigned long hugetlb_cma_total_size(void)
>> +static inline unsigned long hugetlb_cma_size(struct hstate *h)
>>   {
>>       return 0;
>>   }
>> -static inline void hugetlb_cma_validate_params(void)
>> +static inline unsigned long hugetlb_cma_total_size(void)
>>   {
>> +    return 0;
>>   }
>>   static inline bool hugetlb_early_cma(struct hstate *h)
> 


  reply	other threads:[~2026-10-23  6:35 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-22  7:31 [PATCH v2 0/5] mm: hugetlb: add CMA support for PMD-sized pages Qi Zheng
2026-10-22  7:31 ` [PATCH v2 1/5] mm: hugetlb: add explicit page size to hugetlb_cma Qi Zheng
2026-10-22  9:50   ` Muchun Song
2026-10-22  7:31 ` [PATCH v2 2/5] mm: hugetlb: group CMA pool and reservation state Qi Zheng
2026-10-22  9:57   ` Muchun Song
2026-10-22  7:31 ` [PATCH v2 3/5] mm: hugetlb: track CMA reservations by pool Qi Zheng
2026-10-22  8:38   ` Jose A. Perez de Azpillaga
2026-10-22 11:21   ` Muchun Song
2026-10-23  6:35     ` Qi Zheng [this message]
2026-10-23  6:37       ` Muchun Song
2026-10-22  7:31 ` [PATCH v2 4/5] mm: hugetlb: avoid recursive CMA allocation during migration Qi Zheng
2026-10-22  8:51   ` Jose A. Perez de Azpillaga
2026-10-23  7:02   ` Muchun Song
2026-10-23  7:21     ` Qi Zheng
2026-10-22  7:31 ` [PATCH v2 5/5] mm: hugetlb: enable CMA allocation for PMD-sized pages Qi Zheng
2026-10-22  9:05   ` Jose A. Perez de Azpillaga
2026-10-22  9:38     ` Qi Zheng

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=b37a33e2-7dfb-4401-847e-919f0bd61271@linux.dev \
    --to=qi.zheng@linux.dev \
    --cc=akpm@linux-foundation.org \
    --cc=azpijr@gmail.com \
    --cc=david@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=muchun.song@linux.dev \
    --cc=osalvador@suse.de \
    --cc=zhengqi.arch@bytedance.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®