Re: [PATCH 2/3] mm/mglru: improve scan_folios() exhaustion detection

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

On 8/20/2026 12:56 PM, Barry Song (Xiaomi) wrote:
> Commit 16b475d2ac3c ("mm/mglru: avoid reclaim type fall back when
> isolation makes no progress") uses scanned == 0 to determine
> whether scan_folios() has exhausted a reclaim type. However,
> this is not always sufficient. It is possible for scanned > 0,
> while the oldest reclaimable generation is exhausted after the
> first scan_folios() call.
> 
> We detect early_stop in scan_folios(). If we stop early for any reason,
> it means the current reclaim type is not exhausted yet. If early_stop is
> never reached, it means we have exhausted the current oldest generation
> without hitting any scanning limit.
> 
> Another issue is that if the lruvec has 4 generations, we might have
> exhausted the oldest generation while the second oldest generation is
> still reclaimable. In that case, this type is not exhausted yet.
> 
> Add an exhausted output argument to scan_folios() so it can
> explicitly report whether the reclaimable lists for the current
> type have been exhausted.
> 
> Signed-off-by: Barry Song (Xiaomi) <[email protected]>
> ---
>   mm/vmscan.c | 28 ++++++++++++++++++++++------
>   1 file changed, 22 insertions(+), 6 deletions(-)
> 
> diff --git a/mm/vmscan.c b/mm/vmscan.c
> index d5cc30b667ad..1f2e574b0061 100644
> --- a/mm/vmscan.c
> +++ b/mm/vmscan.c
> @@ -4721,7 +4721,8 @@ static bool isolate_folio(struct lruvec *lruvec, struct folio *folio, struct sca
>   
>   static int scan_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
>   		       struct scan_control *sc, int type, int tier,
> -		       struct list_head *list, int *isolatedp)
> +		       struct list_head *list, int *isolatedp,
> +		       bool *exhausted)
>   {
>   	int i;
>   	int gen;
> @@ -4732,12 +4733,15 @@ static int scan_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
>   	int skipped = 0;
>   	unsigned long remaining = nr_to_scan;
>   	struct lru_gen_folio *lrugen = &lruvec->lrugen;
> +	bool early_stop = false;
>   
>   	VM_WARN_ON_ONCE(nr_to_scan > MAX_LRU_BATCH);
>   	VM_WARN_ON_ONCE(!list_empty(list));
>   
> -	if (get_nr_gens(lruvec, type) == MIN_NR_GENS)
> +	if (get_nr_gens(lruvec, type) == MIN_NR_GENS) {
> +		*exhausted = true;
>   		return 0;
> +	}
>   
>   	gen = lru_gen_from_seq(lrugen->min_seq[type]);
>   
> @@ -4768,8 +4772,10 @@ static int scan_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
>   				skipped_zone += delta;
>   			}
>   
> -			if (!--remaining || max(isolated, skipped_zone) >= MIN_LRU_BATCH)
> +			if (!--remaining || max(isolated, skipped_zone) >= MIN_LRU_BATCH) {
> +				early_stop = true;
>   				break;
> +			}
>   		}
>   
>   		if (skipped_zone) {
> @@ -4778,8 +4784,10 @@ static int scan_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
>   			skipped += skipped_zone;
>   		}
>   
> -		if (!remaining || isolated >= MIN_LRU_BATCH)
> +		if (!remaining || isolated >= MIN_LRU_BATCH) {
> +			early_stop = true;
>   			break;
> +		}
>   	}
>   
>   	item = PGSCAN_KSWAPD + reclaimer_offset(sc);
> @@ -4790,6 +4798,13 @@ static int scan_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
>   				scanned, skipped, isolated,
>   				type ? LRU_INACTIVE_FILE : LRU_INACTIVE_ANON);
>   
> +	/*
> +	 * If we didn't stop early, all reclaimable folios in the current
> +	 * generation have been scanned. We are exhausted if this is the last
> +	 * reclaimable generation.
> +	 */
> +	*exhausted = !early_stop &&
> +		     lrugen->min_seq[type] + MIN_NR_GENS == lrugen->max_seq;
>   	*isolatedp = isolated;
>   	return scanned;
>   }
> @@ -4847,11 +4862,12 @@ static int isolate_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
>   	bool type_fallback_allowed = !is_single_type_reclaim(swappiness);
>   	int type = get_type_to_scan(lruvec, swappiness);
>   	int total_scanned = 0, scanned, tier;
> +	bool exhausted;
>   
>   retry:
>   	tier = get_tier_idx(lruvec, type);
>   	scanned = scan_folios(nr_to_scan, lruvec, sc,
> -			      type, tier, list, isolated);
> +			      type, tier, list, isolated, &exhausted);
>   
>   	total_scanned += scanned;
>   	if (*isolated) {
> @@ -4864,7 +4880,7 @@ static int isolate_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
>   	 * We are running out of the current reclaim type. Fall back to
>   	 * the other type if allowed.
>   	 */
> -	if (!scanned && type_fallback_allowed) {
> +	if (exhausted && type_fallback_allowed) {
>   		type = !type;
>   		type_fallback_allowed = false;
>   		goto retry;

LGTM.

Reviewed-by: Ridong Chen <[email protected]>

-- 
Best regards
Ridong
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.