mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] mm/page_alloc: let the highest memory node recover from hopeless state
@ 2026-10-19 18:48 Gregory Price (Meta)
  2026-10-19 19:51 ` Zi Yan
  2026-10-19 20:13 ` Johannes Weiner
  0 siblings, 2 replies; 5+ messages in thread
From: Gregory Price (Meta) @ 2026-10-19 18:48 UTC (permalink / raw)
  To: linux-mm
  Cc: linux-kernel, kernel-team, akpm, vbabka, surenb, mhocko,
	brendan.jackman, hannes, ziy, flyinrm, stable

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@vger.kernel.org
Signed-off-by: Gregory Price (Meta) <gourry@gourry.net>
---
 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


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] mm/page_alloc: let the highest memory node recover from hopeless state
  2026-10-19 18:48 [PATCH] mm/page_alloc: let the highest memory node recover from hopeless state Gregory Price (Meta)
@ 2026-10-19 19:51 ` Zi Yan
  2026-10-19 20:16   ` Gregory Price
  2026-10-19 20:13 ` Johannes Weiner
  1 sibling, 1 reply; 5+ messages in thread
From: Zi Yan @ 2026-10-19 19:51 UTC (permalink / raw)
  To: Gregory Price (Meta), linux-mm, Jiayuan Chen
  Cc: linux-kernel, kernel-team, akpm, vbabka, surenb, mhocko,
	brendan.jackman, hannes, flyinrm, stable

On Mon Oct 19, 2026 at 2:48 PM EDT, Gregory Price (Meta) wrote:
> 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@vger.kernel.org
> Signed-off-by: Gregory Price (Meta) <gourry@gourry.net>
> ---
>  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)

Why does a runtime behavior, clearing kswapd hopeless state, depend on a
static memory topology (excluding memory hotadd/hotremove in this
context)? There is nothing telling us if a fallback node has available memory.

Just reset it regardless. kswapd can go hopeless later if the node
cannot be reclaimed.

BTW, LLM also points out that kswapd_try_clear_hopeless(), called by
direct reclaim, only clears hopeless when the node is balanced, but that
rarely happens. So hopeless state can stay much longer if there is only
one node. Adding Jiayuna, who added kswapd_try_clear_hopeless(), to gvie
some insight.

>  			kswapd_clear_hopeless(pgdat, KSWAPD_CLEAR_HOPELESS_PCP);
>  	}
>  	return ret;




-- 
Best Regards,
Yan, Zi


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] mm/page_alloc: let the highest memory node recover from hopeless state
  2026-10-19 18:48 [PATCH] mm/page_alloc: let the highest memory node recover from hopeless state Gregory Price (Meta)
  2026-10-19 19:51 ` Zi Yan
@ 2026-10-19 20:13 ` Johannes Weiner
  2026-10-19 20:40   ` Gregory Price
  1 sibling, 1 reply; 5+ messages in thread
From: Johannes Weiner @ 2026-10-19 20:13 UTC (permalink / raw)
  To: Gregory Price (Meta)
  Cc: linux-mm, linux-kernel, kernel-team, akpm, vbabka, surenb,
	mhocko, brendan.jackman, ziy, flyinrm, stable

On Mon, Oct 19, 2026 at 02:48:50PM -0400, Gregory Price (Meta) wrote:
> 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.

This seems to be the express goal in the commit referenced by
Fixes:. Can you explain why this premise was wrong?

The patch in question also only added another re-wake event. It didn't
remove one. How can it be at fault for kswapd getting stuck?

> 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.

I don't understand what "having more than one node in the system"
means for re-igniting kswapd on this one node.

Generally I don't understand what the heck we're trying to do with all
these patches against the hopeless state code. It shouldn't be that
hard, right?? If kswapd on a node failed for whatever reason, let it
sleep until direct reclaim makes forward progress, or other frees
(unmap, etc.) put the node back above the high watermarks (which means
enough of the unreclaimable pages were freed to justify a new wakeup
in the future to attempt reclaim against new pages).

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] mm/page_alloc: let the highest memory node recover from hopeless state
  2026-10-19 19:51 ` Zi Yan
@ 2026-10-19 20:16   ` Gregory Price
  0 siblings, 0 replies; 5+ messages in thread
From: Gregory Price @ 2026-10-19 20:16 UTC (permalink / raw)
  To: Zi Yan
  Cc: linux-mm, Jiayuan Chen, linux-kernel, kernel-team, akpm, vbabka,
	surenb, mhocko, brendan.jackman, hannes, flyinrm, stable

On Mon, Oct 19, 2026 at 03:51:27PM -0400, Zi Yan wrote:
> On Mon Oct 19, 2026 at 2:48 PM EDT, Gregory Price (Meta) wrote:
> >  		if (kswapd_test_hopeless(pgdat) &&
> > -		    next_memory_node(pgdat->node_id) < MAX_NUMNODES)
> > +		    num_node_state(N_MEMORY) > 1)
> 
> Why does a runtime behavior, clearing kswapd hopeless state, depend on a
> static memory topology (excluding memory hotadd/hotremove in this
> context)? There is nothing telling us if a fallback node has available memory.
> 
> Just reset it regardless. kswapd can go hopeless later if the node
> cannot be reclaimed.
> 

I mostly agree, but this was more of behavioral change than i was
outright willing to commit to in a stable backport.

I can send a follow up commit to drop the check altogether if you
prefer - but I'm not sure we want to drop it outright in the backport.

> BTW, LLM also points out that kswapd_try_clear_hopeless(), called by
> direct reclaim, only clears hopeless when the node is balanced, but that
> rarely happens. So hopeless state can stay much longer if there is only
> one node. Adding Jiayuna, who added kswapd_try_clear_hopeless(), to gvie
> some insight.
> 

Yeah I have some additional things in my pile on the hopeless flag, but
i haven't gotten around to them.

~Gregory

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] mm/page_alloc: let the highest memory node recover from hopeless state
  2026-10-19 20:13 ` Johannes Weiner
@ 2026-10-19 20:40   ` Gregory Price
  0 siblings, 0 replies; 5+ messages in thread
From: Gregory Price @ 2026-10-19 20:40 UTC (permalink / raw)
  To: Johannes Weiner
  Cc: linux-mm, linux-kernel, kernel-team, akpm, vbabka, surenb,
	mhocko, brendan.jackman, ziy, flyinrm, stable

On Mon, Oct 19, 2026 at 10:13:21PM +0200, Johannes Weiner wrote:
> On Mon, Oct 19, 2026 at 02:48:50PM -0400, Gregory Price (Meta) wrote:
> > 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.
> 
> This seems to be the express goal in the commit referenced by
> Fixes:. Can you explain why this premise was wrong?
>

tl;dr:  next_memory_node() is not the right check for what the
comment and patches say it actually wants to check.

on a 2-socket system you would have:
  if (next_memory_node(0) < MAX_NUMNODES) /* clear's hopeless */
  if (next_memory_node(1) < MAX_NUMNODES) /* doesn't clear hopeless */

despite the fact that each node is the other one's fallback node.

> The patch in question also only added another re-wake event. It didn't
> remove one. How can it be at fault for kswapd getting stuck?

Not at fault for getting stuck - it didn't fully fix the thing it claimed
to fix. So this patch completes that patch's attempt.


> I don't understand what "having more than one node in the system"
> means for re-igniting kswapd on this one node.
> 
> Generally I don't understand what the heck we're trying to do with all
> these patches against the hopeless state code. It shouldn't be that
> hard, right?? If kswapd on a node failed for whatever reason, let it
> sleep until direct reclaim makes forward progress, or other frees
> (unmap, etc.) put the node back above the high watermarks (which means
> enough of the unreclaimable pages were freed to justify a new wakeup
> in the future to attempt reclaim against new pages).
> 

Zi said the same thing, and I agree.

I didn't want to propose that in a stable tagged commit, but if there's
strong opinions here I can just outright drop it.

~Gregory

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-10-19 20:40 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-19 18:48 [PATCH] mm/page_alloc: let the highest memory node recover from hopeless state Gregory Price (Meta)
2026-10-19 19:51 ` Zi Yan
2026-10-19 20:16   ` Gregory Price
2026-10-19 20:13 ` Johannes Weiner
2026-10-19 20:40   ` Gregory Price

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®