From: Josef Bacik start_isolate_page_range() fails with -EBUSY if one of the pageblocks is already isolated, i.e. if somebody else is working on it. It restores the pageblocks which it has isolated itself before it returns, as its kernel-doc says: We then clean up by restoring the migration type on pageblocks we may have modified and return -EBUSY to caller. This prevents two threads from simultaneously working on overlapping ranges. alloc_contig_frozen_range() nevertheless calls undo_isolate_page_range() for the whole range in this case, which clears every isolated pageblock it finds. The only ones left at this point belong to the other user of the range: CPU0 offline_pages() CPU1 alloc_contig_frozen_range() start_isolate_page_range(A) pageblock X: isolated migrate ... start_isolate_page_range(B) X is isolated: -EBUSY (own pageblocks restored) undo_isolate_page_range(B) X: not isolated any more test_pages_isolated(A): -EBUSY (again and again) offline_pages() repeats the migration and test_pages_isolated() until the latter succeeds, which is now impossible and the task spins until it gets a signal, while the free pages of X are handed out by the allocator again. If X is released after the last test_pages_isolated(), __offline_isolated_pages() takes pages which are accounted as free off the free lists as MIGRATE_ISOLATE. Thus NR_FREE_PAGES stays too high, or hits BUG_ON(!PageBuddy(page)) if one of them has been allocated. For another alloc_contig_frozen_range() or cma_alloc() the result is a spurious -EBUSY. Return the error, like the function did until it was reworked. Fixes: b2c9e2fbba32 ("mm: make alloc_contig_range work at pageblock granularity") Cc: Assisted-by: LLM Signed-off-by: Josef Bacik Signed-off-by: David Hildenbrand (Arm) Signed-off-by: Vlastimil Babka (SUSE) --- mm/page_alloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 36079e092875..ee013db45ed1 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -7329,7 +7329,7 @@ int alloc_contig_frozen_range_noprof(unsigned long start, unsigned long end, ret = start_isolate_page_range(start, end, mode); if (ret) - goto done; + return ret; drain_all_pages(cc.zone); -- 2.56.0