From: NeilBrown Two problems are fixed here. 1/ if the array is known to require a resync (parity update), but there are too many failed devices, the resync cannot complete but will be retried indefinitely. 2/ if the array has too many failed drives to be usable and a spare is available, reconstruction will be attempted, but cannot work. This also is retried indefinitely. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton --- 25-akpm/drivers/md/md.c | 12 ++++++------ 25-akpm/drivers/md/raid5.c | 13 +++++++++++++ 25-akpm/drivers/md/raid6main.c | 12 ++++++++++++ 3 files changed, 31 insertions(+), 6 deletions(-) diff -puN drivers/md/md.c~md-make-raid5-and-raid6-robust-against-failure-during-recovery drivers/md/md.c --- 25/drivers/md/md.c~md-make-raid5-and-raid6-robust-against-failure-during-recovery 2005-02-17 18:00:51.000000000 -0800 +++ 25-akpm/drivers/md/md.c 2005-02-17 18:00:51.000000000 -0800 @@ -3655,18 +3655,18 @@ void md_check_recovery(mddev_t *mddev) /* no recovery is running. * remove any failed drives, then - * add spares if possible + * add spares if possible. + * Spare are also removed and re-added, to allow + * the personality to fail the re-add. */ - ITERATE_RDEV(mddev,rdev,rtmp) { + ITERATE_RDEV(mddev,rdev,rtmp) if (rdev->raid_disk >= 0 && - rdev->faulty && + (rdev->faulty || ! rdev->in_sync) && atomic_read(&rdev->nr_pending)==0) { if (mddev->pers->hot_remove_disk(mddev, rdev->raid_disk)==0) rdev->raid_disk = -1; } - if (!rdev->faulty && rdev->raid_disk >= 0 && !rdev->in_sync) - spares++; - } + if (mddev->degraded) { ITERATE_RDEV(mddev,rdev,rtmp) if (rdev->raid_disk < 0 diff -puN drivers/md/raid5.c~md-make-raid5-and-raid6-robust-against-failure-during-recovery drivers/md/raid5.c --- 25/drivers/md/raid5.c~md-make-raid5-and-raid6-robust-against-failure-during-recovery 2005-02-17 18:00:51.000000000 -0800 +++ 25-akpm/drivers/md/raid5.c 2005-02-17 18:00:51.000000000 -0800 @@ -1493,6 +1493,15 @@ static int sync_request (mddev_t *mddev, unplug_slaves(mddev); return 0; } + /* if there is 1 or more failed drives and we are trying + * to resync, then assert that we are finished, because there is + * nothing we can do. + */ + if (mddev->degraded >= 1 && test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) { + int rv = (mddev->size << 1) - sector_nr; + md_done_sync(mddev, rv, 1); + return rv; + } x = sector_nr; chunk_offset = sector_div(x, sectors_per_chunk); @@ -1884,6 +1893,10 @@ static int raid5_add_disk(mddev_t *mddev int disk; struct disk_info *p; + if (mddev->degraded > 1) + /* no point adding a device */ + return 0; + /* * find the disk ... */ diff -puN drivers/md/raid6main.c~md-make-raid5-and-raid6-robust-against-failure-during-recovery drivers/md/raid6main.c --- 25/drivers/md/raid6main.c~md-make-raid5-and-raid6-robust-against-failure-during-recovery 2005-02-17 18:00:51.000000000 -0800 +++ 25-akpm/drivers/md/raid6main.c 2005-02-17 18:00:51.000000000 -0800 @@ -1652,6 +1652,15 @@ static int sync_request (mddev_t *mddev, unplug_slaves(mddev); return 0; } + /* if there are 2 or more failed drives and we are trying + * to resync, then assert that we are finished, because there is + * nothing we can do. + */ + if (mddev->degraded >= 2 && test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) { + int rv = (mddev->size << 1) - sector_nr; + md_done_sync(mddev, rv, 1); + return rv; + } x = sector_nr; chunk_offset = sector_div(x, sectors_per_chunk); @@ -2050,6 +2059,9 @@ static int raid6_add_disk(mddev_t *mddev int disk; struct disk_info *p; + if (mddev->degraded > 2) + /* no point adding a device */ + return 0; /* * find the disk ... */ _