* [PATCH] nilfs2: prevent double insertion of b_assoc_buffers in dirty buffer lookup @ 2026-06-25 5:26 wuyankun 2026-06-25 10:43 ` Ryusuke Konishi 0 siblings, 1 reply; 5+ messages in thread From: wuyankun @ 2026-06-25 5:26 UTC (permalink / raw) To: konishi.ryusuke, slava Cc: linux-nilfs, linux-kernel, syzkaller-bugs, syzbot+c37bed40868932d790e9, wuyankun syzbot reported list corruption caused by double list_add_tail() on bh->b_assoc_buffers in nilfs_lookup_dirty_data_buffers(). A buffer_head can still be dirty and not under async write while already linked on another association list. Add list state checks before enqueueing in both data and node dirty buffer scanners to avoid re-adding already linked nodes. Reported-by: syzbot+c37bed40868932d790e9@syzkaller.appspotmail.com Link: https://syzkaller.appspot.com/bug?extid=c37bed40868932d790e9 Signed-off-by: wuyankun <wuyankun@uniontech.com> --- fs/nilfs2/segment.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index 1491a4d4b1e1..09202d155903 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c @@ -741,6 +741,8 @@ static size_t nilfs_lookup_dirty_data_buffers(struct inode *inode, do { if (!buffer_dirty(bh) || buffer_async_write(bh)) continue; + if (!list_empty(&bh->b_assoc_buffers)) + continue; get_bh(bh); list_add_tail(&bh->b_assoc_buffers, listp); ndirties++; @@ -779,7 +781,8 @@ static void nilfs_lookup_dirty_node_buffers(struct inode *inode, bh = head = folio_buffers(fbatch.folios[i]); do { if (buffer_dirty(bh) && - !buffer_async_write(bh)) { + !buffer_async_write(bh) && + list_empty(&bh->b_assoc_buffers)) { get_bh(bh); list_add_tail(&bh->b_assoc_buffers, listp); -- 2.20.1 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH] nilfs2: prevent double insertion of b_assoc_buffers in dirty buffer lookup 2026-06-25 5:26 [PATCH] nilfs2: prevent double insertion of b_assoc_buffers in dirty buffer lookup wuyankun @ 2026-06-25 10:43 ` Ryusuke Konishi 2026-06-30 17:55 ` Ryusuke Konishi 0 siblings, 1 reply; 5+ messages in thread From: Ryusuke Konishi @ 2026-06-25 10:43 UTC (permalink / raw) To: wuyankun Cc: slava, linux-nilfs, linux-kernel, syzkaller-bugs, syzbot+c37bed40868932d790e9 On Thu, Jun 25, 2026 at 2:27 PM wuyankun wrote: > > syzbot reported list corruption caused by double list_add_tail() on > bh->b_assoc_buffers in nilfs_lookup_dirty_data_buffers(). > > A buffer_head can still be dirty and not under async write while already > linked on another association list. Add list state checks before enqueueing > in both data and node dirty buffer scanners to avoid re-adding already > linked nodes. > > Reported-by: syzbot+c37bed40868932d790e9@syzkaller.appspotmail.com > Link: https://syzkaller.appspot.com/bug?extid=c37bed40868932d790e9 > Signed-off-by: wuyankun <wuyankun@uniontech.com> > --- > fs/nilfs2/segment.c | 5 ++++- > 1 file changed, 4 insertions(+), 1 deletion(-) > > diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c > index 1491a4d4b1e1..09202d155903 100644 > --- a/fs/nilfs2/segment.c > +++ b/fs/nilfs2/segment.c > @@ -741,6 +741,8 @@ static size_t nilfs_lookup_dirty_data_buffers(struct inode *inode, > do { > if (!buffer_dirty(bh) || buffer_async_write(bh)) > continue; > + if (!list_empty(&bh->b_assoc_buffers)) > + continue; > get_bh(bh); > list_add_tail(&bh->b_assoc_buffers, listp); > ndirties++; > @@ -779,7 +781,8 @@ static void nilfs_lookup_dirty_node_buffers(struct inode *inode, > bh = head = folio_buffers(fbatch.folios[i]); > do { > if (buffer_dirty(bh) && > - !buffer_async_write(bh)) { > + !buffer_async_write(bh) && > + list_empty(&bh->b_assoc_buffers)) { > get_bh(bh); > list_add_tail(&bh->b_assoc_buffers, > listp); > -- > 2.20.1 > Thank you for the patch. This patch adds a fix to forcibly avoid double registration of a buffer head to the list at the list manipulation level. However, we need to clarify why that happened in the first place, and what caused the state inconsistency that led to this double registration. The search routine for dirty buffers performs a gang lookup for dirty folios, registering them to the list in ascending order of their offsets in the page cache. Furthermore, the construction and destruction of this list take place inside the log writer, which operates exclusively. Whether the write succeeds or fails, the list is released by nilfs_release_buffers() (called via nilfs_destroy_logs()). Therefore, double registration normally does not occur, meaning there must be an oversight somewhere. As this issue arises from calls made via the GC ioctl (nilfs_ioctl_clean_segments()), the underlying implementation flaw likely lies there. Since it seems reproducible with the syzbot reproducer, I will also trace what is happening to verify if this fix direction is appropriate. Thanks, Ryusuke Konishi ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] nilfs2: prevent double insertion of b_assoc_buffers in dirty buffer lookup 2026-06-25 10:43 ` Ryusuke Konishi @ 2026-06-30 17:55 ` Ryusuke Konishi 2026-07-01 1:53 ` wuyankun 0 siblings, 1 reply; 5+ messages in thread From: Ryusuke Konishi @ 2026-06-30 17:55 UTC (permalink / raw) To: wuyankun Cc: slava, linux-nilfs, linux-kernel, syzkaller-bugs, syzbot+c37bed40868932d790e9 Hi Wuyankun, On Thu, Jun 25, 2026 at 7:43 PM Ryusuke Konishi wrote: > > On Thu, Jun 25, 2026 at 2:27 PM wuyankun wrote: > > > > syzbot reported list corruption caused by double list_add_tail() on > > bh->b_assoc_buffers in nilfs_lookup_dirty_data_buffers(). > > > > A buffer_head can still be dirty and not under async write while already > > linked on another association list. Add list state checks before enqueueing > > in both data and node dirty buffer scanners to avoid re-adding already > > linked nodes. > > > > Reported-by: syzbot+c37bed40868932d790e9@syzkaller.appspotmail.com > > Link: https://syzkaller.appspot.com/bug?extid=c37bed40868932d790e9 > > Signed-off-by: wuyankun <wuyankun@uniontech.com> > > --- > > fs/nilfs2/segment.c | 5 ++++- > > 1 file changed, 4 insertions(+), 1 deletion(-) > > > > diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c > > index 1491a4d4b1e1..09202d155903 100644 > > --- a/fs/nilfs2/segment.c > > +++ b/fs/nilfs2/segment.c > > @@ -741,6 +741,8 @@ static size_t nilfs_lookup_dirty_data_buffers(struct inode *inode, > > do { > > if (!buffer_dirty(bh) || buffer_async_write(bh)) > > continue; > > + if (!list_empty(&bh->b_assoc_buffers)) > > + continue; > > get_bh(bh); > > list_add_tail(&bh->b_assoc_buffers, listp); > > ndirties++; > > @@ -779,7 +781,8 @@ static void nilfs_lookup_dirty_node_buffers(struct inode *inode, > > bh = head = folio_buffers(fbatch.folios[i]); > > do { > > if (buffer_dirty(bh) && > > - !buffer_async_write(bh)) { > > + !buffer_async_write(bh) && > > + list_empty(&bh->b_assoc_buffers)) { > > get_bh(bh); > > list_add_tail(&bh->b_assoc_buffers, > > listp); > > -- > > 2.20.1 > > > > Thank you for the patch. > > This patch adds a fix to forcibly avoid double registration of a > buffer head to the list at the list manipulation level. > > However, we need to clarify why that happened in the first place, and > what caused the state inconsistency that led to this double > registration. > > The search routine for dirty buffers performs a gang lookup for dirty > folios, registering them to the list in ascending order of their > offsets in the page cache. > > Furthermore, the construction and destruction of this list take place > inside the log writer, which operates exclusively. Whether the write > succeeds or fails, the list is released by nilfs_release_buffers() > (called via nilfs_destroy_logs()). Therefore, double registration > normally does not occur, meaning there must be an oversight somewhere. > > As this issue arises from calls made via the GC ioctl > (nilfs_ioctl_clean_segments()), the underlying implementation flaw > likely lies there. > > Since it seems reproducible with the syzbot reproducer, I will also > trace what is happening to verify if this fix direction is > appropriate. Regarding the cause of this issue, the page index of the folio containing the problematic buffer head was 18446744073709551615 (= ULONG_MAX on 64-bit architectures). As a result, filemap_get_folios_tag(), called from nilfs_lookup_dirty_data_buffers(), repeatedly finds the folio at index ULONG_MAX, causing the duplicate processing of dirty buffers. The root cause is that a page/folio with an index of ULONG_MAX has been inserted into the page cache via the GC ioctl. Specifically, nilfs_ioctl_move_blocks() processes the blocks to be moved by GC based on the nilfs_vdesc structures passed as ioctl arguments, reads them into the page cache via nilfs_ioctl_move_inode_block(), and marks them dirty. At this point, there is no range check for vdesc->vd_offset, which determines the page index. Consequently, the artificial request generated by syzbot causes a folio to be inserted at the ULONG_MAX page index. Therefore, the fix should not be to hide the issue by introducing a duplicate check for the buffer list in nilfs_lookup_dirty_data_buffers(). Instead, please define a local variable in nilfs_ioctl_move_inode_block(): __u64 limit_offset = (__u64)inode->i_sb->s_maxbytes >> inode->i_blkbits; and insert an error check just before calling nilfs_gccache_submit_read_data() when vd_flags == 0, returning -EINVAL if vd_offset is greater than or equal to this limit_offset. This will resolve the syzbot issue, but a similar check will likely be required for nilfs_gccache_submit_read_node(), which is called when vd_flags != 0. If that part is not obvious, it might be better to separate it. I will hand this back to you for now, but I can also take over creating the fix patch myself, so please let me know if you would like me to do so. Thanks, Ryusuke Konishi ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] nilfs2: prevent double insertion of b_assoc_buffers in dirty buffer lookup 2026-06-30 17:55 ` Ryusuke Konishi @ 2026-07-01 1:53 ` wuyankun 0 siblings, 0 replies; 5+ messages in thread From: wuyankun @ 2026-07-01 1:53 UTC (permalink / raw) To: konishi.ryusuke Cc: linux-kernel, linux-nilfs, slava, syzbot+c37bed40868932d790e9, syzkaller-bugs, wuyankun Thanks a lot for the detailed investigation and for clarifying the actual root cause. That explanation makes sense, and I agree that the proper fix should be a bounds check in nilfs_ioctl_move_inode_block() rather than masking it in nilfs_lookup_dirty_data_buffers(). Please go ahead and handle the fix patch on your side. I appreciate the help and the clear breakdown of the issue. ^ permalink raw reply [flat|nested] 5+ messages in thread
* [syzbot] [nilfs?] BUG: corrupted list in nilfs_lookup_dirty_data_buffers @ 2026-06-24 19:59 syzbot 2026-06-25 9:14 ` [PATCH] nilfs2: prevent double insertion of b_assoc_buffers in dirty buffer lookup wuyankun 0 siblings, 1 reply; 5+ messages in thread From: syzbot @ 2026-06-24 19:59 UTC (permalink / raw) To: konishi.ryusuke, linux-kernel, linux-nilfs, slava, syzkaller-bugs Hello, syzbot found the following issue on: HEAD commit: f31c00c377cc Merge tag 'platform-drivers-x86-v7.2-1' of gi.. git tree: upstream console output: https://syzkaller.appspot.com/x/log.txt?x=10f687f2580000 kernel config: https://syzkaller.appspot.com/x/.config?x=31a51e0acb798311 dashboard link: https://syzkaller.appspot.com/bug?extid=c37bed40868932d790e9 compiler: Debian clang version 22.1.8 (++20260613092233+e80beda6e255-1~exp1~20260613092250.77), Debian LLD 22.1.8 syz repro: https://syzkaller.appspot.com/x/repro.syz?x=10376ba1580000 C reproducer: https://syzkaller.appspot.com/x/repro.c?x=15c42341580000 Downloadable assets: disk image (non-bootable): https://storage.googleapis.com/syzbot-assets/d900f083ada3/non_bootable_disk-f31c00c3.raw.xz vmlinux: https://storage.googleapis.com/syzbot-assets/65376d2aeca1/vmlinux-f31c00c3.xz kernel image: https://storage.googleapis.com/syzbot-assets/dba2c41e8c30/bzImage-f31c00c3.xz mounted in repro: https://storage.googleapis.com/syzbot-assets/12e3220d6326/mount_0.gz IMPORTANT: if you fix the issue, please add the following tag to the commit: Reported-by: syzbot+c37bed40868932d790e9@syzkaller.appspotmail.com list_add double add: new=ffff888043d25c80, prev=ffff888043d25c80, next=ffffc900034ff1c0. ------------[ cut here ]------------ kernel BUG at lib/list_debug.c:37! Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI CPU: 0 UID: 0 PID: 5513 Comm: syz.0.17 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:__list_add_valid_or_report+0xa5/0x130 lib/list_debug.c:35 Code: 74 12 b0 01 5b 41 5c 41 5d 41 5e 41 5f 5d c3 cc cc cc cc cc 48 c7 c7 60 9f 2a 8c 4c 89 fe 4c 89 f2 48 89 d9 e8 7c 57 63 fc 90 <0f> 0b 48 c7 c7 40 9d 2a 8c e8 6d 57 63 fc 90 0f 0b 48 c7 c7 00 9e RSP: 0018:ffffc900034fed48 EFLAGS: 00010246 RAX: 0000000000000058 RBX: ffffc900034ff1c0 RCX: 74a71100abd37800 RDX: 0000000000000000 RSI: 0000000080000000 RDI: 0000000000000000 RBP: 1ffff9200069fe39 R08: ffff88801fc24713 R09: 1ffff11003f848e2 R10: dffffc0000000000 R11: ffffed1003f848e3 R12: 1ffff110087a4b90 R13: dffffc0000000000 R14: ffff888043d25c80 R15: ffff888043d25c80 FS: 00005555919bc500(0000) GS:ffff88808c821000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f4434df8eb8 CR3: 000000001ab95000 CR4: 0000000000352ef0 Call Trace: <TASK> __list_add_valid include/linux/list.h:96 [inline] __list_add include/linux/list.h:158 [inline] list_add_tail include/linux/list.h:191 [inline] nilfs_lookup_dirty_data_buffers+0x468/0x7b0 fs/nilfs2/segment.c:745 nilfs_segctor_scan_file+0x26a/0xf70 fs/nilfs2/segment.c:1046 nilfs_segctor_collect_blocks fs/nilfs2/segment.c:1198 [inline] nilfs_segctor_collect fs/nilfs2/segment.c:1547 [inline] nilfs_segctor_do_construct+0x1c8d/0x7bb0 fs/nilfs2/segment.c:2122 nilfs_segctor_construct+0x170/0x690 fs/nilfs2/segment.c:2462 nilfs_clean_segments+0x4ec/0xbb0 fs/nilfs2/segment.c:2557 nilfs_ioctl_clean_segments fs/nilfs2/ioctl.c:922 [inline] nilfs_ioctl+0x2619/0x2780 fs/nilfs2/ioctl.c:1352 vfs_ioctl fs/ioctl.c:51 [inline] __do_sys_ioctl fs/ioctl.c:597 [inline] __se_sys_ioctl+0xfc/0x170 fs/ioctl.c:583 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f RIP: 0033:0x7f620d99ce59 Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48 RSP: 002b:00007fffb7f16fb8 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 RAX: ffffffffffffffda RBX: 00007f620dc15fa0 RCX: 00007f620d99ce59 RDX: 0000200000000040 RSI: 0000000040786e88 RDI: 0000000000000004 RBP: 00007f620da32e6f R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 R13: 00007f620dc15fac R14: 00007f620dc15fa0 R15: 00007f620dc15fa0 </TASK> Modules linked in: ---[ end trace 0000000000000000 ]--- RIP: 0010:__list_add_valid_or_report+0xa5/0x130 lib/list_debug.c:35 Code: 74 12 b0 01 5b 41 5c 41 5d 41 5e 41 5f 5d c3 cc cc cc cc cc 48 c7 c7 60 9f 2a 8c 4c 89 fe 4c 89 f2 48 89 d9 e8 7c 57 63 fc 90 <0f> 0b 48 c7 c7 40 9d 2a 8c e8 6d 57 63 fc 90 0f 0b 48 c7 c7 00 9e RSP: 0018:ffffc900034fed48 EFLAGS: 00010246 RAX: 0000000000000058 RBX: ffffc900034ff1c0 RCX: 74a71100abd37800 RDX: 0000000000000000 RSI: 0000000080000000 RDI: 0000000000000000 RBP: 1ffff9200069fe39 R08: ffff88801fc24713 R09: 1ffff11003f848e2 R10: dffffc0000000000 R11: ffffed1003f848e3 R12: 1ffff110087a4b90 R13: dffffc0000000000 R14: ffff888043d25c80 R15: ffff888043d25c80 FS: 00005555919bc500(0000) GS:ffff88808c821000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007fe0c8f2f440 CR3: 000000001ab95000 CR4: 0000000000352ef0 --- This report is generated by a bot. It may contain errors. See https://goo.gl/tpsmEJ for more information about syzbot. syzbot engineers can be reached at syzkaller@googlegroups.com. syzbot will keep track of this issue. See: https://goo.gl/tpsmEJ#status for how to communicate with syzbot. If the report is already addressed, let syzbot know by replying with: #syz fix: exact-commit-title If you want syzbot to run the reproducer, reply with: #syz test: git://repo/address.git branch-or-commit-hash If you attach or paste a git patch, syzbot will apply it before testing. If you want to overwrite report's subsystems, reply with: #syz set subsystems: new-subsystem (See the list of subsystem names on the web dashboard) If the report is a duplicate of another one, reply with: #syz dup: exact-subject-of-another-report If you want to undo deduplication, reply with: #syz undup ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH] nilfs2: prevent double insertion of b_assoc_buffers in dirty buffer lookup 2026-06-24 19:59 [syzbot] [nilfs?] BUG: corrupted list in nilfs_lookup_dirty_data_buffers syzbot @ 2026-06-25 9:14 ` wuyankun 0 siblings, 0 replies; 5+ messages in thread From: wuyankun @ 2026-06-25 9:14 UTC (permalink / raw) To: syzbot+c37bed40868932d790e9 Cc: syzkaller-bugs, konishi.ryusuke, linux-kernel, linux-nilfs, slava #syz test syzbot reported list corruption caused by double list_add_tail() on bh->b_assoc_buffers in nilfs_lookup_dirty_data_buffers(). A buffer_head can still be dirty and not under async write while already linked on another association list. Add list state checks before enqueueing in both data and node dirty buffer scanners to avoid re-adding already linked nodes. diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index 1491a4d4b1e1..09202d155903 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c @@ -741,6 +741,8 @@ static size_t nilfs_lookup_dirty_data_buffers(struct inode *inode, do { if (!buffer_dirty(bh) || buffer_async_write(bh)) continue; + if (!list_empty(&bh->b_assoc_buffers)) + continue; get_bh(bh); list_add_tail(&bh->b_assoc_buffers, listp); ndirties++; @@ -779,7 +781,8 @@ static void nilfs_lookup_dirty_node_buffers(struct inode *inode, bh = head = folio_buffers(fbatch.folios[i]); do { if (buffer_dirty(bh) && - !buffer_async_write(bh)) { + !buffer_async_write(bh) && + list_empty(&bh->b_assoc_buffers)) { get_bh(bh); list_add_tail(&bh->b_assoc_buffers, listp); -- 2.20.1 ^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-07-01 1:54 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-06-25 5:26 [PATCH] nilfs2: prevent double insertion of b_assoc_buffers in dirty buffer lookup wuyankun 2026-06-25 10:43 ` Ryusuke Konishi 2026-06-30 17:55 ` Ryusuke Konishi 2026-07-01 1:53 ` wuyankun -- strict thread matches above, loose matches on Subject: below -- 2026-06-24 19:59 [syzbot] [nilfs?] BUG: corrupted list in nilfs_lookup_dirty_data_buffers syzbot 2026-06-25 9:14 ` [PATCH] nilfs2: prevent double insertion of b_assoc_buffers in dirty buffer lookup wuyankun
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox