aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2010-06-16 03:01:25 -0400
committerNeilBrown <neilb@suse.de>2010-06-23 23:35:18 -0400
commit70fffd0bfab1558a8c64c5e903dea1fb84cd9f6b (patch)
tree126f2ae8faa2cff8f9dde91cc7a07569ff9851cb /drivers/md
parente4e11e385d1e5516ac76c956d6c25e6c2fa1b8d0 (diff)
md: Don't update ->recovery_offset when reshaping an array to fewer devices.
When an array is reshaped to have fewer devices, the reshape proceeds from the end of the devices to the beginning. If a device happens to be non-In_sync (which is possible but rare) we would normally update the ->recovery_offset as the reshape progresses. However that would be wrong as the recover_offset records that the early part of the device is in_sync, while in fact it would only be the later part that is in_sync, and in any case the offset number would be measured from the wrong end of the device. Relatedly, if after a reshape a spare is discovered to not be recoverred all the way to the end, not allow spare_active to incorporate it in the array. This becomes relevant in the following sample scenario: A 4 drive RAID5 is converted to a 6 drive RAID6 in a combined operation. The RAID5->RAID6 conversion will cause a 5 drive to be included as a spare, then the 5drive -> 6drive reshape will effectively rebuild that spare as it progresses. The 6th drive is treated as in_sync the whole time as there is never any case that we might consider reading from it, but must not because there is no valid data. If we interrupt this reshape part-way through and reverse it to return to a 5-drive RAID6 (or event a 4-drive RAID5), we don't want to update the recovery_offset - as that would be wrong - and we don't want to include that spare as active in the 5-drive RAID6 when the reversed reshape completed and it will be mostly out-of-sync still. Signed-off-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'drivers/md')
-rw-r--r--drivers/md/md.c2
-rw-r--r--drivers/md/raid5.c1
2 files changed, 3 insertions, 0 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 4869128bf74..cb20d0b0555 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -2087,6 +2087,7 @@ static void sync_sbs(mddev_t * mddev, int nospares)
2087 /* First make sure individual recovery_offsets are correct */ 2087 /* First make sure individual recovery_offsets are correct */
2088 list_for_each_entry(rdev, &mddev->disks, same_set) { 2088 list_for_each_entry(rdev, &mddev->disks, same_set) {
2089 if (rdev->raid_disk >= 0 && 2089 if (rdev->raid_disk >= 0 &&
2090 mddev->delta_disks >= 0 &&
2090 !test_bit(In_sync, &rdev->flags) && 2091 !test_bit(In_sync, &rdev->flags) &&
2091 mddev->curr_resync_completed > rdev->recovery_offset) 2092 mddev->curr_resync_completed > rdev->recovery_offset)
2092 rdev->recovery_offset = mddev->curr_resync_completed; 2093 rdev->recovery_offset = mddev->curr_resync_completed;
@@ -6872,6 +6873,7 @@ void md_do_sync(mddev_t *mddev)
6872 rcu_read_lock(); 6873 rcu_read_lock();
6873 list_for_each_entry_rcu(rdev, &mddev->disks, same_set) 6874 list_for_each_entry_rcu(rdev, &mddev->disks, same_set)
6874 if (rdev->raid_disk >= 0 && 6875 if (rdev->raid_disk >= 0 &&
6876 mddev->delta_disks >= 0 &&
6875 !test_bit(Faulty, &rdev->flags) && 6877 !test_bit(Faulty, &rdev->flags) &&
6876 !test_bit(In_sync, &rdev->flags) && 6878 !test_bit(In_sync, &rdev->flags) &&
6877 rdev->recovery_offset < mddev->curr_resync) 6879 rdev->recovery_offset < mddev->curr_resync)
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 2c055dec8c6..f972a94bbc3 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -5208,6 +5208,7 @@ static int raid5_spare_active(mddev_t *mddev)
5208 for (i = 0; i < conf->raid_disks; i++) { 5208 for (i = 0; i < conf->raid_disks; i++) {
5209 tmp = conf->disks + i; 5209 tmp = conf->disks + i;
5210 if (tmp->rdev 5210 if (tmp->rdev
5211 && tmp->rdev->recovery_offset == MaxSector
5211 && !test_bit(Faulty, &tmp->rdev->flags) 5212 && !test_bit(Faulty, &tmp->rdev->flags)
5212 && !test_and_set_bit(In_sync, &tmp->rdev->flags)) { 5213 && !test_and_set_bit(In_sync, &tmp->rdev->flags)) {
5213 unsigned long flags; 5214 unsigned long flags;