diff options
author | NeilBrown <neilb@suse.de> | 2013-06-11 01:08:03 -0400 |
---|---|---|
committer | NeilBrown <neilb@suse.de> | 2013-06-13 18:10:27 -0400 |
commit | 725d6e579f06360744fc101b1af2f82d8aa282f1 (patch) | |
tree | c46f6b92ac05727d1201f6f63276dfeb6ddd4096 | |
parent | 635f6416a2e983adac8ccf90bffbeed0c1a76454 (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.c | 15 |
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) | |||
1633 | static int _enough(struct r10conf *conf, int previous, int ignore) | 1633 | static 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; |
1664 | out: | ||
1665 | rcu_read_unlock(); | ||
1666 | return has_enough; | ||
1660 | } | 1667 | } |
1661 | 1668 | ||
1662 | static int enough(struct r10conf *conf, int ignore) | 1669 | static int enough(struct r10conf *conf, int ignore) |