mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 10:00:17 +00:00
f2fs: fix to avoid panic once fallocation fails for pinfile
[ Upstream commit48ea8b2004] 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:f5a53edcf0("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>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
bdb0e04154
commit
2dda0930fb
@@ -1836,18 +1836,20 @@ static int f2fs_expand_inode_data(struct inode *inode, loff_t offset,
|
||||
|
||||
map.m_len = sec_blks;
|
||||
next_alloc:
|
||||
f2fs_down_write(&sbi->pin_sem);
|
||||
|
||||
if (has_not_enough_free_secs(sbi, 0, f2fs_sb_has_blkzoned(sbi) ?
|
||||
ZONED_PIN_SEC_REQUIRED_COUNT :
|
||||
GET_SEC_FROM_SEG(sbi, overprovision_segments(sbi)))) {
|
||||
f2fs_down_write(&sbi->gc_lock);
|
||||
stat_inc_gc_call_count(sbi, FOREGROUND);
|
||||
err = f2fs_gc(sbi, &gc_control);
|
||||
if (err && err != -ENODATA)
|
||||
if (err && err != -ENODATA) {
|
||||
f2fs_up_write(&sbi->pin_sem);
|
||||
goto out_err;
|
||||
}
|
||||
}
|
||||
|
||||
f2fs_down_write(&sbi->pin_sem);
|
||||
|
||||
err = f2fs_allocate_pinning_section(sbi);
|
||||
if (err) {
|
||||
f2fs_up_write(&sbi->pin_sem);
|
||||
|
||||
@@ -2749,7 +2749,7 @@ find_other_zone:
|
||||
MAIN_SECS(sbi));
|
||||
if (secno >= MAIN_SECS(sbi)) {
|
||||
ret = -ENOSPC;
|
||||
f2fs_bug_on(sbi, 1);
|
||||
f2fs_bug_on(sbi, !pinning);
|
||||
goto out_unlock;
|
||||
}
|
||||
}
|
||||
@@ -2795,7 +2795,7 @@ got_it:
|
||||
out_unlock:
|
||||
spin_unlock(&free_i->segmap_lock);
|
||||
|
||||
if (ret == -ENOSPC)
|
||||
if (ret == -ENOSPC && !pinning)
|
||||
f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_NO_SEGMENT);
|
||||
return ret;
|
||||
}
|
||||
@@ -2868,6 +2868,13 @@ static unsigned int __get_next_segno(struct f2fs_sb_info *sbi, int type)
|
||||
return curseg->segno;
|
||||
}
|
||||
|
||||
static void reset_curseg_fields(struct curseg_info *curseg)
|
||||
{
|
||||
curseg->inited = false;
|
||||
curseg->segno = NULL_SEGNO;
|
||||
curseg->next_segno = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a current working segment.
|
||||
* 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)
|
||||
ret = get_new_segment(sbi, &segno, new_sec, pinning);
|
||||
if (ret) {
|
||||
if (ret == -ENOSPC)
|
||||
curseg->segno = NULL_SEGNO;
|
||||
reset_curseg_fields(curseg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -3640,13 +3647,6 @@ static void f2fs_randomize_chunk(struct f2fs_sb_info *sbi,
|
||||
get_random_u32_inclusive(1, sbi->max_fragment_hole);
|
||||
}
|
||||
|
||||
static void reset_curseg_fields(struct curseg_info *curseg)
|
||||
{
|
||||
curseg->inited = false;
|
||||
curseg->segno = NULL_SEGNO;
|
||||
curseg->next_segno = 0;
|
||||
}
|
||||
|
||||
int f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
|
||||
block_t old_blkaddr, block_t *new_blkaddr,
|
||||
struct f2fs_summary *sum, int type,
|
||||
|
||||
Reference in New Issue
Block a user