Re: [PATCH v5 1/5] mm: move mirrored memory overlap checking to the outer loop

From: Wei Yang

Date: Thu Jun 11 2026 - 22:44:13 EST


On Tue, Jun 02, 2026 at 07:55:11AM +0000, Liu, Yuan1 wrote:
>> -----Original Message-----
>> From: Wei Yang <richard.weiyang@xxxxxxxxx>
>> Sent: Monday, May 25, 2026 4:36 PM
>> To: Liu, Yuan1 <yuan1.liu@xxxxxxxxx>
>> Cc: Wei Yang <richard.weiyang@xxxxxxxxx>; David Hildenbrand
>> <david@xxxxxxxxxx>; Oscar Salvador <osalvador@xxxxxxx>; Mike Rapoport
>> <rppt@xxxxxxxxxx>; linux-mm@xxxxxxxxx; Hu, Yong <yong.hu@xxxxxxxxx>; Zou,
>> Nanhai <nanhai.zou@xxxxxxxxx>; Tim Chen <tim.c.chen@xxxxxxxxxxxxxxx>;
>> Zhuo, Qiuxu <qiuxu.zhuo@xxxxxxxxx>; Chen, Yu C <yu.c.chen@xxxxxxxxx>;
>> Deng, Pan <pan.deng@xxxxxxxxx>; Li, Tianyou <tianyou.li@xxxxxxxxx>; Chen
>> Zhang <zhangchen.kidd@xxxxxx>; Zeng, Jason <jason.zeng@xxxxxxxxx>; linux-
>> kernel@xxxxxxxxxxxxxxx
>> Subject: Re: [PATCH v5 1/5] mm: move mirrored memory overlap checking to
>> the outer loop
>>
>> On Fri, May 22, 2026 at 07:43:38AM +0000, Liu, Yuan1 wrote:
>> >> Subject: Re: [PATCH v5 1/5] mm: move mirrored memory overlap checking
>> to
>> >> the outer loop
>> >>
>> >> On Wed, May 20, 2026 at 05:34:53AM -0400, Yuan Liu wrote:
>> >> >Move the overlap memmap initialization check from memmap_init_range()
>> >> >to memmap_init(), and replace the per-PFN check with a memblock-based
>> >> >check.
>> >>
>> >> The description is a little simple.
>> >>
>> >> Even I know the purpose, I feel confused at the first glance.
>> >
>> >Thanks for the review.
>> >I will try to rephrase it and provide a clearer description in the next
>> version.
>> >
>> >> >
>> >> >Reviewed-by: Wei Yang <richard.weiyang@xxxxxxxxx>
>> >> >Reviewed-by: Jason Zeng <jason.zeng@xxxxxxxxx>
>> >> >Signed-off-by: Yuan Liu <yuan1.liu@xxxxxxxxx>
>> >> >---
>> >> > mm/mm_init.c | 29 +++++------------------------
>> >> > 1 file changed, 5 insertions(+), 24 deletions(-)
>> >> >
>> >> >diff --git a/mm/mm_init.c b/mm/mm_init.c
>> >> >index f9f8e1af921c..24e103a402b0 100644
>> >> >--- a/mm/mm_init.c
>> >> >+++ b/mm/mm_init.c
>> >> >@@ -783,28 +783,6 @@ void __meminit init_deferred_page(unsigned long
>> pfn,
>> >> int nid)
>> >> > __init_deferred_page(pfn, nid);
>> >> > }
>> >> >
>> >> >-/* If zone is ZONE_MOVABLE but memory is mirrored, it is an
>> overlapped
>> >> init */
>> >> >-static bool __meminit
>> >> >-overlap_memmap_init(unsigned long zone, unsigned long *pfn)
>> >> >-{
>> >> >- static struct memblock_region *r __meminitdata;
>> >> >-
>> >> >- if (mirrored_kernelcore && zone == ZONE_MOVABLE) {
>> >> >- if (!r || *pfn >= memblock_region_memory_end_pfn(r)) {
>> >> >- for_each_mem_region(r) {
>> >> >- if (*pfn < memblock_region_memory_end_pfn(r))
>> >> >- break;
>> >> >- }
>> >> >- }
>> >> >- if (*pfn >= memblock_region_memory_base_pfn(r) &&
>> >> >- memblock_is_mirror(r)) {
>> >> >- *pfn = memblock_region_memory_end_pfn(r);
>> >> >- return true;
>> >> >- }
>> >> >- }
>> >> >- return false;
>> >> >-}
>> >> >-
>> >> > /*
>> >> > * Only struct pages that correspond to ranges defined by
>> >> memblock.memory
>> >> > * are zeroed and initialized by going through __init_single_page()
>> >> during
>> >> >@@ -891,8 +869,6 @@ void __meminit memmap_init_range(unsigned long
>> size,
>> >> int nid, unsigned long zone
>> >> > * function. They do not exist on hotplugged memory.
>> >> > */
>> >> > if (context == MEMINIT_EARLY) {
>> >> >- if (overlap_memmap_init(zone, &pfn))
>> >> >- continue;
>> >> > if (defer_init(nid, pfn, zone_end_pfn)) {
>> >> > deferred_struct_pages = true;
>> >> > break;
>> >> >@@ -956,6 +932,7 @@ static void __init memmap_init(void)
>> >> > int i, j, zone_id = 0, nid;
>> >> >
>> >> > for_each_mem_pfn_range(i, MAX_NUMNODES, &start_pfn, &end_pfn, &nid)
>> >> {
>> >> >+ struct memblock_region *r = &memblock.memory.regions[i];
>> >> > struct pglist_data *node = NODE_DATA(nid);
>> >> >
>> >> > for (j = 0; j < MAX_NR_ZONES; j++) {
>> >> >@@ -964,6 +941,10 @@ static void __init memmap_init(void)
>> >> > if (!populated_zone(zone))
>> >> > continue;
>> >> >
>> >> >+ if (mirrored_kernelcore && j == ZONE_MOVABLE &&
>> >> >+ memblock_is_mirror(r))
>> >> >+ continue;
>> >> >+
>> >>
>> >> So you have figured out the memory layout of mirror memory?
>> >>
>> >> Would you mind elaborate?
>> >
>> >I have a Xeon server, collected mirror memory layout information as below
>> by using follow changes:
>> >
>> >int __init_memblock memblock_mark_mirror(phys_addr_t base, phys_addr_t
>> size)
>> > {
>> >- if (!mirrored_kernelcore)
>> >+ int ret;
>> >+ phys_addr_t end = base + size - 1;
>> >+
>> >+ pr_info("memblock_mark_mirror: base=%pa, size=%pa,
>> mirrored_kernelcore=%d\n",
>> >+ &base, &size, mirrored_kernelcore);
>> >+
>> >+ if (!mirrored_kernelcore) {
>> >+ pr_info("memblock_mark_mirror: mirrored_kernelcore not
>> enabled, skipping\n");
>> > return 0;
>> >+ }
>> >
>> > system_has_some_mirror = true;
>> >
>> >- return memblock_setclr_flag(&memblock.memory, base, size, 1,
>> MEMBLOCK_MIRROR);
>> >+ ret = memblock_setclr_flag(&memblock.memory, base, size, 1,
>> MEMBLOCK_MIRROR);
>> >+ pr_info("memblock_mark_mirror: marked [%pa-%pa] as MIRROR,
>> ret=%d\n",
>> >+ &base, &end, ret);
>> >+ return ret;
>> > }
>> >
>> >Here is the detailed layout information:
>> >
>>
>> Thanks for the detailed output.
>>
>> After some investigation, I got two things to discuss here:
>>
>> * current mirror memory would disable memmap defer init
>> * confirm the mirror memory layout and may simplify handling
>>
>> Before discussion, let me mark the key point in the output below.
>>
>> >Case 1: efibootmgr -m t -M 0
>> >Enable mirror memory below 4GB, and no mirror memory above 4G
>> >
>> >=== zoneinfo summary ===
>> >node zone start_pfn end_pfn start_addr end_addr
>> >------ ---------- ------------ ------------ ------------------ ----------
>> ---
>> >0 DMA 0x1 0xfff 0x1000 0xffffff
>> >0 DMA32 0x1000 0xfffff 0x1000000 0xffffffff
>> >0 Normal 0x100000 0x7fbffff 0x100000000 0x7fbfffffff
>> >0 Movable 0x140000 0x7fbffff 0x140000000 0x7fbfffffff
>>
>> (1) Normal and Movable zone end with the same address, so overlapped.
>>
>> >1 Normal 0x7fc0000 0xff7ffff 0x7fc0000000
>> 0xff7fffffff
>> >1 Movable 0x8000000 0xff7ffff 0x8000000000
>> 0xff7fffffff
>>
>> The same as (1).
>>
>> >
>> >node start end size flags mirror pfn_range
>> >---- -------------------- -------------------- ------------ ------------ --- -------- ------------------
>> >0 0x0000000000001000 0x000000000009dfff 0x000000000009d000 0x2 yes 0x1-0x9e
>> >0 0x000000000009f000 0x000000000009ffff 0x0000000000001000 0x2 yes 0x9f-0xa0
>> >0 0x0000000000100000 0x0000000066416fff 0x0000000066317000 0x2 yes 0x100-0x66417
>> >0 0x00000000777ff000 0x00000000777fffff 0x0000000000001000 0x2 yes 0x777ff-0x77800
>> >0 0x0000000100000000 0x000000013fffffff 0x0000000040000000 0x2 yes 0x100000-0x140000
>>
>> (2) You mentioned no mirror memory above 4G. If my understanding is
>> correct, 4G's
>> address is 0x100000000. So why this range is marked mirror? Is there some
>> limitation for this?
>
>Hi Wei
>
>efibootmgr enables mirror memory below 4 GB through the -m (--mirror-below-4G)
>option, and configures the percentage of memory to be mirrored above 4 GB through
>the -M (--mirror-above-4G) option.
>

The efibootmgr command used here is: efibootmgr -m t -M 0

This means we expect it configure 0% memory to be mirrored above 4G. But we
see the range [0x100000000, 0x13ffffff] is mirrored, which is above 4G.

Also for the range in node 1, we have mirrored memory.

So I am afraid the behavior is not what it literally means. Or I missed
something?

While more critical thing to confirm is ...

>My understanding is that the layout of mirrored memory is determined by the BIOS.

... after the BIOS configuration, kernel would only see
contiguous mirrored memory for each NUMA node, right? So that we could handle
mirrored memory correctly.

BTW, I mentioned two issues in last reply:

* error on node span calculation
* defer_init misbehavior with mirrored memory

Have you checked about it? Is my finding reasonable?

--
Wei Yang
Help you, Help me