Commit 908f4fbd authored by NeilBrown's avatar NeilBrown

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: default avatarNeilBrown <neilb@suse.de>
parent 2e61ebbc
...@@ -370,12 +370,10 @@ static struct stripe_head *__find_stripe(struct r5conf *conf, sector_t sector, ...@@ -370,12 +370,10 @@ static struct stripe_head *__find_stripe(struct r5conf *conf, sector_t sector,
* of the two sections, and some non-in_sync devices may * of the two sections, and some non-in_sync devices may
* be insync in the section most affected by failed devices. * be insync in the section most affected by failed devices.
*/ */
static int has_failed(struct r5conf *conf) static int calc_degraded(struct r5conf *conf)
{ {
int degraded; int degraded, degraded2;
int i; int i;
if (conf->mddev->reshape_position == MaxSector)
return conf->mddev->degraded > conf->max_degraded;
rcu_read_lock(); rcu_read_lock();
degraded = 0; degraded = 0;
...@@ -399,14 +397,14 @@ static int has_failed(struct r5conf *conf) ...@@ -399,14 +397,14 @@ static int has_failed(struct r5conf *conf)
degraded++; degraded++;
} }
rcu_read_unlock(); rcu_read_unlock();
if (degraded > conf->max_degraded) if (conf->raid_disks == conf->previous_raid_disks)
return 1; return degraded;
rcu_read_lock(); rcu_read_lock();
degraded = 0; degraded2 = 0;
for (i = 0; i < conf->raid_disks; i++) { for (i = 0; i < conf->raid_disks; i++) {
struct md_rdev *rdev = rcu_dereference(conf->disks[i].rdev); struct md_rdev *rdev = rcu_dereference(conf->disks[i].rdev);
if (!rdev || test_bit(Faulty, &rdev->flags)) if (!rdev || test_bit(Faulty, &rdev->flags))
degraded++; degraded2++;
else if (test_bit(In_sync, &rdev->flags)) else if (test_bit(In_sync, &rdev->flags))
; ;
else else
...@@ -416,9 +414,22 @@ static int has_failed(struct r5conf *conf) ...@@ -416,9 +414,22 @@ static int has_failed(struct r5conf *conf)
* almost certainly hasn't. * almost certainly hasn't.
*/ */
if (conf->raid_disks <= conf->previous_raid_disks) if (conf->raid_disks <= conf->previous_raid_disks)
degraded++; degraded2++;
} }
rcu_read_unlock(); rcu_read_unlock();
if (degraded2 > degraded)
return degraded2;
return degraded;
}
static int has_failed(struct r5conf *conf)
{
int degraded;
if (conf->mddev->reshape_position == MaxSector)
return conf->mddev->degraded > conf->max_degraded;
degraded = calc_degraded(conf);
if (degraded > conf->max_degraded) if (degraded > conf->max_degraded)
return 1; return 1;
return 0; return 0;
...@@ -1724,18 +1735,15 @@ static void error(struct mddev *mddev, struct md_rdev *rdev) ...@@ -1724,18 +1735,15 @@ static void error(struct mddev *mddev, struct md_rdev *rdev)
{ {
char b[BDEVNAME_SIZE]; char b[BDEVNAME_SIZE];
struct r5conf *conf = mddev->private; struct r5conf *conf = mddev->private;
unsigned long flags;
pr_debug("raid456: error called\n"); pr_debug("raid456: error called\n");
if (test_and_clear_bit(In_sync, &rdev->flags)) { spin_lock_irqsave(&conf->device_lock, flags);
unsigned long flags; clear_bit(In_sync, &rdev->flags);
spin_lock_irqsave(&conf->device_lock, flags); mddev->degraded = calc_degraded(conf);
mddev->degraded++; spin_unlock_irqrestore(&conf->device_lock, flags);
spin_unlock_irqrestore(&conf->device_lock, flags); set_bit(MD_RECOVERY_INTR, &mddev->recovery);
/*
* if recovery was running, make sure it aborts.
*/
set_bit(MD_RECOVERY_INTR, &mddev->recovery);
}
set_bit(Blocked, &rdev->flags); set_bit(Blocked, &rdev->flags);
set_bit(Faulty, &rdev->flags); set_bit(Faulty, &rdev->flags);
set_bit(MD_CHANGE_DEVS, &mddev->flags); set_bit(MD_CHANGE_DEVS, &mddev->flags);
...@@ -4852,8 +4860,7 @@ static int run(struct mddev *mddev) ...@@ -4852,8 +4860,7 @@ static int run(struct mddev *mddev)
dirty_parity_disks++; dirty_parity_disks++;
} }
mddev->degraded = (max(conf->raid_disks, conf->previous_raid_disks) mddev->degraded = calc_degraded(conf);
- working_disks);
if (has_failed(conf)) { if (has_failed(conf)) {
printk(KERN_ERR "md/raid:%s: not enough operational devices" printk(KERN_ERR "md/raid:%s: not enough operational devices"
...@@ -5025,7 +5032,7 @@ static int raid5_spare_active(struct mddev *mddev) ...@@ -5025,7 +5032,7 @@ static int raid5_spare_active(struct mddev *mddev)
} }
} }
spin_lock_irqsave(&conf->device_lock, flags); spin_lock_irqsave(&conf->device_lock, flags);
mddev->degraded -= count; mddev->degraded = calc_degraded(conf);
spin_unlock_irqrestore(&conf->device_lock, flags); spin_unlock_irqrestore(&conf->device_lock, flags);
print_raid5_conf(conf); print_raid5_conf(conf);
return count; return count;
...@@ -5286,8 +5293,7 @@ static int raid5_start_reshape(struct mddev *mddev) ...@@ -5286,8 +5293,7 @@ static int raid5_start_reshape(struct mddev *mddev)
* pre and post number of devices. * pre and post number of devices.
*/ */
spin_lock_irqsave(&conf->device_lock, flags); spin_lock_irqsave(&conf->device_lock, flags);
mddev->degraded += (conf->raid_disks - conf->previous_raid_disks) mddev->degraded = calc_degraded(conf);
- added_devices;
spin_unlock_irqrestore(&conf->device_lock, flags); spin_unlock_irqrestore(&conf->device_lock, flags);
} }
mddev->raid_disks = conf->raid_disks; mddev->raid_disks = conf->raid_disks;
...@@ -5356,12 +5362,9 @@ static void raid5_finish_reshape(struct mddev *mddev) ...@@ -5356,12 +5362,9 @@ static void raid5_finish_reshape(struct mddev *mddev)
revalidate_disk(mddev->gendisk); revalidate_disk(mddev->gendisk);
} else { } else {
int d; int d;
mddev->degraded = conf->raid_disks; spin_lock_irq(&conf->device_lock);
for (d = 0; d < conf->raid_disks ; d++) mddev->degraded = calc_degraded(conf);
if (conf->disks[d].rdev && spin_unlock_irq(&conf->device_lock);
test_bit(In_sync,
&conf->disks[d].rdev->flags))
mddev->degraded--;
for (d = conf->raid_disks ; for (d = conf->raid_disks ;
d < conf->raid_disks - mddev->delta_disks; d < conf->raid_disks - mddev->delta_disks;
d++) { d++) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment