Re: [PATCH v10 2/2] mm/memory_hotplug: optimize zone contiguous check when changing pfn range
From: Wei Yang
Date: Tue Sep 22 2026 - 09:25:06 EST
On Sun, Sep 20, 2026 at 04:49:46AM -0400, Yuan Liu wrote:
>When move_pfn_range_to_zone() or remove_pfn_range_from_zone() updates a
>zone, set_zone_contiguous() rescans the entire zone pageblock-by-pageblock
>to rebuild zone->contiguous. For large zones this is a significant cost
>during memory hotplug and hot-unplug.
>
>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 whose memory map has been
>initialized and for which pfn_to_online_page() succeeds.
>
>For early boot memory, pages_with_online_memmap is calculated in
>memmap_init_zone_range(). PFNs initialized by memmap_init_range() are
>included in pages_with_online_memmap, and hole PFNs for which
>pfn_to_online_page() succeeds are also counted in
>init_unavailable_range(). For hotplugged memory,
>pages_with_online_memmap is updated through adjust_present_page_count(),
>which is called during memory online and offline operations. When
>spanned_pages == pages_with_online_memmap, every PFN in the zone span
>has a valid memmap entry, so pfn_to_page() can be called for any PFN
>within the zone span without an additional pfn_valid() check.
>
>Note: this counter may temporarily undercount when pages with an
>online memory map exist outside the current zone span. Such pages
>are only created during boot, when initializing the memory map of
>pages that do not fall into any zone span. The undercount itself
>can only happen after boot, during memory hotplug, when growing
>the zone to cover such pages and later shrinking it back, which
>may result in a "too small" value. This is safe: it merely
>prevents detecting a contiguous zone.
>
>Here is an example (page numbers are just for illustration purposes):
> after boot:
> [ zone span ]
> [ zone pages ]
> spanned=10, initialized=15, online=10
> online == spanned -> contiguous
>
> growing after hotplug (hotplug 5):
> [ zone span ]
> [ zone pages ] [ zone pages ]
> spanned=30, initialized=20, online=15
> online != spanned -> not contiguous
>
> shrinking after hotunplug (hotunplug 5 again):
> [ zone span ]
> [ zone pages ]
> spanned=15, initialized=15, online=10
> online != spanned -> not contiguous although contiguous
>
>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().
>
>The following test cases of memory hotplug for a VM [1], tested in the
>environment [2], show that this optimization can significantly reduce the
>memory hotplug time [3].
>
>+----------------+------+---------------+--------------+----------------+
>| | Size | Time (before) | Time (after) | Time Reduction |
>| +------+---------------+--------------+----------------+
>| Plug Memory | 256G | 10s | 3s | 70% |
>| +------+---------------+--------------+----------------+
>| | 512G | 36s | 7s | 81% |
>+----------------+------+---------------+--------------+----------------+
>
>+----------------+------+---------------+--------------+----------------+
>| | Size | Time (before) | Time (after) | Time Reduction |
>| +------+---------------+--------------+----------------+
>| Unplug Memory | 256G | 11s | 4s | 64% |
>| +------+---------------+--------------+----------------+
>| | 512G | 36s | 9s | 75% |
>+----------------+------+---------------+--------------+----------------+
>
>[1] Qemu commands to hotplug 256G/512G memory for a VM:
> object_add memory-backend-ram,id=hotmem0,size=256G/512G,share=on
> device_add virtio-mem-pci,id=vmem1,memdev=hotmem0,bus=port1
> qom-set vmem1 requested-size 256G/512G (Plug Memory)
> qom-set vmem1 requested-size 0G (Unplug Memory)
>
>[2] Hardware : Intel Icelake server
> Guest Kernel : v7.3-rc3
> Qemu : v9.0.0
>
> Launch VM :
> qemu-system-x86_64 -accel kvm -cpu host \
> -drive file=./Centos10_cloud.qcow2,format=qcow2,if=virtio \
> -drive file=./seed.img,format=raw,if=virtio \
> -smp 3,cores=3,threads=1,sockets=1,maxcpus=3 \
> -m 2G,slots=10,maxmem=2052472M \
> -device pcie-root-port,id=port1,bus=pcie.0,slot=1,multifunction=on \
> -device pcie-root-port,id=port2,bus=pcie.0,slot=2 \
> -nographic -machine q35 \
> -nic user,hostfwd=tcp::3000-:22
>
> Guest kernel auto-onlines newly added memory blocks:
> echo online > /sys/devices/system/memory/auto_online_blocks
>
>[3] The time from typing the QEMU commands in [1] to when the output of
> 'grep MemTotal /proc/meminfo' on Guest reflects that all hotplugged
> memory is recognized.
>
>Reported-by: Nanhai Zou <nanhai.zou@xxxxxxxxx>
>Reported-by: Chen Zhang <zhangchen.kidd@xxxxxx>
>Tested-by: Yuan Liu <yuan1.liu@xxxxxxxxx>
>Reviewed-by: Jason Zeng <jason.zeng@xxxxxxxxx>
>Reviewed-by: Chen Yu <yu.c.chen@xxxxxxxxx>
>Reviewed-by: Pan Deng <pan.deng@xxxxxxxxx>
>Co-developed-by: Tianyou Li <tianyou.li@xxxxxxxxx>
>Signed-off-by: Tianyou Li <tianyou.li@xxxxxxxxx>
>Signed-off-by: Yuan Liu <yuan1.liu@xxxxxxxxx>
>Acked-by: Mike Rapoport (Microsoft) <rppt@xxxxxxxxxx>
LGTM, thanks for the effort.
Reviewed-by: Wei Yang <richard.weiyang@xxxxxxxxx>
--
Wei Yang
Help you, Help me