This series introduces a pages_with_online_memmap member into struct
zone to avoid pageblock-by-pageblock scans across the entire zone and
improve memory hotplug performance.
Reworked how pages_with_online_memmap accounts for PFNs in early
boot memory in response to Sashiko's review comments [2], which
identified potential issues with the previous implementation.
Approach
========
Add a new zone member pages_with_online_memmap that tracks the number of
pages within the zone span that have an online memory map (including
present pages and memory holes smaller than a subsection whose memory
map has been initialized). When spanned_pages == pages_with_online_memmap
the zone is contiguous and pfn_to_page() can be called on any PFN in the
zone span without further pfn_valid() checks.
For early boot memory, pages_with_online_memmap is calculated in
memmap_init_zone_range(). Since every PFN within a memblock region
satisfies pfn_to_online_page(), the calculation aligns both boundaries
of each memblock range to PAGES_PER_SUBSECTION and counts the aligned
pages that fall within the zone span. If two adjacent memblock regions
share a subsection (i.e. the hole between them is smaller than a
subsection), the overlapping subsection pages are counted only once.
For hotplugged memory, pages_with_online_memmap is updated through
adjust_present_page_count(), which is called during memory online and
offline.
Only pages that fall within the current zone span are accounted towards
pages_with_online_memmap. A "too small" value is safe, it merely
prevents detecting a contiguous zone.
The contiguity check using pages_with_online_memmap is stricter than the
old pageblock-by-pageblock scan. The old set_zone_contiguous() iterated
at pageblock granularity via pageblock_pfn_to_page(), so a zone could be
marked contiguous even if a subsection-sized hole existed within a
pageblock. The new check requires spanned_pages == pages_with_online_memmap,
meaning every PFN in the zone span must satisfy pfn_to_online_page().
Performance
===========
1. For VM hotplug performance data, please refer to Patch 1.
2. This series also benefits CXL hotplug. Performance results are
as follows
https://lore.kernel.org/all/20260409023552.GA2807@AE/
Tested cases
============
1. Hotplug/unplug correctness with both online_movable and online
policies, including partial unplug, middle-block offline gaps, and
edge-block span shrink.
2. Large scale (256G/512G) plug/unplug performance.
3. Boot-time subsection holes (aligned/unaligned, in-zone and
cross-zone) with correct pages_with_online_memmap accounting.
4. kernelcore=mirror: verified no overcounting.
Patch overview
==============
This series is based on the kernelcore-mirror branch [1].
Patch 1 introduces pages_with_online_memmap to replace
pageblock-by-pageblock scans across the entire zone for zone contiguity
checks.
Patch 2 avoids incorrectly shrinking the zone span during memory unplug
when a memory or hole boundary falls in the middle of a subsection.
v6 changes:
1. Dropped patches 1-3 from v5. The kernelcore=mirror overlap issue
that caused pages_with_online_memmap to be overcounted has been
resolved by the series [1].
2. Reworked pages_with_online_memmap accounting during early boot.
v5:
https://lore.kernel.org/linux-mm/20260520093457.3719960-1-yuan1.liu@intel.com/
v4:
https://lore.kernel.org/linux-mm/20260421125508.2317429-1-yuan1.liu@intel.com/
v3:
https://lore.kernel.org/linux-mm/20260408031615.1831922-1-yuan1.liu@intel.com/
[1] https://git.kernel.org/pub/scm/linux/kernel/git/rppt/memblock.git/log/?h=kernelcore-mirror
[2] https://sashiko.dev/#/patchset/20260520093457.3719960-3-yuan1.liu@intel.com
Yuan Liu (2):
mm/memory_hotplug: optimize zone contiguous check when changing pfn
range
mm/memory_hotplug: improve shrink_zone_span() subsection boundary
checks
Documentation/mm/physical_memory.rst | 13 +++++++
drivers/base/memory.c | 6 +++
include/linux/mmzone.h | 47 ++++++++++++++++++++++
mm/internal.h | 8 +---
mm/memory_hotplug.c | 54 ++++++++++++++------------
mm/mm_init.c | 58 +++++++++++++++++-----------
6 files changed, 132 insertions(+), 54 deletions(-)
base-commit: b69c2a1fa9beb4c3db24b4013e07f5cb7e7260aa
--
2.47.3