lkml.org 
[lkml]   [2022]   [Jan]   [24]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.16 0957/1039] f2fs: fix to reserve space for IO align feature
    Date
    From: Chao Yu <chao@kernel.org>

    commit 300a842937fbcfb5a189cea9ba15374fdb0b5c6b upstream.

    https://bugzilla.kernel.org/show_bug.cgi?id=204137

    With below script, we will hit panic during new segment allocation:

    DISK=bingo.img
    MOUNT_DIR=/mnt/f2fs

    dd if=/dev/zero of=$DISK bs=1M count=105
    mkfs.f2fe -a 1 -o 19 -t 1 -z 1 -f -q $DISK

    mount -t f2fs $DISK $MOUNT_DIR -o "noinline_dentry,flush_merge,noextent_cache,mode=lfs,io_bits=7,fsync_mode=strict"

    for (( i = 0; i < 4096; i++ )); do
    name=`head /dev/urandom | tr -dc A-Za-z0-9 | head -c 10`
    mkdir $MOUNT_DIR/$name
    done

    umount $MOUNT_DIR
    rm $DISK

    ---
    fs/f2fs/f2fs.h | 11 +++++++++++
    fs/f2fs/segment.h | 3 ++-
    fs/f2fs/super.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
    fs/f2fs/sysfs.c | 4 +++-
    4 files changed, 60 insertions(+), 2 deletions(-)

    --- a/fs/f2fs/f2fs.h
    +++ b/fs/f2fs/f2fs.h
    @@ -1018,6 +1018,7 @@ struct f2fs_sm_info {
    unsigned int segment_count; /* total # of segments */
    unsigned int main_segments; /* # of segments in main area */
    unsigned int reserved_segments; /* # of reserved segments */
    + unsigned int additional_reserved_segments;/* reserved segs for IO align feature */
    unsigned int ovp_segments; /* # of overprovision segments */

    /* a threshold to reclaim prefree segments */
    @@ -2198,6 +2199,11 @@ static inline int inc_valid_block_count(

    if (!__allow_reserved_blocks(sbi, inode, true))
    avail_user_block_count -= F2FS_OPTION(sbi).root_reserved_blocks;
    +
    + if (F2FS_IO_ALIGNED(sbi))
    + avail_user_block_count -= sbi->blocks_per_seg *
    + SM_I(sbi)->additional_reserved_segments;
    +
    if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) {
    if (avail_user_block_count > sbi->unusable_block_count)
    avail_user_block_count -= sbi->unusable_block_count;
    @@ -2444,6 +2450,11 @@ static inline int inc_valid_node_count(s

    if (!__allow_reserved_blocks(sbi, inode, false))
    valid_block_count += F2FS_OPTION(sbi).root_reserved_blocks;
    +
    + if (F2FS_IO_ALIGNED(sbi))
    + valid_block_count += sbi->blocks_per_seg *
    + SM_I(sbi)->additional_reserved_segments;
    +
    user_block_count = sbi->user_block_count;
    if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED)))
    user_block_count -= sbi->unusable_block_count;
    --- a/fs/f2fs/segment.h
    +++ b/fs/f2fs/segment.h
    @@ -538,7 +538,8 @@ static inline unsigned int free_segments

    static inline unsigned int reserved_segments(struct f2fs_sb_info *sbi)
    {
    - return SM_I(sbi)->reserved_segments;
    + return SM_I(sbi)->reserved_segments +
    + SM_I(sbi)->additional_reserved_segments;
    }

    static inline unsigned int free_sections(struct f2fs_sb_info *sbi)
    --- a/fs/f2fs/super.c
    +++ b/fs/f2fs/super.c
    @@ -328,6 +328,46 @@ static inline void limit_reserve_root(st
    F2FS_OPTION(sbi).s_resgid));
    }

    +static inline int adjust_reserved_segment(struct f2fs_sb_info *sbi)
    +{
    + unsigned int sec_blks = sbi->blocks_per_seg * sbi->segs_per_sec;
    + unsigned int avg_vblocks;
    + unsigned int wanted_reserved_segments;
    + block_t avail_user_block_count;
    +
    + if (!F2FS_IO_ALIGNED(sbi))
    + return 0;
    +
    + /* average valid block count in section in worst case */
    + avg_vblocks = sec_blks / F2FS_IO_SIZE(sbi);
    +
    + /*
    + * we need enough free space when migrating one section in worst case
    + */
    + wanted_reserved_segments = (F2FS_IO_SIZE(sbi) / avg_vblocks) *
    + reserved_segments(sbi);
    + wanted_reserved_segments -= reserved_segments(sbi);
    +
    + avail_user_block_count = sbi->user_block_count -
    + sbi->current_reserved_blocks -
    + F2FS_OPTION(sbi).root_reserved_blocks;
    +
    + if (wanted_reserved_segments * sbi->blocks_per_seg >
    + avail_user_block_count) {
    + f2fs_err(sbi, "IO align feature can't grab additional reserved segment: %u, available segments: %u",
    + wanted_reserved_segments,
    + avail_user_block_count >> sbi->log_blocks_per_seg);
    + return -ENOSPC;
    + }
    +
    + SM_I(sbi)->additional_reserved_segments = wanted_reserved_segments;
    +
    + f2fs_info(sbi, "IO align feature needs additional reserved segment: %u",
    + wanted_reserved_segments);
    +
    + return 0;
    +}
    +
    static inline void adjust_unusable_cap_perc(struct f2fs_sb_info *sbi)
    {
    if (!F2FS_OPTION(sbi).unusable_cap_perc)
    @@ -4180,6 +4220,10 @@ try_onemore:
    goto free_nm;
    }

    + err = adjust_reserved_segment(sbi);
    + if (err)
    + goto free_nm;
    +
    /* For write statistics */
    sbi->sectors_written_start = f2fs_get_sectors_written(sbi);

    --- a/fs/f2fs/sysfs.c
    +++ b/fs/f2fs/sysfs.c
    @@ -415,7 +415,9 @@ out:
    if (a->struct_type == RESERVED_BLOCKS) {
    spin_lock(&sbi->stat_lock);
    if (t > (unsigned long)(sbi->user_block_count -
    - F2FS_OPTION(sbi).root_reserved_blocks)) {
    + F2FS_OPTION(sbi).root_reserved_blocks -
    + sbi->blocks_per_seg *
    + SM_I(sbi)->additional_reserved_segments)) {
    spin_unlock(&sbi->stat_lock);
    return -EINVAL;
    }

    \
     
     \ /
      Last update: 2022-01-25 00:11    [W:4.026 / U:0.040 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site