f2fs: add f2fs_gc exception handle in f2fs_ioc_gc_range
authorQilong Zhang <zhangqilong3@huawei.com>
Sun, 28 Jun 2020 11:23:03 +0000 (19:23 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Wed, 8 Jul 2020 04:51:44 +0000 (21:51 -0700)
When f2fs_ioc_gc_range performs multiple segments gc ops, the return
value of f2fs_ioc_gc_range is determined by the last segment gc ops.
If its ops failed, the f2fs_ioc_gc_range will be considered to be failed
despite some of previous segments gc ops succeeded. Therefore, so we
fix: Redefine the return value of getting victim ops and add exception
handle for f2fs_gc. In particular, 1).if target has no valid block, it
will go on. 2).if target sectoion has valid block(s), but it is current
section, we will reminder the caller.

Signed-off-by: Qilong Zhang <zhangqilong3@huawei.com>
Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/file.c
fs/f2fs/gc.c
fs/f2fs/segment.c

index e15d4ce4c08e0cd04b9f8efdfd536d61131d9adc..6ef2656c617134ac28572a114c8754937c89c736 100644 (file)
@@ -2525,6 +2525,11 @@ do_more:
        }
 
        ret = f2fs_gc(sbi, range.sync, true, GET_SEGNO(sbi, range.start));
+       if (ret) {
+               if (ret == -EBUSY)
+                       ret = -EAGAIN;
+               goto out;
+       }
        range.start += BLKS_PER_SEC(sbi);
        if (range.start <= end)
                goto do_more;
index 5e1368ce23898a1382f70d4352695a11d9667550..6eec3b2d606d4163459b0ebeebc75d9da30db4f3 100644 (file)
@@ -330,6 +330,7 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
        unsigned int secno, last_victim;
        unsigned int last_segment;
        unsigned int nsearched = 0;
+       int ret = 0;
 
        mutex_lock(&dirty_i->seglist_lock);
        last_segment = MAIN_SECS(sbi) * sbi->segs_per_sec;
@@ -341,12 +342,19 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
        p.min_cost = get_max_cost(sbi, &p);
 
        if (*result != NULL_SEGNO) {
-               if (get_valid_blocks(sbi, *result, false) &&
-                       !sec_usage_check(sbi, GET_SEC_FROM_SEG(sbi, *result)))
+               if (!get_valid_blocks(sbi, *result, false)) {
+                       ret = -ENODATA;
+                       goto out;
+               }
+
+               if (sec_usage_check(sbi, GET_SEC_FROM_SEG(sbi, *result)))
+                       ret = -EBUSY;
+               else
                        p.min_segno = *result;
                goto out;
        }
 
+       ret = -ENODATA;
        if (p.max_search == 0)
                goto out;
 
@@ -447,6 +455,7 @@ got_result:
                        else
                                set_bit(secno, dirty_i->victim_secmap);
                }
+               ret = 0;
 
        }
 out:
@@ -456,7 +465,7 @@ out:
                                prefree_segments(sbi), free_segments(sbi));
        mutex_unlock(&dirty_i->seglist_lock);
 
-       return (p.min_segno == NULL_SEGNO) ? 0 : 1;
+       return ret;
 }
 
 static const struct victim_selection default_v_ops = {
@@ -1340,10 +1349,9 @@ gc_more:
                ret = -EINVAL;
                goto stop;
        }
-       if (!__get_victim(sbi, &segno, gc_type)) {
-               ret = -ENODATA;
+       ret = __get_victim(sbi, &segno, gc_type);
+       if (ret)
                goto stop;
-       }
 
        seg_freed = do_garbage_collect(sbi, segno, &gc_list, gc_type);
        if (gc_type == FG_GC && seg_freed == sbi->segs_per_sec)
index 735c598c25eabb39b9e81957adab9facbd6929ef..5aa4158a1440cc8f5d0b529f8b0a6a5b7845097f 100644 (file)
@@ -2631,7 +2631,7 @@ static int get_ssr_segment(struct f2fs_sb_info *sbi, int type)
        bool reversed = false;
 
        /* f2fs_need_SSR() already forces to do this */
-       if (v_ops->get_victim(sbi, &segno, BG_GC, type, SSR)) {
+       if (!v_ops->get_victim(sbi, &segno, BG_GC, type, SSR)) {
                curseg->next_segno = segno;
                return 1;
        }
@@ -2658,7 +2658,7 @@ static int get_ssr_segment(struct f2fs_sb_info *sbi, int type)
        for (; cnt-- > 0; reversed ? i-- : i++) {
                if (i == type)
                        continue;
-               if (v_ops->get_victim(sbi, &segno, BG_GC, i, SSR)) {
+               if (!v_ops->get_victim(sbi, &segno, BG_GC, i, SSR)) {
                        curseg->next_segno = segno;
                        return 1;
                }