f2fs: add ovp valid_blocks check for bg gc victim to fg_gc
authorHou Pengyang <houpengyang@huawei.com>
Thu, 16 Feb 2017 12:34:31 +0000 (12:34 +0000)
committerBen Hutchings <ben@decadent.org.uk>
Mon, 5 Jun 2017 20:17:15 +0000 (21:17 +0100)
commit e93b9865251a0503d83fd570e7d5a7c8bc351715 upstream.

For foreground gc, greedy algorithm should be adapted, which makes
this formula work well:

(2 * (100 / config.overprovision + 1) + 6)

But currently, we fg_gc have a prior to select bg_gc victim segments to gc
first, these victims are selected by cost-benefit algorithm, we can't guarantee
such segments have the small valid blocks, which may destroy the f2fs rule, on
the worstest case, would consume all the free segments.

This patch fix this by add a filter in check_bg_victims, if segment's has # of
valid blocks over overprovision ratio, skip such segments.

Signed-off-by: Hou Pengyang <houpengyang@huawei.com>
Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
[bwh: Backported to 3.16:
 - In get_victim_by_default(), use continue rather than goto
 - Adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
fs/f2fs/f2fs.h
fs/f2fs/gc.c
fs/f2fs/segment.h

index 58df97e174d015398ab55741c6b9ba3bac2b508e..22e6307b25e20399783d4734ce58fe8fca50ee4d 100644 (file)
@@ -489,6 +489,9 @@ struct f2fs_sb_info {
        struct f2fs_gc_kthread  *gc_thread;     /* GC thread */
        unsigned int cur_victim_sec;            /* current victim section num */
 
+       /* threshold for converting bg victims for fg */
+       u64 fggc_threshold;
+
        /* maximum # of trials to find a victim segment for SSR and GC */
        unsigned int max_victim_search;
 
index d7947d90ccc3df487919723578bf5f81dde2d8a6..6267817dfe87cab79e064d9d47f3c760e5044b47 100644 (file)
@@ -163,7 +163,8 @@ static void select_policy(struct f2fs_sb_info *sbi, int gc_type,
                p->ofs_unit = sbi->segs_per_sec;
        }
 
-       if (p->max_search > sbi->max_victim_search)
+       /* we need to check every dirty segments in the FG_GC case */
+       if (gc_type != FG_GC && p->max_search > sbi->max_victim_search)
                p->max_search = sbi->max_victim_search;
 
        p->offset = sbi->last_victim[p->gc_mode];
@@ -196,6 +197,10 @@ static unsigned int check_bg_victims(struct f2fs_sb_info *sbi)
        for_each_set_bit(secno, dirty_i->victim_secmap, TOTAL_SECS(sbi)) {
                if (sec_usage_check(sbi, secno))
                        continue;
+
+               if (no_fggc_candidate(sbi, secno))
+                       continue;
+
                clear_bit(secno, dirty_i->victim_secmap);
                return secno * sbi->segs_per_sec;
        }
@@ -302,6 +307,9 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
                        continue;
                if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap))
                        continue;
+               if (gc_type == FG_GC && p.alloc_mode == LFS &&
+                                       no_fggc_candidate(sbi, secno))
+                       continue;
 
                cost = get_gc_cost(sbi, segno, &p);
 
@@ -733,7 +741,18 @@ stop:
 
 void build_gc_manager(struct f2fs_sb_info *sbi)
 {
+       u64 main_count, resv_count, ovp_count, blocks_per_sec;
+
        DIRTY_I(sbi)->v_ops = &default_v_ops;
+
+       /* threshold of # of valid blocks in a section for victims of FG_GC */
+       main_count = SM_I(sbi)->main_segments << sbi->log_blocks_per_seg;
+       resv_count = SM_I(sbi)->reserved_segments << sbi->log_blocks_per_seg;
+       ovp_count = SM_I(sbi)->ovp_segments << sbi->log_blocks_per_seg;
+       blocks_per_sec = sbi->blocks_per_seg * sbi->segs_per_sec;
+
+       sbi->fggc_threshold = div_u64((main_count - ovp_count) * blocks_per_sec,
+                                       (main_count - resv_count));
 }
 
 int __init create_gc_caches(void)
index 7091204680f49383ff269f0b8c35834e2c5297d8..64f2d83958ba0d6dd5af43983f83bb2fe923dd76 100644 (file)
@@ -651,6 +651,15 @@ static inline block_t sum_blk_addr(struct f2fs_sb_info *sbi, int base, int type)
                                - (base + 1) + type;
 }
 
+static inline bool no_fggc_candidate(struct f2fs_sb_info *sbi,
+                                               unsigned int secno)
+{
+       if (get_valid_blocks(sbi, secno, sbi->segs_per_sec) >=
+                                               sbi->fggc_threshold)
+               return true;
+       return false;
+}
+
 static inline bool sec_usage_check(struct f2fs_sb_info *sbi, unsigned int secno)
 {
        if (IS_CURSEC(sbi, secno) || (sbi->cur_victim_sec == secno))