]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
Grow: add disks chosen by metadata handler to array for growth.
authorNeilBrown <neilb@suse.de>
Wed, 15 Dec 2010 22:07:52 +0000 (09:07 +1100)
committerNeilBrown <neilb@suse.de>
Wed, 15 Dec 2010 22:07:52 +0000 (09:07 +1100)
With externally managed container based metadata, the ->reshape_super
method must choose any spares that are to be added to the array.
They should be prepared so that ->container_content will find them
as spares (disk.state == 0) which are assigned to a slot
(raid_disk >= 0).
We need to take those and add them to the array(s).

Signed-off-by: NeilBrown <neilb@suse.de>
Grow.c

diff --git a/Grow.c b/Grow.c
index d77b7f0ff9df895ff9c930674e32a2d82bd35e76..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,23 @@ 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);
@@ -1542,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;
@@ -1825,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.
                 */