]>
Commit | Line | Data |
---|---|---|
37554d48 SL |
1 | From 4cd3dcac8a5ed0de17b003d84a0d8d73adfc2f87 Mon Sep 17 00:00:00 2001 |
2 | From: Chao Yu <yuchao0@huawei.com> | |
3 | Date: Mon, 15 Apr 2019 15:28:30 +0800 | |
4 | Subject: f2fs: fix to avoid panic in dec_valid_block_count() | |
5 | ||
6 | [ Upstream commit 5e159cd349bf3a31fb7e35c23a93308eb30f4f71 ] | |
7 | ||
8 | As Jungyeon reported in bugzilla: | |
9 | ||
10 | https://bugzilla.kernel.org/show_bug.cgi?id=203209 | |
11 | ||
12 | - Overview | |
13 | When mounting the attached crafted image and running program, I got this error. | |
14 | Additionally, it hangs on sync after the this script. | |
15 | ||
16 | The image is intentionally fuzzed from a normal f2fs image for testing and I enabled option CONFIG_F2FS_CHECK_FS on. | |
17 | ||
18 | - Reproduces | |
19 | cc poc_01.c | |
20 | ./run.sh f2fs | |
21 | sync | |
22 | ||
23 | kernel BUG at fs/f2fs/f2fs.h:1788! | |
24 | RIP: 0010:f2fs_truncate_data_blocks_range+0x342/0x350 | |
25 | Call Trace: | |
26 | f2fs_truncate_blocks+0x36d/0x3c0 | |
27 | f2fs_truncate+0x88/0x110 | |
28 | f2fs_setattr+0x3e1/0x460 | |
29 | notify_change+0x2da/0x400 | |
30 | do_truncate+0x6d/0xb0 | |
31 | do_sys_ftruncate+0xf1/0x160 | |
32 | do_syscall_64+0x43/0xf0 | |
33 | entry_SYSCALL_64_after_hwframe+0x44/0xa9 | |
34 | ||
35 | The reason is dec_valid_block_count() will trigger kernel panic due to | |
36 | inconsistent count in between inode.i_blocks and actual block. | |
37 | ||
38 | To avoid panic, let's just print debug message and set SBI_NEED_FSCK to | |
39 | give a hint to fsck for latter repairing. | |
40 | ||
41 | Signed-off-by: Chao Yu <yuchao0@huawei.com> | |
42 | [Jaegeuk Kim: fix build warning and add unlikely] | |
43 | Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org> | |
44 | Signed-off-by: Sasha Levin <sashal@kernel.org> | |
45 | --- | |
46 | fs/f2fs/f2fs.h | 12 ++++++++++-- | |
47 | 1 file changed, 10 insertions(+), 2 deletions(-) | |
48 | ||
49 | diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h | |
50 | index a4b6eacf22ea..64f970cca1b4 100644 | |
51 | --- a/fs/f2fs/f2fs.h | |
52 | +++ b/fs/f2fs/f2fs.h | |
53 | @@ -1744,6 +1744,7 @@ enospc: | |
54 | return -ENOSPC; | |
55 | } | |
56 | ||
57 | +void f2fs_msg(struct super_block *sb, const char *level, const char *fmt, ...); | |
58 | static inline void dec_valid_block_count(struct f2fs_sb_info *sbi, | |
59 | struct inode *inode, | |
60 | block_t count) | |
61 | @@ -1752,13 +1753,21 @@ static inline void dec_valid_block_count(struct f2fs_sb_info *sbi, | |
62 | ||
63 | spin_lock(&sbi->stat_lock); | |
64 | f2fs_bug_on(sbi, sbi->total_valid_block_count < (block_t) count); | |
65 | - f2fs_bug_on(sbi, inode->i_blocks < sectors); | |
66 | sbi->total_valid_block_count -= (block_t)count; | |
67 | if (sbi->reserved_blocks && | |
68 | sbi->current_reserved_blocks < sbi->reserved_blocks) | |
69 | sbi->current_reserved_blocks = min(sbi->reserved_blocks, | |
70 | sbi->current_reserved_blocks + count); | |
71 | spin_unlock(&sbi->stat_lock); | |
72 | + if (unlikely(inode->i_blocks < sectors)) { | |
73 | + f2fs_msg(sbi->sb, KERN_WARNING, | |
74 | + "Inconsistent i_blocks, ino:%lu, iblocks:%llu, sectors:%llu", | |
75 | + inode->i_ino, | |
76 | + (unsigned long long)inode->i_blocks, | |
77 | + (unsigned long long)sectors); | |
78 | + set_sbi_flag(sbi, SBI_NEED_FSCK); | |
79 | + return; | |
80 | + } | |
81 | f2fs_i_blocks_write(inode, count, false, true); | |
82 | } | |
83 | ||
84 | @@ -2727,7 +2736,6 @@ static inline void f2fs_update_iostat(struct f2fs_sb_info *sbi, | |
85 | ||
86 | bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi, | |
87 | block_t blkaddr, int type); | |
88 | -void f2fs_msg(struct super_block *sb, const char *level, const char *fmt, ...); | |
89 | static inline void verify_blkaddr(struct f2fs_sb_info *sbi, | |
90 | block_t blkaddr, int type) | |
91 | { | |
92 | -- | |
93 | 2.20.1 | |
94 |