[PATCH v4 3/3] md/raid5: warn when a read fails due in some part to bad-block metadata

From: Doug V Johnson

Date: Fri Oct 16 2026 - 00:27:06 EST


Report that bad block metadata contributed to a read failure on the
array so that it's clear that the failure may not be directly due to
an immediate underlying device read failure.

There has been a documented case of bad block metadata being erroneously
copied around contributing to mystery read failures with no underlying
device failure. This warning will help users understand why the
failure exists and may lead to the discovery of this condition sooner.

Link: https://lore.kernel.org/r/20250224090209.2077-2-dougvj@xxxxxxxxxx
Link: https://lkml.iu.edu/2501.3/01088.html
Assisted-by: LLM
Signed-off-by: Doug V Johnson <me@xxxxxxxxx>
---
drivers/md/raid5.c | 16 ++++++++++++++++
drivers/md/raid5.h | 2 +-
2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 23ff549fa363..f721eb97f655 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -3672,6 +3672,16 @@ handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh,
wake_up_bit(&sh->dev[i].flags, R5_Overlap);
if (bi)
s->to_read--;
+ /*
+ * If we recorded bad blocks from the metadata
+ * on any of the devices then report this to
+ * userspace in case anyone might suspect
+ * something more fundamental instead
+ */
+ if (bi && s->bad_blocks)
+ pr_warn_ratelimited("%s: read encountered block in device bad block list at %llu\n",
+ mdname(conf->mddev),
+ (unsigned long long)sh->sector);
while (bi && bi->bi_iter.bi_sector <
sh->dev[i].sector + RAID5_STRIPE_SECTORS(conf)) {
struct bio *nextbi =
@@ -4764,6 +4774,12 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s)
if (rdev) {
is_bad = rdev_has_badblock(rdev, sh->sector,
RAID5_STRIPE_SECTORS(conf));
+ if (is_bad) {
+ s->bad_blocks++;
+ pr_debug("bad blocks encountered dev %i sector %llu %lu\n",
+ i, (unsigned long long)sh->sector,
+ (unsigned long)RAID5_STRIPE_SECTORS(conf));
+ }
if (s->blocked_rdev == NULL) {
if (is_bad < 0)
set_bit(BlockedBadBlocks, &rdev->flags);
diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h
index cb5feae04db2..6b90c9565ec0 100644
--- a/drivers/md/raid5.h
+++ b/drivers/md/raid5.h
@@ -282,7 +282,7 @@ struct stripe_head_state {
* read all devices, just the replacement targets.
*/
int syncing, expanding, expanded, replacing;
- int locked, uptodate, to_read, to_write, failed, written;
+ int locked, uptodate, to_read, to_write, failed, written, bad_blocks;
int to_fill, compute, req_compute, non_overwrite;
int injournal, just_cached;
int failed_num[2];
--
2.54.0