[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20241211.203019.1906828475608694378.konishi.ryusuke@gmail.com>
Date: Wed, 11 Dec 2024 20:30:19 +0900 (JST)
From: Ryusuke Konishi <konishi.ryusuke@...il.com>
To: syzbot+b2b14916b77acf8626d7@...kaller.appspotmail.com
Cc: linux-kernel@...r.kernel.org, syzkaller-bugs@...glegroups.com
Subject: Re: [syzbot] [nilfs?] WARNING in nilfs_btree_propagate (2)
Check if the buffer is referenced before clearing the page/folio state,
and skip the clear if it is.
#syz test
diff --git a/fs/nilfs2/page.c b/fs/nilfs2/page.c
index 10def4b55995..ad99497f90af 100644
--- a/fs/nilfs2/page.c
+++ b/fs/nilfs2/page.c
@@ -392,6 +392,11 @@ void nilfs_clear_dirty_pages(struct address_space *mapping)
/**
* nilfs_clear_folio_dirty - discard dirty folio
* @folio: dirty folio that will be discarded
+ *
+ * nilfs_clear_folio_dirty() clears working states including dirty state for
+ * the folio and its buffers. If the folio has buffers, clear only if it is
+ * confirmed that none of the buffer heads are busy (none have valid
+ * references and none are locked).
*/
void nilfs_clear_folio_dirty(struct folio *folio)
{
@@ -399,10 +404,6 @@ void nilfs_clear_folio_dirty(struct folio *folio)
BUG_ON(!folio_test_locked(folio));
- folio_clear_uptodate(folio);
- folio_clear_mappedtodisk(folio);
- folio_clear_checked(folio);
-
head = folio_buffers(folio);
if (head) {
const unsigned long clear_bits =
@@ -410,6 +411,25 @@ void nilfs_clear_folio_dirty(struct folio *folio)
BIT(BH_Async_Write) | BIT(BH_NILFS_Volatile) |
BIT(BH_NILFS_Checked) | BIT(BH_NILFS_Redirected) |
BIT(BH_Delay));
+ bool busy, invalidated = false;
+
+recheck_buffers:
+ busy = false;
+ bh = head;
+ do {
+ if (atomic_read(&bh->b_count) | buffer_locked(bh)) {
+ busy = true;
+ break;
+ }
+ } while (bh = bh->b_this_page, bh != head);
+
+ if (busy) {
+ if (invalidated)
+ return;
+ invalidate_bh_lrus();
+ invalidated = true;
+ goto recheck_buffers;
+ }
bh = head;
do {
@@ -419,6 +439,9 @@ void nilfs_clear_folio_dirty(struct folio *folio)
} while (bh = bh->b_this_page, bh != head);
}
+ folio_clear_uptodate(folio);
+ folio_clear_mappedtodisk(folio);
+ folio_clear_checked(folio);
__nilfs_clear_folio_dirty(folio);
}
Powered by blists - more mailing lists