From: Greg Kroah-Hartman Date: Thu, 19 Oct 2017 11:33:46 +0000 (+0200) Subject: 3.18-stable patches X-Git-Tag: v3.18.77~12 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f2502a13edd0594138d446135908eed1acaf1032;p=thirdparty%2Fkernel%2Fstable-queue.git 3.18-stable patches added patches: ext4-avoid-deadlock-when-expanding-inode-size.patch --- diff --git a/queue-3.18/ext4-avoid-deadlock-when-expanding-inode-size.patch b/queue-3.18/ext4-avoid-deadlock-when-expanding-inode-size.patch new file mode 100644 index 00000000000..816a435cf61 --- /dev/null +++ b/queue-3.18/ext4-avoid-deadlock-when-expanding-inode-size.patch @@ -0,0 +1,88 @@ +From 109f9ac01393e2c1e1a18683396191a8e0c2e8ce Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Thu, 11 Aug 2016 12:38:55 -0400 +Subject: [PATCH] ext4: avoid deadlock when expanding inode size + +From: Jan Kara + +[ Upstream commit 2e81a4eeedcaa66e35f58b81e0755b87057ce392 ] + +When we need to move xattrs into external xattr block, we call +ext4_xattr_block_set() from ext4_expand_extra_isize_ea(). That may end +up calling ext4_mark_inode_dirty() again which will recurse back into +the inode expansion code leading to deadlocks. + +Protect from recursion using EXT4_STATE_NO_EXPAND inode flag and move +its management into ext4_expand_extra_isize_ea() since its manipulation +is safe there (due to xattr_sem) from possible races with +ext4_xattr_set_handle() which plays with it as well. + +Signed-off-by: Jan Kara +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/inode.c | 2 -- + fs/ext4/xattr.c | 19 +++++++++++++------ + 2 files changed, 13 insertions(+), 8 deletions(-) + +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -4895,8 +4895,6 @@ int ext4_mark_inode_dirty(handle_t *hand + sbi->s_want_extra_isize, + iloc, handle); + if (ret) { +- ext4_set_inode_state(inode, +- EXT4_STATE_NO_EXPAND); + if (mnt_count != + le16_to_cpu(sbi->s_es->s_mnt_count)) { + ext4_warning(inode->i_sb, +--- a/fs/ext4/xattr.c ++++ b/fs/ext4/xattr.c +@@ -1291,11 +1291,13 @@ int ext4_expand_extra_isize_ea(struct in + int s_min_extra_isize = le16_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_min_extra_isize); + + down_write(&EXT4_I(inode)->xattr_sem); ++ /* ++ * Set EXT4_STATE_NO_EXPAND to avoid recursion when marking inode dirty ++ */ ++ ext4_set_inode_state(inode, EXT4_STATE_NO_EXPAND); + retry: +- if (EXT4_I(inode)->i_extra_isize >= new_extra_isize) { +- up_write(&EXT4_I(inode)->xattr_sem); +- return 0; +- } ++ if (EXT4_I(inode)->i_extra_isize >= new_extra_isize) ++ goto out; + + header = IHDR(inode, raw_inode); + entry = IFIRST(header); +@@ -1324,8 +1326,7 @@ retry: + (void *)header, total_ino, + inode->i_sb->s_blocksize); + EXT4_I(inode)->i_extra_isize = new_extra_isize; +- error = 0; +- goto cleanup; ++ goto out; + } + + /* +@@ -1485,6 +1486,8 @@ retry: + kfree(bs); + } + brelse(bh); ++out: ++ ext4_clear_inode_state(inode, EXT4_STATE_NO_EXPAND); + up_write(&EXT4_I(inode)->xattr_sem); + return 0; + +@@ -1496,6 +1499,10 @@ cleanup: + kfree(is); + kfree(bs); + brelse(bh); ++ /* ++ * We deliberately leave EXT4_STATE_NO_EXPAND set here since inode ++ * size expansion failed. ++ */ + up_write(&EXT4_I(inode)->xattr_sem); + return error; + } diff --git a/queue-3.18/series b/queue-3.18/series index 785376ee02c..b0ee32c3be4 100644 --- a/queue-3.18/series +++ b/queue-3.18/series @@ -1,2 +1,3 @@ x86-mm-disable-preemption-during-cr3-read-write.patch drm-dp-mst-save-vcpi-with-payloads.patch +ext4-avoid-deadlock-when-expanding-inode-size.patch