From: Ryusuke Konishi <konishi.ryusuke@gmail.com>
To: wuyankun <wuyankun@uniontech.com>
Cc: slava@dubeyko.com, linux-nilfs@vger.kernel.org,
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com,
syzbot+c37bed40868932d790e9@syzkaller.appspotmail.com
Subject: Re: [PATCH] nilfs2: prevent double insertion of b_assoc_buffers in dirty buffer lookup
Date: Wed, 1 Jul 2026 02:55:10 +0900 [thread overview]
Message-ID: <CAKFNMonk0BDe3PcNdu7ZvSitO1U1TFEvj9mLXAdBK96fCnBScQ@mail.gmail.com> (raw)
In-Reply-To: <CAKFNMokkDqSYUzNkmvztUHx9U3YWPOdYmJ-9xkkQMnutN6H-ug@mail.gmail.com>
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
next prev parent reply other threads:[~2026-06-30 17:55 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-25 5:26 wuyankun
2026-06-25 10:43 ` Ryusuke Konishi
2026-06-30 17:55 ` Ryusuke Konishi [this message]
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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CAKFNMonk0BDe3PcNdu7ZvSitO1U1TFEvj9mLXAdBK96fCnBScQ@mail.gmail.com \
--to=konishi.ryusuke@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-nilfs@vger.kernel.org \
--cc=slava@dubeyko.com \
--cc=syzbot+c37bed40868932d790e9@syzkaller.appspotmail.com \
--cc=syzkaller-bugs@googlegroups.com \
--cc=wuyankun@uniontech.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®