Skip to content

Commit

Permalink
f2fs: introduce gc_merge mount option
Browse files Browse the repository at this point in the history
In this patch, we will add two new mount options: "gc_merge" and
"nogc_merge", when background_gc is on, "gc_merge" option can be
set to let background GC thread to handle foreground GC requests,
it can eliminate the sluggish issue caused by slow foreground GC
operation when GC is triggered from a process with limited I/O
and CPU resources.

Original idea is from Xiang.

Signed-off-by: Gao Xiang <xiang@kernel.org>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
  • Loading branch information
Chao Yu authored and Jaegeuk Kim committed Mar 31, 2021
1 parent 823d13e commit 5911d2d
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 8 deletions.
6 changes: 6 additions & 0 deletions Documentation/filesystems/f2fs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@ background_gc=%s Turn on/off cleaning operations, namely garbage
on synchronous garbage collection running in background.
Default value for this option is on. So garbage
collection is on by default.
gc_merge When background_gc is on, this option can be enabled to
let background GC thread to handle foreground GC requests,
it can eliminate the sluggish issue caused by slow foreground
GC operation when GC is triggered from a process with limited
I/O and CPU resources.
nogc_merge Disable GC merge feature.
disable_roll_forward Disable the roll-forward recovery routine
norecovery Disable the roll-forward recovery routine, mounted read-
only (i.e., -o ro,disable_roll_forward)
Expand Down
1 change: 1 addition & 0 deletions fs/f2fs/f2fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ extern const char *f2fs_fault_name[FAULT_MAX];
#define F2FS_MOUNT_NORECOVERY 0x04000000
#define F2FS_MOUNT_ATGC 0x08000000
#define F2FS_MOUNT_MERGE_CHECKPOINT 0x10000000
#define F2FS_MOUNT_GC_MERGE 0x20000000

#define F2FS_OPTION(sbi) ((sbi)->mount_opt)
#define clear_opt(sbi, option) (F2FS_OPTION(sbi).opt &= ~F2FS_MOUNT_##option)
Expand Down
26 changes: 22 additions & 4 deletions fs/f2fs/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,24 @@ static int gc_thread_func(void *data)
struct f2fs_sb_info *sbi = data;
struct f2fs_gc_kthread *gc_th = sbi->gc_thread;
wait_queue_head_t *wq = &sbi->gc_thread->gc_wait_queue_head;
wait_queue_head_t *fggc_wq = &sbi->gc_thread->fggc_wq;
unsigned int wait_ms;

wait_ms = gc_th->min_sleep_time;

set_freezable();
do {
bool sync_mode;
bool sync_mode, foreground = false;

wait_event_interruptible_timeout(*wq,
kthread_should_stop() || freezing(current) ||
waitqueue_active(fggc_wq) ||
gc_th->gc_wake,
msecs_to_jiffies(wait_ms));

if (test_opt(sbi, GC_MERGE) && waitqueue_active(fggc_wq))
foreground = true;

/* give it a try one time */
if (gc_th->gc_wake)
gc_th->gc_wake = 0;
Expand Down Expand Up @@ -90,7 +95,10 @@ static int gc_thread_func(void *data)
goto do_gc;
}

if (!down_write_trylock(&sbi->gc_lock)) {
if (foreground) {
down_write(&sbi->gc_lock);
goto do_gc;
} else if (!down_write_trylock(&sbi->gc_lock)) {
stat_other_skip_bggc_count(sbi);
goto next;
}
Expand All @@ -107,14 +115,22 @@ static int gc_thread_func(void *data)
else
increase_sleep_time(gc_th, &wait_ms);
do_gc:
stat_inc_bggc_count(sbi->stat_info);
if (!foreground)
stat_inc_bggc_count(sbi->stat_info);

sync_mode = F2FS_OPTION(sbi).bggc_mode == BGGC_MODE_SYNC;

/* foreground GC was been triggered via f2fs_balance_fs() */
if (foreground)
sync_mode = false;

/* if return value is not zero, no victim was selected */
if (f2fs_gc(sbi, sync_mode, true, false, NULL_SEGNO))
if (f2fs_gc(sbi, sync_mode, !foreground, false, NULL_SEGNO))
wait_ms = gc_th->no_gc_sleep_time;

if (foreground)
wake_up_all(&gc_th->fggc_wq);

trace_f2fs_background_gc(sbi->sb, wait_ms,
prefree_segments(sbi), free_segments(sbi));

Expand Down Expand Up @@ -148,6 +164,7 @@ int f2fs_start_gc_thread(struct f2fs_sb_info *sbi)

sbi->gc_thread = gc_th;
init_waitqueue_head(&sbi->gc_thread->gc_wait_queue_head);
init_waitqueue_head(&sbi->gc_thread->fggc_wq);
sbi->gc_thread->f2fs_gc_task = kthread_run(gc_thread_func, sbi,
"f2fs_gc-%u:%u", MAJOR(dev), MINOR(dev));
if (IS_ERR(gc_th->f2fs_gc_task)) {
Expand All @@ -165,6 +182,7 @@ void f2fs_stop_gc_thread(struct f2fs_sb_info *sbi)
if (!gc_th)
return;
kthread_stop(gc_th->f2fs_gc_task);
wake_up_all(&gc_th->fggc_wq);
kfree(gc_th);
sbi->gc_thread = NULL;
}
Expand Down
6 changes: 6 additions & 0 deletions fs/f2fs/gc.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ struct f2fs_gc_kthread {

/* for changing gc mode */
unsigned int gc_wake;

/* for GC_MERGE mount option */
wait_queue_head_t fggc_wq; /*
* caller of f2fs_balance_fs()
* will wait on this wait queue.
*/
};

struct gc_inode_list {
Expand Down
15 changes: 13 additions & 2 deletions fs/f2fs/segment.c
Original file line number Diff line number Diff line change
Expand Up @@ -503,8 +503,19 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need)
* dir/node pages without enough free segments.
*/
if (has_not_enough_free_secs(sbi, 0, 0)) {
down_write(&sbi->gc_lock);
f2fs_gc(sbi, false, false, false, NULL_SEGNO);
if (test_opt(sbi, GC_MERGE) && sbi->gc_thread &&
sbi->gc_thread->f2fs_gc_task) {
DEFINE_WAIT(wait);

prepare_to_wait(&sbi->gc_thread->fggc_wq, &wait,
TASK_UNINTERRUPTIBLE);
wake_up(&sbi->gc_thread->gc_wait_queue_head);
io_schedule();
finish_wait(&sbi->gc_thread->fggc_wq, &wait);
} else {
down_write(&sbi->gc_lock);
f2fs_gc(sbi, false, false, false, NULL_SEGNO);
}
}
}

Expand Down
19 changes: 17 additions & 2 deletions fs/f2fs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ enum {
Opt_compress_chksum,
Opt_compress_mode,
Opt_atgc,
Opt_gc_merge,
Opt_nogc_merge,
Opt_err,
};

Expand Down Expand Up @@ -223,6 +225,8 @@ static match_table_t f2fs_tokens = {
{Opt_compress_chksum, "compress_chksum"},
{Opt_compress_mode, "compress_mode=%s"},
{Opt_atgc, "atgc"},
{Opt_gc_merge, "gc_merge"},
{Opt_nogc_merge, "nogc_merge"},
{Opt_err, NULL},
};

Expand Down Expand Up @@ -1073,6 +1077,12 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount)
case Opt_atgc:
set_opt(sbi, ATGC);
break;
case Opt_gc_merge:
set_opt(sbi, GC_MERGE);
break;
case Opt_nogc_merge:
clear_opt(sbi, GC_MERGE);
break;
default:
f2fs_err(sbi, "Unrecognized mount option \"%s\" or missing value",
p);
Expand Down Expand Up @@ -1675,6 +1685,9 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
else if (F2FS_OPTION(sbi).bggc_mode == BGGC_MODE_OFF)
seq_printf(seq, ",background_gc=%s", "off");

if (test_opt(sbi, GC_MERGE))
seq_puts(seq, ",gc_merge");

if (test_opt(sbi, DISABLE_ROLL_FORWARD))
seq_puts(seq, ",disable_roll_forward");
if (test_opt(sbi, NORECOVERY))
Expand Down Expand Up @@ -2038,7 +2051,8 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
* option. Also sync the filesystem.
*/
if ((*flags & SB_RDONLY) ||
F2FS_OPTION(sbi).bggc_mode == BGGC_MODE_OFF) {
(F2FS_OPTION(sbi).bggc_mode == BGGC_MODE_OFF &&
!test_opt(sbi, GC_MERGE))) {
if (sbi->gc_thread) {
f2fs_stop_gc_thread(sbi);
need_restart_gc = true;
Expand Down Expand Up @@ -4012,7 +4026,8 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
* If filesystem is not mounted as read-only then
* do start the gc_thread.
*/
if (F2FS_OPTION(sbi).bggc_mode != BGGC_MODE_OFF && !f2fs_readonly(sb)) {
if ((F2FS_OPTION(sbi).bggc_mode != BGGC_MODE_OFF ||
test_opt(sbi, GC_MERGE)) && !f2fs_readonly(sb)) {
/* After POR, we can run background GC thread.*/
err = f2fs_start_gc_thread(sbi);
if (err)
Expand Down

0 comments on commit 5911d2d

Please sign in to comment.