Move get_bh outside of the spinlock critical region
[ext4-patch-queue.git] / block-dio-during-truncate
blob122c4d9064d38ac1d9bb07a6df3df19de660267a
1 ext4: block direct I/O writes during ext4_truncate
3 Just as in ext4_punch_hole() it is important that we block DIO writes
4 while the truncate is proceeding, since during the overwriting DIO
5 write, we drop i_mutex, which means a truncate could start while the
6 Direct I/O operation is still in progress.
8 Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
9 Cc: stable@vger.kernel.org
10 ---
11  fs/ext4/inode.c | 10 ++++++++--
12  1 file changed, 8 insertions(+), 2 deletions(-)
14 diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
15 index 98b9bff..3c5edf2 100644
16 --- a/fs/ext4/inode.c
17 +++ b/fs/ext4/inode.c
18 @@ -3659,12 +3659,16 @@ void ext4_truncate(struct inode *inode)
19         if (inode->i_size == 0 && !test_opt(inode->i_sb, NO_AUTO_DA_ALLOC))
20                 ext4_set_inode_state(inode, EXT4_STATE_DA_ALLOC_CLOSE);
22 +       /* Wait all existing dio workers, newcomers will block on i_mutex */
23 +       ext4_inode_block_unlocked_dio(inode);
24 +       inode_dio_wait(inode);
26         if (ext4_has_inline_data(inode)) {
27                 int has_inline = 1;
29                 ext4_inline_data_truncate(inode, &has_inline);
30                 if (has_inline)
31 -                       return;
32 +                       goto out_resume;
33         }
35         if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
36 @@ -3675,7 +3679,7 @@ void ext4_truncate(struct inode *inode)
37         handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, credits);
38         if (IS_ERR(handle)) {
39                 ext4_std_error(inode->i_sb, PTR_ERR(handle));
40 -               return;
41 +               goto out_resume;
42         }
44         if (inode->i_size & (inode->i_sb->s_blocksize - 1))
45 @@ -3722,6 +3726,8 @@ out_stop:
46         ext4_mark_inode_dirty(handle, inode);
47         ext4_journal_stop(handle);
49 +out_resume:
50 +       ext4_inode_resume_unlocked_dio(inode);
51         trace_ext4_truncate_exit(inode);
52  }