Skip to content

Commit 2dda093

Browse files
chaseyugregkh
authored andcommitted
f2fs: fix to avoid panic once fallocation fails for pinfile
[ Upstream commit 48ea8b2 ] syzbot reports a f2fs bug as below: ------------[ cut here ]------------ kernel BUG at fs/f2fs/segment.c:2746! CPU: 0 UID: 0 PID: 5323 Comm: syz.0.0 Not tainted 6.13.0-rc2-syzkaller-00018-g7cb1b4663150 #0 RIP: 0010:get_new_segment fs/f2fs/segment.c:2746 [inline] RIP: 0010:new_curseg+0x1f52/0x1f70 fs/f2fs/segment.c:2876 Call Trace: <TASK> __allocate_new_segment+0x1ce/0x940 fs/f2fs/segment.c:3210 f2fs_allocate_new_section fs/f2fs/segment.c:3224 [inline] f2fs_allocate_pinning_section+0xfa/0x4e0 fs/f2fs/segment.c:3238 f2fs_expand_inode_data+0x696/0xca0 fs/f2fs/file.c:1830 f2fs_fallocate+0x537/0xa10 fs/f2fs/file.c:1940 vfs_fallocate+0x569/0x6e0 fs/open.c:327 do_vfs_ioctl+0x258c/0x2e40 fs/ioctl.c:885 __do_sys_ioctl fs/ioctl.c:904 [inline] __se_sys_ioctl+0x80/0x170 fs/ioctl.c:892 do_syscall_x64 arch/x86/entry/common.c:52 [inline] do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83 entry_SYSCALL_64_after_hwframe+0x77/0x7f Concurrent pinfile allocation may run out of free section, result in panic in get_new_segment(), let's expand pin_sem lock coverage to include f2fs_gc(), so that we can make sure to reclaim enough free space for following allocation. In addition, do below changes to enhance error path handling: - call f2fs_bug_on() only in non-pinfile allocation path in get_new_segment(). - call reset_curseg_fields() to reset all fields of curseg in new_curseg() Fixes: f5a53ed ("f2fs: support aligned pinned file") Reported-by: syzbot+15669ec8c35ddf6c3d43@syzkaller.appspotmail.com Closes: https://lore.kernel.org/linux-f2fs-devel/675cd64e.050a0220.37aaf.00bb.GAE@google.com Signed-off-by: Chao Yu <chao@kernel.org> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org> Signed-off-by: Rajani Kantha <681739313@139.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent bdb0e04 commit 2dda093

File tree

2 files changed

+15
-13
lines changed

2 files changed

+15
-13
lines changed

fs/f2fs/file.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1836,18 +1836,20 @@ static int f2fs_expand_inode_data(struct inode *inode, loff_t offset,
18361836

18371837
map.m_len = sec_blks;
18381838
next_alloc:
1839+
f2fs_down_write(&sbi->pin_sem);
1840+
18391841
if (has_not_enough_free_secs(sbi, 0, f2fs_sb_has_blkzoned(sbi) ?
18401842
ZONED_PIN_SEC_REQUIRED_COUNT :
18411843
GET_SEC_FROM_SEG(sbi, overprovision_segments(sbi)))) {
18421844
f2fs_down_write(&sbi->gc_lock);
18431845
stat_inc_gc_call_count(sbi, FOREGROUND);
18441846
err = f2fs_gc(sbi, &gc_control);
1845-
if (err && err != -ENODATA)
1847+
if (err && err != -ENODATA) {
1848+
f2fs_up_write(&sbi->pin_sem);
18461849
goto out_err;
1850+
}
18471851
}
18481852

1849-
f2fs_down_write(&sbi->pin_sem);
1850-
18511853
err = f2fs_allocate_pinning_section(sbi);
18521854
if (err) {
18531855
f2fs_up_write(&sbi->pin_sem);

fs/f2fs/segment.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2749,7 +2749,7 @@ static int get_new_segment(struct f2fs_sb_info *sbi,
27492749
MAIN_SECS(sbi));
27502750
if (secno >= MAIN_SECS(sbi)) {
27512751
ret = -ENOSPC;
2752-
f2fs_bug_on(sbi, 1);
2752+
f2fs_bug_on(sbi, !pinning);
27532753
goto out_unlock;
27542754
}
27552755
}
@@ -2795,7 +2795,7 @@ static int get_new_segment(struct f2fs_sb_info *sbi,
27952795
out_unlock:
27962796
spin_unlock(&free_i->segmap_lock);
27972797

2798-
if (ret == -ENOSPC)
2798+
if (ret == -ENOSPC && !pinning)
27992799
f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_NO_SEGMENT);
28002800
return ret;
28012801
}
@@ -2868,6 +2868,13 @@ static unsigned int __get_next_segno(struct f2fs_sb_info *sbi, int type)
28682868
return curseg->segno;
28692869
}
28702870

2871+
static void reset_curseg_fields(struct curseg_info *curseg)
2872+
{
2873+
curseg->inited = false;
2874+
curseg->segno = NULL_SEGNO;
2875+
curseg->next_segno = 0;
2876+
}
2877+
28712878
/*
28722879
* Allocate a current working segment.
28732880
* This function always allocates a free segment in LFS manner.
@@ -2886,7 +2893,7 @@ static int new_curseg(struct f2fs_sb_info *sbi, int type, bool new_sec)
28862893
ret = get_new_segment(sbi, &segno, new_sec, pinning);
28872894
if (ret) {
28882895
if (ret == -ENOSPC)
2889-
curseg->segno = NULL_SEGNO;
2896+
reset_curseg_fields(curseg);
28902897
return ret;
28912898
}
28922899

@@ -3640,13 +3647,6 @@ static void f2fs_randomize_chunk(struct f2fs_sb_info *sbi,
36403647
get_random_u32_inclusive(1, sbi->max_fragment_hole);
36413648
}
36423649

3643-
static void reset_curseg_fields(struct curseg_info *curseg)
3644-
{
3645-
curseg->inited = false;
3646-
curseg->segno = NULL_SEGNO;
3647-
curseg->next_segno = 0;
3648-
}
3649-
36503650
int f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
36513651
block_t old_blkaddr, block_t *new_blkaddr,
36523652
struct f2fs_summary *sum, int type,

0 commit comments

Comments
 (0)