]> Git Repo - linux.git/commit - fs/ext4/inode.c
ext4: fix deadlock with fs freezing and EA inodes
authorJan Kara <[email protected]>
Fri, 27 Nov 2020 11:06:49 +0000 (12:06 +0100)
committerTheodore Ts'o <[email protected]>
Thu, 17 Dec 2020 18:30:45 +0000 (13:30 -0500)
commit46e294efc355c48d1dd4d58501aa56dac461792a
treea1e35e05fd3c0e97f59cf72c697d56d8cd9f0931
parent9bd23c31f392bda88618008f27fd52ee9e0fac38
ext4: fix deadlock with fs freezing and EA inodes

Xattr code using inodes with large xattr data can end up dropping last
inode reference (and thus deleting the inode) from places like
ext4_xattr_set_entry(). That function is called with transaction started
and so ext4_evict_inode() can deadlock against fs freezing like:

CPU1 CPU2

removexattr() freeze_super()
  vfs_removexattr()
    ext4_xattr_set()
      handle = ext4_journal_start()
      ...
      ext4_xattr_set_entry()
        iput(old_ea_inode)
          ext4_evict_inode(old_ea_inode)
  sb->s_writers.frozen = SB_FREEZE_FS;
  sb_wait_write(sb, SB_FREEZE_FS);
  ext4_freeze()
    jbd2_journal_lock_updates()
      -> blocks waiting for all
         handles to stop
            sb_start_intwrite()
      -> blocks as sb is already in SB_FREEZE_FS state

Generally it is advisable to delete inodes from a separate transaction
as it can consume quite some credits however in this case it would be
quite clumsy and furthermore the credits for inode deletion are quite
limited and already accounted for. So just tweak ext4_evict_inode() to
avoid freeze protection if we have transaction already started and thus
it is not really needed anyway.

Cc: [email protected]
Fixes: dec214d00e0d ("ext4: xattr inode deduplication")
Signed-off-by: Jan Kara <[email protected]>
Reviewed-by: Andreas Dilger <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Theodore Ts'o <[email protected]>
fs/ext4/inode.c
This page took 0.05036 seconds and 4 git commands to generate.