Re: [PATCH v3 17/21] mm/mm_init: don't rely on memblock to get KHO scratch migratetype
Pratyush Yadav <[email protected]> Sat, 25 Jul 2026 17:56:08 +0200
| Newsgroups | org.infradead.lists.kexec,org.kernel.vger.linux-kernel,org.kvack.linux-mm |
|---|---|
| Message-ID | <[email protected]> |
On Wed, Jul 15 2026, Mike Rapoport wrote: >> Currently struct page init via memmap_init() or deferred_init_memmap() >> only queries the migrate type from KHO for each discrete memory range. >> That works currently since KHO scratch memory has a different memory >> type so it is always it its own region. >> >> An upcoming patch will add support for discovering blocks of memory with >> no preservations and it will mark it as MEMBLOCK_KHO_SCRATCH to allow >> allocations from them. This can lead to the bootmem KHO scratch areas to >> be merged into larger free ranges. This merging breaks the selection of >> migrate type. >> >> Get rid of kho_scratch_migratetype(). Instead, let the struct page init >> logic set the migratetype to MIGRATE_MOVABLE for all pages, and then >> give KHO a chance to update the migrate type of its bootmem scratch >> areas to MIGRATE_CMA. Since scratch areas should be a few order of >> magnitues smaller than the total system memory, doing it this way is >> more efficient than searching the kho_scratch array for every pageblock. > > It's true for non-deferred case, but with deferred initialization of > struct pages the static part is small and deferred chunks are small, so > we are going to update the migratetype nearly as much as we would check > it with kho_scratch_migratetype(). > > For simplicity of this patchset I'd keep kho_scratch_migratetype(), just > move it over to kexec_handover.h and make it rely on kho_scratch_overlap(). > > The bulk optimization can be a separate patch on top. Sure, will do. > >> Since kho_scratch_migratetype() no longer exists, drop the migratetype >> argument to memmap_init_zone_range() and deferred_init_pages(). >> >> Signed-off-by: Pratyush Yadav (Google) <[email protected]> >> [...] >> +/* >> + * Mark all KHO scratch pageblocks between start_pfn and end_pfn as >> + * MIGRATE_CMA. >> + */ >> +void kho_init_scratch_migratetype(unsigned long start_pfn, unsigned long end_pfn) >> +{ >> + for (unsigned int i = 0; i < kho_scratch_cnt; i++) { >> + unsigned long scratch_start, scratch_end, pfn; >> + >> + scratch_start = PHYS_PFN(kho_scratch[i].addr); >> + scratch_end = PHYS_PFN(kho_scratch[i].addr + kho_scratch[i].size); >> + >> + /* Target range doesn't overlap with scratch. */ >> + if (start_pfn >= scratch_end || end_pfn <= scratch_start) >> + continue; >> + >> + pfn = max_t(unsigned long, start_pfn, scratch_start); >> + pfn = pageblock_start_pfn(pfn); >> + >> + while (pfn < end_pfn && pfn < scratch_end) { >> + init_pageblock_migratetype(pfn_to_page(pfn), >> + MIGRATE_CMA, false); >> + pfn += pageblock_nr_pages; >> + } >> + } >> +} > > static inline enum migratetype kho_scratch_migratetype(unsigned long pfn, > enum migratetype mt) > { > if (kho_scratch_overlap(PFN_PHYS(pfn)), PAGE_SIZE) > return MIGRATE_CMA; > return mt; > } > > Is way easier to parse and reason about ;-) > >> + >> /** >> * kho_reserve_scratch - Reserve a contiguous chunk of memory for kexec >> * [...] >> @@ -2012,8 +2021,7 @@ static inline void __init pgdat_init_report_one_done(void) >> * Return number of pages initialized. >> */ >> static unsigned long __init deferred_init_pages(struct zone *zone, >> - unsigned long start_pfn, unsigned long end_pfn, >> - enum migratetype mt) >> + unsigned long start_pfn, unsigned long end_pfn) >> { >> int nid = zone_to_nid(zone); >> unsigned long nr_pages = end_pfn - start_pfn, pfn = start_pfn; >> @@ -2027,7 +2035,14 @@ static unsigned long __init deferred_init_pages(struct zone *zone, >> pfn = pageblock_align(start_pfn); >> page = pfn_to_page(pfn); >> for (; pfn < end_pfn; pfn += pageblock_nr_pages, page += pageblock_nr_pages) >> - init_pageblock_migratetype(page, mt, false); >> + init_pageblock_migratetype(page, MIGRATE_MOVABLE, false); >> + >> + /* >> + * Update the migrate type for any pageblocks that fall in a KHO scratch >> + * area. Since most pageblocks will not be KHO scratch, do it outside >> + * the loop to only do the search once. >> + */ >> + kho_init_scratch_migratetype(start_pfn, end_pfn); > > And here the chunks are at most MAX_ORDER_NR_PAGES, so bulk init also > wouldn't save much. Hmm, right. I didn't think of that. On my system pageblock order is 9 and max page order is 10, so it does halve the amount of work done, but still, I see your point. It took me a couple of tries to get kho_init_scratch_migratetype() right, and kho_scratch_overlap() is certainly easier to reason about. Oh well, I suppose this gets added to the list of performance improvements we do at some point down the line -- Regards, Pratyush Yadav