Linux-mm Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2] mm/mm_init: fix out-of-range first_deferred_pfn
@ 2026-08-07  3:12 Alexander Graf
  2026-08-07  8:52 ` Mike Rapoport
  0 siblings, 1 reply; 2+ messages in thread
From: Alexander Graf @ 2026-08-07  3:12 UTC (permalink / raw)
  To: Andrew Morton, Mike Rapoport
  Cc: David Hildenbrand, Wei Yang, linux-mm, linux-kernel,
	nh-open-source

With CONFIG_DEFERRED_STRUCT_PAGE_INIT enabled, deferred_grow_zone()
undefers struct page ranges early in boot to satisfy an allocation.  With
a large CMA reservation in place, the ranges it finds may not add up to
the allocation it was asked for, and we end up undeferring all available
RAM and still fall short.  That is fine in itself: the function accounts
for it and leaves the caller to decide whether it now has enough memory.

The function also remembers where undeferring is to continue next, in
pgdat->first_deferred_pfn, and it walks in PAGES_PER_SECTION (128M)
chunks.  If the node's RAM does not end 128M aligned and we undeferred
everything, that "next" points past the end of the node's RAM.

deferred_init_memmap() later picks up from first_deferred_pfn and hits a
BUG_ON(), because it expects a pfn within its node:

  kernel BUG at mm/mm_init.c:2131!
  CPU: 3 UID: 0 PID: 36 Comm: pgdatinit0 Not tainted 7.2.0-rc6 #1
  RIP: 0010:deferred_init_memmap+0x1b8/0x1c0
  RAX: 0000000000236000 R13: 0000000000238000
  Call Trace:
   kthread+0xdf/0x120
   ret_from_fork+0x187/0x250

Detect the end of RAM in deferred_grow_zone() instead of assuming that
more deferral is always available.  When the walk leaves the zone (which
is where this node's RAM ends), record ULONG_MAX, the value that tells
deferred_init_memmap() the memory map is already initialized.

To reproduce with CONFIG_DEFERRED_STRUCT_PAGE_INIT=y and CONFIG_CMA=y:

  qemu-system-x86_64 -enable-kvm -m 8032M -kernel bzImage \
      -append "nokaslr cma=4768M@0x100000000"

The above command panics on every boot without this patch and boots
reliably with it applied.

Fixes: 3acb913c9d5b ("mm/mm_init: use deferred_init_memmap_chunk() in deferred_grow_zone()")
Cc: stable@vger.kernel.org
Assisted-by: Kiro:claude-opus-5
Signed-off-by: Alexander Graf <graf@amazon.com>
---

Notes:
    Changes since v1: changelog rewritten for readability per review feedback.
    No functional change; the diff is byte-identical to v1.
    
    v1: https://lore.kernel.org/linux-mm/20260805224421.15794-1-graf@amazon.com/
    
    Applies unchanged to 6.18.y, 6.19.y, 7.0.y and 7.1.y (checked against
    v6.18.39, v6.19.14, v7.0.14 and v7.1.4); the deferred_init_memmap_chunk()
    signature change in cbbbf7795fc3 sits outside the hunk context, so stable
    needs no separate backport.

 mm/mm_init.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/mm/mm_init.c b/mm/mm_init.c
index 498d62c4ece3..91177be58a00 100644
--- a/mm/mm_init.c
+++ b/mm/mm_init.c
@@ -2214,10 +2214,13 @@ bool __init deferred_grow_zone(struct zone *zone, unsigned int order)
 	}
 
 	/*
-	 * There were no pages to initialize and free which means the zone's
-	 * memory map is completely initialized.
+	 * The loop only tests spfn before entering an iteration, so on exit it
+	 * may point up to a section past the end of the zone.  When it does,
+	 * the rest of the zone has already been handed to
+	 * deferred_init_memmap_chunk() and nothing is left to initialize.
 	 */
-	pgdat->first_deferred_pfn = nr_pages ? spfn : ULONG_MAX;
+	pgdat->first_deferred_pfn =
+		spfn < zone_end_pfn(zone) ? spfn : ULONG_MAX;
 
 	pgdat_resize_unlock(pgdat, &flags);
 

base-commit: 0d839570765118029aa8bf4a95444c6a11aacf85
-- 
2.47.1



^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH v2] mm/mm_init: fix out-of-range first_deferred_pfn
  2026-08-07  3:12 [PATCH v2] mm/mm_init: fix out-of-range first_deferred_pfn Alexander Graf
@ 2026-08-07  8:52 ` Mike Rapoport
  0 siblings, 0 replies; 2+ messages in thread
From: Mike Rapoport @ 2026-08-07  8:52 UTC (permalink / raw)
  To: Andrew Morton, Alexander Graf
  Cc: Mike Rapoport, David Hildenbrand, Wei Yang, linux-mm,
	linux-kernel, nh-open-source

On Fri, 07 Aug 2026 03:12:43 +0000, Alexander Graf wrote:
> With CONFIG_DEFERRED_STRUCT_PAGE_INIT enabled, deferred_grow_zone()
> undefers struct page ranges early in boot to satisfy an allocation.  With
> a large CMA reservation in place, the ranges it finds may not add up to
> the allocation it was asked for, and we end up undeferring all available
> RAM and still fall short.  That is fine in itself: the function accounts
> for it and leaves the caller to decide whether it now has enough memory.
> 
> [...]

I reworded the code comment and the changelog even more and
applied to for-next branch of memblock.git tree, thanks!

[1/1] mm/mm_init: fix out-of-range first_deferred_pfn
      commit: 97090500d776c3f6d08e857e3a0a7cf092999094

tree: https://git.kernel.org/pub/scm/linux/kernel/git/rppt/memblock
branch: for-next

--
Sincerely yours,
Mike.



^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-08-07  8:52 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-07  3:12 [PATCH v2] mm/mm_init: fix out-of-range first_deferred_pfn Alexander Graf
2026-08-07  8:52 ` Mike Rapoport

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox