f2fs: add gc_urgent_high_remaining sysfs node
authorDaeho Jeong <daehojeong@google.com>
Thu, 9 Dec 2021 00:41:51 +0000 (16:41 -0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Fri, 10 Dec 2021 23:48:33 +0000 (15:48 -0800)
Added a new sysfs node called gc_urgent_high_remaining. The user can
set the trial count limit for GC urgent high mode with this value. If
GC thread gets to the limit, the mode will turn back to GC normal mode.
By default, the value is zero, which means there is no limit like before.

Signed-off-by: Daeho Jeong <daehojeong@google.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Documentation/ABI/testing/sysfs-fs-f2fs
fs/f2fs/f2fs.h
fs/f2fs/gc.c
fs/f2fs/super.c
fs/f2fs/sysfs.c

index 9f3c355bb70ec0b95907161a2e482d9f09e53bf7..2416b03ff283734d53e8e7bb22b62485a21983d2 100644 (file)
@@ -533,3 +533,10 @@ Description:       With "mode=fragment:block" mount options, we can scatter block allo
                f2fs will allocate 1..<max_fragment_chunk> blocks in a chunk and make a hole
                in the length of 1..<max_fragment_hole> by turns. This value can be set
                between 1..512 and the default value is 4.
+
+What:          /sys/fs/f2fs/<disk>/gc_urgent_high_remaining
+Date:          December 2021
+Contact:       "Daeho Jeong" <daehojeong@google.com>
+Description:   You can set the trial count limit for GC urgent high mode with this value.
+               If GC thread gets to the limit, the mode will turn back to GC normal mode.
+               By default, the value is zero, which means there is no limit like before.
index cbc73bd71dadf9b0748d66b95dc7ef14cae53054..5da5922867210ea14f94062681641999cb64649e 100644 (file)
@@ -1683,6 +1683,9 @@ struct f2fs_sb_info {
        unsigned int cur_victim_sec;            /* current victim section num */
        unsigned int gc_mode;                   /* current GC state */
        unsigned int next_victim_seg[2];        /* next segment in victim section */
+       spinlock_t gc_urgent_high_lock;
+       bool gc_urgent_high_limited;            /* indicates having limited trial count */
+       unsigned int gc_urgent_high_remaining;  /* remaining trial count for GC_URGENT_HIGH */
 
        /* for skip statistic */
        unsigned int atomic_files;              /* # of opened atomic file */
index b538cbcba351dc2ecb83c093a542795d740e18c3..7fbe46477a5acaca4de8d42e3a3b58bdf964f710 100644 (file)
@@ -92,6 +92,18 @@ static int gc_thread_func(void *data)
                 * So, I'd like to wait some time to collect dirty segments.
                 */
                if (sbi->gc_mode == GC_URGENT_HIGH) {
+                       spin_lock(&sbi->gc_urgent_high_lock);
+                       if (sbi->gc_urgent_high_limited) {
+                               if (!sbi->gc_urgent_high_remaining) {
+                                       sbi->gc_urgent_high_limited = false;
+                                       spin_unlock(&sbi->gc_urgent_high_lock);
+                                       sbi->gc_mode = GC_NORMAL;
+                                       continue;
+                               }
+                               sbi->gc_urgent_high_remaining--;
+                       }
+                       spin_unlock(&sbi->gc_urgent_high_lock);
+
                        wait_ms = gc_th->urgent_sleep_time;
                        down_write(&sbi->gc_lock);
                        goto do_gc;
index 040b6d02e1d8a412edb8ddf47138f5abdc288009..9acd76ea09ca8accc5bbd55290ebc5b22b43221d 100644 (file)
@@ -3548,6 +3548,7 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
        sbi->seq_file_ra_mul = MIN_RA_MUL;
        sbi->max_fragment_chunk = DEF_FRAGMENT_SIZE;
        sbi->max_fragment_hole = DEF_FRAGMENT_SIZE;
+       spin_lock_init(&sbi->gc_urgent_high_lock);
 
        sbi->dir_level = DEF_DIR_LEVEL;
        sbi->interval_time[CP_TIME] = DEF_CP_INTERVAL;
index 47c950f65b6fc46d971479dce60de8899e8f025c..55a7df17d5f3050647f947091c3b63d98223142a 100644 (file)
@@ -487,6 +487,15 @@ out:
                return count;
        }
 
+       if (!strcmp(a->attr.name, "gc_urgent_high_remaining")) {
+               spin_lock(&sbi->gc_urgent_high_lock);
+               sbi->gc_urgent_high_limited = t == 0 ? false : true;
+               sbi->gc_urgent_high_remaining = t;
+               spin_unlock(&sbi->gc_urgent_high_lock);
+
+               return count;
+       }
+
 #ifdef CONFIG_F2FS_IOSTAT
        if (!strcmp(a->attr.name, "iostat_enable")) {
                sbi->iostat_enable = !!t;
@@ -742,6 +751,7 @@ F2FS_RW_ATTR(FAULT_INFO_TYPE, f2fs_fault_info, inject_type, inject_type);
 #endif
 F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, data_io_flag, data_io_flag);
 F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, node_io_flag, node_io_flag);
+F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_urgent_high_remaining, gc_urgent_high_remaining);
 F2FS_RW_ATTR(CPRC_INFO, ckpt_req_control, ckpt_thread_ioprio, ckpt_thread_ioprio);
 F2FS_GENERAL_RO_ATTR(dirty_segments);
 F2FS_GENERAL_RO_ATTR(free_segments);
@@ -855,6 +865,7 @@ static struct attribute *f2fs_attrs[] = {
 #endif
        ATTR_LIST(data_io_flag),
        ATTR_LIST(node_io_flag),
+       ATTR_LIST(gc_urgent_high_remaining),
        ATTR_LIST(ckpt_thread_ioprio),
        ATTR_LIST(dirty_segments),
        ATTR_LIST(free_segments),