]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commit
ext4: fix deadlock with fs freezing and EA inodes
authorJan Kara <jack@suse.cz>
Fri, 27 Nov 2020 11:06:49 +0000 (12:06 +0100)
committerTheodore Ts'o <tytso@mit.edu>
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: stable@vger.kernel.org
Fixes: dec214d00e0d ("ext4: xattr inode deduplication")
Signed-off-by: Jan Kara <jack@suse.cz>
Reviewed-by: Andreas Dilger <adilger@dilger.ca>
Link: https://lore.kernel.org/r/20201127110649.24730-1-jack@suse.cz
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
fs/ext4/inode.c