Skip to content

Commit c4602a1

Browse files
zhangyi089tytso
authored andcommitted
ext4: move zero partial block range functions out of active handle
Move ext4_block_zero_eof() and ext4_zero_partial_blocks() calls out of the active handle context, making them independent operations, and also add return value checks. This is safe because it still ensures data is updated before metadata for data=ordered mode and data=journal mode because we still zero data and ordering data before modifying the metadata. This change is required for iomap infrastructure conversion because the iomap buffered I/O path does not use the same journal infrastructure for partial block zeroing. The lock ordering of folio lock and starting transactions is "folio lock -> transaction start", which is opposite of the current path. Therefore, zeroing partial blocks cannot be performed under the active handle. Signed-off-by: Zhang Yi <yi.zhang@huawei.com> Reviewed-by: Jan Kara <jack@suse.cz> Link: https://patch.msgid.link/20260327102939.1095257-9-yi.zhang@huaweicloud.com Signed-off-by: Theodore Ts'o <tytso@mit.edu>
1 parent ad1876b commit c4602a1

2 files changed

Lines changed: 41 additions & 38 deletions

File tree

fs/ext4/extents.c

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4614,6 +4614,13 @@ static int ext4_alloc_file_blocks(struct file *file, loff_t offset, loff_t len,
46144614
credits = ext4_chunk_trans_blocks(inode, len_lblk);
46154615
depth = ext_depth(inode);
46164616

4617+
/* Zero to the end of the block containing i_size */
4618+
if (new_size > old_size) {
4619+
ret = ext4_block_zero_eof(inode, old_size, LLONG_MAX);
4620+
if (ret)
4621+
return ret;
4622+
}
4623+
46174624
retry:
46184625
while (len_lblk) {
46194626
/*
@@ -4652,10 +4659,8 @@ static int ext4_alloc_file_blocks(struct file *file, loff_t offset, loff_t len,
46524659
if (ext4_update_inode_size(inode, epos) & 0x1)
46534660
inode_set_mtime_to_ts(inode,
46544661
inode_get_ctime(inode));
4655-
if (epos > old_size) {
4662+
if (epos > old_size)
46564663
pagecache_isize_extended(inode, old_size, epos);
4657-
ext4_block_zero_eof(inode, old_size, epos);
4658-
}
46594664
}
46604665
ret2 = ext4_mark_inode_dirty(handle, inode);
46614666
ext4_update_inode_fsync_trans(handle, inode, 1);
@@ -4697,7 +4702,7 @@ static long ext4_zero_range(struct file *file, loff_t offset,
46974702
loff_t align_start, align_end, new_size = 0;
46984703
loff_t end = offset + len;
46994704
unsigned int blocksize = i_blocksize(inode);
4700-
int ret, flags, credits;
4705+
int ret, flags;
47014706

47024707
trace_ext4_zero_range(inode, offset, len, mode);
47034708
WARN_ON_ONCE(!inode_is_locked(inode));
@@ -4751,25 +4756,18 @@ static long ext4_zero_range(struct file *file, loff_t offset,
47514756
if (IS_ALIGNED(offset | end, blocksize))
47524757
return ret;
47534758

4754-
/*
4755-
* In worst case we have to writeout two nonadjacent unwritten
4756-
* blocks and update the inode
4757-
*/
4758-
credits = (2 * ext4_ext_index_trans_blocks(inode, 2)) + 1;
4759-
if (ext4_should_journal_data(inode))
4760-
credits += 2;
4761-
handle = ext4_journal_start(inode, EXT4_HT_MISC, credits);
4759+
/* Zero out partial block at the edges of the range */
4760+
ret = ext4_zero_partial_blocks(inode, offset, len);
4761+
if (ret)
4762+
return ret;
4763+
4764+
handle = ext4_journal_start(inode, EXT4_HT_MISC, 1);
47624765
if (IS_ERR(handle)) {
47634766
ret = PTR_ERR(handle);
47644767
ext4_std_error(inode->i_sb, ret);
47654768
return ret;
47664769
}
47674770

4768-
/* Zero out partial block at the edges of the range */
4769-
ret = ext4_zero_partial_blocks(inode, offset, len);
4770-
if (ret)
4771-
goto out_handle;
4772-
47734771
if (new_size)
47744772
ext4_update_inode_size(inode, new_size);
47754773
ret = ext4_mark_inode_dirty(handle, inode);

fs/ext4/inode.c

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4471,8 +4471,12 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
44714471
if (ret)
44724472
return ret;
44734473

4474+
ret = ext4_zero_partial_blocks(inode, offset, length);
4475+
if (ret)
4476+
return ret;
4477+
44744478
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
4475-
credits = ext4_chunk_trans_extent(inode, 2);
4479+
credits = ext4_chunk_trans_extent(inode, 0);
44764480
else
44774481
credits = ext4_blocks_for_truncate(inode);
44784482
handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, credits);
@@ -4482,10 +4486,6 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
44824486
return ret;
44834487
}
44844488

4485-
ret = ext4_zero_partial_blocks(inode, offset, length);
4486-
if (ret)
4487-
goto out_handle;
4488-
44894489
/* If there are blocks to remove, do it */
44904490
start_lblk = EXT4_B_TO_LBLK(inode, offset);
44914491
end_lblk = end >> inode->i_blkbits;
@@ -4622,6 +4622,11 @@ int ext4_truncate(struct inode *inode)
46224622
err = ext4_inode_attach_jinode(inode);
46234623
if (err)
46244624
goto out_trace;
4625+
4626+
/* Zero to the end of the block containing i_size */
4627+
err = ext4_block_zero_eof(inode, inode->i_size, LLONG_MAX);
4628+
if (err)
4629+
goto out_trace;
46254630
}
46264631

46274632
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
@@ -4635,10 +4640,6 @@ int ext4_truncate(struct inode *inode)
46354640
goto out_trace;
46364641
}
46374642

4638-
/* Zero to the end of the block containing i_size */
4639-
if (inode->i_size & (inode->i_sb->s_blocksize - 1))
4640-
ext4_block_zero_eof(inode, inode->i_size, LLONG_MAX);
4641-
46424643
/*
46434644
* We add the inode to the orphan list, so that if this
46444645
* truncate spans multiple transactions, and we crash, we will
@@ -6008,15 +6009,6 @@ int ext4_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
60086009
goto out_mmap_sem;
60096010
}
60106011

6011-
handle = ext4_journal_start(inode, EXT4_HT_INODE, 3);
6012-
if (IS_ERR(handle)) {
6013-
error = PTR_ERR(handle);
6014-
goto out_mmap_sem;
6015-
}
6016-
if (ext4_handle_valid(handle) && shrink) {
6017-
error = ext4_orphan_add(handle, inode);
6018-
orphan = 1;
6019-
}
60206012
/*
60216013
* Update c/mtime and tail zero the EOF folio on
60226014
* truncate up. ext4_truncate() handles the shrink case
@@ -6025,9 +6017,22 @@ int ext4_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
60256017
if (!shrink) {
60266018
inode_set_mtime_to_ts(inode,
60276019
inode_set_ctime_current(inode));
6028-
if (oldsize & (inode->i_sb->s_blocksize - 1))
6029-
ext4_block_zero_eof(inode, oldsize,
6030-
LLONG_MAX);
6020+
if (oldsize & (inode->i_sb->s_blocksize - 1)) {
6021+
error = ext4_block_zero_eof(inode,
6022+
oldsize, LLONG_MAX);
6023+
if (error)
6024+
goto out_mmap_sem;
6025+
}
6026+
}
6027+
6028+
handle = ext4_journal_start(inode, EXT4_HT_INODE, 3);
6029+
if (IS_ERR(handle)) {
6030+
error = PTR_ERR(handle);
6031+
goto out_mmap_sem;
6032+
}
6033+
if (ext4_handle_valid(handle) && shrink) {
6034+
error = ext4_orphan_add(handle, inode);
6035+
orphan = 1;
60316036
}
60326037

60336038
if (shrink)

0 commit comments

Comments
 (0)