summaryrefslogtreecommitdiffstats
path: root/drivers/md/raid10.c
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2005-09-09 16:24:03 -0700
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-09 16:39:14 -0700
commit6d508242b231cb6e6803faaef54456abe846edb8 (patch)
treec41ca18f31dd2320f2ae7b54602682f81bf18e6e /drivers/md/raid10.c
parent611815651b2640449bda928079160b9263efac1c (diff)
downloadlinux-6d508242b231cb6e6803faaef54456abe846edb8.tar.gz
linux-6d508242b231cb6e6803faaef54456abe846edb8.tar.bz2
linux-6d508242b231cb6e6803faaef54456abe846edb8.zip
[PATCH] md: fix raid10 assembly when too many devices are missing
If you try to assemble an array with too many missing devices, raid10 will now reject the attempt, instead of allowing it. Also check when hot-adding a drive and refuse the hot-add if the array is beyond hope. Signed-off-by: Neil Brown <neilb@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/md/raid10.c')
-rw-r--r--drivers/md/raid10.c30
1 files changed, 27 insertions, 3 deletions
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 5e0b333793d5..834bf0f86222 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -906,6 +906,27 @@ static void close_sync(conf_t *conf)
conf->r10buf_pool = NULL;
}
+/* check if there are enough drives for
+ * every block to appear on atleast one
+ */
+static int enough(conf_t *conf)
+{
+ int first = 0;
+
+ do {
+ int n = conf->copies;
+ int cnt = 0;
+ while (n--) {
+ if (conf->mirrors[first].rdev)
+ cnt++;
+ first = (first+1) % conf->raid_disks;
+ }
+ if (cnt == 0)
+ return 0;
+ } while (first != 0);
+ return 1;
+}
+
static int raid10_spare_active(mddev_t *mddev)
{
int i;
@@ -944,6 +965,8 @@ static int raid10_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
* very different from resync
*/
return 0;
+ if (!enough(conf))
+ return 0;
for (mirror=0; mirror < mddev->raid_disks; mirror++)
if ( !(p=conf->mirrors+mirror)->rdev) {
@@ -1684,9 +1707,10 @@ static int run(mddev_t *mddev)
init_waitqueue_head(&conf->wait_idle);
init_waitqueue_head(&conf->wait_resume);
- if (!conf->working_disks) {
- printk(KERN_ERR "raid10: no operational mirrors for %s\n",
- mdname(mddev));
+ /* need to check that every block has at least one working mirror */
+ if (!enough(conf)) {
+ printk(KERN_ERR "raid10: not enough operational mirrors for %s\n",
+ mdname(mddev));
goto out_free_conf;
}