Skip to content

Commit 33f61ec

Browse files
zhangyi089gregkh
authored andcommitted
ext4: refactor ext4_punch_hole()
[ Upstream commit 982bf37 ] The current implementation of ext4_punch_hole() 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; b) eliminating unnecessary position calculations; c) writing back all data in data=journal mode, and drop page cache from the original offset to the end, rather than using aligned blocks, d) renaming the stale error 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 d9116d2 commit 33f61ec

File tree

2 files changed

+55
-66
lines changed

2 files changed

+55
-66
lines changed

fs/ext4/ext4.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,8 @@ struct ext4_io_submit {
368368
#define EXT4_MAX_BLOCKS(size, offset, blkbits) \
369369
((EXT4_BLOCK_ALIGN(size + offset, blkbits) >> blkbits) - (offset >> \
370370
blkbits))
371+
#define EXT4_B_TO_LBLK(inode, offset) \
372+
(round_up((offset), i_blocksize(inode)) >> (inode)->i_blkbits)
371373

372374
/* Translate a block number to a cluster number */
373375
#define EXT4_B2C(sbi, blk) ((blk) >> (sbi)->s_cluster_bits)

fs/ext4/inode.c

Lines changed: 53 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -3991,58 +3991,49 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
39913991
{
39923992
struct inode *inode = file_inode(file);
39933993
struct super_block *sb = inode->i_sb;
3994-
ext4_lblk_t first_block, stop_block;
3994+
ext4_lblk_t start_lblk, end_lblk;
39953995
struct address_space *mapping = inode->i_mapping;
3996-
loff_t first_block_offset, last_block_offset, max_length;
3997-
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
3996+
loff_t max_end = EXT4_SB(sb)->s_bitmap_maxbytes - sb->s_blocksize;
3997+
loff_t end = offset + length;
39983998
handle_t *handle;
39993999
unsigned int credits;
4000-
int ret = 0, ret2 = 0;
4000+
int ret = 0;
40014001

40024002
trace_ext4_punch_hole(inode, offset, length, 0);
40034003

40044004
inode_lock(inode);
40054005

40064006
/* No need to punch hole beyond i_size */
40074007
if (offset >= inode->i_size)
4008-
goto out_mutex;
4008+
goto out;
40094009

40104010
/*
4011-
* If the hole extends beyond i_size, set the hole
4012-
* to end after the page that contains i_size
4011+
* If the hole extends beyond i_size, set the hole to end after
4012+
* the page that contains i_size, and also make sure that the hole
4013+
* within one block before last range.
40134014
*/
4014-
if (offset + length > inode->i_size) {
4015-
length = inode->i_size +
4016-
PAGE_SIZE - (inode->i_size & (PAGE_SIZE - 1)) -
4017-
offset;
4018-
}
4015+
if (end > inode->i_size)
4016+
end = round_up(inode->i_size, PAGE_SIZE);
4017+
if (end > max_end)
4018+
end = max_end;
4019+
length = end - offset;
40194020

40204021
/*
4021-
* For punch hole the length + offset needs to be within one block
4022-
* before last range. Adjust the length if it goes beyond that limit.
4022+
* Attach jinode to inode for jbd2 if we do any zeroing of partial
4023+
* block.
40234024
*/
4024-
max_length = sbi->s_bitmap_maxbytes - inode->i_sb->s_blocksize;
4025-
if (offset + length > max_length)
4026-
length = max_length - offset;
4027-
4028-
if (offset & (sb->s_blocksize - 1) ||
4029-
(offset + length) & (sb->s_blocksize - 1)) {
4030-
/*
4031-
* Attach jinode to inode for jbd2 if we do any zeroing of
4032-
* partial block
4033-
*/
4025+
if (!IS_ALIGNED(offset | end, sb->s_blocksize)) {
40344026
ret = ext4_inode_attach_jinode(inode);
40354027
if (ret < 0)
4036-
goto out_mutex;
4037-
4028+
goto out;
40384029
}
40394030

40404031
/* Wait all existing dio workers, newcomers will block on i_rwsem */
40414032
inode_dio_wait(inode);
40424033

40434034
ret = file_modified(file);
40444035
if (ret)
4045-
goto out_mutex;
4036+
goto out;
40464037

40474038
/*
40484039
* Prevent page faults from reinstantiating pages we have released from
@@ -4052,22 +4043,16 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
40524043

40534044
ret = ext4_break_layouts(inode);
40544045
if (ret)
4055-
goto out_dio;
4046+
goto out_invalidate_lock;
40564047

4057-
first_block_offset = round_up(offset, sb->s_blocksize);
4058-
last_block_offset = round_down((offset + length), sb->s_blocksize) - 1;
4048+
ret = ext4_update_disksize_before_punch(inode, offset, length);
4049+
if (ret)
4050+
goto out_invalidate_lock;
40594051

40604052
/* Now release the pages and zero block aligned part of pages*/
4061-
if (last_block_offset > first_block_offset) {
4062-
ret = ext4_update_disksize_before_punch(inode, offset, length);
4063-
if (ret)
4064-
goto out_dio;
4065-
4066-
ret = ext4_truncate_page_cache_block_range(inode,
4067-
first_block_offset, last_block_offset + 1);
4068-
if (ret)
4069-
goto out_dio;
4070-
}
4053+
ret = ext4_truncate_page_cache_block_range(inode, offset, end);
4054+
if (ret)
4055+
goto out_invalidate_lock;
40714056

40724057
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
40734058
credits = ext4_writepage_trans_blocks(inode);
@@ -4077,52 +4062,54 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
40774062
if (IS_ERR(handle)) {
40784063
ret = PTR_ERR(handle);
40794064
ext4_std_error(sb, ret);
4080-
goto out_dio;
4065+
goto out_invalidate_lock;
40814066
}
40824067

4083-
ret = ext4_zero_partial_blocks(handle, inode, offset,
4084-
length);
4068+
ret = ext4_zero_partial_blocks(handle, inode, offset, length);
40854069
if (ret)
4086-
goto out_stop;
4087-
4088-
first_block = (offset + sb->s_blocksize - 1) >>
4089-
EXT4_BLOCK_SIZE_BITS(sb);
4090-
stop_block = (offset + length) >> EXT4_BLOCK_SIZE_BITS(sb);
4070+
goto out_handle;
40914071

40924072
/* If there are blocks to remove, do it */
4093-
if (stop_block > first_block) {
4094-
ext4_lblk_t hole_len = stop_block - first_block;
4073+
start_lblk = EXT4_B_TO_LBLK(inode, offset);
4074+
end_lblk = end >> inode->i_blkbits;
4075+
4076+
if (end_lblk > start_lblk) {
4077+
ext4_lblk_t hole_len = end_lblk - start_lblk;
40954078

40964079
down_write(&EXT4_I(inode)->i_data_sem);
40974080
ext4_discard_preallocations(inode);
40984081

4099-
ext4_es_remove_extent(inode, first_block, hole_len);
4082+
ext4_es_remove_extent(inode, start_lblk, hole_len);
41004083

41014084
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
4102-
ret = ext4_ext_remove_space(inode, first_block,
4103-
stop_block - 1);
4085+
ret = ext4_ext_remove_space(inode, start_lblk,
4086+
end_lblk - 1);
41044087
else
4105-
ret = ext4_ind_remove_space(handle, inode, first_block,
4106-
stop_block);
4088+
ret = ext4_ind_remove_space(handle, inode, start_lblk,
4089+
end_lblk);
4090+
if (ret) {
4091+
up_write(&EXT4_I(inode)->i_data_sem);
4092+
goto out_handle;
4093+
}
41074094

4108-
ext4_es_insert_extent(inode, first_block, hole_len, ~0,
4095+
ext4_es_insert_extent(inode, start_lblk, hole_len, ~0,
41094096
EXTENT_STATUS_HOLE, 0);
41104097
up_write(&EXT4_I(inode)->i_data_sem);
41114098
}
4112-
ext4_fc_track_range(handle, inode, first_block, stop_block);
4099+
ext4_fc_track_range(handle, inode, start_lblk, end_lblk);
4100+
4101+
ret = ext4_mark_inode_dirty(handle, inode);
4102+
if (unlikely(ret))
4103+
goto out_handle;
4104+
4105+
ext4_update_inode_fsync_trans(handle, inode, 1);
41134106
if (IS_SYNC(inode))
41144107
ext4_handle_sync(handle);
4115-
4116-
ret2 = ext4_mark_inode_dirty(handle, inode);
4117-
if (unlikely(ret2))
4118-
ret = ret2;
4119-
if (ret >= 0)
4120-
ext4_update_inode_fsync_trans(handle, inode, 1);
4121-
out_stop:
4108+
out_handle:
41224109
ext4_journal_stop(handle);
4123-
out_dio:
4110+
out_invalidate_lock:
41244111
filemap_invalidate_unlock(mapping);
4125-
out_mutex:
4112+
out:
41264113
inode_unlock(inode);
41274114
return ret;
41284115
}

0 commit comments

Comments
 (0)