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)
>
next prev parent 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®