From: Zhang Yi <yi.zhang@xxxxxxxxxx> Introduce ext4_iomap_zero_range() to implement the zero_range iomap path. Currently, this function direct invokes iomap_zero_range() to zero out a mapped partial block during the truncate down, zeroing range and punching hole. Almost all operations are handled by iomap_zero_range(). One important aspect to consider is the truncate-down operation. Since we do not order the data, it is essential to write out zeroed data before the i_disksize update transaction is committed. Otherwise, stale data may left over in the last block, which could be exposed during the next expand truncate operation. Signed-off-by: Zhang Yi <yi.zhang@xxxxxxxxxx> --- fs/ext4/inode.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 34701afe61c2..50e4afd17e93 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -4147,6 +4147,13 @@ static int __ext4_block_zero_page_range(struct address_space *mapping, return err; } +static int ext4_iomap_zero_range(struct inode *inode, loff_t from, + loff_t length, bool *did_zero) +{ + return iomap_zero_range(inode, from, length, did_zero, + &ext4_iomap_buffered_write_ops); +} + /* * ext4_block_zero_page_range() zeros out a mapping of length 'length' * starting from file offset 'from'. The range to be zero'd must @@ -4173,6 +4180,8 @@ static int ext4_block_zero_page_range(struct address_space *mapping, if (IS_DAX(inode)) { return dax_zero_range(inode, from, length, NULL, &ext4_iomap_ops); + } else if (ext4_test_inode_state(inode, EXT4_STATE_BUFFERED_IOMAP)) { + return ext4_iomap_zero_range(inode, from, length, did_zero); } return __ext4_block_zero_page_range(mapping, from, length, did_zero); } @@ -4572,6 +4581,22 @@ int ext4_truncate(struct inode *inode) goto out_trace; ext4_block_truncate_page(mapping, inode->i_size, &zero_len); + /* + * inode with an iomap buffered I/O path does not order data, + * so it is necessary to write out zeroed data before the + * updating i_disksize transaction is committed. Otherwise, + * stale data may remain in the last block, which could be + * exposed during the next expand truncate operation. + */ + if (zero_len && ext4_test_inode_state(inode, + EXT4_STATE_BUFFERED_IOMAP)) { + loff_t zero_end = inode->i_size + zero_len; + + err = filemap_write_and_wait_range(mapping, + inode->i_size, zero_end - 1); + if (err) + goto out_trace; + } } if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) -- 2.46.1