]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - super-intel.c
Modify mdstat parsing for volumes with the bitmap
[thirdparty/mdadm.git] / super-intel.c
index 5c1f759f24a64df2b01321ec406bd59df8f3d4bf..98af3b5e953fc4361afb09cd0def71443addb4bc 100644 (file)
@@ -260,8 +260,9 @@ struct imsm_super {
                                         * (starts at 1)
                                         */
        __u16 filler1;                  /* 0x4E - 0x4F */
-#define IMSM_FILLERS 34
-       __u32 filler[IMSM_FILLERS];     /* 0x50 - 0xD7 RAID_MPB_FILLERS */
+       __u64 creation_time;            /* 0x50 - 0x57 Array creation time */
+#define IMSM_FILLERS 32
+       __u32 filler[IMSM_FILLERS];     /* 0x58 - 0xD7 RAID_MPB_FILLERS */
        struct imsm_disk disk[1];       /* 0xD8 diskTbl[numDisks] */
        /* here comes imsm_dev[num_raid_devs] */
        /* here comes BBM logs */
@@ -1578,6 +1579,7 @@ static void print_imsm_dev(struct intel_super *super,
 
        printf("\n");
        printf("[%.16s]:\n", dev->volume);
+       printf("       Subarray : %d\n", super->current_vol);
        printf("           UUID : %s\n", uuid);
        printf("     RAID Level : %d", get_imsm_raid_level(map));
        if (map2)
@@ -1682,6 +1684,8 @@ static void print_imsm_dev(struct intel_super *super,
                printf("Multiple PPLs on journaling drive\n");
        else
                printf("<unknown:%d>\n", dev->rwh_policy);
+
+       printf("      Volume ID : %u\n", dev->my_vol_raid_dev_num);
 }
 
 static void print_imsm_disk(struct imsm_disk *disk,
@@ -2014,6 +2018,7 @@ static void examine_super_imsm(struct supertype *st, char *homehost)
        __u32 sum;
        __u32 reserved = imsm_reserved_sectors(super, super->disks);
        struct dl *dl;
+       time_t creation_time;
 
        strncpy(str, (char *)mpb->sig, MPB_SIG_LEN);
        str[MPB_SIG_LEN-1] = '\0';
@@ -2022,6 +2027,9 @@ 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));
+       creation_time = __le64_to_cpu(mpb->creation_time);
+       printf("  Creation Time : %.24s\n",
+               creation_time ? ctime(&creation_time) : "Unknown");
        printf("     Attributes : ");
        if (imsm_check_attributes(mpb->attributes))
                printf("All supported\n");
@@ -2126,61 +2134,7 @@ static void export_examine_super_imsm(struct supertype *st)
        printf("MD_LEVEL=container\n");
        printf("MD_UUID=%s\n", nbuf+5);
        printf("MD_DEVICES=%u\n", mpb->num_disks);
-}
-
-static int copy_metadata_imsm(struct supertype *st, int from, int to)
-{
-       /* The second last sector of the device contains
-        * the "struct imsm_super" metadata.
-        * This contains mpb_size which is the size in bytes of the
-        * extended metadata.  This is located immediately before
-        * the imsm_super.
-        * We want to read all that, plus the last sector which
-        * may contain a migration record, and write it all
-        * to the target.
-        */
-       void *buf;
-       unsigned long long dsize, offset;
-       int sectors;
-       struct imsm_super *sb;
-       struct intel_super *super = st->sb;
-       unsigned int sector_size = super->sector_size;
-       unsigned int written = 0;
-
-       if (posix_memalign(&buf, MAX_SECTOR_SIZE, MAX_SECTOR_SIZE) != 0)
-               return 1;
-
-       if (!get_dev_size(from, NULL, &dsize))
-               goto err;
-
-       if (lseek64(from, dsize-(2*sector_size), 0) < 0)
-               goto err;
-       if ((unsigned int)read(from, buf, sector_size) != sector_size)
-               goto err;
-       sb = buf;
-       if (strncmp((char*)sb->sig, MPB_SIGNATURE, MPB_SIG_LEN) != 0)
-               goto err;
-
-       sectors = mpb_sectors(sb, sector_size) + 2;
-       offset = dsize - sectors * sector_size;
-       if (lseek64(from, offset, 0) < 0 ||
-           lseek64(to, offset, 0) < 0)
-               goto err;
-       while (written < sectors * sector_size) {
-               int n = sectors*sector_size - written;
-               if (n > 4096)
-                       n = 4096;
-               if (read(from, buf, n) != n)
-                       goto err;
-               if (write(to, buf, n) != n)
-                       goto err;
-               written += n;
-       }
-       free(buf);
-       return 0;
-err:
-       free(buf);
-       return 1;
+       printf("MD_CREATION_TIME=%llu\n", __le64_to_cpu(mpb->creation_time));
 }
 
 static void detail_super_imsm(struct supertype *st, char *homehost,
@@ -2410,7 +2364,9 @@ static int print_nvme_info(struct sys_dev *hba)
                                continue;
                        if (path_attached_to_hba(rp, hba->path)) {
                                fd = open_dev(ent->d_name);
-                               if (fd < 0) {
+                               if (!imsm_is_nvme_supported(fd, 0)) {
+                                       if (fd >= 0)
+                                               close(fd);
                                        free(rp);
                                        continue;
                                }
@@ -3099,15 +3055,13 @@ static struct imsm_dev *imsm_get_device_during_migration(
  *             sector of disk)
  * Parameters:
  *     super   : imsm internal array info
- *     info    : general array info
  * Returns:
  *      0 : success
  *     -1 : fail
  *     -2 : no migration in progress
  ******************************************************************************/
-static int load_imsm_migr_rec(struct intel_super *super, struct mdinfo *info)
+static int load_imsm_migr_rec(struct intel_super *super)
 {
-       struct mdinfo *sd;
        struct dl *dl;
        char nm[30];
        int retval = -1;
@@ -3115,6 +3069,7 @@ static int load_imsm_migr_rec(struct intel_super *super, struct mdinfo *info)
        struct imsm_dev *dev;
        struct imsm_map *map;
        int slot = -1;
+       int keep_fd = 1;
 
        /* find map under migration */
        dev = imsm_get_device_during_migration(super);
@@ -3123,44 +3078,40 @@ static int load_imsm_migr_rec(struct intel_super *super, struct mdinfo *info)
        if (dev == NULL)
                return -2;
 
-       if (info) {
-               for (sd = info->devs ; sd ; sd = sd->next) {
-                       /* read only from one of the first two slots */
-                       if ((sd->disk.raid_disk < 0) ||
-                           (sd->disk.raid_disk > 1))
-                               continue;
+       map = get_imsm_map(dev, MAP_0);
+       if (!map)
+               return -1;
 
-                       sprintf(nm, "%d:%d", sd->disk.major, sd->disk.minor);
-                       fd = dev_open(nm, O_RDONLY);
-                       if (fd >= 0)
-                               break;
-               }
-       }
-       if (fd < 0) {
-               map = get_imsm_map(dev, MAP_0);
-               for (dl = super->disks; dl; dl = dl->next) {
-                       /* skip spare and failed disks
-                       */
-                       if (dl->index < 0)
-                               continue;
-                       /* read only from one of the first two slots */
-                       if (map)
-                               slot = get_imsm_disk_slot(map, dl->index);
-                       if (map == NULL || slot > 1 || slot < 0)
-                               continue;
+       for (dl = super->disks; dl; dl = dl->next) {
+               /* skip spare and failed disks
+                */
+               if (dl->index < 0)
+                       continue;
+               /* read only from one of the first two slots
+                */
+               slot = get_imsm_disk_slot(map, dl->index);
+               if (slot > 1 || slot < 0)
+                       continue;
+
+               if (dl->fd < 0) {
                        sprintf(nm, "%d:%d", dl->major, dl->minor);
                        fd = dev_open(nm, O_RDONLY);
-                       if (fd >= 0)
+                       if (fd >= 0) {
+                               keep_fd = 0;
                                break;
+                       }
+               } else {
+                       fd = dl->fd;
+                       break;
                }
        }
+
        if (fd < 0)
-               goto out;
+               return retval;
        retval = read_imsm_migr_rec(fd, super);
-
-out:
-       if (fd >= 0)
+       if (!keep_fd)
                close(fd);
+
        return retval;
 }
 
@@ -3221,8 +3172,6 @@ static int write_imsm_migr_rec(struct supertype *st)
        struct intel_super *super = st->sb;
        unsigned int sector_size = super->sector_size;
        unsigned long long dsize;
-       char nm[30];
-       int fd = -1;
        int retval = -1;
        struct dl *sd;
        int len;
@@ -3255,26 +3204,21 @@ static int write_imsm_migr_rec(struct supertype *st)
                if (map == NULL || slot > 1 || slot < 0)
                        continue;
 
-               sprintf(nm, "%d:%d", sd->major, sd->minor);
-               fd = dev_open(nm, O_RDWR);
-               if (fd < 0)
-                       continue;
-               get_dev_size(fd, NULL, &dsize);
-               if (lseek64(fd, dsize - (MIGR_REC_SECTOR_POSITION*sector_size),
+               get_dev_size(sd->fd, NULL, &dsize);
+               if (lseek64(sd->fd, dsize - (MIGR_REC_SECTOR_POSITION *
+                   sector_size),
                    SEEK_SET) < 0) {
                        pr_err("Cannot seek to anchor block: %s\n",
                               strerror(errno));
                        goto out;
                }
-               if ((unsigned int)write(fd, super->migr_rec_buf,
+               if ((unsigned int)write(sd->fd, super->migr_rec_buf,
                    MIGR_REC_BUF_SECTORS*sector_size) !=
                    MIGR_REC_BUF_SECTORS*sector_size) {
                        pr_err("Cannot write migr record block: %s\n",
                               strerror(errno));
                        goto out;
                }
-               close(fd);
-               fd = -1;
        }
        if (sector_size == 4096)
                convert_from_4k_imsm_migr_rec(super);
@@ -3300,8 +3244,6 @@ static int write_imsm_migr_rec(struct supertype *st)
 
        retval = 0;
  out:
-       if (fd >= 0)
-               close(fd);
        return retval;
 }
 
@@ -3499,7 +3441,6 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
                        __u64 blocks_per_unit = blocks_per_migr_unit(super,
                                                                     dev);
                        __u64 units = current_migr_unit(migr_rec);
-                       unsigned long long array_blocks;
                        int used_disks;
 
                        if (__le32_to_cpu(migr_rec->ascending_migr) &&
@@ -3518,12 +3459,8 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
 
                        used_disks = imsm_num_data_members(prev_map);
                        if (used_disks > 0) {
-                               array_blocks = per_dev_array_size(map) *
+                               info->custom_array_size = per_dev_array_size(map) *
                                        used_disks;
-                               info->custom_array_size =
-                                       round_size_to_mb(array_blocks,
-                                                        used_disks);
-
                        }
                }
                case MIGR_VERIFY:
@@ -3878,7 +3815,8 @@ static void imsm_copy_dev(struct imsm_dev *dest, struct imsm_dev *src)
        memcpy(dest, src, sizeof_imsm_dev(src, 0));
 }
 
-static int compare_super_imsm(struct supertype *st, struct supertype *tst)
+static int compare_super_imsm(struct supertype *st, struct supertype *tst,
+                             int verbose)
 {
        /*
         * return:
@@ -3901,18 +3839,20 @@ static int compare_super_imsm(struct supertype *st, struct supertype *tst)
         */
        if (!check_env("IMSM_NO_PLATFORM") && first->hba && sec->hba) {
                if (first->hba->type != sec->hba->type) {
-                       fprintf(stderr,
-                               "HBAs of devices do not match %s != %s\n",
-                               get_sys_dev_type(first->hba->type),
-                               get_sys_dev_type(sec->hba->type));
+                       if (verbose)
+                               pr_err("HBAs of devices do not match %s != %s\n",
+                                      get_sys_dev_type(first->hba->type),
+                                      get_sys_dev_type(sec->hba->type));
                        return 3;
                }
+
                if (first->orom != sec->orom) {
-                       fprintf(stderr,
-                               "HBAs of devices do not match %s != %s\n",
-                               first->hba->pci_id, sec->hba->pci_id);
+                       if (verbose)
+                               pr_err("HBAs of devices do not match %s != %s\n",
+                                      first->hba->pci_id, sec->hba->pci_id);
                        return 3;
                }
+
        }
 
        /* if an anchor does not have num_raid_devs set then it is a free
@@ -5060,7 +5000,7 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
        }
 
        /* load migration record */
-       err = load_imsm_migr_rec(super, NULL);
+       err = load_imsm_migr_rec(super);
        if (err == -1) {
                /* migration is in progress,
                 * but migr_rec cannot be loaded,
@@ -5309,7 +5249,7 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname)
        }
 
        /* load migration record */
-       if (load_imsm_migr_rec(super, NULL) == 0) {
+       if (load_imsm_migr_rec(super) == 0) {
                /* Check for unsupported migration features */
                if (check_mpb_migr_compatibility(super) != 0) {
                        pr_err("Unsupported migration detected");
@@ -5817,6 +5757,7 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
                sum += __gen_imsm_checksum(mpb);
                mpb->family_num = __cpu_to_le32(sum);
                mpb->orig_family_num = mpb->family_num;
+               mpb->creation_time = __cpu_to_le64((__u64)time(NULL));
        }
        super->current_disk = dl;
        return 0;
@@ -5854,6 +5795,9 @@ int mark_spare(struct dl *disk)
        return ret_val;
 }
 
+
+static int write_super_imsm_spare(struct intel_super *super, struct dl *d);
+
 static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
                             int fd, char *devname,
                             unsigned long long data_offset)
@@ -5915,6 +5859,13 @@ static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
                snprintf(controller_path, PATH_MAX-1, "%s/device", devpath);
                free(devpath);
 
+               if (!imsm_is_nvme_supported(dd->fd, 1)) {
+                       if (dd->devname)
+                               free(dd->devname);
+                       free(dd);
+                       return 1;
+               }
+
                if (devpath_to_vendor(controller_path) == 0x8086) {
                        /*
                         * If Intel's NVMe drive has serial ended with
@@ -5983,9 +5934,13 @@ static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
                dd->next = super->disk_mgmt_list;
                super->disk_mgmt_list = dd;
        } else {
+               /* this is called outside of mdmon
+                * write initial spare metadata
+                * mdmon will overwrite it.
+                */
                dd->next = super->disks;
                super->disks = dd;
-               super->updates_pending++;
+               write_super_imsm_spare(super, dd);
        }
 
        return 0;
@@ -6024,15 +5979,15 @@ static union {
        struct imsm_super anchor;
 } spare_record __attribute__ ((aligned(MAX_SECTOR_SIZE)));
 
-/* spare records have their own family number and do not have any defined raid
- * devices
- */
-static int write_super_imsm_spares(struct intel_super *super, int doclose)
+
+static int write_super_imsm_spare(struct intel_super *super, struct dl *d)
 {
        struct imsm_super *mpb = super->anchor;
        struct imsm_super *spare = &spare_record.anchor;
        __u32 sum;
-       struct dl *d;
+
+       if (d->index != -1)
+               return 1;
 
        spare->mpb_size = __cpu_to_le32(sizeof(struct imsm_super));
        spare->generation_num = __cpu_to_le32(1UL);
@@ -6045,28 +6000,41 @@ static int write_super_imsm_spares(struct intel_super *super, int doclose)
        snprintf((char *) spare->sig, MAX_SIGNATURE_LENGTH,
                 MPB_SIGNATURE MPB_VERSION_RAID0);
 
-       for (d = super->disks; d; d = d->next) {
-               if (d->index != -1)
-                       continue;
+       spare->disk[0] = d->disk;
+       if (__le32_to_cpu(d->disk.total_blocks_hi) > 0)
+               spare->attributes |= MPB_ATTRIB_2TB_DISK;
+
+       if (super->sector_size == 4096)
+               convert_to_4k_imsm_disk(&spare->disk[0]);
 
-               spare->disk[0] = d->disk;
-               if (__le32_to_cpu(d->disk.total_blocks_hi) > 0)
-                       spare->attributes |= MPB_ATTRIB_2TB_DISK;
+       sum = __gen_imsm_checksum(spare);
+       spare->family_num = __cpu_to_le32(sum);
+       spare->orig_family_num = 0;
+       sum = __gen_imsm_checksum(spare);
+       spare->check_sum = __cpu_to_le32(sum);
+
+       if (store_imsm_mpb(d->fd, spare)) {
+               pr_err("failed for device %d:%d %s\n",
+                       d->major, d->minor, strerror(errno));
+               return 1;
+       }
 
-               if (super->sector_size == 4096)
-                       convert_to_4k_imsm_disk(&spare->disk[0]);
+       return 0;
+}
+/* spare records have their own family number and do not have any defined raid
+ * devices
+ */
+static int write_super_imsm_spares(struct intel_super *super, int doclose)
+{
+       struct dl *d;
 
-               sum = __gen_imsm_checksum(spare);
-               spare->family_num = __cpu_to_le32(sum);
-               spare->orig_family_num = 0;
-               sum = __gen_imsm_checksum(spare);
-               spare->check_sum = __cpu_to_le32(sum);
+       for (d = super->disks; d; d = d->next) {
+               if (d->index != -1)
+                       continue;
 
-               if (store_imsm_mpb(d->fd, spare)) {
-                       pr_err("failed for device %d:%d %s\n",
-                               d->major, d->minor, strerror(errno));
+               if (write_super_imsm_spare(super, d))
                        return 1;
-               }
+
                if (doclose) {
                        close(d->fd);
                        d->fd = -1;
@@ -6983,7 +6951,7 @@ count_volumes_list(struct md_list *devlist, char *homehost,
 
                        if (st->ss != tst->ss ||
                            st->minor_version != tst->minor_version ||
-                           st->ss->compare_super(st, tst) != 0) {
+                           st->ss->compare_super(st, tst, 1) != 0) {
                                /* Some mismatch. If exactly one array matches this host,
                                 * we can resolve on that one.
                                 * Or, if we are auto assembling, we just ignore the second
@@ -7480,7 +7448,10 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
                                                        verbose);
        }
 
-       if (size && (size < 1024)) {
+       /*
+        * Size is given in sectors.
+        */
+       if (size && (size < 2048)) {
                pr_err("Given size must be greater than 1M.\n");
                /* Depends on algorithm in Create.c :
                 * if container was given (dev == NULL) return -1,
@@ -7600,18 +7571,17 @@ static void default_geometry_imsm(struct supertype *st, int *level, int *layout,
 
 static void handle_missing(struct intel_super *super, struct imsm_dev *dev);
 
-static int kill_subarray_imsm(struct supertype *st)
+static int kill_subarray_imsm(struct supertype *st, char *subarray_id)
 {
-       /* remove the subarray currently referenced by ->current_vol */
+       /* remove the subarray currently referenced by subarray_id */
        __u8 i;
        struct intel_dev **dp;
        struct intel_super *super = st->sb;
-       __u8 current_vol = super->current_vol;
+       __u8 current_vol = strtoul(subarray_id, NULL, 10);
        struct imsm_super *mpb = super->anchor;
 
-       if (super->current_vol < 0)
+       if (mpb->num_raid_devs == 0)
                return 2;
-       super->current_vol = -1; /* invalidate subarray cursor */
 
        /* block deletions that would change the uuid of active subarrays
         *
@@ -7946,7 +7916,8 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
                                skip = 1;
                        if (!skip && (ord & IMSM_ORD_REBUILD))
                                recovery_start = 0;
-
+                       if (!(ord & IMSM_ORD_REBUILD))
+                               this->array.working_disks++;
                        /*
                         * if we skip some disks the array will be assmebled degraded;
                         * reset resync start to avoid a dirty-degraded
@@ -7988,8 +7959,6 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
                                else
                                        this->array.spare_disks++;
                        }
-                       if (info_d->recovery_start == MaxSector)
-                               this->array.working_disks++;
 
                        info_d->events = __le32_to_cpu(mpb->generation_num);
                        info_d->data_offset = pba_of_lba0(map);
@@ -8627,7 +8596,6 @@ static void imsm_set_disk(struct active_array *a, int n, int state)
                                break;
                        }
                        end_migration(dev, super, map_state);
-                       map = get_imsm_map(dev, MAP_0);
                        map->failed_disk_num = ~0;
                        super->updates_pending++;
                        a->last_checkpoint = 0;
@@ -8639,7 +8607,6 @@ static void imsm_set_disk(struct active_array *a, int n, int state)
                                end_migration(dev, super, map_state);
                        else
                                map->map_state = map_state;
-                       map = get_imsm_map(dev, MAP_0);
                        map->failed_disk_num = ~0;
                        super->updates_pending++;
                        break;
@@ -10403,21 +10370,6 @@ static void imsm_delete(struct intel_super *super, struct dl **dlp, unsigned ind
        }
 }
 
-static void close_targets(int *targets, int new_disks)
-{
-       int i;
-
-       if (!targets)
-               return;
-
-       for (i = 0; i < new_disks; i++) {
-               if (targets[i] >= 0) {
-                       close(targets[i]);
-                       targets[i] = -1;
-               }
-       }
-}
-
 static int imsm_get_allowed_degradation(int level, int raid_disks,
                                        struct intel_super *super,
                                        struct imsm_dev *dev)
@@ -10471,62 +10423,6 @@ static int imsm_get_allowed_degradation(int level, int raid_disks,
        }
 }
 
-/*******************************************************************************
- * Function:   open_backup_targets
- * Description:        Function opens file descriptors for all devices given in
- *             info->devs
- * Parameters:
- *     info            : general array info
- *     raid_disks      : number of disks
- *     raid_fds        : table of device's file descriptors
- *     super           : intel super for raid10 degradation check
- *     dev             : intel device for raid10 degradation check
- * Returns:
- *      0 : success
- *     -1 : fail
- ******************************************************************************/
-int open_backup_targets(struct mdinfo *info, int raid_disks, int *raid_fds,
-                       struct intel_super *super, struct imsm_dev *dev)
-{
-       struct mdinfo *sd;
-       int i;
-       int opened = 0;
-
-       for (i = 0; i < raid_disks; i++)
-               raid_fds[i] = -1;
-
-       for (sd = info->devs ; sd ; sd = sd->next) {
-               char *dn;
-
-               if (sd->disk.state & (1<<MD_DISK_FAULTY)) {
-                       dprintf("disk is faulty!!\n");
-                       continue;
-               }
-
-               if (sd->disk.raid_disk >= raid_disks || sd->disk.raid_disk < 0)
-                       continue;
-
-               dn = map_dev(sd->disk.major,
-                            sd->disk.minor, 1);
-               raid_fds[sd->disk.raid_disk] = dev_open(dn, O_RDWR);
-               if (raid_fds[sd->disk.raid_disk] < 0) {
-                       pr_err("cannot open component\n");
-                       continue;
-               }
-               opened++;
-       }
-       /* check if maximum array degradation level is not exceeded
-       */
-       if ((raid_disks - opened) >
-           imsm_get_allowed_degradation(info->new_level, raid_disks,
-                                        super, dev)) {
-               pr_err("Not enough disks can be opened.\n");
-               close_targets(raid_fds, raid_disks);
-               return -2;
-       }
-       return 0;
-}
-
 /*******************************************************************************
  * Function:   validate_container_imsm
  * Description: This routine validates container after assemble,
@@ -10767,13 +10663,11 @@ void init_migr_record_imsm(struct supertype *st, struct imsm_dev *dev,
        int new_data_disks;
        unsigned long long dsize, dev_sectors;
        long long unsigned min_dev_sectors = -1LLU;
-       struct mdinfo *sd;
-       char nm[30];
-       int fd;
        struct imsm_map *map_dest = get_imsm_map(dev, MAP_0);
        struct imsm_map *map_src = get_imsm_map(dev, MAP_1);
        unsigned long long num_migr_units;
        unsigned long long array_blocks;
+       struct dl *dl_disk = NULL;
 
        memset(migr_rec, 0, sizeof(struct migr_record));
        migr_rec->family_num = __cpu_to_le32(super->anchor->family_num);
@@ -10802,16 +10696,14 @@ void init_migr_record_imsm(struct supertype *st, struct imsm_dev *dev,
        migr_rec->post_migr_vol_cap_hi = dev->size_high;
 
        /* Find the smallest dev */
-       for (sd = info->devs ; sd ; sd = sd->next) {
-               sprintf(nm, "%d:%d", sd->disk.major, sd->disk.minor);
-               fd = dev_open(nm, O_RDONLY);
-               if (fd < 0)
+       for (dl_disk =  super->disks; dl_disk ; dl_disk = dl_disk->next) {
+               /* ignore spares in container */
+               if (dl_disk->index < 0)
                        continue;
-               get_dev_size(fd, NULL, &dsize);
+               get_dev_size(dl_disk->fd, NULL, &dsize);
                dev_sectors = dsize / 512;
                if (dev_sectors < min_dev_sectors)
                        min_dev_sectors = dev_sectors;
-               close(fd);
        }
        set_migr_chkp_area_pba(migr_rec, min_dev_sectors -
                                        RAID_DISK_RESERVED_BLOCKS_IMSM_HI);
@@ -10857,8 +10749,11 @@ int save_backup_imsm(struct supertype *st,
 
        targets = xmalloc(new_disks * sizeof(int));
 
-       for (i = 0; i < new_disks; i++)
-               targets[i] = -1;
+       for (i = 0; i < new_disks; i++) {
+               struct dl *dl_disk = get_imsm_dl_disk(super, i);
+
+               targets[i] = dl_disk->fd;
+       }
 
        target_offsets = xcalloc(new_disks, sizeof(unsigned long long));
 
@@ -10871,10 +10766,6 @@ int save_backup_imsm(struct supertype *st,
                target_offsets[i] -= start/data_disks;
        }
 
-       if (open_backup_targets(info, new_disks, targets,
-                               super, dev))
-               goto abort;
-
        dest_layout = imsm_level_to_layout(map_dest->raid_level);
        dest_chunk = __le16_to_cpu(map_dest->blocks_per_strip) * 512;
 
@@ -10898,7 +10789,6 @@ int save_backup_imsm(struct supertype *st,
 
 abort:
        if (targets) {
-               close_targets(targets, new_disks);
                free(targets);
        }
        free(target_offsets);
@@ -10925,7 +10815,7 @@ int save_checkpoint_imsm(struct supertype *st, struct mdinfo *info, int state)
        unsigned long long blocks_per_unit;
        unsigned long long curr_migr_unit;
 
-       if (load_imsm_migr_rec(super, info) != 0) {
+       if (load_imsm_migr_rec(super) != 0) {
                dprintf("imsm: ERROR: Cannot read migration record for checkpoint save.\n");
                return 1;
        }
@@ -10976,8 +10866,7 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info)
        unsigned long long read_offset;
        unsigned long long write_offset;
        unsigned unit_len;
-       int *targets = NULL;
-       int new_disks, i, err;
+       int new_disks, err;
        char *buf = NULL;
        int retval = 1;
        unsigned int sector_size = super->sector_size;
@@ -10985,6 +10874,7 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info)
        unsigned long num_migr_units = get_num_migr_units(migr_rec);
        char buffer[20];
        int skipped_disks = 0;
+       struct dl *dl_disk;
 
        err = sysfs_get_str(info, NULL, "array_state", (char *)buffer, 20);
        if (err < 1)
@@ -11017,37 +10907,34 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info)
        unit_len = __le32_to_cpu(migr_rec->dest_depth_per_unit) * 512;
        if (posix_memalign((void **)&buf, sector_size, unit_len) != 0)
                goto abort;
-       targets = xcalloc(new_disks, sizeof(int));
 
-       if (open_backup_targets(info, new_disks, targets, super, id->dev)) {
-               pr_err("Cannot open some devices belonging to array.\n");
-               goto abort;
-       }
+       for (dl_disk = super->disks; dl_disk; dl_disk = dl_disk->next) {
+               if (dl_disk->index < 0)
+                       continue;
 
-       for (i = 0; i < new_disks; i++) {
-               if (targets[i] < 0) {
+               if (dl_disk->fd < 0) {
                        skipped_disks++;
                        continue;
                }
-               if (lseek64(targets[i], read_offset, SEEK_SET) < 0) {
+               if (lseek64(dl_disk->fd, read_offset, SEEK_SET) < 0) {
                        pr_err("Cannot seek to block: %s\n",
                               strerror(errno));
                        skipped_disks++;
                        continue;
                }
-               if ((unsigned)read(targets[i], buf, unit_len) != unit_len) {
+               if (read(dl_disk->fd, buf, unit_len) != unit_len) {
                        pr_err("Cannot read copy area block: %s\n",
                               strerror(errno));
                        skipped_disks++;
                        continue;
                }
-               if (lseek64(targets[i], write_offset, SEEK_SET) < 0) {
+               if (lseek64(dl_disk->fd, write_offset, SEEK_SET) < 0) {
                        pr_err("Cannot seek to block: %s\n",
                               strerror(errno));
                        skipped_disks++;
                        continue;
                }
-               if ((unsigned)write(targets[i], buf, unit_len) != unit_len) {
+               if (write(dl_disk->fd, buf, unit_len) != unit_len) {
                        pr_err("Cannot restore block: %s\n",
                               strerror(errno));
                        skipped_disks++;
@@ -11071,12 +10958,6 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info)
                retval = 0;
 
 abort:
-       if (targets) {
-               for (i = 0; i < new_disks; i++)
-                       if (targets[i])
-                               close(targets[i]);
-               free(targets);
-       }
        free(buf);
        return retval;
 }
@@ -11706,6 +11587,68 @@ int imsm_takeover(struct supertype *st, struct geo_params *geo)
        return 0;
 }
 
+/* Flush size update if size calculated by num_data_stripes is higher than
+ * imsm_dev_size to eliminate differences during reshape.
+ * Mdmon will recalculate them correctly.
+ * If subarray index is not set then check whole container.
+ * Returns:
+ *     0 - no error occurred
+ *     1 - error detected
+ */
+static int imsm_fix_size_mismatch(struct supertype *st, int subarray_index)
+{
+       struct intel_super *super = st->sb;
+       int tmp = super->current_vol;
+       int ret_val = 1;
+       int i;
+
+       for (i = 0; i < super->anchor->num_raid_devs; i++) {
+               if (subarray_index >= 0 && i != subarray_index)
+                       continue;
+               super->current_vol = i;
+               struct imsm_dev *dev = get_imsm_dev(super, super->current_vol);
+               struct imsm_map *map = get_imsm_map(dev, MAP_0);
+               unsigned int disc_count = imsm_num_data_members(map);
+               struct geo_params geo;
+               struct imsm_update_size_change *update;
+               unsigned long long calc_size = per_dev_array_size(map) * disc_count;
+               unsigned long long d_size = imsm_dev_size(dev);
+               int u_size;
+
+               if (calc_size == d_size || dev->vol.migr_type == MIGR_GEN_MIGR)
+                       continue;
+
+               /* There is a difference, verify that imsm_dev_size is
+                * rounded correctly and push update.
+                */
+               if (d_size != round_size_to_mb(d_size, disc_count)) {
+                       dprintf("imsm: Size of volume %d is not rounded correctly\n",
+                                i);
+                       goto exit;
+               }
+               memset(&geo, 0, sizeof(struct geo_params));
+               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);
+                       flush_metadata_updates(st);
+                       st->update_tail = &st->updates;
+               } else {
+                       imsm_sync_metadata(st);
+               }
+       }
+       ret_val = 0;
+exit:
+       super->current_vol = tmp;
+       return ret_val;
+}
+
 static int imsm_reshape_super(struct supertype *st, unsigned long long size,
                              int level,
                              int layout, int chunksize, int raid_disks,
@@ -11742,6 +11685,11 @@ static int imsm_reshape_super(struct supertype *st, unsigned long long size,
                        struct imsm_update_reshape *u = NULL;
                        int len;
 
+                       if (imsm_fix_size_mismatch(st, -1)) {
+                               dprintf("imsm: Cannot fix size mismatch\n");
+                               goto exit_imsm_reshape_super;
+                       }
+
                        len = imsm_create_metadata_update_for_reshape(
                                st, &geo, old_raid_disks, &u);
 
@@ -12044,6 +11992,7 @@ static int imsm_manage_reshape(
        unsigned long long start_buf_shift; /* [bytes] */
        int degraded = 0;
        int source_layout = 0;
+       int subarray_index = -1;
 
        if (!sra)
                return ret_val;
@@ -12057,6 +12006,7 @@ static int imsm_manage_reshape(
                    dv->dev->vol.migr_state == 1) {
                        dev = dv->dev;
                        migr_vol_qan++;
+                       subarray_index = dv->index;
                }
        }
        /* Only one volume can migrate at the same time */
@@ -12241,6 +12191,14 @@ static int imsm_manage_reshape(
 
        /* return '1' if done */
        ret_val = 1;
+
+       /* After the reshape eliminate size mismatch in metadata.
+        * Don't update md/component_size here, volume hasn't
+        * to take whole space. It is allowed by kernel.
+        * md/component_size will be set propoperly after next assembly.
+        */
+       imsm_fix_size_mismatch(st, subarray_index);
+
 abort:
        free(buf);
        /* See Grow.c: abort_reshape() for further explanation */
@@ -12272,7 +12230,6 @@ struct superswitch super_imsm = {
        .reshape_super  = imsm_reshape_super,
        .manage_reshape = imsm_manage_reshape,
        .recover_backup = recover_backup_imsm,
-       .copy_metadata = copy_metadata_imsm,
        .examine_badblocks = examine_badblocks_imsm,
        .match_home     = match_home_imsm,
        .uuid_from_super= uuid_from_super_imsm,