]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - Grow.c
mdmon: refactor md device name check in main()
[thirdparty/mdadm.git] / Grow.c
diff --git a/Grow.c b/Grow.c
index 6b8321c5172f11e352013f55825f5de2de620dc7..c69a342df945723671455e364354f2b9359323f9 100644 (file)
--- a/Grow.c
+++ b/Grow.c
@@ -26,7 +26,6 @@
 #include       <sys/mman.h>
 #include       <stddef.h>
 #include       <stdint.h>
-#include       <signal.h>
 #include       <sys/wait.h>
 
 #if ! defined(__BIG_ENDIAN) && ! defined(__LITTLE_ENDIAN)
@@ -197,7 +196,12 @@ int Grow_Add_device(char *devname, int fd, char *newdev)
        info.disk.minor = minor(rdev);
        info.disk.raid_disk = d;
        info.disk.state = (1 << MD_DISK_SYNC) | (1 << MD_DISK_ACTIVE);
-       st->ss->update_super(st, &info, "linear-grow-new", newdev, 0, 0, NULL);
+       if (st->ss->update_super(st, &info, UOPT_SPEC_LINEAR_GROW_NEW, newdev,
+                                0, 0, NULL) != 0) {
+               pr_err("Preparing new metadata failed on %s\n", newdev);
+               close(nfd);
+               return 1;
+       }
 
        if (st->ss->store_super(st, nfd)) {
                pr_err("Cannot store new superblock on %s\n", newdev);
@@ -250,8 +254,12 @@ int Grow_Add_device(char *devname, int fd, char *newdev)
                info.array.active_disks = nd+1;
                info.array.working_disks = nd+1;
 
-               st->ss->update_super(st, &info, "linear-grow-update", dv,
-                                    0, 0, NULL);
+               if (st->ss->update_super(st, &info, UOPT_SPEC_LINEAR_GROW_UPDATE, dv,
+                                    0, 0, NULL) != 0) {
+                       pr_err("Updating metadata failed on %s\n", dv);
+                       close(fd2);
+                       return 1;
+               }
 
                if (st->ss->store_super(st, fd2)) {
                        pr_err("Cannot store new superblock on %s\n", dv);
@@ -301,7 +309,7 @@ int Grow_addbitmap(char *devname, int fd, struct context *c, struct shape *s)
                return 1;
        }
        if (bmf.pathname[0]) {
-               if (strcmp(s->bitmap_file,"none") == 0) {
+               if (str_is_none(s->bitmap_file) == true) {
                        if (ioctl(fd, SET_BITMAP_FILE, -1) != 0) {
                                pr_err("failed to remove bitmap %s\n",
                                        bmf.pathname);
@@ -317,7 +325,7 @@ int Grow_addbitmap(char *devname, int fd, struct context *c, struct shape *s)
                return 1;
        }
        if (array.state & (1 << MD_SB_BITMAP_PRESENT)) {
-               if (strcmp(s->bitmap_file, "none")==0) {
+               if (str_is_none(s->bitmap_file) == true) {
                        array.state &= ~(1 << MD_SB_BITMAP_PRESENT);
                        if (md_set_array_info(fd, &array) != 0) {
                                if (array.state & (1 << MD_SB_CLUSTERED))
@@ -332,7 +340,7 @@ int Grow_addbitmap(char *devname, int fd, struct context *c, struct shape *s)
                return 1;
        }
 
-       if (strcmp(s->bitmap_file, "none") == 0) {
+       if (str_is_none(s->bitmap_file) == true) {
                pr_err("no bitmap found on %s\n", devname);
                return 1;
        }
@@ -421,6 +429,12 @@ int Grow_addbitmap(char *devname, int fd, struct context *c, struct shape *s)
                        dv = map_dev(disk.major, disk.minor, 1);
                        if (!dv)
                                continue;
+                       if ((disk.state & (1 << MD_DISK_WRITEMOSTLY)) &&
+                          (strcmp(s->bitmap_file, "clustered") == 0)) {
+                               pr_err("%s disks marked write-mostly are not supported with clustered bitmap\n",devname);
+                               free(mdi);
+                               return 1;
+                       }
                        fd2 = dev_open(dv, O_RDWR);
                        if (fd2 < 0)
                                continue;
@@ -440,8 +454,10 @@ int Grow_addbitmap(char *devname, int fd, struct context *c, struct shape *s)
                                pr_err("failed to load super-block.\n");
                        }
                        close(fd2);
-                       if (rv)
+                       if (rv) {
+                               free(mdi);
                                return 1;
+                       }
                }
                if (offset_setable) {
                        st->ss->getinfo_super(st, mdi, NULL);
@@ -529,12 +545,12 @@ int Grow_consistency_policy(char *devname, int fd, struct context *c, struct sha
        char *subarray = NULL;
        int ret = 0;
        char container_dev[PATH_MAX];
-       char buf[20];
+       char buf[SYSFS_MAX_BUF_SIZE];
 
        if (s->consistency_policy != CONSISTENCY_POLICY_RESYNC &&
            s->consistency_policy != CONSISTENCY_POLICY_PPL) {
                pr_err("Operation not supported for consistency policy %s\n",
-                      map_num(consistency_policies, s->consistency_policy));
+                      map_num_s(consistency_policies, s->consistency_policy));
                return 1;
        }
 
@@ -565,20 +581,20 @@ int Grow_consistency_policy(char *devname, int fd, struct context *c, struct sha
 
        if (sra->consistency_policy == (unsigned)s->consistency_policy) {
                pr_err("Consistency policy is already %s\n",
-                      map_num(consistency_policies, s->consistency_policy));
+                      map_num_s(consistency_policies, s->consistency_policy));
                ret = 1;
                goto free_info;
        } else if (sra->consistency_policy != CONSISTENCY_POLICY_RESYNC &&
                   sra->consistency_policy != CONSISTENCY_POLICY_PPL) {
                pr_err("Current consistency policy is %s, cannot change to %s\n",
-                      map_num(consistency_policies, sra->consistency_policy),
-                      map_num(consistency_policies, s->consistency_policy));
+                      map_num_s(consistency_policies, sra->consistency_policy),
+                      map_num_s(consistency_policies, s->consistency_policy));
                ret = 1;
                goto free_info;
        }
 
        if (s->consistency_policy == CONSISTENCY_POLICY_PPL) {
-               if (sysfs_get_str(sra, NULL, "sync_action", buf, 20) <= 0) {
+               if (sysfs_get_str(sra, NULL, "sync_action", buf, sizeof(buf)) <= 0) {
                        ret = 1;
                        goto free_info;
                } else if (strcmp(buf, "reshape\n") == 0) {
@@ -589,12 +605,12 @@ int Grow_consistency_policy(char *devname, int fd, struct context *c, struct sha
        }
 
        if (subarray) {
-               char *update;
+               enum update_opt update;
 
                if (s->consistency_policy == CONSISTENCY_POLICY_PPL)
-                       update = "ppl";
+                       update = UOPT_PPL;
                else
-                       update = "no-ppl";
+                       update = UOPT_NO_PPL;
 
                sprintf(container_dev, "/dev/%s", st->container_devnm);
 
@@ -652,7 +668,7 @@ int Grow_consistency_policy(char *devname, int fd, struct context *c, struct sha
                                        goto free_info;
                                }
 
-                               ret = st->ss->update_super(st, sra, "ppl",
+                               ret = st->ss->update_super(st, sra, UOPT_PPL,
                                                           devname,
                                                           c->verbose, 0, NULL);
                                if (ret) {
@@ -691,8 +707,8 @@ int Grow_consistency_policy(char *devname, int fd, struct context *c, struct sha
        }
 
        ret = sysfs_set_str(sra, NULL, "consistency_policy",
-                           map_num(consistency_policies,
-                                   s->consistency_policy));
+                           map_num_s(consistency_policies,
+                                        s->consistency_policy));
        if (ret)
                pr_err("Failed to change array consistency policy\n");
 
@@ -801,12 +817,12 @@ static int freeze(struct supertype *st)
        else {
                struct mdinfo *sra = sysfs_read(-1, st->devnm, GET_VERSION);
                int err;
-               char buf[20];
+               char buf[SYSFS_MAX_BUF_SIZE];
 
                if (!sra)
                        return -1;
                /* Need to clear any 'read-auto' status */
-               if (sysfs_get_str(sra, NULL, "array_state", buf, 20) > 0 &&
+               if (sysfs_get_str(sra, NULL, "array_state", buf, sizeof(buf)) > 0 &&
                    strncmp(buf, "read-auto", 9) == 0)
                        sysfs_set_str(sra, NULL, "array_state", "clean");
 
@@ -822,10 +838,10 @@ static void unfreeze(struct supertype *st)
                return unfreeze_container(st);
        else {
                struct mdinfo *sra = sysfs_read(-1, st->devnm, GET_VERSION);
-               char buf[20];
+               char buf[SYSFS_MAX_BUF_SIZE];
 
                if (sra &&
-                   sysfs_get_str(sra, NULL, "sync_action", buf, 20) > 0 &&
+                   sysfs_get_str(sra, NULL, "sync_action", buf, sizeof(buf)) > 0 &&
                    strcmp(buf, "frozen\n") == 0)
                        sysfs_set_str(sra, NULL, "sync_action", "idle");
                sysfs_free(sra);
@@ -835,12 +851,12 @@ static void unfreeze(struct supertype *st)
 static void wait_reshape(struct mdinfo *sra)
 {
        int fd = sysfs_get_fd(sra, NULL, "sync_action");
-       char action[20];
+       char action[SYSFS_MAX_BUF_SIZE];
 
        if (fd < 0)
                return;
 
-       while (sysfs_fd_get_str(fd, action, 20) > 0 &&
+       while (sysfs_fd_get_str(fd, action, sizeof(action)) > 0 &&
               strncmp(action, "reshape", 7) == 0)
                sysfs_wait(fd, NULL);
        close(fd);
@@ -886,7 +902,7 @@ static int subarray_set_num(char *container, struct mdinfo *sra, char *name, int
         * to close a race with the array_state going clean before the
         * next write to raid_disks / stripe_cache_size
         */
-       char safe[50];
+       char safe[SYSFS_MAX_BUF_SIZE];
        int rc;
 
        /* only 'raid_disks' and 'stripe_cache_size' trigger md_allow_write */
@@ -912,7 +928,7 @@ static int subarray_set_num(char *container, struct mdinfo *sra, char *name, int
 }
 
 int start_reshape(struct mdinfo *sra, int already_running,
-                 int before_data_disks, int data_disks)
+                 int before_data_disks, int data_disks, struct supertype *st)
 {
        int err;
        unsigned long long sync_max_to_set;
@@ -926,16 +942,22 @@ int start_reshape(struct mdinfo *sra, int already_running,
        else
                sync_max_to_set = (sra->component_size * data_disks
                                   - sra->reshape_progress) / data_disks;
+
        if (!already_running)
                sysfs_set_num(sra, NULL, "sync_min", sync_max_to_set);
-       err = err ?: sysfs_set_num(sra, NULL, "sync_max", sync_max_to_set);
+
+        if (st->ss->external)
+               err = err ?: sysfs_set_num(sra, NULL, "sync_max", sync_max_to_set);
+       else
+               err = err ?: sysfs_set_str(sra, NULL, "sync_max", "max");
+
        if (!already_running && err == 0) {
                int cnt = 5;
                do {
                        err = sysfs_set_str(sra, NULL, "sync_action",
                                            "reshape");
                        if (err)
-                               sleep(1);
+                               sleep_for(1, 0, true);
                } while (err && errno == EBUSY && cnt-- > 0);
        }
        return err;
@@ -981,8 +1003,8 @@ int remove_disks_for_takeover(struct supertype *st,
                                rv = 1;
                        sysfs_free(arrays);
                        if (rv) {
-                               pr_err("Error. Cannot perform operation on /dev/%s\n", st->devnm);
-                               pr_err("For this operation it MUST be single array in container\n");
+                               pr_err("Error. Cannot perform operation on %s- for this operation "
+                                      "it MUST be single array in container\n", st->devnm);
                                return rv;
                        }
                }
@@ -1045,7 +1067,7 @@ int remove_disks_for_takeover(struct supertype *st,
                remaining = sd->next;
 
                sysfs_set_str(sra, sd, "state", "faulty");
-               sysfs_set_str(sra, sd, "slot", "none");
+               sysfs_set_str(sra, sd, "slot", STR_COMMON_NONE);
                /* for external metadata disks should be removed in mdmon */
                if (!st->ss->external)
                        sysfs_set_str(sra, sd, "state", "remove");
@@ -1686,14 +1708,6 @@ char *analyse_change(char *devname, struct mdinfo *info, struct reshape *re)
                return NULL;
        }
 
-       if (re->after.data_disks == re->before.data_disks &&
-           get_linux_version() < 2006032)
-               return "in-place reshape is not safe before 2.6.32 - sorry.";
-
-       if (re->after.data_disks < re->before.data_disks &&
-           get_linux_version() < 2006030)
-               return "reshape to fewer devices is not supported before 2.6.30 - sorry.";
-
        re->backup_blocks = compute_backup_blocks(
                info->new_chunk, info->array.chunk_size,
                re->after.data_disks, re->before.data_disks);
@@ -1754,9 +1768,67 @@ static int reshape_container(char *container, char *devname,
                             char *backup_file, int verbose,
                             int forked, int restart, int freeze_reshape);
 
+/**
+ * prepare_external_reshape() - prepares update on external metadata if supported.
+ * @devname: Device name.
+ * @subarray: Subarray.
+ * @st: Supertype.
+ * @container: Container.
+ * @cfd: Container file descriptor.
+ *
+ * Function checks that the requested reshape is supported on external metadata,
+ * and performs an initial check that the container holds the pre-requisite
+ * spare devices (mdmon owns final validation).
+ *
+ * Return: 0 on success, else 1
+ */
+static int prepare_external_reshape(char *devname, char *subarray,
+                                   struct supertype *st, char *container,
+                                   const int cfd)
+{
+       struct mdinfo *cc = NULL;
+       struct mdinfo *content = NULL;
+
+       if (st->ss->load_container(st, cfd, NULL)) {
+               pr_err("Cannot read superblock for %s\n", devname);
+               return 1;
+       }
+
+       if (!st->ss->container_content)
+               return 1;
+
+       cc = st->ss->container_content(st, subarray);
+       for (content = cc; content ; content = content->next) {
+               /*
+                * check if reshape is allowed based on metadata
+                * indications stored in content.array.status
+                */
+               if (is_bit_set(&content->array.state, MD_SB_BLOCK_VOLUME) ||
+                   is_bit_set(&content->array.state, MD_SB_BLOCK_CONTAINER_RESHAPE)) {
+                       pr_err("Cannot reshape arrays in container with unsupported metadata: %s(%s)\n",
+                              devname, container);
+                       goto error;
+               }
+               if (content->consistency_policy == CONSISTENCY_POLICY_PPL) {
+                       pr_err("Operation not supported when ppl consistency policy is enabled\n");
+                       goto error;
+               }
+               if (content->consistency_policy == CONSISTENCY_POLICY_BITMAP) {
+                       pr_err("Operation not supported when write-intent bitmap consistency policy is enabled\n");
+                       goto error;
+               }
+       }
+       sysfs_free(cc);
+       if (mdmon_running(container))
+               st->update_tail = &st->updates;
+       return 0;
+error:
+       sysfs_free(cc);
+       return 1;
+}
+
 int Grow_reshape(char *devname, int fd,
                 struct mddev_dev *devlist,
-                unsigned long long data_offset,
                 struct context *c, struct shape *s)
 {
        /* Make some changes in the shape of an array.
@@ -1781,7 +1853,7 @@ int Grow_reshape(char *devname, int fd,
        struct supertype *st;
        char *subarray = NULL;
 
-       int frozen;
+       int frozen = 0;
        int changed = 0;
        char *container = NULL;
        int cfd = -1;
@@ -1790,7 +1862,7 @@ int Grow_reshape(char *devname, int fd,
        int added_disks;
 
        struct mdinfo info;
-       struct mdinfo *sra;
+       struct mdinfo *sra = NULL;
 
        if (md_get_array_info(fd, &array) < 0) {
                pr_err("%s is not an active md array - aborting\n",
@@ -1802,7 +1874,7 @@ int Grow_reshape(char *devname, int fd,
                return 1;
        }
 
-       if (data_offset != INVALID_SECTORS && array.level != 10 &&
+       if (s->data_offset != INVALID_SECTORS && array.level != 10 &&
            (array.level < 4 || array.level > 6)) {
                pr_err("--grow --data-offset not yet supported\n");
                return 1;
@@ -1815,14 +1887,6 @@ int Grow_reshape(char *devname, int fd,
                return 1;
        }
 
-       if (s->raiddisks && s->raiddisks < array.raid_disks &&
-           array.level > 1 && get_linux_version() < 2006032 &&
-           !check_env("MDADM_FORCE_FEWER")) {
-               pr_err("reducing the number of devices is not safe before Linux 2.6.32\n"
-                       "       Please use a newer kernel\n");
-               return 1;
-       }
-
        if (array.level > 1 && s->size > 1 &&
            (unsigned long long) (array.chunk_size / 1024) > s->size) {
                pr_err("component size must be larger than chunk size.\n");
@@ -1838,23 +1902,16 @@ int Grow_reshape(char *devname, int fd,
                pr_err("Cannot increase raid-disks on this array beyond %d\n", st->max_devs);
                return 1;
        }
-       if (s->level == 0 &&
-           (array.state & (1<<MD_SB_BITMAP_PRESENT)) &&
-           !(array.state & (1<<MD_SB_CLUSTERED))) {
-                array.state &= ~(1<<MD_SB_BITMAP_PRESENT);
-                if (md_set_array_info(fd, &array)!= 0) {
-                        pr_err("failed to remove internal bitmap.\n");
-                        return 1;
-                }
-        }
-
-       /* in the external case we need to check that the requested reshape is
-        * supported, and perform an initial check that the container holds the
-        * pre-requisite spare devices (mdmon owns final validation)
-        */
-       if (st->ss->external) {
-               int retval;
+       if (s->level == 0 && (array.state & (1 << MD_SB_BITMAP_PRESENT)) &&
+               !(array.state & (1 << MD_SB_CLUSTERED)) && !st->ss->external) {
+               array.state &= ~(1 << MD_SB_BITMAP_PRESENT);
+               if (md_set_array_info(fd, &array) != 0) {
+                       pr_err("failed to remove internal bitmap.\n");
+                       return 1;
+               }
+       }
 
+       if (st->ss->external) {
                if (subarray) {
                        container = st->container_devnm;
                        cfd = open_dev_excl(st->container_devnm);
@@ -1870,51 +1927,20 @@ int Grow_reshape(char *devname, int fd,
                        return 1;
                }
 
-               retval = st->ss->load_container(st, cfd, NULL);
-
-               if (retval) {
-                       pr_err("Cannot read superblock for %s\n", devname);
+               rv = prepare_external_reshape(devname, subarray, st,
+                                             container, cfd);
+               if (rv > 0) {
                        free(subarray);
-                       return 1;
+                       close(cfd);
+                       goto release;
                }
 
-               /* check if operation is supported for metadata handler */
-               if (st->ss->container_content) {
-                       struct mdinfo *cc = NULL;
-                       struct mdinfo *content = NULL;
-
-                       cc = st->ss->container_content(st, subarray);
-                       for (content = cc; content ; content = content->next) {
-                               int allow_reshape = 1;
-
-                               /* check if reshape is allowed based on metadata
-                                * indications stored in content.array.status
-                                */
-                               if (content->array.state &
-                                   (1 << MD_SB_BLOCK_VOLUME))
-                                       allow_reshape = 0;
-                               if (content->array.state &
-                                   (1 << MD_SB_BLOCK_CONTAINER_RESHAPE))
-                                       allow_reshape = 0;
-                               if (!allow_reshape) {
-                                       pr_err("cannot reshape arrays in container with unsupported metadata: %s(%s)\n",
-                                              devname, container);
-                                       sysfs_free(cc);
-                                       free(subarray);
-                                       return 1;
-                               }
-                               if (content->consistency_policy ==
-                                   CONSISTENCY_POLICY_PPL) {
-                                       pr_err("Operation not supported when ppl consistency policy is enabled\n");
-                                       sysfs_free(cc);
-                                       free(subarray);
-                                       return 1;
-                               }
-                       }
-                       sysfs_free(cc);
+               if (s->raiddisks && subarray) {
+                       pr_err("--raid-devices operation can be performed on a container only\n");
+                       close(cfd);
+                       free(subarray);
+                       return 1;
                }
-               if (mdmon_running(container))
-                       st->update_tail = &st->updates;
        }
 
        added_disks = 0;
@@ -1972,6 +1998,12 @@ int Grow_reshape(char *devname, int fd,
                        goto release;
                }
 
+               if (array.level == 0) {
+                       pr_err("Component size change is not supported for RAID0\n");
+                       rv = 1;
+                       goto release;
+               }
+
                if (reshape_super(st, s->size, UnSet, UnSet, 0, 0, UnSet, NULL,
                                  devname, APPLY_METADATA_CHANGES,
                                  c->verbose > 0)) {
@@ -2053,9 +2085,10 @@ int Grow_reshape(char *devname, int fd,
                        if (!mdmon_running(st->container_devnm))
                                start_mdmon(st->container_devnm);
                        ping_monitor(container);
-                       if (mdmon_running(st->container_devnm) &&
-                                       st->update_tail == NULL)
-                               st->update_tail = &st->updates;
+                       if (mdmon_running(st->container_devnm) == false) {
+                               pr_err("No mdmon found. Grow cannot continue.\n");
+                               goto release;
+                       }
                }
 
                if (s->size == MAX_SIZE)
@@ -2065,11 +2098,7 @@ int Grow_reshape(char *devname, int fd,
                        /* got truncated to 32bit, write to
                         * component_size instead
                         */
-                       if (sra)
-                               rv = sysfs_set_num(sra, NULL,
-                                                  "component_size", s->size);
-                       else
-                               rv = -1;
+                       rv = sysfs_set_num(sra, NULL, "component_size", s->size);
                } else {
                        rv = md_set_array_info(fd, &array);
 
@@ -2113,8 +2142,7 @@ size_change_error:
                         * a backport has been arranged.
                         */
                        if (sra == NULL ||
-                           sysfs_set_str(sra, NULL, "resync_start",
-                                         "none") < 0)
+                           sysfs_set_str(sra, NULL, "resync_start", STR_COMMON_NONE) < 0)
                                pr_err("--assume-clean not supported with --grow on this kernel\n");
                }
                md_get_array_info(fd, &array);
@@ -2130,7 +2158,7 @@ size_change_error:
                                        devname, s->size);
                }
                changed = 1;
-       } else if (array.level != LEVEL_CONTAINER) {
+       } else if (!is_container(array.level)) {
                s->size = get_component_size(fd)/2;
                if (s->size == 0)
                        s->size = array.size;
@@ -2140,7 +2168,7 @@ size_change_error:
        if ((s->level == UnSet || s->level == array.level) &&
            (s->layout_str == NULL) &&
            (s->chunk == 0 || s->chunk == array.chunk_size) &&
-           data_offset == INVALID_SECTORS &&
+           s->data_offset == INVALID_SECTORS &&
            (s->raiddisks == 0 || s->raiddisks == array.raid_disks)) {
                /* Nothing more to do */
                if (!changed && c->verbose >= 0)
@@ -2186,7 +2214,7 @@ size_change_error:
        info.component_size = s->size*2;
        info.new_level = s->level;
        info.new_chunk = s->chunk * 1024;
-       if (info.array.level == LEVEL_CONTAINER) {
+       if (is_container(info.array.level)) {
                info.delta_disks = UnSet;
                info.array.raid_disks = s->raiddisks;
        } else if (s->raiddisks)
@@ -2210,7 +2238,7 @@ size_change_error:
                info.new_layout = UnSet;
                if (info.array.level == 6 && info.new_level == UnSet) {
                        char l[40], *h;
-                       strcpy(l, map_num(r6layout, info.array.layout));
+                       strcpy(l, map_num_s(r6layout, info.array.layout));
                        h = strrchr(l, '-');
                        if (h && strcmp(h, "-6") == 0) {
                                *h = 0;
@@ -2235,7 +2263,7 @@ size_change_error:
                        info.new_layout = info.array.layout;
                else if (info.array.level == 5 && info.new_level == 6) {
                        char l[40];
-                       strcpy(l, map_num(r5layout, info.array.layout));
+                       strcpy(l, map_num_s(r5layout, info.array.layout));
                        strcat(l, "-6");
                        info.new_layout = map_name(r6layout, l);
                } else {
@@ -2299,7 +2327,7 @@ size_change_error:
                                printf("layout for %s set to %d\n",
                                       devname, array.layout);
                }
-       } else if (array.level == LEVEL_CONTAINER) {
+       } else if (is_container(array.level)) {
                /* This change is to be applied to every array in the
                 * container.  This is only needed when the metadata imposes
                 * restraints of the various arrays in the container.
@@ -2308,10 +2336,7 @@ size_change_error:
                 * number of devices (On-Line Capacity Expansion) must be
                 * performed at the level of the container
                 */
-               if (fd > 0) {
-                       close(fd);
-                       fd = -1;
-               }
+               close_fd(&fd);
                rv = reshape_container(container, devname, -1, st, &info,
                                       c->force, c->backup_file, c->verbose,
                                       0, 0, 0);
@@ -2343,7 +2368,7 @@ size_change_error:
                }
                sync_metadata(st);
                rv = reshape_array(container, fd, devname, st, &info, c->force,
-                                  devlist, data_offset, c->backup_file,
+                                  devlist, s->data_offset, c->backup_file,
                                   c->verbose, 0, 0, 0);
                frozen = 0;
        }
@@ -2367,11 +2392,11 @@ release:
 static int verify_reshape_position(struct mdinfo *info, int level)
 {
        int ret_val = 0;
-       char buf[40];
+       char buf[SYSFS_MAX_BUF_SIZE];
        int rv;
 
        /* read sync_max, failure can mean raid0 array */
-       rv = sysfs_get_str(info, NULL, "sync_max", buf, 40);
+       rv = sysfs_get_str(info, NULL, "sync_max", buf, sizeof(buf));
 
        if (rv > 0) {
                char *ep;
@@ -2908,7 +2933,7 @@ static int impose_level(int fd, int level, char *devname, int verbose)
        }
 
        md_get_array_info(fd, &array);
-       if (level == 0 && (array.level >= 4 && array.level <= 6)) {
+       if (level == 0 && is_level456(array.level)) {
                /* To convert to RAID0 we need to fail and
                 * remove any non-data devices. */
                int found = 0;
@@ -3011,7 +3036,7 @@ static int reshape_array(char *container, int fd, char *devname,
        unsigned long long array_size;
        int done;
        struct mdinfo *sra = NULL;
-       char buf[20];
+       char buf[SYSFS_MAX_BUF_SIZE];
 
        /* when reshaping a RAID0, the component_size might be zero.
         * So try to fix that up.
@@ -3020,6 +3045,8 @@ static int reshape_array(char *container, int fd, char *devname,
                dprintf("Cannot get array information.\n");
                goto release;
        }
+       if (st->update_tail == NULL)
+               st->update_tail = &st->updates;
        if (array.level == 0 && info->component_size == 0) {
                get_dev_size(fd, NULL, &array_size);
                info->component_size = array_size / array.raid_disks;
@@ -3198,7 +3225,7 @@ static int reshape_array(char *container, int fd, char *devname,
         * level and frozen, we can safely add them.
         */
        if (devlist) {
-               if (Manage_subdevs(devname, fd, devlist, verbose, 0, NULL, 0))
+               if (Manage_subdevs(devname, fd, devlist, verbose, 0, UOPT_UNDEFINED, 0))
                        goto release;
        }
 
@@ -3452,7 +3479,7 @@ started:
                goto release;
 
        err = start_reshape(sra, restart, reshape.before.data_disks,
-                           reshape.after.data_disks);
+                           reshape.after.data_disks, st);
        if (err) {
                pr_err("Cannot %s reshape for %s\n",
                       restart ? "continue" : "start", devname);
@@ -3471,14 +3498,13 @@ started:
 
        if (!forked)
                if (continue_via_systemd(container ?: sra->sys_name,
-                                        GROW_SERVICE)) {
+                                        GROW_SERVICE, NULL)) {
                        free(fdlist);
                        free(offsets);
                        sysfs_free(sra);
                        return 0;
                }
 
-       close(fd);
        /* Now we just need to kick off the reshape and watch, while
         * handling backups of the data...
         * This is all done by a forked background process.
@@ -3499,6 +3525,9 @@ started:
                break;
        }
 
+       /* Close unused file descriptor in the forked process */
+       close_fd(&fd);
+
        /* If another array on the same devices is busy, the
         * reshape will wait for them.  This would mean that
         * the first section that we suspend will stay suspended
@@ -3537,7 +3566,8 @@ started:
                fd = -1;
        mlockall(MCL_FUTURE);
 
-       signal(SIGTERM, catch_term);
+       if (signal_s(SIGTERM, catch_term) == SIG_ERR)
+               goto release;
 
        if (st->ss->external) {
                /* metadata handler takes it from here */
@@ -3666,7 +3696,7 @@ int reshape_container(char *container, char *devname,
        ping_monitor(container);
 
        if (!forked && !freeze_reshape)
-               if (continue_via_systemd(container, GROW_SERVICE))
+               if (continue_via_systemd(container, GROW_SERVICE, NULL))
                        return 0;
 
        switch (forked ? 0 : fork()) {
@@ -3884,7 +3914,7 @@ int progress_reshape(struct mdinfo *info, struct reshape *reshape,
        unsigned long long array_size = (info->component_size
                                         * reshape->before.data_disks);
        int fd;
-       char buf[20];
+       char buf[SYSFS_MAX_BUF_SIZE];
 
        /* First, we unsuspend any region that is now known to be safe.
         * If suspend_point is on the 'wrong' side of reshape_progress, then
@@ -4062,8 +4092,8 @@ int progress_reshape(struct mdinfo *info, struct reshape *reshape,
                /* Check that sync_action is still 'reshape' to avoid
                 * waiting forever on a dead array
                 */
-               char action[20];
-               if (sysfs_get_str(info, NULL, "sync_action", action, 20) <= 0 ||
+               char action[SYSFS_MAX_BUF_SIZE];
+               if (sysfs_get_str(info, NULL, "sync_action", action, sizeof(action)) <= 0 ||
                    strncmp(action, "reshape", 7) != 0)
                        break;
                /* Some kernels reset 'sync_completed' to zero
@@ -4089,8 +4119,8 @@ int progress_reshape(struct mdinfo *info, struct reshape *reshape,
         */
        if (completed == 0) {
                unsigned long long reshapep;
-               char action[20];
-               if (sysfs_get_str(info, NULL, "sync_action", action, 20) > 0 &&
+               char action[SYSFS_MAX_BUF_SIZE];
+               if (sysfs_get_str(info, NULL, "sync_action", action, sizeof(action)) > 0 &&
                    strncmp(action, "idle", 4) == 0 &&
                    sysfs_get_ll(info, NULL,
                                 "reshape_position", &reshapep) == 0)
@@ -4127,8 +4157,8 @@ check_progress:
         * it was just a device failure that leaves us degraded but
         * functioning.
         */
-       if (sysfs_get_str(info, NULL, "reshape_position", buf,
-                         sizeof(buf)) < 0 || strncmp(buf, "none", 4) != 0) {
+       if (sysfs_get_str(info, NULL, "reshape_position", buf, sizeof(buf)) < 0 ||
+           str_is_none(buf) == false) {
                /* The abort might only be temporary.  Wait up to 10
                 * seconds for fd to contain a valid number again.
                 */
@@ -4208,7 +4238,7 @@ static int grow_backup(struct mdinfo *sra,
                        if (sd->disk.state & (1<<MD_DISK_FAULTY))
                                continue;
                        if (sd->disk.state & (1<<MD_DISK_SYNC)) {
-                               char sbuf[100];
+                               char sbuf[SYSFS_MAX_BUF_SIZE];
 
                                if (sysfs_get_str(sra, sd, "state",
                                                  sbuf, sizeof(sbuf)) < 0 ||
@@ -4902,7 +4932,8 @@ int Grow_restart(struct supertype *st, struct mdinfo *info, int *fdlist,
                                continue;
                        st->ss->getinfo_super(st, &dinfo, NULL);
                        dinfo.reshape_progress = info->reshape_progress;
-                       st->ss->update_super(st, &dinfo, "_reshape_progress",
+                       st->ss->update_super(st, &dinfo,
+                                            UOPT_SPEC__RESHAPE_PROGRESS,
                                             NULL,0, 0, NULL);
                        st->ss->store_super(st, fdlist[j]);
                        st->ss->free_super(st);
@@ -5019,7 +5050,7 @@ int Grow_continue_command(char *devname, int fd,
                        }
                        st->ss->getinfo_super(st, content, NULL);
                        if (!content->reshape_active)
-                               sleep(3);
+                               sleep_for(3, 0, true);
                        else
                                break;
                } while (cnt-- > 0);
@@ -5120,9 +5151,7 @@ int Grow_continue_command(char *devname, int fd,
                        start_mdmon(container);
                ping_monitor(container);
 
-               if (mdmon_running(container))
-                       st->update_tail = &st->updates;
-               else {
+               if (mdmon_running(container) == false) {
                        pr_err("No mdmon found. Grow cannot continue.\n");
                        ret_val = 1;
                        goto Grow_continue_command_exit;