public inbox for stable@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] ext4: Fix deadlock on inode reallocation
@ 2026-03-20  9:04 Jan Kara
  2026-03-25 21:07 ` Mateusz Guzik
  0 siblings, 1 reply; 2+ messages in thread
From: Jan Kara @ 2026-03-20  9:04 UTC (permalink / raw)
  To: Ted Tso; +Cc: linux-ext4, yi1.lai, Mateusz Guzik, Jan Kara, stable

Currently there is a race in ext4 when reallocating freed inode
resulting in a deadlock:

Task1					Task2
ext4_evict_inode()
  handle = ext4_journal_start();
  ...
  if (IS_SYNC(inode))
    handle->h_sync = 1;
  ext4_free_inode()
					ext4_new_inode()
					  handle = ext4_journal_start()
					  finds the bit in inode bitmap
					    already clear
					  insert_inode_locked()
					    waits for inode to be
					      removed from the hash.
  ext4_journal_stop(handle)
    jbd2_journal_stop(handle)
      jbd2_log_wait_commit(journal, tid);
        - deadlocks waiting for transaction handle Task2 holds

Fix the problem by removing inode from the hash already in
ext4_clear_inode() by which time all IO for the inode is done so reuse
is already fine but we are still before possibly blocking on transaction
commit.

Reported-by: "Lai, Yi" <yi1.lai@linux.intel.com>
Link: https://lore.kernel.org/all/abNvb2PcrKj1FBeC@ly-workstation
Fixes: 88ec797c4680 ("fs: make insert_inode_locked() wait for inode destruction")
CC: stable@vger.kernel.org
Signed-off-by: Jan Kara <jack@suse.cz>
---
 fs/ext4/super.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

Ted, this is a regression recently introduced by VFS changes in
insert_inode_locked() but I think it's best fixed in ext4. If you agree, it
would be nice to merge this so that it makes it to 7.0 release. Thanks!

diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 43f680c750ae..b8122d24c083 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1527,6 +1527,27 @@ void ext4_clear_inode(struct inode *inode)
 	invalidate_inode_buffers(inode);
 	clear_inode(inode);
 	ext4_discard_preallocations(inode);
+	/*
+	 * We must remove the inode from the hash before ext4_free_inode()
+	 * clears the bit in inode bitmap as otherwise another process reusing
+	 * the inode will block in insert_inode_hash() waiting for inode
+	 * eviction to complete while holding transaction handle open, but
+	 * ext4_evict_inode() still running for that inode could block waiting
+	 * for transaction commit if the inode is marked as IS_SYNC => deadlock.
+	 *
+	 * Removing the inode from the hash here is safe. There are two cases
+	 * to consider:
+	 * 1) The inode still has references to it (i_nlink > 0). In that case
+	 * we are keeping the inode and once we remove the inode from the hash,
+	 * iget() can create the new inode structure for the same inode number
+	 * and we are fine with that as all IO on behalf of the inode is
+	 * finished.
+	 * 2) We are deleting the inode (i_nlink == 0). In that case inode
+	 * number cannot be reused until ext4_free_inode() clears the bit in
+	 * the inode bitmap, at which point all IO is done and reuse is fine
+	 * again.
+	 */
+	remove_inode_hash(inode);
 	ext4_es_remove_extent(inode, 0, EXT_MAX_BLOCKS);
 	dquot_drop(inode);
 	if (EXT4_I(inode)->jinode) {
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] ext4: Fix deadlock on inode reallocation
  2026-03-20  9:04 [PATCH] ext4: Fix deadlock on inode reallocation Jan Kara
@ 2026-03-25 21:07 ` Mateusz Guzik
  0 siblings, 0 replies; 2+ messages in thread
From: Mateusz Guzik @ 2026-03-25 21:07 UTC (permalink / raw)
  To: Jan Kara; +Cc: Ted Tso, linux-ext4, yi1.lai, stable

can this get any traction?

master as-is contains a change which uncovered the ext4 problem.
either the deadlock needs to be fixed in time for the release or the
other change needs to get temporarily reverted.

interested parties can find proposed revert here:
https://lore.kernel.org/linux-fsdevel/20260316103306.1258289-1-mjguzik@gmail.com/

On Fri, Mar 20, 2026 at 10:04 AM Jan Kara <jack@suse.cz> wrote:
>
> Currently there is a race in ext4 when reallocating freed inode
> resulting in a deadlock:
>
> Task1                                   Task2
> ext4_evict_inode()
>   handle = ext4_journal_start();
>   ...
>   if (IS_SYNC(inode))
>     handle->h_sync = 1;
>   ext4_free_inode()
>                                         ext4_new_inode()
>                                           handle = ext4_journal_start()
>                                           finds the bit in inode bitmap
>                                             already clear
>                                           insert_inode_locked()
>                                             waits for inode to be
>                                               removed from the hash.
>   ext4_journal_stop(handle)
>     jbd2_journal_stop(handle)
>       jbd2_log_wait_commit(journal, tid);
>         - deadlocks waiting for transaction handle Task2 holds
>
> Fix the problem by removing inode from the hash already in
> ext4_clear_inode() by which time all IO for the inode is done so reuse
> is already fine but we are still before possibly blocking on transaction
> commit.
>
> Reported-by: "Lai, Yi" <yi1.lai@linux.intel.com>
> Link: https://lore.kernel.org/all/abNvb2PcrKj1FBeC@ly-workstation
> Fixes: 88ec797c4680 ("fs: make insert_inode_locked() wait for inode destruction")
> CC: stable@vger.kernel.org
> Signed-off-by: Jan Kara <jack@suse.cz>
> ---
>  fs/ext4/super.c | 21 +++++++++++++++++++++
>  1 file changed, 21 insertions(+)
>
> Ted, this is a regression recently introduced by VFS changes in
> insert_inode_locked() but I think it's best fixed in ext4. If you agree, it
> would be nice to merge this so that it makes it to 7.0 release. Thanks!
>
> diff --git a/fs/ext4/super.c b/fs/ext4/super.c
> index 43f680c750ae..b8122d24c083 100644
> --- a/fs/ext4/super.c
> +++ b/fs/ext4/super.c
> @@ -1527,6 +1527,27 @@ void ext4_clear_inode(struct inode *inode)
>         invalidate_inode_buffers(inode);
>         clear_inode(inode);
>         ext4_discard_preallocations(inode);
> +       /*
> +        * We must remove the inode from the hash before ext4_free_inode()
> +        * clears the bit in inode bitmap as otherwise another process reusing
> +        * the inode will block in insert_inode_hash() waiting for inode
> +        * eviction to complete while holding transaction handle open, but
> +        * ext4_evict_inode() still running for that inode could block waiting
> +        * for transaction commit if the inode is marked as IS_SYNC => deadlock.
> +        *
> +        * Removing the inode from the hash here is safe. There are two cases
> +        * to consider:
> +        * 1) The inode still has references to it (i_nlink > 0). In that case
> +        * we are keeping the inode and once we remove the inode from the hash,
> +        * iget() can create the new inode structure for the same inode number
> +        * and we are fine with that as all IO on behalf of the inode is
> +        * finished.
> +        * 2) We are deleting the inode (i_nlink == 0). In that case inode
> +        * number cannot be reused until ext4_free_inode() clears the bit in
> +        * the inode bitmap, at which point all IO is done and reuse is fine
> +        * again.
> +        */
> +       remove_inode_hash(inode);
>         ext4_es_remove_extent(inode, 0, EXT_MAX_BLOCKS);
>         dquot_drop(inode);
>         if (EXT4_I(inode)->jinode) {
> --
> 2.51.0
>

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-03-25 21:07 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-20  9:04 [PATCH] ext4: Fix deadlock on inode reallocation Jan Kara
2026-03-25 21:07 ` Mateusz Guzik

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox