Change the large section GC to locate valid block segments instead of
performing a sequential search. This modification enhances performance
by reducing unnecessary block scanning in large storage sections.

example :
[invalid seg 0] [invalid seg 1] [invalid seg 2]
[  valid seg 3] [  valid seg 4] [  valid seg 5]

Current: In the first GC, nothing is moved,
but in the second GC, segments 3, 4, and 5 are moved.
Change: In the first GC, segments 3, 4, and 5 are moved.

Signed-off-by: yohan.joung <yohan.jo...@sk.com>
---
 fs/f2fs/f2fs.h  |  2 ++
 fs/f2fs/gc.c    | 89 +++++++++++++++++++++++++++++++++++++------------
 fs/f2fs/gc.h    |  6 ++++
 fs/f2fs/super.c |  8 ++++-
 4 files changed, 82 insertions(+), 23 deletions(-)

diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index f1576dc6ec67..348417edac25 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -4008,6 +4008,8 @@ int f2fs_gc_range(struct f2fs_sb_info *sbi,
 int f2fs_resize_fs(struct file *filp, __u64 block_count);
 int __init f2fs_create_garbage_collection_cache(void);
 void f2fs_destroy_garbage_collection_cache(void);
+int __init f2fs_init_garbage_collection_summary_cache(void);
+void f2fs_destroy_garbage_collection_summary_cache(void);
 /* victim selection function for cleaning and SSR */
 int f2fs_get_victim(struct f2fs_sb_info *sbi, unsigned int *result,
                        int gc_type, int type, char alloc_mode,
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index 2b8f9239bede..fcd2cf68612d 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -24,6 +24,7 @@
 #include <trace/events/f2fs.h>
 
 static struct kmem_cache *victim_entry_slab;
+static struct kmem_cache *gc_page_entry_slab;
 
 static unsigned int count_bits(const unsigned long *addr,
                                unsigned int offset, unsigned int len);
@@ -711,6 +712,30 @@ static void release_victim_entry(struct f2fs_sb_info *sbi)
        f2fs_bug_on(sbi, !list_empty(&am->victim_list));
 }
 
+static struct gc_page_entry *add_gc_page_entry(struct list_head *gc_page_list,
+                                       struct page *sum_page, unsigned int 
segno)
+{
+       struct gc_page_entry *gpe;
+
+       gpe = f2fs_kmem_cache_alloc(gc_page_entry_slab, GFP_NOFS, true, NULL);
+       gpe->segno = segno;
+       gpe->sum_page = sum_page;
+       list_add_tail(&gpe->list, gc_page_list);
+       return gpe;
+}
+
+static void release_gc_page_entry(struct list_head *gc_page_list, bool putpage)
+{
+       struct gc_page_entry *gpe, *tmp;
+
+       list_for_each_entry_safe(gpe, tmp, gc_page_list, list) {
+               if (putpage)
+                       f2fs_put_page(gpe->sum_page, 0);
+               list_del(&gpe->list);
+               kmem_cache_free(gc_page_entry_slab, gpe);
+       }
+}
+
 static bool f2fs_pin_section(struct f2fs_sb_info *sbi, unsigned int segno)
 {
        struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
@@ -1721,14 +1746,18 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
        struct page *sum_page;
        struct f2fs_summary_block *sum;
        struct blk_plug plug;
+       struct gc_page_entry *gpe;
        unsigned int segno = start_segno;
        unsigned int end_segno = start_segno + SEGS_PER_SEC(sbi);
        unsigned int sec_end_segno;
+       unsigned int window_granularity = 1;
        int seg_freed = 0, migrated = 0;
        unsigned char type = IS_DATASEG(get_seg_entry(sbi, segno)->type) ?
                                                SUM_TYPE_DATA : SUM_TYPE_NODE;
        unsigned char data_type = (type == SUM_TYPE_DATA) ? DATA : NODE;
        int submitted = 0;
+       int gc_list_count = 0;
+       LIST_HEAD(gc_page_list);
 
        if (__is_large_section(sbi)) {
                sec_end_segno = rounddown(end_segno, SEGS_PER_SEC(sbi));
@@ -1744,7 +1773,7 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
                                        f2fs_usable_segs_in_sec(sbi);
 
                if (gc_type == BG_GC || one_time) {
-                       unsigned int window_granularity =
+                       window_granularity =
                                sbi->migration_window_granularity;
 
                        if (f2fs_sb_has_blkzoned(sbi) &&
@@ -1752,8 +1781,6 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
                                        sbi->gc_thread->boost_zoned_gc_percent))
                                window_granularity *=
                                        BOOST_GC_MULTIPLE;
-
-                       end_segno = start_segno + window_granularity;
                }
 
                if (end_segno > sec_end_segno)
@@ -1762,37 +1789,38 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
 
        sanity_check_seg_type(sbi, get_seg_entry(sbi, segno)->type);
 
-       /* readahead multi ssa blocks those have contiguous address */
-       if (__is_large_section(sbi))
+       for (segno = start_segno; segno < end_segno; segno++) {
+               if (!get_valid_blocks(sbi, segno, false))
+                       continue;
+
+               /* readahead multi ssa blocks those have contiguous address */
                f2fs_ra_meta_pages(sbi, GET_SUM_BLOCK(sbi, segno),
-                                       end_segno - segno, META_SSA, true);
+                               window_granularity, META_SSA, true);
 
-       /* reference all summary page */
-       while (segno < end_segno) {
-               sum_page = f2fs_get_sum_page(sbi, segno++);
+               /* reference all summary page */
+               sum_page = f2fs_get_sum_page(sbi, segno);
                if (IS_ERR(sum_page)) {
                        int err = PTR_ERR(sum_page);
-
-                       end_segno = segno - 1;
-                       for (segno = start_segno; segno < end_segno; segno++) {
-                               sum_page = find_get_page(META_MAPPING(sbi),
-                                               GET_SUM_BLOCK(sbi, segno));
-                               f2fs_put_page(sum_page, 0);
-                               f2fs_put_page(sum_page, 0);
-                       }
+                       release_gc_page_entry(&gc_page_list, true);
                        return err;
                }
+               add_gc_page_entry(&gc_page_list, sum_page, segno);
                unlock_page(sum_page);
+               if (++gc_list_count >= window_granularity)
+                       break;
        }
 
        blk_start_plug(&plug);
 
-       for (segno = start_segno; segno < end_segno; segno++) {
+       list_for_each_entry(gpe, &gc_page_list, list) {
 
                /* find segment summary of victim */
-               sum_page = find_get_page(META_MAPPING(sbi),
-                                       GET_SUM_BLOCK(sbi, segno));
-               f2fs_put_page(sum_page, 0);
+               sum_page = gpe->sum_page;
+               segno = gpe->segno;
+               if (!sum_page) {
+                       f2fs_err(sbi, "Failed to get summary page for segment 
%u", segno);
+                       goto skip;
+               }
 
                if (get_valid_blocks(sbi, segno, false) == 0)
                        goto freed;
@@ -1838,15 +1866,20 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
                if (__is_large_section(sbi))
                        sbi->next_victim_seg[gc_type] =
                                (segno + 1 < sec_end_segno) ?
-                                       segno + 1 : NULL_SEGNO;
+                               segno + 1 : NULL_SEGNO;
+
 skip:
                f2fs_put_page(sum_page, 0);
        }
 
+       if (__is_large_section(sbi) && list_empty(&gc_page_list))
+               sbi->next_victim_seg[gc_type] = NULL_SEGNO;
+
        if (submitted)
                f2fs_submit_merged_write(sbi, data_type);
 
        blk_finish_plug(&plug);
+       release_gc_page_entry(&gc_page_list, false);
 
        if (migrated)
                stat_inc_gc_sec_count(sbi, data_type, gc_type);
@@ -2008,6 +2041,18 @@ int f2fs_gc(struct f2fs_sb_info *sbi, struct 
f2fs_gc_control *gc_control)
        return ret;
 }
 
+int __init f2fs_init_garbage_collection_summary_cache(void)
+{
+       gc_page_entry_slab = f2fs_kmem_cache_create("f2fs_gc_page_entry",
+                                       sizeof(struct gc_page_entry));
+       return gc_page_entry_slab ? 0 : -ENOMEM;
+}
+
+void f2fs_destroy_garbage_collection_summary_cache(void)
+{
+       kmem_cache_destroy(gc_page_entry_slab);
+}
+
 int __init f2fs_create_garbage_collection_cache(void)
 {
        victim_entry_slab = f2fs_kmem_cache_create("f2fs_victim_entry",
diff --git a/fs/f2fs/gc.h b/fs/f2fs/gc.h
index 5c1eaf55e127..9c8695efe394 100644
--- a/fs/f2fs/gc.h
+++ b/fs/f2fs/gc.h
@@ -82,6 +82,12 @@ struct victim_entry {
        struct list_head list;
 };
 
+struct gc_page_entry {
+       unsigned int segno;
+       struct page *sum_page;
+       struct list_head list;
+};
+
 /*
  * inline functions
  */
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index f087b2b71c89..a3241730fe4f 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -5090,9 +5090,12 @@ static int __init init_f2fs_fs(void)
        err = f2fs_create_garbage_collection_cache();
        if (err)
                goto free_extent_cache;
-       err = f2fs_init_sysfs();
+       err = f2fs_init_garbage_collection_summary_cache();
        if (err)
                goto free_garbage_collection_cache;
+       err = f2fs_init_sysfs();
+       if (err)
+               goto free_garbage_collection_summary_cache;
        err = f2fs_init_shrinker();
        if (err)
                goto free_sysfs;
@@ -5141,6 +5144,8 @@ static int __init init_f2fs_fs(void)
        f2fs_exit_shrinker();
 free_sysfs:
        f2fs_exit_sysfs();
+free_garbage_collection_summary_cache:
+       f2fs_destroy_garbage_collection_summary_cache();
 free_garbage_collection_cache:
        f2fs_destroy_garbage_collection_cache();
 free_extent_cache:
@@ -5172,6 +5177,7 @@ static void __exit exit_f2fs_fs(void)
        f2fs_destroy_root_stats();
        f2fs_exit_shrinker();
        f2fs_exit_sysfs();
+       f2fs_destroy_garbage_collection_summary_cache();
        f2fs_destroy_garbage_collection_cache();
        f2fs_destroy_extent_cache();
        f2fs_destroy_recovery_cache();
-- 
2.33.0



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

Reply via email to