Re: [PATCH v4 3/3] mm: hugetlb: fix GFP mask propagation to CMA
From: Kefeng Wang
Date: Thu Nov 12 2026 - 06:35:39 EST
On 11/11/2026 2:46 PM, Qi Zheng wrote:
From: Qi Zheng <zhengqi.arch@xxxxxxxxxxxxx>
cma_alloc_frozen_compound() uses GFP_KERNEL, allowing direct reclaim
during the first MPOL_PREFERRED_MANY allocation attempt even though
the caller clears __GFP_DIRECT_RECLAIM.
MPOL_PREFERRED_MANY is only used for the partner allocator. Without your
patches "mm: hugetlb: add CMA support for PMD-sized pages,"
cma_alloc_frozen_compound() is only used for huge page allocations. In
this case, I think we don't need the gfp flag, which is why I hardcoded
it, so there's no need for the Fixes tag; this patch should be part of
your new feature. Maybe I missed something?
Pass the caller's GFP mask through the helper so CMA respects its
reclaim constraints when trying the preferred nodes.
Fixes: 9bda131c6093 ("mm: cma: add cma_alloc_frozen{_compound}()")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Qi Zheng <zhengqi.arch@xxxxxxxxxxxxx>
Acked-by: Muchun Song <muchun.song@xxxxxxxxx>
Reviewed-by: Jose A. Perez de Azpillaga <azpijr@xxxxxxxxx>
Reviewed-by: Oscar Salvador (SUSE) <osalvador@xxxxxxxxxx>
---
include/linux/cma.h | 2 +-
mm/cma.c | 10 ++++++++--
mm/hugetlb_cma.c | 4 ++--
3 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/include/linux/cma.h b/include/linux/cma.h
index 8555d38a97b1a..4539ea5f2c4e8 100644
--- a/include/linux/cma.h
+++ b/include/linux/cma.h
@@ -53,7 +53,7 @@ extern bool cma_release(struct cma *cma, const struct page *pages, unsigned long
struct page *cma_alloc_frozen(struct cma *cma, unsigned long count,
unsigned int align, bool no_warn);
-struct page *cma_alloc_frozen_compound(struct cma *cma, unsigned int order);
+struct page *cma_alloc_frozen_compound(struct cma *cma, unsigned int order, gfp_t gfp);
bool cma_release_frozen(struct cma *cma, const struct page *pages,
unsigned long count);
diff --git a/mm/cma.c b/mm/cma.c
index 9ec1d1fd5dff5..a7c47c0e7d070 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -933,9 +933,15 @@ struct page *cma_alloc_frozen(struct cma *cma, unsigned long count,
return __cma_alloc_frozen(cma, count, align, gfp);
}
-struct page *cma_alloc_frozen_compound(struct cma *cma, unsigned int order)
+struct page *cma_alloc_frozen_compound(struct cma *cma, unsigned int order, gfp_t gfp)
{
- gfp_t gfp = GFP_KERNEL | __GFP_COMP | __GFP_NOWARN;
+ /*
+ * The only caller of cma_alloc_frozen_compound() is hugetlb, and
+ * hugetlb constructs its gfp mask via htlb_alloc_mask(), which already
+ * sets __GFP_COMP. Check here for usecases bypassing htlb_alloc_mask().
+ */
+ if (WARN_ON_ONCE(!(gfp & __GFP_COMP)))
+ return NULL;
return __cma_alloc_frozen(cma, 1 << order, order, gfp);
}
diff --git a/mm/hugetlb_cma.c b/mm/hugetlb_cma.c
index cd6a64986278a..3e5a30571524a 100644
--- a/mm/hugetlb_cma.c
+++ b/mm/hugetlb_cma.c
@@ -69,14 +69,14 @@ struct folio *hugetlb_cma_alloc_frozen_folio(int order, gfp_t gfp_mask,
}
if (hugetlb_cma[nid] && node_isset(nid, *nmask))
- page = cma_alloc_frozen_compound(hugetlb_cma[nid], order);
+ page = cma_alloc_frozen_compound(hugetlb_cma[nid], order, gfp_mask);
if (!page && !(gfp_mask & __GFP_THISNODE)) {
for_each_node_mask(node, *nmask) {
if (node == nid || !hugetlb_cma[node])
continue;
- page = cma_alloc_frozen_compound(hugetlb_cma[node], order);
+ page = cma_alloc_frozen_compound(hugetlb_cma[node], order, gfp_mask);
if (page)
break;
}