On Thu 25-03-21 17:36:22, Michal Hocko wrote: > If all it takes is to make pfn_to_online_page work (and my > previous attempt is incorrect because it should consult block rather > than section pfn range) This should work. diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 9697acfe96eb..e50d685be8ab 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -510,6 +510,23 @@ static struct memory_block *find_memory_block_by_id(unsigned long block_id) return mem; } +struct page *is_vmemmap_page(unsigned long pfn) +{ + unsigned long nr = pfn_to_section_nr(pfn); + struct memory_block *mem; + unsigned long block_pfn; + + mem = find_memory_block_by_id(memory_block_id(nr)); + if (!mem || !mem->nr_vmemmap_pages) + return NULL; + + block_pfn = section_nr_to_pfn(mem->start_section_nr); + if (pfn - block_pfn > mem->nr_vmemmap_pages) + return NULL; + + return pfn_to_page(pfn); +} + /* * Called under device_hotplug_lock. */ diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 754026a9164d..760bf3ad48d5 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -304,8 +304,16 @@ struct page *pfn_to_online_page(unsigned long pfn) return NULL; ms = __nr_to_section(nr); - if (!online_section(ms)) + if (!online_section(ms)) { + /* + * vmemmap reserved space can eat up a whole section which then + * never gets onlined because it doesn't contain any memory to + * online. + */ + if (memmap_on_memory) + return is_vmemmap_page(pfn); return NULL; + } /* * Save some code text when online_section() + -- Michal Hocko SUSE Labs