From nobody Tue Sep 29 17:40:34 2026 Received: from mta1.migadu.com (out-73.mta1.migadu.com [95.215.58.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 40A6A34C981 for ; Thu, 20 Aug 2026 02:48:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787194129; cv=none; b=u10VH3R/i7iH0c+0/M0PE3gn/kgMZh4cCermSrNrgwLndhxX511xPT/dQjpeyTBBzUeatEXZtgN9LHEBwumLC9w3EOeuJUHliJJhGMr6mORXieQy7IPI95L46bzAUH5sfmzbKZsBTLqRGRUsW3+vJjt3iF+IQTgBqVM3qv32120= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787194129; c=relaxed/simple; bh=kaupwl2CerM+wcHSCXXaFwLigAE3E8c74QApBbEU49A=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=IkWofRL9vBgrjkb+4iULBH4Gcpd7wW9J3oBL2EkITWCb7KoRpdu24jdTfYb44OTBVang31FShGoJGIixHbZD92/P262Uq9Wb+UboDArUWHFPjseRp3tIR5griRagq+I4YXw1RFml275+Qmk1S/vP2GfktaAQuNcFbmqw97DZoZM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=cyc+7oN1; arc=none smtp.client-ip=95.215.58.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="cyc+7oN1" X-Envelope-To: linux-kernel@vger.kernel.org DKIM-Signature: a=rsa-sha256; bh=kaupwl2CerM+wcHSCXXaFwLigAE3E8c74QApBbEU49A=; c=simple/simple; d=linux.dev; h=from:to:subject:date:message-id:mime-version:content-type; s=key1; t=1787194125; v=1; x=1787798925; b=cyc+7oN1V/RyuWDA6yX7TGuwVuvkxIFDEfyO7oCFLaGM4PuJMPPljaqSl4pbWWZ2IS0Ky3hs lAtgufRUd72tFIbQ7z5dK/+4zdeXEh2pbzdgMnke4qYR+AfYF2OhR62ueGHqAl80eJfUxAKahuT U0ExjSOp+DQ59ulJL1ftdoHM= X-Envelope-To: linux-kernel@vger.kernel.org Received: from teawater-KVM-Virtual-Machine (39.156.73.13) by smtp.migadu.com with ESMTPS id f4ede75f08bc8454; Thu, 20 Aug 2026 02:48:45 +0000 X-Mizu-Trace-ID: f4ede75f08bc8454 X-Migadu-Flow: FLOW_OUT From: "Hui Zhu" To: Andrew Morton , Kairui Song , Qi Zheng , Shakeel Butt , Barry Song , Axel Rasmussen , Yuanchu Xie , Wei Xu , Johannes Weiner , David Hildenbrand , Michal Hocko , Lorenzo Stoakes , Baolin Wang , linux-mm@kvack.org, linux-kernel@vger.kernel.org Cc: Hui Zhu Subject: [PATCH mm-unstable v4 1/2] mm/vmscan: fix missing NR_ISOLATED counter update in MGLRU reclaim path Date: Thu, 20 Aug 2026 10:48:14 +0800 Message-ID: <8b1669146ea1d37190a19c0938d6514cbe1cc88a.1787193916.git.zhuhui@kylinos.cn> X-Mailer: git-send-email 2.53.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Hui Zhu MGLRU evict_folios() isolates folios from the LRU without updating the NR_ISOLATED_ANON/FILE counters, unlike the legacy shrink_inactive_list() path. This causes compaction's too_many_isolated() check to under-count isolated pages when MGLRU reclaim is active. Add NR_ISOLATED counter updates in evict_folios(): increment after isolate_folios() and decrement after all retry passes complete, using the existing nr_isolated which holds the original isolated count. Signed-off-by: Hui Zhu Reviewed-by: Baolin Wang Reviewed-by: Barry Song --- mm/vmscan.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mm/vmscan.c b/mm/vmscan.c index c1404a59523d..98226bb021f3 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -4892,6 +4892,9 @@ static int evict_folios(unsigned long nr_to_scan, str= uct lruvec *lruvec, scanned =3D isolate_folios(nr_to_scan, lruvec, sc, swappiness, &list, &isolated, &type, &type_scanned); nr_isolated =3D isolated; + if (nr_isolated) + __mod_node_page_state(pgdat, NR_ISOLATED_ANON + type, + nr_isolated); =20 /* Scanning may have emptied the oldest gen, flush it */ if (scanned) @@ -4954,6 +4957,8 @@ static int evict_folios(unsigned long nr_to_scan, str= uct lruvec *lruvec, goto retry; } =20 + mod_node_page_state(pgdat, NR_ISOLATED_ANON + type, -nr_isolated); + if (nr_isolated > total_reclaimed) mod_lruvec_state(lruvec, PGROTATE_ANON + type, nr_isolated - total_reclaimed); --=20 2.53.0 From nobody Tue Sep 29 17:40:34 2026 Received: from mta0.migadu.com (out-243.mta0.migadu.com [91.218.175.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 683EC367B67 for ; Thu, 20 Aug 2026 02:48:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.243 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787194132; cv=none; b=BgNRrcfjmvwuLrMW4OKiC+vj7mAONWzv2g8zAGnIUiF5Uj4cOvni8UkSv4Tp5M5h73bKVGLe8fo4yrolVON1ejM3vix3GXovYWmcwKfY7D+1ZqBMuPiM5+aV0MspnZ1/iGMmTUUSruaVW/kK08WRHQ6bwOXZCTHrZ7FNn4Xbl5k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787194132; c=relaxed/simple; bh=Bhp2/74VmpHMzBwDgoyvkdbnUqDeX4YHMvi+u6elTeM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=PTRGX0oxQEETdepG6Uel8IckJtC7mtPb+6tQiWvRtQmmCAq6oyBF01rDYMWXquAd8bijBC6DlzF8o7+XXaSPs1r9nl+oAZMqw4u+00+UzrKEw0m/Q+Gl2t2dyPbd5MLz/bQkTfTj3OHTHzPtHbQNZoVfjn++2KeZLbr+/PrZH1Q= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=Yfd+Rxq9; arc=none smtp.client-ip=91.218.175.243 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="Yfd+Rxq9" X-Envelope-To: linux-kernel@vger.kernel.org DKIM-Signature: a=rsa-sha256; bh=Bhp2/74VmpHMzBwDgoyvkdbnUqDeX4YHMvi+u6elTeM=; c=simple/simple; d=linux.dev; h=from:to:subject:date:message-id:mime-version:content-type; s=key1; t=1787194128; v=1; x=1787798928; b=Yfd+Rxq9N4Z5ZmsjtbA9/QguI7AHiEYJjlJLIesWYU/Y4VUhMh8HDjD6pppABG2RtNBK1mti pkl/WW+dnkQq+cLsWAqxYDjTZrqxwnJ7VZ7cgHvV5ZwwjNx8QoY79g9qL1cNRJOHeVkF7o0Wve3 eJ5x9hztzmEue9gIelpNMXdY= X-Envelope-To: linux-kernel@vger.kernel.org Received: from teawater-KVM-Virtual-Machine (39.156.73.13) by smtp.migadu.com with ESMTPS id f7eac550d4626fba; Thu, 20 Aug 2026 02:48:48 +0000 X-Mizu-Trace-ID: f7eac550d4626fba X-Migadu-Flow: FLOW_OUT From: "Hui Zhu" To: Andrew Morton , Kairui Song , Qi Zheng , Shakeel Butt , Barry Song , Axel Rasmussen , Yuanchu Xie , Wei Xu , Johannes Weiner , David Hildenbrand , Michal Hocko , Lorenzo Stoakes , Baolin Wang , linux-mm@kvack.org, linux-kernel@vger.kernel.org Cc: Hui Zhu Subject: [PATCH mm-unstable v4 2/2] mm/vmscan: apply too_many_isolated() throttling to MGLRU eviction Date: Thu, 20 Aug 2026 10:48:15 +0800 Message-ID: X-Mailer: git-send-email 2.53.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Hui Zhu The legacy path throttles direct reclaim in shrink_inactive_list() when too many isolated folios pile up, but MGLRU's evict_folios() isolates folios without this check, which can lead to unnecessary swapping, thrashing and OOM. With the NR_ISOLATED counters now updated in evict_folios(), add throttle_evictable_types() and call it from evict_folios(), before the lruvec lock is taken since throttling sleeps. The legacy path is left untouched. Unlike the legacy path, where the LRU list to isolate from is known before isolation, isolate_folios() picks the type to scan from the refault feedback and may fall back to the other one. Therefore, instead of throttling on a single type, throttle_evictable_types() collects the evictable types that do not have too many isolated folios, and only sleeps when all of them do: like the legacy path, it waits once for concurrent reclaimers to put their isolated folios back, and gives up if that makes no progress. The resulting mask of the types that are not over-isolated is passed to isolate_folios(), which restricts both its initial choice and its fallback to it. This way a type that is merely over-isolated never blocks the reclaim of the other type, and isolation never lands on a throttled type. If a fatal signal is pending, fake reclaim progress the same way the legacy path does, so the dying task exits reclaim quickly instead of being held in the throttle. Signed-off-by: Hui Zhu --- mm/vmscan.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 80 insertions(+), 5 deletions(-) diff --git a/mm/vmscan.c b/mm/vmscan.c index 98226bb021f3..693dc91a1695 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -4833,15 +4833,73 @@ static int get_type_to_scan(struct lruvec *lruvec, = int swappiness) return positive_ctrl_err(&sp, &pv); } =20 +/* + * Unlike the legacy path, where the LRU list to isolate from is known + * before isolation, isolate_folios() picks the type from the refault + * feedback and may fall back to the other one. Therefore, instead of + * throttling on a single type, collect the evictable types that do not + * have too many isolated folios, and only sleep when all of them do. + * + * Returns the mask of the types isolate_folios() may isolate from, or + * 0 if reclaim should stop. Also sets @fatal to tell the caller that + * the task received a fatal signal while waiting. + */ +static unsigned int throttle_evictable_types(struct pglist_data *pgdat, + int swappiness, + struct scan_control *sc, + bool *fatal) +{ + unsigned int allowed; + bool stalled =3D false; + int i; + + *fatal =3D false; + + for (;;) { + allowed =3D 0; + for_each_evictable_type(i, swappiness) { + if (!too_many_isolated(pgdat, i, sc)) + allowed |=3D BIT(i); + } + + if (allowed) + return allowed; + + /* + * All evictable types are over-isolated. Like the legacy + * path, wait once for concurrent reclaimers to put their + * isolated folios back; give up if that makes no progress. + */ + if (stalled) + return 0; + + stalled =3D true; + reclaim_throttle(pgdat, VMSCAN_THROTTLE_ISOLATED); + + /* We are about to die and free our memory. Return now. */ + if (fatal_signal_pending(current)) { + *fatal =3D true; + return 0; + } + } +} + static int isolate_folios(unsigned long nr_to_scan, struct lruvec *lruvec, struct scan_control *sc, int swappiness, - struct list_head *list, int *isolated, - int *isolate_type, int *isolate_scanned) + unsigned int allowed, struct list_head *list, + int *isolated, int *isolate_type, int *isolate_scanned) { int i; int total_scanned =3D 0; int type =3D get_type_to_scan(lruvec, swappiness); =20 + /* + * The preferred type may have been excluded by + * throttle_evictable_types(); start from the other one. + */ + if (!(allowed & BIT(type))) + type =3D !type; + for_each_evictable_type(i, swappiness) { int scanned; int tier =3D get_tier_idx(lruvec, type); @@ -4858,9 +4916,10 @@ static int isolate_folios(unsigned long nr_to_scan, = struct lruvec *lruvec, /* * If scanned > 0 and isolated =3D=3D 0, avoid falling back to the * other type, as this type remains sufficient. Falling back - * too readily can disrupt the positive_ctrl_err() bias. + * too readily can disrupt the positive_ctrl_err() bias. Only + * fall back to a type that is not throttled. */ - if (!scanned) + if (!scanned && (allowed & BIT(!type))) type =3D !type; } =20 @@ -4883,13 +4942,29 @@ static int evict_folios(unsigned long nr_to_scan, s= truct lruvec *lruvec, bool skip_retry =3D false; struct mem_cgroup *memcg =3D lruvec_memcg(lruvec); struct pglist_data *pgdat =3D lruvec_pgdat(lruvec); + unsigned int allowed; + bool fatal; + + allowed =3D throttle_evictable_types(pgdat, swappiness, sc, &fatal); + if (!allowed) { + /* + * We are about to die and free our memory. Like the legacy + * path, pretend some pages were reclaimed so reclaim + * unwinds quickly instead of looping back into the + * throttle. + */ + if (fatal) + sc->nr_reclaimed +=3D SWAP_CLUSTER_MAX; + + return 0; + } =20 lruvec_lock_irq(lruvec); =20 /* In case folio deletion left empty old gens, flush them */ try_to_inc_min_seq(lruvec, swappiness); =20 - scanned =3D isolate_folios(nr_to_scan, lruvec, sc, swappiness, + scanned =3D isolate_folios(nr_to_scan, lruvec, sc, swappiness, allowed, &list, &isolated, &type, &type_scanned); nr_isolated =3D isolated; if (nr_isolated) --=20 2.53.0