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+c37bed...@syzkaller.appspotmail.com
Link:
https://syzkaller.appspot.com/bug?extid=c37bed40868932d790e9
Signed-off-by: wuyankun <
wuya...@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