[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260203062523.3869120-9-yi.zhang@huawei.com>
Date: Tue, 3 Feb 2026 14:25:08 +0800
From: Zhang Yi <yi.zhang@...wei.com>
To: linux-ext4@...r.kernel.org
Cc: linux-fsdevel@...r.kernel.org,
linux-kernel@...r.kernel.org,
tytso@....edu,
adilger.kernel@...ger.ca,
jack@...e.cz,
ojaswin@...ux.ibm.com,
ritesh.list@...il.com,
hch@...radead.org,
djwong@...nel.org,
yi.zhang@...wei.com,
yi.zhang@...weicloud.com,
yizhang089@...il.com,
libaokun1@...wei.com,
yangerkun@...wei.com,
yukuai@...as.com
Subject: [PATCH -next v2 08/22] ext4: zero post EOF partial block before appending write
In cases of appending write beyond the end of file (EOF),
ext4_zero_partial_blocks() is called within ext4_*_write_end() to zero
out the partial block beyond the EOF. This prevents exposing stale data
that might be written through mmap. However, supporting only the regular
buffered write path is insufficient. It is also necessary to support the
DAX path as well as the upcoming iomap buffered write path. Therefore,
move this operation to ext4_write_checks(). In addition, the zero length
is limited within the EOF block to prevent ext4_zero_partial_blocks()
from attempting to zero out the extra end block (although it would not
do anything anyway).
Signed-off-by: Zhang Yi <yi.zhang@...wei.com>
---
fs/ext4/file.c | 20 ++++++++++++++++++++
fs/ext4/inode.c | 21 +++++++--------------
2 files changed, 27 insertions(+), 14 deletions(-)
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 4320ebff74f3..3ecc09f286e4 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -271,6 +271,9 @@ static ssize_t ext4_generic_write_checks(struct kiocb *iocb,
static ssize_t ext4_write_checks(struct kiocb *iocb, struct iov_iter *from)
{
+ struct inode *inode = file_inode(iocb->ki_filp);
+ unsigned int blocksize = i_blocksize(inode);
+ loff_t old_size = i_size_read(inode);
ssize_t ret, count;
count = ext4_generic_write_checks(iocb, from);
@@ -280,6 +283,23 @@ static ssize_t ext4_write_checks(struct kiocb *iocb, struct iov_iter *from)
ret = file_modified(iocb->ki_filp);
if (ret)
return ret;
+
+ /*
+ * If the position is beyond the EOF, it is necessary to zero out the
+ * partial block that beyond the existing EOF, as it may contains
+ * stale data written through mmap.
+ */
+ if (iocb->ki_pos > old_size && (old_size & (blocksize - 1))) {
+ loff_t end = round_up(old_size, blocksize);
+
+ if (iocb->ki_pos < end)
+ end = iocb->ki_pos;
+
+ ret = ext4_zero_partial_blocks(inode, old_size, end - old_size);
+ if (ret)
+ return ret;
+ }
+
return count;
}
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 9c0e70256527..1ac93c39d21e 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -1456,10 +1456,9 @@ static int ext4_write_end(const struct kiocb *iocb,
folio_unlock(folio);
folio_put(folio);
- if (old_size < pos && !verity) {
+ if (old_size < pos && !verity)
pagecache_isize_extended(inode, old_size, pos);
- ext4_zero_partial_blocks(inode, old_size, pos - old_size);
- }
+
/*
* Don't mark the inode dirty under folio lock. First, it unnecessarily
* makes the holding time of folio lock longer. Second, it forces lock
@@ -1574,10 +1573,8 @@ static int ext4_journalled_write_end(const struct kiocb *iocb,
folio_unlock(folio);
folio_put(folio);
- if (old_size < pos && !verity) {
+ if (old_size < pos && !verity)
pagecache_isize_extended(inode, old_size, pos);
- ext4_zero_partial_blocks(inode, old_size, pos - old_size);
- }
if (size_changed) {
ret2 = ext4_mark_inode_dirty(handle, inode);
@@ -3196,7 +3193,7 @@ static int ext4_da_do_write_end(struct address_space *mapping,
struct inode *inode = mapping->host;
loff_t old_size = inode->i_size;
bool disksize_changed = false;
- loff_t new_i_size, zero_len = 0;
+ loff_t new_i_size;
handle_t *handle;
if (unlikely(!folio_buffers(folio))) {
@@ -3240,19 +3237,15 @@ static int ext4_da_do_write_end(struct address_space *mapping,
folio_unlock(folio);
folio_put(folio);
- if (pos > old_size) {
+ if (pos > old_size)
pagecache_isize_extended(inode, old_size, pos);
- zero_len = pos - old_size;
- }
- if (!disksize_changed && !zero_len)
+ if (!disksize_changed)
return copied;
- handle = ext4_journal_start(inode, EXT4_HT_INODE, 2);
+ handle = ext4_journal_start(inode, EXT4_HT_INODE, 1);
if (IS_ERR(handle))
return PTR_ERR(handle);
- if (zero_len)
- ext4_zero_partial_blocks(inode, old_size, zero_len);
ext4_mark_inode_dirty(handle, inode);
ext4_journal_stop(handle);
--
2.52.0
Powered by blists - more mailing lists