diff options
author | NeilBrown <neilb@suse.de> | 2011-12-22 18:17:50 -0500 |
---|---|---|
committer | NeilBrown <neilb@suse.de> | 2011-12-22 18:17:50 -0500 |
commit | 908f4fbd265733310c17ecc906299846b5dac44a (patch) | |
tree | 71e364c57887213431143e6fd1296e8433cc6293 /drivers/md | |
parent | 2e61ebbcc45438899235d7a39f17291cb24e746c (diff) |
md/raid5: be more thorough in calculating 'degraded' value.
When an array is being reshaped to change the number of devices,
the two halves can be differently degraded. e.g. one could be
missing a device and the other not.
So we need to be more careful about calculating the 'degraded'
attribute.
Instead of just inc/dec at appropriate times, perform a full
re-calculation examining both possible cases. This doesn't happen
often so it not a big cost, and we already have most of the code to
do it.
Signed-off-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'drivers/md')
-rw-r--r-- | drivers/md/raid5.c | 63 |
1 files changed, 33 insertions, 30 deletions
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 858fdbb7eb07..a68c49250ed5 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c | |||
@@ -370,12 +370,10 @@ static struct stripe_head *__find_stripe(struct r5conf *conf, sector_t sector, | |||
370 | * of the two sections, and some non-in_sync devices may | 370 | * of the two sections, and some non-in_sync devices may |
371 | * be insync in the section most affected by failed devices. | 371 | * be insync in the section most affected by failed devices. |
372 | */ | 372 | */ |
373 | static int has_failed(struct r5conf *conf) | 373 | static int calc_degraded(struct r5conf *conf) |
374 | { | 374 | { |
375 | int degraded; | 375 | int degraded, degraded2; |
376 | int i; | 376 | int i; |
377 | if (conf->mddev->reshape_position == MaxSector) | ||
378 | return conf->mddev->degraded > conf->max_degraded; | ||
379 | 377 | ||
380 | rcu_read_lock(); | 378 | rcu_read_lock(); |
381 | degraded = 0; | 379 | degraded = 0; |
@@ -399,14 +397,14 @@ static int has_failed(struct r5conf *conf) | |||
399 | degraded++; | 397 | degraded++; |
400 | } | 398 | } |
401 | rcu_read_unlock(); | 399 | rcu_read_unlock(); |
402 | if (degraded > conf->max_degraded) | 400 | if (conf->raid_disks == conf->previous_raid_disks) |
403 | return 1; | 401 | return degraded; |
404 | rcu_read_lock(); | 402 | rcu_read_lock(); |
405 | degraded = 0; | 403 | degraded2 = 0; |
406 | for (i = 0; i < conf->raid_disks; i++) { | 404 | for (i = 0; i < conf->raid_disks; i++) { |
407 | struct md_rdev *rdev = rcu_dereference(conf->disks[i].rdev); | 405 | struct md_rdev *rdev = rcu_dereference(conf->disks[i].rdev); |
408 | if (!rdev || test_bit(Faulty, &rdev->flags)) | 406 | if (!rdev || test_bit(Faulty, &rdev->flags)) |
409 | degraded++; | 407 | degraded2++; |
410 | else if (test_bit(In_sync, &rdev->flags)) | 408 | else if (test_bit(In_sync, &rdev->flags)) |
411 | ; | 409 | ; |
412 | else | 410 | else |
@@ -416,9 +414,22 @@ static int has_failed(struct r5conf *conf) | |||
416 | * almost certainly hasn't. | 414 | * almost certainly hasn't. |
417 | */ | 415 | */ |
418 | if (conf->raid_disks <= conf->previous_raid_disks) | 416 | if (conf->raid_disks <= conf->previous_raid_disks) |
419 | degraded++; | 417 | degraded2++; |
420 | } | 418 | } |
421 | rcu_read_unlock(); | 419 | rcu_read_unlock(); |
420 | if (degraded2 > degraded) | ||
421 | return degraded2; | ||
422 | return degraded; | ||
423 | } | ||
424 | |||
425 | static int has_failed(struct r5conf *conf) | ||
426 | { | ||
427 | int degraded; | ||
428 | |||
429 | if (conf->mddev->reshape_position == MaxSector) | ||
430 | return conf->mddev->degraded > conf->max_degraded; | ||
431 | |||
432 | degraded = calc_degraded(conf); | ||
422 | if (degraded > conf->max_degraded) | 433 | if (degraded > conf->max_degraded) |
423 | return 1; | 434 | return 1; |
424 | return 0; | 435 | return 0; |
@@ -1724,18 +1735,15 @@ static void error(struct mddev *mddev, struct md_rdev *rdev) | |||
1724 | { | 1735 | { |
1725 | char b[BDEVNAME_SIZE]; | 1736 | char b[BDEVNAME_SIZE]; |
1726 | struct r5conf *conf = mddev->private; | 1737 | struct r5conf *conf = mddev->private; |
1738 | unsigned long flags; | ||
1727 | pr_debug("raid456: error called\n"); | 1739 | pr_debug("raid456: error called\n"); |
1728 | 1740 | ||
1729 | if (test_and_clear_bit(In_sync, &rdev->flags)) { | 1741 | spin_lock_irqsave(&conf->device_lock, flags); |
1730 | unsigned long flags; | 1742 | clear_bit(In_sync, &rdev->flags); |
1731 | spin_lock_irqsave(&conf->device_lock, flags); | 1743 | mddev->degraded = calc_degraded(conf); |
1732 | mddev->degraded++; | 1744 | spin_unlock_irqrestore(&conf->device_lock, flags); |
1733 | spin_unlock_irqrestore(&conf->device_lock, flags); | 1745 | set_bit(MD_RECOVERY_INTR, &mddev->recovery); |
1734 | /* | 1746 | |
1735 | * if recovery was running, make sure it aborts. | ||
1736 | */ | ||
1737 | set_bit(MD_RECOVERY_INTR, &mddev->recovery); | ||
1738 | } | ||
1739 | set_bit(Blocked, &rdev->flags); | 1747 | set_bit(Blocked, &rdev->flags); |
1740 | set_bit(Faulty, &rdev->flags); | 1748 | set_bit(Faulty, &rdev->flags); |
1741 | set_bit(MD_CHANGE_DEVS, &mddev->flags); | 1749 | set_bit(MD_CHANGE_DEVS, &mddev->flags); |
@@ -4852,8 +4860,7 @@ static int run(struct mddev *mddev) | |||
4852 | dirty_parity_disks++; | 4860 | dirty_parity_disks++; |
4853 | } | 4861 | } |
4854 | 4862 | ||
4855 | mddev->degraded = (max(conf->raid_disks, conf->previous_raid_disks) | 4863 | mddev->degraded = calc_degraded(conf); |
4856 | - working_disks); | ||
4857 | 4864 | ||
4858 | if (has_failed(conf)) { | 4865 | if (has_failed(conf)) { |
4859 | printk(KERN_ERR "md/raid:%s: not enough operational devices" | 4866 | printk(KERN_ERR "md/raid:%s: not enough operational devices" |
@@ -5025,7 +5032,7 @@ static int raid5_spare_active(struct mddev *mddev) | |||
5025 | } | 5032 | } |
5026 | } | 5033 | } |
5027 | spin_lock_irqsave(&conf->device_lock, flags); | 5034 | spin_lock_irqsave(&conf->device_lock, flags); |
5028 | mddev->degraded -= count; | 5035 | mddev->degraded = calc_degraded(conf); |
5029 | spin_unlock_irqrestore(&conf->device_lock, flags); | 5036 | spin_unlock_irqrestore(&conf->device_lock, flags); |
5030 | print_raid5_conf(conf); | 5037 | print_raid5_conf(conf); |
5031 | return count; | 5038 | return count; |
@@ -5286,8 +5293,7 @@ static int raid5_start_reshape(struct mddev *mddev) | |||
5286 | * pre and post number of devices. | 5293 | * pre and post number of devices. |
5287 | */ | 5294 | */ |
5288 | spin_lock_irqsave(&conf->device_lock, flags); | 5295 | spin_lock_irqsave(&conf->device_lock, flags); |
5289 | mddev->degraded += (conf->raid_disks - conf->previous_raid_disks) | 5296 | mddev->degraded = calc_degraded(conf); |
5290 | - added_devices; | ||
5291 | spin_unlock_irqrestore(&conf->device_lock, flags); | 5297 | spin_unlock_irqrestore(&conf->device_lock, flags); |
5292 | } | 5298 | } |
5293 | mddev->raid_disks = conf->raid_disks; | 5299 | mddev->raid_disks = conf->raid_disks; |
@@ -5356,12 +5362,9 @@ static void raid5_finish_reshape(struct mddev *mddev) | |||
5356 | revalidate_disk(mddev->gendisk); | 5362 | revalidate_disk(mddev->gendisk); |
5357 | } else { | 5363 | } else { |
5358 | int d; | 5364 | int d; |
5359 | mddev->degraded = conf->raid_disks; | 5365 | spin_lock_irq(&conf->device_lock); |
5360 | for (d = 0; d < conf->raid_disks ; d++) | 5366 | mddev->degraded = calc_degraded(conf); |
5361 | if (conf->disks[d].rdev && | 5367 | spin_unlock_irq(&conf->device_lock); |
5362 | test_bit(In_sync, | ||
5363 | &conf->disks[d].rdev->flags)) | ||
5364 | mddev->degraded--; | ||
5365 | for (d = conf->raid_disks ; | 5368 | for (d = conf->raid_disks ; |
5366 | d < conf->raid_disks - mddev->delta_disks; | 5369 | d < conf->raid_disks - mddev->delta_disks; |
5367 | d++) { | 5370 | d++) { |