]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - super-intel.c
mdadm: drop get_required_spare_criteria()
[thirdparty/mdadm.git] / super-intel.c
index deef7c878f3283b0fd927065bae4b8dab593a9ed..7ad391ac92904bccd3ab6c3c5be3519705e67646 100644 (file)
@@ -20,6 +20,7 @@
 #define HAVE_STDINT_H 1
 #include "mdadm.h"
 #include "mdmon.h"
+#include "dlink.h"
 #include "sha1.h"
 #include "platform-intel.h"
 #include <values.h>
@@ -498,8 +499,15 @@ struct intel_disk {
        struct intel_disk *next;
 };
 
+/**
+ * struct extent - reserved space details.
+ * @start: start offset.
+ * @size: size of reservation, set to 0 for metadata reservation.
+ * @vol: index of the volume, meaningful if &size is set.
+ */
 struct extent {
        unsigned long long start, size;
+       int vol;
 };
 
 /* definitions of reshape process types */
@@ -626,9 +634,53 @@ static const char *_sys_dev_type[] = {
        [SYS_DEV_SAS] = "SAS",
        [SYS_DEV_SATA] = "SATA",
        [SYS_DEV_NVME] = "NVMe",
-       [SYS_DEV_VMD] = "VMD"
+       [SYS_DEV_VMD] = "VMD",
+       [SYS_DEV_SATA_VMD] = "SATA VMD"
 };
 
+static int no_platform = -1;
+
+static int check_no_platform(void)
+{
+       static const char search[] = "mdadm.imsm.test=1";
+       FILE *fp;
+
+       if (no_platform >= 0)
+               return no_platform;
+
+       if (check_env("IMSM_NO_PLATFORM")) {
+               no_platform = 1;
+               return 1;
+       }
+       fp = fopen("/proc/cmdline", "r");
+       if (fp) {
+               char *l = conf_line(fp);
+               char *w = l;
+
+               if (l == NULL) {
+                       fclose(fp);
+                       return 0;
+               }
+
+               do {
+                       if (strcmp(w, search) == 0)
+                               no_platform = 1;
+                       w = dl_next(w);
+               } while (w != l);
+               free_line(l);
+               fclose(fp);
+               if (no_platform >= 0)
+                       return no_platform;
+       }
+       no_platform = 0;
+       return 0;
+}
+
+void imsm_set_no_platform(int v)
+{
+       no_platform = v;
+}
+
 const char *get_sys_dev_type(enum sys_dev_type type)
 {
        if (type >= SYS_DEV_MAX)
@@ -713,12 +765,12 @@ static struct sys_dev* find_disk_attached_hba(int fd, const char *devname)
 
        for (elem = list; elem; elem = elem->next)
                if (path_attached_to_hba(disk_path, elem->path))
-                       return elem;
+                       break;
 
        if (disk_path != devname)
                free(disk_path);
 
-       return NULL;
+       return elem;
 }
 
 static int find_intel_hba_capability(int fd, struct intel_super *super,
@@ -1494,9 +1546,10 @@ static struct extent *get_extents(struct intel_super *super, struct dl *dl,
                                  int get_minimal_reservation)
 {
        /* find a list of used extents on the given physical device */
-       struct extent *rv, *e;
-       int i;
        int memberships = count_memberships(dl, super);
+       struct extent *rv = xcalloc(memberships + 1, sizeof(struct extent));
+       struct extent *e = rv;
+       int i;
        __u32 reservation;
 
        /* trim the reserved area for spares, so they can join any array
@@ -1508,9 +1561,6 @@ static struct extent *get_extents(struct intel_super *super, struct dl *dl,
        else
                reservation = MPB_SECTOR_CNT + IMSM_RESERVED_SECTORS;
 
-       rv = xcalloc(sizeof(struct extent), (memberships + 1));
-       e = rv;
-
        for (i = 0; i < super->anchor->num_raid_devs; i++) {
                struct imsm_dev *dev = get_imsm_dev(super, i);
                struct imsm_map *map = get_imsm_map(dev, MAP_0);
@@ -1518,6 +1568,7 @@ static struct extent *get_extents(struct intel_super *super, struct dl *dl,
                if (get_imsm_disk_slot(map, dl->index) >= 0) {
                        e->start = pba_of_lba0(map);
                        e->size = per_dev_array_size(map);
+                       e->vol = i;
                        e++;
                }
        }
@@ -1599,17 +1650,29 @@ static int is_journal(struct imsm_disk *disk)
        return (disk->status & JOURNAL_DISK) == JOURNAL_DISK;
 }
 
-/* round array size down to closest MB and ensure it splits evenly
- * between members
+/**
+ * round_member_size_to_mb()- Round given size to closest MiB.
+ * @size: size to round in sectors.
  */
-static unsigned long long round_size_to_mb(unsigned long long size, unsigned int
-                                          disk_count)
+static inline unsigned long long round_member_size_to_mb(unsigned long long size)
 {
-       size /= disk_count;
-       size = (size >> SECT_PER_MB_SHIFT) << SECT_PER_MB_SHIFT;
-       size *= disk_count;
+       return (size >> SECT_PER_MB_SHIFT) << SECT_PER_MB_SHIFT;
+}
 
-       return size;
+/**
+ * round_size_to_mb()- Round given size.
+ * @array_size: size to round in sectors.
+ * @disk_count: count of data members.
+ *
+ * Get size per each data member and round it to closest MiB to ensure that data
+ * splits evenly between members.
+ *
+ * Return: Array size, rounded down.
+ */
+static inline unsigned long long round_size_to_mb(unsigned long long array_size,
+                                                 unsigned int disk_count)
+{
+       return round_member_size_to_mb(array_size / disk_count) * disk_count;
 }
 
 static int able_to_resync(int raid_level, int missing_disks)
@@ -1673,48 +1736,6 @@ static __u32 imsm_min_reserved_sectors(struct intel_super *super)
        return  (remainder < rv) ? remainder : rv;
 }
 
-/*
- * Return minimum size of a spare and sector size
- * that can be used in this array
- */
-int get_spare_criteria_imsm(struct supertype *st, struct spare_criteria *c)
-{
-       struct intel_super *super = st->sb;
-       struct dl *dl;
-       struct extent *e;
-       int i;
-       unsigned long long size = 0;
-
-       c->min_size = 0;
-       c->sector_size = 0;
-
-       if (!super)
-               return -EINVAL;
-       /* find first active disk in array */
-       dl = super->disks;
-       while (dl && (is_failed(&dl->disk) || dl->index == -1))
-               dl = dl->next;
-       if (!dl)
-               return -EINVAL;
-       /* find last lba used by subarrays */
-       e = get_extents(super, dl, 0);
-       if (!e)
-               return -EINVAL;
-       for (i = 0; e[i].size; i++)
-               continue;
-       if (i > 0)
-               size = e[i-1].start + e[i-1].size;
-       free(e);
-
-       /* add the amount of space needed for metadata */
-       size += imsm_min_reserved_sectors(super);
-
-       c->min_size = size * 512;
-       c->sector_size = super->sector_size;
-
-       return 0;
-}
-
 static bool is_gen_migration(struct imsm_dev *dev);
 
 #define IMSM_4K_DIV 8
@@ -1762,7 +1783,7 @@ static void print_imsm_dev(struct intel_super *super,
        printf("\n");
        printf("    Failed disk : ");
        if (map->failed_disk_num == 0xff)
-               printf("none");
+               printf(STR_COMMON_NONE);
        else
                printf("%i", map->failed_disk_num);
        printf("\n");
@@ -2270,7 +2291,7 @@ static void brief_examine_subarrays_imsm(struct supertype *st, int verbose)
                super->current_vol = i;
                getinfo_super_imsm(st, &info, NULL);
                fname_from_uuid(st, &info, nbuf1, ':');
-               printf("ARRAY /dev/md/%.16s container=%s member=%d UUID=%s\n",
+               printf("ARRAY " DEV_MD_DIR "%.16s container=%s member=%d UUID=%s\n",
                       dev->volume, nbuf + 5, i, nbuf1 + 5);
        }
 }
@@ -2559,6 +2580,8 @@ static void print_found_intel_controllers(struct sys_dev *elem)
 
                if (elem->type == SYS_DEV_VMD)
                        fprintf(stderr, "VMD domain");
+               else if (elem->type == SYS_DEV_SATA_VMD)
+                       fprintf(stderr, "SATA VMD domain");
                else
                        fprintf(stderr, "RAID controller");
 
@@ -2607,9 +2630,14 @@ static void print_imsm_capability(const struct imsm_orom *orom)
        else
                printf("Rapid Storage Technology%s\n",
                        imsm_orom_is_enterprise(orom) ? " enterprise" : "");
-       if (orom->major_ver || orom->minor_ver || orom->hotfix_ver || orom->build)
-               printf("        Version : %d.%d.%d.%d\n", orom->major_ver,
-                               orom->minor_ver, orom->hotfix_ver, orom->build);
+       if (orom->major_ver || orom->minor_ver || orom->hotfix_ver || orom->build) {
+               if (imsm_orom_is_vmd_without_efi(orom))
+                       printf("        Version : %d.%d\n", orom->major_ver,
+                              orom->minor_ver);
+               else
+                       printf("        Version : %d.%d.%d.%d\n", orom->major_ver,
+                              orom->minor_ver, orom->hotfix_ver, orom->build);
+       }
        printf("    RAID Levels :%s%s%s%s%s\n",
               imsm_orom_has_raid0(orom) ? " raid0" : "",
               imsm_orom_has_raid1(orom) ? " raid1" : "",
@@ -2699,7 +2727,7 @@ static int detail_platform_imsm(int verbose, int enumerate_only, char *controlle
        int result=1;
 
        if (enumerate_only) {
-               if (check_env("IMSM_NO_PLATFORM"))
+               if (check_no_platform())
                        return 0;
                list = find_intel_devices();
                if (!list)
@@ -2729,8 +2757,9 @@ static int detail_platform_imsm(int verbose, int enumerate_only, char *controlle
                if (!find_imsm_capability(hba)) {
                        char buf[PATH_MAX];
                        pr_err("imsm capabilities not found for controller: %s (type %s)\n",
-                                 hba->type == SYS_DEV_VMD ? vmd_domain_to_controller(hba, buf) : hba->path,
-                                 get_sys_dev_type(hba->type));
+                                 hba->type == SYS_DEV_VMD || hba->type == SYS_DEV_SATA_VMD ?
+                                 vmd_domain_to_controller(hba, buf) :
+                                 hba->path, get_sys_dev_type(hba->type));
                        continue;
                }
                result = 0;
@@ -2783,11 +2812,12 @@ static int detail_platform_imsm(int verbose, int enumerate_only, char *controlle
 
                        printf(" I/O Controller : %s (%s)\n",
                                hba->path, get_sys_dev_type(hba->type));
-                       if (hba->type == SYS_DEV_SATA) {
+                       if (hba->type == SYS_DEV_SATA || hba->type == SYS_DEV_SATA_VMD) {
                                host_base = ahci_get_port_count(hba->path, &port_count);
                                if (ahci_enumerate_ports(hba->path, port_count, host_base, verbose)) {
                                        if (verbose > 0)
-                                               pr_err("failed to enumerate ports on SATA controller at %s.\n", hba->pci_id);
+                                               pr_err("failed to enumerate ports on %s controller at %s.\n",
+                                                       get_sys_dev_type(hba->type), hba->pci_id);
                                        result |= 2;
                                }
                        }
@@ -2817,7 +2847,8 @@ static int export_detail_platform_imsm(int verbose, char *controller_path)
                if (!find_imsm_capability(hba) && verbose > 0) {
                        char buf[PATH_MAX];
                        pr_err("IMSM_DETAIL_PLATFORM_ERROR=NO_IMSM_CAPABLE_DEVICE_UNDER_%s\n",
-                       hba->type == SYS_DEV_VMD ? vmd_domain_to_controller(hba, buf) : hba->path);
+                               hba->type == SYS_DEV_VMD || hba->type == SYS_DEV_SATA_VMD ?
+                               vmd_domain_to_controller(hba, buf) : hba->path);
                }
                else
                        result = 0;
@@ -2826,7 +2857,7 @@ static int export_detail_platform_imsm(int verbose, char *controller_path)
        const struct orom_entry *entry;
 
        for (entry = orom_entries; entry; entry = entry->next) {
-               if (entry->type == SYS_DEV_VMD) {
+               if (entry->type == SYS_DEV_VMD || entry->type == SYS_DEV_SATA_VMD) {
                        for (hba = list; hba; hba = hba->next)
                                print_imsm_capability_export(&entry->orom);
                        continue;
@@ -2903,34 +2934,6 @@ static void uuid_from_super_imsm(struct supertype *st, int uuid[4])
        memcpy(uuid, buf, 4*4);
 }
 
-#if 0
-static void
-get_imsm_numerical_version(struct imsm_super *mpb, int *m, int *p)
-{
-       __u8 *v = get_imsm_version(mpb);
-       __u8 *end = mpb->sig + MAX_SIGNATURE_LENGTH;
-       char major[] = { 0, 0, 0 };
-       char minor[] = { 0 ,0, 0 };
-       char patch[] = { 0, 0, 0 };
-       char *ver_parse[] = { major, minor, patch };
-       int i, j;
-
-       i = j = 0;
-       while (*v != '\0' && v < end) {
-               if (*v != '.' && j < 2)
-                       ver_parse[i][j++] = *v;
-               else {
-                       i++;
-                       j = 0;
-               }
-               v++;
-       }
-
-       *m = strtol(minor, NULL, 0);
-       *p = strtol(patch, NULL, 0);
-}
-#endif
-
 static __u32 migr_strip_blocks_resync(struct imsm_dev *dev)
 {
        /* migr_strip_size when repairing or initializing parity */
@@ -3823,7 +3826,7 @@ static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char *
                 */
                max_enough = max(max_enough, enough);
        }
-       dprintf("enough: %d\n", max_enough);
+
        info->container_enough = max_enough;
 
        if (super->disks) {
@@ -3893,8 +3896,8 @@ struct mdinfo *getinfo_super_disks_imsm(struct supertype *st)
 }
 
 static int update_super_imsm(struct supertype *st, struct mdinfo *info,
-                            char *update, char *devname, int verbose,
-                            int uuid_set, char *homehost)
+                            enum update_opt update, char *devname,
+                            int verbose, int uuid_set, char *homehost)
 {
        /* For 'assemble' and 'force' we need to return non-zero if any
         * change was made.  For others, the return value is ignored.
@@ -3930,7 +3933,8 @@ static int update_super_imsm(struct supertype *st, struct mdinfo *info,
 
        mpb = super->anchor;
 
-       if (strcmp(update, "uuid") == 0) {
+       switch (update) {
+       case UOPT_UUID:
                /* We take this to mean that the family_num should be updated.
                 * However that is much smaller than the uuid so we cannot really
                 * allow an explicit uuid to be given.  And it is hard to reliably
@@ -3954,10 +3958,14 @@ static int update_super_imsm(struct supertype *st, struct mdinfo *info,
                }
                if (rv == 0)
                        mpb->orig_family_num = info->uuid[0];
-       } else if (strcmp(update, "assemble") == 0)
+               break;
+       case UOPT_SPEC_ASSEMBLE:
                rv = 0;
-       else
+               break;
+       default:
                rv = -1;
+               break;
+       }
 
        /* successful update? recompute checksum */
        if (rv == 0)
@@ -4124,17 +4132,17 @@ static int imsm_read_serial(int fd, char *devname,
 
        memset(buf, 0, sizeof(buf));
 
+       if (check_env("IMSM_DEVNAME_AS_SERIAL")) {
+               memset(serial, 0, serial_buf_len);
+               fd2devname(fd, (char *) serial);
+               return 0;
+       }
+
        rv = nvme_get_serial(fd, buf, sizeof(buf));
 
        if (rv)
                rv = scsi_get_serial(fd, buf, sizeof(buf));
 
-       if (rv && check_env("IMSM_DEVNAME_AS_SERIAL")) {
-               memset(serial, 0, MAX_RAID_SERIAL_LEN);
-               fd2devname(fd, (char *) serial);
-               return 0;
-       }
-
        if (rv != 0) {
                if (devname)
                        pr_err("Failed to retrieve serial for %s\n",
@@ -4510,6 +4518,7 @@ static int load_imsm_mpb(int fd, struct intel_super *super, char *devname)
            MIGR_REC_BUF_SECTORS*MAX_SECTOR_SIZE) != 0) {
                pr_err("could not allocate migr_rec buffer\n");
                free(super->buf);
+               super->buf = NULL;
                return 2;
        }
        super->clean_migration_record_by_mdmon = 0;
@@ -4716,7 +4725,7 @@ static int find_intel_hba_capability(int fd, struct intel_super *super, char *de
                       devname);
                return 1;
        }
-       if (!is_fd_valid(fd) || check_env("IMSM_NO_PLATFORM")) {
+       if (!is_fd_valid(fd) || check_no_platform()) {
                super->orom = NULL;
                super->hba = NULL;
                return 0;
@@ -4737,10 +4746,12 @@ static int find_intel_hba_capability(int fd, struct intel_super *super, char *de
                                "    but the container is assigned to Intel(R) %s %s (",
                                devname,
                                get_sys_dev_type(hba_name->type),
-                               hba_name->type == SYS_DEV_VMD ? "domain" : "RAID controller",
+                               hba_name->type == SYS_DEV_VMD || hba_name->type == SYS_DEV_SATA_VMD ?
+                                       "domain" : "RAID controller",
                                hba_name->pci_id ? : "Err!",
                                get_sys_dev_type(super->hba->type),
-                               hba->type == SYS_DEV_VMD ? "domain" : "RAID controller");
+                               hba->type == SYS_DEV_VMD || hba_name->type == SYS_DEV_SATA_VMD ?
+                                       "domain" : "RAID controller");
 
                        while (hba) {
                                fprintf(stderr, "%s", hba->pci_id ? : "Err!");
@@ -5275,7 +5286,7 @@ static int get_super_block(struct intel_super **super_list, char *devnm, char *d
        /* retry the load if we might have raced against mdmon */
        if (err == 3 && devnm && mdmon_running(devnm))
                for (retry = 0; retry < 3; retry++) {
-                       usleep(3000);
+                       sleep_for(0, MSEC_TO_NSEC(3), true);
                        err = load_and_parse_mpb(dfd, s, NULL, keep_fd);
                        if (err != 3)
                                break;
@@ -5377,7 +5388,7 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname)
 
                if (mdstat && mdmon_running(mdstat->devnm) && getpid() != mdmon_pid(mdstat->devnm)) {
                        for (retry = 0; retry < 3; retry++) {
-                               usleep(3000);
+                               sleep_for(0, MSEC_TO_NSEC(3), true);
                                rv = load_and_parse_mpb(fd, super, devname, 0);
                                if (rv != 3)
                                        break;
@@ -5480,40 +5491,37 @@ static void imsm_update_version_info(struct intel_super *super)
        }
 }
 
-static int check_name(struct intel_super *super, char *name, int quiet)
+/**
+ * imsm_check_name() - check imsm naming criteria.
+ * @super: &intel_super pointer, not NULL.
+ * @name: name to check.
+ * @verbose: verbose level.
+ *
+ * Name must be no longer than &MAX_RAID_SERIAL_LEN and must be unique across volumes.
+ *
+ * Returns: &true if @name matches, &false otherwise.
+ */
+static bool imsm_is_name_allowed(struct intel_super *super, const char * const name,
+                                const int verbose)
 {
        struct imsm_super *mpb = super->anchor;
-       char *reason = NULL;
-       char *start = name;
-       size_t len = strlen(name);
        int i;
 
-       if (len > 0) {
-               while (isspace(start[len - 1]))
-                       start[--len] = 0;
-               while (*start && isspace(*start))
-                       ++start, --len;
-               memmove(name, start, len + 1);
+       if (is_string_lq(name, MAX_RAID_SERIAL_LEN + 1) == false) {
+               pr_vrb("imsm: Name \"%s\" is too long\n", name);
+               return false;
        }
 
-       if (len > MAX_RAID_SERIAL_LEN)
-               reason = "must be 16 characters or less";
-       else if (len == 0)
-               reason = "must be a non-empty string";
-
        for (i = 0; i < mpb->num_raid_devs; i++) {
                struct imsm_dev *dev = get_imsm_dev(super, i);
 
                if (strncmp((char *) dev->volume, name, MAX_RAID_SERIAL_LEN) == 0) {
-                       reason = "already exists";
-                       break;
+                       pr_vrb("imsm: Name \"%s\" already exists\n", name);
+                       return false;
                }
        }
 
-       if (reason && !quiet)
-               pr_err("imsm volume name %s\n", reason);
-
-       return !reason;
+       return true;
 }
 
 static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
@@ -5608,8 +5616,9 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
                }
        }
 
-       if (!check_name(super, name, 0))
+       if (imsm_is_name_allowed(super, name, 1) == false)
                return 0;
+
        dv = xmalloc(sizeof(*dv));
        dev = xcalloc(1, sizeof(*dev) + sizeof(__u32) * (info->raid_disks - 1));
        /*
@@ -5789,6 +5798,10 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
        struct imsm_map *map;
        struct dl *dl, *df;
        int slot;
+       int autolayout = 0;
+
+       if (!is_fd_valid(fd))
+               autolayout = 1;
 
        dev = get_imsm_dev(super, super->current_vol);
        map = get_imsm_map(dev, MAP_0);
@@ -5799,25 +5812,32 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
                return 1;
        }
 
-       if (!is_fd_valid(fd)) {
-               /* we're doing autolayout so grab the pre-marked (in
-                * validate_geometry) raid_disk
-                */
-               for (dl = super->disks; dl; dl = dl->next)
+       for (dl = super->disks; dl ; dl = dl->next) {
+               if (autolayout) {
                        if (dl->raiddisk == dk->raid_disk)
                                break;
-       } else {
-               for (dl = super->disks; dl ; dl = dl->next)
-                       if (dl->major == dk->major &&
-                           dl->minor == dk->minor)
-                               break;
+               } else if (dl->major == dk->major && dl->minor == dk->minor)
+                       break;
        }
 
        if (!dl) {
-               pr_err("%s is not a member of the same container\n", devname);
+               if (!autolayout)
+                       pr_err("%s is not a member of the same container.\n",
+                              devname);
                return 1;
        }
 
+       if (!autolayout && super->current_vol > 0) {
+               int _slot = get_disk_slot_in_dev(super, 0, dl->index);
+
+               if (_slot != dk->raid_disk) {
+                       pr_err("Member %s is in %d slot for the first volume, but is in %d slot for a new volume.\n",
+                              dl->devname, _slot, dk->raid_disk);
+                       pr_err("Raid members are in different order than for the first volume, aborting.\n");
+                       return 1;
+               }
+       }
+
        if (mpb->num_disks == 0)
                if (!get_dev_sector_size(dl->fd, dl->devname,
                                         &super->sector_size))
@@ -6522,7 +6542,7 @@ static int validate_ppl_imsm(struct supertype *st, struct mdinfo *info,
                if (mdmon_running(st->container_devnm))
                        st->update_tail = &st->updates;
 
-               if (st->ss->update_subarray(st, subarray, "ppl", NULL)) {
+               if (st->ss->update_subarray(st, subarray, UOPT_PPL, NULL)) {
                        pr_err("Failed to update subarray %s\n",
                              subarray);
                } else {
@@ -6716,7 +6736,7 @@ static int validate_geometry_imsm_container(struct supertype *st, int level,
        struct intel_super *super = NULL;
        int rv = 0;
 
-       if (level != LEVEL_CONTAINER)
+       if (!is_container(level))
                return 0;
        if (!dev)
                return 1;
@@ -6813,20 +6833,35 @@ static unsigned long long find_size(struct extent *e, int *idx, int num_extents)
        return end - base_start;
 }
 
-static unsigned long long merge_extents(struct intel_super *super, int sum_extents)
+/** merge_extents() - analyze extents and get free size.
+ * @super: Intel metadata, not NULL.
+ * @expanding: if set, we are expanding &super->current_vol.
+ *
+ * Build a composite disk with all known extents and generate a size given the
+ * "all disks in an array must share a common start offset" constraint.
+ * If a volume is expanded, then return free space after the volume.
+ *
+ * Return: Free space or 0 on failure.
+ */
+static unsigned long long merge_extents(struct intel_super *super, const bool expanding)
 {
-       /* build a composite disk with all known extents and generate a new
-        * 'maxsize' given the "all disks in an array must share a common start
-        * offset" constraint
-        */
-       struct extent *e = xcalloc(sum_extents, sizeof(*e));
+       struct extent *e;
        struct dl *dl;
-       int i, j;
-       int start_extent;
-       unsigned long long pos;
+       int i, j, pos_vol_idx = -1;
+       int extent_idx = 0;
+       int sum_extents = 0;
+       unsigned long long pos = 0;
        unsigned long long start = 0;
-       unsigned long long maxsize;
-       unsigned long reserve;
+       unsigned long long free_size = 0;
+
+       unsigned long pre_reservation = 0;
+       unsigned long post_reservation = IMSM_RESERVED_SECTORS;
+       unsigned long reservation_size;
+
+       for (dl = super->disks; dl; dl = dl->next)
+               if (dl->e)
+                       sum_extents += dl->extent_cnt;
+       e = xcalloc(sum_extents, sizeof(struct extent));
 
        /* coalesce and sort all extents. also, check to see if we need to
         * reserve space between member arrays
@@ -6845,50 +6880,57 @@ static unsigned long long merge_extents(struct intel_super *super, int sum_exten
        j = 0;
        while (i < sum_extents) {
                e[j].start = e[i].start;
+               e[j].vol = e[i].vol;
                e[j].size = find_size(e, &i, sum_extents);
                j++;
                if (e[j-1].size == 0)
                        break;
        }
 
-       pos = 0;
-       maxsize = 0;
-       start_extent = 0;
        i = 0;
        do {
-               unsigned long long esize;
+               unsigned long long esize = e[i].start - pos;
 
-               esize = e[i].start - pos;
-               if (esize >= maxsize) {
-                       maxsize = esize;
+               if (expanding ? pos_vol_idx == super->current_vol : esize >= free_size) {
+                       free_size = esize;
                        start = pos;
-                       start_extent = i;
+                       extent_idx = i;
                }
+
                pos = e[i].start + e[i].size;
+               pos_vol_idx = e[i].vol;
+
                i++;
        } while (e[i-1].size);
-       free(e);
 
-       if (maxsize == 0)
+       if (free_size == 0) {
+               dprintf("imsm: Cannot find free size.\n");
+               free(e);
                return 0;
+       }
 
-       /* FIXME assumes volume at offset 0 is the first volume in a
-        * container
-        */
-       if (start_extent > 0)
-               reserve = IMSM_RESERVED_SECTORS; /* gap between raid regions */
-       else
-               reserve = 0;
+       if (!expanding && extent_idx != 0)
+               /*
+                * Not a real first volume in a container is created, pre_reservation is needed.
+                */
+               pre_reservation = IMSM_RESERVED_SECTORS;
 
-       if (maxsize < reserve)
-               return 0;
+       if (e[extent_idx].size == 0)
+               /*
+                * extent_idx points to the metadata, post_reservation is allready done.
+                */
+               post_reservation = 0;
+       free(e);
 
-       super->create_offset = ~((unsigned long long) 0);
-       if (start + reserve > super->create_offset)
-               return 0; /* start overflows create_offset */
-       super->create_offset = start + reserve;
+       reservation_size = pre_reservation + post_reservation;
 
-       return maxsize - reserve;
+       if (free_size < reservation_size) {
+               dprintf("imsm: Reservation size is greater than free space.\n");
+               return 0;
+       }
+
+       super->create_offset = start + pre_reservation;
+       return free_size - reservation_size;
 }
 
 static int is_raid_level_supported(const struct imsm_orom *orom, int level, int raiddisks)
@@ -6934,7 +6976,7 @@ active_arrays_by_format(char *name, char* hba, struct md_list **devlist,
                        int fd = -1;
                        while (dev && !is_fd_valid(fd)) {
                                char *path = xmalloc(strlen(dev->name) + strlen("/dev/") + 1);
-                               num = sprintf(path, "%s%s", "/dev/", dev->name);
+                               num = snprintf(path, PATH_MAX, "%s%s", "/dev/", dev->name);
                                if (num > 0)
                                        fd = open(path, O_RDONLY, 0);
                                if (num <= 0 || !is_fd_valid(fd)) {
@@ -7486,13 +7528,7 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
                return 0;
        }
 
-       /* count total number of extents for merge */
-       i = 0;
-       for (dl = super->disks; dl; dl = dl->next)
-               if (dl->e)
-                       i += dl->extent_cnt;
-
-       maxsize = merge_extents(super, i);
+       maxsize = merge_extents(super, false);
 
        if (mpb->num_raid_devs > 0 && size && size != maxsize)
                pr_err("attempting to create a second volume with size less then remaining space.\n");
@@ -7527,7 +7563,7 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
  * @super: &intel_super pointer, not NULL.
  * @raiddisks: number of raid disks.
  * @size: requested size, could be 0 (means max size).
- * @chunk: requested chunk.
+ * @chunk: requested chunk size in KiB.
  * @freesize: pointer for returned size value.
  *
  * Return: &IMSM_STATUS_OK or &IMSM_STATUS_ERROR.
@@ -7541,22 +7577,22 @@ static imsm_status_t imsm_get_free_size(struct intel_super *super,
                                        const int raiddisks,
                                        unsigned long long size,
                                        const int chunk,
-                                       unsigned long long *freesize)
+                                       unsigned long long *freesize,
+                                       bool expanding)
 {
        struct imsm_super *mpb = super->anchor;
        struct dl *dl;
        int i;
-       int extent_cnt;
        struct extent *e;
+       int cnt = 0;
+       int used = 0;
        unsigned long long maxsize;
-       unsigned long long minsize;
-       int cnt;
-       int used;
+       unsigned long long minsize = size;
+
+       if (minsize == 0)
+               minsize = chunk * 2;
 
        /* find the largest common start free region of the possible disks */
-       used = 0;
-       extent_cnt = 0;
-       cnt = 0;
        for (dl = super->disks; dl; dl = dl->next) {
                dl->raiddisk = -1;
 
@@ -7576,19 +7612,18 @@ static imsm_status_t imsm_get_free_size(struct intel_super *super,
                        ;
                dl->e = e;
                dl->extent_cnt = i;
-               extent_cnt += i;
                cnt++;
        }
 
-       maxsize = merge_extents(super, extent_cnt);
-       minsize = size;
-       if (size == 0)
-               /* chunk is in K */
-               minsize = chunk * 2;
+       maxsize = merge_extents(super, expanding);
+       if (maxsize < minsize)  {
+               pr_err("imsm: Free space is %llu but must be equal or larger than %llu.\n",
+                      maxsize, minsize);
+               return IMSM_STATUS_ERROR;
+       }
 
-       if (cnt < raiddisks || (super->orom && used && used != raiddisks) ||
-           maxsize < minsize || maxsize == 0) {
-               pr_err("not enough devices with space to create array.\n");
+       if (cnt < raiddisks || (super->orom && used && used != raiddisks)) {
+               pr_err("imsm: Not enough devices with space to create array.\n");
                return IMSM_STATUS_ERROR;
        }
 
@@ -7638,7 +7673,7 @@ static imsm_status_t autolayout_imsm(struct intel_super *super,
        int vol_cnt = super->anchor->num_raid_devs;
        imsm_status_t rv;
 
-       rv = imsm_get_free_size(super, raiddisks, size, chunk, freesize);
+       rv = imsm_get_free_size(super, raiddisks, size, chunk, freesize, false);
        if (rv != IMSM_STATUS_OK)
                return IMSM_STATUS_ERROR;
 
@@ -7681,7 +7716,7 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
         * if given unused devices create a container
         * if given given devices in a container create a member volume
         */
-       if (level == LEVEL_CONTAINER)
+       if (is_container(level))
                /* Must be a fresh device to add to a container */
                return validate_geometry_imsm_container(st, level, raiddisks,
                                                        data_offset, dev,
@@ -7703,11 +7738,11 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
                struct intel_super *super = st->sb;
 
                /*
-                * Autolayout mode, st->sb and freesize must be set.
+                * Autolayout mode, st->sb must be set.
                 */
-               if (!super || !freesize) {
-                       pr_vrb("freesize and superblock must be set for autolayout, aborting\n");
-                       return 1;
+               if (!super) {
+                       pr_vrb("superblock must be set for autolayout, aborting\n");
+                       return 0;
                }
 
                if (!validate_geometry_imsm_orom(st->sb, level, layout,
@@ -7715,7 +7750,7 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
                                                 verbose))
                        return 0;
 
-               if (super->orom) {
+               if (super->orom && freesize) {
                        imsm_status_t rv;
                        int count = count_volumes(super->hba, super->orom->dpa,
                                              verbose);
@@ -7833,7 +7868,7 @@ static int kill_subarray_imsm(struct supertype *st, char *subarray_id)
 
                if (i < current_vol)
                        continue;
-               sprintf(subarray, "%u", i);
+               snprintf(subarray, sizeof(subarray), "%u", i);
                if (is_subarray_active(subarray, st->devnm)) {
                        pr_err("deleting subarray-%d would change the UUID of active subarray-%d, aborting\n",
                               current_vol, i);
@@ -7878,37 +7913,40 @@ static int kill_subarray_imsm(struct supertype *st, char *subarray_id)
        return 0;
 }
 
-static int get_rwh_policy_from_update(char *update)
+/**
+ * get_rwh_policy_from_update() - Get the rwh policy for update option.
+ * @update: Update option.
+ */
+static int get_rwh_policy_from_update(enum update_opt update)
 {
-       if (strcmp(update, "ppl") == 0)
+       switch (update) {
+       case UOPT_PPL:
                return RWH_MULTIPLE_DISTRIBUTED;
-       else if (strcmp(update, "no-ppl") == 0)
+       case UOPT_NO_PPL:
                return RWH_MULTIPLE_OFF;
-       else if (strcmp(update, "bitmap") == 0)
+       case UOPT_BITMAP:
                return RWH_BITMAP;
-       else if (strcmp(update, "no-bitmap") == 0)
+       case UOPT_NO_BITMAP:
                return RWH_OFF;
-       return -1;
+       default:
+               break;
+       }
+       return UOPT_UNDEFINED;
 }
 
 static int update_subarray_imsm(struct supertype *st, char *subarray,
-                               char *update, struct mddev_ident *ident)
+                               enum update_opt update, struct mddev_ident *ident)
 {
        /* update the subarray currently referenced by ->current_vol */
        struct intel_super *super = st->sb;
        struct imsm_super *mpb = super->anchor;
 
-       if (strcmp(update, "name") == 0) {
+       if (update == UOPT_NAME) {
                char *name = ident->name;
                char *ep;
                int vol;
 
-               if (is_subarray_active(subarray, st->devnm)) {
-                       pr_err("Unable to update name of active subarray\n");
-                       return 2;
-               }
-
-               if (!check_name(super, name, 0))
+               if (imsm_is_name_allowed(super, name, 1) == false)
                        return 2;
 
                vol = strtoul(subarray, &ep, 10);
@@ -7937,7 +7975,7 @@ static int update_subarray_imsm(struct supertype *st, char *subarray,
                        }
                        super->updates_pending++;
                }
-       } else if (get_rwh_policy_from_update(update) != -1) {
+       } else if (get_rwh_policy_from_update(update) != UOPT_UNDEFINED) {
                int new_policy;
                char *ep;
                int vol = strtoul(subarray, &ep, 10);
@@ -8628,23 +8666,6 @@ static int imsm_set_array_state(struct active_array *a, int consistent)
                        /* still reshaping, maybe update vol_curr_migr_unit */
                        goto mark_checkpoint;
                } else {
-                       if (a->last_checkpoint == 0 && a->prev_action == reshape) {
-                               /* for some reason we aborted the reshape.
-                                *
-                                * disable automatic metadata rollback
-                                * user action is required to recover process
-                                */
-                               if (0) {
-                                       struct imsm_map *map2 =
-                                               get_imsm_map(dev, MAP_1);
-                                       dev->vol.migr_state = 0;
-                                       set_migr_type(dev, 0);
-                                       set_vol_curr_migr_unit(dev, 0);
-                                       memcpy(map, map2,
-                                              sizeof_imsm_map(map2));
-                                       super->updates_pending++;
-                               }
-                       }
                        if (a->last_checkpoint >= a->info.component_size) {
                                unsigned long long array_blocks;
                                int used_disks;
@@ -8708,6 +8729,9 @@ static int imsm_set_array_state(struct active_array *a, int consistent)
                super->updates_pending++;
        }
 
+       if (a->prev_action == idle)
+               goto skip_mark_checkpoint;
+
 mark_checkpoint:
        /* skip checkpointing for general migration,
         * it is controlled in mdadm
@@ -10235,7 +10259,8 @@ static void imsm_process_update(struct supertype *st,
                        if (a->info.container_member == target)
                                break;
                dev = get_imsm_dev(super, u->dev_idx);
-               if (a || !check_name(super, name, 1)) {
+
+               if (a || !dev || imsm_is_name_allowed(super, name, 0) == false) {
                        dprintf("failed to rename subarray-%d\n", target);
                        break;
                }
@@ -10677,7 +10702,7 @@ static int imsm_get_allowed_degradation(int level, int raid_disks,
  ******************************************************************************/
 int validate_container_imsm(struct mdinfo *info)
 {
-       if (check_env("IMSM_NO_PLATFORM"))
+       if (check_no_platform())
                return 0;
 
        struct sys_dev *idev;
@@ -11105,11 +11130,11 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info)
        unsigned int sector_size = super->sector_size;
        unsigned long long curr_migr_unit = current_migr_unit(migr_rec);
        unsigned long long num_migr_units = get_num_migr_units(migr_rec);
-       char buffer[20];
+       char buffer[SYSFS_MAX_BUF_SIZE];
        int skipped_disks = 0;
        struct dl *dl_disk;
 
-       err = sysfs_get_str(info, NULL, "array_state", (char *)buffer, 20);
+       err = sysfs_get_str(info, NULL, "array_state", (char *)buffer, sizeof(buffer));
        if (err < 1)
                return 1;
 
@@ -11203,7 +11228,7 @@ static const char *imsm_get_disk_controller_domain(const char *path)
        char *drv=NULL;
        struct stat st;
 
-       strcpy(disk_path, disk_by_path);
+       strncpy(disk_path, disk_by_path, PATH_MAX);
        strncat(disk_path, path, PATH_MAX - strlen(disk_path) - 1);
        if (stat(disk_path, &st) == 0) {
                struct sys_dev* hba;
@@ -11215,7 +11240,7 @@ static const char *imsm_get_disk_controller_domain(const char *path)
                hba = find_disk_attached_hba(-1, path);
                if (hba && hba->type == SYS_DEV_SAS)
                        drv = "isci";
-               else if (hba && hba->type == SYS_DEV_SATA)
+               else if (hba && (hba->type == SYS_DEV_SATA || hba->type == SYS_DEV_SATA_VMD))
                        drv = "ahci";
                else if (hba && hba->type == SYS_DEV_VMD)
                        drv = "vmd";
@@ -11230,6 +11255,84 @@ static const char *imsm_get_disk_controller_domain(const char *path)
        return drv;
 }
 
+/**
+ * get_spare_criteria_imsm() - set spare criteria.
+ * @st: supertype.
+ * @mddev_path: path to md device devnode, it must be container.
+ * @c: spare_criteria struct to fill, not NULL.
+ *
+ * If superblock is not loaded, use mddev_path to load_container. It must be given in this case.
+ * Filles size and sector size accordingly to superblock.
+ */
+mdadm_status_t get_spare_criteria_imsm(struct supertype *st, char *mddev_path,
+                                      struct spare_criteria *c)
+{
+       mdadm_status_t ret = MDADM_STATUS_ERROR;
+       bool free_superblock = false;
+       unsigned long long size = 0;
+       struct intel_super *super;
+       struct extent *e;
+       struct dl *dl;
+       int i;
+
+       /* If no superblock and no mddev_path, we cannot load superblock. */
+       assert(st->sb || mddev_path);
+
+       if (mddev_path) {
+               int fd = open(mddev_path, O_RDONLY);
+
+               if (!is_fd_valid(fd))
+                       return MDADM_STATUS_ERROR;
+
+               if (!st->sb) {
+                       if (load_container_imsm(st, fd, st->devnm)) {
+                               close(fd);
+                               return MDADM_STATUS_ERROR;
+                       }
+                       free_superblock = true;
+               }
+               close(fd);
+       }
+
+       super = st->sb;
+
+       /* find first active disk in array */
+       dl = super->disks;
+       while (dl && (is_failed(&dl->disk) || dl->index == -1))
+               dl = dl->next;
+
+       if (!dl)
+               goto out;
+
+       /* find last lba used by subarrays */
+       e = get_extents(super, dl, 0);
+       if (!e)
+               goto out;
+
+       for (i = 0; e[i].size; i++)
+               continue;
+       if (i > 0)
+               size = e[i - 1].start + e[i - 1].size;
+       free(e);
+
+       /* add the amount of space needed for metadata */
+       size += imsm_min_reserved_sectors(super);
+
+       c->min_size = size * 512;
+       c->sector_size = super->sector_size;
+       c->criteria_set = true;
+       ret = MDADM_STATUS_SUCCESS;
+
+out:
+       if (free_superblock)
+               free_super_imsm(st);
+
+       if (ret != MDADM_STATUS_SUCCESS)
+               c->criteria_set = false;
+
+       return ret;
+}
+
 static char *imsm_find_array_devnm_by_subdev(int subdev, char *container)
 {
        static char devnm[32];
@@ -11360,7 +11463,7 @@ static struct mdinfo *get_spares_for_grow(struct supertype *st)
 {
        struct spare_criteria sc;
 
-       get_spare_criteria_imsm(st, &sc);
+       get_spare_criteria_imsm(st, NULL, &sc);
        return container_choose_spares(st, &sc, NULL, NULL, NULL, 0);
 }
 
@@ -11557,6 +11660,96 @@ static void imsm_update_metadata_locally(struct supertype *st,
        }
 }
 
+/**
+ * imsm_analyze_expand() - check expand properties and calculate new size.
+ * @st: imsm supertype.
+ * @geo: new geometry params.
+ * @array: array info.
+ * @direction: reshape direction.
+ *
+ * Obtain free space after the &array and verify if expand to requested size is
+ * possible. If geo->size is set to %MAX_SIZE, assume that max free size is
+ * requested.
+ *
+ * Return:
+ * On success %IMSM_STATUS_OK is returned, geo->size and geo->raid_disks are
+ * updated.
+ * On error, %IMSM_STATUS_ERROR is returned.
+ */
+static imsm_status_t imsm_analyze_expand(struct supertype *st,
+                                        struct geo_params *geo,
+                                        struct mdinfo *array,
+                                        int direction)
+{
+       struct intel_super *super = st->sb;
+       struct imsm_dev *dev = get_imsm_dev(super, super->current_vol);
+       struct imsm_map *map = get_imsm_map(dev, MAP_0);
+       int data_disks = imsm_num_data_members(map);
+
+       unsigned long long current_size;
+       unsigned long long free_size;
+       unsigned long long new_size;
+       unsigned long long max_size;
+
+       const int chunk_kib = geo->chunksize / 1024;
+       imsm_status_t rv;
+
+       if (direction == ROLLBACK_METADATA_CHANGES) {
+               /**
+                * Accept size for rollback only.
+                */
+               new_size = geo->size * 2;
+               goto success;
+       }
+
+       if (data_disks == 0) {
+               pr_err("imsm: Cannot retrieve data disks.\n");
+               return IMSM_STATUS_ERROR;
+       }
+       current_size = array->custom_array_size / data_disks;
+
+       rv = imsm_get_free_size(super, dev->vol.map->num_members, 0, chunk_kib, &free_size, true);
+       if (rv != IMSM_STATUS_OK) {
+               pr_err("imsm: Cannot find free space for expand.\n");
+               return IMSM_STATUS_ERROR;
+       }
+       max_size = round_member_size_to_mb(free_size + current_size);
+
+       if (geo->size == MAX_SIZE)
+               new_size = max_size;
+       else
+               new_size = round_member_size_to_mb(geo->size * 2);
+
+       if (new_size == 0) {
+               pr_err("imsm: Rounded requested size is 0.\n");
+               return IMSM_STATUS_ERROR;
+       }
+
+       if (new_size > max_size) {
+               pr_err("imsm: Rounded requested size (%llu) is larger than free space available (%llu).\n",
+                      new_size, max_size);
+               return IMSM_STATUS_ERROR;
+       }
+
+       if (new_size == current_size) {
+               pr_err("imsm: Rounded requested size (%llu) is same as current size (%llu).\n",
+                      new_size, current_size);
+               return IMSM_STATUS_ERROR;
+       }
+
+       if (new_size < current_size) {
+               pr_err("imsm: Size reduction is not supported, rounded requested size (%llu) is smaller than current (%llu).\n",
+                      new_size, current_size);
+               return IMSM_STATUS_ERROR;
+       }
+
+success:
+       dprintf("imsm: New size per member is %llu.\n", new_size);
+       geo->size = data_disks * new_size;
+       geo->raid_disks = dev->vol.map->num_members;
+       return IMSM_STATUS_OK;
+}
+
 /***************************************************************************
 * Function:    imsm_analyze_change
 * Description: Function analyze change for single volume
@@ -11577,13 +11770,6 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
        int devNumChange = 0;
        /* imsm compatible layout value for array geometry verification */
        int imsm_layout = -1;
-       int data_disks;
-       struct imsm_dev *dev;
-       struct imsm_map *map;
-       struct intel_super *super;
-       unsigned long long current_size;
-       unsigned long long free_size;
-       unsigned long long max_size;
        imsm_status_t rv;
 
        getinfo_super_imsm_volume(st, &info, NULL);
@@ -11666,95 +11852,20 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
                geo->chunksize = info.array.chunk_size;
        }
 
-       chunk = geo->chunksize / 1024;
-
-       super = st->sb;
-       dev = get_imsm_dev(super, super->current_vol);
-       map = get_imsm_map(dev, MAP_0);
-       data_disks = imsm_num_data_members(map);
-       /* compute current size per disk member
-        */
-       current_size = info.custom_array_size / data_disks;
-
-       if (geo->size > 0 && geo->size != MAX_SIZE) {
-               /* align component size
-                */
-               geo->size = imsm_component_size_alignment_check(
-                                   get_imsm_raid_level(dev->vol.map),
-                                   chunk * 1024, super->sector_size,
-                                   geo->size * 2);
-               if (geo->size == 0) {
-                       pr_err("Error. Size expansion is supported only (current size is %llu, requested size /rounded/ is 0).\n",
-                                  current_size);
-                       goto analyse_change_exit;
-               }
-       }
-
-       if (current_size != geo->size && geo->size > 0) {
+       if (geo->size > 0) {
                if (change != -1) {
                        pr_err("Error. Size change should be the only one at a time.\n");
                        change = -1;
                        goto analyse_change_exit;
                }
-               if ((super->current_vol + 1) != super->anchor->num_raid_devs) {
-                       pr_err("Error. The last volume in container can be expanded only (%i/%s).\n",
-                              super->current_vol, st->devnm);
-                       goto analyse_change_exit;
-               }
-               /* check the maximum available size
-                */
-               rv = imsm_get_free_size(super, dev->vol.map->num_members,
-                                       0, chunk, &free_size);
 
+               rv = imsm_analyze_expand(st, geo, &info, direction);
                if (rv != IMSM_STATUS_OK)
-                       /* Cannot find maximum available space
-                        */
-                       max_size = 0;
-               else {
-                       max_size = free_size + current_size;
-                       /* align component size
-                        */
-                       max_size = imsm_component_size_alignment_check(
-                                       get_imsm_raid_level(dev->vol.map),
-                                       chunk * 1024, super->sector_size,
-                                       max_size);
-               }
-               if (geo->size == MAX_SIZE) {
-                       /* requested size change to the maximum available size
-                        */
-                       if (max_size == 0) {
-                               pr_err("Error. Cannot find maximum available space.\n");
-                               change = -1;
-                               goto analyse_change_exit;
-                       } else
-                               geo->size = max_size;
-               }
-
-               if (direction == ROLLBACK_METADATA_CHANGES) {
-                       /* accept size for rollback only
-                       */
-               } else {
-                       /* round size due to metadata compatibility
-                       */
-                       geo->size = (geo->size >> SECT_PER_MB_SHIFT)
-                                   << SECT_PER_MB_SHIFT;
-                       dprintf("Prepare update for size change to %llu\n",
-                               geo->size );
-                       if (current_size >= geo->size) {
-                               pr_err("Error. Size expansion is supported only (current size is %llu, requested size /rounded/ is %llu).\n",
-                                      current_size, geo->size);
-                               goto analyse_change_exit;
-                       }
-                       if (max_size && geo->size > max_size) {
-                               pr_err("Error. Requested size is larger than maximum available size (maximum available size is %llu, requested size /rounded/ is %llu).\n",
-                                      max_size, geo->size);
-                               goto analyse_change_exit;
-                       }
-               }
-               geo->size *= data_disks;
-               geo->raid_disks = dev->vol.map->num_members;
+                       goto analyse_change_exit;
                change = CH_ARRAY_SIZE;
        }
+
+       chunk = geo->chunksize / 1024;
        if (!validate_geometry_imsm(st,
                                    geo->level,
                                    imsm_layout,
@@ -11843,7 +11954,7 @@ static int imsm_fix_size_mismatch(struct supertype *st, int subarray_index)
                unsigned long long d_size = imsm_dev_size(dev);
                int u_size;
 
-               if (calc_size == d_size || dev->vol.migr_type == MIGR_GEN_MIGR)
+               if (calc_size == d_size)
                        continue;
 
                /* There is a difference, confirm that imsm_dev_size is
@@ -11858,10 +11969,6 @@ static int imsm_fix_size_mismatch(struct supertype *st, int subarray_index)
                geo.size = d_size;
                u_size = imsm_create_metadata_update_for_size_change(st, &geo,
                                                                     &update);
-               if (u_size < 1) {
-                       dprintf("imsm: Cannot prepare size change update\n");
-                       goto exit;
-               }
                imsm_update_metadata_locally(st, update, u_size);
                if (st->update_tail) {
                        append_metadata_update(st, update, u_size);
@@ -12024,14 +12131,14 @@ exit_imsm_reshape_super:
 static int read_completed(int fd, unsigned long long *val)
 {
        int ret;
-       char buf[50];
+       char buf[SYSFS_MAX_BUF_SIZE];
 
-       ret = sysfs_fd_get_str(fd, buf, 50);
+       ret = sysfs_fd_get_str(fd, buf, sizeof(buf));
        if (ret < 0)
                return ret;
 
        ret = COMPLETED_OK;
-       if (strncmp(buf, "none", 4) == 0) {
+       if (str_is_none(buf) == true) {
                ret = COMPLETED_NONE;
        } else if (strncmp(buf, "delayed", 7) == 0) {
                ret = COMPLETED_DELAYED;
@@ -12077,7 +12184,7 @@ int wait_for_reshape_imsm(struct mdinfo *sra, int ndata)
                                close(fd);
                                return 1;
                        }
-                       usleep(30000);
+                       sleep_for(0, MSEC_TO_NSEC(30), true);
                } else
                        break;
        } while (retry--);
@@ -12099,12 +12206,12 @@ int wait_for_reshape_imsm(struct mdinfo *sra, int ndata)
 
        do {
                int rc;
-               char action[20];
+               char action[SYSFS_MAX_BUF_SIZE];
                int timeout = 3000;
 
                sysfs_wait(fd, &timeout);
                if (sysfs_get_str(sra, NULL, "sync_action",
-                                 action, 20) > 0 &&
+                                 action, sizeof(action)) > 0 &&
                                strncmp(action, "reshape", 7) != 0) {
                        if (strncmp(action, "idle", 4) == 0)
                                break;
@@ -12151,7 +12258,7 @@ int check_degradation_change(struct mdinfo *info,
                        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];
                                int raid_disk = sd->disk.raid_disk;
 
                                if (sysfs_get_str(info,