f2fs: introduce gc_urgent mode for background GC
authorJaegeuk Kim <jaegeuk@kernel.org>
Mon, 7 Aug 2017 05:09:00 +0000 (22:09 -0700)
committerJaegeuk Kim <jaegeuk@kernel.org>
Tue, 15 Aug 2017 17:40:12 +0000 (10:40 -0700)
This patch adds a sysfs entry to control urgent mode for background GC.
If this is set, background GC thread conducts GC with gc_urgent_sleep_time
all the time.

Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Documentation/ABI/testing/sysfs-fs-f2fs
Documentation/filesystems/f2fs.txt
fs/f2fs/gc.c
fs/f2fs/gc.h
fs/f2fs/sysfs.c

index 84c606fb3ca4dff45bbd59af27de49d6d86884ca..621da3fc56c55fe7b9c8014d4798b24a983bb91d 100644 (file)
@@ -130,3 +130,15 @@ Date:              June 2017
 Contact:       "Chao Yu" <yuchao0@huawei.com>
 Description:
                 Controls current reserved blocks in system.
+
+What:          /sys/fs/f2fs/<disk>/gc_urgent
+Date:          August 2017
+Contact:       "Jaegeuk Kim" <jaegeuk@kernel.org>
+Description:
+                Do background GC agressively
+
+What:          /sys/fs/f2fs/<disk>/gc_urgent_sleep_time
+Date:          August 2017
+Contact:       "Jaegeuk Kim" <jaegeuk@kernel.org>
+Description:
+                Controls sleep time of GC urgent mode
index b8f495a8b67dd7c7fd27ab5fdba030a113cbb88a..84f36896766cd9ccde5b7d00acc1a2fa8389b9ba 100644 (file)
@@ -210,6 +210,15 @@ Files in /sys/fs/f2fs/<devname>
                               gc_idle = 1 will select the Cost Benefit approach
                               & setting gc_idle = 2 will select the greedy approach.
 
+ gc_urgent                    This parameter controls triggering background GCs
+                              urgently or not. Setting gc_urgent = 0 [default]
+                              makes back to default behavior, while if it is set
+                              to 1, background thread starts to do GC by given
+                              gc_urgent_sleep_time interval.
+
+ gc_urgent_sleep_time         This parameter controls sleep time for gc_urgent.
+                              500 ms is set by default. See above gc_urgent.
+
  reclaim_segments             This parameter controls the number of prefree
                               segments to be reclaimed. If the number of prefree
                              segments is larger than the number of segments
index 620dca443b297bffdf0e09ff81c2cdf4734b0057..8da7c14a9d29d7fc35f95a77533e243624e87ac8 100644 (file)
@@ -35,9 +35,14 @@ static int gc_thread_func(void *data)
        set_freezable();
        do {
                wait_event_interruptible_timeout(*wq,
-                               kthread_should_stop() || freezing(current),
+                               kthread_should_stop() || freezing(current) ||
+                               gc_th->gc_wake,
                                msecs_to_jiffies(wait_ms));
 
+               /* give it a try one time */
+               if (gc_th->gc_wake)
+                       gc_th->gc_wake = 0;
+
                if (try_to_freeze())
                        continue;
                if (kthread_should_stop())
@@ -74,6 +79,11 @@ static int gc_thread_func(void *data)
                if (!mutex_trylock(&sbi->gc_mutex))
                        goto next;
 
+               if (gc_th->gc_urgent) {
+                       wait_ms = gc_th->urgent_sleep_time;
+                       goto do_gc;
+               }
+
                if (!is_idle(sbi)) {
                        increase_sleep_time(gc_th, &wait_ms);
                        mutex_unlock(&sbi->gc_mutex);
@@ -84,7 +94,7 @@ static int gc_thread_func(void *data)
                        decrease_sleep_time(gc_th, &wait_ms);
                else
                        increase_sleep_time(gc_th, &wait_ms);
-
+do_gc:
                stat_inc_bggc_count(sbi);
 
                /* if return value is not zero, no victim was selected */
@@ -115,11 +125,14 @@ int start_gc_thread(struct f2fs_sb_info *sbi)
                goto out;
        }
 
+       gc_th->urgent_sleep_time = DEF_GC_THREAD_URGENT_SLEEP_TIME;
        gc_th->min_sleep_time = DEF_GC_THREAD_MIN_SLEEP_TIME;
        gc_th->max_sleep_time = DEF_GC_THREAD_MAX_SLEEP_TIME;
        gc_th->no_gc_sleep_time = DEF_GC_THREAD_NOGC_SLEEP_TIME;
 
        gc_th->gc_idle = 0;
+       gc_th->gc_urgent = 0;
+       gc_th->gc_wake= 0;
 
        sbi->gc_thread = gc_th;
        init_waitqueue_head(&sbi->gc_thread->gc_wait_queue_head);
index a993967dcdb979160ec5bced54fa7df565bf1e65..57a9000ce3af62233d68b15c8db33ddaa168e18e 100644 (file)
@@ -13,6 +13,7 @@
                                                 * whether IO subsystem is idle
                                                 * or not
                                                 */
+#define DEF_GC_THREAD_URGENT_SLEEP_TIME        500     /* 500 ms */
 #define DEF_GC_THREAD_MIN_SLEEP_TIME   30000   /* milliseconds */
 #define DEF_GC_THREAD_MAX_SLEEP_TIME   60000
 #define DEF_GC_THREAD_NOGC_SLEEP_TIME  300000  /* wait 5 min */
@@ -27,12 +28,15 @@ struct f2fs_gc_kthread {
        wait_queue_head_t gc_wait_queue_head;
 
        /* for gc sleep time */
+       unsigned int urgent_sleep_time;
        unsigned int min_sleep_time;
        unsigned int max_sleep_time;
        unsigned int no_gc_sleep_time;
 
        /* for changing gc mode */
        unsigned int gc_idle;
+       unsigned int gc_urgent;
+       unsigned int gc_wake;
 };
 
 struct gc_inode_list {
index 3d6bbdb743b0d8d135bbdc9b78d405b136e9c803..c40e5d24df9f768e143179b6f383270a7c46e268 100644 (file)
@@ -156,6 +156,10 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
 
        if (!strcmp(a->attr.name, "iostat_enable") && *ui == 0)
                f2fs_reset_iostat(sbi);
+       if (!strcmp(a->attr.name, "gc_urgent") && t == 1 && sbi->gc_thread) {
+               sbi->gc_thread->gc_wake = 1;
+               wake_up_interruptible_all(&sbi->gc_thread->gc_wait_queue_head);
+       }
 
        return count;
 }
@@ -235,10 +239,13 @@ static struct f2fs_attr f2fs_attr_##_name = {                     \
        .id     = _id,                                          \
 }
 
+F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_urgent_sleep_time,
+                                                       urgent_sleep_time);
 F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_min_sleep_time, min_sleep_time);
 F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_max_sleep_time, max_sleep_time);
 F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_no_gc_sleep_time, no_gc_sleep_time);
 F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_idle, gc_idle);
+F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_urgent, gc_urgent);
 F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, reclaim_segments, rec_prefree_segments);
 F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, max_small_discards, max_discards);
 F2FS_RW_ATTR(RESERVED_BLOCKS, f2fs_sb_info, reserved_blocks, reserved_blocks);
@@ -275,10 +282,12 @@ F2FS_FEATURE_RO_ATTR(inode_checksum, FEAT_INODE_CHECKSUM);
 
 #define ATTR_LIST(name) (&f2fs_attr_##name.attr)
 static struct attribute *f2fs_attrs[] = {
+       ATTR_LIST(gc_urgent_sleep_time),
        ATTR_LIST(gc_min_sleep_time),
        ATTR_LIST(gc_max_sleep_time),
        ATTR_LIST(gc_no_gc_sleep_time),
        ATTR_LIST(gc_idle),
+       ATTR_LIST(gc_urgent),
        ATTR_LIST(reclaim_segments),
        ATTR_LIST(max_small_discards),
        ATTR_LIST(batched_trim_sections),