Skip to content

Commit 300a842

Browse files
chaseyuJaegeuk Kim
authored andcommitted
f2fs: fix to reserve space for IO align feature
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 --- Core dump --- Call Trace: allocate_segment_by_default+0x9d/0x100 [f2fs] f2fs_allocate_data_block+0x3c0/0x5c0 [f2fs] do_write_page+0x62/0x110 [f2fs] f2fs_outplace_write_data+0x43/0xc0 [f2fs] f2fs_do_write_data_page+0x386/0x560 [f2fs] __write_data_page+0x706/0x850 [f2fs] f2fs_write_cache_pages+0x267/0x6a0 [f2fs] f2fs_write_data_pages+0x19c/0x2e0 [f2fs] do_writepages+0x1c/0x70 __filemap_fdatawrite_range+0xaa/0xe0 filemap_fdatawrite+0x1f/0x30 f2fs_sync_dirty_inodes+0x74/0x1f0 [f2fs] block_operations+0xdc/0x350 [f2fs] f2fs_write_checkpoint+0x104/0x1150 [f2fs] f2fs_sync_fs+0xa2/0x120 [f2fs] f2fs_balance_fs_bg+0x33c/0x390 [f2fs] f2fs_write_node_pages+0x4c/0x1f0 [f2fs] do_writepages+0x1c/0x70 __writeback_single_inode+0x45/0x320 writeback_sb_inodes+0x273/0x5c0 wb_writeback+0xff/0x2e0 wb_workfn+0xa1/0x370 process_one_work+0x138/0x350 worker_thread+0x4d/0x3d0 kthread+0x109/0x140 ret_from_fork+0x25/0x30 The root cause here is, with IO alignment feature enables, in worst case, we need F2FS_IO_SIZE() free blocks space for single one 4k write due to IO alignment feature will fill dummy pages to make IO being aligned. So we will easily run out of free segments during non-inline directory's data writeback, even in process of foreground GC. In order to fix this issue, I just propose to reserve additional free space for IO alignment feature to handle worst case of free space usage ratio during FGGC. Fixes: 0a595eb ("f2fs: support IO alignment for DATA and NODE writes") Signed-off-by: Chao Yu <chao@kernel.org> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
1 parent b702c83 commit 300a842

File tree

4 files changed

+60
-2
lines changed

4 files changed

+60
-2
lines changed

fs/f2fs/f2fs.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,6 +1024,7 @@ struct f2fs_sm_info {
10241024
unsigned int segment_count; /* total # of segments */
10251025
unsigned int main_segments; /* # of segments in main area */
10261026
unsigned int reserved_segments; /* # of reserved segments */
1027+
unsigned int additional_reserved_segments;/* reserved segs for IO align feature */
10271028
unsigned int ovp_segments; /* # of overprovision segments */
10281029

10291030
/* a threshold to reclaim prefree segments */
@@ -2205,6 +2206,11 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
22052206

22062207
if (!__allow_reserved_blocks(sbi, inode, true))
22072208
avail_user_block_count -= F2FS_OPTION(sbi).root_reserved_blocks;
2209+
2210+
if (F2FS_IO_ALIGNED(sbi))
2211+
avail_user_block_count -= sbi->blocks_per_seg *
2212+
SM_I(sbi)->additional_reserved_segments;
2213+
22082214
if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) {
22092215
if (avail_user_block_count > sbi->unusable_block_count)
22102216
avail_user_block_count -= sbi->unusable_block_count;
@@ -2451,6 +2457,11 @@ static inline int inc_valid_node_count(struct f2fs_sb_info *sbi,
24512457

24522458
if (!__allow_reserved_blocks(sbi, inode, false))
24532459
valid_block_count += F2FS_OPTION(sbi).root_reserved_blocks;
2460+
2461+
if (F2FS_IO_ALIGNED(sbi))
2462+
valid_block_count += sbi->blocks_per_seg *
2463+
SM_I(sbi)->additional_reserved_segments;
2464+
24542465
user_block_count = sbi->user_block_count;
24552466
if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED)))
24562467
user_block_count -= sbi->unusable_block_count;

fs/f2fs/segment.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,8 @@ static inline unsigned int free_segments(struct f2fs_sb_info *sbi)
538538

539539
static inline unsigned int reserved_segments(struct f2fs_sb_info *sbi)
540540
{
541-
return SM_I(sbi)->reserved_segments;
541+
return SM_I(sbi)->reserved_segments +
542+
SM_I(sbi)->additional_reserved_segments;
542543
}
543544

544545
static inline unsigned int free_sections(struct f2fs_sb_info *sbi)

fs/f2fs/super.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,46 @@ static inline void limit_reserve_root(struct f2fs_sb_info *sbi)
329329
F2FS_OPTION(sbi).s_resgid));
330330
}
331331

332+
static inline int adjust_reserved_segment(struct f2fs_sb_info *sbi)
333+
{
334+
unsigned int sec_blks = sbi->blocks_per_seg * sbi->segs_per_sec;
335+
unsigned int avg_vblocks;
336+
unsigned int wanted_reserved_segments;
337+
block_t avail_user_block_count;
338+
339+
if (!F2FS_IO_ALIGNED(sbi))
340+
return 0;
341+
342+
/* average valid block count in section in worst case */
343+
avg_vblocks = sec_blks / F2FS_IO_SIZE(sbi);
344+
345+
/*
346+
* we need enough free space when migrating one section in worst case
347+
*/
348+
wanted_reserved_segments = (F2FS_IO_SIZE(sbi) / avg_vblocks) *
349+
reserved_segments(sbi);
350+
wanted_reserved_segments -= reserved_segments(sbi);
351+
352+
avail_user_block_count = sbi->user_block_count -
353+
sbi->current_reserved_blocks -
354+
F2FS_OPTION(sbi).root_reserved_blocks;
355+
356+
if (wanted_reserved_segments * sbi->blocks_per_seg >
357+
avail_user_block_count) {
358+
f2fs_err(sbi, "IO align feature can't grab additional reserved segment: %u, available segments: %u",
359+
wanted_reserved_segments,
360+
avail_user_block_count >> sbi->log_blocks_per_seg);
361+
return -ENOSPC;
362+
}
363+
364+
SM_I(sbi)->additional_reserved_segments = wanted_reserved_segments;
365+
366+
f2fs_info(sbi, "IO align feature needs additional reserved segment: %u",
367+
wanted_reserved_segments);
368+
369+
return 0;
370+
}
371+
332372
static inline void adjust_unusable_cap_perc(struct f2fs_sb_info *sbi)
333373
{
334374
if (!F2FS_OPTION(sbi).unusable_cap_perc)
@@ -4182,6 +4222,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
41824222
goto free_nm;
41834223
}
41844224

4225+
err = adjust_reserved_segment(sbi);
4226+
if (err)
4227+
goto free_nm;
4228+
41854229
/* For write statistics */
41864230
sbi->sectors_written_start = f2fs_get_sectors_written(sbi);
41874231

fs/f2fs/sysfs.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,9 @@ static ssize_t __sbi_store(struct f2fs_attr *a,
424424
if (a->struct_type == RESERVED_BLOCKS) {
425425
spin_lock(&sbi->stat_lock);
426426
if (t > (unsigned long)(sbi->user_block_count -
427-
F2FS_OPTION(sbi).root_reserved_blocks)) {
427+
F2FS_OPTION(sbi).root_reserved_blocks -
428+
sbi->blocks_per_seg *
429+
SM_I(sbi)->additional_reserved_segments)) {
428430
spin_unlock(&sbi->stat_lock);
429431
return -EINVAL;
430432
}

0 commit comments

Comments
 (0)