On Fri, Apr 11, 2025 at 3:07 AM Chao Yu <c...@kernel.org> wrote: > > Yohan, > > Sorry for the delay, will catch up this a little bit latter. > > On 2025/4/10 8:17, yohan.joung wrote: > > hi jeageuk, chao > > How about changing the large section gc in this direction? > > Thanks > > > >> 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 | 92 +++++++++++++++++++++++++++++++++++-------------- > >> fs/f2fs/gc.h | 6 ++++ > >> fs/f2fs/super.c | 8 ++++- > >> 4 files changed, 82 insertions(+), 26 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..3b63e85fa038 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;
Plz, refer to the below described in sysfs-fs-f2fs. What: /sys/fs/f2fs/<disk>/migration_window_granularity Date: September 2024 Contact: "Daeho Jeong" <daehoje...@google.com> Description: Controls migration window granularity of garbage collection on large section. it can control the scanning window granularity for GC migration in a unit of segment, while migration_granularity controls the number of segments which can be migrated at the same turn. In your patch, it's more like migration_granularity. Plus, I think we don't need migration_window_granularity anymore with your patch. > >> > >> 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; > >> @@ -1835,18 +1863,20 @@ static int do_garbage_collect(struct f2fs_sb_info > >> *sbi, > >> get_valid_blocks(sbi, segno, false) == 0) > >> seg_freed++; > >> > >> - if (__is_large_section(sbi)) > >> - sbi->next_victim_seg[gc_type] = > >> - (segno + 1 < sec_end_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] = > >> + (segno + 1 < sec_end_segno) ? > >> + segno + 1 : 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 +2038,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 > >> Do you have any numbers showing how much the performance is enhanced? Thanks. > >> > >> > >> _______________________________________________ > >> Linux-f2fs-devel mailing list > >> Linux-f2fs-devel@lists.sourceforge.net > _______________________________________________ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel