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" <tytso@xxxxxxx> Cc: stable@xxxxxxxxxxxxxxx --- fs/ext4/inode.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 98b9bff..3c5edf2 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); } -- 1.7.12.rc0.22.gcdd159b -- To unsubscribe from this list: send the line "unsubscribe stable" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html