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>
This commit is contained in:
Jan Kara 2015-12-07 14:29:17 -05:00 committed by Theodore Ts'o
parent ea3d7209ca
commit 17048e8a08

View file

@ -4685,10 +4685,6 @@ static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset,
if (len <= EXT_UNWRITTEN_MAX_LEN) if (len <= EXT_UNWRITTEN_MAX_LEN)
flags |= EXT4_GET_BLOCKS_NO_NORMALIZE; flags |= EXT4_GET_BLOCKS_NO_NORMALIZE;
/* Wait all existing dio workers, newcomers will block on i_mutex */
ext4_inode_block_unlocked_dio(inode);
inode_dio_wait(inode);
/* /*
* credits to insert 1 extent into extent tree * credits to insert 1 extent into extent tree
*/ */
@ -4752,8 +4748,6 @@ retry:
goto retry; goto retry;
} }
ext4_inode_resume_unlocked_dio(inode);
return ret > 0 ? ret2 : ret; return ret > 0 ? ret2 : ret;
} }
@ -4827,6 +4821,10 @@ static long ext4_zero_range(struct file *file, loff_t offset,
if (mode & FALLOC_FL_KEEP_SIZE) if (mode & FALLOC_FL_KEEP_SIZE)
flags |= EXT4_GET_BLOCKS_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 */ /* Preallocate the range including the unaligned edges */
if (partial_begin || partial_end) { if (partial_begin || partial_end) {
ret = ext4_alloc_file_blocks(file, ret = ext4_alloc_file_blocks(file,
@ -4835,7 +4833,7 @@ static long ext4_zero_range(struct file *file, loff_t offset,
round_down(offset, 1 << blkbits)) >> blkbits, round_down(offset, 1 << blkbits)) >> blkbits,
new_size, flags, mode); new_size, flags, mode);
if (ret) if (ret)
goto out_mutex; goto out_dio;
} }
@ -4844,10 +4842,6 @@ static long ext4_zero_range(struct file *file, loff_t offset,
flags |= (EXT4_GET_BLOCKS_CONVERT_UNWRITTEN | flags |= (EXT4_GET_BLOCKS_CONVERT_UNWRITTEN |
EXT4_EX_NOCACHE); 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 * Prevent page faults from reinstantiating pages we have
* released from page cache. * released from page cache.
@ -4992,8 +4986,13 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
goto out; 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, ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size,
flags, mode); flags, mode);
ext4_inode_resume_unlocked_dio(inode);
if (ret) if (ret)
goto out; goto out;