[PATCH 5/7] f2fs: fix to truncate meta cache entry in F2FS_IOC_SEC_TRIM_FILE

From: Chao Yu

Date: Thu Oct 22 2026 - 08:56:31 EST


From: Chao Yu <chao@xxxxxxxxxx>

F2FS_IOC_SEC_TRIM_FILE discards and/or zeroes out data blocks of the
file in place via f2fs_secure_erase(), but it never truncates the meta
cache entry of the blocks, which may be cached by GC if the inode
requires meta inode GC, e.g. encrypted inode.

GC trusts an uptodate meta cache entry w/o reading the block from disk
again, so it can migrate data which was erased to a new block address,
then the erased data will be resurrected in the file.

- App (file F) - GC
- gc_data_segment() phase 3
- ra_data_block(F, j)
: cache F[j] in META[P]
- ioctl(F2FS_IOC_SEC_TRIM_FILE)
- f2fs_down_write(i_gc_rwsem[WRITE])
- gc_data_segment() phase 4
- f2fs_down_write_trylock(i_gc_rwsem[WRITE])
: fail, skip F[j]
- f2fs_secure_erase(P)
: P was erased, META[P] becomes stale
- f2fs_up_write(i_gc_rwsem[WRITE])
- gc_data_segment() phase 3
- ra_data_block(F, j)
: META[P] is uptodate, skip reading
- gc_data_segment() phase 4
- move_data_block(F, j)
: META[P] is uptodate, skip reading
- memcpy(tentry, sentry)
- f2fs_update_data_blkaddr(newaddr)
: F[j] was resurrected w/ erased data

In addition, GC may be writing back the block w/ meta cache, we need to
wait for the writeback before erasing the block.

Let's call f2fs_wait_on_block_writeback_range() for each block before
erasing it, which waits for writeback of the cache entry, and truncates
the cache entry.

Cc: stable@xxxxxxxxxx
Fixes: 9af846486d78 ("f2fs: add F2FS_IOC_SEC_TRIM_FILE ioctl")
Signed-off-by: Chao Yu <chao@xxxxxxxxxx>
---
fs/f2fs/file.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 27e295bdce1c..363039da3ab2 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -4661,6 +4661,13 @@ static int f2fs_sec_trim_file(struct file *filp, unsigned long arg)
goto out;
}

+ /*
+ * wait for GC's writeback and truncate the meta cache
+ * entry of the block, otherwise GC may migrate stale
+ * data in meta cache after the block was erased.
+ */
+ f2fs_wait_on_block_writeback_range(inode, blkaddr, 1);
+
cur_bdev = f2fs_target_device(sbi, blkaddr, NULL);
if (f2fs_is_multi_device(sbi)) {
int di = f2fs_target_device_index(sbi, blkaddr);
--
2.49.0