On Tue, Oct 10, 2023 at 05:12:01PM -0400, Johannes Weiner wrote: > On Mon, Oct 02, 2023 at 10:26:44PM -0400, Zi Yan wrote: > > @@ -1614,10 +1652,43 @@ static int move_freepages(struct zone *zone, unsigned long start_pfn, > > > > order = buddy_order(page); > > move_to_free_list(page, zone, order, old_mt, new_mt); > > + /* > > + * set page migratetype 1) only after we move all free pages in > > + * one pageblock and 2) for all pageblocks within the page. > > + * > > + * for 1), since move_to_free_list() checks page migratetype with > > + * old_mt and changing one page migratetype affects all pages > > + * within the same pageblock, if we are moving more than > > + * one free pages in the same pageblock, setting migratetype > > + * right after first move_to_free_list() triggers the warning > > + * in the following move_to_free_list(). > > + * > > + * for 2), when a free page order is greater than pageblock_order, > > + * all pageblocks within the free page need to be changed after > > + * move_to_free_list(). > > I think this can be somewhat simplified. > > There are two assumptions we can make. Buddies always consist of 2^n > pages. And buddies and pageblocks are naturally aligned. This means > that if this pageblock has the start of a buddy that straddles into > the next pageblock(s), it must be the first page in the block. That in > turn means we can move the handling before the loop. Eh, scratch that. Obviously, a sub-block buddy can straddle blocks :( So forget about my version of move_free_pages(). Only consider the changes to find_straddling_buddy() and my question about multiple blocks inside the requested range. But I do have another question about your patch then. Say you have an order-1 buddy that straddles into the block: + /* split at start_pfn if it is in the middle of a free page */ + if (new_start_pfn != start_pfn && PageBuddy(pfn_to_page(new_start_pfn))) { + struct page *new_page = pfn_to_page(new_start_pfn); + int new_page_order = buddy_order(new_page); + + if (new_start_pfn + (1 << new_page_order) > start_pfn) { + /* change migratetype so that split_free_page can work */ + set_pageblock_migratetype(pfn_to_page(start_pfn), new_mt); + split_free_page(new_page, buddy_order(new_page), + start_pfn - new_start_pfn); + + mt_changed_pfn = start_pfn; + /* move to next page */ + start_pfn = new_start_pfn + (1 << new_page_order); + } + } this will have changed the type of the block to new_mt. But then the buddy scan will do this: move_to_free_list(page, zone, order, old_mt, new_mt); + /* + * set page migratetype 1) only after we move all free pages in + * one pageblock and 2) for all pageblocks within the page. + * + * for 1), since move_to_free_list() checks page migratetype with + * old_mt and changing one page migratetype affects all pages + * within the same pageblock, if we are moving more than + * one free pages in the same pageblock, setting migratetype + * right after first move_to_free_list() triggers the warning + * in the following move_to_free_list(). + * + * for 2), when a free page order is greater than pageblock_order, + * all pageblocks within the free page need to be changed after + * move_to_free_list(). That move_to_free_list() will complain that the pages no longer match old_mt, no?