diff options
author | Yonggil Song <yonggil.song@samsung.com> | 2023-04-04 15:21:03 +0900 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk@kernel.org> | 2023-04-11 10:16:12 -0700 |
commit | 03aa49e4959fc986d87cfa3cef9a8ccd4aabdb74 (patch) | |
tree | 230941e1a5f53fb98846342a56be32513408954c | |
parent | 06c027abc6153c4a97cba5317844e8dcaaee3cf7 (diff) | |
download | f2fs-tools-03aa49e4959fc986d87cfa3cef9a8ccd4aabdb74.tar.gz |
mkfs.f2fs: Introduce configurable reserved sections
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 -Z 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>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-rw-r--r-- | include/f2fs_fs.h | 22 | ||||
-rw-r--r-- | lib/libf2fs.c | 18 | ||||
-rw-r--r-- | man/mkfs.f2fs.8 | 12 | ||||
-rw-r--r-- | mkfs/f2fs_format.c | 30 | ||||
-rw-r--r-- | mkfs/f2fs_format_main.c | 11 |
5 files changed, 84 insertions, 9 deletions
diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h index f890634..6948814 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 (NR_CURSEG_TYPE + 2U) +#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; @@ -1618,6 +1623,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; @@ -1635,8 +1654,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 93b0604..6b879f9 100644 --- a/lib/libf2fs.c +++ b/lib/libf2fs.c @@ -1066,6 +1066,24 @@ 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 = 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); + } + } } #endif /* adjust wanted_total_sectors */ diff --git a/man/mkfs.f2fs.8 b/man/mkfs.f2fs.8 index a6249f6..474c401 100644 --- a/man/mkfs.f2fs.8 +++ b/man/mkfs.f2fs.8 @@ -92,6 +92,10 @@ mkfs.f2fs \- create an F2FS file system [ .B \-V ] +[ +.B \-Z +.I #-of-reserved-sections +] .I device .I [sectors] .SH DESCRIPTION @@ -265,6 +269,14 @@ Number of sectors. Default is determined by device size. .BI \-V Print the version number and exit. .TP +.BI \-Z " #-of-reserved-sections" +Specify the number of GC reserved sections for zoned device. 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 specified, it will set to default +3.0%. Without '-m' option, the filesystem doesn't support the feature. +.TP .BI \-h,\ \-\-help Print usage and exit. .SH AUTHOR diff --git a/mkfs/f2fs_format.c b/mkfs/f2fs_format.c index f4a49ac..d3bb622 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,31 @@ 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 f50971c..07995b3 100644 --- a/mkfs/f2fs_format_main.c +++ b/mkfs/f2fs_format_main.c @@ -75,6 +75,7 @@ static void mkfs_usage() MSG(0, " -w wanted sector size\n"); MSG(0, " -z # of sections per zone [default:1]\n"); MSG(0, " -V print the version number and exit\n"); + MSG(0, " -Z # of reserved sections [default:auto]\n"); MSG(0, "sectors: number of sectors [default: determined by device size]\n"); exit(1); } @@ -176,7 +177,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:mo:O:rR:s:S:z:t:T:U:Vfw:Z:"; static const struct option long_opts[] = { { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, { .name = NULL, .has_arg = 0, .flag = NULL, .val = 0 } @@ -295,6 +296,9 @@ static void f2fs_parse_options(int argc, char *argv[]) } c.feature |= cpu_to_le32(F2FS_FEATURE_CASEFOLD); break; + case 'Z': + c.conf_reserved_sections = atoi(optarg); + break; default: MSG(0, "\tError: Unknown option %c\n",option); mkfs_usage(); @@ -490,6 +494,11 @@ int main(int argc, char *argv[]) goto err_format; } + if (c.conf_reserved_sections && !c.zoned_mode) { + MSG(0, "\tError: Reserved area can't be specified on non zoned device\n"); + goto err_format; + } + if (f2fs_format_device() < 0) goto err_format; |