[Devel] [PATCH VZ9] mm/vmscan: add rcu_read_lock to replace released shrinker_rwsem

Pavel Tikhomirov ptikhomirov at virtuozzo.com
Tue Feb 6 08:08:18 MSK 2024


After commit [1] we release shrinker_rwsem for nfs while processing
do_shrink_slab, we need this to mitigate blocked shrinker_rwsem due to
a hang in nfs shrinker.

After that we lack shrinker_rwsem and rcu_read_lock in these stacks:

  +-< rcu_dereference_protected(ockdep_is_held(&shrinker_rwsem))
    +-< shrinker_info_protected
      +-< xchg_nr_deferred_memcg
        +-< xchg_nr_deferred
          +-< do_shrink_slab
      +-< add_nr_deferred_memcg
        +-< add_nr_deferred
          +-< do_shrink_slab

As these stacks only use info for read, we can switch to rcu_read_lock,
also need to switch rcu_dereference_protected -> rcu_dereference_check.

https://virtuozzo.atlassian.net/browse/PSBM-153973
Fixes: c0efc56a8f844 ("mm: fix hanging shrinker management on long do_shrink_slab") [1]
Signed-off-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
---
note: In vz7 we don't need it.
---
 mm/vmscan.c | 31 +++++++++++++++++++++++++++----
 1 file changed, 27 insertions(+), 4 deletions(-)

diff --git a/mm/vmscan.c b/mm/vmscan.c
index 847fc2354c3dc..1f2eacbad84d4 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -218,6 +218,13 @@ static struct shrinker_info *shrinker_info_protected(struct mem_cgroup *memcg,
 					 lockdep_is_held(&shrinker_rwsem));
 }
 
+static struct shrinker_info *shrinker_info_check(struct mem_cgroup *memcg,
+						 int nid)
+{
+	return rcu_dereference_check(memcg->nodeinfo[nid]->shrinker_info,
+				     lockdep_is_held(&shrinker_rwsem));
+}
+
 static int expand_one_shrinker_info(struct mem_cgroup *memcg,
 				    int map_size, int defer_size,
 				    int old_map_size, int old_defer_size)
@@ -411,18 +418,34 @@ static long xchg_nr_deferred_memcg(int nid, struct shrinker *shrinker,
 				   struct mem_cgroup *memcg)
 {
 	struct shrinker_info *info;
+	long ret;
 
-	info = shrinker_info_protected(memcg, nid);
-	return atomic_long_xchg(&info->nr_deferred[shrinker->id], 0);
+	/*
+	 * Need rcu lock here in case we've released shrinker_rwsem to prevent
+	 * hang on nfs before calling do_shrink_slab().
+	 */
+	rcu_read_lock();
+	info = shrinker_info_check(memcg, nid);
+	ret = atomic_long_xchg(&info->nr_deferred[shrinker->id], 0);
+	rcu_read_unlock();
+	return ret;
 }
 
 static long add_nr_deferred_memcg(long nr, int nid, struct shrinker *shrinker,
 				  struct mem_cgroup *memcg)
 {
 	struct shrinker_info *info;
+	long ret;
 
-	info = shrinker_info_protected(memcg, nid);
-	return atomic_long_add_return(nr, &info->nr_deferred[shrinker->id]);
+	/*
+	 * Need rcu lock here in case we've released shrinker_rwsem to prevent
+	 * hang on nfs before calling do_shrink_slab().
+	 */
+	rcu_read_lock();
+	info = shrinker_info_check(memcg, nid);
+	ret = atomic_long_add_return(nr, &info->nr_deferred[shrinker->id]);
+	rcu_read_unlock();
+	return ret;
 }
 
 void reparent_shrinker_deferred(struct mem_cgroup *memcg)
-- 
2.43.0



More information about the Devel mailing list