Skip to contentSkip to conversation

make unused huge shrinker memcg aware

PATCH Applied Qi Zheng 5 participants 17 messages Aug 17 – Sep 1

Subsystems (6)
lore
Share & tools
lore

Qi Zheng

author
#0 lore raw

v4 cover make unused huge shrinker memcg aware

From: Qi Zheng <[email protected]>

Changes in v4:
- add [PATCH v4 2/4] to make obj_cgroup_memcg() handle NULL objcg
- store obj_cgroup instead of mem_cgroup in shmem_inode_info to avoid pinning a dying memcg through a long-lived CSS reference (pointed by sashiko)
- fix is_shmem_unused_huge_match() to always check the NUMA node for shrinker reclaim, not only for non-root memcg reclaim (pointed by sashiko)
- collect Reviewed-by
- rebase onto the next-20260814

Note: [PATCH v4 1/4] should ideally be folded into commit 0ef8faff490be ("fs: push nr_cached_objects memcg gating into individual filesystems") in linux-next.

Changes in v3:
- add a fix patch to fix missed removal of super_fs_objects_eligible()
- move the original shrinklist addition logic after all checks are completed, and split it into a separate patch. (suggested by Baolin)
- simplify the shmem_unused_huge_requeue() (suggested by Baolin)
- keep the move_back label in shmem_unused_huge_shrink() (suggested by Baolin)
- rebase onto the next-20260731

Changes in v2:
- temporarily add the dependent patch from Usama to the series for review convenience
- remove shrinklist_scan and shrinklist_isolated from struct shmem_inode_info, and re-implement the logic by resuing the same info->shrinklist (suggested by Baolin)
- add more comments (suggested by Andrew)
- fix missing initialization of info->shrinklist_memcg (pointed by sashiko)
- rebase onto the next-20260717

Hi all,

The shmem unused huge shrinker maintains a per-superblock list of inodes whose tail huge folio extends beyond i_size. Because this list is not memcg aware, reclaim triggered by memcg A can scan inodes across the entire superblock and split huge folios charged to unrelated memcg B, causing unexpected impact on it.

In the worst case, memcg A has no reclaimable shmem at all, making the reclaim entirely useless and incurring unnecessary latency. We observed this in production, where page lock contention during split caused multi-hundred-millisecond stalls:

tid 11340 comm scanner locked a page for 182264 us! kstack:

          unlock_page+1
          split_huge_page_to_list+3135
          shmem_unused_huge_shrink+767
          super_cache_scan+329
          do_shrink_slab+291
          shrink_slab+533
          shrink_node+400
          do_try_to_free_pages+206
          try_to_free_mem_cgroup_pages+262
          try_charge_memcg+591
          mem_cgroup_charge+136
          __handle_mm_fault+2431
          handle_mm_fault+194
          do_user_addr_fault+462
          __do_page_fault+176
          do_page_fault+48
          page_fault+62

Usama's recent patch [1] prevents the shmem unused shrinker from being invoked during memcg-level reclaim altogether, but this is overly
conservative: we can do better by reclaiming only the shmem charged to the reclaiming memcg.

This series converts the shrinker list to a memcg-aware list_lru, so that non-root memcg reclaim walks only candidates charged to the reclaiming memcg. Global reclaim, root memcg reclaim and shmem quota reclaim retain their existing global semantics.

To avoid pinning a dying memcg through a long-lived CSS reference, each inode stores an obj_cgroup reference instead of a mem_cgroup reference. The list_lru add/delete paths resolve the current memcg from the objcg under RCU, staying consistent with list_lru's own memcg migration on offline.

Thanks,
Qi

[1]. https://lore.kernel.org/all/[email protected]/

Qi Zheng (4):
fs: fix missed removal of super_fs_objects_eligible()
mm: memcontrol: make obj_cgroup_memcg() handle NULL objcg
mm: shmem: move unused huge shrinklist queuing past the truncation
check
mm: shmem: make unused huge shrinker memcg aware

 fs/super.c                 |  18 +-
 include/linux/memcontrol.h |  11 +-
 include/linux/shmem_fs.h   |  12 +-
 mm/page_owner.c            |   2 +-
 mm/shmem.c                 | 382 ++++++++++++++++++++++++++++---------
 mm/zswap.c                 |  17 +-
 6 files changed, 315 insertions(+), 127 deletions(-)
Signature · 1 line
2.54.0
author
#1 lore raw

PATCH v4 1/4 fs: fix missed removal of super_fs_objects_eligible()

From: Qi Zheng <[email protected]>

Commit 0ef8faff490be ("fs: push nr_cached_objects memcg gating into individual filesystems") forgot to drop the super_fs_objects_eligible(), just fix it.

Fixes 0ef8faff490be ("fs: push nr_cached_objects memcg gating into individual filesystems")
---
 fs/super.c | 18 ++----------------
 1 file changed, 2 insertions(+), 16 deletions(-)
fs/super.c +2 -16
index 05e4431730387..3ecce24328f67 100644
@@ -171,19 +171,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.
@@ -213,7 +200,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);
@@ -274,8 +261,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);
Signature · 1 line
2.54.0
maintainer
#2 lore raw

Re: [PATCH v4 1/4] fs: fix missed removal of super_fs_objects_eligible()

Quoted 5 lines · On Mon, 17 Aug 2026 17:03:25 +0800 Qi Zheng <[email protected]> wrote:

From: Qi Zheng <[email protected]>

Commit 0ef8faff490be ("fs: push nr_cached_objects memcg gating into individual filesystems") forgot to drop the super_fs_objects_eligible(), just fix it.

Oh. Why? Please can we have a description of what's wrong with the current code?

author
#3 lore raw

Re: [PATCH v4 1/4] fs: fix missed removal of super_fs_objects_eligible()

Hi Andrew,

Quoted 10 lines · Andrew Morton
Quoted 5 lines · On Mon, 17 Aug 2026 17:03:25 +0800 Qi Zheng <[email protected]> wrote:

From: Qi Zheng <[email protected]>

Commit 0ef8faff490be ("fs: push nr_cached_objects memcg gating into individual filesystems") forgot to drop the super_fs_objects_eligible(), just fix it.

Oh. Why? Please can we have a description of what's wrong with the current code?

As I replied in another thread [1], this fix and commit 0ef8faff490be together make up the complete patch originally sent by Usama [2], so they should be squashed together. Without this fix, all memcg-aware nr_cached_objects() will be skipped during memcg-level shrinking. Besides the newly added memcg-aware shmem huge shrinker, XFS will also run into issues.

[1]. https://lore.kernel.org/all/[email protected]/
[2]. https://lore.kernel.org/all/[email protected]/

Thanks,
Qi

Quoted 1 line
maintainer
#4 lore raw

Re: [PATCH v4 1/4] fs: fix missed removal of super_fs_objects_eligible()

Quoted 11 lines · On Sat, 29 Aug 2026 09:49:44 +0800 Qi Zheng <[email protected]> wrote:

Hi Andrew,

Quoted 8 lines · Andrew Morton
Quoted 5 lines · On Mon, 17 Aug 2026 17:03:25 +0800 Qi Zheng <[email protected]> wrote:

From: Qi Zheng <[email protected]>

Commit 0ef8faff490be ("fs: push nr_cached_objects memcg gating into individual filesystems") forgot to drop the super_fs_objects_eligible(), just fix it.

Quoted 6 lines
Quoted 2 lines

Oh. Why? Please can we have a description of what's wrong with the current code?

As I replied in another thread [1], this fix and commit 0ef8faff490be together make up the complete patch originally sent by Usama [2], so they should be squashed together.

0ef8faff490be is upstream so they can't be squashed!

Quoted 4 lines

Without this fix, all memcg-aware
nr_cached_objects() will be skipped during memcg-level shrinking. Besides the newly added memcg-aware shmem huge shrinker, XFS will also run into issues.

OK, please add this info to this patch's changelog. Please also decide whether a cc:stable should be added and if so, ensure the changelog makes clear why we're recommending a backport.

As part of this, let's expand on "XFS will also run into issues".

Thanks.

author
#5 lore raw

Re: [PATCH v4 1/4] fs: fix missed removal of super_fs_objects_eligible()

Hi Andrew,

Quoted 13 lines · Andrew Morton
Quoted 11 lines · On Sat, 29 Aug 2026 09:49:44 +0800 Qi Zheng <[email protected]> wrote:

Hi Andrew,

Quoted 8 lines · Andrew Morton
Quoted 5 lines · On Mon, 17 Aug 2026 17:03:25 +0800 Qi Zheng <[email protected]> wrote:

From: Qi Zheng <[email protected]>

Commit 0ef8faff490be ("fs: push nr_cached_objects memcg gating into individual filesystems") forgot to drop the super_fs_objects_eligible(), just fix it.

Quoted 8 lines
Quoted 6 lines
Quoted 2 lines

Oh. Why? Please can we have a description of what's wrong with the current code?

As I replied in another thread [1], this fix and commit 0ef8faff490be together make up the complete patch originally sent by Usama [2], so they should be squashed together.

0ef8faff490be is upstream so they can't be squashed!

So sad.

Quoted 11 lines
Quoted 5 lines

Without this fix, all memcg-aware
nr_cached_objects() will be skipped during memcg-level shrinking. Besides the newly added memcg-aware shmem huge shrinker, XFS will also run into issues.

OK, please add this info to this patch's changelog. Please also decide whether a cc:stable should be added and if so, ensure the changelog makes clear why we're recommending a backport.

As part of this, let's expand on "XFS will also run into issues".

How about this instead:

---
Commit 0ef8faff490be ("fs: push nr_cached_objects memcg gating into individual filesystems") was meant to drop the blanket memcg gate in fs/super.c and let each ->nr_cached_objects() implementation decide for itself whether it is meaningful in per-memcg reclaim. However, when that patch was applied the removal of super_fs_objects_eligible() and its two call sites in super_cache_scan() / super_cache_count() was lost, so the helper is still gating every ->nr_cached_objects() hook and 0ef8faff490be is effectively a no-op.

Consequences of the leftover gate:

- XFS's inode-reclaim hook, which is intentionally driven from per-memcg contexts to free memcg-charged slab, is still short-circuited in fs/super.c — exactly the regression from commit 0baad6f9b997 ("fs/super: skip non-memcg-aware nr_cached_objects in memcg slab shrink") that 0ef8faff490be was written to undo. Memcg-charged XFS inode slab therefore keeps piling up under per-memcg pressure until global reclaim kicks in.

- Any future ->nr_cached_objects()/->free_cached_objects() that grows memcg awareness is likewise blocked before it can run, so filesystems cannot opt in to per-memcg reclaim on their own — defeating the whole point of pushing the gating decision down into the callbacks.

Drop the leftover helper and its call sites so the intent of 0ef8faff490be actually takes effect.

Fixes 0ef8faff490be ("fs: push nr_cached_objects memcg gating into individual filesystems")

---

Can you fix up the commit message directly on your end? Let me know if you prefer me to spin a v5 instead.

Thank,
Qi

Quoted 3 lines

Thanks.

maintainer
#6 lore raw

Re: [PATCH v4 1/4] fs: fix missed removal of super_fs_objects_eligible()

Quoted 37 lines · On Mon, 31 Aug 2026 10:28:00 +0800 Qi Zheng <[email protected]> wrote:
Quoted 5 lines

OK, please add this info to this patch's changelog. Please also decide whether a cc:stable should be added and if so, ensure the changelog makes clear why we're recommending a backport.

As part of this, let's expand on "XFS will also run into issues".

How about this instead:

---
Commit 0ef8faff490be ("fs: push nr_cached_objects memcg gating into individual filesystems") was meant to drop the blanket memcg gate in fs/super.c and let each ->nr_cached_objects() implementation decide for itself whether it is meaningful in per-memcg reclaim. However, when that patch was applied the removal of super_fs_objects_eligible() and its two call sites in super_cache_scan() / super_cache_count() was lost, so the helper is still gating every ->nr_cached_objects() hook and 0ef8faff490be is effectively a no-op.

Consequences of the leftover gate:

- XFS's inode-reclaim hook, which is intentionally driven from per-memcg contexts to free memcg-charged slab, is still short-circuited in fs/super.c — exactly the regression from commit 0baad6f9b997 ("fs/super: skip non-memcg-aware nr_cached_objects in memcg slab shrink") that 0ef8faff490be was written to undo. Memcg-charged XFS inode slab therefore keeps piling up under per-memcg pressure until global reclaim kicks in.

- Any future ->nr_cached_objects()/->free_cached_objects() that grows memcg awareness is likewise blocked before it can run, so filesystems cannot opt in to per-memcg reclaim on their own — defeating the whole point of pushing the gating decision down into the callbacks.

Drop the leftover helper and its call sites so the intent of 0ef8faff490be actually takes effect.

Quoted 7 lines
Fixes 0ef8faff490be ("fs: push nr_cached_objects memcg gating into

individual filesystems")
Cc: [email protected]
---

Can you fix up the commit message directly on your end? Let me know if you prefer me to spin a v5 instead.

Thanks. I pasted this in and turned your [1/4] into a standalone patch for mm-hotfixes, with a cc:stable.

The remaining three patches I turned into a separate series for the next merge window.

This particular patch has no evidence of reviewer input yet?

From: Qi Zheng <[email protected]>
Subject: fs: fix missed removal of super_fs_objects_eligible()
Date: Mon, 17 Aug 2026 17:03:25 +0800

Commit 0ef8faff490be ("fs: push nr_cached_objects memcg gating into individual filesystems") was meant to drop the blanket memcg gate in fs/super.c and let each ->nr_cached_objects() implementation decide for itself whether it is meaningful in per-memcg reclaim. However, when that patch was applied the removal of super_fs_objects_eligible() and its two call sites in super_cache_scan() / super_cache_count() was lost, so the helper is still gating every ->nr_cached_objects() hook and 0ef8faff490be is effectively a no-op.

Consequences of the leftover gate:

- XFS's inode-reclaim hook, which is intentionally driven from per-memcg contexts to free memcg-charged slab, is still short-circuited in fs/super.c exactly the regression from commit 0baad6f9b997 ("fs/super: skip non-memcg-aware nr_cached_objects in memcg slab shrink") that 0ef8faff490be was written to undo. Memcg-charged XFS inode slab therefore keeps piling up under per-memcg pressure until global reclaim kicks in.

- Any future ->nr_cached_objects()/->free_cached_objects() that grows memcg awareness is likewise blocked before it can run, so filesystems cannot opt in to per-memcg reclaim on their own defeating the whole point of pushing the gating decision down into the callbacks.

Drop the leftover helper and its call sites so the intent of 0ef8faff490be actually takes effect.

Fixes 0ef8faff490b ("fs: push nr_cached_objects memcg gating into individual filesystems")
Cc Baolin Wang <[email protected]>
Cc Christian Brauner <[email protected]>
Cc David Hildenbrand <[email protected]>
Cc Hugh Dickins <[email protected]>
Cc Christian Brauner <[email protected]>
Cc David Hildenbrand <[email protected]>
Cc Hugh Dickins <[email protected]>
Cc Johannes Weiner <[email protected]>
Cc Michal Hocko <[email protected]>
Cc Muchun Song <[email protected]>
Cc Roman Gushchin <[email protected]>
Cc Shakeel Butt <[email protected]>

---

 fs/super.c |   18 ++----------------
 1 file changed, 2 insertions(+), 16 deletions(-)
fs/super.c renamed from fs/super.c~fs-fix-missed-removal-of-super_fs_objects_eligible +2 -16
@@ -172,19 +172,6 @@ static void super_wake(struct super_bloc
 }
 
 /*
- * 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.
  * If that happens we could trigger unregistering the shrinker from within the
@@ -213,7 +200,7 @@ static unsigned long super_cache_scan(st
 	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);
@@ -274,8 +261,7 @@ static unsigned long super_cache_count(s
 		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);

_

author
#7 lore raw

Re: [PATCH v4 1/4] fs: fix missed removal of super_fs_objects_eligible()

Quoted 44 lines · Andrew Morton
Quoted 42 lines · On Mon, 31 Aug 2026 10:28:00 +0800 Qi Zheng <[email protected]> wrote:
Quoted 5 lines

OK, please add this info to this patch's changelog. Please also decide whether a cc:stable should be added and if so, ensure the changelog makes clear why we're recommending a backport.

As part of this, let's expand on "XFS will also run into issues".

How about this instead:

---
Commit 0ef8faff490be ("fs: push nr_cached_objects memcg gating into individual filesystems") was meant to drop the blanket memcg gate in fs/super.c and let each ->nr_cached_objects() implementation decide for itself whether it is meaningful in per-memcg reclaim. However, when that patch was applied the removal of super_fs_objects_eligible() and its two call sites in super_cache_scan() / super_cache_count() was lost, so the helper is still gating every ->nr_cached_objects() hook and 0ef8faff490be is effectively a no-op.

Consequences of the leftover gate:

- XFS's inode-reclaim hook, which is intentionally driven from per-memcg contexts to free memcg-charged slab, is still short-circuited in fs/super.c — exactly the regression from commit 0baad6f9b997 ("fs/super: skip non-memcg-aware nr_cached_objects in memcg slab shrink") that 0ef8faff490be was written to undo. Memcg-charged XFS inode slab therefore keeps piling up under per-memcg pressure until global reclaim kicks in.

- Any future ->nr_cached_objects()/->free_cached_objects() that grows memcg awareness is likewise blocked before it can run, so filesystems cannot opt in to per-memcg reclaim on their own — defeating the whole point of pushing the gating decision down into the callbacks.

Drop the leftover helper and its call sites so the intent of 0ef8faff490be actually takes effect.

Fixes 0ef8faff490be ("fs: push nr_cached_objects memcg gating into

individual filesystems")
Cc: [email protected]
---

Quoted 5 lines
Quoted 2 lines

Can you fix up the commit message directly on your end? Let me know if you prefer me to spin a v5 instead.

Thanks. I pasted this in and turned your [1/4] into a standalone patch for mm-hotfixes, with a cc:stable.

Thanks!

Quoted 3 lines

The remaining three patches I turned into a separate series for the next merge window.

OK.

Quoted 2 lines

This particular patch has no evidence of reviewer input yet?

Hi Usama, could you please help review this patch?

Thanks,
Qi

Quoted 101 lines

From: Qi Zheng <[email protected]>
Subject: fs: fix missed removal of super_fs_objects_eligible()
Date: Mon, 17 Aug 2026 17:03:25 +0800

Commit 0ef8faff490be ("fs: push nr_cached_objects memcg gating into individual filesystems") was meant to drop the blanket memcg gate in fs/super.c and let each ->nr_cached_objects() implementation decide for itself whether it is meaningful in per-memcg reclaim. However, when that patch was applied the removal of super_fs_objects_eligible() and its two call sites in super_cache_scan() / super_cache_count() was lost, so the helper is still gating every ->nr_cached_objects() hook and 0ef8faff490be is effectively a no-op.

Consequences of the leftover gate:

- XFS's inode-reclaim hook, which is intentionally driven from per-memcg contexts to free memcg-charged slab, is still short-circuited in fs/super.c exactly the regression from commit 0baad6f9b997 ("fs/super: skip non-memcg-aware nr_cached_objects in memcg slab shrink") that 0ef8faff490be was written to undo. Memcg-charged XFS inode slab therefore keeps piling up under per-memcg pressure until global reclaim kicks in.

- Any future ->nr_cached_objects()/->free_cached_objects() that grows memcg awareness is likewise blocked before it can run, so filesystems cannot opt in to per-memcg reclaim on their own defeating the whole point of pushing the gating decision down into the callbacks.

Drop the leftover helper and its call sites so the intent of 0ef8faff490be actually takes effect.

Fixes 0ef8faff490b ("fs: push nr_cached_objects memcg gating into individual filesystems")
Cc Baolin Wang <[email protected]>
Cc Christian Brauner <[email protected]>
Cc David Hildenbrand <[email protected]>
Cc Hugh Dickins <[email protected]>
Cc Christian Brauner <[email protected]>
Cc David Hildenbrand <[email protected]>
Cc Hugh Dickins <[email protected]>
Cc Johannes Weiner <[email protected]>
Cc Michal Hocko <[email protected]>
Cc Muchun Song <[email protected]>
Cc Roman Gushchin <[email protected]>
Cc Shakeel Butt <[email protected]>

---

  fs/super.c |   18 ++----------------
  1 file changed, 2 insertions(+), 16 deletions(-)
fs/super.c renamed from fs/super.c~fs-fix-missed-removal-of-super_fs_objects_eligible +2 -16
@@ -172,19 +172,6 @@ static void super_wake(struct super_bloc
  }
 
  /*
- * 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.
   * If that happens we could trigger unregistering the shrinker from within the
@@ -213,7 +200,7 @@ static unsigned long super_cache_scan(st
  	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);
@@ -274,8 +261,7 @@ static unsigned long super_cache_count(s
  		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);

_

Acked-by
#8 lore raw

Re: [PATCH v4 1/4] fs: fix missed removal of super_fs_objects_eligible()

In reply to Andrew Morton
Quoted 107 lines · Andrew Morton
Quoted 37 lines · On Mon, 31 Aug 2026 10:28:00 +0800 Qi Zheng <[email protected]> wrote:
Quoted 5 lines

OK, please add this info to this patch's changelog. Please also decide whether a cc:stable should be added and if so, ensure the changelog makes clear why we're recommending a backport.

As part of this, let's expand on "XFS will also run into issues".

How about this instead:

---
Commit 0ef8faff490be ("fs: push nr_cached_objects memcg gating into individual filesystems") was meant to drop the blanket memcg gate in fs/super.c and let each ->nr_cached_objects() implementation decide for itself whether it is meaningful in per-memcg reclaim. However, when that patch was applied the removal of super_fs_objects_eligible() and its two call sites in super_cache_scan() / super_cache_count() was lost, so the helper is still gating every ->nr_cached_objects() hook and 0ef8faff490be is effectively a no-op.

Consequences of the leftover gate:

- XFS's inode-reclaim hook, which is intentionally driven from per-memcg contexts to free memcg-charged slab, is still short-circuited in fs/super.c — exactly the regression from commit 0baad6f9b997 ("fs/super: skip non-memcg-aware nr_cached_objects in memcg slab shrink") that 0ef8faff490be was written to undo. Memcg-charged XFS inode slab therefore keeps piling up under per-memcg pressure until global reclaim kicks in.

- Any future ->nr_cached_objects()/->free_cached_objects() that grows memcg awareness is likewise blocked before it can run, so filesystems cannot opt in to per-memcg reclaim on their own — defeating the whole point of pushing the gating decision down into the callbacks.

Drop the leftover helper and its call sites so the intent of 0ef8faff490be actually takes effect.

Quoted 7 lines
Fixes 0ef8faff490be ("fs: push nr_cached_objects memcg gating into

individual filesystems")
Cc: [email protected]
---

Can you fix up the commit message directly on your end? Let me know if you prefer me to spin a v5 instead.

Thanks. I pasted this in and turned your [1/4] into a standalone patch for mm-hotfixes, with a cc:stable.

The remaining three patches I turned into a separate series for the next merge window.

This particular patch has no evidence of reviewer input yet?

From: Qi Zheng <[email protected]>
Subject: fs: fix missed removal of super_fs_objects_eligible()
Date: Mon, 17 Aug 2026 17:03:25 +0800

Commit 0ef8faff490be ("fs: push nr_cached_objects memcg gating into individual filesystems") was meant to drop the blanket memcg gate in fs/super.c and let each ->nr_cached_objects() implementation decide for itself whether it is meaningful in per-memcg reclaim. However, when that patch was applied the removal of super_fs_objects_eligible() and its two call sites in super_cache_scan() / super_cache_count() was lost, so the helper is still gating every ->nr_cached_objects() hook and 0ef8faff490be is effectively a no-op.

Consequences of the leftover gate:

- XFS's inode-reclaim hook, which is intentionally driven from per-memcg contexts to free memcg-charged slab, is still short-circuited in fs/super.c exactly the regression from commit 0baad6f9b997 ("fs/super: skip non-memcg-aware nr_cached_objects in memcg slab shrink") that 0ef8faff490be was written to undo. Memcg-charged XFS inode slab therefore keeps piling up under per-memcg pressure until global reclaim kicks in.

- Any future ->nr_cached_objects()/->free_cached_objects() that grows memcg awareness is likewise blocked before it can run, so filesystems cannot opt in to per-memcg reclaim on their own defeating the whole point of pushing the gating decision down into the callbacks.

Drop the leftover helper and its call sites so the intent of 0ef8faff490be actually takes effect.

Fixes 0ef8faff490b ("fs: push nr_cached_objects memcg gating into individual filesystems")
Cc Baolin Wang <[email protected]>
Cc Christian Brauner <[email protected]>
Cc David Hildenbrand <[email protected]>
Cc Hugh Dickins <[email protected]>
Cc Christian Brauner <[email protected]>
Cc David Hildenbrand <[email protected]>
Cc Hugh Dickins <[email protected]>
Cc Johannes Weiner <[email protected]>
Cc Michal Hocko <[email protected]>
Cc Muchun Song <[email protected]>
Cc Roman Gushchin <[email protected]>
Cc Shakeel Butt <[email protected]>
Quoted 2 lines

---

Yeah unfortunately this was a mess up with a part of the patch not being applied.

author
#9 lore raw

PATCH v4 2/4 mm: memcontrol: make obj_cgroup_memcg() handle NULL objcg

In reply to Qi Zheng

From: Qi Zheng <[email protected]>

obj_cgroup_memcg() currently requires a non-NULL objcg, so callers that may hold a NULL objcg must guard the call with an explicit NULL check. This pattern is duplicated in folio_memcg(), folio_memcg_check(), mm/page_owner.c, and mm/zswap.c.

Teach obj_cgroup_memcg() to accept NULL and return NULL in that case, then remove the redundant NULL checks at the call sites. Also remove the mem_cgroup_from_entry() wrapper in zswap, which existed solely to provide this NULL-safe behaviour, and replace its two callers with direct obj_cgroup_memcg() calls.

No functional change intended.

---
 include/linux/memcontrol.h | 11 ++++++++---
 mm/page_owner.c            |  2 +-
 mm/zswap.c                 | 17 ++---------------
 3 files changed, 11 insertions(+), 19 deletions(-)
include/linux/memcontrol.h +8 -3
index cba35690c21aa..5107c227ae9b8 100644
@@ -375,7 +375,7 @@ enum objext_flags {
 static inline struct mem_cgroup *obj_cgroup_memcg(struct obj_cgroup *objcg)
 {
 	lockdep_assert_once(rcu_read_lock_held() || lockdep_is_held(&cgroup_mutex));
-	return READ_ONCE(objcg->memcg);
+	return objcg ? READ_ONCE(objcg->memcg) : NULL;
 }
 
 /*
@@ -428,7 +428,7 @@ static inline struct mem_cgroup *folio_memcg(struct folio *folio)
 {
 	struct obj_cgroup *objcg = folio_objcg(folio);
 
-	return objcg ? obj_cgroup_memcg(objcg) : NULL;
+	return obj_cgroup_memcg(objcg);
 }
 
 /*
@@ -471,7 +471,7 @@ static inline struct mem_cgroup *folio_memcg_check(struct folio *folio)
 
 	objcg = (void *)(memcg_data & ~OBJEXTS_FLAGS_MASK);
 
-	return objcg ? obj_cgroup_memcg(objcg) : NULL;
+	return obj_cgroup_memcg(objcg);
 }
 
 static inline struct mem_cgroup *page_memcg_check(struct page *page)
@@ -1045,6 +1045,11 @@ void mem_cgroup_flush_workqueue(void);
 extern int mem_cgroup_init(void);
 #else /* CONFIG_MEMCG */
 
+static inline struct mem_cgroup *obj_cgroup_memcg(struct obj_cgroup *objcg)
+{
+	return NULL;
+}
+
 #define MEM_CGROUP_ID_SHIFT	0
 
 #define root_mem_cgroup		(NULL)
mm/page_owner.c +1 -1
index fbbda7ba914ba..3fc37d9b908ef 100644
@@ -575,7 +575,7 @@ static inline int print_page_owner_memcg(char *kbuf, size_t count, int ret,
 	}
 
 	objcg = (void *)(memcg_data & ~OBJEXTS_FLAGS_MASK);
-	memcg = objcg ? obj_cgroup_memcg(objcg) : NULL;
+	memcg = obj_cgroup_memcg(objcg);
 	if (!memcg)
 		goto out_unlock;
 
mm/zswap.c +2 -15
index 37f34e406c8e3..c1dc60926bad9 100644
@@ -647,19 +647,6 @@ static int zswap_enabled_param_set(const char *val,
 * lru functions
 **********************************/
 
-/* should be called under RCU */
-#ifdef CONFIG_MEMCG
-static inline struct mem_cgroup *mem_cgroup_from_entry(struct zswap_entry *entry)
-{
-	return entry->objcg ? obj_cgroup_memcg(entry->objcg) : NULL;
-}
-#else
-static inline struct mem_cgroup *mem_cgroup_from_entry(struct zswap_entry *entry)
-{
-	return NULL;
-}
-#endif
-
 static inline int entry_to_nid(struct zswap_entry *entry)
 {
 	return page_to_nid(virt_to_page(entry));
@@ -682,7 +669,7 @@ static void zswap_lru_add(struct zswap_entry *entry)
 	 * Similar reasoning holds for list_lru_del().
 	 */
 	rcu_read_lock();
-	memcg = mem_cgroup_from_entry(entry);
+	memcg = obj_cgroup_memcg(entry->objcg);
 	/* will always succeed */
 	list_lru_add(&zswap_list_lru, &entry->lru, nid, memcg);
 	rcu_read_unlock();
@@ -694,7 +681,7 @@ static void zswap_lru_del(struct zswap_entry *entry)
 	struct mem_cgroup *memcg;
 
 	rcu_read_lock();
-	memcg = mem_cgroup_from_entry(entry);
+	memcg = obj_cgroup_memcg(entry->objcg);
 	/* will always succeed */
 	list_lru_del(&zswap_list_lru, &entry->lru, nid, memcg);
 	rcu_read_unlock();
Signature · 1 line
2.54.0
author
#10 lore raw

Re: [PATCH v4 2/4] mm: memcontrol: make obj_cgroup_memcg() handle NULL objcg

CC the maintainers of MEMCG who were missed in the previous email.

maintainer Acked-by on v4 2/4
#11 lore raw

Re: [PATCH v4 2/4] mm: memcontrol: make obj_cgroup_memcg() handle NULL objcg

In reply to Qi Zheng
Quoted 13 lines · Qi Zheng

From: Qi Zheng <[email protected]>

obj_cgroup_memcg() currently requires a non-NULL objcg, so callers that may hold a NULL objcg must guard the call with an explicit NULL check. This pattern is duplicated in folio_memcg(), folio_memcg_check(), mm/page_owner.c, and mm/zswap.c.

Teach obj_cgroup_memcg() to accept NULL and return NULL in that case, then remove the redundant NULL checks at the call sites. Also remove the mem_cgroup_from_entry() wrapper in zswap, which existed solely to provide this NULL-safe behaviour, and replace its two callers with direct obj_cgroup_memcg() calls.

Quoted 3 lines

No functional change intended.

author
#12 lore raw

PATCH v4 3/4 mm: shmem: move unused huge shrinklist queuing past the truncation check

In reply to Qi Zheng

From: Qi Zheng <[email protected]>

The shmem_get_folio_gfp() adds the inode to the unused huge shrinker list at the alloced label, but a subsequent truncation check may still fail and remove the folio, leaving the inode on the list with a stale folio.

The original code works because the shrinker re-looks-up the folio and drops stale entries, but it is cleaner to queue the inode only after all checks that might remove the folio have passed.

So just make the pure structural move with no functional change, and it serves as preparation for the memcg-aware shrinker conversion.

---
 mm/shmem.c | 48 +++++++++++++++++++++++++++---------------------
 1 file changed, 27 insertions(+), 21 deletions(-)
mm/shmem.c +27 -21
index 897fa2b61346f..81eff314cfab8 100644
@@ -2536,27 +2536,6 @@ static int shmem_get_folio_gfp(struct inode *inode, pgoff_t index,
 
 alloced:
 	alloced = true;
-	if (folio_test_large(folio) &&
-	    DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE) <
-					folio_next_index(folio)) {
-		struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
-		struct shmem_inode_info *info = SHMEM_I(inode);
-		/*
-		 * Part of the large folio is beyond i_size: subject
-		 * to shrink under memory pressure.
-		 */
-		spin_lock(&sbinfo->shrinklist_lock);
-		/*
-		 * _careful to defend against unlocked access to
-		 * ->shrink_list in shmem_unused_huge_shrink()
-		 */
-		if (list_empty_careful(&info->shrinklist)) {
-			list_add_tail(&info->shrinklist,
-				      &sbinfo->shrinklist);
-			sbinfo->shrinklist_len++;
-		}
-		spin_unlock(&sbinfo->shrinklist_lock);
-	}
 
 	if (sgp == SGP_WRITE)
 		folio_set_referenced(folio);
@@ -2586,6 +2565,33 @@ static int shmem_get_folio_gfp(struct inode *inode, pgoff_t index,
 		error = -EINVAL;
 		goto unlock;
 	}
+
+	/*
+	 * Queue the inode on the shrink list only after all checks that might
+	 * remove the folio have passed. Otherwise the inode could be left on
+	 * the shrinker list with a stale folio.
+	 */
+	if (alloced && folio_test_large(folio) &&
+	    DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE) < folio_next_index(folio)) {
+		struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
+		struct shmem_inode_info *info = SHMEM_I(inode);
+		/*
+		 * Part of the large folio is beyond i_size: subject
+		 * to shrink under memory pressure.
+		 */
+		spin_lock(&sbinfo->shrinklist_lock);
+		/*
+		 * _careful to defend against unlocked access to
+		 * ->shrink_list in shmem_unused_huge_shrink()
+		 */
+		if (list_empty_careful(&info->shrinklist)) {
+			list_add_tail(&info->shrinklist,
+				      &sbinfo->shrinklist);
+			sbinfo->shrinklist_len++;
+		}
+		spin_unlock(&sbinfo->shrinklist_lock);
+	}
+
 out:
 	*foliop = folio;
 	return 0;
Signature · 1 line
2.54.0
author
#13 lore raw

PATCH v4 4/4 mm: shmem: make unused huge shrinker memcg aware

In reply to Qi Zheng

From: Qi Zheng <[email protected]>

The shmem unused huge shrinker keeps a per-superblock list of inodes whose tail huge folio extends beyond i_size. Since that list is not memcg aware, reclaim triggered by one memcg can scan inodes from the whole superblock and split shmem huge folios charged to unrelated memcgs.

Convert the shrink list to a memcg-aware list_lru. Queue each inode on the list_lru sublist matching the memcg and node of the current tail huge folio, so non-root memcg reclaim only walks candidates charged to the reclaiming memcg. Global reclaim, root memcg reclaim and shmem quota reclaim keep global semantics.

Rather than pinning a struct mem_cgroup reference in shmem_inode_info, store a struct obj_cgroup reference instead. The list_lru add and delete paths resolve the current memcg from the objcg under RCU, so that memcg offline and list_lru entry migration remain consistent: list_lru migrates entries to the parent memcg sublist on offline, and obj_cgroup_memcg() follows the same reparenting, ensuring the correct sublist is always found at delete time. This avoids pinning a dying memcg through a long-lived CSS reference.

The list_lru still tracks inodes while the actual split target is the current tail huge folio, so validate the folio memcg/node during scan. If the folio no longer matches the reclaim context or splitting cannot proceed, requeue the inode according to the current tail folio; if the inode is no longer shrinkable, drop the scan entry.

This can be tested with the shrinker debugfs interface by allocating 32 tmpfs tail THPs in each of two memcgs, then scanning the sb-tmpfs shrinker with memcg A's cgroup id:

               before A scan    after A scan
  base         A=64M, B=64M     A=64M, B=64M (per-memcg count is skipped)
  patched      A=64M, B=64M     A=0,   B=64M
---
 include/linux/shmem_fs.h |  12 +-
 mm/shmem.c               | 362 ++++++++++++++++++++++++++++++---------
 2 files changed, 289 insertions(+), 85 deletions(-)
include/linux/shmem_fs.h +9 -3
index 5663dff53186e..a7c7a96a7cbf9 100644
@@ -11,6 +11,7 @@
 #include <linux/fs_parser.h>
 #include <linux/userfaultfd_k.h>
 #include <linux/bits.h>
+#include <linux/list_lru.h>
 
 /* inode in-kernel data */
 
@@ -54,6 +55,11 @@ struct shmem_inode_info {
 	struct dquot __rcu	*i_dquot[MAXQUOTAS];
 #endif
 	struct inode		vfs_inode;
+
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+	struct obj_cgroup	*shrinklist_objcg;
+	int			shrinklist_nid;
+#endif
 };
 
 #define SHMEM_FL_USER_VISIBLE		(FS_FL_USER_VISIBLE | FS_CASEFOLD_FL)
@@ -83,9 +89,9 @@ struct shmem_sb_info {
 	ino_t next_ino;		    /* The next per-sb inode number to use */
 	ino_t __percpu *ino_batch;  /* The next per-cpu inode number to use */
 	struct mempolicy *mpol;     /* default memory policy for mappings */
-	spinlock_t shrinklist_lock;   /* Protects shrinklist */
-	struct list_head shrinklist;  /* List of shinkable inodes */
-	unsigned long shrinklist_len; /* Length of shrinklist */
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+	struct list_lru shrinklist; /* List of shrinkable inodes */
+#endif
 	struct shmem_quota_limits qlimits; /* Default quota limits */
 	struct simple_xattr_cache xa_cache;
 };
mm/shmem.c +280 -82

466 lines not on this page · raw message

Signature · 1 line
2.54.0
reviewer Reviewed-by on v4 4/4
#14 lore raw

Re: [PATCH v4 4/4] mm: shmem: make unused huge shrinker memcg aware

Quoted 32 lines · Qi Zheng

From: Qi Zheng <[email protected]>

The shmem unused huge shrinker keeps a per-superblock list of inodes whose tail huge folio extends beyond i_size. Since that list is not memcg aware, reclaim triggered by one memcg can scan inodes from the whole superblock and split shmem huge folios charged to unrelated memcgs.

Convert the shrink list to a memcg-aware list_lru. Queue each inode on the list_lru sublist matching the memcg and node of the current tail huge folio, so non-root memcg reclaim only walks candidates charged to the reclaiming memcg. Global reclaim, root memcg reclaim and shmem quota reclaim keep global semantics.

Rather than pinning a struct mem_cgroup reference in shmem_inode_info, store a struct obj_cgroup reference instead. The list_lru add and delete paths resolve the current memcg from the objcg under RCU, so that memcg offline and list_lru entry migration remain consistent: list_lru migrates entries to the parent memcg sublist on offline, and obj_cgroup_memcg() follows the same reparenting, ensuring the correct sublist is always found at delete time. This avoids pinning a dying memcg through a long-lived CSS reference.

The list_lru still tracks inodes while the actual split target is the current tail huge folio, so validate the folio memcg/node during scan. If the folio no longer matches the reclaim context or splitting cannot proceed, requeue the inode according to the current tail folio; if the inode is no longer shrinkable, drop the scan entry.

This can be tested with the shrinker debugfs interface by allocating 32 tmpfs tail THPs in each of two memcgs, then scanning the sb-tmpfs shrinker with memcg A's cgroup id:

Quoted 6 lines
                before A scan    after A scan
   base         A=64M, B=64M     A=64M, B=64M (per-memcg count is skipped)
   patched      A=64M, B=64M     A=0,   B=64M

---

Nothing else jumped out at me. Thanks.

maintainer
#15 lore raw
In reply to Qi Zheng
Quoted 3 lines · On Mon, 17 Aug 2026 17:03:24 +0800 Qi Zheng <[email protected]> wrote:

Changes in v4:
Changes in v3:
Changes in v2:

Thanks for the diligent versioning info. fyi, it is conventional to maintain this below the --- separator. It's not really the most important part of the [0/N]!

Quoted 11 lines

The shmem unused huge shrinker maintains a per-superblock list of inodes whose tail huge folio extends beyond i_size. Because this list is not memcg aware, reclaim triggered by memcg A can scan inodes across the entire superblock and split huge folios charged to unrelated memcg B, causing unexpected impact on it.

In the worst case, memcg A has no reclaimable shmem at all, making the reclaim entirely useless and incurring unnecessary latency. We observed this in production, where page lock contention during split caused multi-hundred-millisecond stalls:

Ugh. That's the most important part!

Quoted 29 lines

tid 11340 comm scanner locked a page for 182264 us! kstack:

          unlock_page+1
          split_huge_page_to_list+3135
          shmem_unused_huge_shrink+767
          super_cache_scan+329
          do_shrink_slab+291
          shrink_slab+533
          shrink_node+400
          do_try_to_free_pages+206
          try_to_free_mem_cgroup_pages+262
          try_charge_memcg+591
          mem_cgroup_charge+136
          __handle_mm_fault+2431
          handle_mm_fault+194
          do_user_addr_fault+462
          __do_page_fault+176
          do_page_fault+48
          page_fault+62

Usama's recent patch [1] prevents the shmem unused shrinker from being invoked during memcg-level reclaim altogether, but this is overly
conservative: we can do better by reclaiming only the shmem charged to the reclaiming memcg.

This series converts the shrinker list to a memcg-aware list_lru, so that non-root memcg reclaim walks only candidates charged to the reclaiming memcg. Global reclaim, root memcg reclaim and shmem quota reclaim retain their existing global semantics.

Quoted 5 lines

To avoid pinning a dying memcg through a long-lived CSS reference, each inode stores an obj_cgroup reference instead of a mem_cgroup reference. The list_lru add/delete paths resolve the current memcg from the objcg under RCU, staying consistent with list_lru's own memcg migration on offline.

Sashiko said a few things and they look disturbing-if-true:

	https://sashiko.dev/#/patchset/[email protected]

(Apologies if this has already been considered - we don't have ways of tracking all this (yet, I hope) apart from personal memory and personal memorys are quite fried at present)

author
#16 lore raw

Hi Andrew,

Quoted 9 lines · Andrew Morton
Quoted 3 lines · On Mon, 17 Aug 2026 17:03:24 +0800 Qi Zheng <[email protected]> wrote:

Changes in v4:
Changes in v3:
Changes in v2:

Thanks for the diligent versioning info. fyi, it is conventional to maintain this below the --- separator. It's not really the most important part of the [0/N]!

Got it.

Quoted 50 lines
Quoted 8 lines

The shmem unused huge shrinker maintains a per-superblock list of inodes whose tail huge folio extends beyond i_size. Because this list is not memcg aware, reclaim triggered by memcg A can scan inodes across the entire superblock and split huge folios charged to unrelated memcg B, causing unexpected impact on it.

Quoted 4 lines

In the worst case, memcg A has no reclaimable shmem at all, making the reclaim entirely useless and incurring unnecessary latency. We observed this in production, where page lock contention during split caused multi-hundred-millisecond stalls:

Ugh. That's the most important part!

Quoted 29 lines
   tid 11340 comm scanner locked a page for 182264 us! kstack:
           unlock_page+1
           split_huge_page_to_list+3135
           shmem_unused_huge_shrink+767
           super_cache_scan+329
           do_shrink_slab+291
           shrink_slab+533
           shrink_node+400
           do_try_to_free_pages+206
           try_to_free_mem_cgroup_pages+262
           try_charge_memcg+591
           mem_cgroup_charge+136
           __handle_mm_fault+2431
           handle_mm_fault+194
           do_user_addr_fault+462
           __do_page_fault+176
           do_page_fault+48
           page_fault+62

Usama's recent patch [1] prevents the shmem unused shrinker from being invoked during memcg-level reclaim altogether, but this is overly
conservative: we can do better by reclaiming only the shmem charged to the reclaiming memcg.

This series converts the shrinker list to a memcg-aware list_lru, so that non-root memcg reclaim walks only candidates charged to the reclaiming memcg. Global reclaim, root memcg reclaim and shmem quota reclaim retain their existing global semantics.

Quoted 5 lines

To avoid pinning a dying memcg through a long-lived CSS reference, each inode stores an obj_cgroup reference instead of a mem_cgroup reference. The list_lru add/delete paths resolve the current memcg from the objcg under RCU, staying consistent with list_lru's own memcg migration on offline.

Quoted 7 lines

Sashiko said a few things and they look disturbing-if-true:

	https://sashiko.dev/#/patchset/[email protected]

(Apologies if this has already been considered - we don't have ways of tracking all this (yet, I hope) apart from personal memory and personal memorys are quite fried at present)

As both Usama and I have pointed out [1][2], [PATCH v4 1/4] is the part that got dropped during the merge. The complete patch [3] was actually reviewed a while ago.

[1].https://lore.kernel.org/all/[email protected]/ [2]. https://lore.kernel.org/all/[email protected]/
[3]. https://lore.kernel.org/all/[email protected]/

Thanks,
Qi

Quoted 1 line