aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2011-07-27 11:00:36 +1000
committerNeilBrown <neilb@suse.de>2011-07-27 11:00:36 +1000
commit5389042ffa36976caa45a79af16081d759001fa7 (patch)
treeeb303de141a50f41ccac438e734b65dbfe25825e
parenta478a069b6adf186373a6648c54fc5f1d3c2f8eb (diff)
md: change managed of recovery_disabled.
If we hit a read error while recovering a mirror, we want to abort the recovery without necessarily failing the disk - as having a disk this a read error is better than not having an array at all. Currently this is managed with a per-array flag "recovery_disabled" and is only implemented for RAID1. For RAID10 we will need finer grained control as we might want to disable recovery for individual devices separately. So push more of the decision making into the personality. 'recovery_disabled' is now a 'cookie' which is copied when the personality want to disable recovery and is changed when a device is added to the array as this is used as a trigger to 'try recovery again'. This will allow RAID10 to get the control that it needs. Signed-off-by: NeilBrown <neilb@suse.de>
-rw-r--r--drivers/md/md.c4
-rw-r--r--drivers/md/md.h9
-rw-r--r--drivers/md/raid1.c7
-rw-r--r--drivers/md/raid1.h6
4 files changed, 19 insertions, 7 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 77bd8d8708e..c7d9c6af463 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -1922,7 +1922,7 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
bd_link_disk_holder(rdev->bdev, mddev->gendisk);
/* May as well allow recovery to be retried once */
- mddev->recovery_disabled = 0;
+ mddev->recovery_disabled++;
return 0;
@@ -7070,7 +7070,7 @@ static int remove_and_add_spares(mddev_t *mddev)
}
}
- if (mddev->degraded && !mddev->recovery_disabled) {
+ if (mddev->degraded) {
list_for_each_entry(rdev, &mddev->disks, same_set) {
if (rdev->raid_disk >= 0 &&
!test_bit(In_sync, &rdev->flags) &&
diff --git a/drivers/md/md.h b/drivers/md/md.h
index 6863f722cd2..de5455d30d4 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -239,9 +239,12 @@ struct mddev_s
#define MD_RECOVERY_FROZEN 9
unsigned long recovery;
- int recovery_disabled; /* if we detect that recovery
- * will always fail, set this
- * so we don't loop trying */
+ /* If a RAID personality determines that recovery (of a particular
+ * device) will fail due to a read error on the source device, it
+ * takes a copy of this number and does not attempt recovery again
+ * until this number changes.
+ */
+ int recovery_disabled;
int in_sync; /* know to not need resync */
/* 'open_mutex' avoids races between 'md_open' and 'do_md_stop', so
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 1d79a041db0..44069b38d6d 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -956,7 +956,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
* However don't try a recovery from this drive as
* it is very likely to fail.
*/
- mddev->recovery_disabled = 1;
+ conf->recovery_disabled = mddev->recovery_disabled;
return;
}
if (test_and_clear_bit(In_sync, &rdev->flags)) {
@@ -1052,6 +1052,9 @@ static int raid1_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
int first = 0;
int last = mddev->raid_disks - 1;
+ if (mddev->recovery_disabled == conf->recovery_disabled)
+ return -EBUSY;
+
if (rdev->raid_disk >= 0)
first = last = rdev->raid_disk;
@@ -1107,7 +1110,7 @@ static int raid1_remove_disk(mddev_t *mddev, int number)
* is not possible.
*/
if (!test_bit(Faulty, &rdev->flags) &&
- !mddev->recovery_disabled &&
+ mddev->recovery_disabled != conf->recovery_disabled &&
mddev->degraded < conf->raid_disks) {
err = -EBUSY;
goto abort;
diff --git a/drivers/md/raid1.h b/drivers/md/raid1.h
index e743a64fac4..3cd18cfda2a 100644
--- a/drivers/md/raid1.h
+++ b/drivers/md/raid1.h
@@ -48,6 +48,12 @@ struct r1_private_data_s {
* (fresh device added).
* Cleared when a sync completes.
*/
+ int recovery_disabled; /* when the same as
+ * mddev->recovery_disabled
+ * we don't allow recovery
+ * to be attempted as we
+ * expect a read error
+ */
wait_queue_head_t wait_barrier;