mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Muchun Song <muchun.song@linux.dev>
To: Qi Zheng <qi.zheng@linux.dev>
Cc: linux-mm@kvack.org, linux-kernel@vger.kernel.org,
	Qi Zheng <zhengqi.arch@bytedance.com>,
	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: Thu, 22 Oct 2026 19:21:49 +0800	[thread overview]
Message-ID: <b5745b31-adec-4158-bba4-2c21dbfe2566@linux.dev> (raw)
In-Reply-To: <29b35f7221c30f1dfa320a933f6095f37b612a37.1792651104.git.zhengqi.arch@bytedance.com>



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[]?

> +
> +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()?

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

PMD_ORDER is better.

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

> +		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?

> +
> +	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.

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)


  parent reply	other threads:[~2026-10-22 11:22 UTC|newest]

Thread overview: 13+ 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 [this message]
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-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=b5745b31-adec-4158-bba4-2c21dbfe2566@linux.dev \
    --to=muchun.song@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=osalvador@suse.de \
    --cc=qi.zheng@linux.dev \
    --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®