diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2015-07-24 15:27:53 +1000 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2015-07-24 15:28:41 +1000 |
commit | 82bbe0f45b1187115ee17a300717785907241d3e (patch) | |
tree | fd32abf2c27a0fa790d666ffcfa2cae71dcc1054 | |
parent | 5bd776b2454fc227e740d0b3dd3241c8a9621737 (diff) |
Revert "mm: srcu-ify shrinkers"
This reverts commit dab937da82f9504fbac75592a1825614318d73e7.
-rw-r--r-- | fs/super.c | 8 | ||||
-rw-r--r-- | mm/vmscan.c | 39 |
2 files changed, 25 insertions, 22 deletions
diff --git a/fs/super.c b/fs/super.c index c917817c8d40..b61372354f2b 100644 --- a/fs/super.c +++ b/fs/super.c @@ -49,8 +49,8 @@ static char *sb_writers_name[SB_FREEZE_LEVELS] = { * One thing we have to be careful of with a per-sb shrinker is that we don't * drop the last active reference to the superblock from within the shrinker. * If that happens we could trigger unregistering the shrinker from within the - * shrinker path. Hence we take a passive reference to the superblock to avoid - * this from occurring. + * shrinker path and that leads to deadlock on the shrinker_rwsem. Hence we + * take a passive reference to the superblock to avoid this from occurring. */ static unsigned long super_cache_scan(struct shrinker *shrink, struct shrink_control *sc) @@ -121,8 +121,8 @@ static unsigned long super_cache_count(struct shrinker *shrink, * Don't call trylock_super as it is a potential * scalability bottleneck. The counts could get updated * between super_cache_count and super_cache_scan anyway. - * SRCU guarantees object validity across this call -- thus - * it is safe to call list_lru_shrink_count() and + * Call to super_cache_count with shrinker_rwsem held + * ensures the safety of call to list_lru_shrink_count() and * s_op->nr_cached_objects(). */ if (sb->s_op && sb->s_op->nr_cached_objects) diff --git a/mm/vmscan.c b/mm/vmscan.c index 4a860f0e37d7..6dffe70442a6 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -36,7 +36,7 @@ #include <linux/cpuset.h> #include <linux/compaction.h> #include <linux/notifier.h> -#include <linux/srcu.h> +#include <linux/rwsem.h> #include <linux/delay.h> #include <linux/kthread.h> #include <linux/freezer.h> @@ -146,9 +146,8 @@ int vm_swappiness = 60; */ unsigned long vm_total_pages; -DEFINE_STATIC_SRCU(shrinker_srcu); static LIST_HEAD(shrinker_list); -static DEFINE_SPINLOCK(shrinker_list_lock); +static DECLARE_RWSEM(shrinker_rwsem); #ifdef CONFIG_MEMCG static bool global_reclaim(struct scan_control *sc) @@ -243,9 +242,9 @@ int register_shrinker(struct shrinker *shrinker) if (!shrinker->nr_deferred) return -ENOMEM; - spin_lock(&shrinker_list_lock); - list_add_tail_rcu(&shrinker->list, &shrinker_list); - spin_unlock(&shrinker_list_lock); + down_write(&shrinker_rwsem); + list_add_tail(&shrinker->list, &shrinker_list); + up_write(&shrinker_rwsem); return 0; } EXPORT_SYMBOL(register_shrinker); @@ -255,14 +254,9 @@ EXPORT_SYMBOL(register_shrinker); */ void unregister_shrinker(struct shrinker *shrinker) { - spin_lock(&shrinker_list_lock); - list_del_rcu(&shrinker->list); - spin_unlock(&shrinker_list_lock); - /* - * Before freeing nr_deferred, ensure all srcu - * readers are done with their critical region. - */ - synchronize_srcu(&shrinker_srcu); + down_write(&shrinker_rwsem); + list_del(&shrinker->list); + up_write(&shrinker_rwsem); kfree(shrinker->nr_deferred); } EXPORT_SYMBOL(unregister_shrinker); @@ -414,7 +408,6 @@ static unsigned long shrink_slab(gfp_t gfp_mask, int nid, unsigned long nr_scanned, unsigned long nr_eligible) { - int idx; struct shrinker *shrinker; unsigned long freed = 0; @@ -424,9 +417,18 @@ static unsigned long shrink_slab(gfp_t gfp_mask, int nid, if (nr_scanned == 0) nr_scanned = SWAP_CLUSTER_MAX; - idx = srcu_read_lock(&shrinker_srcu); + if (!down_read_trylock(&shrinker_rwsem)) { + /* + * If we would return 0, our callers would understand that we + * have nothing else to shrink and give up trying. By returning + * 1 we keep it going and assume we'll be able to shrink next + * time. + */ + freed = 1; + goto out; + } - list_for_each_entry_rcu(shrinker, &shrinker_list, list) { + list_for_each_entry(shrinker, &shrinker_list, list) { struct shrink_control sc = { .gfp_mask = gfp_mask, .nid = nid, @@ -442,7 +444,8 @@ static unsigned long shrink_slab(gfp_t gfp_mask, int nid, freed += do_shrink_slab(&sc, shrinker, nr_scanned, nr_eligible); } - srcu_read_unlock(&shrinker_srcu, idx); + up_read(&shrinker_rwsem); +out: cond_resched(); return freed; } |