Re: [PATCH v3 2/9] ext4: skip tail block zeroing for inline data files

From: Zhang Yi

Date: Mon Jul 13 2026 - 02:38:10 EST




On 7/9/2026 9:25 PM, Jan Kara wrote:
On Wed 08-07-26 14:20:42, Zhang Yi wrote:
From: Zhang Yi <yi.zhang@xxxxxxxxxx>

ext4_block_zero_eof() is called from ext4_write_checks() on every
append write beyond EOF. For inline data files, ext4_get_block()
returns -ERANGE when ext4_load_tail_bh() looks up the tail block.
However, this error is currently ignored because the return value
of ext4_get_block() in ext4_load_tail_bh() is discarded.

Before we fix ext4_load_tail_bh() to properly propagate the error,
skip the zeroing for inline data inodes to avoid unnecessary
failures or confusion.

Fixes: 3f60efd65412d ("ext4: zero post-EOF partial block before appending write")
Signed-off-by: Zhang Yi <yi.zhang@xxxxxxxxxx>

Hum, but this check is racy (inline data can be removed from
ext4_page_mkwrite() after this check) so we could in theory miss some
zeroing we should do. I didn't put too deep thought to whether it really
can do some harm or not but it would at least deserve a comment.

Honza

You're right, the race does exist. Thank you for pointing this out. Let
me analyze the scenario precisely.

ext4_block_zero_eof() is invoked during a file-extending operation (when
buffered write with start_pos > old_size) to zero out the contents of
the old post-EOF block. This zeroing is intended to prevent stale page-
cache or on-disk data from being exposed.

Now consider a race between a file-extending operation and a concurrent
mmap write. In the mmap path, ext4_page_mkwrite() first converts inline
data via ext4_convert_inline_data_nolock(). During that conversion, the
entire block is zeroed with memset() before the inline data is copied
in. As a result, by the time the conversion completes, any stale post-
EOF data that ext4_block_zero_eof() would normally guard against has
already been cleared.

The only remaining concern is a scenario where an mmap write touches the
old post-EOF block after the conversion but before the file is expanded.
However, that would constitute undefined behavior regardless of whether
inline data is involved.

So from a practical standpoint, I do not see a real issue here. I will
add a comment in the next revision to clarify this reasoning.

Thanks,
Yi.


---
fs/ext4/inode.c | 3 +++
1 file changed, 3 insertions(+)

diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 7b2face041ef..a3f7c71b701d 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -4218,6 +4218,9 @@ int ext4_block_zero_eof(struct inode *inode, loff_t from, loff_t end)
offset = from & (blocksize - 1);
if (!offset || from >= end)
return 0;
+ /* Inline data has no tail block to zero. */
+ if (ext4_has_inline_data(inode))
+ return 0;
/* If we are processing an encrypted inode during orphan list handling */
if (IS_ENCRYPTED(inode) && !fscrypt_has_encryption_key(inode))
return 0;
--
2.52.0