[PATCH 1/4] md/md-bitmap: mask sb->state on load to drop runtime-only bits
From: Mykola Marzhan
Date: Sun Jul 19 2026 - 10:44:32 EST
md_bitmap_read_sb() does `bitmap->flags |= le32_to_cpu(sb->state)`
with no mask, so any bit set in the on-disk state field becomes a
runtime flag. With BITMAP_WRITE_ERROR (bit 2) set on disk,
md_bitmap_create() fails with -EIO and the array refuses to assemble
until the bitmap superblock is rewritten externally.
That bit can genuinely be on disk: kernels before v4.15 wrote
sb->state unmasked -- commit 97f0eb9f0fec ("md/bitmap: clear
BITMAP_WRITE_ERROR bit before writing it to sb") added the
write-side clear -- so an array that hit a transient bitmap write
error under an older kernel carries the bit forever. On-disk
corruption or an external write plants it today.
The write side has masked WRITE_ERROR out since v4.15; the load side
is the missing half. Mask the loaded state to BITMAP_STALE, the
only bit this loader consumes: WRITE_ERROR and DAEMON_BUSY are
kernel-runtime signals, FIRST_USE and CLEAN are used only by the
llbitmap loader (a superblock this loader accepts cannot carry
them, since versions above BITMAP_MAJOR_CLUSTERED are rejected),
and HOSTENDIAN is derived from sb->version, not sb->state.
Reproducer: write 0x04 into byte offset 48 (the state field) of the
bitmap superblock on every member (a single forged member can be
masked by another member's clean copy), then assemble: RUN_ARRAY
fails with -EIO. With this fix the array starts and sb->events
advances normally.
Fixes: 32a7627cf3a3 ("[PATCH] md: optimised resync using Bitmap based intent logging")
Cc: stable@xxxxxxxxxxxxxxx
Assisted-by: Claude-Code:claude-opus-4-8
Signed-off-by: Mykola Marzhan <mykola@xxxxxxxxxxx>
---
drivers/md/md-bitmap.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c
index 0f02e2956398..4dd3fc2a9e15 100644
--- a/drivers/md/md-bitmap.c
+++ b/drivers/md/md-bitmap.c
@@ -931,8 +931,13 @@ static int md_bitmap_read_sb(struct bitmap *bitmap)
}
}
- /* assign fields using values from superblock */
- bitmap->flags |= le32_to_cpu(sb->state);
+ /*
+ * Only BITMAP_STALE is meaningful to this loader from sb->state:
+ * WRITE_ERROR and DAEMON_BUSY are kernel-runtime signals (kernels
+ * before v4.15 persisted WRITE_ERROR), FIRST_USE/CLEAN are
+ * llbitmap-only, and HOSTENDIAN is derived from sb->version below.
+ */
+ bitmap->flags |= le32_to_cpu(sb->state) & BIT(BITMAP_STALE);
if (le32_to_cpu(sb->version) == BITMAP_MAJOR_HOSTENDIAN)
set_bit(BITMAP_HOSTENDIAN, &bitmap->flags);
bitmap->events_cleared = le64_to_cpu(sb->events_cleared);
--
2.43.0