[PATCH 4/6] mm/page_alloc: don't undo another isolation in alloc_contig_range
From: Gregory Price (Meta)
Date: Tue Oct 27 2026 - 00:23:36 EST
An alloc_contig_range() that overlaps a block going offline can leave
the offline spinning until it gets a signal, holding the device hotplug
lock. When isolation fails, alloc_contig_frozen_range() undoes it over
the whole range, clearing the offline's MIGRATE_ISOLATE too:
CPU 1 (offline_pages) CPU 2 (alloc_contig_range)
start_isolate_page_range()
blocks are MIGRATE_ISOLATE
start_isolate_page_range()
-EBUSY on CPU 1's blocks
undo_isolate_page_range()
blocks are MIGRATE_MOVABLE
test_pages_isolated()
never succeeds again
start_isolate_page_range() fails only on a block someone else isolated,
after undoing its own, so this undo only ever clears another caller's.
Return directly, as before alloc_contig_range() went pageblock granular.
With offline_pages() parked after isolating a DIMM block and a 1G
hugetlb allocation made over it, the offline on base still loops 30s
later in 4 of 4 runs:
offline_pages+0x5b2/0x1570
memory_subsys_offline+0x17e/0x470
device_offline+0x250/0x340
state_store+0x88/0x110
With this patch the allocation still fails, and the offline completes in
3 of 3 runs.
Fixes: b2c9e2fbba32 ("mm: make alloc_contig_range work at pageblock granularity")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Gregory Price (Meta) <gourry@xxxxxxxxxx>
---
mm/page_alloc.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 55d3fc4b307f5..bb3c7e95f2ed4 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -7396,9 +7396,13 @@ int alloc_contig_frozen_range_noprof(unsigned long start, unsigned long end,
* put back to page allocator so that buddy can use them.
*/
+ /*
+ * On failure this has undone its own isolation, and any other
+ * isolated blocks in the range belong to someone else, e.g. offline.
+ */
ret = start_isolate_page_range(start, end, mode);
if (ret)
- goto done;
+ return ret;
drain_all_pages(cc.zone);
--
2.53.0-Meta