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 <zab@versity.com>
This commit is contained in:
Zach Brown
2019-09-09 15:13:33 -07:00
committed by Zach Brown
parent 8c631b019b
commit 15becd6ef8

View File

@@ -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);