On 21 Aug 2023, at 14:33, Johannes Weiner wrote: > The buddy allocator coalesces compatible blocks during freeing, but it > doesn't update the types of the subblocks to match. When an allocation > later breaks the chunk down again, its pieces will be put on freelists > of the wrong type. This encourages incompatible page mixing (ask for > one type, get another), and thus long-term fragmentation. > > Update the subblocks when merging a larger chunk, such that a later > expand() will maintain freelist type hygiene. > > Signed-off-by: Johannes Weiner <hannes@xxxxxxxxxxx> > --- > mm/page_alloc.c | 37 ++++++++++++++++++++++--------------- > 1 file changed, 22 insertions(+), 15 deletions(-) > > diff --git a/mm/page_alloc.c b/mm/page_alloc.c > index a5e36d186893..6c9f565b2613 100644 > --- a/mm/page_alloc.c > +++ b/mm/page_alloc.c > @@ -438,6 +438,17 @@ void set_pageblock_migratetype(struct page *page, int migratetype) > page_to_pfn(page), MIGRATETYPE_MASK); > } > > +static void change_pageblock_range(struct page *pageblock_page, > + int start_order, int migratetype) > +{ > + int nr_pageblocks = 1 << (start_order - pageblock_order); > + > + while (nr_pageblocks--) { > + set_pageblock_migratetype(pageblock_page, migratetype); > + pageblock_page += pageblock_nr_pages; > + } > +} > + Is this code move included by accident? > #ifdef CONFIG_DEBUG_VM > static int page_outside_zone_boundaries(struct zone *zone, struct page *page) > { > @@ -808,10 +819,17 @@ static inline void __free_one_page(struct page *page, > */ > int buddy_mt = get_pfnblock_migratetype(buddy, buddy_pfn); > > - if (migratetype != buddy_mt > - && (!migratetype_is_mergeable(migratetype) || > - !migratetype_is_mergeable(buddy_mt))) > - goto done_merging; > + if (migratetype != buddy_mt) { > + if (!migratetype_is_mergeable(migratetype) || > + !migratetype_is_mergeable(buddy_mt)) > + goto done_merging; > + /* > + * Match buddy type. This ensures that > + * an expand() down the line puts the > + * sub-blocks on the right freelists. > + */ > + set_pageblock_migratetype(buddy, migratetype); > + } > } > > /* > @@ -1687,17 +1705,6 @@ int move_freepages_block(struct zone *zone, struct page *page, > num_movable); > } > > -static void change_pageblock_range(struct page *pageblock_page, > - int start_order, int migratetype) > -{ > - int nr_pageblocks = 1 << (start_order - pageblock_order); > - > - while (nr_pageblocks--) { > - set_pageblock_migratetype(pageblock_page, migratetype); > - pageblock_page += pageblock_nr_pages; > - } > -} > - > /* > * When we are falling back to another migratetype during allocation, try to > * steal extra free pages from the same pageblocks to satisfy further > -- > 2.41.0 -- Best Regards, Yan, Zi
Attachment:
signature.asc
Description: OpenPGP digital signature