Skip to content

Commit 5bc9ad7

Browse files
mjguzikbrauner
authored andcommitted
vfs: handle __wait_on_freeing_inode() and evict() race
Lockless hash lookup can find and lock the inode after it gets the I_FREEING flag set, at which point it blocks waiting for teardown in evict() to finish. However, the flag is still set even after evict() wakes up all waiters. This results in a race where if the inode lock is taken late enough, it can happen after both hash removal and wakeups, meaning there is nobody to wake the racing thread up. This worked prior to RCU-based lookup because the entire ordeal was synchronized with the inode hash lock. Since unhashing requires the inode lock, we can safely check whether it happened after acquiring it. Link: https://lore.kernel.org/v9fs/[email protected]/ Reported-by: Dominique Martinet <[email protected]> Fixes: 7180f8d ("vfs: add rcu-based find_inode variants for iget ops") Signed-off-by: Mateusz Guzik <[email protected]> Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Jan Kara <[email protected]> Signed-off-by: Christian Brauner <[email protected]>
1 parent fcad933 commit 5bc9ad7

File tree

1 file changed

+20
-0
lines changed

1 file changed

+20
-0
lines changed

fs/inode.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,16 @@ static void evict(struct inode *inode)
676676

677677
remove_inode_hash(inode);
678678

679+
/*
680+
* Wake up waiters in __wait_on_freeing_inode().
681+
*
682+
* Lockless hash lookup may end up finding the inode before we removed
683+
* it above, but only lock it *after* we are done with the wakeup below.
684+
* In this case the potential waiter cannot safely block.
685+
*
686+
* The inode being unhashed after the call to remove_inode_hash() is
687+
* used as an indicator whether blocking on it is safe.
688+
*/
679689
spin_lock(&inode->i_lock);
680690
wake_up_bit(&inode->i_state, __I_NEW);
681691
BUG_ON(inode->i_state != (I_FREEING | I_CLEAR));
@@ -2291,6 +2301,16 @@ static void __wait_on_freeing_inode(struct inode *inode, bool locked)
22912301
{
22922302
wait_queue_head_t *wq;
22932303
DEFINE_WAIT_BIT(wait, &inode->i_state, __I_NEW);
2304+
2305+
/*
2306+
* Handle racing against evict(), see that routine for more details.
2307+
*/
2308+
if (unlikely(inode_unhashed(inode))) {
2309+
WARN_ON(locked);
2310+
spin_unlock(&inode->i_lock);
2311+
return;
2312+
}
2313+
22942314
wq = bit_waitqueue(&inode->i_state, __I_NEW);
22952315
prepare_to_wait(wq, &wait.wq_entry, TASK_UNINTERRUPTIBLE);
22962316
spin_unlock(&inode->i_lock);

0 commit comments

Comments
 (0)