]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - super-intel.c
md.4: two typos fixed
[thirdparty/mdadm.git] / super-intel.c
index 292584b163950a2edf5e9408afb94b4bdd34edd9..ddf4de90100c1e3d4dcf79c751c0cd4e1368194f 100644 (file)
 #define MAX_SIGNATURE_LENGTH  32
 #define MAX_RAID_SERIAL_LEN   16
 
-#define MPB_ATTRIB_CHECKSUM_VERIFY __cpu_to_le32(0x80000000)
-#define MPB_ATTRIB_PM      __cpu_to_le32(0x40000000)
-#define MPB_ATTRIB_2TB     __cpu_to_le32(0x20000000)
-#define MPB_ATTRIB_RAID0   __cpu_to_le32(0x00000001)
-#define MPB_ATTRIB_RAID1   __cpu_to_le32(0x00000002)
-#define MPB_ATTRIB_RAID10  __cpu_to_le32(0x00000004)
-#define MPB_ATTRIB_RAID1E  __cpu_to_le32(0x00000008)
-#define MPB_ATTRIB_RAID5   __cpu_to_le32(0x00000010)
-#define MPB_ATTRIB_RAIDCNG __cpu_to_le32(0x00000020)
+/* supports RAID0 */
+#define MPB_ATTRIB_RAID0               __cpu_to_le32(0x00000001)
+/* supports RAID1 */
+#define MPB_ATTRIB_RAID1               __cpu_to_le32(0x00000002)
+/* supports RAID10 */
+#define MPB_ATTRIB_RAID10              __cpu_to_le32(0x00000004)
+/* supports RAID1E */
+#define MPB_ATTRIB_RAID1E              __cpu_to_le32(0x00000008)
+/* supports RAID5 */
+#define MPB_ATTRIB_RAID5               __cpu_to_le32(0x00000010)
+/* supports RAID CNG */
+#define MPB_ATTRIB_RAIDCNG             __cpu_to_le32(0x00000020)
+/* supports expanded stripe sizes of  256K, 512K and 1MB */
+#define MPB_ATTRIB_EXP_STRIPE_SIZE     __cpu_to_le32(0x00000040)
+
+/* The OROM Support RST Caching of Volumes */
+#define MPB_ATTRIB_NVM                 __cpu_to_le32(0x02000000)
+/* The OROM supports creating disks greater than 2TB */
+#define MPB_ATTRIB_2TB_DISK            __cpu_to_le32(0x04000000)
+/* The OROM supports Bad Block Management */
+#define MPB_ATTRIB_BBM                 __cpu_to_le32(0x08000000)
+
+/* THe OROM Supports NVM Caching of Volumes */
+#define MPB_ATTRIB_NEVER_USE2           __cpu_to_le32(0x10000000)
+/* The OROM supports creating volumes greater than 2TB */
+#define MPB_ATTRIB_2TB                 __cpu_to_le32(0x20000000)
+/* originally for PMP, now it's wasted b/c. Never use this bit! */
+#define MPB_ATTRIB_NEVER_USE           __cpu_to_le32(0x40000000)
+/* Verify MPB contents against checksum after reading MPB */
+#define MPB_ATTRIB_CHECKSUM_VERIFY     __cpu_to_le32(0x80000000)
+
+/* Define all supported attributes that have to be accepted by mdadm
+ */
+#define MPB_ATTRIB_SUPPORTED          (MPB_ATTRIB_CHECKSUM_VERIFY | \
+                                       MPB_ATTRIB_2TB             | \
+                                       MPB_ATTRIB_2TB_DISK        | \
+                                       MPB_ATTRIB_RAID0           | \
+                                       MPB_ATTRIB_RAID1           | \
+                                       MPB_ATTRIB_RAID10          | \
+                                       MPB_ATTRIB_RAID5           | \
+                                       MPB_ATTRIB_EXP_STRIPE_SIZE)
+
+/* Define attributes that are unused but not harmful */
+#define MPB_ATTRIB_IGNORED             (MPB_ATTRIB_NEVER_USE)
 
 #define MPB_SECTOR_CNT 2210
 #define IMSM_RESERVED_SECTORS 4096
@@ -309,7 +344,7 @@ struct intel_super {
                struct extent *e; /* for determining freespace @ create */
                int raiddisk; /* slot to fill in autolayout */
                enum action action;
-       } *disks;
+       } *disks, *current_disk;
        struct dl *disk_mgmt_list; /* list of disks to add/remove while mdmon
                                      active */
        struct dl *missing; /* disks removed while we weren't looking */
@@ -563,7 +598,7 @@ static __u8 *get_imsm_version(struct imsm_super *mpb)
 {
        return &mpb->sig[MPB_SIG_LEN];
 }
-#endif 
+#endif
 
 /* retrieve a disk directly from the anchor when the anchor is known to be
  * up-to-date, currently only at load time
@@ -1095,7 +1130,95 @@ void examine_migr_rec_imsm(struct intel_super *super)
                break;
        }
 }
+#endif /* MDASSEMBLE */
+/*******************************************************************************
+ * function: imsm_check_attributes
+ * Description: Function checks if features represented by attributes flags
+ *             are supported by mdadm.
+ * Parameters:
+ *             attributes - Attributes read from metadata
+ * Returns:
+ *             0 - passed attributes contains unsupported features flags
+ *             1 - all features are supported
+ ******************************************************************************/
+static int imsm_check_attributes(__u32 attributes)
+{
+       int ret_val = 1;
+       __u32 not_supported = MPB_ATTRIB_SUPPORTED^0xffffffff;
 
+       not_supported &= ~MPB_ATTRIB_IGNORED;
+
+       not_supported &= attributes;
+       if (not_supported) {
+               fprintf(stderr, Name "(IMSM): Unsupported attributes : %x\n",
+                       (unsigned)__le32_to_cpu(not_supported));
+               if (not_supported & MPB_ATTRIB_CHECKSUM_VERIFY) {
+                       dprintf("\t\tMPB_ATTRIB_CHECKSUM_VERIFY \n");
+                       not_supported ^= MPB_ATTRIB_CHECKSUM_VERIFY;
+               }
+               if (not_supported & MPB_ATTRIB_2TB) {
+                       dprintf("\t\tMPB_ATTRIB_2TB\n");
+                       not_supported ^= MPB_ATTRIB_2TB;
+               }
+               if (not_supported & MPB_ATTRIB_RAID0) {
+                       dprintf("\t\tMPB_ATTRIB_RAID0\n");
+                       not_supported ^= MPB_ATTRIB_RAID0;
+               }
+               if (not_supported & MPB_ATTRIB_RAID1) {
+                       dprintf("\t\tMPB_ATTRIB_RAID1\n");
+                       not_supported ^= MPB_ATTRIB_RAID1;
+               }
+               if (not_supported & MPB_ATTRIB_RAID10) {
+                       dprintf("\t\tMPB_ATTRIB_RAID10\n");
+                       not_supported ^= MPB_ATTRIB_RAID10;
+               }
+               if (not_supported & MPB_ATTRIB_RAID1E) {
+                       dprintf("\t\tMPB_ATTRIB_RAID1E\n");
+                       not_supported ^= MPB_ATTRIB_RAID1E;
+               }
+               if (not_supported & MPB_ATTRIB_RAID5) {
+               dprintf("\t\tMPB_ATTRIB_RAID5\n");
+                       not_supported ^= MPB_ATTRIB_RAID5;
+               }
+               if (not_supported & MPB_ATTRIB_RAIDCNG) {
+                       dprintf("\t\tMPB_ATTRIB_RAIDCNG\n");
+                       not_supported ^= MPB_ATTRIB_RAIDCNG;
+               }
+               if (not_supported & MPB_ATTRIB_BBM) {
+                       dprintf("\t\tMPB_ATTRIB_BBM\n");
+               not_supported ^= MPB_ATTRIB_BBM;
+               }
+               if (not_supported & MPB_ATTRIB_CHECKSUM_VERIFY) {
+                       dprintf("\t\tMPB_ATTRIB_CHECKSUM_VERIFY (== MPB_ATTRIB_LEGACY)\n");
+                       not_supported ^= MPB_ATTRIB_CHECKSUM_VERIFY;
+               }
+               if (not_supported & MPB_ATTRIB_EXP_STRIPE_SIZE) {
+                       dprintf("\t\tMPB_ATTRIB_EXP_STRIP_SIZE\n");
+                       not_supported ^= MPB_ATTRIB_EXP_STRIPE_SIZE;
+               }
+               if (not_supported & MPB_ATTRIB_2TB_DISK) {
+                       dprintf("\t\tMPB_ATTRIB_2TB_DISK\n");
+                       not_supported ^= MPB_ATTRIB_2TB_DISK;
+               }
+               if (not_supported & MPB_ATTRIB_NEVER_USE2) {
+                       dprintf("\t\tMPB_ATTRIB_NEVER_USE2\n");
+                       not_supported ^= MPB_ATTRIB_NEVER_USE2;
+               }
+               if (not_supported & MPB_ATTRIB_NEVER_USE) {
+                       dprintf("\t\tMPB_ATTRIB_NEVER_USE\n");
+                       not_supported ^= MPB_ATTRIB_NEVER_USE;
+               }
+
+               if (not_supported)
+                       dprintf(Name "(IMSM): Unknown attributes : %x\n", not_supported);
+
+               ret_val = 0;
+       }
+
+       return ret_val;
+}
+
+#ifndef MDASSEMBLE
 static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char *map);
 
 static void examine_super_imsm(struct supertype *st, char *homehost)
@@ -1117,6 +1240,11 @@ static void examine_super_imsm(struct supertype *st, char *homehost)
        printf("    Orig Family : %08x\n", __le32_to_cpu(mpb->orig_family_num));
        printf("         Family : %08x\n", __le32_to_cpu(mpb->family_num));
        printf("     Generation : %08x\n", __le32_to_cpu(mpb->generation_num));
+       printf("     Attributes : ");
+       if (imsm_check_attributes(mpb->attributes))
+               printf("All supported\n");
+       else
+               printf("not supported\n");
        getinfo_super_imsm(st, &info, NULL);
        fname_from_uuid(st, &info, nbuf, ':');
        printf("           UUID : %s\n", nbuf + 5);
@@ -1396,9 +1524,9 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b
                        fd2devname(fd, buf);
                        printf("          Port%d : %s", port, buf);
                        if (imsm_read_serial(fd, NULL, (__u8 *) buf) == 0)
-                               printf(" (%s)\n", buf);
+                               printf(" (%.*s)\n", MAX_RAID_SERIAL_LEN, buf);
                        else
-                               printf("()\n");
+                               printf(" ()\n");
                }
                close(fd);
                free(path);
@@ -1419,8 +1547,6 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b
        return err;
 }
 
-
-
 static void print_found_intel_controllers(struct sys_dev *elem)
 {
        for (; elem; elem = elem->next) {
@@ -1944,6 +2070,7 @@ out:
        return retval;
 }
 
+#ifndef MDASSEMBLE
 /*******************************************************************************
  * function: imsm_create_metadata_checkpoint_update
  * Description: It creates update for checkpoint change.
@@ -2061,6 +2188,7 @@ static int write_imsm_migr_rec(struct supertype *st)
                close(fd);
        return retval;
 }
+#endif /* MDASSEMBLE */
 
 static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info, char *dmap)
 {
@@ -2079,7 +2207,7 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
        if (prev_map)
                map_to_analyse = prev_map;
 
-       dl = super->disks;
+       dl = super->current_disk;
 
        info->container_member    = super->current_vol;
        info->array.raid_disks    = map->num_members;
@@ -2126,7 +2254,6 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
                                /* conversion is happening as RAID5 */
                                info->array.level = 5;
                                info->array.layout = ALGORITHM_PARITY_N;
-                               info->array.raid_disks += 1;
                                info->delta_disks -= 1;
                                break;
                        default:
@@ -2142,11 +2269,13 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
                info->new_chunk = info->array.chunk_size;
                info->delta_disks = 0;
        }
-       info->disk.major = 0;
-       info->disk.minor = 0;
+
        if (dl) {
                info->disk.major = dl->major;
                info->disk.minor = dl->minor;
+               info->disk.number = dl->index;
+               info->disk.raid_disk = get_imsm_disk_slot(map_to_analyse,
+                                                         dl->index);
        }
 
        info->data_offset         = __le32_to_cpu(map_to_analyse->pba_of_lba0);
@@ -2205,7 +2334,9 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
 
                        dprintf("IMSM: General Migration checkpoint : %llu "
                               "(%llu) -> read reshape progress : %llu\n",
-                               units, blocks_per_unit, info->reshape_progress);
+                               (unsigned long long)units,
+                               (unsigned long long)blocks_per_unit,
+                               info->reshape_progress);
 
                        used_disks = imsm_num_data_members(dev, 1);
                        if (used_disks > 0) {
@@ -4206,7 +4337,7 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
                        devname);
                return 1;
        }
-       set_imsm_ord_tbl_ent(map, dk->number, dl->index);
+       set_imsm_ord_tbl_ent(map, dk->raid_disk, dl->index);
        dl->disk.status = CONFIGURED_DISK;
 
        /* if we are creating the first raid device update the family number */
@@ -4226,7 +4357,7 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
                mpb->family_num = __cpu_to_le32(sum);
                mpb->orig_family_num = mpb->family_num;
        }
-
+       super->current_disk = dl;
        return 0;
 }
 
@@ -4392,8 +4523,6 @@ static int write_super_imsm_spares(struct intel_super *super, int doclose)
        return 0;
 }
 
-static int is_gen_migration(struct imsm_dev *dev);
-
 static int write_super_imsm(struct supertype *st, int doclose)
 {
        struct intel_super *super = st->sb;
@@ -4465,7 +4594,8 @@ static int write_super_imsm(struct supertype *st, int doclose)
 
                        get_dev_size(d->fd, NULL, &dsize);
                        if (lseek64(d->fd, dsize - 512, SEEK_SET) >= 0) {
-                               write(d->fd, super->migr_rec_buf, 512);
+                               if (write(d->fd, super->migr_rec_buf, 512) != 512)
+                                       perror("Write migr_rec failed");
                        }
                }
                if (doclose) {
@@ -4792,6 +4922,15 @@ static int is_raid_level_supported(const struct imsm_orom *orom, int level, int
        return 0;
 }
 
+static int imsm_default_chunk(const struct imsm_orom *orom)
+{
+       /* up to 512 if the plaform supports it, otherwise the platform max.
+        * 128 if no platform detected
+        */
+       int fs = max(7, orom ? fls(orom->sss) : 0);
+
+       return min(512, (1 << fs));
+}
 
 #define pr_vrb(fmt, arg...) (void) (verbose && fprintf(stderr, Name fmt, ##arg))
 /*
@@ -4820,15 +4959,16 @@ validate_geometry_imsm_orom(struct intel_super *super, int level, int layout,
                        level, raiddisks, raiddisks > 1 ? "s" : "");
                return 0;
        }
-       if (super->orom && level != 1) {
-               if (chunk && (*chunk == 0 || *chunk == UnSet))
-                       *chunk = imsm_orom_default_chunk(super->orom);
-               else if (chunk && !imsm_orom_has_chunk(super->orom, *chunk)) {
-                       pr_vrb(": platform does not support a chunk size of: "
-                              "%d\n", *chunk);
-                       return 0;
-               }
+
+       if (chunk && (*chunk == 0 || *chunk == UnSet))
+               *chunk = imsm_default_chunk(super->orom);
+
+       if (super->orom && chunk && !imsm_orom_has_chunk(super->orom, *chunk)) {
+               pr_vrb(": platform does not support a chunk size of: "
+                      "%d\n", *chunk);
+               return 0;
        }
+
        if (layout != imsm_level_to_layout(level)) {
                if (level == 5)
                        pr_vrb(": imsm raid 5 only supports the left-asymmetric layout\n");
@@ -5178,9 +5318,8 @@ static void default_geometry_imsm(struct supertype *st, int *level, int *layout,
        if (level && layout && *layout == UnSet)
                *layout = imsm_level_to_layout(*level);
 
-       if (chunk && (*chunk == UnSet || *chunk == 0) && 
-           super && super->orom)
-               *chunk = imsm_orom_default_chunk(super->orom);
+       if (chunk && (*chunk == UnSet || *chunk == 0))
+               *chunk = imsm_default_chunk(super->orom);
 }
 
 static void handle_missing(struct intel_super *super, struct imsm_dev *dev);
@@ -5313,6 +5452,9 @@ static int update_subarray_imsm(struct supertype *st, char *subarray,
 
 static int is_gen_migration(struct imsm_dev *dev)
 {
+       if (dev == NULL)
+               return 0;
+
        if (!dev->vol.migr_state)
                return 0;
 
@@ -5373,7 +5515,9 @@ static void update_recovery_start(struct intel_super *super,
        rebuild->recovery_start = units * blocks_per_migr_unit(super, dev);
 }
 
+#ifndef MDASSEMBLE
 static int recover_backup_imsm(struct supertype *st, struct mdinfo *info);
+#endif
 
 static struct mdinfo *container_content_imsm(struct supertype *st, char *subarray)
 {
@@ -5394,6 +5538,13 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
        struct dl *d;
        int spare_disks = 0;
 
+       /* do not assemble arrays when not all attributes are supported */
+       if (imsm_check_attributes(mpb->attributes) == 0) {
+               fprintf(stderr, Name ": IMSM metadata loading not allowed "
+                       "due to attributes incompatibility.\n");
+               return NULL;
+       }
+
        /* check for bad blocks */
        if (imsm_bbm_log_size(super->anchor))
                bbm_errors = 1;
@@ -5537,10 +5688,11 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
                update_recovery_start(super, dev, this);
                this->array.spare_disks += spare_disks;
 
+#ifndef MDASSEMBLE
                /* check for reshape */
                if (this->reshape_active == 1)
                        recover_backup_imsm(st, this);
-
+#endif
                rest = this;
        }
 
@@ -5856,14 +6008,18 @@ static int imsm_set_array_state(struct active_array *a, int consistent)
                } else {
                        if (a->last_checkpoint == 0 && a->prev_action == reshape) {
                                /* for some reason we aborted the reshape.
-                                * Better clean up
+                                *
+                                * disable automatic metadata rollback
+                                * user action is required to recover process
                                 */
+                               if (0) {
                                struct imsm_map *map2 = get_imsm_map(dev, 1);
                                dev->vol.migr_state = 0;
                                dev->vol.migr_type = 0;
                                dev->vol.curr_migr_unit = 0;
                                memcpy(map, map2, sizeof_imsm_map(map2));
                                super->updates_pending++;
+                               }
                        }
                        if (a->last_checkpoint >= a->info.component_size) {
                                unsigned long long array_blocks;
@@ -6872,7 +7028,7 @@ static int apply_takeover_update(struct imsm_update_takeover *u,
        for (du = super->missing; du; du = du->next)
                if (du->index >= 0) {
                        set_imsm_ord_tbl_ent(map, du->index, du->index);
-                       mark_missing(dev_new, &du->disk, du->index);
+                       mark_missing(dv->dev, &du->disk, du->index);
                }
 
        return 1;
@@ -7563,7 +7719,7 @@ static void imsm_delete(struct intel_super *super, struct dl **dlp, unsigned ind
                __free_imsm_disk(dl);
        }
 }
-
+#endif /* MDASSEMBLE */
 /*******************************************************************************
  * Function:   open_backup_targets
  * Description:        Function opens file descriptors for all devices given in
@@ -7603,6 +7759,7 @@ int open_backup_targets(struct mdinfo *info, int raid_disks, int *raid_fds)
        return 0;
 }
 
+#ifndef MDASSEMBLE
 /*******************************************************************************
  * Function:   init_migr_record_imsm
  * Description:        Function inits imsm migration record
@@ -7706,26 +7863,34 @@ int save_backup_imsm(struct supertype *st,
        int new_disks = map_dest->num_members;
        int dest_layout = 0;
        int dest_chunk;
+       unsigned long long start;
+       int data_disks = imsm_num_data_members(dev, 0);
 
        targets = malloc(new_disks * sizeof(int));
        if (!targets)
                goto abort;
 
+       for (i = 0; i < new_disks; i++)
+               targets[i] = -1;
+
        target_offsets = malloc(new_disks * sizeof(unsigned long long));
        if (!target_offsets)
                goto abort;
 
+       start = info->reshape_progress * 512;
        for (i = 0; i < new_disks; i++) {
-               targets[i] = -1;
                target_offsets[i] = (unsigned long long)
                  __le32_to_cpu(super->migr_rec->ckpt_area_pba) * 512;
+               /* move back copy area adderss, it will be moved forward
+                * in restore_stripes() using start input variable
+                */
+               target_offsets[i] -= start/data_disks;
        }
 
        if (open_backup_targets(info, new_disks, targets))
                goto abort;
 
-       if (map_dest->raid_level != 0)
-               dest_layout = ALGORITHM_LEFT_ASYMMETRIC;
+       dest_layout = imsm_level_to_layout(map_dest->raid_level);
        dest_chunk = __le16_to_cpu(map_dest->blocks_per_strip) * 512;
 
        if (restore_stripes(targets, /* list of dest devices */
@@ -7737,7 +7902,7 @@ int save_backup_imsm(struct supertype *st,
                            -1,    /* source backup file descriptor */
                            0,     /* input buf offset
                                    * always 0 buf is already offseted */
-                           0,
+                           start,
                            length,
                            buf) != 0) {
                fprintf(stderr, Name ": Error restoring stripes\n");
@@ -7774,24 +7939,34 @@ abort:
 int save_checkpoint_imsm(struct supertype *st, struct mdinfo *info, int state)
 {
        struct intel_super *super = st->sb;
+       unsigned long long blocks_per_unit;
+       unsigned long long curr_migr_unit;
+
        if (load_imsm_migr_rec(super, info) != 0) {
                dprintf("imsm: ERROR: Cannot read migration record "
                        "for checkpoint save.\n");
                return 1;
        }
 
-       if (__le32_to_cpu(super->migr_rec->blocks_per_unit) == 0) {
+       blocks_per_unit = __le32_to_cpu(super->migr_rec->blocks_per_unit);
+       if (blocks_per_unit == 0) {
                dprintf("imsm: no migration in progress.\n");
                return 2;
        }
+       curr_migr_unit = info->reshape_progress / blocks_per_unit;
+       /* check if array is alligned to copy area
+        * if it is not alligned, add one to current migration unit value
+        * this can happend on array reshape finish only
+        */
+       if (info->reshape_progress % blocks_per_unit)
+               curr_migr_unit++;
 
        super->migr_rec->curr_migr_unit =
-         __cpu_to_le32(info->reshape_progress /
-                       __le32_to_cpu(super->migr_rec->blocks_per_unit));
+               __cpu_to_le32(curr_migr_unit);
        super->migr_rec->rec_status = __cpu_to_le32(state);
        super->migr_rec->dest_1st_member_lba =
-         __cpu_to_le32((__le32_to_cpu(super->migr_rec->curr_migr_unit))
-                       * __le32_to_cpu(super->migr_rec->dest_depth_per_unit));
+               __cpu_to_le32(curr_migr_unit *
+                             __le32_to_cpu(super->migr_rec->dest_depth_per_unit));
        if (write_imsm_migr_rec(st) < 0) {
                dprintf("imsm: Cannot write migration record "
                        "outside backup area\n");
@@ -7801,9 +7976,6 @@ int save_checkpoint_imsm(struct supertype *st, struct mdinfo *info, int state)
        return 0;
 }
 
-static __u64 blocks_per_migr_unit(struct intel_super *super,
-                                 struct imsm_dev *dev);
-
 /*******************************************************************************
  * Function:   recover_backup_imsm
  * Description:        Function recovers critical data from the Migration Copy Area
@@ -7885,7 +8057,7 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info)
                                strerror(errno));
                        goto abort;
                }
-               if (read(targets[i], buf, unit_len) != unit_len) {
+               if ((unsigned)read(targets[i], buf, unit_len) != unit_len) {
                        fprintf(stderr,
                                Name ": Cannot read copy area block: %s\n",
                                strerror(errno));
@@ -7897,7 +8069,7 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info)
                                strerror(errno));
                        goto abort;
                }
-               if (write(targets[i], buf, unit_len) != unit_len) {
+               if ((unsigned)write(targets[i], buf, unit_len) != unit_len) {
                        fprintf(stderr,
                                Name ": Cannot restore block: %s\n",
                                strerror(errno));
@@ -8148,6 +8320,7 @@ static int imsm_create_metadata_update_for_reshape(
            || delta_disks > spares->array.spare_disks) {
                fprintf(stderr, Name ": imsm: ERROR: Cannot get spare devices "
                        "for %s.\n", geo->dev_name);
+               i = -1;
                goto abort;
        }
 
@@ -8507,8 +8680,9 @@ static int imsm_reshape_super(struct supertype *st, long long size, int level,
                dprintf("imsm: info: Volume operation\n");
                /* find requested device */
                while (dev) {
-                       imsm_find_array_minor_by_subdev(dev->index, st->container_dev, &devnum);
-                       if (devnum == geo.dev_id)
+                       if (imsm_find_array_minor_by_subdev(
+                                   dev->index, st->container_dev, &devnum) == 0
+                           && devnum == geo.dev_id)
                                break;
                        dev = dev->next;
                }
@@ -8772,8 +8946,7 @@ static int imsm_manage_reshape(
        }
 
        max_position = sra->component_size * ndata;
-       if (map_src->raid_level != 0)
-               source_layout = ALGORITHM_LEFT_ASYMMETRIC;
+       source_layout = imsm_level_to_layout(map_src->raid_level);
 
        while (__le32_to_cpu(migr_rec->curr_migr_unit) <
               __le32_to_cpu(migr_rec->num_migr_units)) {
@@ -8854,11 +9027,19 @@ static int imsm_manage_reshape(
                                        "migration record (UNIT_SRC_IN_CP_AREA)\n");
                                goto abort;
                        }
+               } else {
+                       /* set next step to use whole border area */
+                       border /= next_step;
+                       if (border > 1)
+                               next_step *= border;
                }
                /* When data backed up, checkpoint stored,
                 * kick the kernel to reshape unit of data
                 */
                next_step = next_step + sra->reshape_progress;
+               /* limit next step to array max position */
+               if (next_step > max_position)
+                       next_step = max_position;
                sysfs_set_num(sra, NULL, "suspend_lo", sra->reshape_progress);
                sysfs_set_num(sra, NULL, "suspend_hi", next_step);
                sra->reshape_progress = next_step;
@@ -8909,6 +9090,7 @@ struct superswitch super_imsm = {
        .get_disk_controller_domain = imsm_get_disk_controller_domain,
        .reshape_super  = imsm_reshape_super,
        .manage_reshape = imsm_manage_reshape,
+       .recover_backup = recover_backup_imsm,
 #endif
        .match_home     = match_home_imsm,
        .uuid_from_super= uuid_from_super_imsm,
@@ -8928,7 +9110,6 @@ struct superswitch super_imsm = {
        .match_metadata_desc = match_metadata_desc_imsm,
        .container_content = container_content_imsm,
 
-       .recover_backup = recover_backup_imsm,
 
        .external       = 1,
        .name = "imsm",