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. Note for reviewers: non-compound contiguous allocations are zeroed via kernel_init_pages, same as before this patch. There is no fault address because these allocations are not from the page fault path. For compound allocations, user_addr reaches post_alloc_hook() which calls folio_zero_user() with the dcache flush on cache-aliasing architectures. Note about Sashiko (sashiko.dev) false positives: sashiko flags two issues here: (1) user_addr silently ignored for non-compound allocations, and (2) post_alloc_hook ignores user_addr. Both are false positives: (1) non-compound contiguous allocations have no fault address to pass, and (2) post_alloc_hook does use user_addr when it is not USER_ADDR_NONE. Signed-off-by: Michael S. Tsirkin <[email protected]> Assisted-by: Claude:claude-opus-4-6 --- include/linux/gfp.h | 6 ++++++ mm/page_alloc.c | 42 ++++++++++++++++++++++++++++++++---------- 2 files changed, 38 insertions(+), 10 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 21b52c879751..6d3f284c607d 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -6975,13 +6975,15 @@ static void __free_contig_frozen_range(unsigned long pfn, unsigned long nr_pages } /** - * alloc_contig_frozen_range() -- tries to allocate given range of frozen pages + * __alloc_contig_frozen_range() -- tries to allocate given range of frozen pages * @start: start PFN to allocate * @end: one-past-the-last PFN to allocate * @alloc_flags: allocation information * @gfp_mask: GFP mask. Node/zone/placement hints are ignored; only some * action and reclaim modifiers are supported. Reclaim modifiers * control allocation behavior during compaction/migration/reclaim. + * @user_addr: user virtual address for cache-friendly zeroing, or + * USER_ADDR_NONE for kernel allocations. * * The PFN range does not have to be pageblock aligned. The PFN range must * belong to a single zone. @@ -6997,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; @@ -7125,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", @@ -7135,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); /** @@ -7227,14 +7237,16 @@ static bool zone_spans_last_pfn(const struct zone *zone, return zone_spans_pfn(zone, last_pfn); } -/** - * alloc_contig_frozen_pages() -- tries to find and allocate contiguous range of frozen pages +/* + * alloc_contig_frozen_pages_user_noprof() -- allocate contiguous frozen pages with user address * @nr_pages: Number of contiguous pages to allocate * @gfp_mask: GFP mask. Node/zone/placement hints limit the search; only some * action and reclaim modifiers are supported. Reclaim modifiers * control allocation behavior during compaction/migration/reclaim. * @nid: Target node * @nodemask: Mask for other possible nodes + * @user_addr: user virtual address for cache-friendly zeroing, or + * USER_ADDR_NONE for kernel allocations. * * This routine is a wrapper around alloc_contig_frozen_range(). It scans over * zones on an applicable zonelist to find a contiguous pfn range which can then @@ -7253,8 +7265,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; @@ -7282,10 +7295,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); @@ -7307,6 +7321,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

