md/raid10: check In_sync flag in 'enough()'.
It isn't really enough to check that the rdev is present, we need to also be sure that the device is still In_sync. Doing this requires using rcu_dereference to access the rdev, and holding the rcu_read_lock() to ensure the rdev doesn't disappear while we look at it. Signed-off-by: NeilBrown <neilb@suse.de>
This commit is contained in:
parent
635f6416a2
commit
725d6e579f
@ -1633,6 +1633,7 @@ static void status(struct seq_file *seq, struct mddev *mddev)
|
||||
static int _enough(struct r10conf *conf, int previous, int ignore)
|
||||
{
|
||||
int first = 0;
|
||||
int has_enough = 0;
|
||||
int disks, ncopies;
|
||||
if (previous) {
|
||||
disks = conf->prev.raid_disks;
|
||||
@ -1642,21 +1643,27 @@ static int _enough(struct r10conf *conf, int previous, int ignore)
|
||||
ncopies = conf->geo.near_copies;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
do {
|
||||
int n = conf->copies;
|
||||
int cnt = 0;
|
||||
int this = first;
|
||||
while (n--) {
|
||||
if (conf->mirrors[this].rdev &&
|
||||
this != ignore)
|
||||
struct md_rdev *rdev;
|
||||
if (this != ignore &&
|
||||
(rdev = rcu_dereference(conf->mirrors[this].rdev)) &&
|
||||
test_bit(In_sync, &rdev->flags))
|
||||
cnt++;
|
||||
this = (this+1) % disks;
|
||||
}
|
||||
if (cnt == 0)
|
||||
return 0;
|
||||
goto out;
|
||||
first = (first + ncopies) % disks;
|
||||
} while (first != 0);
|
||||
return 1;
|
||||
has_enough = 1;
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
return has_enough;
|
||||
}
|
||||
|
||||
static int enough(struct r10conf *conf, int ignore)
|
||||
|
Loading…
Reference in New Issue
Block a user