]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - Grow.c
imsm: set imsm spare uuid to 0
[thirdparty/mdadm.git] / Grow.c
diff --git a/Grow.c b/Grow.c
index 40b4809a8f17c406e524809df6515241b51c413a..21e14373da579343b93ba93d906a8dcea0f7e69b 100644 (file)
--- a/Grow.c
+++ b/Grow.c
@@ -666,7 +666,8 @@ void abort_reshape(struct mdinfo *sra)
        sysfs_set_str(sra, NULL, "sync_max", "max");
 }
 
-static int reshape_container_raid_disks(char *container, int raid_disks)
+static int reshape_container_raid_disks(struct supertype *st,
+                                       char *container, int raid_disks)
 {
        /* for each subarray switch to a raid level that can
         * support the reshape, and set raid disks
@@ -682,15 +683,17 @@ static int reshape_container_raid_disks(char *container, int raid_disks)
 
        changed = 0;
        for (e = ent; e; e = e->next) {
-               struct mdinfo *sub;
+               struct mdinfo *sub, *info;
                unsigned int cache;
                int level, takeover_delta = 0;
                int parity_disks = 1;
                unsigned int odata;
                unsigned long blocks;
+               char *subarray;
 
                if (!is_container_member(e, container))
                        continue;
+               subarray = strchr(e->metadata_version+10, '/')+1;
 
                rv = -1;
                level = map_name(pers, e->level);
@@ -756,6 +759,25 @@ static int reshape_container_raid_disks(char *container, int raid_disks)
                                changed++;
                        break;
                }
+
+               /* add the devices that were chosen */
+               info = st->ss->container_content(st, subarray);
+               if (info) {
+                       struct mdinfo *d;
+                       for (d = info->devs; d; d = d->next) {
+                               if (d->disk.state == 0 &&
+                                   d->disk.raid_disk >= 0) {
+                                       /* This is a spare that wants to
+                                        * be part of the array.
+                                        */
+                                       add_disk(-1, st, info, d);
+                               }
+                       }
+               }
+               sysfs_free(info);
+
+               if (!rv && level > 1)
+                       start_reshape(sub);
                sysfs_free(sub);
                if (rv)
                        break;
@@ -823,6 +845,9 @@ static void revert_container_raid_disks(struct supertype *st, int fd, char *cont
                                disks_fixed = 1;
                } else if (sub)
                        disks_fixed = 1;
+
+               if (sub)
+                       abort_reshape(sub);
                sysfs_free(sub);
 
                if (!disks_fixed || !level_fixed)
@@ -1537,7 +1562,7 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
                        goto release;
                }
 
-               count = reshape_container_raid_disks(container, raid_disks);
+               count = reshape_container_raid_disks(st, container, raid_disks);
                if (count < 0) {
                        revert_container_raid_disks(st, fd, container);
                        rv = 1;
@@ -1820,6 +1845,29 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
                        break;
                }
 
+               /* ->reshape_super might have chosen some spares from the
+                * container that it wants to be part of the new array.
+                * We can collect them with ->container_content and give
+                * them to the kernel.
+                */
+               if (st->ss->reshape_super && st->ss->container_content) {
+                       struct mdinfo *info =
+                               st->ss->container_content(st, subarray);
+                       struct mdinfo *d;
+
+                       if (info)
+                               for (d = info->devs; d; d = d->next) {
+                                       if (d->disk.state == 0 &&
+                                           d->disk.raid_disk >= 0) {
+                                               /* This is a spare that wants to
+                                                * be part of the array.
+                                                */
+                                               add_disk(fd, st, info, d);
+                                       }
+                               }
+                       sysfs_free(info);
+               }
+
                /* lastly, check that the internal stripe cache is
                 * large enough, or it won't work.
                 */
@@ -1885,6 +1933,7 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
                        break;
                }
 
+               start_reshape(sra);
                if (st->ss->external) {
                        /* metadata handler takes it from here */
                        ping_manager(container);
@@ -1916,6 +1965,7 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
                        fprintf(stderr, Name ": %s: Cannot find a superblock\n",
                                devname);
                        rv = 1;
+                       abort_reshape(sra);
                        break;
                }
 
@@ -1929,7 +1979,6 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
                 * handling backups of the data...
                 * This is all done by a forked background process.
                 */
-               start_reshape(sra);
                switch(fork()) {
                case 0:
                        close(fd);