Linux-mm Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: "Barry Song (Xiaomi)" <baohua@kernel.org>
To: akpm@linux-foundation.org
Cc: axelrasmussen@google.com, baolin.wang@linux.alibaba.com,
	baoquan.he@linux.dev, hannes@cmpxchg.org, hui.zhu@linux.dev,
	kasong@tencent.com, kunwu.chan@gmail.com, liam@infradead.org,
	lianux.mm@gmail.com, linux-kernel@vger.kernel.org,
	linux-mm@kvack.org, liuxiang.277@bytedance.com,
	lyugaofei@xiaomi.com, mhocko@kernel.org, mhocko@suse.com,
	qi.zheng@linux.dev, ridong.chen@linux.dev, rppt@kernel.org,
	ryncsn@gmail.com, shakeel.butt@linux.dev, surenb@google.com,
	wangzicheng@honor.com, weixugc@google.com, yuanchu@google.com,
	zhangbo56@xiaomi.com, zhuhui@kylinos.cn,
	sidchintamaneni@gmail.com, Barry Song <baohua@kernel.org>
Subject: [PATCH v7 04/16] mm/mglru: lift the forced protection of reclaimer
Date: Thu, 12 Nov 2026 07:25:51 +0800	[thread overview]
Message-ID: <20261111232603.9934-5-baohua@kernel.org> (raw)
In-Reply-To: <20261111232603.9934-1-baohua@kernel.org>

From: Kairui Song <kasong@tencent.com>

When a type is drained down to MIN_NR_GENS gens, the reclaimer will
fail to make any progress on that type without aging.

However aging comes with a cost, and it will take time to finish. Even
if we do aging more proactively, when under great pressure, gens will
still be drained very fast so the new gens produced by aging can't catch
up with the consumption. With MIN_NR_GENS setting blocking the reclaim,
we will run into OOM. This OOM can be reproduced by the previous test
program [1] used for fixing another aging problem [2]. When running in
great pressure, certain workloads will keep seeing premature OOM with
MGLRU, and never see any OOM with classical LRU.

This might get worse if we implement async aging, or avoid hotness
inversion in aging, as they will slow down the aging process even more.

To fix this, let's first drop the get_nr_gens() == MIN_NR_GENS early
return and let the raised-priority scan bound cover max_seq itself.

Mapped folios will still survive as the rmap PTE check will keep them.
Unmapped cache folios may thrashing more when under great pressure,
which is really a problem that should be fixed with refault distance
and frequecy aware promotoin instead [3].

Link: https://github.com/ryncsn/emm-test-project/tree/master/file-anon-mix-pressure [1]
Link: https://lore.kernel.org/linux-mm/20260428-mglru-reclaim-v7-0-02fabb92dc43@tencent.com/ [2]
Link: https://lore.kernel.org/linux-mm/20260502-mglru-fg-v1-0-913619b014d9@tencent.com/ [3]
Signed-off-by: Kairui Song <kasong@tencent.com>
Signed-off-by: Barry Song (Xiaomi) <baohua@kernel.org>
Reviewed-by: Kunwu Chan <kunwu.chan@gmail.com>
---
 mm/vmscan.c | 34 +++++++++++++++++++++++++---------
 1 file changed, 25 insertions(+), 9 deletions(-)

diff --git a/mm/vmscan.c b/mm/vmscan.c
index 593f407c0668..db0a8a3e8887 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -4672,7 +4672,7 @@ void lru_gen_reparent_memcg(struct mem_cgroup *memcg, struct mem_cgroup *parent,
  ******************************************************************************/
 
 static bool sort_folio(struct lruvec *lruvec, struct folio *folio, struct scan_control *sc,
-		       int min_gen, int tier_idx)
+		       int min_gen, int max_gen, int tier_idx)
 {
 	int gen = folio_lru_gen(folio);
 	int type = folio_is_file_lru(folio);
@@ -4689,12 +4689,22 @@ static bool sort_folio(struct lruvec *lruvec, struct folio *folio, struct scan_c
 	if (!folio_evictable(folio))
 		return false;
 
-	/* promoted */
+	/* promoted, or moved due to reparenting. */
 	if (gen != min_gen) {
 		list_move(&folio->lru, &lrugen->folios[gen][type][zone]);
 		return true;
 	}
 
+	/*
+	 * We are reclaiming the last gen left. Folios in this gen can no
+	 * longer be promoted or protected, so just isolate them. The one
+	 * exception is lru_gen_reparent_memcg(), which is handled above.
+	 */
+	if (min_gen == max_gen) {
+		VM_WARN_ON_ONCE(zone > sc->reclaim_idx);
+		return false;
+	}
+
 	/* protected */
 	if (tier > tier_idx || refs + workingset == BIT(LRU_REFS_WIDTH) + 1) {
 		gen = folio_inc_gen(lruvec, folio, min_gen);
@@ -4749,15 +4759,16 @@ static int scan_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
 		       struct list_head *list, int *isolatedp)
 {
 	int i;
-	int gen;
 	enum node_stat_item item;
 	int sorted = 0;
 	int scanned = 0;
 	int isolated = 0;
 	int skipped = 0;
+	int gen, max_gen;
 	unsigned long min_seq;
 	unsigned long remaining = nr_to_scan;
 	struct lru_gen_folio *lrugen = &lruvec->lrugen;
+	DEFINE_MAX_SEQ(lruvec);
 
 	VM_WARN_ON_ONCE(nr_to_scan > MAX_LRU_BATCH);
 	VM_WARN_ON_ONCE(!list_empty(list));
@@ -4770,18 +4781,24 @@ static int scan_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
 	if (sc->priority == DEF_PRIORITY)
 		min_seq = lrugen->min_seq[type];
 	else
-		min_seq = lruvec_populated_min_seq(lruvec, type, lrugen->max_seq - MIN_NR_GENS + 1);
-
-	if (get_nr_gens(lruvec, type) == MIN_NR_GENS)
-		return 0;
+		min_seq = lruvec_populated_min_seq(lruvec, type, lrugen->max_seq);
 
 	gen = lru_gen_from_seq(min_seq);
+	max_gen = lru_gen_from_seq(max_seq);
+
 	for (i = MAX_NR_ZONES; i > 0; i--) {
 		LIST_HEAD(moved);
 		int skipped_zone = 0;
 		int zone = (sc->reclaim_idx + i) % MAX_NR_ZONES;
 		struct list_head *head = &lrugen->folios[gen][type][zone];
 
+		/*
+		 * If there is only one gen left, rotating the unreclaimable
+		 * zone become meaningless, just skip them.
+		 */
+		if (gen == max_gen && zone > sc->reclaim_idx)
+			continue;
+
 		while (!list_empty(head)) {
 			struct folio *folio = lru_to_folio(head);
 			int delta = folio_nr_pages(folio);
@@ -4792,8 +4809,7 @@ static int scan_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
 			VM_WARN_ON_ONCE_FOLIO(folio_zonenum(folio) != zone, folio);
 
 			scanned += delta;
-
-			if (sort_folio(lruvec, folio, sc, gen, tier))
+			if (sort_folio(lruvec, folio, sc, gen, max_gen, tier))
 				sorted += delta;
 			else if (isolate_folio(lruvec, folio, sc)) {
 				list_add(&folio->lru, list);
-- 
2.34.1



  parent reply	other threads:[~2026-11-11 23:26 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-11 23:25 [PATCH v7 00/16] mm: mglru: fix swappiness behavior Barry Song (Xiaomi)
2026-11-11 23:25 ` [PATCH v7 01/16] mm/mglru: report evictable sizes per type Barry Song (Xiaomi)
2026-11-11 23:25 ` [PATCH v7 02/16] mm/mglru: extract lruvec_populated_min_seq() helper Barry Song (Xiaomi)
2026-11-12  5:00   ` sashiko-bot
2026-11-12  5:11     ` Barry Song
2026-11-11 23:25 ` [PATCH v7 03/16] mm/mglru: reclaim from the oldest populated gen Barry Song (Xiaomi)
2026-11-12  5:00   ` sashiko-bot
2026-11-11 23:25 ` Barry Song (Xiaomi) [this message]
2026-11-12  5:00   ` [PATCH v7 04/16] mm/mglru: lift the forced protection of reclaimer sashiko-bot
2026-11-11 23:25 ` [PATCH v7 05/16] mm/mglru: skip zones above reclaim_idx instead of rotating them Barry Song (Xiaomi)
2026-11-12  5:01   ` sashiko-bot
2026-11-12  6:36     ` Barry Song
2026-11-11 23:25 ` [PATCH v7 06/16] mm/mglru: return for unavailable anon reclaim earlier Barry Song (Xiaomi)
2026-11-11 23:25 ` [PATCH v7 07/16] mm/mglru: balance anon and file scan budget by refault rate Barry Song (Xiaomi)
2026-11-12  5:01   ` sashiko-bot
2026-11-11 23:25 ` [PATCH v7 08/16] mm/mglru: lift youngest gen protection for higher priority Barry Song (Xiaomi)
2026-11-11 23:25 ` [PATCH v7 09/16] mm/mglru: Avoid placing rejected folios below populated gen Barry Song (Xiaomi)
2026-11-11 23:25 ` [PATCH v7 10/16] mm/mglru: Run aging when pages are rare outside the youngest gen Barry Song (Xiaomi)
2026-11-12  5:01   ` sashiko-bot
2026-11-12  5:47     ` Barry Song
2026-11-11 23:25 ` [PATCH v7 11/16] mm/mglru: Run aging when one type has no populatable folios Barry Song (Xiaomi)
2026-11-12  5:01   ` sashiko-bot
2026-11-11 23:25 ` [PATCH v7 12/16] mm/mglru: Restrict eviction accounting to eligible zones Barry Song (Xiaomi)
2026-11-12  5:01   ` sashiko-bot
2026-11-12  9:24     ` Barry Song
2026-11-11 23:26 ` [PATCH v7 13/16] mm/mglru: Reduce LRU lock contention by shrinking folio batches in inc_min_seq Barry Song (Xiaomi)
2026-11-11 23:26 ` [PATCH v7 14/16] mm/mglru: Avoid prolonged anon reclaim with swappiness=200 Barry Song (Xiaomi)
2026-11-12  5:01   ` sashiko-bot
2026-11-12 10:32     ` Barry Song
2026-11-12 10:46       ` Kairui Song
2026-11-11 23:26 ` [PATCH v7 15/16] mm/mglru: Make swappiness=1 file reclaim more aggressive Barry Song (Xiaomi)
2026-11-12  5:01   ` sashiko-bot
2026-11-11 23:26 ` [PATCH v7 16/16] mm/mglru: Avoid scan anon while swapcache is low for GFP_NOIO allocation Barry Song (Xiaomi)
2026-11-12  5:01   ` sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261111232603.9934-5-baohua@kernel.org \
    --to=baohua@kernel.org \
    --cc=akpm@linux-foundation.org \
    --cc=axelrasmussen@google.com \
    --cc=baolin.wang@linux.alibaba.com \
    --cc=baoquan.he@linux.dev \
    --cc=hannes@cmpxchg.org \
    --cc=hui.zhu@linux.dev \
    --cc=kasong@tencent.com \
    --cc=kunwu.chan@gmail.com \
    --cc=liam@infradead.org \
    --cc=lianux.mm@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=liuxiang.277@bytedance.com \
    --cc=lyugaofei@xiaomi.com \
    --cc=mhocko@kernel.org \
    --cc=mhocko@suse.com \
    --cc=qi.zheng@linux.dev \
    --cc=ridong.chen@linux.dev \
    --cc=rppt@kernel.org \
    --cc=ryncsn@gmail.com \
    --cc=shakeel.butt@linux.dev \
    --cc=sidchintamaneni@gmail.com \
    --cc=surenb@google.com \
    --cc=wangzicheng@honor.com \
    --cc=weixugc@google.com \
    --cc=yuanchu@google.com \
    --cc=zhangbo56@xiaomi.com \
    --cc=zhuhui@kylinos.cn \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox