Re: [PATCH 1/1] fs: fix deadlock in insert_inode_locked() waiting for inode eviction

From: Mateusz Guzik

Date: Thu Mar 26 2026 - 19:33:56 EST


On Fri, Mar 27, 2026 at 12:21 AM Xiang Shen <turyshen@xxxxxxxxx> wrote:
>
> 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.
>

Please see the ext4 fix:
https://lore.kernel.org/linux-ext4/20260320090428.24899-2-jack@xxxxxxx/