[PATCH v9 08/37] mm: add alloc_contig_frozen_pages_user for cache-friendly zeroing

From: Michael S. Tsirkin

Date: Fri May 29 2026 - 12:11:42 EST


Add a _user variant of alloc_contig_frozen_pages that accepts a user_addr
parameter for cache-friendly zeroing of contiguous allocations.

No functional change; all existing callers continue to pass
USER_ADDR_NONE.

Signed-off-by: Michael S. Tsirkin <mst@xxxxxxxxxx>
Assisted-by: Claude:claude-opus-4-6
---
include/linux/gfp.h | 6 ++++++
mm/page_alloc.c | 32 +++++++++++++++++++++++++-------
2 files changed, 31 insertions(+), 7 deletions(-)

diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index ee35c5367abc..73109d4e31a4 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -453,6 +453,12 @@ struct page *alloc_contig_frozen_pages_noprof(unsigned long nr_pages,
#define alloc_contig_frozen_pages(...) \
alloc_hooks(alloc_contig_frozen_pages_noprof(__VA_ARGS__))

+struct page *alloc_contig_frozen_pages_user_noprof(unsigned long nr_pages,
+ gfp_t gfp_mask, int nid, nodemask_t *nodemask,
+ unsigned long user_addr);
+#define alloc_contig_frozen_pages_user(...) \
+ alloc_hooks(alloc_contig_frozen_pages_user_noprof(__VA_ARGS__))
+
struct page *alloc_contig_pages_noprof(unsigned long nr_pages, gfp_t gfp_mask,
int nid, nodemask_t *nodemask);
#define alloc_contig_pages(...) \
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index b96c9892f6c6..b725a3b59835 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -6999,8 +6999,9 @@ static void __free_contig_frozen_range(unsigned long pfn, unsigned long nr_pages
*
* Return: zero on success or negative error code.
*/
-int alloc_contig_frozen_range_noprof(unsigned long start, unsigned long end,
- acr_flags_t alloc_flags, gfp_t gfp_mask)
+static int __alloc_contig_frozen_range(unsigned long start, unsigned long end,
+ acr_flags_t alloc_flags, gfp_t gfp_mask,
+ unsigned long user_addr)
{
const unsigned int order = ilog2(end - start);
unsigned long outer_start, outer_end;
@@ -7127,7 +7128,7 @@ int alloc_contig_frozen_range_noprof(unsigned long start, unsigned long end,
struct page *head = pfn_to_page(start);

check_new_pages(head, order);
- prep_new_page(head, order, gfp_mask, 0, USER_ADDR_NONE);
+ prep_new_page(head, order, gfp_mask, 0, user_addr);
} else {
ret = -EINVAL;
WARN(true, "PFN range: requested [%lu, %lu), allocated [%lu, %lu)\n",
@@ -7137,6 +7138,13 @@ int alloc_contig_frozen_range_noprof(unsigned long start, unsigned long end,
undo_isolate_page_range(start, end);
return ret;
}
+
+int alloc_contig_frozen_range_noprof(unsigned long start, unsigned long end,
+ acr_flags_t alloc_flags, gfp_t gfp_mask)
+{
+ return __alloc_contig_frozen_range(start, end, alloc_flags, gfp_mask,
+ USER_ADDR_NONE);
+}
EXPORT_SYMBOL(alloc_contig_frozen_range_noprof);

/**
@@ -7255,8 +7263,9 @@ static bool zone_spans_last_pfn(const struct zone *zone,
*
* Return: pointer to contiguous frozen pages on success, or NULL if not successful.
*/
-struct page *alloc_contig_frozen_pages_noprof(unsigned long nr_pages,
- gfp_t gfp_mask, int nid, nodemask_t *nodemask)
+struct page *alloc_contig_frozen_pages_user_noprof(unsigned long nr_pages,
+ gfp_t gfp_mask, int nid, nodemask_t *nodemask,
+ unsigned long user_addr)
{
unsigned long ret, pfn, flags;
struct zonelist *zonelist;
@@ -7284,10 +7293,11 @@ struct page *alloc_contig_frozen_pages_noprof(unsigned long nr_pages,
* win the race and cause allocation to fail.
*/
spin_unlock_irqrestore(&zone->lock, flags);
- ret = alloc_contig_frozen_range_noprof(pfn,
+ ret = __alloc_contig_frozen_range(pfn,
pfn + nr_pages,
ACR_FLAGS_NONE,
- gfp_mask);
+ gfp_mask,
+ user_addr);
if (!ret)
return pfn_to_page(pfn);
spin_lock_irqsave(&zone->lock, flags);
@@ -7309,6 +7319,14 @@ struct page *alloc_contig_frozen_pages_noprof(unsigned long nr_pages,
}
return NULL;
}
+EXPORT_SYMBOL(alloc_contig_frozen_pages_user_noprof);
+
+struct page *alloc_contig_frozen_pages_noprof(unsigned long nr_pages,
+ gfp_t gfp_mask, int nid, nodemask_t *nodemask)
+{
+ return alloc_contig_frozen_pages_user_noprof(nr_pages, gfp_mask, nid,
+ nodemask, USER_ADDR_NONE);
+}
EXPORT_SYMBOL(alloc_contig_frozen_pages_noprof);

/**
--
MST