Commit 88ec797c4680 ("fs: make insert_inode_locked() wait for inode destruction") changed insert_inode_locked() to sleep via __wait_on_freeing_inode() when it encounters an inode being freed. This introduces a deadlock when the caller already holds resources that the eviction path needs. For example, ext4_new_inode() holds an active jbd2 journal handle when it calls insert_inode_locked(). If a stale inode with the same ino is being freed, the function now sleeps waiting for eviction to complete. However, ext4_evict_inode() needs to start a new journal transaction via ext4_journal_start(), which may block in add_transaction_credits() waiting for the current transaction to commit. That transaction cannot commit because the caller's handle (in ext4_new_inode) is still active, resulting in a deadlock: Thread A (ext4_new_inode) Thread B (evicting old inode) ------------------------- ---------------------------- jbd2_journal_start() -> handle insert_inode_locked() finds old inode I_FREEING __wait_on_freeing_inode() schedule() [waits for B] ext4_evict_inode() ext4_journal_start() add_transaction_credits() [waits for T to commit] [T blocked by A's handle] Fix this by replacing the blocking __wait_on_freeing_inode() call with a non-blocking drop-and-retry loop. When a freeing inode is encountered, drop both i_lock and inode_hash_lock, yield the CPU with cond_resched(), and restart the outer while(1) loop via continue. Unlike the pre-88ec797c4680 code which skipped freeing inodes within the inner hlist_for_each_entry loop (risking duplicate inodes in the hash), this fix restarts the entire lookup from scratch -- the new inode is only inserted when no matching entry (including freeing ones) exists in the hash chain. Fixes: 88ec797c4680 ("fs: make insert_inode_locked() wait for inode destruction") Cc: stable@vger.kernel.org Signed-off-by: Xiang Shen --- fs/inode.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/inode.c b/fs/inode.c index cc12b68e021b..8ecdd297c83f 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1842,7 +1842,6 @@ int insert_inode_locked(struct inode *inode) while (1) { struct inode *old = NULL; spin_lock(&inode_hash_lock); -repeat: hlist_for_each_entry(old, head, i_hash) { if (old->i_ino != ino) continue; @@ -1860,9 +1859,10 @@ int insert_inode_locked(struct inode *inode) return 0; } if (inode_state_read(old) & (I_FREEING | I_WILL_FREE)) { - __wait_on_freeing_inode(old, true, false); - old = NULL; - goto repeat; + spin_unlock(&old->i_lock); + spin_unlock(&inode_hash_lock); + cond_resched(); + continue; } if (unlikely(inode_state_read(old) & I_CREATING)) { spin_unlock(&old->i_lock); -- 2.34.1