A write that skips write-behind (full behind queue, a waiting reader, failed behind-bio allocation) races the in-flight behind write it overlaps: nothing orders the two on the write-mostly member, and if the older behind data lands last the member keeps stale data for sectors already acknowledged as rewritten. Serialize on CollisionCheck, which marks exactly the rdevs owning a serial tree: serialize_policy rdevs plus write-mostly members when write-behind arms serialization -- the case the MD_SERIALIZE_POLICY test misses. remove_serial() under the same condition. This also avoids the old gate's latent NULL deref for rdevs hot-added under serialize_policy (they never get a serial tree). Fixes: d0d2d8ba0494 ("md/raid1: introduce wait_for_serialization") Cc: stable@vger.kernel.org Assisted-by: Claude:claude-fable-5 Signed-off-by: Mykola Marzhan --- drivers/md/raid1.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index afe2ca96ad8c..997f79c05db7 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -564,7 +564,7 @@ static void raid1_end_write_request(struct bio *bio) call_bio_endio(r1_bio); } } - } else if (test_bit(MD_SERIALIZE_POLICY, &rdev->mddev->flags)) + } else if (test_bit(CollisionCheck, &rdev->flags)) remove_serial(rdev, lo, hi); if (r1_bio->bios[mirror] == NULL) rdev_dec_pending(rdev, conf->mddev); @@ -1677,7 +1677,11 @@ static bool raid1_write_request(struct mddev *mddev, struct bio *bio, mbio = bio_alloc_clone(rdev->bdev, bio, GFP_NOIO, &mddev->bio_set); - if (test_bit(MD_SERIALIZE_POLICY, &mddev->flags)) + /* + * CollisionCheck marks every rdev with a serial + * tree; order against in-flight write-behind I/O. + */ + if (test_bit(CollisionCheck, &rdev->flags)) wait_for_serialization(rdev, r1_bio); } -- 2.52.0