[PATCH] md: cause md/raid1 to "repack" working devices when number of drives is changed
authorNeilBrown <neilb@cse.unsw.edu.au>
Wed, 22 Jun 2005 00:17:09 +0000 (17:17 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Wed, 22 Jun 2005 02:07:42 +0000 (19:07 -0700)
i.e.  missing or failed drives are moved to the end of the list.  The means
a 3 drive md array with the first drive missing can be shrunk to a two
drive array.  Currently that isn't possible.

Also, the "last_used" device number might be out-of-range after the number
of devices is reduced, so we set it to 0.

Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
drivers/md/raid1.c

index 1db5de52d37665e2ec1aa28c2f8678a5565fbb84..4947f599b652f342bce4709d08355a5c6b888d6a 100644 (file)
@@ -1349,17 +1349,26 @@ static int raid1_reshape(mddev_t *mddev, int raid_disks)
         * We allocate a new r1bio_pool if we can.
         * Then raise a device barrier and wait until all IO stops.
         * Then resize conf->mirrors and swap in the new r1bio pool.
+        *
+        * At the same time, we "pack" the devices so that all the missing
+        * devices have the higher raid_disk numbers.
         */
        mempool_t *newpool, *oldpool;
        struct pool_info *newpoolinfo;
        mirror_info_t *newmirrors;
        conf_t *conf = mddev_to_conf(mddev);
+       int cnt;
 
-       int d;
+       int d, d2;
 
-       for (d= raid_disks; d < conf->raid_disks; d++)
-               if (conf->mirrors[d].rdev)
+       if (raid_disks < conf->raid_disks) {
+               cnt=0;
+               for (d= 0; d < conf->raid_disks; d++)
+                       if (conf->mirrors[d].rdev)
+                               cnt++;
+               if (cnt > raid_disks)
                        return -EBUSY;
+       }
 
        newpoolinfo = kmalloc(sizeof(*newpoolinfo), GFP_KERNEL);
        if (!newpoolinfo)
@@ -1390,8 +1399,12 @@ static int raid1_reshape(mddev_t *mddev, int raid_disks)
        /* ok, everything is stopped */
        oldpool = conf->r1bio_pool;
        conf->r1bio_pool = newpool;
-       for (d=0; d < raid_disks && d < conf->raid_disks; d++)
-               newmirrors[d] = conf->mirrors[d];
+
+       for (d=d2=0; d < conf->raid_disks; d++)
+               if (conf->mirrors[d].rdev) {
+                       conf->mirrors[d].rdev->raid_disk = d2;
+                       newmirrors[d2++].rdev = conf->mirrors[d].rdev;
+               }
        kfree(conf->mirrors);
        conf->mirrors = newmirrors;
        kfree(conf->poolinfo);
@@ -1400,6 +1413,7 @@ static int raid1_reshape(mddev_t *mddev, int raid_disks)
        mddev->degraded += (raid_disks - conf->raid_disks);
        conf->raid_disks = mddev->raid_disks = raid_disks;
 
+       conf->last_used = 0; /* just make sure it is in-range */
        spin_lock_irq(&conf->resync_lock);
        conf->barrier--;
        spin_unlock_irq(&conf->resync_lock);