Commit 20189e98 authored by Chao Yu's avatar Chao Yu Committed by Khalid Elmously

f2fs: fix to do sanity check on segment bitmap of LFS curseg

BugLink: https://bugs.launchpad.net/bugs/1848589

[ Upstream commit c854f4d6 ]

As Jungyeon Reported in bugzilla:

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

- Reproduces
gcc poc_13.c
./run.sh f2fs

- Kernel messages
 F2FS-fs (sdb): Bitmap was wrongly set, blk:4608
 kernel BUG at fs/f2fs/segment.c:2133!
 RIP: 0010:update_sit_entry+0x35d/0x3e0
 Call Trace:
  f2fs_allocate_data_block+0x16c/0x5a0
  do_write_page+0x57/0x100
  f2fs_do_write_node_page+0x33/0xa0
  __write_node_page+0x270/0x4e0
  f2fs_sync_node_pages+0x5df/0x670
  f2fs_write_checkpoint+0x364/0x13a0
  f2fs_sync_fs+0xa3/0x130
  f2fs_do_sync_file+0x1a6/0x810
  do_fsync+0x33/0x60
  __x64_sys_fsync+0xb/0x10
  do_syscall_64+0x43/0x110
  entry_SYSCALL_64_after_hwframe+0x44/0xa9

The testcase fails because that, in fuzzed image, current segment was
allocated with LFS type, its .next_blkoff should point to an unused
block address, but actually, its bitmap shows it's not. So during
allocation, f2fs crash when setting bitmap.

Introducing sanity_check_curseg() to check such inconsistence of
current in-used segment.
Signed-off-by: default avatarChao Yu <yuchao0@huawei.com>
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
Signed-off-by: default avatarConnor Kuehl <connor.kuehl@canonical.com>
Signed-off-by: default avatarKleber Sacilotto de Souza <kleber.souza@canonical.com>
parent 6be5ea3e
...@@ -2262,6 +2262,41 @@ static int build_dirty_segmap(struct f2fs_sb_info *sbi) ...@@ -2262,6 +2262,41 @@ static int build_dirty_segmap(struct f2fs_sb_info *sbi)
return init_victim_secmap(sbi); return init_victim_secmap(sbi);
} }
static int sanity_check_curseg(struct f2fs_sb_info *sbi)
{
int i;
/*
* In LFS/SSR curseg, .next_blkoff should point to an unused blkaddr;
* In LFS curseg, all blkaddr after .next_blkoff should be unused.
*/
for (i = 0; i < NO_CHECK_TYPE; i++) {
struct curseg_info *curseg = CURSEG_I(sbi, i);
struct seg_entry *se = get_seg_entry(sbi, curseg->segno);
unsigned int blkofs = curseg->next_blkoff;
if (f2fs_test_bit(blkofs, se->cur_valid_map))
goto out;
if (curseg->alloc_type == SSR)
continue;
for (blkofs += 1; blkofs < sbi->blocks_per_seg; blkofs++) {
if (!f2fs_test_bit(blkofs, se->cur_valid_map))
continue;
out:
f2fs_msg(sbi->sb, KERN_ERR,
"Current segment's next free block offset is "
"inconsistent with bitmap, logtype:%u, "
"segno:%u, type:%u, next_blkoff:%u, blkofs:%u",
i, curseg->segno, curseg->alloc_type,
curseg->next_blkoff, blkofs);
return -EINVAL;
}
}
return 0;
}
/* /*
* Update min, max modified time for cost-benefit GC algorithm * Update min, max modified time for cost-benefit GC algorithm
*/ */
...@@ -2350,6 +2385,10 @@ int build_segment_manager(struct f2fs_sb_info *sbi) ...@@ -2350,6 +2385,10 @@ int build_segment_manager(struct f2fs_sb_info *sbi)
if (err) if (err)
return err; return err;
err = sanity_check_curseg(sbi);
if (err)
return err;
init_min_max_mtime(sbi); init_min_max_mtime(sbi);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment