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

Konstantin Khorenko khorenko at virtuozzo.com
Mon Feb 19 21:13:16 MSK 2024


The commit is pushed to "branch-rh9-5.14.0-362.8.1.vz9.35.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh9-5.14.0-362.8.1.vz9.35.14
------>
commit 9d5cbd19fa5eeab1fa4857163edf1a5b2cab807d
Author: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
Date:   Tue Feb 6 13:08:18 2024 +0800

    mm/vmscan: add rcu_read_lock to replace released shrinker_rwsem
    
    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>
    
    Feature: fix mm/nfs
---
 mm/vmscan.c | 31 +++++++++++++++++++++++++++----
 1 file changed, 27 insertions(+), 4 deletions(-)

diff --git a/mm/vmscan.c b/mm/vmscan.c
index 847fc2354c3d..1f2eacbad84d 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)


More information about the Devel mailing list