]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
f2fs: block cache/dio write during f2fs_enable_checkpoint()
authorChao Yu <chao@kernel.org>
Mon, 27 Oct 2025 06:35:34 +0000 (14:35 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Thu, 4 Dec 2025 02:00:02 +0000 (02:00 +0000)
If there are too many background IOs during f2fs_enable_checkpoint(),
sync_inodes_sb() may be blocked for long time due to it will loop to
write dirty datas which are generated by in parallel write()
continuously.

Let's change as below to resolve this issue:
- hold cp_enable_rwsem write lock to block any cache/dio write
- decrease DEF_ENABLE_INTERVAL from 16 to 5

In addition, dump more logs during f2fs_enable_checkpoint().

Testcase:
1. fill data into filesystem until 90% usage.
2. mount -o remount,checkpoint=disable:10% /data
3. fio --rw=randwrite  --bs=4kb  --size=1GB  --numjobs=10  \
--iodepth=64  --ioengine=psync  --time_based  --runtime=600 \
--directory=/data/fio_dir/ &
4. mount -o remount,checkpoint=enable /data

Before:
F2FS-fs (dm-51): f2fs_enable_checkpoint() finishes, writeback:7232, sync:39793, cp:457

After:
F2FS-fs (dm-51): f2fs_enable_checkpoint end, writeback:5032, lock:0, sync_inode:5552, sync_fs:84

Signed-off-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/data.c
fs/f2fs/f2fs.h
fs/f2fs/super.c

index ee519de1aa1a4266192729453568588663ddba3d..7be0837a9456612514af04d59c2296125e2ea96b 100644 (file)
@@ -1418,6 +1418,7 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type)
 
 static void f2fs_map_lock(struct f2fs_sb_info *sbi, int flag)
 {
+       f2fs_down_read(&sbi->cp_enable_rwsem);
        if (flag == F2FS_GET_BLOCK_PRE_AIO)
                f2fs_down_read(&sbi->node_change);
        else
@@ -1430,6 +1431,7 @@ static void f2fs_map_unlock(struct f2fs_sb_info *sbi, int flag)
                f2fs_up_read(&sbi->node_change);
        else
                f2fs_unlock_op(sbi);
+       f2fs_up_read(&sbi->cp_enable_rwsem);
 }
 
 int f2fs_get_block_locked(struct dnode_of_data *dn, pgoff_t index)
index d4f5648477de6a862b80ad0b6a6c49c928147b66..0e2c5e86a6a16b465d5056cfc62a20e4c703f449 100644 (file)
@@ -281,7 +281,7 @@ enum {
 #define DEF_CP_INTERVAL                        60      /* 60 secs */
 #define DEF_IDLE_INTERVAL              5       /* 5 secs */
 #define DEF_DISABLE_INTERVAL           5       /* 5 secs */
-#define DEF_ENABLE_INTERVAL            16      /* 16 secs */
+#define DEF_ENABLE_INTERVAL            5       /* 5 secs */
 #define DEF_DISABLE_QUICK_INTERVAL     1       /* 1 secs */
 #define DEF_UMOUNT_DISCARD_TIMEOUT     5       /* 5 secs */
 
@@ -1695,6 +1695,7 @@ struct f2fs_sb_info {
        long interval_time[MAX_TIME];           /* to store thresholds */
        struct ckpt_req_control cprc_info;      /* for checkpoint request control */
        struct cp_stats cp_stats;               /* for time stat of checkpoint */
+       struct f2fs_rwsem cp_enable_rwsem;      /* block cache/dio write */
 
        struct inode_management im[MAX_INO_ENTRY];      /* manage inode cache */
 
index 60382c9b5293d043e7e676d26e7cb0a8c6571fb7..bdb5ddb4f9662e885d4d2b94fa9f1958be3c0e77 100644 (file)
@@ -2635,10 +2635,11 @@ restore_flag:
 static int f2fs_enable_checkpoint(struct f2fs_sb_info *sbi)
 {
        unsigned int nr_pages = get_pages(sbi, F2FS_DIRTY_DATA) / 16;
-       long long start, writeback, end;
+       long long start, writeback, lock, sync_inode, end;
        int ret;
 
-       f2fs_info(sbi, "f2fs_enable_checkpoint() starts, meta: %lld, node: %lld, data: %lld",
+       f2fs_info(sbi, "%s start, meta: %lld, node: %lld, data: %lld",
+                                       __func__,
                                        get_pages(sbi, F2FS_DIRTY_META),
                                        get_pages(sbi, F2FS_DIRTY_NODES),
                                        get_pages(sbi, F2FS_DIRTY_DATA));
@@ -2657,11 +2658,18 @@ static int f2fs_enable_checkpoint(struct f2fs_sb_info *sbi)
        }
        writeback = ktime_get();
 
-       sync_inodes_sb(sbi->sb);
+       f2fs_down_write(&sbi->cp_enable_rwsem);
+
+       lock = ktime_get();
+
+       if (get_pages(sbi, F2FS_DIRTY_DATA))
+               sync_inodes_sb(sbi->sb);
 
        if (unlikely(get_pages(sbi, F2FS_DIRTY_DATA)))
-               f2fs_warn(sbi, "checkpoint=enable has some unwritten data: %lld",
-                                       get_pages(sbi, F2FS_DIRTY_DATA));
+               f2fs_warn(sbi, "%s: has some unwritten data: %lld",
+                       __func__, get_pages(sbi, F2FS_DIRTY_DATA));
+
+       sync_inode = ktime_get();
 
        f2fs_down_write(&sbi->gc_lock);
        f2fs_dirty_to_prefree(sbi);
@@ -2670,6 +2678,13 @@ static int f2fs_enable_checkpoint(struct f2fs_sb_info *sbi)
        set_sbi_flag(sbi, SBI_IS_DIRTY);
        f2fs_up_write(&sbi->gc_lock);
 
+       f2fs_info(sbi, "%s sync_fs, meta: %lld, imeta: %lld, node: %lld, dents: %lld, qdata: %lld",
+                                       __func__,
+                                       get_pages(sbi, F2FS_DIRTY_META),
+                                       get_pages(sbi, F2FS_DIRTY_IMETA),
+                                       get_pages(sbi, F2FS_DIRTY_NODES),
+                                       get_pages(sbi, F2FS_DIRTY_DENTS),
+                                       get_pages(sbi, F2FS_DIRTY_QDATA));
        ret = f2fs_sync_fs(sbi->sb, 1);
        if (ret)
                f2fs_err(sbi, "%s sync_fs failed, ret: %d", __func__, ret);
@@ -2677,11 +2692,17 @@ static int f2fs_enable_checkpoint(struct f2fs_sb_info *sbi)
        /* Let's ensure there's no pending checkpoint anymore */
        f2fs_flush_ckpt_thread(sbi);
 
+       f2fs_up_write(&sbi->cp_enable_rwsem);
+
        end = ktime_get();
 
-       f2fs_info(sbi, "f2fs_enable_checkpoint() finishes, writeback:%llu, sync:%llu",
-                                       ktime_ms_delta(writeback, start),
-                                       ktime_ms_delta(end, writeback));
+       f2fs_info(sbi, "%s end, writeback:%llu, "
+                               "lock:%llu, sync_inode:%llu, sync_fs:%llu",
+                               __func__,
+                               ktime_ms_delta(writeback, start),
+                               ktime_ms_delta(lock, writeback),
+                               ktime_ms_delta(sync_inode, lock),
+                               ktime_ms_delta(end, sync_inode));
        return ret;
 }
 
@@ -4870,6 +4891,7 @@ try_onemore:
        init_f2fs_rwsem(&sbi->node_change);
        spin_lock_init(&sbi->stat_lock);
        init_f2fs_rwsem(&sbi->cp_rwsem);
+       init_f2fs_rwsem(&sbi->cp_enable_rwsem);
        init_f2fs_rwsem(&sbi->quota_sem);
        init_waitqueue_head(&sbi->cp_wait);
        spin_lock_init(&sbi->error_lock);