[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