]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - Grow.c
FIX: resolve make everything compilation error
[thirdparty/mdadm.git] / Grow.c
diff --git a/Grow.c b/Grow.c
index a0dbb205bf3d2ee2ced1c1ba3b7c417c8cebb1a9..389992e24a3e84cee1997776d91f96dc6d85da6c 100644 (file)
--- a/Grow.c
+++ b/Grow.c
@@ -650,7 +650,7 @@ static void wait_reshape(struct mdinfo *sra)
 static int reshape_super(struct supertype *st, long long size, int level,
                         int layout, int chunksize, int raid_disks,
                         int delta_disks, char *backup_file, char *dev,
-                        int verbose)
+                        int direction, int verbose)
 {
        /* nothing extra to check in the native case */
        if (!st->ss->external)
@@ -664,7 +664,7 @@ static int reshape_super(struct supertype *st, long long size, int level,
 
        return st->ss->reshape_super(st, size, level, layout, chunksize,
                                     raid_disks, delta_disks, backup_file, dev,
-                                    verbose);
+                                    direction, verbose);
 }
 
 static void sync_metadata(struct supertype *st)
@@ -1023,6 +1023,10 @@ char *analyse_change(struct mdinfo *info, struct reshape *re)
                 * raid5 with 2 disks, or
                 * raid0 with 1 disk
                 */
+               if (info->new_level > 1 &&
+                   (info->component_size & 7))
+                       return "Cannot convert RAID1 of this size - "
+                               "reduce size to multiple of 4K first.";
                if (info->new_level == 0) {
                        if (info->delta_disks != UnSet &&
                            info->delta_disks != 0)
@@ -1382,6 +1386,44 @@ char *analyse_change(struct mdinfo *info, struct reshape *re)
        return NULL;
 }
 
+static int set_array_size(struct supertype *st, struct mdinfo *sra,
+                         char *text_version)
+{
+       struct mdinfo *info;
+       char *subarray;
+       int ret_val = -1;
+
+       if ((st == NULL) || (sra == NULL))
+               return ret_val;
+
+       if (text_version == NULL)
+               text_version = sra->text_version;
+       subarray = strchr(text_version+1, '/')+1;
+       info = st->ss->container_content(st, subarray);
+       if (info) {
+               unsigned long long current_size = 0;
+               unsigned long long new_size =
+                       info->custom_array_size/2;
+
+               if (sysfs_get_ll(sra, NULL, "array_size", &current_size) == 0 &&
+                   new_size > current_size) {
+                       if (sysfs_set_num(sra, NULL, "array_size", new_size)
+                                       < 0)
+                               dprintf("Error: Cannot set array size");
+                       else {
+                               ret_val = 0;
+                               dprintf("Array size changed");
+                       }
+                       dprintf(" from %llu to %llu.\n",
+                               current_size, new_size);
+               }
+               sysfs_free(info);
+       } else
+               dprintf("Error: set_array_size(): info pointer in NULL\n");
+
+       return ret_val;
+}
+
 static int reshape_array(char *container, int fd, char *devname,
                         struct supertype *st, struct mdinfo *info,
                         int force, struct mddev_dev *devlist,
@@ -1584,16 +1626,38 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
                long long orig_size = get_component_size(fd)/2;
                long long min_csize;
                struct mdinfo *mdi;
+               int raid0_takeover = 0;
 
                if (orig_size == 0)
                        orig_size = array.size;
 
                if (reshape_super(st, size, UnSet, UnSet, 0, 0, UnSet, NULL,
-                                 devname, !quiet)) {
+                                 devname, APPLY_METADATA_CHANGES, !quiet)) {
                        rv = 1;
                        goto release;
                }
                sync_metadata(st);
+               if (st->ss->external) {
+                       /* metadata can have size limitation
+                        * update size value according to metadata information
+                        */
+                       struct mdinfo *sizeinfo =
+                               st->ss->container_content(st, subarray);
+                       if (sizeinfo) {
+                               unsigned long long new_size =
+                                       sizeinfo->custom_array_size/2;
+                               int data_disks = get_data_disks(
+                                               sizeinfo->array.level,
+                                               sizeinfo->array.layout,
+                                               sizeinfo->array.raid_disks);
+                               new_size /= data_disks;
+                               dprintf("Metadata size correction from %llu to "
+                                       "%llu (%llu)\n", orig_size, new_size,
+                                       new_size * data_disks);
+                               size = new_size;
+                               sysfs_free(sizeinfo);
+                       }
+               }
 
                /* Update the size of each member device in case
                 * they have been resized.  This will never reduce
@@ -1601,9 +1665,12 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
                 * understands '0' to mean 'max'.
                 */
                min_csize = 0;
+               rv = 0;
                for (mdi = sra->devs; mdi; mdi = mdi->next) {
-                       if (sysfs_set_num(sra, mdi, "size", size) < 0)
+                       if (sysfs_set_num(sra, mdi, "size", size) < 0) {
+                               rv = 1;
                                break;
+                       }
                        if (array.not_persistent == 0 &&
                            array.major_version == 0 &&
                            get_linux_version() < 3001000) {
@@ -1618,11 +1685,16 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
                                }
                        }
                }
+               if (rv) {
+                       fprintf(stderr, Name ": Cannot set size on "
+                               "array members.\n");
+                       goto size_change_error;
+               }
                if (min_csize && size > min_csize) {
                        fprintf(stderr, Name ": Cannot safely make this array "
                                "use more than 2TB per device on this kernel.\n");
                        rv = 1;
-                       goto release;
+                       goto size_change_error;
                }
                if (min_csize && size == 0) {
                        /* Don't let the kernel choose a size - it will get
@@ -1632,6 +1704,27 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
                                "2TB per device\n");
                        size = min_csize;
                }
+               if (st->ss->external) {
+                       if (sra->array.level == 0) {
+                               rv = sysfs_set_str(sra, NULL, "level",
+                                                  "raid5");
+                               if (!rv) {
+                                       raid0_takeover = 1;
+                                       /* get array parametes after takeover
+                                        * to chane one parameter at time only
+                                        */
+                                       rv = ioctl(fd, GET_ARRAY_INFO, &array);
+                               }
+                       }
+                       /* make sure mdmon is
+                        * aware of the new level */
+                       if (!mdmon_running(st->container_dev))
+                               start_mdmon(st->container_dev);
+                       ping_monitor(container);
+                       if (mdmon_running(st->container_dev) &&
+                                       st->update_tail == NULL)
+                               st->update_tail = &st->updates;
+               }
 
                array.size = size;
                if (array.size != size) {
@@ -1643,14 +1736,35 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
                                                   "component_size", size);
                        else
                                rv = -1;
-               } else
+               } else {
                        rv = ioctl(fd, SET_ARRAY_INFO, &array);
+
+                       /* manage array size when it is managed externally
+                        */
+                       if ((rv == 0) && st->ss->external)
+                               rv = set_array_size(st, sra, sra->text_version);
+               }
+
+               if (raid0_takeover) {
+                       /* do not recync non-existing parity,
+                        * we will drop it anyway
+                        */
+                       sysfs_set_str(sra, NULL, "sync_action", "idle");
+                       /* go back to raid0, drop parity disk
+                        */
+                       sysfs_set_str(sra, NULL, "level", "raid0");
+                       ioctl(fd, GET_ARRAY_INFO, &array);
+               }
+
+size_change_error:
                if (rv != 0) {
                        int err = errno;
 
                        /* restore metadata */
                        if (reshape_super(st, orig_size, UnSet, UnSet, 0, 0,
-                                         UnSet, NULL, devname, !quiet) == 0)
+                                         UnSet, NULL, devname,
+                                         ROLLBACK_METADATA_CHANGES,
+                                         !quiet) == 0)
                                sync_metadata(st);
                        fprintf(stderr, Name ": Cannot set device size for %s: %s\n",
                                devname, strerror(err));
@@ -1859,10 +1973,11 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
                /* Impose these changes on a single array.  First
                 * check that the metadata is OK with the change. */
 
-               if (reshape_super(st, info.component_size, info.new_level,
+               if (reshape_super(st, -1, info.new_level,
                                  info.new_layout, info.new_chunk,
                                  info.array.raid_disks, info.delta_disks,
-                                 backup_file, devname, quiet)) {
+                                 backup_file, devname, APPLY_METADATA_CHANGES,
+                                 quiet)) {
                        rv = 1;
                        goto release;
                }
@@ -2503,35 +2618,8 @@ started:
         */
        if (reshape.before.data_disks !=
            reshape.after.data_disks &&
-           info->custom_array_size) {
-               struct mdinfo *info2;
-               char *subarray = strchr(info->text_version+1, '/')+1;
-
-               info2 = st->ss->container_content(st, subarray);
-               if (info2) {
-                       unsigned long long current_size = 0;
-                       unsigned long long new_size =
-                               info2->custom_array_size/2;
-
-                       if (sysfs_get_ll(sra,
-                                        NULL,
-                                        "array_size",
-                                        &current_size) == 0 &&
-                           new_size > current_size) {
-                               if (sysfs_set_num(sra, NULL,
-                                                 "array_size", new_size)
-                                   < 0)
-                                       dprintf("Error: Cannot"
-                                               " set array size");
-                               else
-                                       dprintf("Array size "
-                                               "changed");
-                               dprintf(" from %llu to %llu.\n",
-                                       current_size, new_size);
-                       }
-                       sysfs_free(info2);
-               }
-       }
+           info->custom_array_size)
+               set_array_size(st, info, info->text_version);
 
        if (info->new_level != reshape.level) {
 
@@ -2588,7 +2676,8 @@ int reshape_container(char *container, char *devname,
            reshape_super(st, -1, info->new_level,
                          info->new_layout, info->new_chunk,
                          info->array.raid_disks, info->delta_disks,
-                         backup_file, devname, quiet)) {
+                         backup_file, devname, APPLY_METADATA_CHANGES,
+                         quiet)) {
                unfreeze(st);
                return 1;
        }