|
@@ -84,7 +84,7 @@ static int gc_thread_func(void *data)
|
|
|
stat_inc_bggc_count(sbi);
|
|
|
|
|
|
/* if return value is not zero, no victim was selected */
|
|
|
- if (f2fs_gc(sbi, test_opt(sbi, FORCE_FG_GC), true))
|
|
|
+ if (f2fs_gc(sbi, test_opt(sbi, FORCE_FG_GC), true, NULL_SEGNO))
|
|
|
wait_ms = gc_th->no_gc_sleep_time;
|
|
|
|
|
|
trace_f2fs_background_gc(sbi->sb, wait_ms,
|
|
@@ -176,7 +176,7 @@ static void select_policy(struct f2fs_sb_info *sbi, int gc_type,
|
|
|
if (type == CURSEG_HOT_DATA || IS_NODESEG(type))
|
|
|
p->offset = 0;
|
|
|
else
|
|
|
- p->offset = sbi->last_victim[p->gc_mode];
|
|
|
+ p->offset = SIT_I(sbi)->last_victim[p->gc_mode];
|
|
|
}
|
|
|
|
|
|
static unsigned int get_max_cost(struct f2fs_sb_info *sbi,
|
|
@@ -295,6 +295,7 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
|
|
|
unsigned int *result, int gc_type, int type, char alloc_mode)
|
|
|
{
|
|
|
struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
|
|
|
+ struct sit_info *sm = SIT_I(sbi);
|
|
|
struct victim_sel_policy p;
|
|
|
unsigned int secno, last_victim;
|
|
|
unsigned int last_segment = MAIN_SEGS(sbi);
|
|
@@ -308,10 +309,18 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
|
|
|
p.min_segno = NULL_SEGNO;
|
|
|
p.min_cost = get_max_cost(sbi, &p);
|
|
|
|
|
|
+ if (*result != NULL_SEGNO) {
|
|
|
+ if (IS_DATASEG(get_seg_entry(sbi, *result)->type) &&
|
|
|
+ get_valid_blocks(sbi, *result, false) &&
|
|
|
+ !sec_usage_check(sbi, GET_SEC_FROM_SEG(sbi, *result)))
|
|
|
+ p.min_segno = *result;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
if (p.max_search == 0)
|
|
|
goto out;
|
|
|
|
|
|
- last_victim = sbi->last_victim[p.gc_mode];
|
|
|
+ last_victim = sm->last_victim[p.gc_mode];
|
|
|
if (p.alloc_mode == LFS && gc_type == FG_GC) {
|
|
|
p.min_segno = check_bg_victims(sbi);
|
|
|
if (p.min_segno != NULL_SEGNO)
|
|
@@ -324,9 +333,10 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
|
|
|
|
|
|
segno = find_next_bit(p.dirty_segmap, last_segment, p.offset);
|
|
|
if (segno >= last_segment) {
|
|
|
- if (sbi->last_victim[p.gc_mode]) {
|
|
|
- last_segment = sbi->last_victim[p.gc_mode];
|
|
|
- sbi->last_victim[p.gc_mode] = 0;
|
|
|
+ if (sm->last_victim[p.gc_mode]) {
|
|
|
+ last_segment =
|
|
|
+ sm->last_victim[p.gc_mode];
|
|
|
+ sm->last_victim[p.gc_mode] = 0;
|
|
|
p.offset = 0;
|
|
|
continue;
|
|
|
}
|
|
@@ -361,11 +371,11 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
|
|
|
}
|
|
|
next:
|
|
|
if (nsearched >= p.max_search) {
|
|
|
- if (!sbi->last_victim[p.gc_mode] && segno <= last_victim)
|
|
|
- sbi->last_victim[p.gc_mode] = last_victim + 1;
|
|
|
+ if (!sm->last_victim[p.gc_mode] && segno <= last_victim)
|
|
|
+ sm->last_victim[p.gc_mode] = last_victim + 1;
|
|
|
else
|
|
|
- sbi->last_victim[p.gc_mode] = segno + 1;
|
|
|
- sbi->last_victim[p.gc_mode] %= MAIN_SEGS(sbi);
|
|
|
+ sm->last_victim[p.gc_mode] = segno + 1;
|
|
|
+ sm->last_victim[p.gc_mode] %= MAIN_SEGS(sbi);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
@@ -912,7 +922,6 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
|
|
|
* - mutex_lock(sentry_lock) - change_curseg()
|
|
|
* - lock_page(sum_page)
|
|
|
*/
|
|
|
-
|
|
|
if (type == SUM_TYPE_NODE)
|
|
|
gc_node_segment(sbi, sum->entries, segno, gc_type);
|
|
|
else
|
|
@@ -939,13 +948,14 @@ next:
|
|
|
return sec_freed;
|
|
|
}
|
|
|
|
|
|
-int f2fs_gc(struct f2fs_sb_info *sbi, bool sync, bool background)
|
|
|
+int f2fs_gc(struct f2fs_sb_info *sbi, bool sync,
|
|
|
+ bool background, unsigned int segno)
|
|
|
{
|
|
|
- unsigned int segno;
|
|
|
int gc_type = sync ? FG_GC : BG_GC;
|
|
|
int sec_freed = 0;
|
|
|
int ret = -EINVAL;
|
|
|
struct cp_control cpc;
|
|
|
+ unsigned int init_segno = segno;
|
|
|
struct gc_inode_list gc_list = {
|
|
|
.ilist = LIST_HEAD_INIT(gc_list.ilist),
|
|
|
.iroot = RADIX_TREE_INIT(GFP_NOFS),
|
|
@@ -990,13 +1000,17 @@ gc_more:
|
|
|
sbi->cur_victim_sec = NULL_SEGNO;
|
|
|
|
|
|
if (!sync) {
|
|
|
- if (has_not_enough_free_secs(sbi, sec_freed, 0))
|
|
|
+ if (has_not_enough_free_secs(sbi, sec_freed, 0)) {
|
|
|
+ segno = NULL_SEGNO;
|
|
|
goto gc_more;
|
|
|
+ }
|
|
|
|
|
|
if (gc_type == FG_GC)
|
|
|
ret = write_checkpoint(sbi, &cpc);
|
|
|
}
|
|
|
stop:
|
|
|
+ SIT_I(sbi)->last_victim[ALLOC_NEXT] = 0;
|
|
|
+ SIT_I(sbi)->last_victim[FLUSH_DEVICE] = init_segno;
|
|
|
mutex_unlock(&sbi->gc_mutex);
|
|
|
|
|
|
put_gc_inode(&gc_list);
|