Re: [PATCH v5 03/10] md/raid1: serialize non-write-behind writes on CollisionCheck rdevs

[email protected] Thu, 23 Jul 2026 21:04:40 +0000
Newsgroups org.kernel.vger.linux-raid,org.kernel.vger.linux-pci
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

New issues:
- [High] Hot-added devices silently bypass the array's `MD_SERIALIZE_POLICY`, leaving them vulnerable to overlap write data corruption.

Pre-existing issues:
- [High] Dynamic evaluation of `CollisionCheck` during write-behind I/O completion races with sysfs state changes, leading to use-after-free and memory leaks.
--

--- Patch [3]: [PATCH v5 03/10] md/raid1: serialize non-write-behind writes on CollisionCheck rdevs ---
commit b12be35453573f37c0313dbe2cfc0eb2808cb133
Author: Mykola Marzhan <[email protected]>
md/raid1: serialize non-write-behind writes on CollisionCheck rdevs

This patch changes the serialization gate in raid1 to use CollisionCheck
instead of MD_SERIALIZE_POLICY. It aims to correctly serialize on
write-mostly members when write-behind is armed, and remove a latent NULL
dereference.

Cc: [email protected]

> diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
> index afe2ca96ad8c2..997f79c05db7b 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))

[Severity: High]
This is a pre-existing issue, but does this unlocked dynamic check of
CollisionCheck create a time-of-check to time-of-use race against sysfs
state changes?

When -writemostly is echoed to sysfs, mddev_suspend() is called. For
write-behind I/O, mddev->active_io is decremented early when non-writemostly
clones finish, which allows mddev_suspend() to return while the write-mostly
clone is still in flight.

Then state_store() in drivers/md/md.c calls mddev_destroy_serial_pool()
which frees rdev->serial and clears CollisionCheck:

drivers/md/md.c:rdev_uninit_serial() {
    if (!test_and_clear_bit(CollisionCheck, &rdev->flags))
        return;

    kvfree(rdev->serial);
    rdev->serial = NULL;
}

When the in-flight write-mostly clone subsequently completes here in
raid1_end_write_request(), could it check CollisionCheck and either call
remove_serial() on the freed pointer, or skip it and leak the serial_info
elements?

>  		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))

[Severity: High]
By gating serialization exclusively on CollisionCheck, do hot-added devices
now silently bypass serialization?

When an array has MD_SERIALIZE_POLICY enabled and a new device is hot-added,
mddev_create_serial_pool() skips initializing the device's serial tree
because it doesn't check the global policy flag.

Since CollisionCheck remains unset for the new device, this change masks
the previous NULL pointer dereference crash by skipping serialization for
the hot-added device entirely. Will this leave the array vulnerable to
overlap write data corruption when stale data persists?

>  				wait_for_serialization(rdev, r1_bio);
>  		}

-- 
Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=3