Re: [PATCH 5/7] mm/mglru: use explicit tier range in read_ctrl_pos()

From: Baoquan He

Date: Wed Aug 19 2026 - 06:19:25 EST


On 08/18/26 at 01:38pm, Kairui Song via B4 Relay wrote:
> From: Kairui Song <kasong@xxxxxxxxxxx>
>
> read_ctrl_pos() encodes the tier range in a single "tier" parameter
> via "tier % MAX_NR_TIERS" as the start and "min(tier, MAX_NR_TIERS-1)"
> as the end. This is hard to follow, maintain, or extend. Tier values
> 0..3 select a single tier, while tier == MAX_NR_TIERS selects the
> full range.
>
> Replace it with explicit (tier_min, tier_max) parameters using a
> closed [tier_min, tier_max] interval, and add LRU_TIER_MIN and
> LRU_TIER_MAX for the tier bounds. The call sites now become
> self-documenting:
>
> - get_tier_idx: (LRU_TIER_MIN, LRU_TIER_MIN) for the first tier,
> (tier, tier) for each subsequent tier
> - get_type_to_scan: (LRU_TIER_MIN, LRU_TIER_MAX) for the full range
>
> No functional change.
>
> Signed-off-by: Kairui Song <kasong@xxxxxxxxxxx>
> ---
> include/linux/mmzone.h | 2 ++
> mm/vmscan.c | 18 ++++++++++--------
> 2 files changed, 12 insertions(+), 8 deletions(-)

To be honest, I like the old version better. The complexity is
encapsulated inside the function, and tier_idx can reflect if it's
operating on a specific tier or the whole tier. Anyway, this is also
good:

Reviewed-by: Baoquan He <baoquan.he@xxxxxxxxx>

>
> diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
> index 32d9354a754f..d0b5c6217d25 100644
> --- a/include/linux/mmzone.h
> +++ b/include/linux/mmzone.h
> @@ -492,6 +492,8 @@ enum lruvec_flags {
> * folio->flags, masked by LRU_REFS_MASK.
> */
> #define MAX_NR_TIERS 4U
> +#define LRU_TIER_MIN 0U
> +#define LRU_TIER_MAX (MAX_NR_TIERS - 1)
>
> #ifndef __GENERATING_BOUNDS_H
>
> diff --git a/mm/vmscan.c b/mm/vmscan.c
> index a819be6b7ae9..a613bb8d7271 100644
> --- a/mm/vmscan.c
> +++ b/mm/vmscan.c
> @@ -3198,8 +3198,8 @@ struct ctrl_pos {
> int gain;
> };
>
> -static void read_ctrl_pos(struct lruvec *lruvec, int type, int tier, int gain,
> - struct ctrl_pos *pos)
> +static void read_ctrl_pos(struct lruvec *lruvec, int type, int tier_min,
> + int tier_max, int gain, struct ctrl_pos *pos)
> {
> int i;
> struct lru_gen_folio *lrugen = &lruvec->lrugen;
> @@ -3208,7 +3208,7 @@ static void read_ctrl_pos(struct lruvec *lruvec, int type, int tier, int gain,
> pos->gain = gain;
> pos->refaulted = pos->total = 0;
>
> - for (i = tier % MAX_NR_TIERS; i <= min(tier, MAX_NR_TIERS - 1); i++) {
> + for (i = tier_min; i <= tier_max; i++) {
> pos->refaulted += lrugen->avg_refaulted[type][i] +
> atomic_long_read(&lrugen->refaulted[hist][type][i]);
> pos->total += lrugen->avg_total[type][i] +
> @@ -4804,9 +4804,9 @@ static int get_tier_idx(struct lruvec *lruvec, int type)
> * This value is chosen because any other tier would have at least twice
> * as many refaults as the first tier.
> */
> - read_ctrl_pos(lruvec, type, 0, 2, &sp);
> - for (tier = 1; tier < MAX_NR_TIERS; tier++) {
> - read_ctrl_pos(lruvec, type, tier, 3, &pv);
> + read_ctrl_pos(lruvec, type, LRU_TIER_MIN, LRU_TIER_MIN, 2, &sp);
> + for (tier = LRU_TIER_MIN + 1; tier <= LRU_TIER_MAX; tier++) {
> + read_ctrl_pos(lruvec, type, tier, tier, 3, &pv);
> if (!positive_ctrl_err(&sp, &pv))
> break;
> }
> @@ -4827,8 +4827,10 @@ static int get_type_to_scan(struct lruvec *lruvec, int swappiness)
> * Compare the sum of all tiers of anon with that of file to determine
> * which type to scan.
> */
> - read_ctrl_pos(lruvec, LRU_GEN_ANON, MAX_NR_TIERS, swappiness, &sp);
> - read_ctrl_pos(lruvec, LRU_GEN_FILE, MAX_NR_TIERS, MAX_SWAPPINESS - swappiness, &pv);
> + read_ctrl_pos(lruvec, LRU_GEN_ANON, LRU_TIER_MIN, LRU_TIER_MAX,
> + swappiness, &sp);
> + read_ctrl_pos(lruvec, LRU_GEN_FILE, LRU_TIER_MIN, LRU_TIER_MAX,
> + MAX_SWAPPINESS - swappiness, &pv);
>
> return positive_ctrl_err(&sp, &pv);
> }
>
> --
> 2.55.0
>
>