[PATCH 1/2] mm/vmscan: remove redundant !mem_cgroup_online() checks

From: T.J. Mercier

Date: Tue Oct 27 2026 - 21:06:46 EST


Since commit f1cf8d2f36dc ("mm: memcontrol: eliminate the problem of
dying memory cgroup for LRU folios") and commit 0e0ac326c511 ("memcg:
move LRU size accounting on reparenting instead of copying it"),
mem_cgroup_css_offline() reparents all LRU folios to the parent memcg
and zeroes the child's lrugen->nr_pages and lru_zone_size before the
memcg is offlined. Nothing can repopulate the offlined memcg's lruvec
afterwards. A folio that is off the LRU during reparenting looks up its
lruvec through its objcg, which now points to the parent so it is put
back on the parent's LRU.

As a result, lruvec_lru_size() and lruvec_evictable_size() are always 0
when !mem_cgroup_online(memcg) is true, making the offlined memcg special
cases in get_scan_count(), lruvec_is_sizable(), and shrink_one() dead
code. Remove them.

With the get_nr_to_scan() special case removed, an offlined memcg that
still has stale effective protection now has
apply_proportional_protection() applied like get_scan_count() does, so
the MGLRU and traditional LRU behavior is now the same.

Signed-off-by: T.J. Mercier <tjmercier@xxxxxxxxxx>
---
include/linux/mmzone.h | 8 ++++----
mm/vmscan.c | 28 +++++-----------------------
2 files changed, 9 insertions(+), 27 deletions(-)

diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 3b96d6c7123b..7f078ff0dd76 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -638,10 +638,10 @@ struct lru_gen_mm_walk {
* The events that trigger the above operations are:
* 1. The first attempt to reclaim a memcg below low, which triggers
* MEMCG_LRU_TAIL;
- * 2. The first attempt to reclaim a memcg offlined or below reclaimable size
- * threshold, which triggers MEMCG_LRU_TAIL;
- * 3. The second attempt to reclaim a memcg offlined or below reclaimable size
- * threshold, which triggers MEMCG_LRU_YOUNG;
+ * 2. The first attempt to reclaim a memcg below reclaimable size threshold,
+ * which triggers MEMCG_LRU_TAIL;
+ * 3. The second attempt to reclaim a memcg below reclaimable size threshold,
+ * which triggers MEMCG_LRU_YOUNG;
* 4. Attempting to reclaim a memcg below min, which triggers MEMCG_LRU_YOUNG;
* 5. Finishing the aging on the eviction path, which triggers MEMCG_LRU_YOUNG;
* 6. Offlining a memcg, which triggers MEMCG_LRU_OLD.
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 9959ca158ce8..636152d8c94d 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -2754,13 +2754,6 @@ static void get_scan_count(struct lruvec *lruvec, struct scan_control *sc,
scan = apply_proportional_protection(memcg, sc, lruvec_size);
scan >>= sc->priority;

- /*
- * If the cgroup's already been deleted, make sure to
- * scrape out the remaining cache.
- */
- if (!scan && !mem_cgroup_online(memcg))
- scan = min(lruvec_size, SWAP_CLUSTER_MAX);
-
switch (scan_balance) {
case SCAN_EQUAL:
/* Scan lists relative to size */
@@ -2769,14 +2762,8 @@ static void get_scan_count(struct lruvec *lruvec, struct scan_control *sc,
/*
* Scan types proportional to swappiness and
* their relative recent reclaim efficiency.
- * Make sure we don't miss the last page on
- * the offlined memory cgroups because of a
- * round-off error.
*/
- scan = mem_cgroup_online(memcg) ?
- div64_u64(scan * fraction[file], denominator) :
- DIV64_U64_ROUND_UP(scan * fraction[file],
- denominator);
+ scan = div64_u64(scan * fraction[file], denominator);
break;
case SCAN_FILE:
case SCAN_ANON:
@@ -4355,12 +4342,11 @@ static bool lruvec_is_sizable(struct lruvec *lruvec, struct scan_control *sc)
{
unsigned long total;
int swappiness = get_swappiness(lruvec, sc);
- struct mem_cgroup *memcg = lruvec_memcg(lruvec);

total = lruvec_evictable_size(lruvec, swappiness);

/* whether the size is big enough to be helpful */
- return mem_cgroup_online(memcg) ? (total >> sc->priority) : total;
+ return total >> sc->priority;
}

static bool lruvec_is_reclaimable(struct lruvec *lruvec, struct scan_control *sc,
@@ -5199,10 +5185,6 @@ static long get_nr_to_scan(struct lruvec *lruvec, struct scan_control *sc,

evictable = lruvec_evictable_size(lruvec, swappiness);

- /* try to scrape all its memory if this memcg was deleted */
- if (!mem_cgroup_online(memcg))
- return evictable;
-
nr_to_scan = apply_proportional_protection(memcg, sc, evictable);
nr_to_scan >>= sc->priority;

@@ -5325,13 +5307,13 @@ static int shrink_one(struct lruvec *lruvec, struct scan_control *sc)

flush_reclaim_state(sc);

- if (need_rotate && mem_cgroup_online(memcg))
+ if (need_rotate)
return MEMCG_LRU_YOUNG;

- if (!need_rotate && lruvec_is_sizable(lruvec, sc))
+ if (lruvec_is_sizable(lruvec, sc))
return 0;

- /* one retry if offlined or too small */
+ /* one retry if too small */
return READ_ONCE(lruvec->lrugen.seg) != MEMCG_LRU_TAIL ?
MEMCG_LRU_TAIL : MEMCG_LRU_YOUNG;
}
--
2.56.0.307.g5fe7bd680c-goog