From 3661f06bec593627d54ff05650b60833f9dd71b2 Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Wed, 20 Dec 2017 17:04:25 -0800 Subject: [PATCH] scoutfs: add trigger to drop lock cache We have a corruption that can happen when a lock is reclaimed but it's cache is still dirty. Detect this corruption by placing a trigger in statfs which fires off lock reclaim. Statfs is nice because for scoutfs it's lockless, which means there should not be any references on locks when the trigger is fired. Signed-off-by: Mark Fasheh --- kmod/src/lock.c | 25 +++++++++++++++---------- kmod/src/lock.h | 2 ++ kmod/src/super.c | 8 ++++++++ kmod/src/triggers.c | 1 + kmod/src/triggers.h | 1 + 5 files changed, 27 insertions(+), 10 deletions(-) diff --git a/kmod/src/lock.c b/kmod/src/lock.c index b16b2264..32d7deb6 100644 --- a/kmod/src/lock.c +++ b/kmod/src/lock.c @@ -29,6 +29,7 @@ #include "trans.h" #include "counters.h" #include "endian_swap.h" +#include "triggers.h" #define LN_FMT "%u.%u.%u.%llu.%llu" #define LN_ARG(name) \ @@ -592,19 +593,12 @@ static void scoutfs_lock_reclaim(struct work_struct *work) put_scoutfs_lock(linfo->sb, lock); } -static int shrink_lock_tree(struct shrinker *shrink, struct shrink_control *sc) +void scoutfs_free_unused_locks(struct super_block *sb, unsigned long nr) { - struct lock_info *linfo = container_of(shrink, struct lock_info, - shrinker); + struct lock_info *linfo = SCOUTFS_SB(sb)->lock_info; struct scoutfs_lock *lock; struct scoutfs_lock *tmp; unsigned long flags; - unsigned long nr; - int ret; - - nr = sc->nr_to_scan; - if (!nr) - goto out; spin_lock_irqsave(&linfo->lock, flags); list_for_each_entry_safe(lock, tmp, &linfo->lru_list, lru_entry) { @@ -622,8 +616,19 @@ static int shrink_lock_tree(struct shrinker *shrink, struct shrink_control *sc) queue_work(linfo->lock_reclaim_wq, &lock->reclaim_work); } spin_unlock_irqrestore(&linfo->lock, flags); +} + +static int shrink_lock_tree(struct shrinker *shrink, struct shrink_control *sc) +{ + struct lock_info *linfo = container_of(shrink, struct lock_info, + shrinker); + unsigned long nr; + int ret; + + nr = sc->nr_to_scan; + if (nr) + scoutfs_free_unused_locks(linfo->sb, nr); -out: ret = min_t(unsigned long, linfo->lru_nr, INT_MAX); trace_scoutfs_lock_shrink_exit(linfo->sb, sc->nr_to_scan, ret); return ret; diff --git a/kmod/src/lock.h b/kmod/src/lock.h index 63a914fe..6d0339e8 100644 --- a/kmod/src/lock.h +++ b/kmod/src/lock.h @@ -60,6 +60,8 @@ void scoutfs_unlock(struct super_block *sb, struct scoutfs_lock *lock, void scoutfs_unlock_flags(struct super_block *sb, struct scoutfs_lock *lock, int level, int flags); +void scoutfs_free_unused_locks(struct super_block *sb, unsigned long nr); + int scoutfs_lock_setup(struct super_block *sb); void scoutfs_lock_destroy(struct super_block *sb); diff --git a/kmod/src/super.c b/kmod/src/super.c index 9772a8a4..d39c3dbd 100644 --- a/kmod/src/super.c +++ b/kmod/src/super.c @@ -88,6 +88,14 @@ static int scoutfs_statfs(struct dentry *dentry, struct kstatfs *kst) kst->f_frsize = SCOUTFS_BLOCK_SIZE; /* the vfs fills f_flags */ + /* + * We don't take cluster locks in statfs which makes it a very + * convenient place to trigger lock reclaim for debugging. We + * try to free as many locks as possible. + */ + if (scoutfs_trigger(sb, STATFS_LOCK_PURGE)) + scoutfs_free_unused_locks(sb, -1UL); + return 0; } diff --git a/kmod/src/triggers.c b/kmod/src/triggers.c index 200d29e7..67cef0e6 100644 --- a/kmod/src/triggers.c +++ b/kmod/src/triggers.c @@ -41,6 +41,7 @@ static char *names[] = { [SCOUTFS_TRIGGER_BTREE_STALE_READ] = "btree_stale_read", [SCOUTFS_TRIGGER_HARD_STALE_ERROR] = "hard_stale_error", [SCOUTFS_TRIGGER_SEG_STALE_READ] = "seg_stale_read", + [SCOUTFS_TRIGGER_STATFS_LOCK_PURGE] = "statfs_lock_purge", }; bool scoutfs_trigger_test_and_clear(struct super_block *sb, unsigned int t) diff --git a/kmod/src/triggers.h b/kmod/src/triggers.h index 1b802c5e..900e433f 100644 --- a/kmod/src/triggers.h +++ b/kmod/src/triggers.h @@ -5,6 +5,7 @@ enum { SCOUTFS_TRIGGER_BTREE_STALE_READ, SCOUTFS_TRIGGER_HARD_STALE_ERROR, SCOUTFS_TRIGGER_SEG_STALE_READ, + SCOUTFS_TRIGGER_STATFS_LOCK_PURGE, SCOUTFS_TRIGGER_NR, };