A write-behind write is acknowledged to the caller while its copy to the write-mostly member is still in flight. wait_for_serialization() exists to order later overlapping writes behind it, but the non-behind clone path only takes it under serialize_policy. A write to a write-behind array skips the behind path whenever the behind queue is full, a reader is waiting on behind completion, or the behind bio allocation fails (raid1_start_write_behind()) -- and then races the in-flight behind write on the write-mostly member without any ordering: if the older behind data lands last, the member keeps stale data for sectors whose newer write the caller has already seen acknowledged. Gate the non-behind serialization on CollisionCheck alone. The flag marks exactly the rdevs that own a serial tree: every rdev present when serialize_policy is enabled, and write-mostly members when write-behind arms serialization, which is the case the current test misses. Take the matching remove_serial() at completion under the same condition. Discards take the same non-behind path and are now ordered as well. For an rdev hot-added while serialize_policy is already enabled, mddev_create_serial_pool() never builds a serial tree, so the old MD_SERIALIZE_POLICY gate sent it into wait_for_serialization() with rdev->serial == NULL -- a latent oops that the per-rdev gate avoids by construction. REQ_NOWAIT writes can wait here when they overlap an in-flight behind write, as they already do on the behind path and under serialize_policy. 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 | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index afe2ca96ad8c..8172df882f26 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,14 @@ 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)) + /* + * Order against in-flight write-behind I/O: a + * behind write is acked early, and an unordered + * overwrite could land first, leaving its stale + * data on the member last. CollisionCheck marks + * every rdev that owns a serial tree. + */ + if (test_bit(CollisionCheck, &rdev->flags)) wait_for_serialization(rdev, r1_bio); } -- 2.43.0