RE: [PATCH v6 1/2] mm/memory_hotplug: optimize zone contiguous check when changing pfn range
"Liu, Yuan1" <[email protected]>
| Newsgroups | org.kernel.vger.linux-kernel,org.kvack.linux-mm |
|---|---|
| Message-ID | <PH7PR11MB6932A554A6D18A4F1A29E90DA3D22@PH7PR11MB6932.namprd11.prod.outlook.com> |
> -----Original Message----- > From: David Hildenbrand (Arm) <[email protected]> > Sent: Wednesday, August 5, 2026 7:53 PM > To: Liu, Yuan1 <[email protected]>; Oscar Salvador <[email protected]>; > Mike Rapoport <[email protected]>; Wei Yang <[email protected]> > Cc: [email protected]; Zou, Nanhai <[email protected]>; Deng, Pan > <[email protected]>; Li, Tianyou <[email protected]>; Chen Zhang > <[email protected]>; Zeng, Jason <[email protected]>; linux- > [email protected] > Subject: Re: [PATCH v6 1/2] mm/memory_hotplug: optimize zone contiguous > check when changing pfn range > [...] > > > > diff --git a/Documentation/mm/physical_memory.rst > b/Documentation/mm/physical_memory.rst > > index b76183545e5b..0aa65e6b5499 100644 > > --- a/Documentation/mm/physical_memory.rst > > +++ b/Documentation/mm/physical_memory.rst > > @@ -483,6 +483,19 @@ General > > ``present_pages`` should use ``get_online_mems()`` to get a stable > value. It > > is initialized by ``calculate_node_totalpages()``. > > > > +``pages_with_online_memmap`` > > + Tracks pages within the zone that have an online memory map (present > pages > > + and memory holes whose memory map has been initialized). When > > + ``spanned_pages`` == ``pages_with_online_memmap``, ``pfn_to_page()`` > can be > > + performed without further checks on any PFN within the zone span. > > + > > + Note: this counter may temporarily undercount when pages with an > online > > + memory map exist outside the current zone span. This can only happen > during > > + boot, when initializing the memory map of pages that do not fall into > any > > + zone span. Growing the zone to cover such pages and later shrinking > it back > > + may result in a "too small" value. This is safe: it merely prevents > > + detecting a contiguous zone. > > It's suboptimal that we repeat the same comment that we already have in > struct > zone. Can we just keep it vry simple here? > > "Pages within the zone that have an online memory map: present pages and > memory > holes whose memory map has been initialized. See XXX for more details." Thanks for pointing out, I will simplify to this short description. > > + > > ``present_early_pages`` > > The present pages existing within the zone located on memory > available since > > early boot, excluding hotplugged memory. Defined only when > > diff --git a/drivers/base/memory.c b/drivers/base/memory.c > > index bcfe2d9f4adb..237ace435372 100644 > > --- a/drivers/base/memory.c > > +++ b/drivers/base/memory.c > > @@ -246,6 +246,7 @@ static int memory_block_online(struct memory_block > *mem) > > nr_vmemmap_pages = mem->altmap->free; > > > > mem_hotplug_begin(); > > + clear_zone_contiguous(zone); > > if (nr_vmemmap_pages) { > > ret = mhp_init_memmap_on_memory(start_pfn, nr_vmemmap_pages, > zone); > > if (ret) > > @@ -270,6 +271,7 @@ static int memory_block_online(struct memory_block > *mem) > > > > mem->zone = zone; > > out: > > + set_zone_contiguous(zone); > > mem_hotplug_done(); > > return ret; > > } > > @@ -282,6 +284,7 @@ static int memory_block_offline(struct memory_block > *mem) > > unsigned long start_pfn = section_nr_to_pfn(mem->start_section_nr); > > unsigned long nr_pages = PAGES_PER_SECTION * sections_per_block; > > unsigned long nr_vmemmap_pages = 0; > > + struct zone *zone; > > Why the temporary variable, and why not initialize it directly here? Note > that > > > int ret; > > > > if (!mem->zone) > > We already use mem->zone here. So if you add a variable, convert that one > as > well. But I guess we can just life without one. Will remove the temporary variable in next version. > > @@ -294,7 +297,9 @@ static int memory_block_offline(struct memory_block > *mem) > > if (mem->altmap) > > nr_vmemmap_pages = mem->altmap->free; > > > > + zone = mem->zone; > > mem_hotplug_begin(); > > + clear_zone_contiguous(zone); > > if (nr_vmemmap_pages) > > adjust_present_page_count(pfn_to_page(start_pfn), mem->group, > > -nr_vmemmap_pages); > > @@ -314,6 +319,7 @@ static int memory_block_offline(struct memory_block > *mem) > > > > mem->zone = NULL; > > out: > > + set_zone_contiguous(zone); > > mem_hotplug_done(); > > return ret; > > } > > [...] > > > +static inline void set_zone_contiguous(struct zone *zone) > > +{ > > + if (zone_is_zone_device(zone)) > > + return; > > + if (zone->spanned_pages == zone->pages_with_online_memmap) > > + zone->contiguous = true; > > Maybe it was already discussed (and I recall that we previously had that), > but I > think we really need READ_ONCE semantics here and WRITE_ONCE semantics in > memory > hotplug code. Otherwise concurrent updates could lead to weird things when > the > compiler does load-tearing. Thanks for your guidance. I should have considered the READ_ONCE/WRITE_ONCE semantics here. I'll add them in the next Revision. > [...] > > > > > +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; > > These two can be const. Will do. > > + 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); > > Hm, I don't immediately understand why we do the PAGES_PER_SUBSECTION > thing > here. Why is that required? pages_with_online_memmap counts all PFNs where pfn_to_online_page() is valid. With CONFIG_SPARSEMEM_VMEMMAP, pfn_section_valid() operates at PAGES_PER_SUBSECTION granularity — when any page in a subsection has memory, the entire subsection is valid/online. So we align to subsection boundaries to include hole pages within partially-populated subsections. I can also add a comment in the code to make this intent clearer. /* * With CONFIG_SPARSEMEM_VMEMMAP, pfn_section_valid() operates at * PAGES_PER_SUBSECTION granularity, so align to subsection boundaries * to include all PFNs for which pfn_to_online_page() is valid. */ Best Regards, Liu, Yuan1 > Cheers, > > David