From: Theodore Ts'o Date: Mon, 15 Jul 2013 04:09:56 +0000 (-0400) Subject: ext4: block direct I/O writes during ext4_truncate X-Git-Tag: next-20130717~62^2~2 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=839ffb2667d0ccb593efd74b42219fcc1d2b18f6;p=karo-tx-linux.git ext4: block direct I/O writes during ext4_truncate Just as in ext4_punch_hole() it is important that we block DIO writes while the truncate is proceeding, since during the overwriting DIO write, we drop i_mutex, which means a truncate could start while the Direct I/O operation is still in progress. Signed-off-by: "Theodore Ts'o" Cc: stable@vger.kernel.org --- diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 98b9bff92a8a..3c5edf29e2ae 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -3659,12 +3659,16 @@ void ext4_truncate(struct inode *inode) if (inode->i_size == 0 && !test_opt(inode->i_sb, NO_AUTO_DA_ALLOC)) ext4_set_inode_state(inode, EXT4_STATE_DA_ALLOC_CLOSE); + /* Wait all existing dio workers, newcomers will block on i_mutex */ + ext4_inode_block_unlocked_dio(inode); + inode_dio_wait(inode); + if (ext4_has_inline_data(inode)) { int has_inline = 1; ext4_inline_data_truncate(inode, &has_inline); if (has_inline) - return; + goto out_resume; } if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) @@ -3675,7 +3679,7 @@ void ext4_truncate(struct inode *inode) handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, credits); if (IS_ERR(handle)) { ext4_std_error(inode->i_sb, PTR_ERR(handle)); - return; + goto out_resume; } if (inode->i_size & (inode->i_sb->s_blocksize - 1)) @@ -3722,6 +3726,8 @@ out_stop: ext4_mark_inode_dirty(handle, inode); ext4_journal_stop(handle); +out_resume: + ext4_inode_resume_unlocked_dio(inode); trace_ext4_truncate_exit(inode); }