Skip to content

Commit 47a7c01

Browse files
Qi Zhengakpm00
authored andcommitted
Revert "mm: shrinkers: convert shrinker_rwsem to mutex"
Patch series "revert shrinker_srcu related changes". This patch (of 7): This reverts commit cf2e309. Kernel test robot reports -88.8% regression in stress-ng.ramfs.ops_per_sec test case [1], which is caused by commit f95bdb7 ("mm: vmscan: make global slab shrink lockless"). The root cause is that SRCU has to be careful to not frequently check for SRCU read-side critical section exits. Therefore, even if no one is currently in the SRCU read-side critical section, synchronize_srcu() cannot return quickly. That's why unregister_shrinker() has become slower. After discussion, we will try to use the refcount+RCU method [2] proposed by Dave Chinner to continue to re-implement the lockless slab shrink. So revert the shrinker_mutex back to shrinker_rwsem first. [1]. https://lore.kernel.org/lkml/[email protected]/ [2]. https://lore.kernel.org/lkml/[email protected]/ Link: https://lkml.kernel.org/r/[email protected] Link: https://lkml.kernel.org/r/[email protected] Reported-by: kernel test robot <[email protected]> Closes: https://lore.kernel.org/oe-lkp/[email protected] Signed-off-by: Qi Zheng <[email protected]> Cc: Dave Chinner <[email protected]> Cc: Kirill Tkhai <[email protected]> Cc: Muchun Song <[email protected]> Cc: Roman Gushchin <[email protected]> Cc: Vlastimil Babka <[email protected]> Cc: Yujie Liu <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 679bd7e commit 47a7c01

File tree

5 files changed

+27
-27
lines changed

5 files changed

+27
-27
lines changed

drivers/md/dm-cache-metadata.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1828,7 +1828,7 @@ int dm_cache_metadata_abort(struct dm_cache_metadata *cmd)
18281828
* Replacement block manager (new_bm) is created and old_bm destroyed outside of
18291829
* cmd root_lock to avoid ABBA deadlock that would result (due to life-cycle of
18301830
* shrinker associated with the block manager's bufio client vs cmd root_lock).
1831-
* - must take shrinker_mutex without holding cmd->root_lock
1831+
* - must take shrinker_rwsem without holding cmd->root_lock
18321832
*/
18331833
new_bm = dm_block_manager_create(cmd->bdev, DM_CACHE_METADATA_BLOCK_SIZE << SECTOR_SHIFT,
18341834
CACHE_MAX_CONCURRENT_LOCKS);

drivers/md/dm-thin-metadata.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1887,7 +1887,7 @@ int dm_pool_abort_metadata(struct dm_pool_metadata *pmd)
18871887
* Replacement block manager (new_bm) is created and old_bm destroyed outside of
18881888
* pmd root_lock to avoid ABBA deadlock that would result (due to life-cycle of
18891889
* shrinker associated with the block manager's bufio client vs pmd root_lock).
1890-
* - must take shrinker_mutex without holding pmd->root_lock
1890+
* - must take shrinker_rwsem without holding pmd->root_lock
18911891
*/
18921892
new_bm = dm_block_manager_create(pmd->bdev, THIN_METADATA_BLOCK_SIZE << SECTOR_SHIFT,
18931893
THIN_MAX_CONCURRENT_LOCKS);

fs/super.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ static char *sb_writers_name[SB_FREEZE_LEVELS] = {
5454
* One thing we have to be careful of with a per-sb shrinker is that we don't
5555
* drop the last active reference to the superblock from within the shrinker.
5656
* If that happens we could trigger unregistering the shrinker from within the
57-
* shrinker path and that leads to deadlock on the shrinker_mutex. Hence we
57+
* shrinker path and that leads to deadlock on the shrinker_rwsem. Hence we
5858
* take a passive reference to the superblock to avoid this from occurring.
5959
*/
6060
static unsigned long super_cache_scan(struct shrinker *shrink,

mm/shrinker_debug.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
#include <linux/srcu.h>
99

1010
/* defined in vmscan.c */
11-
extern struct mutex shrinker_mutex;
11+
extern struct rw_semaphore shrinker_rwsem;
1212
extern struct list_head shrinker_list;
1313
extern struct srcu_struct shrinker_srcu;
1414

@@ -168,7 +168,7 @@ int shrinker_debugfs_add(struct shrinker *shrinker)
168168
char buf[128];
169169
int id;
170170

171-
lockdep_assert_held(&shrinker_mutex);
171+
lockdep_assert_held(&shrinker_rwsem);
172172

173173
/* debugfs isn't initialized yet, add debugfs entries later. */
174174
if (!shrinker_debugfs_root)
@@ -211,7 +211,7 @@ int shrinker_debugfs_rename(struct shrinker *shrinker, const char *fmt, ...)
211211
if (!new)
212212
return -ENOMEM;
213213

214-
mutex_lock(&shrinker_mutex);
214+
down_write(&shrinker_rwsem);
215215

216216
old = shrinker->name;
217217
shrinker->name = new;
@@ -229,7 +229,7 @@ int shrinker_debugfs_rename(struct shrinker *shrinker, const char *fmt, ...)
229229
shrinker->debugfs_entry = entry;
230230
}
231231

232-
mutex_unlock(&shrinker_mutex);
232+
up_write(&shrinker_rwsem);
233233

234234
kfree_const(old);
235235

@@ -242,7 +242,7 @@ struct dentry *shrinker_debugfs_detach(struct shrinker *shrinker,
242242
{
243243
struct dentry *entry = shrinker->debugfs_entry;
244244

245-
lockdep_assert_held(&shrinker_mutex);
245+
lockdep_assert_held(&shrinker_rwsem);
246246

247247
kfree_const(shrinker->name);
248248
shrinker->name = NULL;
@@ -271,14 +271,14 @@ static int __init shrinker_debugfs_init(void)
271271
shrinker_debugfs_root = dentry;
272272

273273
/* Create debugfs entries for shrinkers registered at boot */
274-
mutex_lock(&shrinker_mutex);
274+
down_write(&shrinker_rwsem);
275275
list_for_each_entry(shrinker, &shrinker_list, list)
276276
if (!shrinker->debugfs_entry) {
277277
ret = shrinker_debugfs_add(shrinker);
278278
if (ret)
279279
break;
280280
}
281-
mutex_unlock(&shrinker_mutex);
281+
up_write(&shrinker_rwsem);
282282

283283
return ret;
284284
}

mm/vmscan.c

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
#include <linux/cpuset.h>
3636
#include <linux/compaction.h>
3737
#include <linux/notifier.h>
38-
#include <linux/mutex.h>
38+
#include <linux/rwsem.h>
3939
#include <linux/delay.h>
4040
#include <linux/kthread.h>
4141
#include <linux/freezer.h>
@@ -190,7 +190,7 @@ struct scan_control {
190190
int vm_swappiness = 60;
191191

192192
LIST_HEAD(shrinker_list);
193-
DEFINE_MUTEX(shrinker_mutex);
193+
DECLARE_RWSEM(shrinker_rwsem);
194194
DEFINE_SRCU(shrinker_srcu);
195195
static atomic_t shrinker_srcu_generation = ATOMIC_INIT(0);
196196

@@ -213,7 +213,7 @@ static struct shrinker_info *shrinker_info_protected(struct mem_cgroup *memcg,
213213
{
214214
return srcu_dereference_check(memcg->nodeinfo[nid]->shrinker_info,
215215
&shrinker_srcu,
216-
lockdep_is_held(&shrinker_mutex));
216+
lockdep_is_held(&shrinker_rwsem));
217217
}
218218

219219
static struct shrinker_info *shrinker_info_srcu(struct mem_cgroup *memcg,
@@ -292,7 +292,7 @@ int alloc_shrinker_info(struct mem_cgroup *memcg)
292292
int nid, size, ret = 0;
293293
int map_size, defer_size = 0;
294294

295-
mutex_lock(&shrinker_mutex);
295+
down_write(&shrinker_rwsem);
296296
map_size = shrinker_map_size(shrinker_nr_max);
297297
defer_size = shrinker_defer_size(shrinker_nr_max);
298298
size = map_size + defer_size;
@@ -308,7 +308,7 @@ int alloc_shrinker_info(struct mem_cgroup *memcg)
308308
info->map_nr_max = shrinker_nr_max;
309309
rcu_assign_pointer(memcg->nodeinfo[nid]->shrinker_info, info);
310310
}
311-
mutex_unlock(&shrinker_mutex);
311+
up_write(&shrinker_rwsem);
312312

313313
return ret;
314314
}
@@ -324,7 +324,7 @@ static int expand_shrinker_info(int new_id)
324324
if (!root_mem_cgroup)
325325
goto out;
326326

327-
lockdep_assert_held(&shrinker_mutex);
327+
lockdep_assert_held(&shrinker_rwsem);
328328

329329
map_size = shrinker_map_size(new_nr_max);
330330
defer_size = shrinker_defer_size(new_nr_max);
@@ -374,7 +374,7 @@ static int prealloc_memcg_shrinker(struct shrinker *shrinker)
374374
if (mem_cgroup_disabled())
375375
return -ENOSYS;
376376

377-
mutex_lock(&shrinker_mutex);
377+
down_write(&shrinker_rwsem);
378378
id = idr_alloc(&shrinker_idr, shrinker, 0, 0, GFP_KERNEL);
379379
if (id < 0)
380380
goto unlock;
@@ -388,7 +388,7 @@ static int prealloc_memcg_shrinker(struct shrinker *shrinker)
388388
shrinker->id = id;
389389
ret = 0;
390390
unlock:
391-
mutex_unlock(&shrinker_mutex);
391+
up_write(&shrinker_rwsem);
392392
return ret;
393393
}
394394

@@ -398,7 +398,7 @@ static void unregister_memcg_shrinker(struct shrinker *shrinker)
398398

399399
BUG_ON(id < 0);
400400

401-
lockdep_assert_held(&shrinker_mutex);
401+
lockdep_assert_held(&shrinker_rwsem);
402402

403403
idr_remove(&shrinker_idr, id);
404404
}
@@ -433,7 +433,7 @@ void reparent_shrinker_deferred(struct mem_cgroup *memcg)
433433
parent = root_mem_cgroup;
434434

435435
/* Prevent from concurrent shrinker_info expand */
436-
mutex_lock(&shrinker_mutex);
436+
down_write(&shrinker_rwsem);
437437
for_each_node(nid) {
438438
child_info = shrinker_info_protected(memcg, nid);
439439
parent_info = shrinker_info_protected(parent, nid);
@@ -442,7 +442,7 @@ void reparent_shrinker_deferred(struct mem_cgroup *memcg)
442442
atomic_long_add(nr, &parent_info->nr_deferred[i]);
443443
}
444444
}
445-
mutex_unlock(&shrinker_mutex);
445+
up_write(&shrinker_rwsem);
446446
}
447447

448448
static bool cgroup_reclaim(struct scan_control *sc)
@@ -743,9 +743,9 @@ void free_prealloced_shrinker(struct shrinker *shrinker)
743743
shrinker->name = NULL;
744744
#endif
745745
if (shrinker->flags & SHRINKER_MEMCG_AWARE) {
746-
mutex_lock(&shrinker_mutex);
746+
down_write(&shrinker_rwsem);
747747
unregister_memcg_shrinker(shrinker);
748-
mutex_unlock(&shrinker_mutex);
748+
up_write(&shrinker_rwsem);
749749
return;
750750
}
751751

@@ -755,11 +755,11 @@ void free_prealloced_shrinker(struct shrinker *shrinker)
755755

756756
void register_shrinker_prepared(struct shrinker *shrinker)
757757
{
758-
mutex_lock(&shrinker_mutex);
758+
down_write(&shrinker_rwsem);
759759
list_add_tail_rcu(&shrinker->list, &shrinker_list);
760760
shrinker->flags |= SHRINKER_REGISTERED;
761761
shrinker_debugfs_add(shrinker);
762-
mutex_unlock(&shrinker_mutex);
762+
up_write(&shrinker_rwsem);
763763
}
764764

765765
static int __register_shrinker(struct shrinker *shrinker)
@@ -810,13 +810,13 @@ void unregister_shrinker(struct shrinker *shrinker)
810810
if (!(shrinker->flags & SHRINKER_REGISTERED))
811811
return;
812812

813-
mutex_lock(&shrinker_mutex);
813+
down_write(&shrinker_rwsem);
814814
list_del_rcu(&shrinker->list);
815815
shrinker->flags &= ~SHRINKER_REGISTERED;
816816
if (shrinker->flags & SHRINKER_MEMCG_AWARE)
817817
unregister_memcg_shrinker(shrinker);
818818
debugfs_entry = shrinker_debugfs_detach(shrinker, &debugfs_id);
819-
mutex_unlock(&shrinker_mutex);
819+
up_write(&shrinker_rwsem);
820820

821821
atomic_inc(&shrinker_srcu_generation);
822822
synchronize_srcu(&shrinker_srcu);

0 commit comments

Comments
 (0)