* [PATCH 0/2] mm/vmscan: remove obsolete offlined memcg reclaim handling
@ 2026-10-28 1:06 T.J. Mercier
2026-10-28 1:06 ` [PATCH 1/2] mm/vmscan: remove redundant !mem_cgroup_online() checks T.J. Mercier
2026-10-28 1:06 ` [PATCH 2/2] mm/mglru: stop rotating offlined memcgs to the old generation T.J. Mercier
0 siblings, 2 replies; 15+ messages in thread
From: T.J. Mercier @ 2026-10-28 1:06 UTC (permalink / raw)
To: roman.gushchin, muchun.song, Andrew Morton, Kairui Song, Qi Zheng,
Shakeel Butt, Barry Song, Axel Rasmussen, Yuanchu Xie, Wei Xu,
Baoquan He, Baolin Wang, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Jonathan Corbet, Shuah Khan,
Randy Dunlap, Johannes Weiner
Cc: cgroups, T.J. Mercier, linux-mm, linux-doc, linux-kernel
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"), LRU
folios and their size accounting are reparented to the parent memcg
before a memcg is offlined, leaving the offlined memcg's lruvec
permanently empty.
This series removes the remaining reclaim special-casing for offlined
memcgs that assumed they could still hold LRU folios:
1. Remove redundant !mem_cgroup_online() checks in vmscan.c
2. Stop rotating offlined memcgs to the head of the old generation
(MEMCG_LRU_OLD) in MGLRU.
T.J. Mercier (2):
mm/vmscan: remove redundant !mem_cgroup_online() checks
mm/mglru: stop rotating offlined memcgs to the old generation
Documentation/mm/multigen_lru.rst | 4 +--
include/linux/mmzone.h | 22 +++++---------
mm/memcontrol.c | 1 -
mm/vmscan.c | 48 ++++---------------------------
4 files changed, 14 insertions(+), 61 deletions(-)
base-commit: 2bba28e98578de622ef307d00875aa8f8bca3d10
--
2.56.0.307.g5fe7bd680c-goog
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 1/2] mm/vmscan: remove redundant !mem_cgroup_online() checks
2026-10-28 1:06 [PATCH 0/2] mm/vmscan: remove obsolete offlined memcg reclaim handling T.J. Mercier
@ 2026-10-28 1:06 ` T.J. Mercier
2026-10-28 2:32 ` Balbir Singh
` (4 more replies)
2026-10-28 1:06 ` [PATCH 2/2] mm/mglru: stop rotating offlined memcgs to the old generation T.J. Mercier
1 sibling, 5 replies; 15+ messages in thread
From: T.J. Mercier @ 2026-10-28 1:06 UTC (permalink / raw)
To: roman.gushchin, muchun.song, Andrew Morton, Kairui Song, Qi Zheng,
Shakeel Butt, Barry Song, Axel Rasmussen, Yuanchu Xie, Wei Xu,
Baoquan He, Baolin Wang, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Johannes Weiner
Cc: cgroups, T.J. Mercier, linux-mm, linux-kernel
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@google.com>
---
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
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 2/2] mm/mglru: stop rotating offlined memcgs to the old generation
2026-10-28 1:06 [PATCH 0/2] mm/vmscan: remove obsolete offlined memcg reclaim handling T.J. Mercier
2026-10-28 1:06 ` [PATCH 1/2] mm/vmscan: remove redundant !mem_cgroup_online() checks T.J. Mercier
@ 2026-10-28 1:06 ` T.J. Mercier
2026-10-28 2:42 ` Balbir Singh
` (2 more replies)
1 sibling, 3 replies; 15+ messages in thread
From: T.J. Mercier @ 2026-10-28 1:06 UTC (permalink / raw)
To: roman.gushchin, muchun.song, Andrew Morton, Kairui Song, Qi Zheng,
Shakeel Butt, Barry Song, Axel Rasmussen, Yuanchu Xie, Wei Xu,
Baoquan He, Baolin Wang, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Jonathan Corbet, Shuah Khan,
Randy Dunlap, Johannes Weiner
Cc: cgroups, T.J. Mercier, linux-mm, linux-doc, linux-kernel
lru_gen_offline_memcg() moves an offlining memcg to the head of the old
generation of the memcg LRU (MEMCG_LRU_OLD), so that global reclaim
visits it first and evicts the folios it left behind.
Since commit f1cf8d2f36dc ("mm: memcontrol: eliminate the problem of
dying memory cgroup for LRU folios"), those folios are reparented to the
parent before lru_gen_offline_memcg() runs, and nothing can be added
back to the offlined memcg's lruvec afterwards. Putting an empty
offlined memcg at the head of the old generation no longer serves any
purpose and only delays reclaim from the memcgs that still have memory
due to additional shrink_many() iteration.
Remove lru_gen_offline_memcg(), so that an offlined memcg is rotated
like any other memcg below the reclaimable size threshold until
lru_gen_release_memcg() takes it off the memcg LRU. MEMCG_LRU_OLD has no
other user, so remove the op and update the memcg LRU comment as well.
Signed-off-by: T.J. Mercier <tjmercier@google.com>
---
Documentation/mm/multigen_lru.rst | 4 +---
include/linux/mmzone.h | 14 +++-----------
mm/memcontrol.c | 1 -
mm/vmscan.c | 20 +-------------------
4 files changed, 5 insertions(+), 34 deletions(-)
diff --git a/Documentation/mm/multigen_lru.rst b/Documentation/mm/multigen_lru.rst
index 52ed5092022f..b532ce961371 100644
--- a/Documentation/mm/multigen_lru.rst
+++ b/Documentation/mm/multigen_lru.rst
@@ -234,9 +234,7 @@ the active/inactive LRU (of folios):
1. It has the young and the old (generations), i.e., the counterparts
to the active and the inactive;
2. The increment of ``max_seq`` triggers promotion, i.e., the
- counterpart to activation;
-3. Other events trigger similar operations, e.g., offlining an memcg
- triggers demotion, i.e., the counterpart to deactivation.
+ counterpart to activation.
In terms of global reclaim, it has two distinct features:
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 7f078ff0dd76..542e465ee7a1 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -626,12 +626,10 @@ struct lru_gen_mm_walk {
* per-node memcg generation counter, whose reminder (mod MEMCG_NR_GENS) indexes
* the old generation, is incremented when all its bins become empty.
*
- * There are three operations:
+ * There are two operations:
* 1. MEMCG_LRU_TAIL, which moves a memcg to the tail of a random bin in its
* current generation (old or young) and updates its "seg" to "tail";
- * 2. MEMCG_LRU_OLD, which moves a memcg to the head of a random bin in the old
- * generation, updates its "gen" to "old" and resets its "seg" to "default";
- * 3. MEMCG_LRU_YOUNG, which moves a memcg to the tail of a random bin in the
+ * 2. MEMCG_LRU_YOUNG, which moves a memcg to the tail of a random bin in the
* young generation, updates its "gen" to "young" and resets its "seg" to
* "default".
*
@@ -643,8 +641,7 @@ struct lru_gen_mm_walk {
* 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.
+ * 5. Finishing the aging on the eviction path, which triggers MEMCG_LRU_YOUNG.
*
* Notes:
* 1. Memcg LRU only applies to global reclaim, and the round-robin incrementing
@@ -675,7 +672,6 @@ bool lru_gen_look_around(struct page_vma_mapped_walk *pvmw, unsigned int nr);
void lru_gen_init_memcg(struct mem_cgroup *memcg);
void lru_gen_exit_memcg(struct mem_cgroup *memcg);
void lru_gen_online_memcg(struct mem_cgroup *memcg);
-void lru_gen_offline_memcg(struct mem_cgroup *memcg);
void lru_gen_release_memcg(struct mem_cgroup *memcg);
void max_lru_gen_memcg(struct mem_cgroup *memcg, int nid);
bool recheck_lru_gen_max_memcg(struct mem_cgroup *memcg, int nid);
@@ -709,10 +705,6 @@ static inline void lru_gen_online_memcg(struct mem_cgroup *memcg)
{
}
-static inline void lru_gen_offline_memcg(struct mem_cgroup *memcg)
-{
-}
-
static inline void lru_gen_release_memcg(struct mem_cgroup *memcg)
{
}
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index a05d9a8baa1b..e2ddf0680e62 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -4475,7 +4475,6 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css)
memcg_reparent_objcgs(memcg);
reparent_shrinker_deferred(memcg);
wb_memcg_offline(memcg);
- lru_gen_offline_memcg(memcg);
drain_all_stock(memcg);
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 636152d8c94d..45a2c1021f4f 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -4538,7 +4538,6 @@ bool lru_gen_look_around(struct page_vma_mapped_walk *pvmw, unsigned int nr)
enum {
MEMCG_LRU_NOP,
MEMCG_LRU_TAIL,
- MEMCG_LRU_OLD,
MEMCG_LRU_YOUNG,
};
@@ -4560,8 +4559,6 @@ static void lru_gen_rotate_memcg(struct lruvec *lruvec, int op)
/* see the comment on MEMCG_NR_GENS */
if (op == MEMCG_LRU_TAIL)
seg = MEMCG_LRU_TAIL;
- else if (op == MEMCG_LRU_OLD)
- new = get_memcg_gen(pgdat->memcg_lru.seq);
else if (op == MEMCG_LRU_YOUNG)
new = get_memcg_gen(pgdat->memcg_lru.seq + 1);
else
@@ -4571,11 +4568,7 @@ static void lru_gen_rotate_memcg(struct lruvec *lruvec, int op)
WRITE_ONCE(lruvec->lrugen.gen, new);
hlist_nulls_del_rcu(&lruvec->lrugen.list);
-
- if (op == MEMCG_LRU_OLD)
- hlist_nulls_add_head_rcu(&lruvec->lrugen.list, &pgdat->memcg_lru.fifo[new][bin]);
- else
- hlist_nulls_add_tail_rcu(&lruvec->lrugen.list, &pgdat->memcg_lru.fifo[new][bin]);
+ hlist_nulls_add_tail_rcu(&lruvec->lrugen.list, &pgdat->memcg_lru.fifo[new][bin]);
pgdat->memcg_lru.nr_memcgs[old]--;
pgdat->memcg_lru.nr_memcgs[new]++;
@@ -4613,17 +4606,6 @@ void lru_gen_online_memcg(struct mem_cgroup *memcg)
}
}
-void lru_gen_offline_memcg(struct mem_cgroup *memcg)
-{
- int nid;
-
- for_each_node(nid) {
- struct lruvec *lruvec = get_lruvec(memcg, nid);
-
- lru_gen_rotate_memcg(lruvec, MEMCG_LRU_OLD);
- }
-}
-
void lru_gen_release_memcg(struct mem_cgroup *memcg)
{
int gen;
--
2.56.0.307.g5fe7bd680c-goog
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH 1/2] mm/vmscan: remove redundant !mem_cgroup_online() checks
2026-10-28 1:06 ` [PATCH 1/2] mm/vmscan: remove redundant !mem_cgroup_online() checks T.J. Mercier
@ 2026-10-28 2:32 ` Balbir Singh
2026-10-28 20:10 ` T.J. Mercier
2026-10-28 10:19 ` Kairui Song
` (3 subsequent siblings)
4 siblings, 1 reply; 15+ messages in thread
From: Balbir Singh @ 2026-10-28 2:32 UTC (permalink / raw)
To: T.J. Mercier
Cc: roman.gushchin, muchun.song, Andrew Morton, Kairui Song, Qi Zheng,
Shakeel Butt, Barry Song, Axel Rasmussen, Yuanchu Xie, Wei Xu,
Baoquan He, Baolin Wang, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Johannes Weiner, cgroups,
linux-mm, linux-kernel
On Tue, Oct 27, 2026 at 06:06:05PM -0700, T.J. Mercier wrote:
> 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@google.com>
> ---
> 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;
> }
> --
In some of the places do you want to consider adding a VM_WARN_ON_ONCE
for memcg_online not being true?
Acked-by: Balbir Singh <balbirs@nvidia.com>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/2] mm/mglru: stop rotating offlined memcgs to the old generation
2026-10-28 1:06 ` [PATCH 2/2] mm/mglru: stop rotating offlined memcgs to the old generation T.J. Mercier
@ 2026-10-28 2:42 ` Balbir Singh
2026-10-28 10:43 ` Kairui Song
2026-10-29 6:09 ` Baolin Wang
2 siblings, 0 replies; 15+ messages in thread
From: Balbir Singh @ 2026-10-28 2:42 UTC (permalink / raw)
To: T.J. Mercier
Cc: roman.gushchin, muchun.song, Andrew Morton, Kairui Song, Qi Zheng,
Shakeel Butt, Barry Song, Axel Rasmussen, Yuanchu Xie, Wei Xu,
Baoquan He, Baolin Wang, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Jonathan Corbet, Shuah Khan,
Randy Dunlap, Johannes Weiner, cgroups, linux-mm, linux-doc,
linux-kernel
On Tue, Oct 27, 2026 at 06:06:06PM -0700, T.J. Mercier wrote:
> lru_gen_offline_memcg() moves an offlining memcg to the head of the old
> generation of the memcg LRU (MEMCG_LRU_OLD), so that global reclaim
> visits it first and evicts the folios it left behind.
>
> Since commit f1cf8d2f36dc ("mm: memcontrol: eliminate the problem of
> dying memory cgroup for LRU folios"), those folios are reparented to the
> parent before lru_gen_offline_memcg() runs, and nothing can be added
> back to the offlined memcg's lruvec afterwards. Putting an empty
> offlined memcg at the head of the old generation no longer serves any
> purpose and only delays reclaim from the memcgs that still have memory
> due to additional shrink_many() iteration.
>
> Remove lru_gen_offline_memcg(), so that an offlined memcg is rotated
> like any other memcg below the reclaimable size threshold until
> lru_gen_release_memcg() takes it off the memcg LRU. MEMCG_LRU_OLD has no
> other user, so remove the op and update the memcg LRU comment as well.
>
> Signed-off-by: T.J. Mercier <tjmercier@google.com>
> ---
> Documentation/mm/multigen_lru.rst | 4 +---
> include/linux/mmzone.h | 14 +++-----------
> mm/memcontrol.c | 1 -
> mm/vmscan.c | 20 +-------------------
> 4 files changed, 5 insertions(+), 34 deletions(-)
>
> diff --git a/Documentation/mm/multigen_lru.rst b/Documentation/mm/multigen_lru.rst
> index 52ed5092022f..b532ce961371 100644
> --- a/Documentation/mm/multigen_lru.rst
> +++ b/Documentation/mm/multigen_lru.rst
> @@ -234,9 +234,7 @@ the active/inactive LRU (of folios):
> 1. It has the young and the old (generations), i.e., the counterparts
> to the active and the inactive;
> 2. The increment of ``max_seq`` triggers promotion, i.e., the
> - counterpart to activation;
> -3. Other events trigger similar operations, e.g., offlining an memcg
> - triggers demotion, i.e., the counterpart to deactivation.
> + counterpart to activation.
>
> In terms of global reclaim, it has two distinct features:
>
> diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
> index 7f078ff0dd76..542e465ee7a1 100644
> --- a/include/linux/mmzone.h
> +++ b/include/linux/mmzone.h
> @@ -626,12 +626,10 @@ struct lru_gen_mm_walk {
> * per-node memcg generation counter, whose reminder (mod MEMCG_NR_GENS) indexes
> * the old generation, is incremented when all its bins become empty.
> *
> - * There are three operations:
> + * There are two operations:
> * 1. MEMCG_LRU_TAIL, which moves a memcg to the tail of a random bin in its
> * current generation (old or young) and updates its "seg" to "tail";
> - * 2. MEMCG_LRU_OLD, which moves a memcg to the head of a random bin in the old
> - * generation, updates its "gen" to "old" and resets its "seg" to "default";
> - * 3. MEMCG_LRU_YOUNG, which moves a memcg to the tail of a random bin in the
> + * 2. MEMCG_LRU_YOUNG, which moves a memcg to the tail of a random bin in the
> * young generation, updates its "gen" to "young" and resets its "seg" to
> * "default".
> *
> @@ -643,8 +641,7 @@ struct lru_gen_mm_walk {
> * 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.
> + * 5. Finishing the aging on the eviction path, which triggers MEMCG_LRU_YOUNG.
> *
> * Notes:
> * 1. Memcg LRU only applies to global reclaim, and the round-robin incrementing
> @@ -675,7 +672,6 @@ bool lru_gen_look_around(struct page_vma_mapped_walk *pvmw, unsigned int nr);
> void lru_gen_init_memcg(struct mem_cgroup *memcg);
> void lru_gen_exit_memcg(struct mem_cgroup *memcg);
> void lru_gen_online_memcg(struct mem_cgroup *memcg);
> -void lru_gen_offline_memcg(struct mem_cgroup *memcg);
> void lru_gen_release_memcg(struct mem_cgroup *memcg);
> void max_lru_gen_memcg(struct mem_cgroup *memcg, int nid);
> bool recheck_lru_gen_max_memcg(struct mem_cgroup *memcg, int nid);
> @@ -709,10 +705,6 @@ static inline void lru_gen_online_memcg(struct mem_cgroup *memcg)
> {
> }
>
> -static inline void lru_gen_offline_memcg(struct mem_cgroup *memcg)
> -{
> -}
> -
> static inline void lru_gen_release_memcg(struct mem_cgroup *memcg)
> {
> }
> diff --git a/mm/memcontrol.c b/mm/memcontrol.c
> index a05d9a8baa1b..e2ddf0680e62 100644
> --- a/mm/memcontrol.c
> +++ b/mm/memcontrol.c
> @@ -4475,7 +4475,6 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css)
> memcg_reparent_objcgs(memcg);
> reparent_shrinker_deferred(memcg);
> wb_memcg_offline(memcg);
> - lru_gen_offline_memcg(memcg);
>
> drain_all_stock(memcg);
>
> diff --git a/mm/vmscan.c b/mm/vmscan.c
> index 636152d8c94d..45a2c1021f4f 100644
> --- a/mm/vmscan.c
> +++ b/mm/vmscan.c
> @@ -4538,7 +4538,6 @@ bool lru_gen_look_around(struct page_vma_mapped_walk *pvmw, unsigned int nr)
> enum {
> MEMCG_LRU_NOP,
> MEMCG_LRU_TAIL,
> - MEMCG_LRU_OLD,
> MEMCG_LRU_YOUNG,
> };
>
> @@ -4560,8 +4559,6 @@ static void lru_gen_rotate_memcg(struct lruvec *lruvec, int op)
> /* see the comment on MEMCG_NR_GENS */
> if (op == MEMCG_LRU_TAIL)
> seg = MEMCG_LRU_TAIL;
> - else if (op == MEMCG_LRU_OLD)
> - new = get_memcg_gen(pgdat->memcg_lru.seq);
> else if (op == MEMCG_LRU_YOUNG)
> new = get_memcg_gen(pgdat->memcg_lru.seq + 1);
> else
> @@ -4571,11 +4568,7 @@ static void lru_gen_rotate_memcg(struct lruvec *lruvec, int op)
> WRITE_ONCE(lruvec->lrugen.gen, new);
>
> hlist_nulls_del_rcu(&lruvec->lrugen.list);
> -
> - if (op == MEMCG_LRU_OLD)
> - hlist_nulls_add_head_rcu(&lruvec->lrugen.list, &pgdat->memcg_lru.fifo[new][bin]);
> - else
> - hlist_nulls_add_tail_rcu(&lruvec->lrugen.list, &pgdat->memcg_lru.fifo[new][bin]);
> + hlist_nulls_add_tail_rcu(&lruvec->lrugen.list, &pgdat->memcg_lru.fifo[new][bin]);
>
> pgdat->memcg_lru.nr_memcgs[old]--;
> pgdat->memcg_lru.nr_memcgs[new]++;
> @@ -4613,17 +4606,6 @@ void lru_gen_online_memcg(struct mem_cgroup *memcg)
> }
> }
>
> -void lru_gen_offline_memcg(struct mem_cgroup *memcg)
> -{
> - int nid;
> -
> - for_each_node(nid) {
> - struct lruvec *lruvec = get_lruvec(memcg, nid);
> -
> - lru_gen_rotate_memcg(lruvec, MEMCG_LRU_OLD);
> - }
> -}
> -
> void lru_gen_release_memcg(struct mem_cgroup *memcg)
> {
> int gen;
Acked-by: Balbir Singh <balbirs@nvidia.com>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/2] mm/vmscan: remove redundant !mem_cgroup_online() checks
2026-10-28 1:06 ` [PATCH 1/2] mm/vmscan: remove redundant !mem_cgroup_online() checks T.J. Mercier
2026-10-28 2:32 ` Balbir Singh
@ 2026-10-28 10:19 ` Kairui Song
2026-10-28 20:10 ` T.J. Mercier
2026-10-28 20:35 ` Barry Song
` (2 subsequent siblings)
4 siblings, 1 reply; 15+ messages in thread
From: Kairui Song @ 2026-10-28 10:19 UTC (permalink / raw)
To: T.J. Mercier
Cc: roman.gushchin, muchun.song, Andrew Morton, Kairui Song, Qi Zheng,
Shakeel Butt, Barry Song, Axel Rasmussen, Yuanchu Xie, Wei Xu,
Baoquan He, Baolin Wang, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Johannes Weiner, cgroups,
linux-mm, linux-kernel
On Tue, Oct 27, 2026 at 06:06:05PM +0800, T.J. Mercier wrote:
> 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@google.com>
> ---
> include/linux/mmzone.h | 8 ++++----
> mm/vmscan.c | 28 +++++-----------------------
> 2 files changed, 9 insertions(+), 27 deletions(-)
Nice!
>
> 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;
> }
This part looks much cleaner, thanks!
Reviewed-by: Kairui Song <kasong@tencent.com>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/2] mm/mglru: stop rotating offlined memcgs to the old generation
2026-10-28 1:06 ` [PATCH 2/2] mm/mglru: stop rotating offlined memcgs to the old generation T.J. Mercier
2026-10-28 2:42 ` Balbir Singh
@ 2026-10-28 10:43 ` Kairui Song
2026-10-28 20:56 ` Barry Song
2026-10-29 6:09 ` Baolin Wang
2 siblings, 1 reply; 15+ messages in thread
From: Kairui Song @ 2026-10-28 10:43 UTC (permalink / raw)
To: T.J. Mercier
Cc: roman.gushchin, muchun.song, Andrew Morton, Kairui Song, Qi Zheng,
Shakeel Butt, Barry Song, Axel Rasmussen, Yuanchu Xie, Wei Xu,
Baoquan He, Baolin Wang, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Jonathan Corbet, Shuah Khan,
Randy Dunlap, Johannes Weiner, cgroups, linux-mm, linux-doc,
linux-kernel
On Tue, Oct 27, 2026 at 06:06:06PM +0800, T.J. Mercier wrote:
> lru_gen_offline_memcg() moves an offlining memcg to the head of the old
> generation of the memcg LRU (MEMCG_LRU_OLD), so that global reclaim
> visits it first and evicts the folios it left behind.
>
> Since commit f1cf8d2f36dc ("mm: memcontrol: eliminate the problem of
> dying memory cgroup for LRU folios"), those folios are reparented to the
> parent before lru_gen_offline_memcg() runs, and nothing can be added
> back to the offlined memcg's lruvec afterwards. Putting an empty
> offlined memcg at the head of the old generation no longer serves any
> purpose and only delays reclaim from the memcgs that still have memory
> due to additional shrink_many() iteration.
>
> Remove lru_gen_offline_memcg(), so that an offlined memcg is rotated
> like any other memcg below the reclaimable size threshold until
> lru_gen_release_memcg() takes it off the memcg LRU. MEMCG_LRU_OLD has no
> other user, so remove the op and update the memcg LRU comment as well.
>
> Signed-off-by: T.J. Mercier <tjmercier@google.com>
> ---
> Documentation/mm/multigen_lru.rst | 4 +---
> include/linux/mmzone.h | 14 +++-----------
> mm/memcontrol.c | 1 -
> mm/vmscan.c | 20 +-------------------
> 4 files changed, 5 insertions(+), 34 deletions(-)
>
...
> diff --git a/mm/vmscan.c b/mm/vmscan.c
> index 636152d8c94d..45a2c1021f4f 100644
> --- a/mm/vmscan.c
> +++ b/mm/vmscan.c
> @@ -4538,7 +4538,6 @@ bool lru_gen_look_around(struct page_vma_mapped_walk *pvmw, unsigned int nr)
> enum {
> MEMCG_LRU_NOP,
> MEMCG_LRU_TAIL,
> - MEMCG_LRU_OLD,
> MEMCG_LRU_YOUNG,
> };
I think there could be other usage of this LRU_OLD macro, but indeed
offline is the only user currently, removing it is cleaner.
And everything looks good to me, thanks!
Reviewed-by: Kairui Song <kasong@tencent.com>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/2] mm/vmscan: remove redundant !mem_cgroup_online() checks
2026-10-28 2:32 ` Balbir Singh
@ 2026-10-28 20:10 ` T.J. Mercier
0 siblings, 0 replies; 15+ messages in thread
From: T.J. Mercier @ 2026-10-28 20:10 UTC (permalink / raw)
To: Balbir Singh
Cc: roman.gushchin, muchun.song, Andrew Morton, Kairui Song, Qi Zheng,
Shakeel Butt, Barry Song, Axel Rasmussen, Yuanchu Xie, Wei Xu,
Baoquan He, Baolin Wang, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Johannes Weiner, cgroups,
linux-mm, linux-kernel
On Tue, Oct 27, 2026 at 7:32 PM Balbir Singh <balbirs@nvidia.com> wrote:
>
> On Tue, Oct 27, 2026 at 06:06:05PM -0700, T.J. Mercier wrote:
> > 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@google.com>
> > ---
> > 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;
> > }
> > --
>
> In some of the places do you want to consider adding a VM_WARN_ON_ONCE
> for memcg_online not being true?
>
> Acked-by: Balbir Singh <balbirs@nvidia.com>
Thanks, does this look ok to you? We could also put it on the read
side in lruvec_lru_size(), but that backtrace will just show the
reclaim stack rather than whoever is trying to mutate the size of an
offline memcg.
@@ -49,6 +49,7 @@ static __always_inline void __update_lru_size(struct
lruvec *lruvec,
lockdep_assert_held(&lruvec->lru_lock);
WARN_ON_ONCE(nr_pages != (int)nr_pages);
+ VM_WARN_ON_ONCE(!mem_cgroup_online(lruvec_memcg(lruvec)));
mod_lruvec_state(lruvec, NR_LRU_BASE + lru, nr_pages);
__mod_zone_page_state(&pgdat->node_zones[zid],
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/2] mm/vmscan: remove redundant !mem_cgroup_online() checks
2026-10-28 10:19 ` Kairui Song
@ 2026-10-28 20:10 ` T.J. Mercier
0 siblings, 0 replies; 15+ messages in thread
From: T.J. Mercier @ 2026-10-28 20:10 UTC (permalink / raw)
To: Kairui Song
Cc: roman.gushchin, muchun.song, Andrew Morton, Kairui Song, Qi Zheng,
Shakeel Butt, Barry Song, Axel Rasmussen, Yuanchu Xie, Wei Xu,
Baoquan He, Baolin Wang, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Johannes Weiner, cgroups,
linux-mm, linux-kernel
On Wed, Oct 28, 2026 at 3:20 AM Kairui Song <ryncsn@gmail.com> wrote:
>
> On Tue, Oct 27, 2026 at 06:06:05PM +0800, T.J. Mercier wrote:
> > 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@google.com>
> > ---
> > include/linux/mmzone.h | 8 ++++----
> > mm/vmscan.c | 28 +++++-----------------------
> > 2 files changed, 9 insertions(+), 27 deletions(-)
>
> Nice!
>
> >
> > 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;
> > }
>
> This part looks much cleaner, thanks!
>
> Reviewed-by: Kairui Song <kasong@tencent.com>
Thanks Kairui
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/2] mm/vmscan: remove redundant !mem_cgroup_online() checks
2026-10-28 1:06 ` [PATCH 1/2] mm/vmscan: remove redundant !mem_cgroup_online() checks T.J. Mercier
2026-10-28 2:32 ` Balbir Singh
2026-10-28 10:19 ` Kairui Song
@ 2026-10-28 20:35 ` Barry Song
2026-10-28 21:21 ` Johannes Weiner
2026-10-28 21:26 ` Shakeel Butt
4 siblings, 0 replies; 15+ messages in thread
From: Barry Song @ 2026-10-28 20:35 UTC (permalink / raw)
To: T.J. Mercier
Cc: roman.gushchin, muchun.song, Andrew Morton, Kairui Song, Qi Zheng,
Shakeel Butt, Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He,
Baolin Wang, David Hildenbrand, Lorenzo Stoakes, Liam R. Howlett,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Johannes Weiner, cgroups, linux-mm, linux-kernel
On Wed, Oct 28, 2026 at 9:06 AM T.J. Mercier <tjmercier@google.com> wrote:
>
> 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@google.com>
> ---
Reviewed-by: Barry Song <baohua@kernel.org>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/2] mm/mglru: stop rotating offlined memcgs to the old generation
2026-10-28 10:43 ` Kairui Song
@ 2026-10-28 20:56 ` Barry Song
2026-10-28 21:22 ` T.J. Mercier
0 siblings, 1 reply; 15+ messages in thread
From: Barry Song @ 2026-10-28 20:56 UTC (permalink / raw)
To: Kairui Song
Cc: T.J. Mercier, roman.gushchin, muchun.song, Andrew Morton,
Kairui Song, Qi Zheng, Shakeel Butt, Axel Rasmussen, Yuanchu Xie,
Wei Xu, Baoquan He, Baolin Wang, David Hildenbrand,
Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Jonathan Corbet, Shuah Khan,
Randy Dunlap, Johannes Weiner, cgroups, linux-mm, linux-doc,
linux-kernel
On Wed, Oct 28, 2026 at 6:43 PM Kairui Song <ryncsn@gmail.com> wrote:
>
> On Tue, Oct 27, 2026 at 06:06:06PM +0800, T.J. Mercier wrote:
> > lru_gen_offline_memcg() moves an offlining memcg to the head of the old
> > generation of the memcg LRU (MEMCG_LRU_OLD), so that global reclaim
> > visits it first and evicts the folios it left behind.
> >
> > Since commit f1cf8d2f36dc ("mm: memcontrol: eliminate the problem of
> > dying memory cgroup for LRU folios"), those folios are reparented to the
> > parent before lru_gen_offline_memcg() runs, and nothing can be added
> > back to the offlined memcg's lruvec afterwards. Putting an empty
> > offlined memcg at the head of the old generation no longer serves any
> > purpose and only delays reclaim from the memcgs that still have memory
> > due to additional shrink_many() iteration.
> >
> > Remove lru_gen_offline_memcg(), so that an offlined memcg is rotated
> > like any other memcg below the reclaimable size threshold until
> > lru_gen_release_memcg() takes it off the memcg LRU. MEMCG_LRU_OLD has no
> > other user, so remove the op and update the memcg LRU comment as well.
> >
> > Signed-off-by: T.J. Mercier <tjmercier@google.com>
> > ---
> > Documentation/mm/multigen_lru.rst | 4 +---
> > include/linux/mmzone.h | 14 +++-----------
> > mm/memcontrol.c | 1 -
> > mm/vmscan.c | 20 +-------------------
> > 4 files changed, 5 insertions(+), 34 deletions(-)
> >
>
> ...
>
> > diff --git a/mm/vmscan.c b/mm/vmscan.c
> > index 636152d8c94d..45a2c1021f4f 100644
> > --- a/mm/vmscan.c
> > +++ b/mm/vmscan.c
> > @@ -4538,7 +4538,6 @@ bool lru_gen_look_around(struct page_vma_mapped_walk *pvmw, unsigned int nr)
> > enum {
> > MEMCG_LRU_NOP,
> > MEMCG_LRU_TAIL,
> > - MEMCG_LRU_OLD,
> > MEMCG_LRU_YOUNG,
> > };
>
> I think there could be other usage of this LRU_OLD macro, but indeed
> offline is the only user currently, removing it is cleaner.
I'm imagining an Android use case where, after LMKD or similar
userspace killers implemented by various OEMs kill an application,
we may want to prioritize reclaiming its memory by making it more
likely to be scanned and reclaimed, while the killed application's
memcg still exists - not offlined.
Similarly, a foreground application might benefit from a lower
chance of being scanned and reclaimed. This suggests that Android
background-to-foreground transitions, or LMKD itself, could
potentially leverage the reordering of memcg LRUs.
But anyway, this is not a reason to keep
MEMCG_LRU_OLD for now.
>
> And everything looks good to me, thanks!
>
> Reviewed-by: Kairui Song <kasong@tencent.com>
+1
Reviewed-by: Barry Song <baohua@kernel.org>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/2] mm/vmscan: remove redundant !mem_cgroup_online() checks
2026-10-28 1:06 ` [PATCH 1/2] mm/vmscan: remove redundant !mem_cgroup_online() checks T.J. Mercier
` (2 preceding siblings ...)
2026-10-28 20:35 ` Barry Song
@ 2026-10-28 21:21 ` Johannes Weiner
2026-10-28 21:26 ` Shakeel Butt
4 siblings, 0 replies; 15+ messages in thread
From: Johannes Weiner @ 2026-10-28 21:21 UTC (permalink / raw)
To: T.J. Mercier
Cc: roman.gushchin, muchun.song, Andrew Morton, Kairui Song, Qi Zheng,
Shakeel Butt, Barry Song, Axel Rasmussen, Yuanchu Xie, Wei Xu,
Baoquan He, Baolin Wang, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, cgroups, linux-mm, linux-kernel
On Tue, Oct 27, 2026 at 06:06:05PM -0700, T.J. Mercier wrote:
> 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@google.com>
Great cleanup!
Reviewed-by: Johannes Weiner <hannes@cmpxchg.org>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/2] mm/mglru: stop rotating offlined memcgs to the old generation
2026-10-28 20:56 ` Barry Song
@ 2026-10-28 21:22 ` T.J. Mercier
0 siblings, 0 replies; 15+ messages in thread
From: T.J. Mercier @ 2026-10-28 21:22 UTC (permalink / raw)
To: Barry Song
Cc: Kairui Song, roman.gushchin, muchun.song, Andrew Morton,
Kairui Song, Qi Zheng, Shakeel Butt, Axel Rasmussen, Yuanchu Xie,
Wei Xu, Baoquan He, Baolin Wang, David Hildenbrand,
Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Jonathan Corbet, Shuah Khan,
Randy Dunlap, Johannes Weiner, cgroups, linux-mm, linux-doc,
linux-kernel
On Wed, Oct 28, 2026 at 1:57 PM Barry Song <baohua@kernel.org> wrote:
>
> On Wed, Oct 28, 2026 at 6:43 PM Kairui Song <ryncsn@gmail.com> wrote:
> >
> > On Tue, Oct 27, 2026 at 06:06:06PM +0800, T.J. Mercier wrote:
> > > lru_gen_offline_memcg() moves an offlining memcg to the head of the old
> > > generation of the memcg LRU (MEMCG_LRU_OLD), so that global reclaim
> > > visits it first and evicts the folios it left behind.
> > >
> > > Since commit f1cf8d2f36dc ("mm: memcontrol: eliminate the problem of
> > > dying memory cgroup for LRU folios"), those folios are reparented to the
> > > parent before lru_gen_offline_memcg() runs, and nothing can be added
> > > back to the offlined memcg's lruvec afterwards. Putting an empty
> > > offlined memcg at the head of the old generation no longer serves any
> > > purpose and only delays reclaim from the memcgs that still have memory
> > > due to additional shrink_many() iteration.
> > >
> > > Remove lru_gen_offline_memcg(), so that an offlined memcg is rotated
> > > like any other memcg below the reclaimable size threshold until
> > > lru_gen_release_memcg() takes it off the memcg LRU. MEMCG_LRU_OLD has no
> > > other user, so remove the op and update the memcg LRU comment as well.
> > >
> > > Signed-off-by: T.J. Mercier <tjmercier@google.com>
> > > ---
> > > Documentation/mm/multigen_lru.rst | 4 +---
> > > include/linux/mmzone.h | 14 +++-----------
> > > mm/memcontrol.c | 1 -
> > > mm/vmscan.c | 20 +-------------------
> > > 4 files changed, 5 insertions(+), 34 deletions(-)
> > >
> >
> > ...
> >
> > > diff --git a/mm/vmscan.c b/mm/vmscan.c
> > > index 636152d8c94d..45a2c1021f4f 100644
> > > --- a/mm/vmscan.c
> > > +++ b/mm/vmscan.c
> > > @@ -4538,7 +4538,6 @@ bool lru_gen_look_around(struct page_vma_mapped_walk *pvmw, unsigned int nr)
> > > enum {
> > > MEMCG_LRU_NOP,
> > > MEMCG_LRU_TAIL,
> > > - MEMCG_LRU_OLD,
> > > MEMCG_LRU_YOUNG,
> > > };
> >
> > I think there could be other usage of this LRU_OLD macro, but indeed
> > offline is the only user currently, removing it is cleaner.
>
> I'm imagining an Android use case where, after LMKD or similar
> userspace killers implemented by various OEMs kill an application,
> we may want to prioritize reclaiming its memory by making it more
> likely to be scanned and reclaimed, while the killed application's
> memcg still exists - not offlined.
I think it's an idea worth investigating. I had a similar idea which
is proactive instead of depending on reclaim hints. The code is behind
a currently inactive flag - it runs memory.reclaim on an application
cgroup before offlining it (so no zombie or reparenting), but I
haven't had time to properly test it yet.
https://cs.android.com/android/platform/superproject/+/android-latest-release:system/core/libprocessgroup/include_platform/processgroup/processgroup_platform.h;drc=2ed7b05ab42dd67391ad2819b0ee399d89128ead;l=33-34
> Similarly, a foreground application might benefit from a lower
> chance of being scanned and reclaimed. This suggests that Android
> background-to-foreground transitions, or LMKD itself, could
> potentially leverage the reordering of memcg LRUs.
We are planning to use memory.low/min for foreground protection.
> But anyway, this is not a reason to keep
> MEMCG_LRU_OLD for now.
>
> >
> > And everything looks good to me, thanks!
> >
> > Reviewed-by: Kairui Song <kasong@tencent.com>
>
> +1
>
> Reviewed-by: Barry Song <baohua@kernel.org>
Thanks!
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/2] mm/vmscan: remove redundant !mem_cgroup_online() checks
2026-10-28 1:06 ` [PATCH 1/2] mm/vmscan: remove redundant !mem_cgroup_online() checks T.J. Mercier
` (3 preceding siblings ...)
2026-10-28 21:21 ` Johannes Weiner
@ 2026-10-28 21:26 ` Shakeel Butt
4 siblings, 0 replies; 15+ messages in thread
From: Shakeel Butt @ 2026-10-28 21:26 UTC (permalink / raw)
To: T.J. Mercier
Cc: roman.gushchin, muchun.song, Andrew Morton, Kairui Song, Qi Zheng,
Barry Song, Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He,
Baolin Wang, David Hildenbrand, Lorenzo Stoakes, Liam R. Howlett,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Johannes Weiner, cgroups, linux-mm, linux-kernel
On Tue, Oct 27, 2026 at 06:06:05PM -0700, T.J. Mercier wrote:
> 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@google.com>
Acked-by: Shakeel Butt <shakeel.butt@linux.dev>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/2] mm/mglru: stop rotating offlined memcgs to the old generation
2026-10-28 1:06 ` [PATCH 2/2] mm/mglru: stop rotating offlined memcgs to the old generation T.J. Mercier
2026-10-28 2:42 ` Balbir Singh
2026-10-28 10:43 ` Kairui Song
@ 2026-10-29 6:09 ` Baolin Wang
2 siblings, 0 replies; 15+ messages in thread
From: Baolin Wang @ 2026-10-29 6:09 UTC (permalink / raw)
To: T.J. Mercier, roman.gushchin, muchun.song, Andrew Morton,
Kairui Song, Qi Zheng, Shakeel Butt, Barry Song, Axel Rasmussen,
Yuanchu Xie, Wei Xu, Baoquan He, David Hildenbrand,
Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Jonathan Corbet, Shuah Khan,
Randy Dunlap, Johannes Weiner
Cc: cgroups, linux-mm, linux-doc, linux-kernel
On 10/28/26 9:06 AM, T.J. Mercier wrote:
> lru_gen_offline_memcg() moves an offlining memcg to the head of the old
> generation of the memcg LRU (MEMCG_LRU_OLD), so that global reclaim
> visits it first and evicts the folios it left behind.
>
> Since commit f1cf8d2f36dc ("mm: memcontrol: eliminate the problem of
> dying memory cgroup for LRU folios"), those folios are reparented to the
> parent before lru_gen_offline_memcg() runs, and nothing can be added
> back to the offlined memcg's lruvec afterwards. Putting an empty
> offlined memcg at the head of the old generation no longer serves any
> purpose and only delays reclaim from the memcgs that still have memory
> due to additional shrink_many() iteration.
>
> Remove lru_gen_offline_memcg(), so that an offlined memcg is rotated
> like any other memcg below the reclaimable size threshold until
> lru_gen_release_memcg() takes it off the memcg LRU. MEMCG_LRU_OLD has no
> other user, so remove the op and update the memcg LRU comment as well.
>
> Signed-off-by: T.J. Mercier <tjmercier@google.com>
> ---
Thanks for the cleanups. LGTM.
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2026-10-29 6:09 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-28 1:06 [PATCH 0/2] mm/vmscan: remove obsolete offlined memcg reclaim handling T.J. Mercier
2026-10-28 1:06 ` [PATCH 1/2] mm/vmscan: remove redundant !mem_cgroup_online() checks T.J. Mercier
2026-10-28 2:32 ` Balbir Singh
2026-10-28 20:10 ` T.J. Mercier
2026-10-28 10:19 ` Kairui Song
2026-10-28 20:10 ` T.J. Mercier
2026-10-28 20:35 ` Barry Song
2026-10-28 21:21 ` Johannes Weiner
2026-10-28 21:26 ` Shakeel Butt
2026-10-28 1:06 ` [PATCH 2/2] mm/mglru: stop rotating offlined memcgs to the old generation T.J. Mercier
2026-10-28 2:42 ` Balbir Singh
2026-10-28 10:43 ` Kairui Song
2026-10-28 20:56 ` Barry Song
2026-10-28 21:22 ` T.J. Mercier
2026-10-29 6:09 ` Baolin Wang
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.