diff options
| author | Jan Kara <jack@suse.com> | 2015-12-07 14:29:17 -0500 |
|---|---|---|
| committer | Theodore Ts'o <tytso@mit.edu> | 2015-12-07 14:29:17 -0500 |
| commit | 17048e8a083fec7ad841d88ef0812707fbc7e39f (patch) | |
| tree | a5f6ac206edfbe5807e6f9834d6dfe663e9b31c6 | |
| parent | ea3d7209ca01da209cda6f0dea8be9cc4b7a933b (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>
| -rw-r--r-- | fs/ext4/extents.c | 21 |
1 files changed, 10 insertions, 11 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 5be9ca5a8a7a..65b5ada2833f 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
| @@ -4685,10 +4685,6 @@ static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset, | |||
| 4685 | if (len <= EXT_UNWRITTEN_MAX_LEN) | 4685 | if (len <= EXT_UNWRITTEN_MAX_LEN) |
| 4686 | flags |= EXT4_GET_BLOCKS_NO_NORMALIZE; | 4686 | flags |= EXT4_GET_BLOCKS_NO_NORMALIZE; |
| 4687 | 4687 | ||
| 4688 | /* Wait all existing dio workers, newcomers will block on i_mutex */ | ||
| 4689 | ext4_inode_block_unlocked_dio(inode); | ||
| 4690 | inode_dio_wait(inode); | ||
| 4691 | |||
| 4692 | /* | 4688 | /* |
| 4693 | * credits to insert 1 extent into extent tree | 4689 | * credits to insert 1 extent into extent tree |
| 4694 | */ | 4690 | */ |
| @@ -4752,8 +4748,6 @@ retry: | |||
| 4752 | goto retry; | 4748 | goto retry; |
| 4753 | } | 4749 | } |
| 4754 | 4750 | ||
| 4755 | ext4_inode_resume_unlocked_dio(inode); | ||
| 4756 | |||
| 4757 | return ret > 0 ? ret2 : ret; | 4751 | return ret > 0 ? ret2 : ret; |
| 4758 | } | 4752 | } |
| 4759 | 4753 | ||
| @@ -4827,6 +4821,10 @@ static long ext4_zero_range(struct file *file, loff_t offset, | |||
| 4827 | if (mode & FALLOC_FL_KEEP_SIZE) | 4821 | if (mode & FALLOC_FL_KEEP_SIZE) |
| 4828 | flags |= EXT4_GET_BLOCKS_KEEP_SIZE; | 4822 | flags |= EXT4_GET_BLOCKS_KEEP_SIZE; |
| 4829 | 4823 | ||
| 4824 | /* Wait all existing dio workers, newcomers will block on i_mutex */ | ||
| 4825 | ext4_inode_block_unlocked_dio(inode); | ||
| 4826 | inode_dio_wait(inode); | ||
| 4827 | |||
| 4830 | /* Preallocate the range including the unaligned edges */ | 4828 | /* Preallocate the range including the unaligned edges */ |
| 4831 | if (partial_begin || partial_end) { | 4829 | if (partial_begin || partial_end) { |
| 4832 | ret = ext4_alloc_file_blocks(file, | 4830 | ret = ext4_alloc_file_blocks(file, |
| @@ -4835,7 +4833,7 @@ static long ext4_zero_range(struct file *file, loff_t offset, | |||
| 4835 | round_down(offset, 1 << blkbits)) >> blkbits, | 4833 | round_down(offset, 1 << blkbits)) >> blkbits, |
| 4836 | new_size, flags, mode); | 4834 | new_size, flags, mode); |
| 4837 | if (ret) | 4835 | if (ret) |
| 4838 | goto out_mutex; | 4836 | goto out_dio; |
| 4839 | 4837 | ||
| 4840 | } | 4838 | } |
| 4841 | 4839 | ||
| @@ -4844,10 +4842,6 @@ static long ext4_zero_range(struct file *file, loff_t offset, | |||
| 4844 | flags |= (EXT4_GET_BLOCKS_CONVERT_UNWRITTEN | | 4842 | flags |= (EXT4_GET_BLOCKS_CONVERT_UNWRITTEN | |
| 4845 | EXT4_EX_NOCACHE); | 4843 | EXT4_EX_NOCACHE); |
| 4846 | 4844 | ||
| 4847 | /* Wait all existing dio workers, newcomers will block on i_mutex */ | ||
| 4848 | ext4_inode_block_unlocked_dio(inode); | ||
| 4849 | inode_dio_wait(inode); | ||
| 4850 | |||
| 4851 | /* | 4845 | /* |
| 4852 | * Prevent page faults from reinstantiating pages we have | 4846 | * Prevent page faults from reinstantiating pages we have |
| 4853 | * released from page cache. | 4847 | * released from page cache. |
| @@ -4992,8 +4986,13 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) | |||
| 4992 | goto out; | 4986 | goto out; |
| 4993 | } | 4987 | } |
| 4994 | 4988 | ||
| 4989 | /* Wait all existing dio workers, newcomers will block on i_mutex */ | ||
| 4990 | ext4_inode_block_unlocked_dio(inode); | ||
| 4991 | inode_dio_wait(inode); | ||
| 4992 | |||
| 4995 | ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size, | 4993 | ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size, |
| 4996 | flags, mode); | 4994 | flags, mode); |
| 4995 | ext4_inode_resume_unlocked_dio(inode); | ||
| 4997 | if (ret) | 4996 | if (ret) |
| 4998 | goto out; | 4997 | goto out; |
| 4999 | 4998 | ||
