RE: [PATCH v5 1/5] mm: move mirrored memory overlap checking to the outer loop
From: Liu, Yuan1
Date: Thu Jul 09 2026 - 23:20:05 EST
> >> -----Original Message-----
> >> From: David Hildenbrand (Arm) <david@xxxxxxxxxx>
> >> Sent: Thursday, June 25, 2026 8:05 PM
> >> To: Liu, Yuan1 <yuan1.liu@xxxxxxxxx>; Oscar Salvador
> <osalvador@xxxxxxx>;
> >> Mike Rapoport <rppt@xxxxxxxxxx>; Wei Yang <richard.weiyang@xxxxxxxxx>
> >> Cc: 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 5/20/26 11:34, 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.
> >>>
> >>> Reviewed-by: Wei Yang <richard.weiyang@xxxxxxxxx>
> >>> Reviewed-by: Jason Zeng <jason.zeng@xxxxxxxxx>
> >>> Signed-off-by: Yuan Liu <yuan1.liu@xxxxxxxxx>
> >>> ---
> >>
> >> IIRC, with the patch from Mike+Wei this patch here should no longer be
> >> required,
> >> right?
> >>
> >> https://lore.kernel.org/r/20260625073941.145014-1-rppt@xxxxxxxxxx
> >
> > Hi David
> >
> > Yes, we don't need the overlap-related patch anymore. The zone
> contiguity optimization will build on top of Mike's and Wei's changes, and
> I'll update the patches accordingly.
> >
> > These days I've been revisiting the issue where pages_with_online_memmap
> overcounts subsection hole pages in early sections.
> >
> > We previously attempted to address this with a patch [1], but I think
> the concern raised by Sashiko [2] is valid, so we may not be able to use
> patch [1].
> >
> > I can think of the following alternative approach, which can avoid
> changing semantics of pfn_valid() or first_valid_pfn():
> >
> > Basically we calculate pages_with_online_memmap by iterating over
> subsections in each zone during memmap_init(), to see
> pfn_to_online_page(start_pfn) is true or not.
> > If it is true, then the whole subsection will be counted into
> pages_with_online_memmap.
>
> We really should strive for a solution that doesn't walk any PFN ranges to
> perform a pfn_to_online_page().
Hi David
Yes, I agree with your point. So I am thinking a slightly changed approach.
Since every PFN within a memblock satisfies pfn_to_online_page(), we just need to align both boundary sides of a memblock to subsection size, and count pages in these memblock subsections.
A bit detailed description of the new approach:
1. Align the memblock boundaries to PAGES_PER_SUBSECTION when calculating how many online pages are actually covered by each memblock.
2. If the boundaries of two adjacent memblocks fall within the same subsection, exclude the overlapping pages to avoid double counting.
3. Keep the PFN range passed to init_unavailable_range() unchanged, so that all valid PFNs continue to be initialized.
I'd like to hear your thoughts on this approach first. If you agree, I'll prepare the next revision accordingly based on [1] changes
[1] "mm/mm_init: don't overlap zones with kernelcore=mirror"
https://git.kernel.org/pub/scm/linux/kernel/git/rppt/memblock.git/commit/?h=kernelcore-mirror&id=b69c2a1fa9beb4c3db24b4013e07f5cb7e7260aa
The relevant code is as follows:
+static void __init update_zone_online_memmap_pages(struct zone *zone,
+ unsigned long start_pfn,
+ unsigned long end_pfn,
+ unsigned long *hole_pfn)
+{
+#ifdef CONFIG_SPARSEMEM_VMEMMAP
+ unsigned long zone_start_pfn = zone->zone_start_pfn;
+ unsigned long zone_end_pfn = zone_start_pfn + zone->spanned_pages;
+ unsigned long sub_start, sub_end;
+
+ sub_start = max(ALIGN_DOWN(start_pfn, PAGES_PER_SUBSECTION), zone_start_pfn);
+ sub_end = min(ALIGN(end_pfn, PAGES_PER_SUBSECTION), zone_end_pfn);
+
+ /*
+ * For an in-zone hole smaller than a subsection, the adjacent
+ * memblock ranges share a subsection. Avoid counting the same
+ * subsection's pages twice.
+ */
+ if (*hole_pfn > zone_start_pfn) {
+ unsigned long prev_sub_end = min(ALIGN(*hole_pfn, PAGES_PER_SUBSECTION),
+ zone_end_pfn);
+ sub_start = max(sub_start, prev_sub_end);
+ }
+
+ if (sub_start < sub_end)
+ zone->pages_with_online_memmap += sub_end - sub_start;
+#else
+ zone->pages_with_online_memmap += end_pfn - start_pfn;
+#endif
+}
+
static void __init memmap_init_zone_range(struct zone *zone,
unsigned long start_pfn,
unsigned long end_pfn,
@@ -932,6 +963,8 @@ static void __init memmap_init_zone_range(struct zone *zone,
if (start_pfn >= end_pfn)
return;
+ update_zone_online_memmap_pages(zone, start_pfn, end_pfn, hole_pfn);
+
memmap_init_range(end_pfn - start_pfn, nid, zone_id, start_pfn,
zone_end_pfn, MEMINIT_EARLY, NULL, mt, false);
> --
> Cheers,
>
> David