FAILED: patch "[PATCH] f2fs: read i_size once in f2fs_vm_page_mkwrite" failed to apply to 6.1-stable tree
Subsystems (2)
Sasha Levin
maintainerThe patch below does not apply to the 6.1-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.1.y
git checkout FETCH_HEAD
git cherry-pick -x c04f209773ecb31e592cababce0d6658ee0b8d58
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '[email protected]' --subject-prefix 'PATCH 6.1.y' 'HEAD^..'
Thanks,
Sasha
------------------ original commit in Linus's tree ------------------
From c04f209773ecb31e592cababce0d6658ee0b8d58 Mon Sep 17 00:00:00 2001
From: Nanzhe Zhao <[email protected]>
Date: Tue, 13 Oct 2026 18:56:28 +0800
Subject: [PATCH] f2fs: read i_size once in f2fs_vm_page_mkwrite
f2fs_vm_page_mkwrite() reads i_size twice: once to check whether the folio is partially beyond EOF, and once to calculate the offset for folio_zero_segment(). But a concurrent buffered write can extend isize and cause the following race condition to corrupt data:
buffered write writes [0,3500)
CPU0 (write fault) CPU1 (buffered write)
---- ----
f2fs_vm_page_mkwrite()
folio_lock(folio)
if (((loff_t)(folio->index + 1) << PAGE_SHIFT) >
i_size_read(inode))
/* i_size_read() = 3500 */
write(fd, buf, 200, 4096)
/* writes into page1, does not
wait for folio lock */
i_size_write(inode, 4296) offset = i_size_read(inode) & ~PAGE_MASK
/* i_size_read() = 4296, offset = 200 */ folio_zero_segment(folio, offset, folio_size(folio)) /* valid data [200, 3500) is zeroed */
Fix this by reading i_size once and using the same value for both the EOF check and the zeroing offset.
--- fs/f2fs/file.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
fs/f2fs/file.c +10 -4
@@ -125,6 +125,7 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf)struct f2fs_sb_info *sbi =F2FS_I_SB (inode);struct dnode_of_data dn;bool need_alloc = !f2fs_is_pinned_file (inode); +loff_t isize;int err =0 ;vm_fault_t ret;
@@ -188,8 +189,14 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf)filemap_invalidate_lock_shared (inode->i_mapping);folio_lock (folio); +/* +* A concurrent buffered write can extend isize, so we store isize in a +* local variable to let the zeroing offset match the EOF check below. +*/ + isize =i_size_read (inode); +if (unlikely (folio->mapping != inode->i_mapping || -folio_pos (folio) >i_size_read (inode) || +folio_pos (folio) > isize || !folio_test_uptodate (folio))) {folio_unlock (folio); err = -EFAULT ;
@@ -219,11 +226,10 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf)f2fs_wait_on_block_writeback (inode, dn.data_blkaddr);/* page is wholly or partially inside EOF */ -if (((loff_t)(folio->index +1 ) <<PAGE_SHIFT ) > -i_size_read (inode)) { +if (((loff_t)(folio->index +1 ) <<PAGE_SHIFT ) > isize) {loff_t offset; - offset =i_size_read (inode) & ~PAGE_MASK ; + offset = isize & ~PAGE_MASK ;folio_zero_segment (folio, offset,folio_size (folio)); }folio_mark_dirty (folio);
Signature · 1 line
2.53.0