* [PATCH] minix: restore uptodate on bitmap buffers before redirtying them
@ 2026-10-19 1:36 Sanan Hasanov
0 siblings, 0 replies; only message in thread
From: Sanan Hasanov @ 2026-10-19 1:36 UTC (permalink / raw)
To: Christian Brauner
Cc: Jan Kara, Alexander Viro, linux-fsdevel, linux-kernel,
Sanan Hasanov, syzbot+e353ad4408c4f9fac965
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
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-10-19 1:36 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-19 1:36 [PATCH] minix: restore uptodate on bitmap buffers before redirtying them Sanan Hasanov
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®