[RFC PATCH 1/4] mm/vmscan: only reclaim slab in node reclaim when over min_slab_pages

Ridong Chen <[email protected]>
Newsgroups org.kvack.linux-mm,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
From: Ridong Chen <[email protected]>

Since commit d8ff6fde8e88 ("mm/vmscan: take min_slab_pages into account
when try to call shrink_node"), node reclaim enters shrink_node() when
reclaimable slab is over min_slab_pages OR unmapped page cache is over
min_unmapped_pages.

But the threshold only decides whether to enter shrink_node(), not what
it reclaims.  min_slab_pages is documented to gate slab reclaim alone:
"On Zone reclaim slabs will be reclaimed if more than this percentage of
pages in a zone are reclaimable slab pages".  Yet once unmapped page
cache alone trips the gate, shrink_node() still invokes the slab
shrinkers and can drive reclaimable slab below min_slab_pages.

Carry the decision into the reclaim path via a scan_control flag and
skip the slab shrinkers when reclaimable slab is already at or below
min_slab_pages, so the limit gates slab reclaim as documented.  The flag
defaults to zero, so kswapd, direct reclaim, memcg reclaim, proactive
reclaim and drop_caches are unaffected; only the node reclaim path sets
it.

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Ridong Chen <[email protected]>
---
 mm/vmscan.c | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/mm/vmscan.c b/mm/vmscan.c
index c17ac77b08a4..7e65d0ba4a96 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -114,6 +114,12 @@ struct scan_control {
 	/* zone_reclaim_mode, boost reclaim, cgroup restrictions */
 	unsigned int may_swap:1;
 
+	/*
+	 * When set, the slab shrinkers are not invoked because reclaimable
+	 * slab is already at or below min_slab_pages.
+	 */
+	unsigned int skip_slab_reclaim:1;
+
 	/* Not allow cache_trim_mode to be turned on as part of reclaim? */
 	unsigned int no_cache_trim_mode:1;
 
@@ -5120,7 +5126,8 @@ static int shrink_one(struct lruvec *lruvec, struct scan_control *sc)
 
 	need_rotate = try_to_shrink_lruvec(lruvec, sc);
 
-	shrink_slab(sc->gfp_mask, pgdat->node_id, memcg, sc->priority);
+	if (!sc->skip_slab_reclaim)
+		shrink_slab(sc->gfp_mask, pgdat->node_id, memcg, sc->priority);
 
 	if (!sc->proactive)
 		vmpressure(sc->gfp_mask, sc->order, memcg, false,
@@ -6237,8 +6244,9 @@ static void shrink_node_memcgs(pg_data_t *pgdat, struct scan_control *sc)
 
 		shrink_lruvec(lruvec, sc);
 
-		shrink_slab(sc->gfp_mask, pgdat->node_id, memcg,
-			    sc->priority);
+		if (!sc->skip_slab_reclaim)
+			shrink_slab(sc->gfp_mask, pgdat->node_id, memcg,
+				    sc->priority);
 
 		/* Record the group's reclaim efficiency */
 		if (!sc->proactive)
@@ -7940,6 +7948,15 @@ unsigned long node_reclaim(struct pglist_data *pgdat, gfp_t gfp_mask, unsigned i
 	if (test_and_set_bit_lock(PGDAT_RECLAIM_LOCKED, &pgdat->flags))
 		return 0;
 
+	/*
+	 * min_slab_pages only gates slab reclaim: when reclaimable slab is
+	 * already at or below the limit, leave the shrinkers alone even if we
+	 * entered node reclaim to trim unmapped page cache.
+	 */
+	sc.skip_slab_reclaim =
+		node_page_state_pages(pgdat, NR_SLAB_RECLAIMABLE_B) <=
+		pgdat->min_slab_pages;
+
 	ret = __node_reclaim(pgdat, nr_pages, &sc);
 	clear_bit_unlock(PGDAT_RECLAIM_LOCKED, &pgdat->flags);
 
-- 
2.34.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.