From b70ab407503706289163dd59f1ac3e942bacc37d Mon Sep 17 00:00:00 2001 From: Chi Zhiling Date: Sun, 4 Oct 2026 18:19:30 +0800 Subject: [PATCH] exfat: advance valid_size to EOF for append writes For an append write, the write position is recalculated by generic_write_checks(). Therefore, the write position must be obtained after generic_write_checks() returns. Using the original write position to advance valid_size may cause the valid_size update to be skipped, potentially exposing stale data. Also move the truncate_pagecache() check below the recalculated position, so that pos is never read before it is assigned. Fixes: 11a347fb6cef ("exfat: change to get file size from DataLength") Cc: stable@vger.kernel.org Signed-off-by: Chi Zhiling Signed-off-by: Namjae Jeon --- fs/exfat/file.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/fs/exfat/file.c b/fs/exfat/file.c index 3867e78c2312..87afb6bffd35 100644 --- a/fs/exfat/file.c +++ b/fs/exfat/file.c @@ -854,8 +854,7 @@ static ssize_t exfat_file_write_iter(struct kiocb *iocb, struct iov_iter *iter) struct file *file = iocb->ki_filp; struct inode *inode = file_inode(file); struct exfat_inode_info *ei = EXFAT_I(inode); - loff_t pos = iocb->ki_pos; - loff_t valid_size; + loff_t pos, valid_size; int err; if (unlikely(exfat_forced_shutdown(inode->i_sb))) @@ -863,11 +862,6 @@ static ssize_t exfat_file_write_iter(struct kiocb *iocb, struct iov_iter *iter) inode_lock(inode); - if (pos > i_size_read(inode)) - truncate_pagecache(inode, i_size_read(inode)); - - valid_size = ei->valid_size; - ret = generic_write_checks(iocb, iter); if (ret <= 0) goto unlock; @@ -878,6 +872,11 @@ static ssize_t exfat_file_write_iter(struct kiocb *iocb, struct iov_iter *iter) goto unlock; } + pos = iocb->ki_pos; + if (pos > i_size_read(inode)) + truncate_pagecache(inode, i_size_read(inode)); + + valid_size = ei->valid_size; if (pos > valid_size) { ret = exfat_extend_valid_size(inode, pos); if (ret < 0 && ret != -ENOSPC) { @@ -887,6 +886,8 @@ static ssize_t exfat_file_write_iter(struct kiocb *iocb, struct iov_iter *iter) } if (ret < 0) goto unlock; + + pos = valid_size; } if (iocb->ki_flags & IOCB_DIRECT) @@ -899,9 +900,6 @@ static ssize_t exfat_file_write_iter(struct kiocb *iocb, struct iov_iter *iter) inode_unlock(inode); - if (pos > valid_size) - pos = valid_size; - if (iocb->ki_pos > pos) { ssize_t err = generic_write_sync(iocb, iocb->ki_pos - pos);