[PATCH RFC 02/32] mm/memcontrol: allow update of LRU statistic without holding LRU lock

From: Kairui Song via B4 Relay

Date: Fri May 01 2026 - 17:05:10 EST


From: Kairui Song <kasong@xxxxxxxxxxx>

To enable moving file pages in folio_mark_accessed directly and lazily
for MGLRU, allow updating the LRU statistic atomically without holding a
lock. It may cause temporary counter underflow, which should be fine as
we still follow final consistency of the counter, and it only serves as
a factor for calculating the reclaim budget in vmscan. A little
inaccuracy has no visible effect.

Signed-off-by: Kairui Song <kasong@xxxxxxxxxxx>
---
include/linux/memcontrol.h | 2 +-
include/linux/mm_inline.h | 3 +--
mm/memcontrol.c | 4 ++--
3 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 345a6ba8a3a7..2552f24afe38 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -889,7 +889,7 @@ unsigned long mem_cgroup_get_zone_lru_size(struct lruvec *lruvec,

mz = container_of(lruvec, struct mem_cgroup_per_node, lruvec);
val = atomic_long_read(&mz->lru_zone_size[zone_idx][lru]);
- if (WARN_ON_ONCE(val < 0))
+ if (val < 0)
return 0;

return val;
diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h
index a171070e15f0..045f9ee3880a 100644
--- a/include/linux/mm_inline.h
+++ b/include/linux/mm_inline.h
@@ -36,11 +36,10 @@ static __always_inline void __update_lru_size(struct lruvec *lruvec,
{
struct pglist_data *pgdat = lruvec_pgdat(lruvec);

- lockdep_assert_held(&lruvec->lru_lock);
WARN_ON_ONCE(nr_pages != (int)nr_pages);

mod_lruvec_state(lruvec, NR_LRU_BASE + lru, nr_pages);
- __mod_zone_page_state(&pgdat->node_zones[zid],
+ mod_zone_page_state(&pgdat->node_zones[zid],
NR_ZONE_LRU_BASE + lru, nr_pages);
}

diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 71fad2239973..a3571763e813 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -1477,8 +1477,8 @@ struct lruvec *folio_lruvec_lock_irqsave(struct folio *folio,
* @zid: zone id of the accounted pages
* @nr_pages: positive when adding or negative when removing
*
- * This function must be called under lru_lock, just before a page is added
- * to or just after a page is removed from an lru list.
+ * This function must be called when a page is added to or removed from
+ * an lru list. Caller need to protect the lruvec from being freed.
*/
void mem_cgroup_update_lru_size(struct lruvec *lruvec, enum lru_list lru,
int zid, long nr_pages)

--
2.54.0