From: Usama Arif <usama.arif@linux.dev>
To: brauner@kernel.org, qi.zheng@linux.dev, jack@suse.cz,
linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org,
Al Viro <viro@zeniv.linux.org.uk>,
linux-mm@kvack.org
Cc: hughd@google.com, boris@bur.io, clm@fb.com, dsterba@suse.com,
linux-btrfs@vger.kernel.org, cem@kernel.org,
linux-xfs@vger.kernel.org, shakeel.butt@linux.dev,
hannes@cmpxchg.org, riel@surriel.com, kernel-team@meta.com,
Usama Arif <usama.arif@linux.dev>
Subject: [PATCH] fs: push nr_cached_objects memcg gating into individual filesystems
Date: Tue, 14 Jul 2026 03:14:54 -0700 [thread overview]
Message-ID: <20260714101454.1202449-1-usama.arif@linux.dev> (raw)
Commit 0baad6f9b997 ("fs/super: skip non-memcg-aware nr_cached_objects
in memcg slab shrink") added a check in fs/super.c that skips the
->nr_cached_objects() hook whenever the shrinker is invoked for a
non-root memcg, because none of the current implementations (btrfs,
xfs, shmem huge) honour sc->memcg.
That policy is really a filesystem-owned property: fs/super.c should
not encode the assumption that these hooks are never memcg-aware,
since a future implementation might legitimately filter by sc->memcg.
Move the check into btrfs_nr_cached_objects(), xfs_fs_nr_cached_objects()
and shmem_unused_huge_count() so each filesystem can lift the
restriction independently once its underlying counters/scans become
memcg-aware, without needing a coordinated change to fs/super.c.
Behaviour is unchanged: calls into these hooks from shrink_slab_memcg()
still early-return 0 for non-root memcg contexts, keeping the shrinker
bit clearable in each memcg's bitmap; the global (kswapd or root
direct reclaim) path still drives them as before.
Signed-off-by: Usama Arif <usama.arif@linux.dev>
---
fs/btrfs/super.c | 11 +++++++++++
fs/super.c | 19 ++-----------------
fs/xfs/xfs_super.c | 12 ++++++++++++
mm/shmem.c | 11 +++++++++++
4 files changed, 36 insertions(+), 17 deletions(-)
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index a7d804219bec..16c24bccc897 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -22,6 +22,7 @@
#include <linux/namei.h>
#include <linux/miscdevice.h>
#include <linux/magic.h>
+#include <linux/memcontrol.h>
#include <linux/slab.h>
#include <linux/ratelimit.h>
#include <linux/crc32c.h>
@@ -2434,6 +2435,16 @@ static long btrfs_nr_cached_objects(struct super_block *sb, struct shrink_contro
struct btrfs_fs_info *fs_info = btrfs_sb(sb);
const s64 nr = percpu_counter_read_positive(&fs_info->evictable_extent_maps);
+ /*
+ * The evictable extent map counter is filesystem-global and does not
+ * honour sc->memcg, so it is only meaningful on the global (kswapd or
+ * root direct reclaim) shrink path. Skip the per-memcg iterations of
+ * shrink_slab_memcg() to avoid queueing duplicate global work and
+ * pinning the shrinker bit in every memcg's bitmap.
+ */
+ if (sc->memcg && !mem_cgroup_is_root(sc->memcg))
+ return 0;
+
trace_btrfs_extent_map_shrinker_count(fs_info, nr);
return nr;
diff --git a/fs/super.c b/fs/super.c
index d2d04a6f4f84..a8fd61136aaf 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -24,7 +24,6 @@
#include <linux/export.h>
#include <linux/slab.h>
#include <linux/blkdev.h>
-#include <linux/memcontrol.h>
#include <linux/mount.h>
#include <linux/security.h>
#include <linux/writeback.h> /* for the emergency remount stuff */
@@ -170,19 +169,6 @@ static void super_wake(struct super_block *sb, unsigned int flag)
wake_up_var(&sb->s_flags);
}
-/*
- * The s_op->nr_cached_objects hooks (used for example by btrfs and xfs)
- * operate on filesystem-global state and ignore sc->memcg. Driving them
- * from per-memcg shrink_slab_memcg() invocations only burns CPU walking
- * per-cpu counters and queueing duplicate work: the actual reclaim happens on
- * the global path (kswapd or root direct reclaim) regardless. Restrict them
- * to that path.
- */
-static inline bool super_fs_objects_eligible(struct shrink_control *sc)
-{
- return !sc->memcg || mem_cgroup_is_root(sc->memcg);
-}
-
/*
* One thing we have to be careful of with a per-sb shrinker is that we don't
* drop the last active reference to the superblock from within the shrinker.
@@ -212,7 +198,7 @@ static unsigned long super_cache_scan(struct shrinker *shrink,
if (!super_trylock_shared(sb))
return SHRINK_STOP;
- if (sb->s_op->nr_cached_objects && super_fs_objects_eligible(sc))
+ if (sb->s_op->nr_cached_objects)
fs_objects = sb->s_op->nr_cached_objects(sb, sc);
inodes = list_lru_shrink_count(&sb->s_inode_lru, sc);
@@ -273,8 +259,7 @@ static unsigned long super_cache_count(struct shrinker *shrink,
return 0;
smp_rmb();
- if (sb->s_op && sb->s_op->nr_cached_objects &&
- super_fs_objects_eligible(sc))
+ if (sb->s_op && sb->s_op->nr_cached_objects)
total_objects = sb->s_op->nr_cached_objects(sb, sc);
total_objects += list_lru_shrink_count(&sb->s_dentry_lru, sc);
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index eac7f9503805..f0d8251fad3b 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -54,6 +54,7 @@
#include "scrub/rcbag_btree.h"
#include <linux/magic.h>
+#include <linux/memcontrol.h>
#include <linux/fs_context.h>
#include <linux/fs_parser.h>
#include <linux/fserror.h>
@@ -1242,6 +1243,17 @@ xfs_fs_nr_cached_objects(
/* Paranoia: catch incorrect calls during mount setup or teardown */
if (WARN_ON_ONCE(!sb->s_fs_info))
return 0;
+
+ /*
+ * The reclaimable inode count is filesystem-global and does not honour
+ * sc->memcg, so it is only meaningful on the global (kswapd or root
+ * direct reclaim) shrink path. Skip the per-memcg iterations of
+ * shrink_slab_memcg() to avoid queueing duplicate global work and
+ * pinning the shrinker bit in every memcg's bitmap.
+ */
+ if (sc->memcg && !mem_cgroup_is_root(sc->memcg))
+ return 0;
+
return xfs_reclaim_inodes_count(XFS_M(sb));
}
diff --git a/mm/shmem.c b/mm/shmem.c
index 5789a0f5a346..3ba812e4f5ba 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -846,6 +846,17 @@ static long shmem_unused_huge_count(struct super_block *sb,
struct shrink_control *sc)
{
struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
+
+ /*
+ * The per-superblock shrinklist is filesystem-global and does not
+ * honour sc->memcg, so it is only meaningful on the global (kswapd or
+ * root direct reclaim) shrink path. Skip the per-memcg iterations of
+ * shrink_slab_memcg() to avoid queueing duplicate global work and
+ * pinning the shrinker bit in every memcg's bitmap.
+ */
+ if (sc->memcg && !mem_cgroup_is_root(sc->memcg))
+ return 0;
+
return READ_ONCE(sbinfo->shrinklist_len);
}
#else /* !CONFIG_TRANSPARENT_HUGEPAGE */
--
2.53.0-Meta
next reply other threads:[~2026-07-14 10:15 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-14 10:14 Usama Arif [this message]
2026-07-14 10:56 ` [PATCH] fs: push nr_cached_objects memcg gating into individual filesystems Qi Zheng
2026-07-14 15:20 ` Jan Kara
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260714101454.1202449-1-usama.arif@linux.dev \
--to=usama.arif@linux.dev \
--cc=boris@bur.io \
--cc=brauner@kernel.org \
--cc=cem@kernel.org \
--cc=clm@fb.com \
--cc=dsterba@suse.com \
--cc=hannes@cmpxchg.org \
--cc=hughd@google.com \
--cc=jack@suse.cz \
--cc=kernel-team@meta.com \
--cc=linux-btrfs@vger.kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=linux-xfs@vger.kernel.org \
--cc=qi.zheng@linux.dev \
--cc=riel@surriel.com \
--cc=shakeel.butt@linux.dev \
--cc=viro@zeniv.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.