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: Chao Yu <yuchao0@huawei.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
parent
3537581a72
commit
d9872a698c
|
@ -130,3 +130,15 @@ Date: June 2017
|
||||||
Contact: "Chao Yu" <yuchao0@huawei.com>
|
Contact: "Chao Yu" <yuchao0@huawei.com>
|
||||||
Description:
|
Description:
|
||||||
Controls current reserved blocks in system.
|
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
|
||||||
|
|
|
@ -210,6 +210,15 @@ Files in /sys/fs/f2fs/<devname>
|
||||||
gc_idle = 1 will select the Cost Benefit approach
|
gc_idle = 1 will select the Cost Benefit approach
|
||||||
& setting gc_idle = 2 will select the greedy 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
|
reclaim_segments This parameter controls the number of prefree
|
||||||
segments to be reclaimed. If the number of prefree
|
segments to be reclaimed. If the number of prefree
|
||||||
segments is larger than the number of segments
|
segments is larger than the number of segments
|
||||||
|
|
17
fs/f2fs/gc.c
17
fs/f2fs/gc.c
|
@ -35,9 +35,14 @@ static int gc_thread_func(void *data)
|
||||||
set_freezable();
|
set_freezable();
|
||||||
do {
|
do {
|
||||||
wait_event_interruptible_timeout(*wq,
|
wait_event_interruptible_timeout(*wq,
|
||||||
kthread_should_stop() || freezing(current),
|
kthread_should_stop() || freezing(current) ||
|
||||||
|
gc_th->gc_wake,
|
||||||
msecs_to_jiffies(wait_ms));
|
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())
|
if (try_to_freeze())
|
||||||
continue;
|
continue;
|
||||||
if (kthread_should_stop())
|
if (kthread_should_stop())
|
||||||
|
@ -74,6 +79,11 @@ static int gc_thread_func(void *data)
|
||||||
if (!mutex_trylock(&sbi->gc_mutex))
|
if (!mutex_trylock(&sbi->gc_mutex))
|
||||||
goto next;
|
goto next;
|
||||||
|
|
||||||
|
if (gc_th->gc_urgent) {
|
||||||
|
wait_ms = gc_th->urgent_sleep_time;
|
||||||
|
goto do_gc;
|
||||||
|
}
|
||||||
|
|
||||||
if (!is_idle(sbi)) {
|
if (!is_idle(sbi)) {
|
||||||
increase_sleep_time(gc_th, &wait_ms);
|
increase_sleep_time(gc_th, &wait_ms);
|
||||||
mutex_unlock(&sbi->gc_mutex);
|
mutex_unlock(&sbi->gc_mutex);
|
||||||
|
@ -84,7 +94,7 @@ static int gc_thread_func(void *data)
|
||||||
decrease_sleep_time(gc_th, &wait_ms);
|
decrease_sleep_time(gc_th, &wait_ms);
|
||||||
else
|
else
|
||||||
increase_sleep_time(gc_th, &wait_ms);
|
increase_sleep_time(gc_th, &wait_ms);
|
||||||
|
do_gc:
|
||||||
stat_inc_bggc_count(sbi);
|
stat_inc_bggc_count(sbi);
|
||||||
|
|
||||||
/* if return value is not zero, no victim was selected */
|
/* 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;
|
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->min_sleep_time = DEF_GC_THREAD_MIN_SLEEP_TIME;
|
||||||
gc_th->max_sleep_time = DEF_GC_THREAD_MAX_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->no_gc_sleep_time = DEF_GC_THREAD_NOGC_SLEEP_TIME;
|
||||||
|
|
||||||
gc_th->gc_idle = 0;
|
gc_th->gc_idle = 0;
|
||||||
|
gc_th->gc_urgent = 0;
|
||||||
|
gc_th->gc_wake= 0;
|
||||||
|
|
||||||
sbi->gc_thread = gc_th;
|
sbi->gc_thread = gc_th;
|
||||||
init_waitqueue_head(&sbi->gc_thread->gc_wait_queue_head);
|
init_waitqueue_head(&sbi->gc_thread->gc_wait_queue_head);
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
* whether IO subsystem is idle
|
* whether IO subsystem is idle
|
||||||
* or not
|
* 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_MIN_SLEEP_TIME 30000 /* milliseconds */
|
||||||
#define DEF_GC_THREAD_MAX_SLEEP_TIME 60000
|
#define DEF_GC_THREAD_MAX_SLEEP_TIME 60000
|
||||||
#define DEF_GC_THREAD_NOGC_SLEEP_TIME 300000 /* wait 5 min */
|
#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;
|
wait_queue_head_t gc_wait_queue_head;
|
||||||
|
|
||||||
/* for gc sleep time */
|
/* for gc sleep time */
|
||||||
|
unsigned int urgent_sleep_time;
|
||||||
unsigned int min_sleep_time;
|
unsigned int min_sleep_time;
|
||||||
unsigned int max_sleep_time;
|
unsigned int max_sleep_time;
|
||||||
unsigned int no_gc_sleep_time;
|
unsigned int no_gc_sleep_time;
|
||||||
|
|
||||||
/* for changing gc mode */
|
/* for changing gc mode */
|
||||||
unsigned int gc_idle;
|
unsigned int gc_idle;
|
||||||
|
unsigned int gc_urgent;
|
||||||
|
unsigned int gc_wake;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct gc_inode_list {
|
struct gc_inode_list {
|
||||||
|
|
|
@ -156,6 +156,10 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
|
||||||
|
|
||||||
if (!strcmp(a->attr.name, "iostat_enable") && *ui == 0)
|
if (!strcmp(a->attr.name, "iostat_enable") && *ui == 0)
|
||||||
f2fs_reset_iostat(sbi);
|
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;
|
return count;
|
||||||
}
|
}
|
||||||
|
@ -235,10 +239,13 @@ static struct f2fs_attr f2fs_attr_##_name = { \
|
||||||
.id = _id, \
|
.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_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_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_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_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(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(DCC_INFO, discard_cmd_control, max_small_discards, max_discards);
|
||||||
F2FS_RW_ATTR(RESERVED_BLOCKS, f2fs_sb_info, reserved_blocks, reserved_blocks);
|
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)
|
#define ATTR_LIST(name) (&f2fs_attr_##name.attr)
|
||||||
static struct attribute *f2fs_attrs[] = {
|
static struct attribute *f2fs_attrs[] = {
|
||||||
|
ATTR_LIST(gc_urgent_sleep_time),
|
||||||
ATTR_LIST(gc_min_sleep_time),
|
ATTR_LIST(gc_min_sleep_time),
|
||||||
ATTR_LIST(gc_max_sleep_time),
|
ATTR_LIST(gc_max_sleep_time),
|
||||||
ATTR_LIST(gc_no_gc_sleep_time),
|
ATTR_LIST(gc_no_gc_sleep_time),
|
||||||
ATTR_LIST(gc_idle),
|
ATTR_LIST(gc_idle),
|
||||||
|
ATTR_LIST(gc_urgent),
|
||||||
ATTR_LIST(reclaim_segments),
|
ATTR_LIST(reclaim_segments),
|
||||||
ATTR_LIST(max_small_discards),
|
ATTR_LIST(max_small_discards),
|
||||||
ATTR_LIST(batched_trim_sections),
|
ATTR_LIST(batched_trim_sections),
|
||||||
|
|
Loading…
Reference in New Issue