diff options
author | Jan Kara <jack@suse.com> | 2015-12-07 14:29:17 -0500 |
---|---|---|
committer | Sasha Levin <sasha.levin@oracle.com> | 2016-03-23 10:20:24 -0400 |
commit | 9621787d69783fc23d14e1332377d7170d6928ed (patch) | |
tree | 7c392086817f76689b59f59fa4d5100b68d9b768 | |
parent | 248766f068fd1d3d95479f470bc926d1136141d6 (diff) |
ext4: move unlocked dio protection from ext4_alloc_file_blocks()
Currently ext4_alloc_file_blocks() was handling protection against
unlocked DIO. However we now need to sometimes call it under i_mmap_sem
and sometimes not and DIO protection ranks above it (although strictly
speaking this cannot currently create any deadlocks). Also
ext4_zero_range() was actually getting & releasing unlocked DIO
protection twice in some cases. Luckily it didn't introduce any real bug
but it was a land mine waiting to be stepped on. So move DIO protection
out from ext4_alloc_file_blocks() into the two callsites.
Signed-off-by: Jan Kara <jack@suse.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Reviewed-by: Mingming Cao <mingming.cao@oracle.com>
Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
-rw-r--r-- | fs/ext4/extents.c | 15 |
1 files changed, 10 insertions, 5 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 96835e7fa715..fee4844a58e9 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -4798,6 +4798,10 @@ static long ext4_zero_range(struct file *file, loff_t offset, if (mode & FALLOC_FL_KEEP_SIZE) flags |= EXT4_GET_BLOCKS_KEEP_SIZE; + /* Wait all existing dio workers, newcomers will block on i_mutex */ + ext4_inode_block_unlocked_dio(inode); + inode_dio_wait(inode); + /* Preallocate the range including the unaligned edges */ if (partial_begin || partial_end) { ret = ext4_alloc_file_blocks(file, @@ -4806,7 +4810,7 @@ static long ext4_zero_range(struct file *file, loff_t offset, round_down(offset, 1 << blkbits)) >> blkbits, new_size, flags, mode); if (ret) - goto out_mutex; + goto out_dio; } @@ -4815,10 +4819,6 @@ static long ext4_zero_range(struct file *file, loff_t offset, flags |= (EXT4_GET_BLOCKS_CONVERT_UNWRITTEN | EXT4_EX_NOCACHE); - /* Wait all existing dio workers, newcomers will block on i_mutex */ - ext4_inode_block_unlocked_dio(inode); - inode_dio_wait(inode); - /* * Prevent page faults from reinstantiating pages we have * released from page cache. @@ -4958,8 +4958,13 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) goto out; } + /* Wait all existing dio workers, newcomers will block on i_mutex */ + ext4_inode_block_unlocked_dio(inode); + inode_dio_wait(inode); + ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size, flags, mode); + ext4_inode_resume_unlocked_dio(inode); if (ret) goto out; |