Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d9872a69 authored by Jaegeuk Kim's avatar Jaegeuk Kim
Browse files

f2fs: introduce gc_urgent mode for background GC



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: default avatarChao Yu <yuchao0@huawei.com>
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent 3537581a
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -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
+9 −0
Original line number Diff line number Diff line
@@ -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
+15 −2
Original line number Diff line number Diff line
@@ -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);
+4 −0
Original line number Diff line number Diff line
@@ -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 {
+9 −0
Original line number Diff line number Diff line
@@ -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),