]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
f2fs: fix to trigger foreground gc during f2fs_map_blocks() in lfs mode
authorChao Yu <chao@kernel.org>
Thu, 24 Jul 2025 08:01:44 +0000 (16:01 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Mon, 28 Jul 2025 16:36:54 +0000 (16:36 +0000)
w/ "mode=lfs" mount option, generic/299 will cause system panic as below:

------------[ cut here ]------------
kernel BUG at fs/f2fs/segment.c:2835!
Call Trace:
 <TASK>
 f2fs_allocate_data_block+0x6f4/0xc50
 f2fs_map_blocks+0x970/0x1550
 f2fs_iomap_begin+0xb2/0x1e0
 iomap_iter+0x1d6/0x430
 __iomap_dio_rw+0x208/0x9a0
 f2fs_file_write_iter+0x6b3/0xfa0
 aio_write+0x15d/0x2e0
 io_submit_one+0x55e/0xab0
 __x64_sys_io_submit+0xa5/0x230
 do_syscall_64+0x84/0x2f0
 entry_SYSCALL_64_after_hwframe+0x76/0x7e
RIP: 0010:new_curseg+0x70f/0x720

The root cause of we run out-of-space is: in f2fs_map_blocks(), f2fs may
trigger foreground gc only if it allocates any physical block, it will be
a little bit later when there is multiple threads writing data w/
aio/dio/bufio method in parallel, since we always use OPU in lfs mode, so
f2fs_map_blocks() does block allocations aggressively.

In order to fix this issue, let's give a chance to trigger foreground
gc in prior to block allocation in f2fs_map_blocks().

Fixes: 36abef4e796d ("f2fs: introduce mode=lfs mount option")
Cc: Daeho Jeong <daehojeong@google.com>
Signed-off-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/data.c

index e11dd1431e5b537d02ba5ae500d506638dc2a32d..083d66b8ba0784fa9b89f4be08a6e02c31a55e1b 100644 (file)
@@ -1573,8 +1573,11 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, int flag)
        end = pgofs + maxblocks;
 
 next_dnode:
-       if (map->m_may_create)
+       if (map->m_may_create) {
+               if (f2fs_lfs_mode(sbi))
+                       f2fs_balance_fs(sbi, true);
                f2fs_map_lock(sbi, flag);
+       }
 
        /* When reading holes, we need its node page */
        set_new_dnode(&dn, inode, NULL, NULL, 0);