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