From: Kunwu Chan <kunwu.chan@gmail.com>
To: john <love_goo@163.com>
Cc: Kunwu Chan <kunwu.chan@gmail.com>,
akpm@linux-foundation.org, liuye@kylinos.cn, hannes@cmpxchg.org,
mhocko@kernel.org, david@kernel.org, ljs@kernel.org,
hughd@google.com, mgorman@techsingularity.net,
yang@os.amperecomputing.com, zhangqiuhao@huawei.com,
wangkefeng.wang@huawei.com, mawupeng1@huwei.com,
linux-mm@kvack.org, linux-kernel@vger.kernel.org,
Wupeng Ma <mawupeng1@huawei.com>
Subject: Re: [PATCH resend 1/2] mm: vmscan: charge isolate overshoot against scan quota
Date: Wed, 9 Sep 2026 17:52:22 +0800 [thread overview]
Message-ID: <20260909095227.2522994-1-kunwu.chan@gmail.com> (raw)
In-Reply-To: <20260901084706.3784449-2-love_goo@163.com>
On Tue, 1 Sep 2026 16:47:05 +0800 john <love_goo@163.com> wrote:
> From: Wupeng Ma <mawupeng1@huawei.com>
>
> shrink_lruvec() charges the per-LRU budget nr[lru] in SWAP_CLUSTER_MAX
> (32) chunks, but isolate_lru_folios() may scan far more per call: a
> large folio can jump scan by many pages at once (a PMD-sized folio
> counts 512), and a zone-ineligible LRU walks the whole list without
> feeding scan back. The overshoot is never refunded, so shrink_lruvec()
> keeps charging only 32 per round and rescans the same folios.
>
> Have isolate_lru_folios() record its scanned count in sc->nr_isolate_scanned
> and let shrink_lruvec() subtract the overshoot from the remaining quota so
> the next round skips already-scanned folios. The field is reset to 0
I'm not sure this is true across shrink_lruvec() invocations.
isolate_lru_folios() splices folios_skipped back to the head of the LRU,
while get_scan_count() provides a fresh nr[lru] each time shrink_lruvec()
is entered. Thus, charging sc->nr_isolate_scanned against nr[lru] appears
to prevent repeated 32-page scans within the same shrink_lruvec()
invocation, but the same ineligible folios can still be encountered
again by a subsequent invocation.
Is the intended fix specifically to avoid repeated scanning within one
shrink_lruvec() invocation, or is there another mechanism that prevents
these skipped folios from being rescanned by a subsequent shrink_lruvec()
invocation?
Thanks,
KunWu
> before each shrink_list() call, as shrink_list() only reaches
> isolate_lru_folios() on some paths (active + skipped_deactivate,
> too_many_isolated stall bail out early); a stale value would otherwise
> be charged. The budget floor stays nr_to_scan via max() so an empty
> LRU (sc->nr_isolate_scanned = 0) still advances and cannot deadlock.
>
> Co-developed-by: Qiuhao Zhang <zhangqiuhao@huawei.com>
> Signed-off-by: Qiuhao Zhang <zhangqiuhao@huawei.com>
> Signed-off-by: Wupeng Ma <mawupeng1@huawei.com>
> ---
> mm/vmscan.c | 32 +++++++++++++++++++++-----------
> 1 file changed, 21 insertions(+), 11 deletions(-)
>
> diff --git a/mm/vmscan.c b/mm/vmscan.c
> index f11491ee9ed5c..823af9e86efd3 100644
> --- a/mm/vmscan.c
> +++ b/mm/vmscan.c
> @@ -166,6 +166,9 @@ struct scan_control {
> /* Incremented by the number of inactive pages that were scanned */
> unsigned long nr_scanned;
>
> + /* Number of pages that were scanned from isolate_lru_folios() */
> + unsigned long nr_isolate_scanned;
> +
> /* Number of pages freed so far during a call to shrink_zones() */
> unsigned long nr_reclaimed;
>
> @@ -1670,7 +1673,6 @@ static __always_inline void update_lru_sizes(struct lruvec *lruvec,
> * @nr_to_scan: The number of eligible pages to look through on the list.
> * @lruvec: The LRU vector to pull pages from.
> * @dst: The temp list to put pages on to.
> - * @nr_scanned: The number of pages that were scanned.
> * @sc: The scan_control struct for this reclaim session
> * @lru: LRU list id for isolating
> *
> @@ -1678,8 +1680,7 @@ static __always_inline void update_lru_sizes(struct lruvec *lruvec,
> */
> static unsigned long isolate_lru_folios(unsigned long nr_to_scan,
> struct lruvec *lruvec, struct list_head *dst,
> - unsigned long *nr_scanned, struct scan_control *sc,
> - enum lru_list lru)
> + struct scan_control *sc, enum lru_list lru)
> {
> struct list_head *src = &lruvec->lists[lru];
> unsigned long nr_taken = 0;
> @@ -1763,7 +1764,7 @@ static unsigned long isolate_lru_folios(unsigned long nr_to_scan,
> skipped += nr_skipped[zid];
> }
> }
> - *nr_scanned = total_scan;
> + sc->nr_isolate_scanned = total_scan;
> trace_mm_vmscan_lru_isolate(sc->reclaim_idx, sc->order, nr_to_scan,
> total_scan, skipped, nr_taken, lru);
> update_lru_sizes(lruvec, lru, nr_zone_taken);
> @@ -2011,8 +2012,8 @@ static unsigned long shrink_inactive_list(unsigned long nr_to_scan,
>
> lruvec_lock_irq(lruvec);
>
> - nr_taken = isolate_lru_folios(nr_to_scan, lruvec, &folio_list,
> - &nr_scanned, sc, lru);
> + nr_taken = isolate_lru_folios(nr_to_scan, lruvec, &folio_list, sc, lru);
> + nr_scanned = sc->nr_isolate_scanned;
>
> __mod_node_page_state(pgdat, NR_ISOLATED_ANON + file, nr_taken);
> item = PGSCAN_KSWAPD + reclaimer_offset(sc);
> @@ -2068,7 +2069,6 @@ static void shrink_active_list(unsigned long nr_to_scan,
> enum lru_list lru)
> {
> unsigned long nr_taken;
> - unsigned long nr_scanned;
> vma_flags_t vma_flags;
> LIST_HEAD(l_hold); /* The folios which were snipped off */
> LIST_HEAD(l_active);
> @@ -2082,12 +2082,11 @@ static void shrink_active_list(unsigned long nr_to_scan,
>
> lruvec_lock_irq(lruvec);
>
> - nr_taken = isolate_lru_folios(nr_to_scan, lruvec, &l_hold,
> - &nr_scanned, sc, lru);
> + nr_taken = isolate_lru_folios(nr_to_scan, lruvec, &l_hold, sc, lru);
>
> __mod_node_page_state(pgdat, NR_ISOLATED_ANON + file, nr_taken);
>
> - mod_lruvec_state(lruvec, PGREFILL, nr_scanned);
> + mod_lruvec_state(lruvec, PGREFILL, sc->nr_isolate_scanned);
>
> lruvec_unlock_irq(lruvec);
>
> @@ -6013,10 +6012,21 @@ static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc)
> for_each_evictable_lru(lru) {
> if (nr[lru]) {
> nr_to_scan = min(nr[lru], SWAP_CLUSTER_MAX);
> - nr[lru] -= nr_to_scan;
>
> + sc->nr_isolate_scanned = 0;
> nr_reclaimed += shrink_list(lru, nr_to_scan,
> lruvec, sc);
> + /*
> + * isolate_lru_folios() may scan far more
> + * than nr_to_scan when the LRU holds
> + * ineligible folios (zone-skip) or large
> + * folios. Charge that overshoot against the
> + * remaining quota (clamped by min() so it
> + * cannot go negative) so the next iteration
> + * does not rescan the same skipped folios.
> + */
> + nr[lru] -= min(nr[lru],
> + max(nr_to_scan, sc->nr_isolate_scanned));
> }
> }
>
> --
> 2.53.0
>
>
next prev parent reply other threads:[~2026-09-09 9:52 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-01 8:47 [PATCH resend 0/2] mm: vmscan: fix scan overshoot and ineligible folio scanning john
2026-09-01 8:47 ` [PATCH resend 1/2] mm: vmscan: charge isolate overshoot against scan quota john
2026-09-09 9:52 ` Kunwu Chan [this message]
2026-09-01 8:47 ` [PATCH resend 2/2] mm: vmscan: stop scanning ineligible folios after max_nr_skipped john
2026-09-09 9:56 ` Kunwu Chan
2026-09-08 1:49 ` [PATCH resend 0/2] mm: vmscan: fix scan overshoot and ineligible folio scanning john
2026-09-09 2:11 ` Andrew Morton
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=20260909095227.2522994-1-kunwu.chan@gmail.com \
--to=kunwu.chan@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=david@kernel.org \
--cc=hannes@cmpxchg.org \
--cc=hughd@google.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=liuye@kylinos.cn \
--cc=ljs@kernel.org \
--cc=love_goo@163.com \
--cc=mawupeng1@huawei.com \
--cc=mawupeng1@huwei.com \
--cc=mgorman@techsingularity.net \
--cc=mhocko@kernel.org \
--cc=wangkefeng.wang@huawei.com \
--cc=yang@os.amperecomputing.com \
--cc=zhangqiuhao@huawei.com \
/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
all inboxes | Powered by JetHome®