Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

NeilBrown 725d6e57 635f6416

+11 -4
+11 -4
drivers/md/raid10.c
··· 1633 1633 static int _enough(struct r10conf *conf, int previous, int ignore) 1634 1634 { 1635 1635 int first = 0; 1636 + int has_enough = 0; 1636 1637 int disks, ncopies; 1637 1638 if (previous) { 1638 1639 disks = conf->prev.raid_disks; ··· 1643 1642 ncopies = conf->geo.near_copies; 1644 1643 } 1645 1644 1645 + rcu_read_lock(); 1646 1646 do { 1647 1647 int n = conf->copies; 1648 1648 int cnt = 0; 1649 1649 int this = first; 1650 1650 while (n--) { 1651 - if (conf->mirrors[this].rdev && 1652 - this != ignore) 1651 + struct md_rdev *rdev; 1652 + if (this != ignore && 1653 + (rdev = rcu_dereference(conf->mirrors[this].rdev)) && 1654 + test_bit(In_sync, &rdev->flags)) 1653 1655 cnt++; 1654 1656 this = (this+1) % disks; 1655 1657 } 1656 1658 if (cnt == 0) 1657 - return 0; 1659 + goto out; 1658 1660 first = (first + ncopies) % disks; 1659 1661 } while (first != 0); 1660 - return 1; 1662 + has_enough = 1; 1663 + out: 1664 + rcu_read_unlock(); 1665 + return has_enough; 1661 1666 } 1662 1667 1663 1668 static int enough(struct r10conf *conf, int ignore)