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 <zhangqilo...@huawei.com>
---
 fs/f2fs/file.c    |  5 +++++
 fs/f2fs/gc.c      | 19 +++++++++++++------
 fs/f2fs/segment.c |  4 ++--
 3 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 3268f8dd59bb..209dd9cb4b7b 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -2527,6 +2527,11 @@ static int f2fs_ioc_gc_range(struct file *filp, unsigned 
long arg)
        }
 
        ret = f2fs_gc(sbi, range.sync, true, GET_SEGNO(sbi, range.start));
+       if (ret) {
+               if (ret == -EAGAIN)
+                       ret = -EBUSY;
+               goto out;
+       }
        range.start += BLKS_PER_SEC(sbi);
        if (range.start <= end)
                goto do_more;
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index 5b95d5a146eb..297e53ef4cb1 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -321,6 +321,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;
 
        mutex_lock(&dirty_i->seglist_lock);
        last_segment = MAIN_SECS(sbi) * sbi->segs_per_sec;
@@ -332,12 +333,18 @@ 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)))
+               ret = 0;
+               if (!get_valid_blocks(sbi, *result, false))
+                       goto out;
+
+               if (sec_usage_check(sbi, GET_SEC_FROM_SEG(sbi, *result)))
+                       ret = -EAGAIN;
+               else
                        p.min_segno = *result;
                goto out;
        }
 
+       ret = -ENODATA;
        if (p.max_search == 0)
                goto out;
 
@@ -440,6 +447,7 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
                        else
                                set_bit(secno, dirty_i->victim_secmap);
                }
+               ret = 0;
 
        }
 out:
@@ -449,7 +457,7 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
                                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 = {
@@ -1333,10 +1341,9 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync,
                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)
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index 196f31503511..b9fd93761b0a 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -2605,7 +2605,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;
        }
@@ -2632,7 +2632,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;
                }
-- 
2.17.1



_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

Reply via email to