Skip to content

Commit db1fcf7

Browse files
zhangyi089gregkh
authored andcommitted
ext4: refactor ext4_zero_range()
[ Upstream commit 53471e0 ] The current implementation of ext4_zero_range() contains complex position calculations and stale error tags. To improve the code's clarity and maintainability, it is essential to clean up the code and improve its readability, this can be achieved by: a) simplifying and renaming variables, making the style the same as ext4_punch_hole(); b) eliminating unnecessary position calculations, writing back all data in data=journal mode, and drop page cache from the original offset to the end, rather than using aligned blocks; c) renaming the stale out_mutex tags. Signed-off-by: Zhang Yi <[email protected]> Reviewed-by: Jan Kara <[email protected]> Reviewed-by: Ojaswin Mujoo <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Theodore Ts'o <[email protected]> Stable-dep-of: 29ec9be ("ext4: fix incorrect punch max_end") Signed-off-by: Sasha Levin <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 33f61ec commit db1fcf7

File tree

1 file changed

+57
-85
lines changed

1 file changed

+57
-85
lines changed

fs/ext4/extents.c

Lines changed: 57 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -4571,118 +4571,86 @@ static long ext4_zero_range(struct file *file, loff_t offset,
45714571
struct inode *inode = file_inode(file);
45724572
struct address_space *mapping = file->f_mapping;
45734573
handle_t *handle = NULL;
4574-
unsigned int max_blocks;
45754574
loff_t new_size = 0;
4576-
int ret = 0;
4577-
int flags;
4578-
int credits;
4579-
int partial_begin, partial_end;
4580-
loff_t start, end;
4581-
ext4_lblk_t lblk;
4575+
loff_t end = offset + len;
4576+
ext4_lblk_t start_lblk, end_lblk;
4577+
unsigned int blocksize = i_blocksize(inode);
45824578
unsigned int blkbits = inode->i_blkbits;
4579+
int ret, flags, credits;
45834580

45844581
trace_ext4_zero_range(inode, offset, len, mode);
45854582

4586-
/*
4587-
* Round up offset. This is not fallocate, we need to zero out
4588-
* blocks, so convert interior block aligned part of the range to
4589-
* unwritten and possibly manually zero out unaligned parts of the
4590-
* range. Here, start and partial_begin are inclusive, end and
4591-
* partial_end are exclusive.
4592-
*/
4593-
start = round_up(offset, 1 << blkbits);
4594-
end = round_down((offset + len), 1 << blkbits);
4595-
4596-
if (start < offset || end > offset + len)
4597-
return -EINVAL;
4598-
partial_begin = offset & ((1 << blkbits) - 1);
4599-
partial_end = (offset + len) & ((1 << blkbits) - 1);
4600-
4601-
lblk = start >> blkbits;
4602-
max_blocks = (end >> blkbits);
4603-
if (max_blocks < lblk)
4604-
max_blocks = 0;
4605-
else
4606-
max_blocks -= lblk;
4607-
46084583
inode_lock(inode);
46094584

46104585
/*
46114586
* Indirect files do not support unwritten extents
46124587
*/
46134588
if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) {
46144589
ret = -EOPNOTSUPP;
4615-
goto out_mutex;
4590+
goto out;
46164591
}
46174592

46184593
if (!(mode & FALLOC_FL_KEEP_SIZE) &&
4619-
(offset + len > inode->i_size ||
4620-
offset + len > EXT4_I(inode)->i_disksize)) {
4621-
new_size = offset + len;
4594+
(end > inode->i_size || end > EXT4_I(inode)->i_disksize)) {
4595+
new_size = end;
46224596
ret = inode_newsize_ok(inode, new_size);
46234597
if (ret)
4624-
goto out_mutex;
4598+
goto out;
46254599
}
46264600

4627-
flags = EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT;
4628-
46294601
/* Wait all existing dio workers, newcomers will block on i_rwsem */
46304602
inode_dio_wait(inode);
46314603

46324604
ret = file_modified(file);
46334605
if (ret)
4634-
goto out_mutex;
4635-
4636-
/* Preallocate the range including the unaligned edges */
4637-
if (partial_begin || partial_end) {
4638-
ret = ext4_alloc_file_blocks(file,
4639-
round_down(offset, 1 << blkbits) >> blkbits,
4640-
(round_up((offset + len), 1 << blkbits) -
4641-
round_down(offset, 1 << blkbits)) >> blkbits,
4642-
new_size, flags);
4643-
if (ret)
4644-
goto out_mutex;
4606+
goto out;
46454607

4646-
}
4608+
/*
4609+
* Prevent page faults from reinstantiating pages we have released
4610+
* from page cache.
4611+
*/
4612+
filemap_invalidate_lock(mapping);
46474613

4648-
/* Zero range excluding the unaligned edges */
4649-
if (max_blocks > 0) {
4650-
flags |= (EXT4_GET_BLOCKS_CONVERT_UNWRITTEN |
4651-
EXT4_EX_NOCACHE);
4614+
ret = ext4_break_layouts(inode);
4615+
if (ret)
4616+
goto out_invalidate_lock;
46524617

4653-
/*
4654-
* Prevent page faults from reinstantiating pages we have
4655-
* released from page cache.
4656-
*/
4657-
filemap_invalidate_lock(mapping);
4618+
flags = EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT;
4619+
/* Preallocate the range including the unaligned edges */
4620+
if (!IS_ALIGNED(offset | end, blocksize)) {
4621+
ext4_lblk_t alloc_lblk = offset >> blkbits;
4622+
ext4_lblk_t len_lblk = EXT4_MAX_BLOCKS(len, offset, blkbits);
46584623

4659-
ret = ext4_break_layouts(inode);
4660-
if (ret) {
4661-
filemap_invalidate_unlock(mapping);
4662-
goto out_mutex;
4663-
}
4624+
ret = ext4_alloc_file_blocks(file, alloc_lblk, len_lblk,
4625+
new_size, flags);
4626+
if (ret)
4627+
goto out_invalidate_lock;
4628+
}
46644629

4665-
ret = ext4_update_disksize_before_punch(inode, offset, len);
4666-
if (ret) {
4667-
filemap_invalidate_unlock(mapping);
4668-
goto out_mutex;
4669-
}
4630+
ret = ext4_update_disksize_before_punch(inode, offset, len);
4631+
if (ret)
4632+
goto out_invalidate_lock;
46704633

4671-
/* Now release the pages and zero block aligned part of pages */
4672-
ret = ext4_truncate_page_cache_block_range(inode, start, end);
4673-
if (ret) {
4674-
filemap_invalidate_unlock(mapping);
4675-
goto out_mutex;
4676-
}
4634+
/* Now release the pages and zero block aligned part of pages */
4635+
ret = ext4_truncate_page_cache_block_range(inode, offset, end);
4636+
if (ret)
4637+
goto out_invalidate_lock;
46774638

4678-
ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size,
4679-
flags);
4680-
filemap_invalidate_unlock(mapping);
4639+
/* Zero range excluding the unaligned edges */
4640+
start_lblk = EXT4_B_TO_LBLK(inode, offset);
4641+
end_lblk = end >> blkbits;
4642+
if (end_lblk > start_lblk) {
4643+
ext4_lblk_t zero_blks = end_lblk - start_lblk;
4644+
4645+
flags |= (EXT4_GET_BLOCKS_CONVERT_UNWRITTEN | EXT4_EX_NOCACHE);
4646+
ret = ext4_alloc_file_blocks(file, start_lblk, zero_blks,
4647+
new_size, flags);
46814648
if (ret)
4682-
goto out_mutex;
4649+
goto out_invalidate_lock;
46834650
}
4684-
if (!partial_begin && !partial_end)
4685-
goto out_mutex;
4651+
/* Finish zeroing out if it doesn't contain partial block */
4652+
if (IS_ALIGNED(offset | end, blocksize))
4653+
goto out_invalidate_lock;
46864654

46874655
/*
46884656
* In worst case we have to writeout two nonadjacent unwritten
@@ -4695,25 +4663,29 @@ static long ext4_zero_range(struct file *file, loff_t offset,
46954663
if (IS_ERR(handle)) {
46964664
ret = PTR_ERR(handle);
46974665
ext4_std_error(inode->i_sb, ret);
4698-
goto out_mutex;
4666+
goto out_invalidate_lock;
46994667
}
47004668

4669+
/* Zero out partial block at the edges of the range */
4670+
ret = ext4_zero_partial_blocks(handle, inode, offset, len);
4671+
if (ret)
4672+
goto out_handle;
4673+
47014674
if (new_size)
47024675
ext4_update_inode_size(inode, new_size);
47034676
ret = ext4_mark_inode_dirty(handle, inode);
47044677
if (unlikely(ret))
47054678
goto out_handle;
4706-
/* Zero out partial block at the edges of the range */
4707-
ret = ext4_zero_partial_blocks(handle, inode, offset, len);
4708-
if (ret >= 0)
4709-
ext4_update_inode_fsync_trans(handle, inode, 1);
47104679

4680+
ext4_update_inode_fsync_trans(handle, inode, 1);
47114681
if (file->f_flags & O_SYNC)
47124682
ext4_handle_sync(handle);
47134683

47144684
out_handle:
47154685
ext4_journal_stop(handle);
4716-
out_mutex:
4686+
out_invalidate_lock:
4687+
filemap_invalidate_unlock(mapping);
4688+
out:
47174689
inode_unlock(inode);
47184690
return ret;
47194691
}

0 commit comments

Comments
 (0)