From 15becd6ef8a17ee954fa86e3890bdfa9d69b974c Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Mon, 9 Sep 2019 15:13:33 -0700 Subject: [PATCH] scoutfs: force locks idle as shutdown frees Usually lock_free() is called as users finish using a lock and when its state shows that it is idle and won't be freed out from under another use. During shutdown we manually call lock_free() on all locks because shutdown promises that there will be no more lock users, including networking callbacks. But there is a case where network requests can be pending and we shutdown before waiting for their reply. This trips BUG_ON assertions in lock_free() that would otherwise catch unsafe calls of lock_free(). This is easiest to reproduce by interrupting a mount (which is waiting on a lock to read the root inode). The fix is to update each lock's state during shutdown to reflect the promise made by shutdown. Requests aren't actually pending because we've shutdown networking befrore getting here. Signed-off-by: Zach Brown --- kmod/src/lock.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/kmod/src/lock.c b/kmod/src/lock.c index 9536376a..290439dd 100644 --- a/kmod/src/lock.c +++ b/kmod/src/lock.c @@ -1492,14 +1492,19 @@ void scoutfs_lock_destroy(struct super_block *sb) debugfs_remove(linfo->tseq_dentry); /* - * This is very clumsy and brute force. This will be cleaned up - * as we add proper lock recovery. + * Usually lock_free is only called once locks are idle but all + * locks are idle by definition during shutdown. We need to + * manually update the lock's state to reflect that we've given + * up on pending work that would otherwise prevent free from + * being called (and would trip assertions in our manual calling + * of free). */ spin_lock(&linfo->lock); node = rb_first(&linfo->lock_tree); while (node) { lock = rb_entry(node, struct scoutfs_lock, node); node = rb_next(node); + lock->request_pending = 0; if (!list_empty(&lock->lru_head)) __lock_del_lru(linfo, lock); lock_remove(linfo, lock);