]> git.baikalelectronics.ru Git - 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)
commit39a7984d4b397a3a9610cb160aedc0e3f841c700
treea1e35e05fd3c0e97f59cf72c697d56d8cd9f0931
parent505427b89f85600956b0b4161f77fa03c0f91c49
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: b1dc15f7b506 ("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