Skip to content

Commit 2ae6aaf

Browse files
Li Nanliu-song-6
authored andcommitted
md/raid10: fix io loss while replacement replace rdev
When removing a disk with replacement, the replacement will be used to replace rdev. During this process, there is a brief window in which both rdev and replacement are read as NULL in raid10_write_request(). This will result in io not being submitted but it should be. //remove //write raid10_remove_disk raid10_write_request mirror->rdev = NULL read rdev -> NULL mirror->rdev = mirror->replacement mirror->replacement = NULL read replacement -> NULL Fix it by reading replacement first and rdev later, meanwhile, use smp_mb() to prevent memory reordering. Fixes: 475b032 ("md/raid10: writes should get directed to replacement as well as original.") Signed-off-by: Li Nan <[email protected]> Reviewed-by: Yu Kuai <[email protected]> Signed-off-by: Song Liu <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 8d355a4 commit 2ae6aaf

File tree

1 file changed

+18
-4
lines changed

1 file changed

+18
-4
lines changed

drivers/md/raid10.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -779,8 +779,16 @@ static struct md_rdev *read_balance(struct r10conf *conf,
779779
disk = r10_bio->devs[slot].devnum;
780780
rdev = rcu_dereference(conf->mirrors[disk].replacement);
781781
if (rdev == NULL || test_bit(Faulty, &rdev->flags) ||
782-
r10_bio->devs[slot].addr + sectors > rdev->recovery_offset)
782+
r10_bio->devs[slot].addr + sectors >
783+
rdev->recovery_offset) {
784+
/*
785+
* Read replacement first to prevent reading both rdev
786+
* and replacement as NULL during replacement replace
787+
* rdev.
788+
*/
789+
smp_mb();
783790
rdev = rcu_dereference(conf->mirrors[disk].rdev);
791+
}
784792
if (rdev == NULL ||
785793
test_bit(Faulty, &rdev->flags))
786794
continue;
@@ -1482,9 +1490,15 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
14821490

14831491
for (i = 0; i < conf->copies; i++) {
14841492
int d = r10_bio->devs[i].devnum;
1485-
struct md_rdev *rdev = rcu_dereference(conf->mirrors[d].rdev);
1486-
struct md_rdev *rrdev = rcu_dereference(
1487-
conf->mirrors[d].replacement);
1493+
struct md_rdev *rdev, *rrdev;
1494+
1495+
rrdev = rcu_dereference(conf->mirrors[d].replacement);
1496+
/*
1497+
* Read replacement first to prevent reading both rdev and
1498+
* replacement as NULL during replacement replace rdev.
1499+
*/
1500+
smp_mb();
1501+
rdev = rcu_dereference(conf->mirrors[d].rdev);
14881502
if (rdev == rrdev)
14891503
rrdev = NULL;
14901504
if (rdev && (test_bit(Faulty, &rdev->flags)))

0 commit comments

Comments
 (0)