aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2015-07-24 15:27:53 +1000
committerStephen Rothwell <sfr@canb.auug.org.au>2015-07-24 15:28:41 +1000
commit82bbe0f45b1187115ee17a300717785907241d3e (patch)
treefd32abf2c27a0fa790d666ffcfa2cae71dcc1054
parent5bd776b2454fc227e740d0b3dd3241c8a9621737 (diff)
Revert "mm: srcu-ify shrinkers"
This reverts commit dab937da82f9504fbac75592a1825614318d73e7.
-rw-r--r--fs/super.c8
-rw-r--r--mm/vmscan.c39
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;
}