On Tue, Mar 26, 2024 at 12:28:37PM +0100, Vlastimil Babka wrote: > On 3/20/24 7:02 PM, Johannes Weiner wrote: > > Currently, page block type conversion during fallbacks, atomic > > reservations and isolation can strand various amounts of free pages on > > incorrect freelists. > > > > For example, fallback stealing moves free pages in the block to the > > new type's freelists, but then may not actually claim the block for > > that type if there aren't enough compatible pages already allocated. > > > > In all cases, free page moving might fail if the block straddles more > > than one zone, in which case no free pages are moved at all, but the > > block type is changed anyway. > > > > This is detrimental to type hygiene on the freelists. It encourages > > incompatible page mixing down the line (ask for one type, get another) > > and thus contributes to long-term fragmentation. > > > > Split the process into a proper transaction: check first if conversion > > will happen, then try to move the free pages, and only if that was > > successful convert the block to the new type. > > > > Tested-by: "Huang, Ying" <ying.huang@xxxxxxxxx> > > Signed-off-by: Johannes Weiner <hannes@xxxxxxxxxxx> > > Reviewed-by: Vlastimil Babka <vbabka@xxxxxxx> Thanks! > > /* Take ownership for orders >= pageblock_order */ > > if (current_order >= pageblock_order) { > > + del_page_from_free_list(page, zone, current_order); > > change_pageblock_range(page, current_order, start_type); > > - goto single_page; > > + expand(zone, page, order, current_order, start_type); > > + return page; > > Is the exact order here important (AFAIK shouldn't be?) or we could just > change_pageblock_range(); block_type = start_type; goto single_page? At the end of the series, the delete function will do the (type-sensitive) accounting and have a sanity check on the mt. So we have to remove the page from the list before updating the type. We *could* do it in this patch and revert it again 4 patches later, but that's likely not worth the hassle to temporarily save one line. > > single_page: > > - move_to_free_list(page, zone, current_order, start_type); > > + del_page_from_free_list(page, zone, current_order); > > + expand(zone, page, order, current_order, block_type); > > + return page; > > }