aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2013-06-11 01:08:03 -0400
committerNeilBrown <neilb@suse.de>2013-06-13 18:10:27 -0400
commit725d6e579f06360744fc101b1af2f82d8aa282f1 (patch)
treec46f6b92ac05727d1201f6f63276dfeb6ddd4096
parent635f6416a2e983adac8ccf90bffbeed0c1a76454 (diff)
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>
-rw-r--r--drivers/md/raid10.c15
1 files changed, 11 insertions, 4 deletions
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 5169ed2a9156..aa8ba0760cac 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1633,6 +1633,7 @@ static void status(struct seq_file *seq, struct mddev *mddev)
1633static int _enough(struct r10conf *conf, int previous, int ignore) 1633static int _enough(struct r10conf *conf, int previous, int ignore)
1634{ 1634{
1635 int first = 0; 1635 int first = 0;
1636 int has_enough = 0;
1636 int disks, ncopies; 1637 int disks, ncopies;
1637 if (previous) { 1638 if (previous) {
1638 disks = conf->prev.raid_disks; 1639 disks = conf->prev.raid_disks;
@@ -1642,21 +1643,27 @@ static int _enough(struct r10conf *conf, int previous, int ignore)
1642 ncopies = conf->geo.near_copies; 1643 ncopies = conf->geo.near_copies;
1643 } 1644 }
1644 1645
1646 rcu_read_lock();
1645 do { 1647 do {
1646 int n = conf->copies; 1648 int n = conf->copies;
1647 int cnt = 0; 1649 int cnt = 0;
1648 int this = first; 1650 int this = first;
1649 while (n--) { 1651 while (n--) {
1650 if (conf->mirrors[this].rdev && 1652 struct md_rdev *rdev;
1651 this != ignore) 1653 if (this != ignore &&
1654 (rdev = rcu_dereference(conf->mirrors[this].rdev)) &&
1655 test_bit(In_sync, &rdev->flags))
1652 cnt++; 1656 cnt++;
1653 this = (this+1) % disks; 1657 this = (this+1) % disks;
1654 } 1658 }
1655 if (cnt == 0) 1659 if (cnt == 0)
1656 return 0; 1660 goto out;
1657 first = (first + ncopies) % disks; 1661 first = (first + ncopies) % disks;
1658 } while (first != 0); 1662 } while (first != 0);
1659 return 1; 1663 has_enough = 1;
1664out:
1665 rcu_read_unlock();
1666 return has_enough;
1660} 1667}
1661 1668
1662static int enough(struct r10conf *conf, int ignore) 1669static int enough(struct r10conf *conf, int ignore)