Skip to content

Commit 69e2d5c

Browse files
zhangyi089tytso
authored andcommitted
ext4: move ordered data handling out of ext4_block_do_zero_range()
Remove the handle parameter from ext4_block_do_zero_range() and move the ordered data handling to ext4_block_zero_eof(). This is necessary for truncate up and append writes across a range extending beyond EOF. The ordered data must be committed before updating i_disksize to prevent exposing stale on-disk data from concurrent post-EOF mmap writes during previous folio writeback or in case of system crash during append writes. This is unnecessary for partial block hole punching because the entire punch operation does not provide atomicity guarantees and can already expose intermediate results in case of crash. Hole punching can only ever expose data that was there before the punch but missed zeroing during append / truncate could expose data that was not visible in the file before the operation. Since ordered data handling is no longer performed inside ext4_zero_partial_blocks(), ext4_punch_hole() no longer needs to attach jinode. This is prepared for the conversion to the iomap infrastructure, which does not use ordered data mode while zeroing post-EOF partial blocks. Signed-off-by: Zhang Yi <yi.zhang@huawei.com> Reviewed-by: Jan Kara <jack@suse.cz> Link: https://patch.msgid.link/20260327102939.1095257-6-yi.zhang@huaweicloud.com Signed-off-by: Theodore Ts'o <tytso@mit.edu>
1 parent ad11526 commit 69e2d5c

1 file changed

Lines changed: 32 additions & 29 deletions

File tree

fs/ext4/inode.c

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4105,12 +4105,12 @@ static struct buffer_head *ext4_load_tail_bh(struct inode *inode, loff_t from)
41054105
return err ? ERR_PTR(err) : NULL;
41064106
}
41074107

4108-
static int ext4_block_do_zero_range(handle_t *handle, struct inode *inode,
4109-
loff_t from, loff_t length, bool *did_zero)
4108+
static int ext4_block_do_zero_range(struct inode *inode, loff_t from,
4109+
loff_t length, bool *did_zero,
4110+
bool *zero_written)
41104111
{
41114112
struct buffer_head *bh;
41124113
struct folio *folio;
4113-
int err = 0;
41144114

41154115
bh = ext4_load_tail_bh(inode, from);
41164116
if (IS_ERR_OR_NULL(bh))
@@ -4121,19 +4121,14 @@ static int ext4_block_do_zero_range(handle_t *handle, struct inode *inode,
41214121
BUFFER_TRACE(bh, "zeroed end of block");
41224122

41234123
mark_buffer_dirty(bh);
4124-
/*
4125-
* Only the written block requires ordered data to prevent exposing
4126-
* stale data.
4127-
*/
4128-
if (ext4_should_order_data(inode) &&
4129-
!buffer_unwritten(bh) && !buffer_delay(bh))
4130-
err = ext4_jbd2_inode_add_write(handle, inode, from, length);
4131-
if (!err && did_zero)
4124+
if (did_zero)
41324125
*did_zero = true;
4126+
if (zero_written && !buffer_unwritten(bh) && !buffer_delay(bh))
4127+
*zero_written = true;
41334128

41344129
folio_unlock(folio);
41354130
folio_put(folio);
4136-
return err;
4131+
return 0;
41374132
}
41384133

41394134
static int ext4_block_journalled_zero_range(handle_t *handle,
@@ -4176,7 +4171,8 @@ static int ext4_block_journalled_zero_range(handle_t *handle,
41764171
* shortened to end of the block that corresponds to 'from'.
41774172
*/
41784173
static int ext4_block_zero_range(handle_t *handle, struct inode *inode,
4179-
loff_t from, loff_t length, bool *did_zero)
4174+
loff_t from, loff_t length, bool *did_zero,
4175+
bool *zero_written)
41804176
{
41814177
unsigned blocksize = inode->i_sb->s_blocksize;
41824178
unsigned int max = blocksize - (from & (blocksize - 1));
@@ -4195,7 +4191,8 @@ static int ext4_block_zero_range(handle_t *handle, struct inode *inode,
41954191
return ext4_block_journalled_zero_range(handle, inode, from,
41964192
length, did_zero);
41974193
}
4198-
return ext4_block_do_zero_range(handle, inode, from, length, did_zero);
4194+
return ext4_block_do_zero_range(inode, from, length, did_zero,
4195+
zero_written);
41994196
}
42004197

42014198
/*
@@ -4211,6 +4208,9 @@ int ext4_block_zero_eof(handle_t *handle, struct inode *inode,
42114208
unsigned int blocksize = i_blocksize(inode);
42124209
unsigned int offset;
42134210
loff_t length = end - from;
4211+
bool did_zero = false;
4212+
bool zero_written = false;
4213+
int err;
42144214

42154215
offset = from & (blocksize - 1);
42164216
if (!offset || from >= end)
@@ -4222,7 +4222,21 @@ int ext4_block_zero_eof(handle_t *handle, struct inode *inode,
42224222
if (length > blocksize - offset)
42234223
length = blocksize - offset;
42244224

4225-
return ext4_block_zero_range(handle, inode, from, length, NULL);
4225+
err = ext4_block_zero_range(handle, inode, from, length,
4226+
&did_zero, &zero_written);
4227+
if (err)
4228+
return err;
4229+
/*
4230+
* It's necessary to order zeroed data before update i_disksize when
4231+
* truncating up or performing an append write, because there might be
4232+
* exposing stale on-disk data which may caused by concurrent post-EOF
4233+
* mmap write during folio writeback.
4234+
*/
4235+
if (ext4_should_order_data(inode) &&
4236+
did_zero && zero_written && !IS_DAX(inode))
4237+
err = ext4_jbd2_inode_add_write(handle, inode, from, length);
4238+
4239+
return err;
42264240
}
42274241

42284242
int ext4_zero_partial_blocks(handle_t *handle, struct inode *inode,
@@ -4244,21 +4258,21 @@ int ext4_zero_partial_blocks(handle_t *handle, struct inode *inode,
42444258
if (start == end &&
42454259
(partial_start || (partial_end != sb->s_blocksize - 1))) {
42464260
err = ext4_block_zero_range(handle, inode, lstart,
4247-
length, NULL);
4261+
length, NULL, NULL);
42484262
return err;
42494263
}
42504264
/* Handle partial zero out on the start of the range */
42514265
if (partial_start) {
42524266
err = ext4_block_zero_range(handle, inode, lstart,
4253-
sb->s_blocksize, NULL);
4267+
sb->s_blocksize, NULL, NULL);
42544268
if (err)
42554269
return err;
42564270
}
42574271
/* Handle partial zero out on the end of the range */
42584272
if (partial_end != sb->s_blocksize - 1)
42594273
err = ext4_block_zero_range(handle, inode,
42604274
byte_end - partial_end,
4261-
partial_end + 1, NULL);
4275+
partial_end + 1, NULL, NULL);
42624276
return err;
42634277
}
42644278

@@ -4433,17 +4447,6 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
44334447
end = max_end;
44344448
length = end - offset;
44354449

4436-
/*
4437-
* Attach jinode to inode for jbd2 if we do any zeroing of partial
4438-
* block.
4439-
*/
4440-
if (!IS_ALIGNED(offset | end, sb->s_blocksize)) {
4441-
ret = ext4_inode_attach_jinode(inode);
4442-
if (ret < 0)
4443-
return ret;
4444-
}
4445-
4446-
44474450
ret = ext4_update_disksize_before_punch(inode, offset, length);
44484451
if (ret)
44494452
return ret;

0 commit comments

Comments
 (0)