[PATCH] md: fix raid10 assembly when too many devices are missing
authorNeilBrown <neilb@suse.de>
Fri, 9 Sep 2005 23:24:03 +0000 (16:24 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Fri, 9 Sep 2005 23:39:14 +0000 (16:39 -0700)
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>
drivers/md/raid10.c

index 5e0b333793d5bbe705f34671b167b064b88cdfd1..834bf0f862225c471648fbea0863d8cb1541ad88 100644 (file)
@@ -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;
        }