[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