Skip to contentSkip to conversation

mm/shrinker: do not hold RCU lock in shrinker_debugfs_count_show()

PATCH Applied Shakeel Butt 9 participants 14 messages Jun 10 – Aug 25

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 mm/shrinker: do not hold RCU lock in shrinker_debugfs_count_show()

Reading the debugfs "count" file of a memcg-aware shrinker can sleep inside an RCU read-side critical section:

  BUG: sleeping function called from invalid context at kernel/cgroup/rstat.c:421
  RCU nest depth: 1, expected: 0
   css_rstat_flush
   mem_cgroup_flush_stats
   zswap_shrinker_count
   shrinker_debugfs_count_show

shrinker_debugfs_count_show() invokes the ->count_objects() callback under rcu_read_lock(). The zswap callback flushes memcg stats via css_rstat_flush(), which may sleep, so it must not run under RCU.

The RCU lock is not needed here. mem_cgroup_iter() takes RCU internally and returns a memcg holding a css reference (dropped on the next iteration or by mem_cgroup_iter_break()), so the memcg stays alive without it. The shrinker is kept alive by the open debugfs file:
shrinker_free() removes the debugfs entries via debugfs_remove_recursive(), which waits for in-flight readers to drain, before call_rcu(..., shrinker_free_rcu_cb). The sibling "scan" handler already invokes the sleeping ->scan_objects() callback with no RCU section.

Drop the rcu_read_lock()/rcu_read_unlock().

Fixes 5035ebc644ae ("mm: shrinkers: introduce debugfs interface for memory shrinkers")
---
 mm/shrinker_debug.c | 4 ----
 1 file changed, 4 deletions(-)
mm/shrinker_debug.c +0 -4
index affa64437302..cda4e86428c8 100644
@@ -57,8 +57,6 @@ static int shrinker_debugfs_count_show(struct seq_file *m, void *v)
 	if (!count_per_node)
 		return -ENOMEM;
 
-	rcu_read_lock();
-
 	memcg_aware = shrinker->flags & SHRINKER_MEMCG_AWARE;
 
 	memcg = mem_cgroup_iter(NULL, NULL, NULL);
@@ -88,8 +86,6 @@ static int shrinker_debugfs_count_show(struct seq_file *m, void *v)
 		}
 	} while ((memcg = mem_cgroup_iter(NULL, memcg, NULL)) != NULL);
 
-	rcu_read_unlock();
-
 	kfree(count_per_node);
 	return ret;
 }
Signature · 1 line
2.53.0-Meta
Reviewed-by on v1 1/1
#1 lore raw
Quoted 24 lines · On Wed, 10 Jun 2026 16:20:48 -0700 Shakeel Butt <[email protected]> wrote:

Reading the debugfs "count" file of a memcg-aware shrinker can sleep inside an RCU read-side critical section:

  BUG: sleeping function called from invalid context at kernel/cgroup/rstat.c:421
  RCU nest depth: 1, expected: 0
   css_rstat_flush
   mem_cgroup_flush_stats
   zswap_shrinker_count
   shrinker_debugfs_count_show

shrinker_debugfs_count_show() invokes the ->count_objects() callback under rcu_read_lock(). The zswap callback flushes memcg stats via css_rstat_flush(), which may sleep, so it must not run under RCU.

The RCU lock is not needed here. mem_cgroup_iter() takes RCU internally and returns a memcg holding a css reference (dropped on the next iteration or by mem_cgroup_iter_break()), so the memcg stays alive without it. The shrinker is kept alive by the open debugfs file:
shrinker_free() removes the debugfs entries via debugfs_remove_recursive(), which waits for in-flight readers to drain, before call_rcu(..., shrinker_free_rcu_cb). The sibling "scan" handler already invokes the sleeping ->scan_objects() callback with no RCU section.

Quoted 1 line

Drop the rcu_read_lock()/rcu_read_unlock().

All make sense to me, thank you for the nice description and the fix!

Quoted 6 lines
Fixes 5035ebc644ae ("mm: shrinkers: introduce debugfs interface for memory shrinkers")

Thanks,
SJ

[...]

#2 lore raw
Quoted 26 lines · On Wed, 10 Jun 2026 17:22:51 -0700 SeongJae Park <[email protected]> wrote:
Quoted 24 lines · On Wed, 10 Jun 2026 16:20:48 -0700 Shakeel Butt <[email protected]> wrote:

Reading the debugfs "count" file of a memcg-aware shrinker can sleep inside an RCU read-side critical section:

  BUG: sleeping function called from invalid context at kernel/cgroup/rstat.c:421
  RCU nest depth: 1, expected: 0
   css_rstat_flush
   mem_cgroup_flush_stats
   zswap_shrinker_count
   shrinker_debugfs_count_show

shrinker_debugfs_count_show() invokes the ->count_objects() callback under rcu_read_lock(). The zswap callback flushes memcg stats via css_rstat_flush(), which may sleep, so it must not run under RCU.

The RCU lock is not needed here. mem_cgroup_iter() takes RCU internally and returns a memcg holding a css reference (dropped on the next iteration or by mem_cgroup_iter_break()), so the memcg stays alive without it. The shrinker is kept alive by the open debugfs file:
shrinker_free() removes the debugfs entries via debugfs_remove_recursive(), which waits for in-flight readers to drain, before call_rcu(..., shrinker_free_rcu_cb). The sibling "scan" handler already invokes the sleeping ->scan_objects() callback with no RCU section.

Quoted 6 lines
Quoted 1 line

Drop the rcu_read_lock()/rcu_read_unlock().

All make sense to me, thank you for the nice description and the fix!

Quoted 2 lines
Fixes 5035ebc644ae ("mm: shrinkers: introduce debugfs interface for memory shrinkers")

Forgot asking this, sorry. Are you intentionally not adding Cc: stable@ here? I think the user impact is arguably minor enough to not Cc-ing stable@, but just thought it would be good to make the intention clear.

Quoted 6 lines
Quoted 4 lines

Thanks,
SJ

[...]

#3 lore raw
Quoted 30 lines · SeongJae Park
Quoted 28 lines · On Wed, 10 Jun 2026 17:22:51 -0700 SeongJae Park <[email protected]> wrote:
Quoted 25 lines · On Wed, 10 Jun 2026 16:20:48 -0700 Shakeel Butt <[email protected]> wrote:

Reading the debugfs "count" file of a memcg-aware shrinker can sleep inside an RCU read-side critical section:

  BUG: sleeping function called from invalid context at kernel/cgroup/rstat.c:421
  RCU nest depth: 1, expected: 0
   css_rstat_flush
   mem_cgroup_flush_stats
   zswap_shrinker_count
   shrinker_debugfs_count_show

shrinker_debugfs_count_show() invokes the ->count_objects() callback under rcu_read_lock(). The zswap callback flushes memcg stats via css_rstat_flush(), which may sleep, so it must not run under RCU.

The RCU lock is not needed here. mem_cgroup_iter() takes RCU internally and returns a memcg holding a css reference (dropped on the next iteration or by mem_cgroup_iter_break()), so the memcg stays alive without it. The shrinker is kept alive by the open debugfs file:
shrinker_free() removes the debugfs entries via debugfs_remove_recursive(), which waits for in-flight readers to drain, before call_rcu(..., shrinker_free_rcu_cb). The sibling "scan" handler already invokes the sleeping ->scan_objects() callback with no RCU section.

Drop the rcu_read_lock()/rcu_read_unlock().

Quoted 9 lines
Quoted 4 lines

All make sense to me, thank you for the nice description and the fix!

Quoted 2 lines
Fixes 5035ebc644ae ("mm: shrinkers: introduce debugfs interface for memory shrinkers")

Forgot asking this, sorry. Are you intentionally not adding Cc: stable@ here? I think the user impact is arguably minor enough to not Cc-ing stable@, but just thought it would be good to make the intention clear.

Haha I was just being lazy to think through if this should be CCed to stable or not and letting others/reviewers do that for me :P

Quoted 6 lines
Quoted 6 lines
Quoted 4 lines

Thanks.

reviewer Reviewed-by on v1 1/1
#4 lore raw
In reply to Shakeel Butt
Quoted 26 lines · Shakeel Butt

Reading the debugfs "count" file of a memcg-aware shrinker can sleep inside an RCU read-side critical section:

   BUG: sleeping function called from invalid context at kernel/cgroup/rstat.c:421
   RCU nest depth: 1, expected: 0
    css_rstat_flush
    mem_cgroup_flush_stats
    zswap_shrinker_count
    shrinker_debugfs_count_show

shrinker_debugfs_count_show() invokes the ->count_objects() callback under rcu_read_lock(). The zswap callback flushes memcg stats via css_rstat_flush(), which may sleep, so it must not run under RCU.

The RCU lock is not needed here. mem_cgroup_iter() takes RCU internally and returns a memcg holding a css reference (dropped on the next iteration or by mem_cgroup_iter_break()), so the memcg stays alive without it. The shrinker is kept alive by the open debugfs file:
shrinker_free() removes the debugfs entries via debugfs_remove_recursive(), which waits for in-flight readers to drain, before call_rcu(..., shrinker_free_rcu_cb). The sibling "scan" handler already invokes the sleeping ->scan_objects() callback with no RCU section.

Drop the rcu_read_lock()/rcu_read_unlock().

Quoted 9 lines
Fixes 5035ebc644ae ("mm: shrinkers: introduce debugfs interface for memory shrinkers")
---
  mm/shrinker_debug.c | 4 ----
  1 file changed, 4 deletions(-)

LGTM, so:

Thanks!

Tested-by on v1 1/1
#5 lore raw
In reply to Shakeel Butt
Quoted 49 lines · Shakeel Butt

Reading the debugfs "count" file of a memcg-aware shrinker can sleep inside an RCU read-side critical section:

  BUG: sleeping function called from invalid context at kernel/cgroup/rstat.c:421
  RCU nest depth: 1, expected: 0
   css_rstat_flush
   mem_cgroup_flush_stats
   zswap_shrinker_count
   shrinker_debugfs_count_show

shrinker_debugfs_count_show() invokes the ->count_objects() callback under rcu_read_lock(). The zswap callback flushes memcg stats via css_rstat_flush(), which may sleep, so it must not run under RCU.

The RCU lock is not needed here. mem_cgroup_iter() takes RCU internally and returns a memcg holding a css reference (dropped on the next iteration or by mem_cgroup_iter_break()), so the memcg stays alive without it. The shrinker is kept alive by the open debugfs file:
shrinker_free() removes the debugfs entries via debugfs_remove_recursive(), which waits for in-flight readers to drain, before call_rcu(..., shrinker_free_rcu_cb). The sibling "scan" handler already invokes the sleeping ->scan_objects() callback with no RCU section.

Drop the rcu_read_lock()/rcu_read_unlock().

Fixes 5035ebc644ae ("mm: shrinkers: introduce debugfs interface for memory shrinkers")
---
 mm/shrinker_debug.c | 4 ----
 1 file changed, 4 deletions(-)
mm/shrinker_debug.c +0 -2
index affa64437302..cda4e86428c8 100644
@@ -57,8 +57,6 @@ static int shrinker_debugfs_count_show(struct seq_file *m, void *v)
 	if (!count_per_node)
 		return -ENOMEM;
 
-	rcu_read_lock();
-
 	memcg_aware = shrinker->flags & SHRINKER_MEMCG_AWARE;
 
 	memcg = mem_cgroup_iter(NULL, NULL, NULL);

mm/shrinker_debug.c static int shrinker_debugfs_count_show(struct seq_file *m, void *v) · line 91

Quoted 8 lines
mm/shrinker_debug.c +0 -2
@@ -88,8 +86,6 @@ static int shrinker_debugfs_count_show(struct seq_file *m, void *v)
 		}
 	} while ((memcg = mem_cgroup_iter(NULL, memcg, NULL)) != NULL);
 
-	rcu_read_unlock();
-
 	kfree(count_per_node);
 	return ret;
 }

Thanks for the fix!

Zenghui

Reviewed-by on v1 1/1
#6 lore raw
In reply to Shakeel Butt
Quoted 25 lines · Shakeel Butt

Reading the debugfs "count" file of a memcg-aware shrinker can sleep inside an RCU read-side critical section:

  BUG: sleeping function called from invalid context at kernel/cgroup/rstat.c:421
  RCU nest depth: 1, expected: 0
   css_rstat_flush
   mem_cgroup_flush_stats
   zswap_shrinker_count
   shrinker_debugfs_count_show

shrinker_debugfs_count_show() invokes the ->count_objects() callback under rcu_read_lock(). The zswap callback flushes memcg stats via css_rstat_flush(), which may sleep, so it must not run under RCU.

The RCU lock is not needed here. mem_cgroup_iter() takes RCU internally and returns a memcg holding a css reference (dropped on the next iteration or by mem_cgroup_iter_break()), so the memcg stays alive without it. The shrinker is kept alive by the open debugfs file:
shrinker_free() removes the debugfs entries via debugfs_remove_recursive(), which waits for in-flight readers to drain, before call_rcu(..., shrinker_free_rcu_cb). The sibling "scan" handler already invokes the sleeping ->scan_objects() callback with no RCU section.

Quoted 7 lines

Drop the rcu_read_lock()/rcu_read_unlock().

Fixes 5035ebc644ae ("mm: shrinkers: introduce debugfs interface for memory shrinkers")

Too fast :)

reviewer Acked-by on v1 1/1
#7 lore raw
In reply to Shakeel Butt
Quoted 28 lines · Shakeel Butt

Reading the debugfs "count" file of a memcg-aware shrinker can sleep inside an RCU read-side critical section:

 BUG: sleeping function called from invalid context at kernel/cgroup/rstat.c:421
 RCU nest depth: 1, expected: 0
  css_rstat_flush
  mem_cgroup_flush_stats
  zswap_shrinker_count
  shrinker_debugfs_count_show

shrinker_debugfs_count_show() invokes the ->count_objects() callback under rcu_read_lock(). The zswap callback flushes memcg stats via css_rstat_flush(), which may sleep, so it must not run under RCU.

The RCU lock is not needed here. mem_cgroup_iter() takes RCU internally and returns a memcg holding a css reference (dropped on the next iteration or by mem_cgroup_iter_break()), so the memcg stays alive without it. The shrinker is kept alive by the open debugfs file:
shrinker_free() removes the debugfs entries via debugfs_remove_recursive(), which waits for in-flight readers to drain, before call_rcu(..., shrinker_free_rcu_cb). The sibling "scan" handler already invokes the sleeping ->scan_objects() callback with no RCU section.

Quoted 7 lines

Drop the rcu_read_lock()/rcu_read_unlock().

Fixes 5035ebc644ae ("mm: shrinkers: introduce debugfs interface for memory shrinkers")

Thanks.

reviewer Reviewed-by on v1 1/1
#8 lore raw
In reply to Shakeel Butt
Quoted 24 lines · Shakeel Butt

Reading the debugfs "count" file of a memcg-aware shrinker can sleep inside an RCU read-side critical section:

  BUG: sleeping function called from invalid context at kernel/cgroup/rstat.c:421
  RCU nest depth: 1, expected: 0
   css_rstat_flush
   mem_cgroup_flush_stats
   zswap_shrinker_count
   shrinker_debugfs_count_show

shrinker_debugfs_count_show() invokes the ->count_objects() callback under rcu_read_lock(). The zswap callback flushes memcg stats via css_rstat_flush(), which may sleep, so it must not run under RCU.

The RCU lock is not needed here. mem_cgroup_iter() takes RCU internally and returns a memcg holding a css reference (dropped on the next iteration or by mem_cgroup_iter_break()), so the memcg stays alive without it. The shrinker is kept alive by the open debugfs file:
shrinker_free() removes the debugfs entries via debugfs_remove_recursive(), which waits for in-flight readers to drain, before call_rcu(..., shrinker_free_rcu_cb). The sibling "scan" handler already invokes the sleeping ->scan_objects() callback with no RCU section.

Quoted 7 lines

Drop the rcu_read_lock()/rcu_read_unlock().

Fixes 5035ebc644ae ("mm: shrinkers: introduce debugfs interface for memory shrinkers")
Reviewed-by on v1 1/1
#9 lore raw
In reply to Shakeel Butt
Quoted 60 lines · Shakeel Butt

Reading the debugfs "count" file of a memcg-aware shrinker can sleep inside an RCU read-side critical section:

  BUG: sleeping function called from invalid context at kernel/cgroup/rstat.c:421
  RCU nest depth: 1, expected: 0
   css_rstat_flush
   mem_cgroup_flush_stats
   zswap_shrinker_count
   shrinker_debugfs_count_show

shrinker_debugfs_count_show() invokes the ->count_objects() callback under rcu_read_lock(). The zswap callback flushes memcg stats via css_rstat_flush(), which may sleep, so it must not run under RCU.

The RCU lock is not needed here. mem_cgroup_iter() takes RCU internally and returns a memcg holding a css reference (dropped on the next iteration or by mem_cgroup_iter_break()), so the memcg stays alive without it. The shrinker is kept alive by the open debugfs file:
shrinker_free() removes the debugfs entries via debugfs_remove_recursive(), which waits for in-flight readers to drain, before call_rcu(..., shrinker_free_rcu_cb). The sibling "scan" handler already invokes the sleeping ->scan_objects() callback with no RCU section.

Drop the rcu_read_lock()/rcu_read_unlock().

Fixes 5035ebc644ae ("mm: shrinkers: introduce debugfs interface for memory shrinkers")
---
 mm/shrinker_debug.c | 4 ----
 1 file changed, 4 deletions(-)
mm/shrinker_debug.c +0 -4
index affa64437302..cda4e86428c8 100644
@@ -57,8 +57,6 @@ static int shrinker_debugfs_count_show(struct seq_file *m, void *v)
 	if (!count_per_node)
 		return -ENOMEM;
 
-	rcu_read_lock();
-
 	memcg_aware = shrinker->flags & SHRINKER_MEMCG_AWARE;
 
 	memcg = mem_cgroup_iter(NULL, NULL, NULL);
@@ -88,8 +86,6 @@ static int shrinker_debugfs_count_show(struct seq_file *m, void *v)
 		}
 	} while ((memcg = mem_cgroup_iter(NULL, memcg, NULL)) != NULL);
 
-	rcu_read_unlock();
-
 	kfree(count_per_node);
 	return ret;
 }
Signature · 1 line
2.53.0-Meta
#10 lore raw
Quoted 53 lines · Nick Huang
Quoted 52 lines · Shakeel Butt

Reading the debugfs "count" file of a memcg-aware shrinker can sleep inside an RCU read-side critical section:

  BUG: sleeping function called from invalid context at kernel/cgroup/rstat.c:421
  RCU nest depth: 1, expected: 0
   css_rstat_flush
   mem_cgroup_flush_stats
   zswap_shrinker_count
   shrinker_debugfs_count_show

shrinker_debugfs_count_show() invokes the ->count_objects() callback under rcu_read_lock(). The zswap callback flushes memcg stats via css_rstat_flush(), which may sleep, so it must not run under RCU.

The RCU lock is not needed here. mem_cgroup_iter() takes RCU internally and returns a memcg holding a css reference (dropped on the next iteration or by mem_cgroup_iter_break()), so the memcg stays alive without it. The shrinker is kept alive by the open debugfs file:
shrinker_free() removes the debugfs entries via debugfs_remove_recursive(), which waits for in-flight readers to drain, before call_rcu(..., shrinker_free_rcu_cb). The sibling "scan" handler already invokes the sleeping ->scan_objects() callback with no RCU section.

Drop the rcu_read_lock()/rcu_read_unlock().

Fixes 5035ebc644ae ("mm: shrinkers: introduce debugfs interface for memory shrinkers")
---
 mm/shrinker_debug.c | 4 ----
 1 file changed, 4 deletions(-)
mm/shrinker_debug.c +0 -2
index affa64437302..cda4e86428c8 100644
@@ -57,8 +57,6 @@ static int shrinker_debugfs_count_show(struct seq_file *m, void *v)
 	if (!count_per_node)
 		return -ENOMEM;
 
-	rcu_read_lock();
-
 	memcg_aware = shrinker->flags & SHRINKER_MEMCG_AWARE;
 
 	memcg = mem_cgroup_iter(NULL, NULL, NULL);
@@ -88,8 +86,6 @@ static int shrinker_debugfs_count_show(struct seq_file *m, void *v)
 		}
 	} while ((memcg = mem_cgroup_iter(NULL, memcg, NULL)) != NULL);
 
Quoted 9 lines
Quoted 8 lines
mm/shrinker_debug.c +0 -2
-	rcu_read_unlock();
-
 	kfree(count_per_node);
 	return ret;
 }
Signature · 1 line
2.53.0-Meta

Sorry, but what exactly did you review here? In the past you were sending AI slop:
https://lore.kernel.org/all/aeNGbNyPxJssnkbO@lucifer/

Not even properly following the process.
https://lore.kernel.org/all/[email protected]/

https://lore.kernel.org/all/?q=f%3Asef1548%40gmail.com

Why suddenly reviewing MM patches?

Best regards,
Krzysztof

#11 lore raw
Quoted 71 lines · Krzysztof Kozlowski
Quoted 53 lines · Nick Huang
Quoted 52 lines · Shakeel Butt

Reading the debugfs "count" file of a memcg-aware shrinker can sleep inside an RCU read-side critical section:

  BUG: sleeping function called from invalid context at kernel/cgroup/rstat.c:421
  RCU nest depth: 1, expected: 0
   css_rstat_flush
   mem_cgroup_flush_stats
   zswap_shrinker_count
   shrinker_debugfs_count_show

shrinker_debugfs_count_show() invokes the ->count_objects() callback under rcu_read_lock(). The zswap callback flushes memcg stats via css_rstat_flush(), which may sleep, so it must not run under RCU.

The RCU lock is not needed here. mem_cgroup_iter() takes RCU internally and returns a memcg holding a css reference (dropped on the next iteration or by mem_cgroup_iter_break()), so the memcg stays alive without it. The shrinker is kept alive by the open debugfs file:
shrinker_free() removes the debugfs entries via debugfs_remove_recursive(), which waits for in-flight readers to drain, before call_rcu(..., shrinker_free_rcu_cb). The sibling "scan" handler already invokes the sleeping ->scan_objects() callback with no RCU section.

Drop the rcu_read_lock()/rcu_read_unlock().

Fixes 5035ebc644ae ("mm: shrinkers: introduce debugfs interface for memory shrinkers")
---
 mm/shrinker_debug.c | 4 ----
 1 file changed, 4 deletions(-)
mm/shrinker_debug.c +0 -2
index affa64437302..cda4e86428c8 100644
@@ -57,8 +57,6 @@ static int shrinker_debugfs_count_show(struct seq_file *m, void *v)
 	if (!count_per_node)
 		return -ENOMEM;
 
-	rcu_read_lock();
-
 	memcg_aware = shrinker->flags & SHRINKER_MEMCG_AWARE;
 
 	memcg = mem_cgroup_iter(NULL, NULL, NULL);
@@ -88,8 +86,6 @@ static int shrinker_debugfs_count_show(struct seq_file *m, void *v)
 		}
 	} while ((memcg = mem_cgroup_iter(NULL, memcg, NULL)) != NULL);
 
Quoted 9 lines
Quoted 8 lines
mm/shrinker_debug.c +0 -2
-	rcu_read_unlock();
-
 	kfree(count_per_node);
 	return ret;
 }
Signature · 1 line
2.53.0-Meta

Sorry, but what exactly did you review here? In the past you were sending AI slop:
https://lore.kernel.org/all/aeNGbNyPxJssnkbO@lucifer/

Not even properly following the process.
https://lore.kernel.org/all/[email protected]/

Quoted 6 lines

https://lore.kernel.org/all/?q=f%3Asef1548%40gmail.com

Why suddenly reviewing MM patches?

Best regards,
Krzysztof

Hi Krzysztof

I saw this patch on the mailing list and was interested in the RCU issue, so I looked at the related code. I checked that removing the outer RCU read-side critical section doesn't break the memcg lifetime, since mem_cgroup_iter() returns the memcg with a CSS reference held.
I should have explained what I checked instead of just adding a Reviewed-by.
Thanks for pointing that out.

Regards,
Nick Huang

#12 lore raw
Quoted 79 lines · Nick Huang
Quoted 71 lines · Krzysztof Kozlowski
Quoted 53 lines · Nick Huang
Quoted 52 lines · Shakeel Butt

Reading the debugfs "count" file of a memcg-aware shrinker can sleep inside an RCU read-side critical section:

  BUG: sleeping function called from invalid context at kernel/cgroup/rstat.c:421
  RCU nest depth: 1, expected: 0
   css_rstat_flush
   mem_cgroup_flush_stats
   zswap_shrinker_count
   shrinker_debugfs_count_show

shrinker_debugfs_count_show() invokes the ->count_objects() callback under rcu_read_lock(). The zswap callback flushes memcg stats via css_rstat_flush(), which may sleep, so it must not run under RCU.

The RCU lock is not needed here. mem_cgroup_iter() takes RCU internally and returns a memcg holding a css reference (dropped on the next iteration or by mem_cgroup_iter_break()), so the memcg stays alive without it. The shrinker is kept alive by the open debugfs file:
shrinker_free() removes the debugfs entries via debugfs_remove_recursive(), which waits for in-flight readers to drain, before call_rcu(..., shrinker_free_rcu_cb). The sibling "scan" handler already invokes the sleeping ->scan_objects() callback with no RCU section.

Drop the rcu_read_lock()/rcu_read_unlock().

Fixes 5035ebc644ae ("mm: shrinkers: introduce debugfs interface for memory shrinkers")
---
 mm/shrinker_debug.c | 4 ----
 1 file changed, 4 deletions(-)
mm/shrinker_debug.c +0 -2
index affa64437302..cda4e86428c8 100644
@@ -57,8 +57,6 @@ static int shrinker_debugfs_count_show(struct seq_file *m, void *v)
 	if (!count_per_node)
 		return -ENOMEM;
 
-	rcu_read_lock();
-
 	memcg_aware = shrinker->flags & SHRINKER_MEMCG_AWARE;
 
 	memcg = mem_cgroup_iter(NULL, NULL, NULL);
@@ -88,8 +86,6 @@ static int shrinker_debugfs_count_show(struct seq_file *m, void *v)
 		}
 	} while ((memcg = mem_cgroup_iter(NULL, memcg, NULL)) != NULL);
 
Quoted 9 lines
Quoted 8 lines
mm/shrinker_debug.c +0 -2
-	rcu_read_unlock();
-
 	kfree(count_per_node);
 	return ret;
 }
Signature · 1 line
2.53.0-Meta

Sorry, but what exactly did you review here? In the past you were sending AI slop:
https://lore.kernel.org/all/aeNGbNyPxJssnkbO@lucifer/

Not even properly following the process.
https://lore.kernel.org/all/[email protected]/

Quoted 6 lines

https://lore.kernel.org/all/?q=f%3Asef1548%40gmail.com

Why suddenly reviewing MM patches?

Best regards,
Krzysztof

Quoted 7 lines

Hi Krzysztof

I saw this patch on the mailing list and was interested in the RCU issue, so I looked at the related code. I checked that removing the outer RCU read-side critical section doesn't break the memcg lifetime, since mem_cgroup_iter() returns the memcg with a CSS reference held.
I should have explained what I checked instead of just adding a Reviewed-by.
Thanks for pointing that out.

After all the maintainers already provided a review...

Best regards,
Krzysztof

#13 lore raw

Krzysztof Kozlowski <[email protected]> 於 2026年8月25日週二 下午9:56寫道:

Quoted 89 lines · Nick Huang
Quoted 79 lines · Krzysztof Kozlowski
Quoted 71 lines · Nick Huang
Quoted 53 lines · Shakeel Butt
Quoted 52 lines

Reading the debugfs "count" file of a memcg-aware shrinker can sleep inside an RCU read-side critical section:

  BUG: sleeping function called from invalid context at kernel/cgroup/rstat.c:421
  RCU nest depth: 1, expected: 0
   css_rstat_flush
   mem_cgroup_flush_stats
   zswap_shrinker_count
   shrinker_debugfs_count_show

shrinker_debugfs_count_show() invokes the ->count_objects() callback under rcu_read_lock(). The zswap callback flushes memcg stats via css_rstat_flush(), which may sleep, so it must not run under RCU.

The RCU lock is not needed here. mem_cgroup_iter() takes RCU internally and returns a memcg holding a css reference (dropped on the next iteration or by mem_cgroup_iter_break()), so the memcg stays alive without it. The shrinker is kept alive by the open debugfs file:
shrinker_free() removes the debugfs entries via debugfs_remove_recursive(), which waits for in-flight readers to drain, before call_rcu(..., shrinker_free_rcu_cb). The sibling "scan" handler already invokes the sleeping ->scan_objects() callback with no RCU section.

Drop the rcu_read_lock()/rcu_read_unlock().

Fixes 5035ebc644ae ("mm: shrinkers: introduce debugfs interface for memory shrinkers")
---
 mm/shrinker_debug.c | 4 ----
 1 file changed, 4 deletions(-)
mm/shrinker_debug.c +0 -2
index affa64437302..cda4e86428c8 100644
@@ -57,8 +57,6 @@ static int shrinker_debugfs_count_show(struct seq_file *m, void *v)
   if (!count_per_node)
           return -ENOMEM;
 
-  rcu_read_lock();
-
   memcg_aware = shrinker->flags & SHRINKER_MEMCG_AWARE;
 
   memcg = mem_cgroup_iter(NULL, NULL, NULL);
@@ -88,8 +86,6 @@ static int shrinker_debugfs_count_show(struct seq_file *m, void *v)
           }
   } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL)) != NULL);
 
Quoted 9 lines
Quoted 8 lines
mm/shrinker_debug.c +0 -3
-  rcu_read_unlock();
-
   kfree(count_per_node);
   return ret;
 }
--

2.53.0-Meta

Sorry, but what exactly did you review here? In the past you were sending AI slop:
https://lore.kernel.org/all/aeNGbNyPxJssnkbO@lucifer/

Not even properly following the process.
https://lore.kernel.org/all/[email protected]/

Quoted 6 lines

https://lore.kernel.org/all/?q=f%3Asef1548%40gmail.com

Why suddenly reviewing MM patches?

Best regards,
Krzysztof

Quoted 7 lines

Hi Krzysztof

I saw this patch on the mailing list and was interested in the RCU issue, so I looked at the related code. I checked that removing the outer RCU read-side critical section doesn't break the memcg lifetime, since mem_cgroup_iter() returns the memcg with a CSS reference held.
I should have explained what I checked instead of just adding a Reviewed-by.
Thanks for pointing that out.

Quoted 4 lines

After all the maintainers already provided a review...

Best regards,
Krzysztof

Hi Krzysztof
Sorry, I misread it and didn't realize that the maintainers had already reviewed it.
Thanks for pointing that out, and thanks for taking the time to respond.

Signature · 2 lines
Regards,
Nick Huang