Move iput(tmp_inode) after ext4_writepages_up_write() to avoid a circular lock dependency between s_writepages_rwsem and sb_internal (freeze protection). The deadlock scenario: CPU0 (EXT4_IOC_MIGRATE) CPU1 (orphan cleanup during mount) ---- ---- ext4_ext_migrate() ext4_writepages_down_write() s_writepages_rwsem (write) ext4_evict_inode() sb_start_intwrite() [sb_internal] ... ext4_writepages() s_writepages_rwsem (read) [BLOCKED] iput(tmp_inode) ext4_evict_inode() sb_start_intwrite() [BLOCKED] The tmp_inode is a temporary inode with nlink=0 created solely for building the extent tree. Its eviction does not require s_writepages_rwsem protection, so deferring iput() until after releasing the rwsem is safe. Reported-by: syzbot+f0b58a1f5075a90dd9a5@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=f0b58a1f5075a90dd9a5 Fixes: cb85f4d23f79 ("ext4: fix race between writepages and enabling EXT4_EXTENTS_FL") Signed-off-by: Yun Zhou --- fs/ext4/migrate.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c index 477d43d7e294..25368eb44e85 100644 --- a/fs/ext4/migrate.c +++ b/fs/ext4/migrate.c @@ -464,6 +464,7 @@ int ext4_ext_migrate(struct inode *inode) if (IS_ERR(tmp_inode)) { retval = PTR_ERR(tmp_inode); ext4_journal_stop(handle); + tmp_inode = NULL; goto out_unlock; } /* @@ -591,9 +592,10 @@ int ext4_ext_migrate(struct inode *inode) ext4_journal_stop(handle); out_tmp_inode: unlock_new_inode(tmp_inode); - iput(tmp_inode); out_unlock: ext4_writepages_up_write(inode->i_sb, alloc_ctx); + if (tmp_inode) + iput(tmp_inode); return retval; } -- 2.43.0