Skip to content

Commit 7d81ec0

Browse files
zhangyi089tytso
authored andcommitted
ext4: ensure zeroed partial blocks are persisted in SYNC mode
In ext4_zero_range() and ext4_punch_hole(), when operating in SYNC mode and zeroing a partial block, only data=journal modes guarantee that the zeroed data is synchronously persisted after the operation completes. For data=ordered/writeback mode and non-journal modes, this guarantee is missing. Introduce a partial_zero parameter to explicitly trigger writeback for all scenarios where a partial block is zeroed, ensuring the zeroed data is durably persisted. Signed-off-by: Zhang Yi <yi.zhang@huawei.com> Link: https://patch.msgid.link/20260327102939.1095257-10-yi.zhang@huaweicloud.com Signed-off-by: Theodore Ts'o <tytso@mit.edu>
1 parent c4602a1 commit 7d81ec0

3 files changed

Lines changed: 23 additions & 7 deletions

File tree

fs/ext4/ext4.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3099,7 +3099,7 @@ extern int ext4_meta_trans_blocks(struct inode *inode, int lblocks,
30993099
int pextents);
31003100
extern int ext4_block_zero_eof(struct inode *inode, loff_t from, loff_t end);
31013101
extern int ext4_zero_partial_blocks(struct inode *inode, loff_t lstart,
3102-
loff_t length);
3102+
loff_t length, bool *did_zero);
31033103
extern vm_fault_t ext4_page_mkwrite(struct vm_fault *vmf);
31043104
extern qsize_t *ext4_get_reserved_space(struct inode *inode);
31053105
extern int ext4_get_projid(struct inode *inode, kprojid_t *projid);

fs/ext4/extents.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4702,6 +4702,7 @@ static long ext4_zero_range(struct file *file, loff_t offset,
47024702
loff_t align_start, align_end, new_size = 0;
47034703
loff_t end = offset + len;
47044704
unsigned int blocksize = i_blocksize(inode);
4705+
bool partial_zeroed = false;
47054706
int ret, flags;
47064707

47074708
trace_ext4_zero_range(inode, offset, len, mode);
@@ -4757,9 +4758,15 @@ static long ext4_zero_range(struct file *file, loff_t offset,
47574758
return ret;
47584759

47594760
/* Zero out partial block at the edges of the range */
4760-
ret = ext4_zero_partial_blocks(inode, offset, len);
4761+
ret = ext4_zero_partial_blocks(inode, offset, len, &partial_zeroed);
47614762
if (ret)
47624763
return ret;
4764+
if (((file->f_flags & O_SYNC) || IS_SYNC(inode)) && partial_zeroed) {
4765+
ret = filemap_write_and_wait_range(inode->i_mapping, offset,
4766+
end - 1);
4767+
if (ret)
4768+
return ret;
4769+
}
47634770

47644771
handle = ext4_journal_start(inode, EXT4_HT_MISC, 1);
47654772
if (IS_ERR(handle)) {

fs/ext4/inode.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4257,7 +4257,8 @@ int ext4_block_zero_eof(struct inode *inode, loff_t from, loff_t end)
42574257
return 0;
42584258
}
42594259

4260-
int ext4_zero_partial_blocks(struct inode *inode, loff_t lstart, loff_t length)
4260+
int ext4_zero_partial_blocks(struct inode *inode, loff_t lstart, loff_t length,
4261+
bool *did_zero)
42614262
{
42624263
struct super_block *sb = inode->i_sb;
42634264
unsigned partial_start, partial_end;
@@ -4274,20 +4275,21 @@ int ext4_zero_partial_blocks(struct inode *inode, loff_t lstart, loff_t length)
42744275
/* Handle partial zero within the single block */
42754276
if (start == end &&
42764277
(partial_start || (partial_end != sb->s_blocksize - 1))) {
4277-
err = ext4_block_zero_range(inode, lstart, length, NULL, NULL);
4278+
err = ext4_block_zero_range(inode, lstart, length, did_zero,
4279+
NULL);
42784280
return err;
42794281
}
42804282
/* Handle partial zero out on the start of the range */
42814283
if (partial_start) {
42824284
err = ext4_block_zero_range(inode, lstart, sb->s_blocksize,
4283-
NULL, NULL);
4285+
did_zero, NULL);
42844286
if (err)
42854287
return err;
42864288
}
42874289
/* Handle partial zero out on the end of the range */
42884290
if (partial_end != sb->s_blocksize - 1)
42894291
err = ext4_block_zero_range(inode, byte_end - partial_end,
4290-
partial_end + 1, NULL, NULL);
4292+
partial_end + 1, did_zero, NULL);
42914293
return err;
42924294
}
42934295

@@ -4436,6 +4438,7 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
44364438
loff_t end = offset + length;
44374439
handle_t *handle;
44384440
unsigned int credits;
4441+
bool partial_zeroed = false;
44394442
int ret;
44404443

44414444
trace_ext4_punch_hole(inode, offset, length, 0);
@@ -4471,9 +4474,15 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
44714474
if (ret)
44724475
return ret;
44734476

4474-
ret = ext4_zero_partial_blocks(inode, offset, length);
4477+
ret = ext4_zero_partial_blocks(inode, offset, length, &partial_zeroed);
44754478
if (ret)
44764479
return ret;
4480+
if (((file->f_flags & O_SYNC) || IS_SYNC(inode)) && partial_zeroed) {
4481+
ret = filemap_write_and_wait_range(inode->i_mapping, offset,
4482+
end - 1);
4483+
if (ret)
4484+
return ret;
4485+
}
44774486

44784487
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
44794488
credits = ext4_chunk_trans_extent(inode, 0);

0 commit comments

Comments
 (0)