All of lore.kernel.org
 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: 18+ 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-23  6:35     ` Qi Zheng
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
2026-10-22  9:13   ` sashiko-bot

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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.