diff options
Diffstat (limited to 'drivers/md/raid5.c')
-rw-r--r-- | drivers/md/raid5.c | 75 |
1 files changed, 71 insertions, 4 deletions
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index f972a94bbc32..d4b233c25f2e 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c | |||
@@ -366,6 +366,73 @@ static struct stripe_head *__find_stripe(raid5_conf_t *conf, sector_t sector, | |||
366 | return NULL; | 366 | return NULL; |
367 | } | 367 | } |
368 | 368 | ||
369 | /* | ||
370 | * Need to check if array has failed when deciding whether to: | ||
371 | * - start an array | ||
372 | * - remove non-faulty devices | ||
373 | * - add a spare | ||
374 | * - allow a reshape | ||
375 | * This determination is simple when no reshape is happening. | ||
376 | * However if there is a reshape, we need to carefully check | ||
377 | * both the before and after sections. | ||
378 | * This is because some failed devices may only affect one | ||
379 | * of the two sections, and some non-in_sync devices may | ||
380 | * be insync in the section most affected by failed devices. | ||
381 | */ | ||
382 | static int has_failed(raid5_conf_t *conf) | ||
383 | { | ||
384 | int degraded; | ||
385 | int i; | ||
386 | if (conf->mddev->reshape_position == MaxSector) | ||
387 | return conf->mddev->degraded > conf->max_degraded; | ||
388 | |||
389 | rcu_read_lock(); | ||
390 | degraded = 0; | ||
391 | for (i = 0; i < conf->previous_raid_disks; i++) { | ||
392 | mdk_rdev_t *rdev = rcu_dereference(conf->disks[i].rdev); | ||
393 | if (!rdev || test_bit(Faulty, &rdev->flags)) | ||
394 | degraded++; | ||
395 | else if (test_bit(In_sync, &rdev->flags)) | ||
396 | ; | ||
397 | else | ||
398 | /* not in-sync or faulty. | ||
399 | * If the reshape increases the number of devices, | ||
400 | * this is being recovered by the reshape, so | ||
401 | * this 'previous' section is not in_sync. | ||
402 | * If the number of devices is being reduced however, | ||
403 | * the device can only be part of the array if | ||
404 | * we are reverting a reshape, so this section will | ||
405 | * be in-sync. | ||
406 | */ | ||
407 | if (conf->raid_disks >= conf->previous_raid_disks) | ||
408 | degraded++; | ||
409 | } | ||
410 | rcu_read_unlock(); | ||
411 | if (degraded > conf->max_degraded) | ||
412 | return 1; | ||
413 | rcu_read_lock(); | ||
414 | degraded = 0; | ||
415 | for (i = 0; i < conf->raid_disks; i++) { | ||
416 | mdk_rdev_t *rdev = rcu_dereference(conf->disks[i].rdev); | ||
417 | if (!rdev || test_bit(Faulty, &rdev->flags)) | ||
418 | degraded++; | ||
419 | else if (test_bit(In_sync, &rdev->flags)) | ||
420 | ; | ||
421 | else | ||
422 | /* not in-sync or faulty. | ||
423 | * If reshape increases the number of devices, this | ||
424 | * section has already been recovered, else it | ||
425 | * almost certainly hasn't. | ||
426 | */ | ||
427 | if (conf->raid_disks <= conf->previous_raid_disks) | ||
428 | degraded++; | ||
429 | } | ||
430 | rcu_read_unlock(); | ||
431 | if (degraded > conf->max_degraded) | ||
432 | return 1; | ||
433 | return 0; | ||
434 | } | ||
435 | |||
369 | static void unplug_slaves(mddev_t *mddev); | 436 | static void unplug_slaves(mddev_t *mddev); |
370 | static void raid5_unplug_device(struct request_queue *q); | 437 | static void raid5_unplug_device(struct request_queue *q); |
371 | 438 | ||
@@ -5006,7 +5073,7 @@ static int run(mddev_t *mddev) | |||
5006 | mddev->degraded = (max(conf->raid_disks, conf->previous_raid_disks) | 5073 | mddev->degraded = (max(conf->raid_disks, conf->previous_raid_disks) |
5007 | - working_disks); | 5074 | - working_disks); |
5008 | 5075 | ||
5009 | if (mddev->degraded > conf->max_degraded) { | 5076 | if (has_failed(conf)) { |
5010 | printk(KERN_ERR "md/raid:%s: not enough operational devices" | 5077 | printk(KERN_ERR "md/raid:%s: not enough operational devices" |
5011 | " (%d/%d failed)\n", | 5078 | " (%d/%d failed)\n", |
5012 | mdname(mddev), mddev->degraded, conf->raid_disks); | 5079 | mdname(mddev), mddev->degraded, conf->raid_disks); |
@@ -5244,7 +5311,7 @@ static int raid5_remove_disk(mddev_t *mddev, int number) | |||
5244 | * isn't possible. | 5311 | * isn't possible. |
5245 | */ | 5312 | */ |
5246 | if (!test_bit(Faulty, &rdev->flags) && | 5313 | if (!test_bit(Faulty, &rdev->flags) && |
5247 | mddev->degraded <= conf->max_degraded && | 5314 | !has_failed(conf) && |
5248 | number < conf->raid_disks) { | 5315 | number < conf->raid_disks) { |
5249 | err = -EBUSY; | 5316 | err = -EBUSY; |
5250 | goto abort; | 5317 | goto abort; |
@@ -5272,7 +5339,7 @@ static int raid5_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) | |||
5272 | int first = 0; | 5339 | int first = 0; |
5273 | int last = conf->raid_disks - 1; | 5340 | int last = conf->raid_disks - 1; |
5274 | 5341 | ||
5275 | if (mddev->degraded > conf->max_degraded) | 5342 | if (has_failed(conf)) |
5276 | /* no point adding a device */ | 5343 | /* no point adding a device */ |
5277 | return -EINVAL; | 5344 | return -EINVAL; |
5278 | 5345 | ||
@@ -5364,7 +5431,7 @@ static int check_reshape(mddev_t *mddev) | |||
5364 | if (mddev->bitmap) | 5431 | if (mddev->bitmap) |
5365 | /* Cannot grow a bitmap yet */ | 5432 | /* Cannot grow a bitmap yet */ |
5366 | return -EBUSY; | 5433 | return -EBUSY; |
5367 | if (mddev->degraded > conf->max_degraded) | 5434 | if (has_failed(conf)) |
5368 | return -EINVAL; | 5435 | return -EINVAL; |
5369 | if (mddev->delta_disks < 0) { | 5436 | if (mddev->delta_disks < 0) { |
5370 | /* We might be able to shrink, but the devices must | 5437 | /* We might be able to shrink, but the devices must |