Re: [PATCH] mm/shrinker: do not hold RCU lock in shrinker_debugfs_count_show()

Nick Huang <[email protected]>
Newsgroups org.kvack.linux-mm,org.kernel.vger.linux-kernel
Message-ID <aoxKKXjs3o6jUanE@nickhuang>
On Wed, Jun 10, 2026 at 04:20:48PM -0700, Shakeel Butt 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().
> 
> Fixes: 5035ebc644ae ("mm: shrinkers: introduce debugfs interface for memory shrinkers")
> Reported-by: Zenghui Yu <[email protected]>
> Closes: https://lore.kernel.org/all/[email protected]/
> Suggested-by: Nhat Pham <[email protected]>
> Signed-off-by: Shakeel Butt <[email protected]>
> ---
>  mm/shrinker_debug.c | 4 ----
>  1 file changed, 4 deletions(-)
> 
> diff --git a/mm/shrinker_debug.c b/mm/shrinker_debug.c
> index affa64437302..cda4e86428c8 100644
> --- a/mm/shrinker_debug.c
> +++ b/mm/shrinker_debug.c
> @@ -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;
>  }
> -- 
> 2.53.0-Meta
>
Reviewed-by: Nick Huang <[email protected]>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.