mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-01 22:54:01 +00:00
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: Jaegeuk Kim <jaegeuk.kim@samsung.com>
This commit is contained in:
parent
c335a86930
commit
408e937561
3 changed files with 23 additions and 41 deletions
|
@ -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);
|
||||||
|
|
60
fs/f2fs/gc.c
60
fs/f2fs/gc.c
|
@ -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,
|
||||||
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) {
|
if (!__get_victim(sbi, &segno, gc_type, NO_CHECK_TYPE))
|
||||||
int i;
|
goto stop;
|
||||||
if (has_not_enough_free_secs(sbi))
|
|
||||||
gc_type = FG_GC;
|
|
||||||
|
|
||||||
cur_free_secs = free_sections(sbi) + nfree;
|
for (i = 0; i < sbi->segs_per_sec; i++) {
|
||||||
|
/*
|
||||||
/* We got free space successfully. */
|
* do_garbage_collect will give us three gc_status:
|
||||||
if (nGC < cur_free_secs - old_free_secs)
|
* 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)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!__get_victim(sbi, &segno, gc_type, NO_CHECK_TYPE))
|
|
||||||
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)
|
||||||
*/
|
*/
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue