From: Sanan Hasanov <sanan.hasanou@gmail.com>
To: Christian Brauner <brauner@kernel.org>
Cc: Jan Kara <jack@suse.cz>, Alexander Viro <viro@zeniv.linux.org.uk>,
linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org,
Sanan Hasanov <sanan.hasanov@ucf.edu>,
syzbot+e353ad4408c4f9fac965@syzkaller.appspotmail.com
Subject: [PATCH] minix: restore uptodate on bitmap buffers before redirtying them
Date: Sun, 18 Oct 2026 21:36:45 -0400 [thread overview]
Message-ID: <20261019013645.40834-1-sanan.hasanou@gmail.com> (raw)
From: Sanan Hasanov <sanan.hasanov@ucf.edu>
The inode and zone bitmap buffers are read once at mount time and stay
pinned in sbi->s_imap[] and sbi->s_zmap[] until unmount. Their in-memory
contents are the authoritative copy of the allocation state.
If writeback of one of these buffers fails, the buffer write completion
handler marks a write I/O error and clears BH_Uptodate. The next bitmap
update then calls mark_buffer_dirty() on a buffer that is no longer
uptodate and trips:
WARNING: fs/buffer.c:991 at mark_buffer_dirty+0x299/0x410
...
minix_free_block fs/minix/bitmap.c
free_data fs/minix/itree_common.c:272 [inline]
truncate fs/minix/itree_common.c:321 [inline]
V1_minix_truncate+0x310/0x10c0 fs/minix/itree_v1.c:61
minix_evict_inode+0x1c9/0x260 fs/minix/inode.c:52
evict+0x624/0xb50 fs/inode.c:822
minix_mkdir+0xdc/0x120 fs/minix/namei.c:136
syzbot hits this by shrinking the loop device under a mounted minix
filesystem so that bitmap writeback fails, then letting a failed mkdir
evict the new inode and free its blocks.
Since the buffer data is still valid, do what ext2 and ext4 do for their
long-lived superblock buffers: clear the write I/O error and set the
buffer uptodate again before dirtying it, so the bitmap is written out
again on the next writeback. Do this under the buffer lock so it cannot
interleave with a write that is still in flight and about to fail. The
original failure has already been logged and recorded in the block
device mapping by mark_buffer_write_io_error(), so clearing the per-buffer
flag does not hide it.
Reported-by: syzbot+e353ad4408c4f9fac965@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=e353ad4408c4f9fac965
Signed-off-by: Sanan Hasanov <sanan.hasanov@ucf.edu>
---
fs/minix/bitmap.c | 26 ++++++++++++++++++++++----
1 file changed, 22 insertions(+), 4 deletions(-)
diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c
index abec43833..0ac96c88e 100644
--- a/fs/minix/bitmap.c
+++ b/fs/minix/bitmap.c
@@ -39,6 +39,24 @@ static __u32 count_free(struct buffer_head *map[], unsigned blocksize, __u32 num
return sum;
}
+/*
+ * The bitmap buffers stay pinned for the lifetime of the mount and their
+ * in-memory contents are authoritative. A failed writeback clears
+ * BH_Uptodate on them, so restore it before redirtying the buffer instead
+ * of tripping the warning in mark_buffer_dirty(). The buffer lock keeps
+ * this from racing with a write that is still in flight.
+ */
+static void minix_mark_bitmap_dirty(struct buffer_head *bh)
+{
+ lock_buffer(bh);
+ if (!buffer_uptodate(bh)) {
+ clear_buffer_write_io_error(bh);
+ set_buffer_uptodate(bh);
+ }
+ mark_buffer_dirty(bh);
+ unlock_buffer(bh);
+}
+
void minix_free_block(struct inode *inode, unsigned long block)
{
struct super_block *sb = inode->i_sb;
@@ -64,7 +82,7 @@ void minix_free_block(struct inode *inode, unsigned long block)
printk("minix_free_block (%s:%lu): bit already cleared\n",
sb->s_id, block);
spin_unlock(&bitmap_lock);
- mark_buffer_dirty(bh);
+ minix_mark_bitmap_dirty(bh);
return;
}
@@ -83,7 +101,7 @@ int minix_new_block(struct inode * inode)
if (j < bits_per_zone) {
minix_set_bit(j, bh->b_data);
spin_unlock(&bitmap_lock);
- mark_buffer_dirty(bh);
+ minix_mark_bitmap_dirty(bh);
j += i * bits_per_zone + sbi->s_firstdatazone-1;
if (j < sbi->s_firstdatazone || j >= sbi->s_nzones)
break;
@@ -207,7 +225,7 @@ void minix_free_inode(struct inode * inode)
if (!minix_test_and_clear_bit(bit, bh->b_data))
printk("minix_free_inode: bit %lu already cleared\n", bit);
spin_unlock(&bitmap_lock);
- mark_buffer_dirty(bh);
+ minix_mark_bitmap_dirty(bh);
}
struct inode *minix_new_inode(const struct inode *dir, umode_t mode)
@@ -243,7 +261,7 @@ struct inode *minix_new_inode(const struct inode *dir, umode_t mode)
return ERR_PTR(-ENOSPC);
}
spin_unlock(&bitmap_lock);
- mark_buffer_dirty(bh);
+ minix_mark_bitmap_dirty(bh);
j += i * bits_per_zone;
if (!j || j > sbi->s_ninodes) {
iput(inode);
--
2.48.1
reply other threads:[~2026-10-19 1:36 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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=20261019013645.40834-1-sanan.hasanou@gmail.com \
--to=sanan.hasanou@gmail.com \
--cc=brauner@kernel.org \
--cc=jack@suse.cz \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=sanan.hasanov@ucf.edu \
--cc=syzbot+e353ad4408c4f9fac965@syzkaller.appspotmail.com \
--cc=viro@zeniv.linux.org.uk \
/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®