On Mon, Jun 08, 2026 at 04:36:38AM -0400, Michael S. Tsirkin wrote:
> When post_alloc_hook() needs to zero a page for an explicit
> __GFP_ZERO allocation for a user page (user_addr is set), use
> folio_zero_user()
> instead of kernel_init_pages(). This zeros near the faulting
> address last, keeping those cachelines hot for the impending
> user access.
>
> folio_zero_user() is only used for explicit __GFP_ZERO, not for
> init_on_alloc. On architectures with virtually-indexed caches
> (e.g., ARM), clear_user_highpage() performs per-line cache
> operations; using it for init_on_alloc would add overhead that
> kernel_init_pages() avoids (the page fault path flushes the
> cache at PTE installation time regardless).
>
> No functional change yet: current callers do not pass __GFP_ZERO
> for user pages (they zero at the callsite instead). Subsequent
> patches will convert them.
>
> Signed-off-by: Michael S. Tsirkin <[email protected]>
> Assisted-by: Claude:claude-opus-4-6
> ---
> mm/page_alloc.c | 35 ++++++++++++++++++++++++++++++++---
> 1 file changed, 32 insertions(+), 3 deletions(-)
>
> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> index 4676fd49819e..d4fbf1861a8a 100644
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
> @@ -1861,9 +1861,38 @@ inline void post_alloc_hook(struct page *page,
> unsigned int order,
> for (i = 0; i != 1 << order; ++i)
> page_kasan_tag_reset(page + i);
> }
> - /* If memory is still not initialized, initialize it now. */
> - if (init)
> - kernel_init_pages(page, 1 << order);
> + /*
> + * On architectures with cache aliasing, pages zeroed via the
> + * kernel direct map (e.g. init_on_free) must be re-zeroed
> + * through a user-congruent mapping. Host-zeroed pages
> + * (zeroed flag) don't need this: physical RAM is clean.
> + */
> + if (!init && (gfp_flags & __GFP_ZERO) &&
> + user_addr != USER_ADDR_NONE &&
> + user_alloc_needs_zeroing())
We check this (gfp_flags & __GFP_ZERO) && user_addr != USER_ADDR_NONE thing
twice, can we just put in a 'init_should_folio_zero' const bool or something?
> + init = true;
As Vlasta says not sure if we want to add complexity just for these arches.
> + /*
> + * If memory is still not initialized, initialize it now.
I kinda hate that 'init' is unclear as to 'do init' or 'was init somewhere
else'... Anwyay.
> + * When __GFP_ZERO was explicitly requested and user_addr is set,
> + * use folio_zero_user() which zeros near the faulting address
> + * last, keeping those cachelines hot. For init_on_alloc, use
> + * kernel_init_pages() to avoid unnecessary cache flush overhead
> + * on architectures with virtually-indexed caches.
This whole paragraph seems pretty useless and just describing the code?
> + */
> + if (init) {
> + if ((gfp_flags & __GFP_ZERO) && user_addr != USER_ADDR_NONE) {
> + /*
> + * folio_zero_user relies on folio_nr_pages which
> + * requires __GFP_COMP for order > 0. All user folio
> + * allocations set __GFP_COMP via __folio_alloc.
This whole paragraph is useless and very like the kind of stuff AI generates for
comments, i.e. overly long + entirely unnecessary stuff.
> + * user_addr != USER_ADDR_NONE implies sleepable
> + * context (user page fault).
Can you safely assume that? Also inferring which context we are in from this
parameter seems risky.
It seems to me that you're now making it such that kernel developers:
- Have to know when and when not to specify a user address, and under what
circumstances we might consider that to be mapped.
- Need to know to do this correctly for aliasing architectures or have silent
correctness issues.
- Need to take context into account when specifying this.
We definitely need to find a simpler way to do this!
> + */
> + VM_WARN_ON_ONCE(order && !(gfp_flags & __GFP_COMP));
Surely by now we can assume this?
> + folio_zero_user(page_folio(page), user_addr);
> + } else
> + kernel_init_pages(page, 1 << order);
I hate this hanging else branch... definitely prefer {} on both branches.
But in any case it seems like we could avoid some indentation with something
like:
if (init && init_should_folio_zero) {
...
} else if (init) {
...
}
Or even a:
if (!init)
goto out;
And stick an out label below?
> + }
>
> set_page_owner(page, order, gfp_flags);
> page_table_check_alloc(page, order);
> --
> MST
>
Oh and in general it seems that this conflicts with [0] which removes
kernel_init_pages().
[0];https://lore.kernel.org/all/[email protected]/
Thanks, Lorenzo