| From: Ryusuke Konishi <konishi.ryusuke@gmail.com> |
| Subject: nilfs2: fix kernel bug due to missing clearing of buffer delay flag |
| Date: Wed, 16 Oct 2024 06:32:07 +0900 |
| |
| Syzbot reported that after nilfs2 reads a corrupted file system image and |
| degrades to read-only, the BUG_ON check for the buffer delay flag in |
| submit_bh_wbc() may fail, causing a kernel bug. |
| |
| This is because the buffer delay flag is not cleared when clearing the |
| buffer state flags to discard a page/folio or a buffer head. So, fix |
| this. |
| |
| This became necessary when the use of nilfs2's own page clear routine was |
| expanded. This state inconsistency does not occur if the buffer is |
| written normally by log writing. |
| |
| Link: https://lkml.kernel.org/r/20241015213300.7114-1-konishi.ryusuke@gmail.com |
| Fixes: 8c26c4e2694a ("nilfs2: fix issue with flush kernel thread after remount in RO mode because of driver's internal error or metadata corruption") |
| Signed-off-by: Ryusuke Konishi <konishi.ryusuke@gmail.com> |
| Reported-by: syzbot+985ada84bf055a575c07@syzkaller.appspotmail.com |
| Closes: https://syzkaller.appspot.com/bug?extid=985ada84bf055a575c07 |
| Cc: <stable@vger.kernel.org> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| --- |
| |
| fs/nilfs2/page.c | 6 ++++-- |
| 1 file changed, 4 insertions(+), 2 deletions(-) |
| |
| --- a/fs/nilfs2/page.c~nilfs2-fix-kernel-bug-due-to-missing-clearing-of-buffer-delay-flag |
| +++ a/fs/nilfs2/page.c |
| @@ -77,7 +77,8 @@ void nilfs_forget_buffer(struct buffer_h |
| const unsigned long clear_bits = |
| (BIT(BH_Uptodate) | BIT(BH_Dirty) | BIT(BH_Mapped) | |
| BIT(BH_Async_Write) | BIT(BH_NILFS_Volatile) | |
| - BIT(BH_NILFS_Checked) | BIT(BH_NILFS_Redirected)); |
| + BIT(BH_NILFS_Checked) | BIT(BH_NILFS_Redirected) | |
| + BIT(BH_Delay)); |
| |
| lock_buffer(bh); |
| set_mask_bits(&bh->b_state, clear_bits, 0); |
| @@ -406,7 +407,8 @@ void nilfs_clear_folio_dirty(struct foli |
| const unsigned long clear_bits = |
| (BIT(BH_Uptodate) | BIT(BH_Dirty) | BIT(BH_Mapped) | |
| BIT(BH_Async_Write) | BIT(BH_NILFS_Volatile) | |
| - BIT(BH_NILFS_Checked) | BIT(BH_NILFS_Redirected)); |
| + BIT(BH_NILFS_Checked) | BIT(BH_NILFS_Redirected) | |
| + BIT(BH_Delay)); |
| |
| bh = head; |
| do { |
| _ |