Linux-mm Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: "Graf (AWS), Alexander" <graf@amazon.de>
To: Mike Rapoport <rppt@kernel.org>
Cc: Andrew Morton <akpm@linux-foundation.org>,
	David Hildenbrand <david@kernel.org>,
	Wei Yang <richard.weiyang@gmail.com>,
	"linux-mm@kvack.org" <linux-mm@kvack.org>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	"nh-open-source@amazon.com" <nh-open-source@amazon.com>
Subject: Re: [PATCH] mm/mm_init: fix out-of-range first_deferred_pfn
Date: Fri, 7 Aug 2026 02:43:35 +0000	[thread overview]
Message-ID: <cd2f3dbb-8a2e-4a5d-8705-e670aecb0762@amazon.com> (raw)
In-Reply-To: <anQf2kFzA63_3ayh@kernel.org>


On 06.08.26 07:47, Mike Rapoport wrote:
> Hi Alex,
>
> On Wed, Aug 05, 2026 at 10:44:21PM +0000, Alexander Graf wrote:
>> deferred_grow_zone() initializes deferred struct pages a section at a
>> time until the allocation that called into it can be satisfied, and
>> records where to resume in pgdat->first_deferred_pfn.  Reserve most of
>> the top zone early (a large CMA reservation is the easy way) and a single
>> early allocation has to walk the whole zone instead of stopping in its
>> first free section.  If that zone does not end on a section boundary, the
>> pgdatinit kthread then dies:
>>
>>    kernel BUG at mm/mm_init.c:2131!
>>    Oops: invalid opcode: 0000 [#1] SMP NOPTI
>>    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
>>
>> RAX is pgdat_end_pfn(), R13 the pfn that was stored.  The loop advances
>> spfn in whole PAGES_PER_SECTION steps and only tests it before entering
>> an iteration, so once the walk reaches the end of a zone that ends
>> mid-section the escaping spfn is SECTION_ALIGN_UP(zone_end_pfn()).
>> Commit 3acb913c9d5b ("mm/mm_init: use deferred_init_memmap_chunk() in
>> deferred_grow_zone()") dropped the clamp that used to prevent that: epfn
>> came from __next_mem_pfn_range_in_zone(), since removed, which capped it
>> with min(zone_end_pfn(zone), epfn), so spfn could reach zone_end_pfn but
>> never pass it.  The assert is fatal either way, panicking under
>> panic_on_oops and otherwise leaving page_alloc_init_late() waiting
>> forever for a completion the dead kthread never reports.
>>
>> Store ULONG_MAX once spfn has left the zone.  Nothing is left
>> uninitialized: the loop covers a single gap-free interval, and because it
>> only enters with spfn < zone_end_pfn() the escaping value is exactly
>> SECTION_ALIGN_UP(zone_end_pfn()), which is the last_pfn that
>> deferred_init_memmap() would have used for the same pfn range.  A zone
>> that does end section-aligned now takes this path too and loses its
>> zero-work padata job along with that node's pr_info() and the WARN_ON()
>> on the next zone.
>>
>> 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 only two paragraphs I understood is this and the BUG splat ;-P
>
> Can we please have a lot more of human touch on the changelog?


Fair callout. The patch description is truly awful :(. Please excuse the 
slop. I wanted to send this out quickly before it keeps collecting dust :).

The problem is that with CONFIG_DEFERRED_STRUCT_PAGE_INIT enabled, we 
undefer some struct page ranges early in boot in deferred_grow_zone(). 
With a large CMA allocation in place, the early allocation we can 
satisfy may not span the full desired allocation and we end up 
undeferring all available RAM and still not satisfy the fully targeted 
allocation. That is perfectly fine: The function accounts for that case 
and leaves it to the caller to determine whether it now has sufficient 
available memory.

However, the function *also* remembers where deferred allocation starts 
next (pgdat->first_deferred_pfn). And it does so based on 
PAGES_PER_SECTION (128M) chunks. If the node's RAM end is not 128M 
aligned and we undeferred everything, then that "next" points past end 
of the node's RAM end.

When later deferred_init_memmap() tries to pick up from 
first_deferred_pfn, it runs into a BUG_ON because it expects the pfn to 
be within its node's RAM range. The canary for "everything is already 
initialized" is ULONG_MAX.

Hence this patch modifies the check in deferred_grow_zone() to already 
properly detect end of RAM. Instead of assuming that there is always 
more deferral available, we cap it at end of zone (which is equivalent 
to end of this node's end of RAM).


Let me send a v2 with the description above.

Alex


      reply	other threads:[~2026-08-07  2:44 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-05 22:44 [PATCH] mm/mm_init: fix out-of-range first_deferred_pfn Alexander Graf
2026-08-06  5:47 ` Mike Rapoport
2026-08-07  2:43   ` Graf (AWS), Alexander [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=cd2f3dbb-8a2e-4a5d-8705-e670aecb0762@amazon.com \
    --to=graf@amazon.de \
    --cc=akpm@linux-foundation.org \
    --cc=david@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=nh-open-source@amazon.com \
    --cc=richard.weiyang@gmail.com \
    --cc=rppt@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox