[PATCH 1/1][SRU][Q] mm: page_alloc: avoid kswapd thrashing due to NUMA restrictions
AceLan Kao
acelan.kao at canonical.com
Tue Sep 30 05:02:57 UTC 2025
From: Johannes Weiner <hannes at cmpxchg.org>
BugLink: https://bugs.launchpad.net/bugs/2103680
On NUMA systems without bindings, allocations check all nodes for free
space, then wake up the kswapds on all nodes and retry. This ensures
all available space is evenly used before reclaim begins. However,
when one process or certain allocations have node restrictions, they
can cause kswapds on only a subset of nodes to be woken up.
Since kswapd hysteresis targets watermarks that are *higher* than
needed for allocation, even *unrestricted* allocations can now get
suckered onto such nodes that are already pressured. This ends up
concentrating all allocations on them, even when there are idle nodes
available for the unrestricted requests.
This was observed with two numa nodes, where node0 is normal and node1
is ZONE_MOVABLE to facilitate hotplugging: a kernel allocation wakes
kswapd on node0 only (since node1 is not eligible); once kswapd0 is
active, the watermarks hover between low and high, and then even the
movable allocations end up on node0, only to be kicked out again;
meanwhile node1 is empty and idle.
Similar behavior is possible when a process with NUMA bindings is
causing selective kswapd wakeups.
To fix this, on NUMA systems augment the (misleading) watermark test
with a check for whether kswapd is already active during the first
iteration through the zonelist. If this fails to place the request,
kswapd must be running everywhere already, and the watermark test is
good enough to decide placement.
With this patch, unrestricted requests successfully make use of node1,
even while kswapd is reclaiming node0 for restricted allocations.
[gourry at gourry.net: don't retry if no kswapds were active]
Link: https://lkml.kernel.org/r/20250919162134.1098208-1-hannes@cmpxchg.org
Signed-off-by: Gregory Price <gourry at gourry.net>
Tested-by: Joshua Hahn <joshua.hahnjy at gmail.com>
Signed-off-by: Johannes Weiner <hannes at cmpxchg.org>
Acked-by: Zi Yan <ziy at nvidia.com>
Cc: Brendan Jackman <jackmanb at google.com>
Cc: Joshua Hahn <joshua.hahnjy at gmail.com>
Cc: Michal Hocko <mhocko at suse.com>
Cc: Suren Baghdasaryan <surenb at google.com>
Cc: Vlastimil Babka <vbabka at suse.cz>
Signed-off-by: Andrew Morton <akpm at linux-foundation.org>
(cherry picked from commit 19c5fb83f2a4dde7b53b3aeb1fa87bfa3559286b linux-next)
Signed-off-by: Chia-Lin Kao (AceLan) <acelan.kao at canonical.com>
---
mm/page_alloc.c | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index d1d037f97c5f..893e28f5d4db 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -3724,6 +3724,8 @@ get_page_from_freelist(gfp_t gfp_mask, unsigned int order, int alloc_flags,
struct pglist_data *last_pgdat = NULL;
bool last_pgdat_dirty_ok = false;
bool no_fallback;
+ bool skip_kswapd_nodes = nr_online_nodes > 1;
+ bool skipped_kswapd_nodes = false;
retry:
/*
@@ -3786,6 +3788,19 @@ get_page_from_freelist(gfp_t gfp_mask, unsigned int order, int alloc_flags,
}
}
+ /*
+ * If kswapd is already active on a node, keep looking
+ * for other nodes that might be idle. This can happen
+ * if another process has NUMA bindings and is causing
+ * kswapd wakeups on only some nodes. Avoid accidental
+ * "node_reclaim_mode"-like behavior in this case.
+ */
+ if (skip_kswapd_nodes &&
+ !waitqueue_active(&zone->zone_pgdat->kswapd_wait)) {
+ skipped_kswapd_nodes = true;
+ continue;
+ }
+
cond_accept_memory(zone, order, alloc_flags);
/*
@@ -3877,6 +3892,15 @@ get_page_from_freelist(gfp_t gfp_mask, unsigned int order, int alloc_flags,
}
}
+ /*
+ * If we skipped over nodes with active kswapds and found no
+ * idle nodes, retry and place anywhere the watermarks permit.
+ */
+ if (skip_kswapd_nodes && skipped_kswapd_nodes) {
+ skip_kswapd_nodes = false;
+ goto retry;
+ }
+
/*
* It's possible on a UMA machine to get through all zones that are
* fragmented. If avoiding fragmentation, reset and try again.
--
2.43.0
More information about the kernel-team
mailing list