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 <ptikhomi...@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

_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to