[PATCH] mm/page_alloc: let the highest memory node recover from hopeless state
From: Gregory Price (Meta)
Date: Mon Oct 19 2026 - 14:52:44 EST
free_frozen_page_commit() clears a hopeless node's kswapd failures once
its zone recovers above the high watermark, but only if another memory
node exists for allocations to fall back to.
The test `next_memory_node(nid) < MAX_NUMNODES` finds only memory nodes
with a higher id. The highest-numbered memory node therefore never
recovers on this path, and its kswapd stays disabled until reclaim on
that node makes progress and balances it, or demotion is re-enabled.
In many cases, direct reclaim many never fully run against a lower
node (CXL/kmem), and that means its kswapd can end up full disabled
in rare situations.
To reproduce, fill the highest memory node with bound, non-THP anonymous
memory and no swap until kswapd gives up, then free it: /proc/zoneinfo
keeps showing node_unreclaimable 1 for that node. A lower node recovers.
Count the memory nodes instead. Adding first_memory_node != nid to the
existing test would also work, but a count says directly what the check
means: some other memory node exists.
Fixes: e7a5f249e6db ("mm: re-enable kswapd when memory pressure subsides or demotion is toggled")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Gregory Price (Meta) <gourry@xxxxxxxxxx>
---
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 417c427b196d9..6d4f03faf96ee 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -2929,7 +2929,7 @@ static bool free_frozen_page_commit(struct zone *zone,
* kswapd work again by resetting kswapd_failures.
*/
if (kswapd_test_hopeless(pgdat) &&
- next_memory_node(pgdat->node_id) < MAX_NUMNODES)
+ num_node_state(N_MEMORY) > 1)
kswapd_clear_hopeless(pgdat, KSWAPD_CLEAR_HOPELESS_PCP);
}
return ret;
--
2.53.0-Meta