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, };