Re: [PATCH v2] fs: push nr_cached_objects memcg gating into individual filesystems

Qi Zheng <[email protected]> Thu, 30 Jul 2026 16:58:03 +0800
Newsgroups org.kernel.vger.cgroups,org.kernel.vger.linux-btrfs,org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-kernel,org.kvack.linux-mm
Message-ID <[email protected]>

On 7/15/26 6:35 PM, Usama Arif wrote:
> Commit 0baad6f9b997 ("fs/super: skip non-memcg-aware nr_cached_objects
> in memcg slab shrink") added a check in fs/super.c that skipped every
> ->nr_cached_objects() hook whenever the shrinker was invoked for a
> non-root memcg, on the assumption that none of them honour sc->memcg.
> 
> That assumption is wrong for XFS, whose inode-reclaim hook is
> intentionally driven from per-memcg contexts to free memcg-charged
> slab. Encoding a blanket "never memcg-aware" policy in fs/super.c
> short-circuits that path.
> 
> Push the check down into the callbacks whose counters really are
> irrelevant to per-memcg reclaim - btrfs_nr_cached_objects() and
> shmem_unused_huge_count() - and drop the fs/super.c gate. Each
> filesystem can now lift the restriction independently if its counter
> later grows memcg awareness, without touching fs/super.c.
> 
> Introduce mem_cgroup_shrink_is_root() in <linux/memcontrol.h> so the
> callbacks don't open-code "sc->memcg is NULL or root".
> 
> Fixes: 0baad6f9b997 ("fs/super: skip non-memcg-aware nr_cached_objects in memcg slab shrink")
> Acked-by: Qi Zheng <[email protected]>
> Reviewed-by: Jan Kara <[email protected]>
> Reviewed-by: Shakeel Butt <[email protected]>
> Signed-off-by: Usama Arif <[email protected]>
> ---
> v1 -> v2:
> - Do not gate xfs_fs_nr_cached_objects(); XFS's inode reclaim is
>    intentionally driven from per-memcg contexts to free memcg-charged
>    slab (Dave Chinner).
> - Add mem_cgroup_shrink_is_root() helper in <linux/memcontrol.h> so the
>    filesystem callbacks don't open-code "sc->memcg is NULL or root".
>    (Dave Chinner)
> - Add fixes tag (Dave Chinner)
> ---
>   fs/btrfs/super.c           | 10 ++++++++++
>   fs/super.c                 | 19 ++-----------------
>   include/linux/memcontrol.h | 21 +++++++++++++++++++++
>   mm/shmem.c                 | 10 ++++++++++
>   4 files changed, 43 insertions(+), 17 deletions(-)
> 
> diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
> index a7d804219bec..cc4537435399 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,15 @@ 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.
> +	 */
> +	if (!mem_cgroup_shrink_is_root(sc))
> +		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);
> -}
> -

Hi Christian, it looks like you missed this when pushing. The commit
0ef8faff490be (next-20260729) doesn't include this part of the code.

Thanks,
Qi