Commit 408e9375 authored by Jaegeuk Kim's avatar Jaegeuk Kim

f2fs: revisit the f2fs_gc flow

I'd like to revisit the f2fs_gc flow and rewrite as follows.

1. In practical, the nGC parameter of f2fs_gc is meaningless. So, let's
  remove it.
2. Background GC marks victim blocks as dirty one at a time.
3. Foreground GC should do cleaning job until acquiring enough free
  sections. Afterwards, it needs to do checkpoint.
Signed-off-by: default avatarJaegeuk Kim <jaegeuk.kim@samsung.com>
parent c335a869
...@@ -986,7 +986,7 @@ int do_write_data_page(struct page *); ...@@ -986,7 +986,7 @@ int do_write_data_page(struct page *);
int start_gc_thread(struct f2fs_sb_info *); int start_gc_thread(struct f2fs_sb_info *);
void stop_gc_thread(struct f2fs_sb_info *); void stop_gc_thread(struct f2fs_sb_info *);
block_t start_bidx_of_node(unsigned int); block_t start_bidx_of_node(unsigned int);
int f2fs_gc(struct f2fs_sb_info *, int); int f2fs_gc(struct f2fs_sb_info *);
void build_gc_manager(struct f2fs_sb_info *); void build_gc_manager(struct f2fs_sb_info *);
int create_gc_caches(void); int create_gc_caches(void);
void destroy_gc_caches(void); void destroy_gc_caches(void);
......
...@@ -78,7 +78,7 @@ static int gc_thread_func(void *data) ...@@ -78,7 +78,7 @@ static int gc_thread_func(void *data)
sbi->bg_gc++; sbi->bg_gc++;
if (f2fs_gc(sbi, 1) == GC_NONE) if (f2fs_gc(sbi) == GC_NONE)
wait_ms = GC_THREAD_NOGC_SLEEP_TIME; wait_ms = GC_THREAD_NOGC_SLEEP_TIME;
else if (wait_ms == GC_THREAD_NOGC_SLEEP_TIME) else if (wait_ms == GC_THREAD_NOGC_SLEEP_TIME)
wait_ms = GC_THREAD_MAX_SLEEP_TIME; wait_ms = GC_THREAD_MAX_SLEEP_TIME;
...@@ -651,62 +651,44 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, unsigned int segno, ...@@ -651,62 +651,44 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, unsigned int segno,
return ret; return ret;
} }
int f2fs_gc(struct f2fs_sb_info *sbi, int nGC) int f2fs_gc(struct f2fs_sb_info *sbi)
{ {
unsigned int segno;
int old_free_secs, cur_free_secs;
int gc_status, nfree;
struct list_head ilist; struct list_head ilist;
unsigned int segno, i;
int gc_type = BG_GC; int gc_type = BG_GC;
int gc_status = GC_NONE;
INIT_LIST_HEAD(&ilist); INIT_LIST_HEAD(&ilist);
gc_more: gc_more:
nfree = 0; if (!(sbi->sb->s_flags & MS_ACTIVE))
gc_status = GC_NONE; goto stop;
if (has_not_enough_free_secs(sbi)) if (has_not_enough_free_secs(sbi))
old_free_secs = reserved_sections(sbi); gc_type = FG_GC;
else
old_free_secs = free_sections(sbi);
while (sbi->sb->s_flags & MS_ACTIVE) {
int i;
if (has_not_enough_free_secs(sbi))
gc_type = FG_GC;
cur_free_secs = free_sections(sbi) + nfree; if (!__get_victim(sbi, &segno, gc_type, NO_CHECK_TYPE))
goto stop;
/* We got free space successfully. */ for (i = 0; i < sbi->segs_per_sec; i++) {
if (nGC < cur_free_secs - old_free_secs) /*
break; * do_garbage_collect will give us three gc_status:
* GC_ERROR, GC_DONE, and GC_BLOCKED.
if (!__get_victim(sbi, &segno, gc_type, NO_CHECK_TYPE)) * If GC is finished uncleanly, we have to return
* the victim to dirty segment list.
*/
gc_status = do_garbage_collect(sbi, segno + i, &ilist, gc_type);
if (gc_status != GC_DONE)
break; break;
for (i = 0; i < sbi->segs_per_sec; i++) {
/*
* do_garbage_collect will give us three gc_status:
* GC_ERROR, GC_DONE, and GC_BLOCKED.
* If GC is finished uncleanly, we have to return
* the victim to dirty segment list.
*/
gc_status = do_garbage_collect(sbi, segno + i,
&ilist, gc_type);
if (gc_status != GC_DONE)
goto stop;
nfree++;
}
} }
stop: if (has_not_enough_free_secs(sbi)) {
if (has_not_enough_free_secs(sbi) || gc_status == GC_BLOCKED) {
write_checkpoint(sbi, (gc_status == GC_BLOCKED), false); write_checkpoint(sbi, (gc_status == GC_BLOCKED), false);
if (nfree) if (has_not_enough_free_secs(sbi))
goto gc_more; goto gc_more;
} }
stop:
mutex_unlock(&sbi->gc_mutex); mutex_unlock(&sbi->gc_mutex);
put_gc_inode(&ilist); put_gc_inode(&ilist);
BUG_ON(!list_empty(&ilist));
return gc_status; return gc_status;
} }
......
...@@ -31,7 +31,7 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi) ...@@ -31,7 +31,7 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi)
*/ */
if (has_not_enough_free_secs(sbi)) { if (has_not_enough_free_secs(sbi)) {
mutex_lock(&sbi->gc_mutex); mutex_lock(&sbi->gc_mutex);
f2fs_gc(sbi, 1); f2fs_gc(sbi);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment