FAILED: patch "[PATCH] f2fs: fix to do sanity check on f2fs_get_node_folio_ra()" failed to apply to 6.18-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 6.18-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.18.y
git checkout FETCH_HEAD
git cherry-pick -x 8712353ed80f87271d732297567dcdbe4b84e8c7
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026070234-outdated-refutable-f834@gregkh' --subject-prefix 'PATCH 6.18.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 8712353ed80f87271d732297567dcdbe4b84e8c7 Mon Sep 17 00:00:00 2001
From: Chao Yu <[email protected]>
Date: Fri, 22 May 2026 15:53:29 +0800
Subject: [PATCH] f2fs: fix to do sanity check on f2fs_get_node_folio_ra()
kernel BUG at fs/f2fs/file.c:845!
Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI CPU: 0 UID: 0 PID: 5336 Comm: syz.0.0 Not tainted syzkaller #0 PREEMPT(full) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 RIP: 0010:f2fs_do_truncate_blocks+0x1115/0x1140 fs/f2fs/file.c:845 Code: fc fc 90 0f 0b e8 8b 9d 9a fd 90 0f 0b e8 83 9d 9a fd 48 89 df 48 c7 c6 60 d1 1a 8c e8 54 f1 fc fc 90 0f 0b e8 6c 9d 9a fd 90 <0f> 0b e8 64 9d 9a fd 90 0f 0b 90 e9 93 fd ff ff e8 56 9d 9a fd 90 RSP: 0018:ffffc9000e4474c0 EFLAGS: 00010283 RAX: ffffffff842b1d34 RBX: 0000000000000003 RCX: 0000000000100000 RDX: ffffc9000f03a000 RSI: 0000000000035503 RDI: 0000000000035504 RBP: ffffc9000e447608 R08: ffff8880123b0000 R09: 0000000000000002 R10: 00000000fffffffe R11: 0000000000000002 R12: 0000000000000001 R13: 0000000000000000 R14: 1ffff92001c88ea0 R15: 00000000ffff039c FS: 00007f7e02ee36c0(0000) GS:ffff88808c887000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007ff0305c4000 CR3: 0000000012d4c000 CR4: 0000000000352ef0 Call Trace: <TASK> f2fs_truncate_blocks+0x10a/0x300 fs/f2fs/file.c:882 f2fs_truncate+0x471/0x7c0 fs/f2fs/file.c:940 f2fs_evict_inode+0xa3f/0x1ac0 fs/f2fs/inode.c:907 evict+0x61e/0xb10 fs/inode.c:841 f2fs_fill_super+0x5f43/0x78f0 fs/f2fs/super.c:5224 get_tree_bdev_flags+0x431/0x4f0 fs/super.c:1694 vfs_get_tree+0x92/0x2a0 fs/super.c:1754 fc_mount fs/namespace.c:1193 [inline] do_new_mount_fc fs/namespace.c:3758 [inline] do_new_mount+0x341/0xd30 fs/namespace.c:3834 do_mount fs/namespace.c:4167 [inline] __do_sys_mount fs/namespace.c:4383 [inline] __se_sys_mount+0x31d/0x420 fs/namespace.c:4360 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0x15f/0xf80 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f
count = ADDRS_PER_PAGE(dn.node_folio, inode); count -= dn.ofs_in_node; f2fs_bug_on(sbi, count < 0);
The fuzz test will trigger above bug_on in f2fs.
The root cause should be: in the corrupted inode, there is a direct node which has the same ino and nid in its footer, so in f2fs_do_truncate_blocks(), after f2fs_get_dnode_of_data() finds such dnode:
1) ADDRS_PER_PAGE(dn.node_folio, inode) will return 923
2) once dn.ofs_in_node points to addr[923, 1017]
Then it will trigger the system panic.
Let's introduce NODE_TYPE_NON_IXNODE to indicate current node should not be an inode or xattr node, and then use it in below path to detect inconsistent node chain in inode mapping table:
- f2fs_do_truncate_blocks
- f2fs_get_dnode_of_data
- f2fs_get_node_folio_ra
- __get_node_folio
- f2fs_sanity_check_node_footer
- case NODE_TYPE_NON_IXNODE -> check whether it is inode|xnode
fs/f2fs/f2fs.h +1 -0
@@ -1592,6 +1592,7 @@ enum node_type {NODE_TYPE_INODE ,NODE_TYPE_XATTR ,NODE_TYPE_NON_INODE , + NODE_TYPE_NON_IXNODE, /* non inode and xnode */ };/* a threshold of maximum elapsed time in critical region to print tracepoint */
fs/f2fs/node.c +5 -1
@@ -1548,6 +1548,10 @@ int f2fs_sanity_check_node_footer(struct f2fs_sb_info *sbi,if (is_inode) goto out_err;break ; +case NODE_TYPE_NON_IXNODE : +if (is_inode || is_xnode) + goto out_err; +break ;default :break ; }
@@ -1643,7 +1647,7 @@ static struct folio *f2fs_get_node_folio_ra(struct folio *parent, int start)struct f2fs_sb_info *sbi =F2FS_F_SB (parent);nid_t nid =get_nid (parent, start, false); -return __get_node_folio (sbi, nid, parent, start,NODE_TYPE_REGULAR ); +return __get_node_folio (sbi, nid, parent, start,NODE_TYPE_NON_IXNODE ); }static void flush_inline_data (struct f2fs_sb_info *sbi,nid_t ino)
Sasha Levin
maintainerPATCH 1/5 f2fs: use memalloc_retry_wait() as much as possible
From: Chao Yu <[email protected]>
[ Upstream commit 30a8496694f1a93328e5d7f19206380346918b5a ]
memalloc_retry_wait() is recommended in memory allocation retry logic, use it as much as possible.
Stable-dep-of: 8712353ed80f ("f2fs: fix to do sanity check on f2fs_get_node_folio_ra()")
--- fs/f2fs/segment.c | 2 +- fs/f2fs/super.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
fs/f2fs/segment.c +1 -1
@@ -234,7 +234,7 @@ static int __replace_atomic_write_block(struct inode *inode, pgoff_t index, err =f2fs_get_dnode_of_data (&dn, index,ALLOC_NODE );if (err) {if (err == -ENOMEM ) { -f2fs_io_schedule_timeout (DEFAULT_IO_TIMEOUT ); +memalloc_retry_wait (GFP_NOFS ); goto retry; }return err;
fs/f2fs/super.c +1 -1
@@ -3128,7 +3128,7 @@ static ssize_t f2fs_quota_write(struct super_block *sb, int type, &folio, &fsdata);if (unlikely (err)) {if (err == -ENOMEM ) { -f2fs_io_schedule_timeout (DEFAULT_IO_TIMEOUT ); +memalloc_retry_wait (GFP_NOFS ); goto retry; }set_sbi_flag (F2FS_SB (sb),SBI_QUOTA_NEED_REPAIR );
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/5 f2fs: introduce f2fs_schedule_timeout()
From: Chao Yu <[email protected]>
[ Upstream commit 76e780d88c771921ea643fb8a6c8d0b08c17cb7b ]
In f2fs retry logic, we will call f2fs_io_schedule_timeout() to sleep as uninterruptible state (waiting for IO) for a while, however, in several paths below, we are not blocked by IO:
- f2fs_write_single_data_page() return -EAGAIN due to racing on cp_rwsem.
- f2fs_flush_device_cache() failed to submit preflush command.
- __issue_discard_cmd_range() sleeps periodically in between two in batch discard submissions.
So, in order to reveal state of task more accurate, let's introduce f2fs_schedule_timeout() and call it in above paths in where we are waiting for non-IO reasons.
Then we can get real reason of uninterruptible sleep for a thread in tracepoint, perfetto, etc.
Stable-dep-of: 8712353ed80f ("f2fs: fix to do sanity check on f2fs_get_node_folio_ra()")
--- fs/f2fs/checkpoint.c | 4 ++-- fs/f2fs/compress.c | 4 ++-- fs/f2fs/data.c | 4 ++-- fs/f2fs/f2fs.h | 22 +++++++++++++++------- fs/f2fs/segment.c | 4 ++-- fs/f2fs/super.c | 2 +- 6 files changed, 24 insertions(+), 16 deletions(-)
fs/f2fs/checkpoint.c +2 -2
@@ -1318,7 +1318,7 @@ void f2fs_wait_on_all_pages(struct f2fs_sb_info *sbi, int type)f2fs_submit_merged_write (sbi,DATA );prepare_to_wait (&sbi->cp_wait, &wait,TASK_UNINTERRUPTIBLE ); -io_schedule_timeout (DEFAULT_IO_TIMEOUT ); +io_schedule_timeout (DEFAULT_SCHEDULE_TIMEOUT ); }finish_wait (&sbi->cp_wait, &wait); }
@@ -1974,7 +1974,7 @@ void f2fs_flush_ckpt_thread(struct f2fs_sb_info *sbi)/* Let's wait for the previous dispatched checkpoint. */ while (atomic_read (&cprc->queued_ckpt)) -io_schedule_timeout (DEFAULT_IO_TIMEOUT ); +io_schedule_timeout (DEFAULT_SCHEDULE_TIMEOUT ); }void f2fs_init_ckpt_req_control (struct f2fs_sb_info *sbi)
fs/f2fs/compress.c +2 -2
@@ -1057,7 +1057,7 @@ static void cancel_cluster_writeback(struct compress_ctx *cc,f2fs_submit_merged_write (F2FS_I_SB (cc->inode),DATA );while (atomic_read (&cic->pending_pages) != (cc->valid_nr_cpages - submitted +1 )) -f2fs_io_schedule_timeout (DEFAULT_IO_TIMEOUT ); +f2fs_io_schedule_timeout (DEFAULT_SCHEDULE_TIMEOUT ); }/* Cancel writeback and stay locked. */
@@ -1582,7 +1582,7 @@ static int f2fs_write_raw_pages(struct compress_ctx *cc,*/ if (IS_NOQUOTA (cc->inode)) goto out; -f2fs_io_schedule_timeout (DEFAULT_IO_TIMEOUT ); +f2fs_schedule_timeout (DEFAULT_SCHEDULE_TIMEOUT ); goto retry_write; } goto out;
fs/f2fs/data.c +2 -2
@@ -3185,8 +3185,8 @@ static int f2fs_write_cache_pages(struct address_space *mapping, }else if (ret == -EAGAIN ) { ret =0 ;if (wbc->sync_mode ==WB_SYNC_ALL ) { -f2fs_io_schedule_timeout ( -DEFAULT_IO_TIMEOUT ); +f2fs_schedule_timeout ( +DEFAULT_SCHEDULE_TIMEOUT ); goto retry_write; } goto next;
fs/f2fs/f2fs.h +15 -7
@@ -665,8 +665,8 @@ enum {#define DEFAULT_RETRY_IO_COUNT 8/* maximum retry read IO or flush count */ -/* congestion wait timeout value, default: 20ms */ -#define DEFAULT_IO_TIMEOUT (msecs_to_jiffies(20)) +/* IO/non-IO congestion wait timeout value, default: 20ms */ +#define DEFAULT_SCHEDULE_TIMEOUT (msecs_to_jiffies(20))/* timeout value injected, default: 1000ms */ #define DEFAULT_FAULT_TIMEOUT (msecs_to_jiffies(1000))
@@ -4939,22 +4939,30 @@ static inline bool f2fs_block_unit_discard(struct f2fs_sb_info *sbi)return F2FS_OPTION (sbi).discard_unit ==DISCARD_UNIT_BLOCK ; } -static inline void f2fs_io_schedule_timeout (long timeout) +static inline void __f2fs_schedule_timeout (long timeout,bool io) {set_current_state (TASK_UNINTERRUPTIBLE ); -io_schedule_timeout (timeout); +if (io) +io_schedule_timeout (timeout); +else +schedule_timeout (timeout); } +#define f2fs_io_schedule_timeout (timeout) \ + __f2fs_schedule_timeout(timeout, true) +#define f2fs_schedule_timeout (timeout) \ + __f2fs_schedule_timeout(timeout, false) +static inline void f2fs_io_schedule_timeout_killable (long timeout) {while (timeout) {if (fatal_signal_pending (current))return ;set_current_state (TASK_UNINTERRUPTIBLE ); -io_schedule_timeout (DEFAULT_IO_TIMEOUT ); -if (timeout <=DEFAULT_IO_TIMEOUT ) +io_schedule_timeout (DEFAULT_SCHEDULE_TIMEOUT ); +if (timeout <=DEFAULT_SCHEDULE_TIMEOUT )return ; - timeout -=DEFAULT_IO_TIMEOUT ; + timeout -=DEFAULT_SCHEDULE_TIMEOUT ; } }
fs/f2fs/segment.c +2 -2
@@ -750,7 +750,7 @@ int f2fs_flush_device_cache(struct f2fs_sb_info *sbi)do { ret =__submit_flush_wait (sbi,FDEV (i).bdev);if (ret) -f2fs_io_schedule_timeout (DEFAULT_IO_TIMEOUT ); +f2fs_schedule_timeout (DEFAULT_SCHEDULE_TIMEOUT ); }while (ret && --count);if (ret) {
@@ -3472,7 +3472,7 @@ static unsigned int __issue_discard_cmd_range(struct f2fs_sb_info *sbi,blk_finish_plug (&plug);mutex_unlock (&dcc->cmd_lock); trimmed +=__wait_all_discard_cmd (sbi,NULL ); -f2fs_io_schedule_timeout (DEFAULT_IO_TIMEOUT ); +f2fs_schedule_timeout (DEFAULT_SCHEDULE_TIMEOUT ); goto next; } skip:
fs/f2fs/super.c +1 -1
@@ -2656,7 +2656,7 @@ static int f2fs_enable_checkpoint(struct f2fs_sb_info *sbi)/* we should flush all the data to keep data consistency */ while (get_pages (sbi,F2FS_DIRTY_DATA )) {writeback_inodes_sb_nr (sbi->sb, nr_pages,WB_REASON_SYNC ); -f2fs_io_schedule_timeout (DEFAULT_IO_TIMEOUT ); +f2fs_io_schedule_timeout (DEFAULT_SCHEDULE_TIMEOUT );if (f2fs_time_over (sbi,ENABLE_TIME ))break ;
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 3/5 f2fs: optimize trace_f2fs_write_checkpoint with enums
In reply to Sasha LevinFrom: YH Lin <[email protected]>
[ Upstream commit 8d1cb17aca466b361cca17834b8bb1cf3e3d1818 ]
This patch optimizes the tracepoint by replacing these hardcoded strings with a new enumeration f2fs_cp_phase.
1.Defines enum f2fs_cp_phase with values for each checkpoint phase. 2.Updates trace_f2fs_write_checkpoint to accept a u16 phase argument instead of a string pointer.
3.Uses __print_symbolic in TP_printk to convert the enum values back to their corresponding strings for human-readable trace output.
This change reduces the storage overhead for each trace event by replacing a variable-length string with a 2-byte integer, while maintaining the same readable output in ftrace.
Stable-dep-of: 8712353ed80f ("f2fs: fix to do sanity check on f2fs_get_node_folio_ra()")
--- fs/f2fs/checkpoint.c | 6 +++--- fs/f2fs/f2fs.h | 6 ++++++ include/trace/events/f2fs.h | 19 ++++++++++++++----- 3 files changed, 23 insertions(+), 8 deletions(-)
fs/f2fs/checkpoint.c +3 -3
@@ -1673,7 +1673,7 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) goto out; } -trace_f2fs_write_checkpoint (sbi->sb, cpc->reason,"start block_ops" ); +trace_f2fs_write_checkpoint (sbi->sb, cpc->reason,CP_PHASE_START_BLOCK_OPS ); err =block_operations (sbi);if (err)
@@ -1681,7 +1681,7 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)stat_cp_time (cpc,CP_TIME_OP_LOCK ); -trace_f2fs_write_checkpoint (sbi->sb, cpc->reason,"finish block_ops" ); +trace_f2fs_write_checkpoint (sbi->sb, cpc->reason,CP_PHASE_FINISH_BLOCK_OPS );f2fs_flush_merged_writes (sbi);
@@ -1747,7 +1747,7 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)/* update CP_TIME to trigger checkpoint periodically */ f2fs_update_time (sbi,CP_TIME ); -trace_f2fs_write_checkpoint (sbi->sb, cpc->reason,"finish checkpoint" ); +trace_f2fs_write_checkpoint (sbi->sb, cpc->reason,CP_PHASE_FINISH_CHECKPOINT ); out:if (cpc->reason !=CP_RESIZE )f2fs_up_write (&sbi->cp_global_sem);
fs/f2fs/f2fs.h +6 -0
@@ -319,6 +319,12 @@ struct cp_control {struct cp_stats stats; }; +enum f2fs_cp_phase { +CP_PHASE_START_BLOCK_OPS , +CP_PHASE_FINISH_BLOCK_OPS , +CP_PHASE_FINISH_CHECKPOINT , +}; +/* * indicate meta/data type */
include/trace/events/f2fs.h +14 -5
@@ -50,6 +50,9 @@ TRACE_DEFINE_ENUM(CP_PAUSE);TRACE_DEFINE_ENUM (CP_RESIZE );TRACE_DEFINE_ENUM (EX_READ );TRACE_DEFINE_ENUM (EX_BLOCK_AGE ); +TRACE_DEFINE_ENUM (CP_PHASE_START_BLOCK_OPS ); +TRACE_DEFINE_ENUM (CP_PHASE_FINISH_BLOCK_OPS ); +TRACE_DEFINE_ENUM (CP_PHASE_FINISH_CHECKPOINT );#define show_block_type (type) \ __print_symbolic(type, \
@@ -175,6 +178,12 @@ TRACE_DEFINE_ENUM(EX_BLOCK_AGE);#define S_ALL_PERM (S_ISUID | S_ISGID | S_ISVTX | \ S_IRWXU | S_IRWXG | S_IRWXO) +#define show_cp_phase (phase) \ + __print_symbolic(phase, \ + { CP_PHASE_START_BLOCK_OPS, "start block_ops" }, \ + { CP_PHASE_FINISH_BLOCK_OPS, "finish block_ops" }, \ + { CP_PHASE_FINISH_CHECKPOINT, "finish checkpoint" }) +struct f2fs_sb_info ;struct f2fs_io_info ;struct extent_info ;
@@ -1541,26 +1550,26 @@ TRACE_EVENT(f2fs_readpages,TRACE_EVENT (f2fs_write_checkpoint, - TP_PROTO(struct super_block *sb, int reason, const char *msg), + TP_PROTO(struct super_block *sb, int reason, u16 phase), -TP_ARGS (sb, reason, msg), +TP_ARGS (sb, reason, phase),TP_STRUCT__entry ( __field(dev_t, dev) __field(int, reason) -__string (dest_msg, msg) +__field (u16, phase) ),TP_fast_assign ( __entry->dev = sb->s_dev; __entry->reason = reason; - __assign_str(dest_msg); + __entry->phase = phase; ),TP_printk ("dev = (%d,%d), checkpoint for %s, state = %s" ,show_dev (__entry->dev),show_cpreason (__entry->reason), -__get_str (dest_msg)) +show_cp_phase (__entry->phase)) ); DECLARE_EVENT_CLASS(f2fs_discard,
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 4/5 f2fs: detect more inconsistent cases in sanity_check_node_footer()
In reply to Sasha LevinFrom: Chao Yu <[email protected]>
[ Upstream commit 93ffb6c28ff180560d2d7313ac106efcd9e012b8 ]
Let's enhance sanity_check_node_footer() to detect more inconsistent cases as below:
Node Type Node Footer Info
=================== =============================NODE_TYPE_REGULAR inode = true and xnode = trueNODE_TYPE_INODE inode = false or xnode = trueNODE_TYPE_XATTR inode = true or xnode = falseNODE_TYPE_NON_INODE inode = false
Stable-dep-of: 8712353ed80f ("f2fs: fix to do sanity check on f2fs_get_node_folio_ra()")
--- fs/f2fs/node.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-)
fs/f2fs/node.c +12 -3
@@ -1504,20 +1504,29 @@ int f2fs_sanity_check_node_footer(struct f2fs_sb_info *sbi, struct folio *folio, pgoff_t nid, enum node_type ntype, bool in_irq) { + bool is_inode, is_xnode; +if (unlikely (nid !=nid_of_node (folio))) goto out_err; + is_inode =IS_INODE (folio); + is_xnode =f2fs_has_xattr_block (ofs_of_node (folio)); +switch (ntype) { +case NODE_TYPE_REGULAR : +if (is_inode && is_xnode) + goto out_err; +break ;case NODE_TYPE_INODE : -if (!IS_INODE (folio)) +if (!is_inode || is_xnode) goto out_err;break ;case NODE_TYPE_XATTR : -if (!f2fs_has_xattr_block (ofs_of_node (folio))) +if (is_inode || !is_xnode) goto out_err;break ;case NODE_TYPE_NON_INODE : -if (IS_INODE (folio)) +if (is_inode) goto out_err;break ;default :
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 5/5 f2fs: fix to do sanity check on f2fs_get_node_folio_ra()
In reply to Sasha LevinFrom: Chao Yu <[email protected]>
[ Upstream commit 8712353ed80f87271d732297567dcdbe4b84e8c7 ]
kernel BUG at fs/f2fs/file.c:845!
Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI CPU: 0 UID: 0 PID: 5336 Comm: syz.0.0 Not tainted syzkaller #0 PREEMPT(full) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 RIP: 0010:f2fs_do_truncate_blocks+0x1115/0x1140 fs/f2fs/file.c:845 Code: fc fc 90 0f 0b e8 8b 9d 9a fd 90 0f 0b e8 83 9d 9a fd 48 89 df 48 c7 c6 60 d1 1a 8c e8 54 f1 fc fc 90 0f 0b e8 6c 9d 9a fd 90 <0f> 0b e8 64 9d 9a fd 90 0f 0b 90 e9 93 fd ff ff e8 56 9d 9a fd 90 RSP: 0018:ffffc9000e4474c0 EFLAGS: 00010283 RAX: ffffffff842b1d34 RBX: 0000000000000003 RCX: 0000000000100000 RDX: ffffc9000f03a000 RSI: 0000000000035503 RDI: 0000000000035504 RBP: ffffc9000e447608 R08: ffff8880123b0000 R09: 0000000000000002 R10: 00000000fffffffe R11: 0000000000000002 R12: 0000000000000001 R13: 0000000000000000 R14: 1ffff92001c88ea0 R15: 00000000ffff039c FS: 00007f7e02ee36c0(0000) GS:ffff88808c887000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007ff0305c4000 CR3: 0000000012d4c000 CR4: 0000000000352ef0 Call Trace: <TASK> f2fs_truncate_blocks+0x10a/0x300 fs/f2fs/file.c:882 f2fs_truncate+0x471/0x7c0 fs/f2fs/file.c:940 f2fs_evict_inode+0xa3f/0x1ac0 fs/f2fs/inode.c:907 evict+0x61e/0xb10 fs/inode.c:841 f2fs_fill_super+0x5f43/0x78f0 fs/f2fs/super.c:5224 get_tree_bdev_flags+0x431/0x4f0 fs/super.c:1694 vfs_get_tree+0x92/0x2a0 fs/super.c:1754 fc_mount fs/namespace.c:1193 [inline] do_new_mount_fc fs/namespace.c:3758 [inline] do_new_mount+0x341/0xd30 fs/namespace.c:3834 do_mount fs/namespace.c:4167 [inline] __do_sys_mount fs/namespace.c:4383 [inline] __se_sys_mount+0x31d/0x420 fs/namespace.c:4360 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0x15f/0xf80 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f
count = ADDRS_PER_PAGE(dn.node_folio, inode); count -= dn.ofs_in_node; f2fs_bug_on(sbi, count < 0);
The fuzz test will trigger above bug_on in f2fs.
The root cause should be: in the corrupted inode, there is a direct node which has the same ino and nid in its footer, so in f2fs_do_truncate_blocks(), after f2fs_get_dnode_of_data() finds such dnode:
1) ADDRS_PER_PAGE(dn.node_folio, inode) will return 923
2) once dn.ofs_in_node points to addr[923, 1017]
Then it will trigger the system panic.
Let's introduce NODE_TYPE_NON_IXNODE to indicate current node should not be an inode or xattr node, and then use it in below path to detect inconsistent node chain in inode mapping table:
- f2fs_do_truncate_blocks
- f2fs_get_dnode_of_data
- f2fs_get_node_folio_ra
- __get_node_folio
- f2fs_sanity_check_node_footer
- case NODE_TYPE_NON_IXNODE -> check whether it is inode|xnode
--- fs/f2fs/f2fs.h | 1 + fs/f2fs/node.c | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-)
fs/f2fs/f2fs.h +1 -0
@@ -1533,6 +1533,7 @@ enum node_type {NODE_TYPE_INODE ,NODE_TYPE_XATTR ,NODE_TYPE_NON_INODE , + NODE_TYPE_NON_IXNODE, /* non inode and xnode */ };
fs/f2fs/node.c +5 -1
@@ -1529,6 +1529,10 @@ int f2fs_sanity_check_node_footer(struct f2fs_sb_info *sbi,if (is_inode) goto out_err;break ; +case NODE_TYPE_NON_IXNODE : +if (is_inode || is_xnode) + goto out_err; +break ;default :break ; }
@@ -1622,7 +1626,7 @@ static struct folio *f2fs_get_node_folio_ra(struct folio *parent, int start)struct f2fs_sb_info *sbi =F2FS_F_SB (parent);nid_t nid =get_nid (parent, start, false); -return __get_node_folio (sbi, nid, parent, start,NODE_TYPE_REGULAR ); +return __get_node_folio (sbi, nid, parent, start,NODE_TYPE_NON_IXNODE ); }static void flush_inline_data (struct f2fs_sb_info *sbi,nid_t ino)
Signature · 1 line
2.53.0