[PATCH RFC 08/15] mm/memcg: add folio-based lruvec live helper
From: Kairui Song via B4 Relay
Date: Mon Aug 03 2026 - 15:50:21 EST
From: Kairui Song <kasong@xxxxxxxxxxx>
Add a helper that resolves a stable lruvec for a folio under RCU
without taking the lruvec lock. It takes a folio directly so the
lruvec lookup happens inside the RCU read-side critical section,
which a lruvec-based interface cannot guarantee.
The lock-taking variant now inlines the ancestor walk instead of
calling a separate helper.
No functional change.
Signed-off-by: Kairui Song <kasong@xxxxxxxxxxx>
---
include/linux/memcontrol.h | 38 ++++++++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 68f363000d7f..ea0111392b9b 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -1506,6 +1506,44 @@ static inline void lruvec_lock_irq(struct lruvec *lruvec)
spin_lock_irq(&lruvec->lru_lock);
}
+/**
+ * folio_lruvec_live_get - get a live lruvec for a folio under RCU
+ * @folio: the folio
+ *
+ * Computes @folio's lruvec and walks up to the nearest live ancestor
+ * if the folio's memcg is dying. Must be paired with
+ * folio_lruvec_live_put().
+ *
+ * Return: the live lruvec, with rcu_read_lock held.
+ */
+static inline struct lruvec *folio_lruvec_live_get(struct folio *folio)
+{
+#ifdef CONFIG_MEMCG
+ struct lruvec *lruvec;
+ struct pglist_data *pgdat;
+ struct mem_cgroup *memcg;
+
+ rcu_read_lock();
+ lruvec = folio_lruvec(folio);
+ pgdat = lruvec_pgdat(lruvec);
+ memcg = lruvec_memcg(lruvec);
+ while (unlikely(memcg && css_is_dying(&memcg->css))) {
+ memcg = parent_mem_cgroup(memcg);
+ lruvec = mem_cgroup_lruvec(memcg, pgdat);
+ }
+ return lruvec;
+#else
+ return folio_lruvec(folio);
+#endif
+}
+
+static inline void folio_lruvec_live_put(struct lruvec *lruvec)
+{
+#ifdef CONFIG_MEMCG
+ rcu_read_unlock();
+#endif
+}
+
static inline struct lruvec *lruvec_live_lock_irq(struct lruvec *lruvec)
{
#ifdef CONFIG_MEMCG
--
2.55.0