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 <[email protected]>
>> ---
>>  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


_______________________________________________
Linux-f2fs-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

Reply via email to