Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Zhang Yi and committed by
Theodore Ts'o
7d81ec02 c4602a1d

+23 -7
+1 -1
fs/ext4/ext4.h
··· 3099 3099 int pextents); 3100 3100 extern int ext4_block_zero_eof(struct inode *inode, loff_t from, loff_t end); 3101 3101 extern int ext4_zero_partial_blocks(struct inode *inode, loff_t lstart, 3102 - loff_t length); 3102 + loff_t length, bool *did_zero); 3103 3103 extern vm_fault_t ext4_page_mkwrite(struct vm_fault *vmf); 3104 3104 extern qsize_t *ext4_get_reserved_space(struct inode *inode); 3105 3105 extern int ext4_get_projid(struct inode *inode, kprojid_t *projid);
+8 -1
fs/ext4/extents.c
··· 4702 4702 loff_t align_start, align_end, new_size = 0; 4703 4703 loff_t end = offset + len; 4704 4704 unsigned int blocksize = i_blocksize(inode); 4705 + bool partial_zeroed = false; 4705 4706 int ret, flags; 4706 4707 4707 4708 trace_ext4_zero_range(inode, offset, len, mode); ··· 4758 4757 return ret; 4759 4758 4760 4759 /* Zero out partial block at the edges of the range */ 4761 - ret = ext4_zero_partial_blocks(inode, offset, len); 4760 + ret = ext4_zero_partial_blocks(inode, offset, len, &partial_zeroed); 4762 4761 if (ret) 4763 4762 return ret; 4763 + if (((file->f_flags & O_SYNC) || IS_SYNC(inode)) && partial_zeroed) { 4764 + ret = filemap_write_and_wait_range(inode->i_mapping, offset, 4765 + end - 1); 4766 + if (ret) 4767 + return ret; 4768 + } 4764 4769 4765 4770 handle = ext4_journal_start(inode, EXT4_HT_MISC, 1); 4766 4771 if (IS_ERR(handle)) {
+14 -5
fs/ext4/inode.c
··· 4257 4257 return 0; 4258 4258 } 4259 4259 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) 4261 4262 { 4262 4263 struct super_block *sb = inode->i_sb; 4263 4264 unsigned partial_start, partial_end; ··· 4275 4274 /* Handle partial zero within the single block */ 4276 4275 if (start == end && 4277 4276 (partial_start || (partial_end != sb->s_blocksize - 1))) { 4278 - err = ext4_block_zero_range(inode, lstart, length, NULL, NULL); 4277 + err = ext4_block_zero_range(inode, lstart, length, did_zero, 4278 + NULL); 4279 4279 return err; 4280 4280 } 4281 4281 /* Handle partial zero out on the start of the range */ 4282 4282 if (partial_start) { 4283 4283 err = ext4_block_zero_range(inode, lstart, sb->s_blocksize, 4284 - NULL, NULL); 4284 + did_zero, NULL); 4285 4285 if (err) 4286 4286 return err; 4287 4287 } 4288 4288 /* Handle partial zero out on the end of the range */ 4289 4289 if (partial_end != sb->s_blocksize - 1) 4290 4290 err = ext4_block_zero_range(inode, byte_end - partial_end, 4291 - partial_end + 1, NULL, NULL); 4291 + partial_end + 1, did_zero, NULL); 4292 4292 return err; 4293 4293 } 4294 4294 ··· 4438 4436 loff_t end = offset + length; 4439 4437 handle_t *handle; 4440 4438 unsigned int credits; 4439 + bool partial_zeroed = false; 4441 4440 int ret; 4442 4441 4443 4442 trace_ext4_punch_hole(inode, offset, length, 0); ··· 4474 4471 if (ret) 4475 4472 return ret; 4476 4473 4477 - ret = ext4_zero_partial_blocks(inode, offset, length); 4474 + ret = ext4_zero_partial_blocks(inode, offset, length, &partial_zeroed); 4478 4475 if (ret) 4479 4476 return ret; 4477 + if (((file->f_flags & O_SYNC) || IS_SYNC(inode)) && partial_zeroed) { 4478 + ret = filemap_write_and_wait_range(inode->i_mapping, offset, 4479 + end - 1); 4480 + if (ret) 4481 + return ret; 4482 + } 4480 4483 4481 4484 if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) 4482 4485 credits = ext4_chunk_trans_extent(inode, 0);