Skip to content

Commit 4805ef3

Browse files
RichardWeiYangakpm00
authored andcommitted
mm/page_alloc: check the correct buddy if it is a starting block
find_large_buddy() search buddy based on start_pfn, which maybe different from page's pfn, e.g. when page is not pageblock aligned, because prep_move_freepages_block() always align start_pfn to pageblock. This means when we found a starting block at start_pfn, it may check on the wrong page theoretically. And not split the free page as it is supposed to, causing a freelist migratetype mismatch. The good news is the page passed to __move_freepages_block_isolate() has only two possible cases: * page is pageblock aligned * page is __first_valid_page() of this block So it is safe for the first case, and it won't get a buddy larger than pageblock for the second case. To fix the issue, check the returned pfn of find_large_buddy() to decide whether to split the free page: 1. if it is not a PageBuddy pfn, no split; 2. if it is a PageBuddy pfn but order <= pageblock_order, no split; 3. if it is a PageBuddy pfn with order > pageblock_order, start_pfn is either in the starting block or tail block, split the PageBuddy at pageblock_order level. Link: https://lkml.kernel.org/r/20250905140358.28849-1-richard.weiyang@gmail.com Signed-off-by: Wei Yang <richard.weiyang@gmail.com> Reviewed-by: Zi Yan <ziy@nvidia.com> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: David Hildenbrand <david@redhat.com> Cc: Baolin Wang <baolin.wang@linux.alibaba.com> Cc: Vlastimil Babka <vbabka@suse.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent 5ce1dbf commit 4805ef3

File tree

1 file changed

+8
-17
lines changed

1 file changed

+8
-17
lines changed

mm/page_alloc.c

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2090,9 +2090,10 @@ static inline void toggle_pageblock_isolate(struct page *page, bool isolate)
20902090
static bool __move_freepages_block_isolate(struct zone *zone,
20912091
struct page *page, bool isolate)
20922092
{
2093-
unsigned long start_pfn, pfn;
2093+
unsigned long start_pfn, buddy_pfn;
20942094
int from_mt;
20952095
int to_mt;
2096+
struct page *buddy;
20962097

20972098
if (isolate == get_pageblock_isolate(page)) {
20982099
VM_WARN_ONCE(1, "%s a pageblock that is already in that state",
@@ -2107,29 +2108,19 @@ static bool __move_freepages_block_isolate(struct zone *zone,
21072108
if (pageblock_order == MAX_PAGE_ORDER)
21082109
goto move;
21092110

2110-
/* We're a tail block in a larger buddy */
2111-
pfn = find_large_buddy(start_pfn);
2112-
if (pfn != start_pfn) {
2113-
struct page *buddy = pfn_to_page(pfn);
2111+
buddy_pfn = find_large_buddy(start_pfn);
2112+
buddy = pfn_to_page(buddy_pfn);
2113+
/* We're a part of a larger buddy */
2114+
if (PageBuddy(buddy) && buddy_order(buddy) > pageblock_order) {
21142115
int order = buddy_order(buddy);
21152116

21162117
del_page_from_free_list(buddy, zone, order,
2117-
get_pfnblock_migratetype(buddy, pfn));
2118+
get_pfnblock_migratetype(buddy, buddy_pfn));
21182119
toggle_pageblock_isolate(page, isolate);
2119-
split_large_buddy(zone, buddy, pfn, order, FPI_NONE);
2120+
split_large_buddy(zone, buddy, buddy_pfn, order, FPI_NONE);
21202121
return true;
21212122
}
21222123

2123-
/* We're the starting block of a larger buddy */
2124-
if (PageBuddy(page) && buddy_order(page) > pageblock_order) {
2125-
int order = buddy_order(page);
2126-
2127-
del_page_from_free_list(page, zone, order,
2128-
get_pfnblock_migratetype(page, pfn));
2129-
toggle_pageblock_isolate(page, isolate);
2130-
split_large_buddy(zone, page, pfn, order, FPI_NONE);
2131-
return true;
2132-
}
21332124
move:
21342125
/* Use MIGRATETYPE_MASK to get non-isolate migratetype */
21352126
if (isolate) {

0 commit comments

Comments
 (0)