Message ID | 20230317044151epcms2p5872591b638dab3261a9dd563253f1b94@epcms2p5 (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | [f2fs-dev,v1] mkfs.f2fs: Introduce configurable reserved sections | expand |
On 03/17, Yonggil Song wrote: > Overview > ======== > > This option allows zoned block device users to configure GC reserved and > overprovision area manually according to their demands on performance of > sustained write latency and WAF. > > Problem > ======= > > The overprovision segments that mkfs generates are mostly occupied by GC > reserved. This degrades WAF performance. > > Experiment > ========== > > The following experiment evaluated the application of configurable reserved. > The experimental environment is as follows. > > System info > - 4.2Ghz, 8 core CPU > - 64GiB Memory > Device info > - a conventional null_blk with 448MiB capacity(meta area) and > - a sequential null_blk with 953 zones of 64MiB > Format > - as-is (find out ovp ratio): mkfs.f2fs <conv null_blk> -c <seq null_blk> -m > Info: Overprovision ratio = 3.700% > Info: Overprovision segments = 1152 (GC reserved = 1088) > - config rsvd: mkfs.f2fs <conv null_blk> -c <seq null_blk> -m 8 -o 2.965 > Info: Overprovision ratio = 2.965% > Info: Overprovision segments = 1152 (GC reserved = 256) > Mount > - mount <conv null_blk> <mount point> > Fio script > - fio --rw=randwrite --bs=4k --ba=4k --filesize=58630m --norandommap --overwrite=1 --name=job1 --filename=<mount point>/sustain --time_based --runtime=2h > WAF calculation > - (IOs on conv. null_blk + IOs on seq. null_blk) / random write IOs > > Conclusion > ========== > > In the experiment, it can be shown that reducing the reserved segments > decreases WAF to 10% (from 222 to 23) although it triggers checkpoint more > frequently during gc. With direct IO, the WAF of as-is gets much higher. > In other words, a user can configure more reserved segments for lower GC > latency or allocate less reserved segments for lower WAF on the same number > of OP segments. > > Signed-off-by: Yonggil Song <yonggil.song@samsung.com> > --- > include/f2fs_fs.h | 22 ++++++++++++++++++++-- > lib/libf2fs.c | 22 ++++++++++++++++++++++ > man/mkfs.f2fs.8 | 9 +++++++-- > mkfs/f2fs_format.c | 29 +++++++++++++++++++++++------ > mkfs/f2fs_format_main.c | 5 +++-- > 5 files changed, 75 insertions(+), 12 deletions(-) > > diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h > index 333ae07a5ebd..1d41e9f8397e 100644 > --- a/include/f2fs_fs.h > +++ b/include/f2fs_fs.h > @@ -375,6 +375,10 @@ static inline uint64_t bswap_64(uint64_t val) > > #define LPF "lost+found" > > +/* one for gc buffer, the other for node */ > +#define MIN_RSVD_SECS (uint32_t)(NR_CURSEG_TYPE + 2) > +#define CONFIG_RSVD_DEFAULT_OP_RATIO 3.0 > + > enum f2fs_config_func { > MKFS, > FSCK, > @@ -460,6 +464,7 @@ typedef struct { > #define ALIGN_UP(addrs, size) ALIGN_DOWN(((addrs) + (size) - 1), (size)) > > struct f2fs_configuration { > + uint32_t conf_reserved_sections; > uint32_t reserved_segments; > uint32_t new_reserved_segments; > int sparse_mode; > @@ -1614,6 +1619,20 @@ extern uint32_t f2fs_get_usable_segments(struct f2fs_super_block *sb); > #define ZONE_ALIGN(blks) SIZE_ALIGN(blks, c.blks_per_seg * \ > c.segs_per_zone) > > +static inline double get_reserved(struct f2fs_super_block *sb, double ovp) > +{ > + double reserved; > + uint32_t usable_main_segs = f2fs_get_usable_segments(sb); > + uint32_t segs_per_sec = round_up(usable_main_segs, get_sb(section_count)); > + > + if (c.conf_reserved_sections) > + reserved = c.conf_reserved_sections * segs_per_sec; > + else > + reserved = (100 / ovp + 1 + NR_CURSEG_TYPE) * segs_per_sec; > + > + return reserved; > +} > + > static inline double get_best_overprovision(struct f2fs_super_block *sb) > { > double reserved, ovp, candidate, end, diff, space; > @@ -1631,8 +1650,7 @@ static inline double get_best_overprovision(struct f2fs_super_block *sb) > } > > for (; candidate <= end; candidate += diff) { > - reserved = (100 / candidate + 1 + NR_CURSEG_TYPE) * > - round_up(usable_main_segs, get_sb(section_count)); > + reserved = get_reserved(sb, candidate); > ovp = (usable_main_segs - reserved) * candidate / 100; > if (ovp < 0) > continue; > diff --git a/lib/libf2fs.c b/lib/libf2fs.c > index f63307a42a08..b5644ff6ebdd 100644 > --- a/lib/libf2fs.c > +++ b/lib/libf2fs.c > @@ -1069,6 +1069,28 @@ int get_device_info(int i) > dev->nr_rnd_zones); > MSG(0, " %zu blocks per zone\n", > dev->zone_blocks); > + if (c.conf_reserved_sections) { > + if (c.conf_reserved_sections < MIN_RSVD_SECS) { > + MSG(0, " Too small sections are reserved(%u secs)\n", > + c.conf_reserved_sections); > + c.conf_reserved_sections = > + max(c.conf_reserved_sections, MIN_RSVD_SECS); > + MSG(0, " It is operated as a minimum reserved sections(%u secs)\n", > + c.conf_reserved_sections); > + } else { > + MSG(0, " %u sections are reserved\n", > + c.conf_reserved_sections); > + } > + if (!c.overprovision) { > + c.overprovision = CONFIG_RSVD_DEFAULT_OP_RATIO; > + MSG(0, " Overprovision ratio is set to default(%.1lf%%)\n", > + c.overprovision); > + } > + } else { > + MSG(0, > + " 0 reserved sections are received.\n" > + " Reserved sections are calculating\n"); > + } > } > #endif > /* adjust wanted_total_sectors */ > diff --git a/man/mkfs.f2fs.8 b/man/mkfs.f2fs.8 > index a6249f6ef6ed..800c4c79bf37 100644 > --- a/man/mkfs.f2fs.8 > +++ b/man/mkfs.f2fs.8 > @@ -43,6 +43,7 @@ mkfs.f2fs \- create an F2FS file system > ] > [ > .B \-m > +.I #-of-reserved-sections > ] > [ > .B \-o > @@ -152,8 +153,12 @@ Enable extended node bitmap. > .BI \-l " volume-label" > Specify the volume label to the partition mounted as F2FS. > .TP > -.BI \-m > -Specify f2fs filesystem to supports the block zoned feature. > +.BI \-m " #-of-reserved-sections" > +Specify f2fs filesystem to supports the block zoned feature and reserved sections. > +If specified to non-zero, reserved segments count is set to the larger size > +between 8 sections and the input value. If specified to zero, the best number > +will be assigned automatically according to the partition size. If overprovision-ratio-percentage > +is not specifed, it will set to default 3.0%. > Without it, the filesystem doesn't support the feature. > .TP > .BI \-o " overprovision-ratio-percentage" > diff --git a/mkfs/f2fs_format.c b/mkfs/f2fs_format.c > index f4a49acc498c..22e53be5003d 100644 > --- a/mkfs/f2fs_format.c > +++ b/mkfs/f2fs_format.c > @@ -483,9 +483,7 @@ static int f2fs_prepare_super_block(void) > if (c.overprovision == 0) > c.overprovision = get_best_overprovision(sb); > > - c.reserved_segments = > - (100 / c.overprovision + 1 + NR_CURSEG_TYPE) * > - round_up(f2fs_get_usable_segments(sb), get_sb(section_count)); > + c.reserved_segments = get_reserved(sb, c.overprovision); > > if (c.feature & cpu_to_le32(F2FS_FEATURE_RO)) { > c.overprovision = 0; > @@ -765,11 +763,30 @@ static int f2fs_write_check_point_pack(void) > get_cp(rsvd_segment_count)) * > c.overprovision / 100); > > - if (get_cp(overprov_segment_count) < get_cp(rsvd_segment_count)) > + if (!(c.conf_reserved_sections) && > + get_cp(overprov_segment_count) < get_cp(rsvd_segment_count)) > set_cp(overprov_segment_count, get_cp(rsvd_segment_count)); > > - set_cp(overprov_segment_count, get_cp(overprov_segment_count) + > - 2 * get_sb(segs_per_sec)); > + /* > + * If conf_reserved_sections has a non zero value, overprov_segment_count > + * is set to overprov_segment_count + rsvd_segment_count. > + */ > + if (c.conf_reserved_sections) { > + /* > + * Overprovision segments must be bigger than two sections. > + * In non configurable reserved section case, overprovision > + * segments are always bigger than two sections. > + */ > + if (get_cp(overprov_segment_count) < 2 * get_sb(segs_per_sec)) { > + MSG(0, "\tError: Not enough overprovision segments (%u)\n", > + get_cp(overprov_segment_count)); > + goto free_cp_payload; > + } > + set_cp(overprov_segment_count, get_cp(overprov_segment_count) + > + get_cp(rsvd_segment_count)); > + } else > + set_cp(overprov_segment_count, get_cp(overprov_segment_count) + > + 2 * get_sb(segs_per_sec)); > > if (f2fs_get_usable_segments(sb) <= get_cp(overprov_segment_count)) { > MSG(0, "\tError: Not enough segments to create F2FS Volume\n"); > diff --git a/mkfs/f2fs_format_main.c b/mkfs/f2fs_format_main.c > index f50971c4591c..a4accda91780 100644 > --- a/mkfs/f2fs_format_main.c > +++ b/mkfs/f2fs_format_main.c > @@ -61,7 +61,7 @@ static void mkfs_usage() > MSG(0, " -i extended node bitmap, node ratio is 20%% by default\n"); > MSG(0, " -l label\n"); > MSG(0, " -U uuid\n"); > - MSG(0, " -m support zoned block device [default:0]\n"); > + MSG(0, " -m support zoned block device, # of reserved sections [default:0]\n"); > MSG(0, " -o overprovision percentage [default:auto]\n"); > MSG(0, " -O feature1[,feature2,...] e.g. \"encrypt\"\n"); > MSG(0, " -C [encoding[:flag1,...]] Support casefolding with optional flags\n"); > @@ -176,7 +176,7 @@ static void add_default_options(void) > > static void f2fs_parse_options(int argc, char *argv[]) > { > - static const char *option_string = "qa:c:C:d:e:E:g:hil:mo:O:rR:s:S:z:t:T:U:Vfw:"; > + static const char *option_string = "qa:c:C:d:e:E:g:hil:m:o:O:rR:s:S:z:t:T:U:Vfw:"; > static const struct option long_opts[] = { > { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, > { .name = NULL, .has_arg = 0, .flag = NULL, .val = 0 } > @@ -235,6 +235,7 @@ static void f2fs_parse_options(int argc, char *argv[]) > break; > case 'm': > c.zoned_mode = 1; > + c.conf_reserved_sections = atoi(optarg); This breaks the existing "-m" option. Can you address to support that? > break; > case 'o': > c.overprovision = atof(optarg); > -- > 2.34.1
On 03/17, Yonggil Song wrote: >> Overview >> ======== >> >> This option allows zoned block device users to configure GC reserved and >> overprovision area manually according to their demands on performance of >> sustained write latency and WAF. >> >> Problem >> ======= >> >> The overprovision segments that mkfs generates are mostly occupied by GC >> reserved. This degrades WAF performance. >> >> Experiment >> ========== >> >> The following experiment evaluated the application of configurable reserved. >> The experimental environment is as follows. >> >> System info >> - 4.2Ghz, 8 core CPU >> - 64GiB Memory >> Device info >> - a conventional null_blk with 448MiB capacity(meta area) and >> - a sequential null_blk with 953 zones of 64MiB >> Format >> - as-is (find out ovp ratio): mkfs.f2fs <conv null_blk> -c <seq null_blk> -m >> Info: Overprovision ratio = 3.700% >> Info: Overprovision segments = 1152 (GC reserved = 1088) >> - config rsvd: mkfs.f2fs <conv null_blk> -c <seq null_blk> -m 8 -o 2.965 >> Info: Overprovision ratio = 2.965% >> Info: Overprovision segments = 1152 (GC reserved = 256) >> Mount >> - mount <conv null_blk> <mount point> >> Fio script >> - fio --rw=randwrite --bs=4k --ba=4k --filesize=58630m --norandommap --overwrite=1 --name=job1 --filename=<mount point>/sustain --time_based --runtime=2h >> WAF calculation >> - (IOs on conv. null_blk + IOs on seq. null_blk) / random write IOs >> >> Conclusion >> ========== >> >> In the experiment, it can be shown that reducing the reserved segments >> decreases WAF to 10% (from 222 to 23) although it triggers checkpoint more >> frequently during gc. With direct IO, the WAF of as-is gets much higher. >> In other words, a user can configure more reserved segments for lower GC >> latency or allocate less reserved segments for lower WAF on the same number >> of OP segments. >> >> Signed-off-by: Yonggil Song <yonggil.song@samsung.com> >> --- >> include/f2fs_fs.h | 22 ++++++++++++++++++++-- >> lib/libf2fs.c | 22 ++++++++++++++++++++++ >> man/mkfs.f2fs.8 | 9 +++++++-- >> mkfs/f2fs_format.c | 29 +++++++++++++++++++++++------ >> mkfs/f2fs_format_main.c | 5 +++-- >> 5 files changed, 75 insertions(+), 12 deletions(-) >> >> diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h >> index 333ae07a5ebd..1d41e9f8397e 100644 >> --- a/include/f2fs_fs.h >> +++ b/include/f2fs_fs.h >> @@ -375,6 +375,10 @@ static inline uint64_t bswap_64(uint64_t val) >> >> #define LPF "lost+found" >> >> +/* one for gc buffer, the other for node */ >> +#define MIN_RSVD_SECS (uint32_t)(NR_CURSEG_TYPE + 2) >> +#define CONFIG_RSVD_DEFAULT_OP_RATIO 3.0 >> + >> enum f2fs_config_func { >> MKFS, >> FSCK, >> @@ -460,6 +464,7 @@ typedef struct { >> #define ALIGN_UP(addrs, size) ALIGN_DOWN(((addrs) + (size) - 1), (size)) >> >> struct f2fs_configuration { >> + uint32_t conf_reserved_sections; >> uint32_t reserved_segments; >> uint32_t new_reserved_segments; >> int sparse_mode; >> @@ -1614,6 +1619,20 @@ extern uint32_t f2fs_get_usable_segments(struct f2fs_super_block *sb); >> #define ZONE_ALIGN(blks) SIZE_ALIGN(blks, c.blks_per_seg * \ >> c.segs_per_zone) >> >> +static inline double get_reserved(struct f2fs_super_block *sb, double ovp) >> +{ >> + double reserved; >> + uint32_t usable_main_segs = f2fs_get_usable_segments(sb); >> + uint32_t segs_per_sec = round_up(usable_main_segs, get_sb(section_count)); >> + >> + if (c.conf_reserved_sections) >> + reserved = c.conf_reserved_sections * segs_per_sec; >> + else >> + reserved = (100 / ovp + 1 + NR_CURSEG_TYPE) * segs_per_sec; >> + >> + return reserved; >> +} >> + >> static inline double get_best_overprovision(struct f2fs_super_block *sb) >> { >> double reserved, ovp, candidate, end, diff, space; >> @@ -1631,8 +1650,7 @@ static inline double get_best_overprovision(struct f2fs_super_block *sb) >> } >> >> for (; candidate <= end; candidate += diff) { >> - reserved = (100 / candidate + 1 + NR_CURSEG_TYPE) * >> - round_up(usable_main_segs, get_sb(section_count)); >> + reserved = get_reserved(sb, candidate); >> ovp = (usable_main_segs - reserved) * candidate / 100; >> if (ovp < 0) >> continue; >> diff --git a/lib/libf2fs.c b/lib/libf2fs.c >> index f63307a42a08..b5644ff6ebdd 100644 >> --- a/lib/libf2fs.c >> +++ b/lib/libf2fs.c >> @@ -1069,6 +1069,28 @@ int get_device_info(int i) >> dev->nr_rnd_zones); >> MSG(0, " %zu blocks per zone\n", >> dev->zone_blocks); >> + if (c.conf_reserved_sections) { >> + if (c.conf_reserved_sections < MIN_RSVD_SECS) { >> + MSG(0, " Too small sections are reserved(%u secs)\n", >> + c.conf_reserved_sections); >> + c.conf_reserved_sections = >> + max(c.conf_reserved_sections, MIN_RSVD_SECS); >> + MSG(0, " It is operated as a minimum reserved sections(%u secs)\n", >> + c.conf_reserved_sections); >> + } else { >> + MSG(0, " %u sections are reserved\n", >> + c.conf_reserved_sections); >> + } >> + if (!c.overprovision) { >> + c.overprovision = CONFIG_RSVD_DEFAULT_OP_RATIO; >> + MSG(0, " Overprovision ratio is set to default(%.1lf%%)\n", >> + c.overprovision); >> + } >> + } else { >> + MSG(0, >> + " 0 reserved sections are received.\n" >> + " Reserved sections are calculating\n"); >> + } >> } >> #endif >> /* adjust wanted_total_sectors */ >> diff --git a/man/mkfs.f2fs.8 b/man/mkfs.f2fs.8 >> index a6249f6ef6ed..800c4c79bf37 100644 >> --- a/man/mkfs.f2fs.8 >> +++ b/man/mkfs.f2fs.8 >> @@ -43,6 +43,7 @@ mkfs.f2fs \- create an F2FS file system >> ] >> [ >> .B \-m >> +.I #-of-reserved-sections >> ] >> [ >> .B \-o >> @@ -152,8 +153,12 @@ Enable extended node bitmap. >> .BI \-l " volume-label" >> Specify the volume label to the partition mounted as F2FS. >> .TP >> -.BI \-m >> -Specify f2fs filesystem to supports the block zoned feature. >> +.BI \-m " #-of-reserved-sections" >> +Specify f2fs filesystem to supports the block zoned feature and reserved sections. >> +If specified to non-zero, reserved segments count is set to the larger size >> +between 8 sections and the input value. If specified to zero, the best number >> +will be assigned automatically according to the partition size. If overprovision-ratio-percentage >> +is not specifed, it will set to default 3.0%. >> Without it, the filesystem doesn't support the feature. >> .TP >> .BI \-o " overprovision-ratio-percentage" >> diff --git a/mkfs/f2fs_format.c b/mkfs/f2fs_format.c >> index f4a49acc498c..22e53be5003d 100644 >> --- a/mkfs/f2fs_format.c >> +++ b/mkfs/f2fs_format.c >> @@ -483,9 +483,7 @@ static int f2fs_prepare_super_block(void) >> if (c.overprovision == 0) >> c.overprovision = get_best_overprovision(sb); >> >> - c.reserved_segments = >> - (100 / c.overprovision + 1 + NR_CURSEG_TYPE) * >> - round_up(f2fs_get_usable_segments(sb), get_sb(section_count)); >> + c.reserved_segments = get_reserved(sb, c.overprovision); >> >> if (c.feature & cpu_to_le32(F2FS_FEATURE_RO)) { >> c.overprovision = 0; >> @@ -765,11 +763,30 @@ static int f2fs_write_check_point_pack(void) >> get_cp(rsvd_segment_count)) * >> c.overprovision / 100); >> >> - if (get_cp(overprov_segment_count) < get_cp(rsvd_segment_count)) >> + if (!(c.conf_reserved_sections) && >> + get_cp(overprov_segment_count) < get_cp(rsvd_segment_count)) >> set_cp(overprov_segment_count, get_cp(rsvd_segment_count)); >> >> - set_cp(overprov_segment_count, get_cp(overprov_segment_count) + >> - 2 * get_sb(segs_per_sec)); >> + /* >> + * If conf_reserved_sections has a non zero value, overprov_segment_count >> + * is set to overprov_segment_count + rsvd_segment_count. >> + */ >> + if (c.conf_reserved_sections) { >> + /* >> + * Overprovision segments must be bigger than two sections. >> + * In non configurable reserved section case, overprovision >> + * segments are always bigger than two sections. >> + */ >> + if (get_cp(overprov_segment_count) < 2 * get_sb(segs_per_sec)) { >> + MSG(0, "\tError: Not enough overprovision segments (%u)\n", >> + get_cp(overprov_segment_count)); >> + goto free_cp_payload; >> + } >> + set_cp(overprov_segment_count, get_cp(overprov_segment_count) + >> + get_cp(rsvd_segment_count)); >> + } else >> + set_cp(overprov_segment_count, get_cp(overprov_segment_count) + >> + 2 * get_sb(segs_per_sec)); >> >> if (f2fs_get_usable_segments(sb) <= get_cp(overprov_segment_count)) { >> MSG(0, "\tError: Not enough segments to create F2FS Volume\n"); >> diff --git a/mkfs/f2fs_format_main.c b/mkfs/f2fs_format_main.c >> index f50971c4591c..a4accda91780 100644 >> --- a/mkfs/f2fs_format_main.c >> +++ b/mkfs/f2fs_format_main.c >> @@ -61,7 +61,7 @@ static void mkfs_usage() >> MSG(0, " -i extended node bitmap, node ratio is 20%% by default\n"); >> MSG(0, " -l label\n"); >> MSG(0, " -U uuid\n"); >> - MSG(0, " -m support zoned block device [default:0]\n"); >> + MSG(0, " -m support zoned block device, # of reserved sections [default:0]\n"); >> MSG(0, " -o overprovision percentage [default:auto]\n"); >> MSG(0, " -O feature1[,feature2,...] e.g. \"encrypt\"\n"); >> MSG(0, " -C [encoding[:flag1,...]] Support casefolding with optional flags\n"); >> @@ -176,7 +176,7 @@ static void add_default_options(void) >> >> static void f2fs_parse_options(int argc, char *argv[]) >> { >> - static const char *option_string = "qa:c:C:d:e:E:g:hil:mo:O:rR:s:S:z:t:T:U:Vfw:"; >> + static const char *option_string = "qa:c:C:d:e:E:g:hil:m:o:O:rR:s:S:z:t:T:U:Vfw:"; >> static const struct option long_opts[] = { >> { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, >> { .name = NULL, .has_arg = 0, .flag = NULL, .val = 0 } >> @@ -235,6 +235,7 @@ static void f2fs_parse_options(int argc, char *argv[]) >> break; >> case 'm': >> c.zoned_mode = 1; >> + c.conf_reserved_sections = atoi(optarg); > >This breaks the existing "-m" option. Can you address to support that? > Ok, we're gonna change it to new letter "-Z". The option is valid only when "-m" is specified. Thanks for your review >> break; >> case 'o': >> c.overprovision = atof(optarg); >> -- >> 2.34.1
diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h index 333ae07a5ebd..1d41e9f8397e 100644 --- a/include/f2fs_fs.h +++ b/include/f2fs_fs.h @@ -375,6 +375,10 @@ static inline uint64_t bswap_64(uint64_t val) #define LPF "lost+found" +/* one for gc buffer, the other for node */ +#define MIN_RSVD_SECS (uint32_t)(NR_CURSEG_TYPE + 2) +#define CONFIG_RSVD_DEFAULT_OP_RATIO 3.0 + enum f2fs_config_func { MKFS, FSCK, @@ -460,6 +464,7 @@ typedef struct { #define ALIGN_UP(addrs, size) ALIGN_DOWN(((addrs) + (size) - 1), (size)) struct f2fs_configuration { + uint32_t conf_reserved_sections; uint32_t reserved_segments; uint32_t new_reserved_segments; int sparse_mode; @@ -1614,6 +1619,20 @@ extern uint32_t f2fs_get_usable_segments(struct f2fs_super_block *sb); #define ZONE_ALIGN(blks) SIZE_ALIGN(blks, c.blks_per_seg * \ c.segs_per_zone) +static inline double get_reserved(struct f2fs_super_block *sb, double ovp) +{ + double reserved; + uint32_t usable_main_segs = f2fs_get_usable_segments(sb); + uint32_t segs_per_sec = round_up(usable_main_segs, get_sb(section_count)); + + if (c.conf_reserved_sections) + reserved = c.conf_reserved_sections * segs_per_sec; + else + reserved = (100 / ovp + 1 + NR_CURSEG_TYPE) * segs_per_sec; + + return reserved; +} + static inline double get_best_overprovision(struct f2fs_super_block *sb) { double reserved, ovp, candidate, end, diff, space; @@ -1631,8 +1650,7 @@ static inline double get_best_overprovision(struct f2fs_super_block *sb) } for (; candidate <= end; candidate += diff) { - reserved = (100 / candidate + 1 + NR_CURSEG_TYPE) * - round_up(usable_main_segs, get_sb(section_count)); + reserved = get_reserved(sb, candidate); ovp = (usable_main_segs - reserved) * candidate / 100; if (ovp < 0) continue; diff --git a/lib/libf2fs.c b/lib/libf2fs.c index f63307a42a08..b5644ff6ebdd 100644 --- a/lib/libf2fs.c +++ b/lib/libf2fs.c @@ -1069,6 +1069,28 @@ int get_device_info(int i) dev->nr_rnd_zones); MSG(0, " %zu blocks per zone\n", dev->zone_blocks); + if (c.conf_reserved_sections) { + if (c.conf_reserved_sections < MIN_RSVD_SECS) { + MSG(0, " Too small sections are reserved(%u secs)\n", + c.conf_reserved_sections); + c.conf_reserved_sections = + max(c.conf_reserved_sections, MIN_RSVD_SECS); + MSG(0, " It is operated as a minimum reserved sections(%u secs)\n", + c.conf_reserved_sections); + } else { + MSG(0, " %u sections are reserved\n", + c.conf_reserved_sections); + } + if (!c.overprovision) { + c.overprovision = CONFIG_RSVD_DEFAULT_OP_RATIO; + MSG(0, " Overprovision ratio is set to default(%.1lf%%)\n", + c.overprovision); + } + } else { + MSG(0, + " 0 reserved sections are received.\n" + " Reserved sections are calculating\n"); + } } #endif /* adjust wanted_total_sectors */ diff --git a/man/mkfs.f2fs.8 b/man/mkfs.f2fs.8 index a6249f6ef6ed..800c4c79bf37 100644 --- a/man/mkfs.f2fs.8 +++ b/man/mkfs.f2fs.8 @@ -43,6 +43,7 @@ mkfs.f2fs \- create an F2FS file system ] [ .B \-m +.I #-of-reserved-sections ] [ .B \-o @@ -152,8 +153,12 @@ Enable extended node bitmap. .BI \-l " volume-label" Specify the volume label to the partition mounted as F2FS. .TP -.BI \-m -Specify f2fs filesystem to supports the block zoned feature. +.BI \-m " #-of-reserved-sections" +Specify f2fs filesystem to supports the block zoned feature and reserved sections. +If specified to non-zero, reserved segments count is set to the larger size +between 8 sections and the input value. If specified to zero, the best number +will be assigned automatically according to the partition size. If overprovision-ratio-percentage +is not specifed, it will set to default 3.0%. Without it, the filesystem doesn't support the feature. .TP .BI \-o " overprovision-ratio-percentage" diff --git a/mkfs/f2fs_format.c b/mkfs/f2fs_format.c index f4a49acc498c..22e53be5003d 100644 --- a/mkfs/f2fs_format.c +++ b/mkfs/f2fs_format.c @@ -483,9 +483,7 @@ static int f2fs_prepare_super_block(void) if (c.overprovision == 0) c.overprovision = get_best_overprovision(sb); - c.reserved_segments = - (100 / c.overprovision + 1 + NR_CURSEG_TYPE) * - round_up(f2fs_get_usable_segments(sb), get_sb(section_count)); + c.reserved_segments = get_reserved(sb, c.overprovision); if (c.feature & cpu_to_le32(F2FS_FEATURE_RO)) { c.overprovision = 0; @@ -765,11 +763,30 @@ static int f2fs_write_check_point_pack(void) get_cp(rsvd_segment_count)) * c.overprovision / 100); - if (get_cp(overprov_segment_count) < get_cp(rsvd_segment_count)) + if (!(c.conf_reserved_sections) && + get_cp(overprov_segment_count) < get_cp(rsvd_segment_count)) set_cp(overprov_segment_count, get_cp(rsvd_segment_count)); - set_cp(overprov_segment_count, get_cp(overprov_segment_count) + - 2 * get_sb(segs_per_sec)); + /* + * If conf_reserved_sections has a non zero value, overprov_segment_count + * is set to overprov_segment_count + rsvd_segment_count. + */ + if (c.conf_reserved_sections) { + /* + * Overprovision segments must be bigger than two sections. + * In non configurable reserved section case, overprovision + * segments are always bigger than two sections. + */ + if (get_cp(overprov_segment_count) < 2 * get_sb(segs_per_sec)) { + MSG(0, "\tError: Not enough overprovision segments (%u)\n", + get_cp(overprov_segment_count)); + goto free_cp_payload; + } + set_cp(overprov_segment_count, get_cp(overprov_segment_count) + + get_cp(rsvd_segment_count)); + } else + set_cp(overprov_segment_count, get_cp(overprov_segment_count) + + 2 * get_sb(segs_per_sec)); if (f2fs_get_usable_segments(sb) <= get_cp(overprov_segment_count)) { MSG(0, "\tError: Not enough segments to create F2FS Volume\n"); diff --git a/mkfs/f2fs_format_main.c b/mkfs/f2fs_format_main.c index f50971c4591c..a4accda91780 100644 --- a/mkfs/f2fs_format_main.c +++ b/mkfs/f2fs_format_main.c @@ -61,7 +61,7 @@ static void mkfs_usage() MSG(0, " -i extended node bitmap, node ratio is 20%% by default\n"); MSG(0, " -l label\n"); MSG(0, " -U uuid\n"); - MSG(0, " -m support zoned block device [default:0]\n"); + MSG(0, " -m support zoned block device, # of reserved sections [default:0]\n"); MSG(0, " -o overprovision percentage [default:auto]\n"); MSG(0, " -O feature1[,feature2,...] e.g. \"encrypt\"\n"); MSG(0, " -C [encoding[:flag1,...]] Support casefolding with optional flags\n"); @@ -176,7 +176,7 @@ static void add_default_options(void) static void f2fs_parse_options(int argc, char *argv[]) { - static const char *option_string = "qa:c:C:d:e:E:g:hil:mo:O:rR:s:S:z:t:T:U:Vfw:"; + static const char *option_string = "qa:c:C:d:e:E:g:hil:m:o:O:rR:s:S:z:t:T:U:Vfw:"; static const struct option long_opts[] = { { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, { .name = NULL, .has_arg = 0, .flag = NULL, .val = 0 } @@ -235,6 +235,7 @@ static void f2fs_parse_options(int argc, char *argv[]) break; case 'm': c.zoned_mode = 1; + c.conf_reserved_sections = atoi(optarg); break; case 'o': c.overprovision = atof(optarg);
Overview ======== This option allows zoned block device users to configure GC reserved and overprovision area manually according to their demands on performance of sustained write latency and WAF. Problem ======= The overprovision segments that mkfs generates are mostly occupied by GC reserved. This degrades WAF performance. Experiment ========== The following experiment evaluated the application of configurable reserved. The experimental environment is as follows. System info - 4.2Ghz, 8 core CPU - 64GiB Memory Device info - a conventional null_blk with 448MiB capacity(meta area) and - a sequential null_blk with 953 zones of 64MiB Format - as-is (find out ovp ratio): mkfs.f2fs <conv null_blk> -c <seq null_blk> -m Info: Overprovision ratio = 3.700% Info: Overprovision segments = 1152 (GC reserved = 1088) - config rsvd: mkfs.f2fs <conv null_blk> -c <seq null_blk> -m 8 -o 2.965 Info: Overprovision ratio = 2.965% Info: Overprovision segments = 1152 (GC reserved = 256) Mount - mount <conv null_blk> <mount point> Fio script - fio --rw=randwrite --bs=4k --ba=4k --filesize=58630m --norandommap --overwrite=1 --name=job1 --filename=<mount point>/sustain --time_based --runtime=2h WAF calculation - (IOs on conv. null_blk + IOs on seq. null_blk) / random write IOs Conclusion ========== In the experiment, it can be shown that reducing the reserved segments decreases WAF to 10% (from 222 to 23) although it triggers checkpoint more frequently during gc. With direct IO, the WAF of as-is gets much higher. In other words, a user can configure more reserved segments for lower GC latency or allocate less reserved segments for lower WAF on the same number of OP segments. Signed-off-by: Yonggil Song <yonggil.song@samsung.com> --- include/f2fs_fs.h | 22 ++++++++++++++++++++-- lib/libf2fs.c | 22 ++++++++++++++++++++++ man/mkfs.f2fs.8 | 9 +++++++-- mkfs/f2fs_format.c | 29 +++++++++++++++++++++++------ mkfs/f2fs_format_main.c | 5 +++-- 5 files changed, 75 insertions(+), 12 deletions(-)