From: Chao Yu <chao@kernel.org>
To: jaegeuk@kernel.org
Cc: linux-f2fs-devel@lists.sourceforge.net,
linux-kernel@vger.kernel.org, Chao Yu <chao@kernel.org>,
stable@kernel.org
Subject: [PATCH 6/7] f2fs: fix to serialize truncation of COW blocks w/ GC
Date: Thu, 22 Oct 2026 12:52:43 +0000 [thread overview]
Message-ID: <20261022125244.2205275-6-chao@kernel.org> (raw)
In-Reply-To: <20261022125244.2205275-1-chao@kernel.org>
From: Chao Yu <chao@kernel.org>
GC migrates blocks of COW inode w/ the COW inode and its i_gc_rwsem,
however f2fs_ioc_start_atomic_write() truncates blocks of the reused
COW inode w/o holding COW inode's i_gc_rwsem, it only holds the
original inode's locks, so the truncation can race w/ GC.
Case #1: GC caches stale data of a freed block in meta cache
- GC (phase 3, cow inode C) - ioctl(F2FS_IOC_START_ATOMIC_WRITE)
- f2fs_down_write_trylock(C's i_gc_rwsem[WRITE])
- ra_data_block(C, j)
- f2fs_grab_cache_folio(orig mapping, j)
- f2fs_get_dnode_of_data(C, j)
: get P
- f2fs_put_dnode()
- f2fs_is_valid_blkaddr(P)
- f2fs_folio_wait_writeback()
- f2fs_wait_on_block_writeback()
- f2fs_ioc_start_atomic_write()
- f2fs_down_write(orig's i_gc_rwsem)
- f2fs_do_truncate_blocks(C, 0, true)
- f2fs_truncate_data_blocks_range()
- f2fs_set_data_blkaddr(NULL_ADDR)
- f2fs_invalidate_blocks(P)
- f2fs_invalidate_internal_cache(P)
: nothing is cached
- f2fs_grab_cache(META, P)
: cache P in META[P]
- f2fs_submit_cache_read(P)
: SIT of P is still valid
- update_sit_entry(P, -1)
: P was freed
- end_io: f2fs_cache_set_uptodate(META[P])
: META[P] is stale for a freed block
On superblock w/o encrypt, verity and compression features, checkpoint
does not truncate meta cache, so META[P] survives after checkpoint, then:
- checkpoint, P can be reused
- writeback of victim's atomic write
- do_write_block()
: allocate P, write victim's data to P, META[P] is not invalidated
- GC phase 3: ra_data_block(victim's cow inode, k)
: META[P] is uptodate, skip reading
- GC phase 4: move_data_block(victim's cow inode, k)
: META[P] is uptodate, skip reading
- memcpy(tentry, sentry)
- f2fs_update_data_blkaddr(newaddr)
: victim's block was overwritten w/ stale data
Case #2: GC reports a false inconsistency error
- GC (phase 3, cow inode C) - ioctl(F2FS_IOC_START_ATOMIC_WRITE)
- ra_data_block(C, j)
- f2fs_get_dnode_of_data(C, j)
: get P
- f2fs_put_dnode()
- f2fs_do_truncate_blocks(C, 0, true)
- f2fs_invalidate_blocks(P)
- update_sit_entry(P, -1)
- f2fs_is_valid_blkaddr(P, DATA_GENERIC_ENHANCE)
: or in f2fs_submit_cache_read()
- __is_bitmap_valid()
- f2fs_err("Inconsistent error blkaddr:...")
- set_sbi_flag(SBI_NEED_FSCK)
- dump_stack()
- f2fs_handle_error(ERROR_INVALID_BLKADDR)
All other truncation paths hold i_gc_rwsem[WRITE] of the truncated
inode, let's hold COW inode's i_gc_rwsem[WRITE] during truncation of
COW blocks as well, then GC will skip COW blocks due to failure of
f2fs_down_write_trylock().
Cc: stable@kernel.org
Fixes: f18d00769336 ("f2fs: use meta inode for GC of COW file")
Signed-off-by: Chao Yu <chao@kernel.org>
---
fs/f2fs/file.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 363039da3ab2..3a7093a7c12e 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -2445,11 +2445,20 @@ static int f2fs_ioc_start_atomic_write(struct file *filp, bool truncate)
F2FS_I(fi->cow_inode)->atomic_inode = inode;
} else {
/* Reuse the already created COW inode */
+ struct f2fs_inode_info *cfi = F2FS_I(fi->cow_inode);
+
f2fs_bug_on(sbi, get_dirty_pages(fi->cow_inode));
invalidate_mapping_pages(fi->cow_inode->i_mapping, 0, -1);
+ /*
+ * GC migrates COW blocks w/ cow inode and its i_gc_rwsem, so
+ * hold it to serialize truncation of COW blocks w/ GC.
+ */
+ f2fs_down_write_nested(&cfi->i_gc_rwsem[WRITE],
+ SINGLE_DEPTH_NESTING);
ret = f2fs_do_truncate_blocks(fi->cow_inode, 0, true);
+ f2fs_up_write(&cfi->i_gc_rwsem[WRITE]);
if (ret)
goto out_unlock;
}
--
2.49.0
next prev parent reply other threads:[~2026-10-22 12:53 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-22 12:52 [PATCH 1/7] f2fs: fix to persist i_size extended inside last block for fsync Chao Yu
2026-10-22 12:52 ` [PATCH 2/7] f2fs: fix to return -EIO from f2fs_sync_fs() if cp_error is set Chao Yu
2026-10-22 12:52 ` [PATCH 3/7] f2fs: fix to return -EIO from f2fs_write_checkpoint() once " Chao Yu
2026-10-22 12:52 ` [PATCH 4/7] f2fs: fix to truncate stale meta cache entry on in-place update Chao Yu
2026-10-22 12:52 ` [PATCH 5/7] f2fs: fix to truncate meta cache entry in F2FS_IOC_SEC_TRIM_FILE Chao Yu
2026-10-22 12:52 ` Chao Yu [this message]
2026-10-22 12:52 ` [PATCH 7/7] f2fs: cache: fix to initialize f2fs_writeback info at mount time Chao Yu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261022125244.2205275-6-chao@kernel.org \
--to=chao@kernel.org \
--cc=jaegeuk@kernel.org \
--cc=linux-f2fs-devel@lists.sourceforge.net \
--cc=linux-kernel@vger.kernel.org \
--cc=stable@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®