mirror of
https://github.com/versity/scoutfs.git
synced 2026-09-05 23:56:58 +00:00
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 <mfasheh@versity.com>
This commit is contained in:
+15
-10
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user