]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - super-intel.c
Change update to enum in update_super and update_subarray
[thirdparty/mdadm.git] / super-intel.c
index da376251ce4e4eea5368afef11ebee49e1857e8e..1f5f6eda6d22d22503214ce118e33ed0035d13e8 100644 (file)
@@ -366,6 +366,18 @@ struct migr_record {
 };
 ASSERT_SIZE(migr_record, 128)
 
+/**
+ * enum imsm_status - internal IMSM return values representation.
+ * @STATUS_OK: function succeeded.
+ * @STATUS_ERROR: General error ocurred (not specified).
+ *
+ * Typedefed to imsm_status_t.
+ */
+typedef enum imsm_status {
+       IMSM_STATUS_ERROR = -1,
+       IMSM_STATUS_OK = 0,
+} imsm_status_t;
+
 struct md_list {
        /* usage marker:
         *  1: load metadata
@@ -691,7 +703,7 @@ static struct sys_dev* find_disk_attached_hba(int fd, const char *devname)
        if ((list = find_intel_devices()) == NULL)
                return 0;
 
-       if (fd < 0)
+       if (!is_fd_valid(fd))
                disk_path  = (char *) devname;
        else
                disk_path = diskfd_to_devpath(fd, 1, NULL);
@@ -851,6 +863,21 @@ static struct disk_info *get_disk_info(struct imsm_update_create_array *update)
        return inf;
 }
 
+/**
+ * __get_imsm_dev() - Get device with index from imsm_super.
+ * @mpb: &imsm_super pointer, not NULL.
+ * @index: Device index.
+ *
+ * Function works as non-NULL, aborting in such a case,
+ * when NULL would be returned.
+ *
+ * Device index should be in range 0 up to num_raid_devs.
+ * Function assumes the index was already verified.
+ * Index must be valid, otherwise abort() is called.
+ *
+ * Return: Pointer to corresponding imsm_dev.
+ *
+ */
 static struct imsm_dev *__get_imsm_dev(struct imsm_super *mpb, __u8 index)
 {
        int offset;
@@ -858,30 +885,47 @@ static struct imsm_dev *__get_imsm_dev(struct imsm_super *mpb, __u8 index)
        void *_mpb = mpb;
 
        if (index >= mpb->num_raid_devs)
-               return NULL;
+               goto error;
 
        /* devices start after all disks */
        offset = ((void *) &mpb->disk[mpb->num_disks]) - _mpb;
 
-       for (i = 0; i <= index; i++)
+       for (i = 0; i <= index; i++, offset += sizeof_imsm_dev(_mpb + offset, 0))
                if (i == index)
                        return _mpb + offset;
-               else
-                       offset += sizeof_imsm_dev(_mpb + offset, 0);
-
-       return NULL;
+error:
+       pr_err("cannot find imsm_dev with index %u in imsm_super\n", index);
+       abort();
 }
 
+/**
+ * get_imsm_dev() - Get device with index from intel_super.
+ * @super: &intel_super pointer, not NULL.
+ * @index: Device index.
+ *
+ * Function works as non-NULL, aborting in such a case,
+ * when NULL would be returned.
+ *
+ * Device index should be in range 0 up to num_raid_devs.
+ * Function assumes the index was already verified.
+ * Index must be valid, otherwise abort() is called.
+ *
+ * Return: Pointer to corresponding imsm_dev.
+ *
+ */
 static struct imsm_dev *get_imsm_dev(struct intel_super *super, __u8 index)
 {
        struct intel_dev *dv;
 
        if (index >= super->anchor->num_raid_devs)
-               return NULL;
+               goto error;
+
        for (dv = super->devlist; dv; dv = dv->next)
                if (dv->index == index)
                        return dv->dev;
-       return NULL;
+error:
+       pr_err("cannot find imsm_dev with index %u in intel_super\n", index);
+       abort();
 }
 
 static inline unsigned long long __le48_to_cpu(const struct bbm_log_block_addr
@@ -1151,7 +1195,7 @@ static void set_imsm_ord_tbl_ent(struct imsm_map *map, int slot, __u32 ord)
        map->disk_ord_tbl[slot] = __cpu_to_le32(ord);
 }
 
-static int get_imsm_disk_slot(struct imsm_map *map, unsigned idx)
+static int get_imsm_disk_slot(struct imsm_map *map, const unsigned int idx)
 {
        int slot;
        __u32 ord;
@@ -1162,7 +1206,7 @@ static int get_imsm_disk_slot(struct imsm_map *map, unsigned idx)
                        return slot;
        }
 
-       return -1;
+       return IMSM_STATUS_ERROR;
 }
 
 static int get_imsm_raid_level(struct imsm_map *map)
@@ -1177,6 +1221,23 @@ static int get_imsm_raid_level(struct imsm_map *map)
        return map->raid_level;
 }
 
+/**
+ * get_disk_slot_in_dev() - retrieve disk slot from &imsm_dev.
+ * @super: &intel_super pointer, not NULL.
+ * @dev_idx: imsm device index.
+ * @idx: disk index.
+ *
+ * Return: Slot on success, IMSM_STATUS_ERROR otherwise.
+ */
+static int get_disk_slot_in_dev(struct intel_super *super, const __u8 dev_idx,
+                               const unsigned int idx)
+{
+       struct imsm_dev *dev = get_imsm_dev(super, dev_idx);
+       struct imsm_map *map = get_imsm_map(dev, MAP_0);
+
+       return get_imsm_disk_slot(map, idx);
+}
+
 static int cmp_extent(const void *av, const void *bv)
 {
        const struct extent *a = av;
@@ -1193,13 +1254,9 @@ static int count_memberships(struct dl *dl, struct intel_super *super)
        int memberships = 0;
        int i;
 
-       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);
-
-               if (get_imsm_disk_slot(map, dl->index) >= 0)
+       for (i = 0; i < super->anchor->num_raid_devs; i++)
+               if (get_disk_slot_in_dev(super, i, dl->index) >= 0)
                        memberships++;
-       }
 
        return memberships;
 }
@@ -1228,6 +1285,33 @@ static unsigned long long total_blocks(struct imsm_disk *disk)
        return join_u32(disk->total_blocks_lo, disk->total_blocks_hi);
 }
 
+/**
+ * imsm_num_data_members() - get data drives count for an array.
+ * @map: Map to analyze.
+ *
+ * num_data_members value represents minimal count of drives for level.
+ * The name of the property could be misleading for RAID5 with asymmetric layout
+ * because some data required to be calculated from parity.
+ * The property is extracted from level and num_members value.
+ *
+ * Return: num_data_members value on success, zero otherwise.
+ */
+static __u8 imsm_num_data_members(struct imsm_map *map)
+{
+       switch (get_imsm_raid_level(map)) {
+       case 0:
+               return map->num_members;
+       case 1:
+       case 10:
+               return map->num_members / 2;
+       case 5:
+               return map->num_members - 1;
+       default:
+               dprintf("unsupported raid level\n");
+               return 0;
+       }
+}
+
 static unsigned long long pba_of_lba0(struct imsm_map *map)
 {
        if (map == NULL)
@@ -1301,6 +1385,24 @@ static void set_total_blocks(struct imsm_disk *disk, unsigned long long n)
        split_ull(n, &disk->total_blocks_lo, &disk->total_blocks_hi);
 }
 
+/**
+ * set_num_domains() - Set number of domains for an array.
+ * @map: Map to be updated.
+ *
+ * num_domains property represents copies count of each data drive, thus make
+ * it meaningful only for RAID1 and RAID10. IMSM supports two domains for
+ * raid1 and raid10.
+ */
+static void set_num_domains(struct imsm_map *map)
+{
+       int level = get_imsm_raid_level(map);
+
+       if (level == 1 || level == 10)
+               map->num_domains = 2;
+       else
+               map->num_domains = 1;
+}
+
 static void set_pba_of_lba0(struct imsm_map *map, unsigned long long n)
 {
        split_ull(n, &map->pba_of_lba0_lo, &map->pba_of_lba0_hi);
@@ -1316,6 +1418,24 @@ static void set_num_data_stripes(struct imsm_map *map, unsigned long long n)
        split_ull(n, &map->num_data_stripes_lo, &map->num_data_stripes_hi);
 }
 
+/**
+ * update_num_data_stripes() - Calculate and update num_data_stripes value.
+ * @map: map to be updated.
+ * @dev_size: size of volume.
+ *
+ * num_data_stripes value is addictionally divided by num_domains, therefore for
+ * levels where num_domains is not 1, nds is a part of real value.
+ */
+static void update_num_data_stripes(struct imsm_map *map,
+                                    unsigned long long dev_size)
+{
+       unsigned long long nds = dev_size / imsm_num_data_members(map);
+
+       nds /= map->num_domains;
+       nds /= map->blocks_per_strip;
+       set_num_data_stripes(map, nds);
+}
+
 static void set_vol_curr_migr_unit(struct imsm_dev *dev, unsigned long long n)
 {
        if (dev == NULL)
@@ -1595,7 +1715,7 @@ int get_spare_criteria_imsm(struct supertype *st, struct spare_criteria *c)
        return 0;
 }
 
-static int is_gen_migration(struct imsm_dev *dev);
+static bool is_gen_migration(struct imsm_dev *dev);
 
 #define IMSM_4K_DIV 8
 
@@ -1839,13 +1959,14 @@ void examine_migr_rec_imsm(struct intel_super *super)
                struct imsm_map *map;
                int slot = -1;
 
-               if (is_gen_migration(dev) == 0)
+               if (is_gen_migration(dev) == false)
                                continue;
 
                printf("\nMigration Record Information:");
 
                /* first map under migration */
                map = get_imsm_map(dev, MAP_0);
+
                if (map)
                        slot = get_imsm_disk_slot(map, super->disks->index);
                if (map == NULL || slot > 1 || slot < 0) {
@@ -2343,7 +2464,7 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b
                }
 
                fd = dev_open(ent->d_name, O_RDONLY);
-               if (fd < 0)
+               if (!is_fd_valid(fd))
                        printf("          Port%d : - disk info unavailable -\n", port);
                else {
                        fd2devname(fd, buf);
@@ -2392,7 +2513,7 @@ static int print_nvme_info(struct sys_dev *hba)
                        goto skip;
 
                fd = open_dev(ent->d_name);
-               if (fd < 0)
+               if (!is_fd_valid(fd))
                        goto skip;
 
                if (!diskfd_to_devpath(fd, 0, ns_path) ||
@@ -2418,8 +2539,7 @@ static int print_nvme_info(struct sys_dev *hba)
                        printf("()\n");
 
 skip:
-               if (fd > -1)
-                       close(fd);
+               close_fd(&fd);
        }
 
        closedir(dir);
@@ -2872,26 +2992,6 @@ static __u32 num_stripes_per_unit_rebuild(struct imsm_dev *dev)
                return num_stripes_per_unit_resync(dev);
 }
 
-static __u8 imsm_num_data_members(struct imsm_map *map)
-{
-       /* named 'imsm_' because raid0, raid1 and raid10
-        * counter-intuitively have the same number of data disks
-        */
-       switch (get_imsm_raid_level(map)) {
-       case 0:
-               return map->num_members;
-               break;
-       case 1:
-       case 10:
-               return map->num_members/2;
-       case 5:
-               return map->num_members - 1;
-       default:
-               dprintf("unsupported raid level\n");
-               return 0;
-       }
-}
-
 static unsigned long long calc_component_size(struct imsm_map *map,
                                              struct imsm_dev *dev)
 {
@@ -3128,10 +3228,11 @@ static int load_imsm_migr_rec(struct intel_super *super)
                if (slot > 1 || slot < 0)
                        continue;
 
-               if (dl->fd < 0) {
+               if (!is_fd_valid(dl->fd)) {
                        sprintf(nm, "%d:%d", dl->major, dl->minor);
                        fd = dev_open(nm, O_RDONLY);
-                       if (fd >= 0) {
+
+                       if (is_fd_valid(fd)) {
                                keep_fd = 0;
                                break;
                        }
@@ -3141,7 +3242,7 @@ static int load_imsm_migr_rec(struct intel_super *super)
                }
        }
 
-       if (fd < 0)
+       if (!is_fd_valid(fd))
                return retval;
        retval = read_imsm_migr_rec(fd, super);
        if (!keep_fd)
@@ -3418,6 +3519,12 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
        info->recovery_blocked = imsm_reshape_blocks_arrays_changes(st->sb);
 
        if (is_gen_migration(dev)) {
+               /*
+                * device prev_map should be added if it is in the middle
+                * of migration
+                */
+               assert(prev_map);
+
                info->reshape_active = 1;
                info->new_level = get_imsm_raid_level(map);
                info->new_layout = imsm_level_to_layout(info->new_level);
@@ -3786,8 +3893,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.
@@ -3823,7 +3930,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
@@ -3847,10 +3955,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)
@@ -4212,7 +4324,7 @@ static void end_migration(struct imsm_dev *dev, struct intel_super *super,
         *
         * FIXME add support for raid-level-migration
         */
-       if (map_state != map->map_state && (is_gen_migration(dev) == 0) &&
+       if (map_state != map->map_state && (is_gen_migration(dev) == false) &&
            prev->map_state != IMSM_T_STATE_UNINITIALIZED) {
                /* when final map state is other than expected
                 * merge maps (not for migration)
@@ -4315,8 +4427,7 @@ int check_mpb_migr_compatibility(struct intel_super *super)
        for (i = 0; i < super->anchor->num_raid_devs; i++) {
                struct imsm_dev *dev_iter = __get_imsm_dev(super->anchor, i);
 
-               if (dev_iter &&
-                   dev_iter->vol.migr_state == 1 &&
+               if (dev_iter->vol.migr_state == 1 &&
                    dev_iter->vol.migr_type == MIGR_GEN_MIGR) {
                        /* This device is migrating */
                        map0 = get_imsm_map(dev_iter, MAP_0);
@@ -4465,8 +4576,6 @@ static void clear_hi(struct intel_super *super)
        }
        for (i = 0; i < mpb->num_raid_devs; ++i) {
                struct imsm_dev *dev = get_imsm_dev(super, i);
-               if (!dev)
-                       return;
                for (n = 0; n < 2; ++n) {
                        struct imsm_map *map = get_imsm_map(dev, n);
                        if (!map)
@@ -4499,10 +4608,10 @@ load_and_parse_mpb(int fd, struct intel_super *super, char *devname, int keep_fd
        return err;
 }
 
-static void __free_imsm_disk(struct dl *d, int close_fd)
+static void __free_imsm_disk(struct dl *d, int do_close)
 {
-       if (close_fd && d->fd > -1)
-               close(d->fd);
+       if (do_close)
+               close_fd(&d->fd);
        if (d->devname)
                free(d->devname);
        if (d->e)
@@ -4607,12 +4716,12 @@ static int find_intel_hba_capability(int fd, struct intel_super *super, char *de
        struct sys_dev *hba_name;
        int rv = 0;
 
-       if (fd >= 0 && test_partition(fd)) {
+       if (is_fd_valid(fd) && test_partition(fd)) {
                pr_err("imsm: %s is a partition, cannot be used in IMSM\n",
                       devname);
                return 1;
        }
-       if (fd < 0 || check_env("IMSM_NO_PLATFORM")) {
+       if (!is_fd_valid(fd) || check_env("IMSM_NO_PLATFORM")) {
                super->orom = NULL;
                super->hba = NULL;
                return 0;
@@ -5021,7 +5130,7 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
        int err = 0;
        int i = 0;
 
-       if (fd >= 0)
+       if (is_fd_valid(fd))
                /* 'fd' is an opened container */
                err = get_sra_super_block(fd, &super_list, devname, &i, keep_fd);
        else
@@ -5078,7 +5187,7 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
                return err;
 
        *sbp = super;
-       if (fd >= 0)
+       if (is_fd_valid(fd))
                strcpy(st->container_devnm, fd2devnm(fd));
        else
                st->container_devnm[0] = 0;
@@ -5104,7 +5213,7 @@ get_devlist_super_block(struct md_list *devlist, struct intel_super **super_list
                if (tmpdev->container == 1) {
                        int lmax = 0;
                        int fd = dev_open(tmpdev->devname, O_RDONLY|O_EXCL);
-                       if (fd < 0) {
+                       if (!is_fd_valid(fd)) {
                                pr_err("cannot open device %s: %s\n",
                                        tmpdev->devname, strerror(errno));
                                err = 8;
@@ -5156,7 +5265,7 @@ static int get_super_block(struct intel_super **super_list, char *devnm, char *d
 
        sprintf(nm, "%d:%d", major, minor);
        dfd = dev_open(nm, O_RDWR);
-       if (dfd < 0) {
+       if (!is_fd_valid(dfd)) {
                err = 2;
                goto error;
        }
@@ -5171,7 +5280,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;
@@ -5183,11 +5292,10 @@ static int get_super_block(struct intel_super **super_list, char *devnm, char *d
        } else {
                if (s)
                        free_imsm(s);
-               if (dfd >= 0)
-                       close(dfd);
+               close_fd(&dfd);
        }
-       if (dfd >= 0 && !keep_fd)
-               close(dfd);
+       if (!keep_fd)
+               close_fd(&dfd);
        return err;
 
 }
@@ -5274,7 +5382,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;
@@ -5433,7 +5541,6 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
        int namelen;
        unsigned long long array_blocks;
        size_t size_old, size_new;
-       unsigned long long num_data_stripes;
        unsigned int data_disks;
        unsigned long long size_per_member;
 
@@ -5551,18 +5658,9 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
        }
 
        map->raid_level = info->level;
-       if (info->level == 10) {
+       if (info->level == 10)
                map->raid_level = 1;
-               map->num_domains = info->raid_disks / 2;
-       } else if (info->level == 1)
-               map->num_domains = info->raid_disks;
-       else
-               map->num_domains = 1;
-
-       /* info->size is only int so use the 'size' parameter instead */
-       num_data_stripes = size_per_member / info_to_blocks_per_strip(info);
-       num_data_stripes /= map->num_domains;
-       set_num_data_stripes(map, num_data_stripes);
+       set_num_domains(map);
 
        size_per_member += NUM_BLOCKS_DIRTY_STRIPE_REGION;
        set_blocks_per_member(map, info_to_blocks_per_member(info,
@@ -5570,6 +5668,7 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
                                                             BLOCKS_PER_KB));
 
        map->num_members = info->raid_disks;
+       update_num_data_stripes(map, array_blocks);
        for (i = 0; i < map->num_members; i++) {
                /* initialized in add_to_super */
                set_imsm_ord_tbl_ent(map, i, IMSM_ORD_REBUILD);
@@ -5586,7 +5685,7 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
                free(dev);
                free(dv);
                pr_err("imsm does not support consistency policy %s\n",
-                      map_num(consistency_policies, s->consistency_policy));
+                      map_num_s(consistency_policies, s->consistency_policy));
                return 0;
        }
 
@@ -5673,7 +5772,7 @@ static int drive_validate_sector_size(struct intel_super *super, struct dl *dl)
 {
        unsigned int member_sector_size;
 
-       if (dl->fd < 0) {
+       if (!is_fd_valid(dl->fd)) {
                pr_err("Invalid file descriptor for %s\n", dl->devname);
                return 0;
        }
@@ -5695,6 +5794,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);
@@ -5705,25 +5808,32 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
                return 1;
        }
 
-       if (fd == -1) {
-               /* 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))
@@ -5797,7 +5907,7 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
                struct imsm_dev *_dev = __get_imsm_dev(mpb, 0);
 
                _disk = __get_imsm_disk(mpb, dl->index);
-               if (!_dev || !_disk) {
+               if (!_disk) {
                        pr_err("BUG mpb setup error\n");
                        return 1;
                }
@@ -6081,10 +6191,8 @@ static int write_super_imsm_spares(struct intel_super *super, int doclose)
                if (write_super_imsm_spare(super, d))
                        return 1;
 
-               if (doclose) {
-                       close(d->fd);
-                       d->fd = -1;
-               }
+               if (doclose)
+                       close_fd(&d->fd);
        }
 
        return 0;
@@ -6134,10 +6242,10 @@ static int write_super_imsm(struct supertype *st, int doclose)
        for (i = 0; i < mpb->num_raid_devs; i++) {
                struct imsm_dev *dev = __get_imsm_dev(mpb, i);
                struct imsm_dev *dev2 = get_imsm_dev(super, i);
-               if (dev && dev2) {
-                       imsm_copy_dev(dev, dev2);
-                       mpb_size += sizeof_imsm_dev(dev, 0);
-               }
+
+               imsm_copy_dev(dev, dev2);
+               mpb_size += sizeof_imsm_dev(dev, 0);
+
                if (is_gen_migration(dev2))
                        clear_migration_record = 0;
        }
@@ -6198,10 +6306,8 @@ static int write_super_imsm(struct supertype *st, int doclose)
                                d->major, d->minor,
                                d->fd, strerror(errno));
 
-               if (doclose) {
-                       close(d->fd);
-                       d->fd = -1;
-               }
+               if (doclose)
+                       close_fd(&d->fd);
        }
 
        if (spares)
@@ -6432,7 +6538,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 {
@@ -6626,16 +6732,14 @@ 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;
 
        fd = dev_open(dev, O_RDONLY|O_EXCL);
-       if (fd < 0) {
-               if (verbose > 0)
-                       pr_err("imsm: Cannot open %s: %s\n",
-                               dev, strerror(errno));
+       if (!is_fd_valid(fd)) {
+               pr_vrb("imsm: Cannot open %s: %s\n", dev, strerror(errno));
                return 0;
        }
        if (!get_dev_size(fd, dev, &ldsize))
@@ -6844,12 +6948,12 @@ active_arrays_by_format(char *name, char* hba, struct md_list **devlist,
                    memb->members) {
                        struct dev_member *dev = memb->members;
                        int fd = -1;
-                       while(dev && (fd < 0)) {
+                       while (dev && !is_fd_valid(fd)) {
                                char *path = xmalloc(strlen(dev->name) + strlen("/dev/") + 1);
                                num = sprintf(path, "%s%s", "/dev/", dev->name);
                                if (num > 0)
                                        fd = open(path, O_RDONLY, 0);
-                               if (num <= 0 || fd < 0) {
+                               if (num <= 0 || !is_fd_valid(fd)) {
                                        pr_vrb("Cannot open %s: %s\n",
                                               dev->name, strerror(errno));
                                }
@@ -6857,7 +6961,7 @@ active_arrays_by_format(char *name, char* hba, struct md_list **devlist,
                                dev = dev->next;
                        }
                        found = 0;
-                       if (fd >= 0 && disk_attached_to_hba(fd, hba)) {
+                       if (is_fd_valid(fd) && disk_attached_to_hba(fd, hba)) {
                                struct mdstat_ent *vol;
                                for (vol = mdstat ; vol ; vol = vol->next) {
                                        if (vol->active > 0 &&
@@ -6877,8 +6981,7 @@ active_arrays_by_format(char *name, char* hba, struct md_list **devlist,
                                        *devlist = dv;
                                }
                        }
-                       if (fd >= 0)
-                               close(fd);
+                       close_fd(&fd);
                }
        }
        free_mdstat(mdstat);
@@ -6939,7 +7042,7 @@ get_devices(const char *hba_path)
                free(path);
                path = NULL;
                fd = dev_open(ent->d_name, O_RDONLY);
-               if (fd >= 0) {
+               if (is_fd_valid(fd)) {
                        fd2devname(fd, buf);
                        close(fd);
                } else {
@@ -6998,7 +7101,7 @@ count_volumes_list(struct md_list *devlist, char *homehost,
                }
                tmpdev->container = 0;
                dfd = dev_open(devname, O_RDONLY|O_EXCL);
-               if (dfd < 0) {
+               if (!is_fd_valid(dfd)) {
                        dprintf("cannot open device %s: %s\n",
                                devname, strerror(errno));
                        tmpdev->used = 2;
@@ -7035,8 +7138,8 @@ count_volumes_list(struct md_list *devlist, char *homehost,
                                tmpdev->used = 2;
                        }
                }
-               if (dfd >= 0)
-                       close(dfd);
+               close_fd(&dfd);
+
                if (tmpdev->used == 2 || tmpdev->used == 4) {
                        /* Ignore unrecognised devices during auto-assembly */
                        goto loop;
@@ -7435,11 +7538,27 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
        return 1;
 }
 
-static int imsm_get_free_size(struct supertype *st, int raiddisks,
-                        unsigned long long size, int chunk,
-                        unsigned long long *freesize)
+/**
+ * imsm_get_free_size() - get the biggest, common free space from members.
+ * @super: &intel_super pointer, not NULL.
+ * @raiddisks: number of raid disks.
+ * @size: requested size, could be 0 (means max size).
+ * @chunk: requested chunk.
+ * @freesize: pointer for returned size value.
+ *
+ * Return: &IMSM_STATUS_OK or &IMSM_STATUS_ERROR.
+ *
+ * @freesize is set to meaningful value, this can be @size, or calculated
+ * max free size.
+ * super->create_offset value is modified and set appropriately in
+ * merge_extends() for further creation.
+ */
+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)
 {
-       struct intel_super *super = st->sb;
        struct imsm_super *mpb = super->anchor;
        struct dl *dl;
        int i;
@@ -7483,12 +7602,10 @@ static int imsm_get_free_size(struct supertype *st, int raiddisks,
                /* chunk is in K */
                minsize = chunk * 2;
 
-       if (cnt < raiddisks ||
-           (super->orom && used && used != raiddisks) ||
-           maxsize < minsize ||
-           maxsize == 0) {
+       if (cnt < raiddisks || (super->orom && used && used != raiddisks) ||
+           maxsize < minsize || maxsize == 0) {
                pr_err("not enough devices with space to create array.\n");
-               return 0; /* No enough free spaces large enough */
+               return IMSM_STATUS_ERROR;
        }
 
        if (size == 0) {
@@ -7501,37 +7618,69 @@ static int imsm_get_free_size(struct supertype *st, int raiddisks,
        }
        if (mpb->num_raid_devs > 0 && size && size != maxsize)
                pr_err("attempting to create a second volume with size less then remaining space.\n");
-       cnt = 0;
-       for (dl = super->disks; dl; dl = dl->next)
-               if (dl->e)
-                       dl->raiddisk = cnt++;
-
        *freesize = size;
 
        dprintf("imsm: imsm_get_free_size() returns : %llu\n", size);
 
-       return 1;
+       return IMSM_STATUS_OK;
 }
 
-static int reserve_space(struct supertype *st, int raiddisks,
-                        unsigned long long size, int chunk,
-                        unsigned long long *freesize)
+/**
+ * autolayout_imsm() - automatically layout a new volume.
+ * @super: &intel_super pointer, not NULL.
+ * @raiddisks: number of raid disks.
+ * @size: requested size, could be 0 (means max size).
+ * @chunk: requested chunk.
+ * @freesize: pointer for returned size value.
+ *
+ * We are being asked to automatically layout a new volume based on the current
+ * contents of the container. If the parameters can be satisfied autolayout_imsm
+ * will record the disks, start offset, and will return size of the volume to
+ * be created. See imsm_get_free_size() for details.
+ * add_to_super() and getinfo_super() detect when autolayout is in progress.
+ * If first volume exists, slots are set consistently to it.
+ *
+ * Return: &IMSM_STATUS_OK on success, &IMSM_STATUS_ERROR otherwise.
+ *
+ * Disks are marked for creation via dl->raiddisk.
+ */
+static imsm_status_t autolayout_imsm(struct intel_super *super,
+                                    const int raiddisks,
+                                    unsigned long long size, const int chunk,
+                                    unsigned long long *freesize)
 {
-       struct intel_super *super = st->sb;
-       struct dl *dl;
-       int cnt;
-       int rv = 0;
+       int curr_slot = 0;
+       struct dl *disk;
+       int vol_cnt = super->anchor->num_raid_devs;
+       imsm_status_t rv;
 
-       rv = imsm_get_free_size(st, raiddisks, size, chunk, freesize);
-       if (rv) {
-               cnt = 0;
-               for (dl = super->disks; dl; dl = dl->next)
-                       if (dl->e)
-                               dl->raiddisk = cnt++;
-               rv = 1;
+       rv = imsm_get_free_size(super, raiddisks, size, chunk, freesize);
+       if (rv != IMSM_STATUS_OK)
+               return IMSM_STATUS_ERROR;
+
+       for (disk = super->disks; disk; disk = disk->next) {
+               if (!disk->e)
+                       continue;
+
+               if (curr_slot == raiddisks)
+                       break;
+
+               if (vol_cnt == 0) {
+                       disk->raiddisk = curr_slot;
+               } else {
+                       int _slot = get_disk_slot_in_dev(super, 0, disk->index);
+
+                       if (_slot == -1) {
+                               pr_err("Disk %s is not used in first volume, aborting\n",
+                                      disk->devname);
+                               return IMSM_STATUS_ERROR;
+                       }
+                       disk->raiddisk = _slot;
+               }
+               curr_slot++;
        }
 
-       return rv;
+       return IMSM_STATUS_OK;
 }
 
 static int validate_geometry_imsm(struct supertype *st, int level, int layout,
@@ -7548,7 +7697,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,
@@ -7567,35 +7716,35 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
        }
 
        if (!dev) {
-               if (st->sb) {
-                       struct intel_super *super = st->sb;
-                       if (!validate_geometry_imsm_orom(st->sb, level, layout,
-                                                        raiddisks, chunk, size,
-                                                        verbose))
+               struct intel_super *super = st->sb;
+
+               /*
+                * Autolayout mode, st->sb and freesize must be set.
+                */
+               if (!super || !freesize) {
+                       pr_vrb("freesize and superblock must be set for autolayout, aborting\n");
+                       return 1;
+               }
+
+               if (!validate_geometry_imsm_orom(st->sb, level, layout,
+                                                raiddisks, chunk, size,
+                                                verbose))
+                       return 0;
+
+               if (super->orom) {
+                       imsm_status_t rv;
+                       int count = count_volumes(super->hba, super->orom->dpa,
+                                             verbose);
+                       if (super->orom->vphba <= count) {
+                               pr_vrb("platform does not support more than %d raid volumes.\n",
+                                      super->orom->vphba);
                                return 0;
-                       /* we are being asked to automatically layout a
-                        * new volume based on the current contents of
-                        * the container.  If the the parameters can be
-                        * satisfied reserve_space will record the disks,
-                        * start offset, and size of the volume to be
-                        * created.  add_to_super and getinfo_super
-                        * detect when autolayout is in progress.
-                        */
-                       /* assuming that freesize is always given when array is
-                          created */
-                       if (super->orom && freesize) {
-                               int count;
-                               count = count_volumes(super->hba,
-                                                     super->orom->dpa, verbose);
-                               if (super->orom->vphba <= count) {
-                                       pr_vrb("platform does not support more than %d raid volumes.\n",
-                                              super->orom->vphba);
-                                       return 0;
-                               }
                        }
-                       if (freesize)
-                               return reserve_space(st, raiddisks, size,
-                                                    *chunk, freesize);
+
+                       rv = autolayout_imsm(super, raiddisks, size, *chunk,
+                                            freesize);
+                       if (rv != IMSM_STATUS_OK)
+                               return 0;
                }
                return 1;
        }
@@ -7609,26 +7758,26 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
 
        /* This device needs to be a device in an 'imsm' container */
        fd = open(dev, O_RDONLY|O_EXCL, 0);
-       if (fd >= 0) {
-               if (verbose)
-                       pr_err("Cannot create this array on device %s\n",
-                              dev);
+
+       if (is_fd_valid(fd)) {
+               pr_vrb("Cannot create this array on device %s\n", dev);
                close(fd);
                return 0;
        }
-       if (errno != EBUSY || (fd = open(dev, O_RDONLY, 0)) < 0) {
-               if (verbose)
-                       pr_err("Cannot open %s: %s\n",
-                               dev, strerror(errno));
+       if (errno == EBUSY)
+               fd = open(dev, O_RDONLY, 0);
+
+       if (!is_fd_valid(fd)) {
+               pr_vrb("Cannot open %s: %s\n", dev, strerror(errno));
                return 0;
        }
+
        /* Well, it is in use by someone, maybe an 'imsm' container. */
        cfd = open_container(fd);
-       close(fd);
-       if (cfd < 0) {
-               if (verbose)
-                       pr_err("Cannot use %s: It is busy\n",
-                               dev);
+       close_fd(&fd);
+
+       if (!is_fd_valid(cfd)) {
+               pr_vrb("Cannot use %s: It is busy\n", dev);
                return 0;
        }
        sra = sysfs_read(cfd, NULL, GET_VERSION);
@@ -7745,36 +7894,39 @@ 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))
                        return 2;
 
@@ -7804,7 +7956,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);
@@ -7836,18 +7988,13 @@ static int update_subarray_imsm(struct supertype *st, char *subarray,
        return 0;
 }
 
-static int is_gen_migration(struct imsm_dev *dev)
+static bool is_gen_migration(struct imsm_dev *dev)
 {
-       if (dev == NULL)
-               return 0;
-
-       if (!dev->vol.migr_state)
-               return 0;
-
-       if (migr_type(dev) == MIGR_GEN_MIGR)
-               return 1;
+       if (dev && dev->vol.migr_state &&
+           migr_type(dev) == MIGR_GEN_MIGR)
+               return true;
 
-       return 0;
+       return false;
 }
 
 static int is_rebuilding(struct imsm_dev *dev)
@@ -8047,10 +8194,6 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
                                if ((!able_to_resync(level, missing) ||
                                     recovery_start == 0))
                                        this->resync_start = MaxSector;
-                       } else {
-                               /*
-                                * FIXME handle dirty degraded
-                                */
                        }
 
                        if (skip)
@@ -8233,19 +8376,19 @@ static int imsm_count_failed(struct intel_super *super, struct imsm_dev *dev,
 }
 
 static int imsm_open_new(struct supertype *c, struct active_array *a,
-                        char *inst)
+                        int inst)
 {
        struct intel_super *super = c->sb;
        struct imsm_super *mpb = super->anchor;
        struct imsm_update_prealloc_bb_mem u;
 
-       if (atoi(inst) >= mpb->num_raid_devs) {
-               pr_err("subarry index %d, out of range\n", atoi(inst));
+       if (inst >= mpb->num_raid_devs) {
+               pr_err("subarry index %d, out of range\n", inst);
                return -ENODEV;
        }
 
-       dprintf("imsm: open_new %s\n", inst);
-       a->info.container_member = atoi(inst);
+       dprintf("imsm: open_new %d\n", inst);
+       a->info.container_member = inst;
 
        u.type = update_prealloc_badblocks_mem;
        imsm_update_metadata_locally(c, &u, sizeof(u));
@@ -8355,7 +8498,7 @@ static void handle_missing(struct intel_super *super, struct imsm_dev *dev)
        dprintf("imsm: mark missing\n");
        /* end process for initialization and rebuild only
         */
-       if (is_gen_migration(dev) == 0) {
+       if (is_gen_migration(dev) == false) {
                int failed = imsm_count_failed(super, dev, MAP_0);
 
                if (failed) {
@@ -8907,7 +9050,7 @@ static struct dl *imsm_add_spare(struct intel_super *super, int slot,
        for (dl = super->disks; dl; dl = dl->next) {
                /* If in this array, skip */
                for (d = a->info.devs ; d ; d = d->next)
-                       if (d->state_fd >= 0 &&
+                       if (is_fd_valid(d->state_fd) &&
                            d->disk.major == dl->major &&
                            d->disk.minor == dl->minor) {
                                dprintf("%x:%x already in array\n",
@@ -9010,29 +9153,26 @@ static int imsm_rebuild_allowed(struct supertype *cont, int dev_idx, int failed)
        __u8 state;
 
        dev2 = get_imsm_dev(cont->sb, dev_idx);
-       if (dev2) {
-               state = imsm_check_degraded(cont->sb, dev2, failed, MAP_0);
-               if (state == IMSM_T_STATE_FAILED) {
-                       map = get_imsm_map(dev2, MAP_0);
-                       if (!map)
-                               return 1;
-                       for (slot = 0; slot < map->num_members; slot++) {
-                               /*
-                                * Check if failed disks are deleted from intel
-                                * disk list or are marked to be deleted
-                                */
-                               idx = get_imsm_disk_idx(dev2, slot, MAP_X);
-                               idisk = get_imsm_dl_disk(cont->sb, idx);
-                               /*
-                                * Do not rebuild the array if failed disks
-                                * from failed sub-array are not removed from
-                                * container.
-                                */
-                               if (idisk &&
-                                   is_failed(&idisk->disk) &&
-                                   (idisk->action != DISK_REMOVE))
-                                       return 0;
-                       }
+
+       state = imsm_check_degraded(cont->sb, dev2, failed, MAP_0);
+       if (state == IMSM_T_STATE_FAILED) {
+               map = get_imsm_map(dev2, MAP_0);
+               for (slot = 0; slot < map->num_members; slot++) {
+                       /*
+                        * Check if failed disks are deleted from intel
+                        * disk list or are marked to be deleted
+                        */
+                       idx = get_imsm_disk_idx(dev2, slot, MAP_X);
+                       idisk = get_imsm_dl_disk(cont->sb, idx);
+                       /*
+                        * Do not rebuild the array if failed disks
+                        * from failed sub-array are not removed from
+                        * container.
+                        */
+                       if (idisk &&
+                           is_failed(&idisk->disk) &&
+                           (idisk->action != DISK_REMOVE))
+                               return 0;
                }
        }
        return 1;
@@ -9067,13 +9207,15 @@ static struct mdinfo *imsm_activate_spare(struct active_array *a,
        int i;
        int allowed;
 
-       for (d = a->info.devs ; d ; d = d->next) {
-               if ((d->curr_state & DS_FAULTY) &&
-                       d->state_fd >= 0)
+       for (d = a->info.devs ; d; d = d->next) {
+               if (!is_fd_valid(d->state_fd))
+                       continue;
+
+               if (d->curr_state & DS_FAULTY)
                        /* wait for Removal to happen */
                        return NULL;
-               if (d->state_fd >= 0)
-                       failed--;
+
+               failed--;
        }
 
        dprintf("imsm: activate spare: inst=%d failed=%d (%d) level=%d\n",
@@ -9129,7 +9271,7 @@ static struct mdinfo *imsm_activate_spare(struct active_array *a,
                        if (d->disk.raid_disk == i)
                                break;
                dprintf("found %d: %p %x\n", i, d, d?d->curr_state:0);
-               if (d && (d->state_fd >= 0))
+               if (d && is_fd_valid(d->state_fd))
                        continue;
 
                /*
@@ -9384,7 +9526,6 @@ static int apply_reshape_migration_update(struct imsm_update_reshape_migration *
                        /* update chunk size
                         */
                        if (u->new_chunksize > 0) {
-                               unsigned long long num_data_stripes;
                                struct imsm_map *dest_map =
                                        get_imsm_map(dev, MAP_0);
                                int used_disks =
@@ -9395,11 +9536,7 @@ static int apply_reshape_migration_update(struct imsm_update_reshape_migration *
 
                                map->blocks_per_strip =
                                        __cpu_to_le16(u->new_chunksize * 2);
-                               num_data_stripes =
-                                       imsm_dev_size(dev) / used_disks;
-                               num_data_stripes /= map->blocks_per_strip;
-                               num_data_stripes /= map->num_domains;
-                               set_num_data_stripes(map, num_data_stripes);
+                               update_num_data_stripes(map, imsm_dev_size(dev));
                        }
 
                        /* ensure blocks_per_member has valid value
@@ -9473,7 +9610,6 @@ static int apply_size_change_update(struct imsm_update_size_change *u,
                        struct imsm_map *map = get_imsm_map(dev, MAP_0);
                        int used_disks = imsm_num_data_members(map);
                        unsigned long long blocks_per_member;
-                       unsigned long long num_data_stripes;
                        unsigned long long new_size_per_disk;
 
                        if (used_disks == 0)
@@ -9484,16 +9620,10 @@ static int apply_size_change_update(struct imsm_update_size_change *u,
                        new_size_per_disk = u->new_size / used_disks;
                        blocks_per_member = new_size_per_disk +
                                            NUM_BLOCKS_DIRTY_STRIPE_REGION;
-                       num_data_stripes = new_size_per_disk /
-                                          map->blocks_per_strip;
-                       num_data_stripes /= map->num_domains;
-                       dprintf("(size: %llu, blocks per member: %llu, num_data_stipes: %llu)\n",
-                               u->new_size, new_size_per_disk,
-                               num_data_stripes);
-                       set_blocks_per_member(map, blocks_per_member);
-                       set_num_data_stripes(map, num_data_stripes);
-                       imsm_set_array_size(dev, u->new_size);
 
+                       imsm_set_array_size(dev, u->new_size);
+                       set_blocks_per_member(map, blocks_per_member);
+                       update_num_data_stripes(map, u->new_size);
                        ret_val = 1;
                        break;
                }
@@ -9616,10 +9746,9 @@ static int apply_update_activate_spare(struct imsm_update_activate_spare *u,
                /* count arrays using the victim in the metadata */
                found = 0;
                for (a = active_array; a ; a = a->next) {
-                       dev = get_imsm_dev(super, a->info.container_member);
-                       map = get_imsm_map(dev, MAP_0);
+                       int dev_idx = a->info.container_member;
 
-                       if (get_imsm_disk_slot(map, victim) >= 0)
+                       if (get_disk_slot_in_dev(super, dev_idx, victim) >= 0)
                                found++;
                }
 
@@ -9775,8 +9904,6 @@ static int apply_takeover_update(struct imsm_update_takeover *u,
        map = get_imsm_map(dev, MAP_0);
 
        if (u->direction == R10_TO_R0) {
-               unsigned long long num_data_stripes;
-
                /* Number of failed disks must be half of initial disk number */
                if (imsm_count_failed(super, dev, MAP_0) !=
                                (map->num_members / 2))
@@ -9797,19 +9924,16 @@ static int apply_takeover_update(struct imsm_update_takeover *u,
                        }
                }
                /* update map */
-               map->num_members = map->num_members / 2;
+               map->num_members /= map->num_domains;
                map->map_state = IMSM_T_STATE_NORMAL;
-               map->num_domains = 1;
                map->raid_level = 0;
+               set_num_domains(map);
+               update_num_data_stripes(map, imsm_dev_size(dev));
                map->failed_disk_num = -1;
-               num_data_stripes = imsm_dev_size(dev) / 2;
-               num_data_stripes /= map->blocks_per_strip;
-               set_num_data_stripes(map, num_data_stripes);
        }
 
        if (u->direction == R0_TO_R10) {
                void **space;
-               unsigned long long num_data_stripes;
 
                /* update slots in current disk list */
                for (dm = super->disks; dm; dm = dm->next) {
@@ -9844,14 +9968,12 @@ static int apply_takeover_update(struct imsm_update_takeover *u,
                memcpy(dev_new, dev, sizeof(*dev));
                /* update new map */
                map = get_imsm_map(dev_new, MAP_0);
-               map->num_members = map->num_members * 2;
+
                map->map_state = IMSM_T_STATE_DEGRADED;
-               map->num_domains = 2;
                map->raid_level = 1;
-               num_data_stripes = imsm_dev_size(dev) / 2;
-               num_data_stripes /= map->blocks_per_strip;
-               num_data_stripes /= map->num_domains;
-               set_num_data_stripes(map, num_data_stripes);
+               set_num_domains(map);
+               map->num_members = map->num_members * map->num_domains;
+               update_num_data_stripes(map, imsm_dev_size(dev));
 
                /* replace dev<->dev_new */
                dv->dev = dev_new;
@@ -10083,7 +10205,6 @@ static void imsm_process_update(struct supertype *st,
                int victim = u->dev_idx;
                struct active_array *a;
                struct intel_dev **dp;
-               struct imsm_dev *dev;
 
                /* sanity check that we are not affecting the uuid of
                 * active arrays, or deleting an active array
@@ -10099,8 +10220,7 @@ static void imsm_process_update(struct supertype *st,
                 * is active in the container, so checking
                 * mpb->num_raid_devs is just extra paranoia
                 */
-               dev = get_imsm_dev(super, victim);
-               if (a || !dev || mpb->num_raid_devs == 1) {
+               if (a || mpb->num_raid_devs == 1 || victim >= super->anchor->num_raid_devs) {
                        dprintf("failed to delete subarray-%d\n", victim);
                        break;
                }
@@ -10134,7 +10254,7 @@ 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 || !dev || !check_name(super, name, 1)) {
+               if (a || !check_name(super, name, 1)) {
                        dprintf("failed to rename subarray-%d\n", target);
                        break;
                }
@@ -10163,10 +10283,6 @@ static void imsm_process_update(struct supertype *st,
                struct imsm_update_rwh_policy *u = (void *)update->buf;
                int target = u->dev_idx;
                struct imsm_dev *dev = get_imsm_dev(super, target);
-               if (!dev) {
-                       dprintf("could not find subarray-%d\n", target);
-                       break;
-               }
 
                if (dev->rwh_policy != u->new_policy) {
                        dev->rwh_policy = u->new_policy;
@@ -10882,26 +10998,22 @@ int save_backup_imsm(struct supertype *st,
 {
        int rv = -1;
        struct intel_super *super = st->sb;
-       unsigned long long *target_offsets;
-       int *targets;
        int i;
        struct imsm_map *map_dest = get_imsm_map(dev, MAP_0);
        int new_disks = map_dest->num_members;
        int dest_layout = 0;
-       int dest_chunk;
-       unsigned long long start;
+       int dest_chunk, targets[new_disks];
+       unsigned long long start, target_offsets[new_disks];
        int data_disks = imsm_num_data_members(map_dest);
 
-       targets = xmalloc(new_disks * sizeof(int));
-
        for (i = 0; i < new_disks; i++) {
                struct dl *dl_disk = get_imsm_dl_disk(super, i);
-
-               targets[i] = dl_disk->fd;
+               if (dl_disk && is_fd_valid(dl_disk->fd))
+                       targets[i] = dl_disk->fd;
+               else
+                       goto abort;
        }
 
-       target_offsets = xcalloc(new_disks, sizeof(unsigned long long));
-
        start = info->reshape_progress * 512;
        for (i = 0; i < new_disks; i++) {
                target_offsets[i] = migr_chkp_area_pba(super->migr_rec) * 512;
@@ -10933,11 +11045,6 @@ int save_backup_imsm(struct supertype *st,
        rv = 0;
 
 abort:
-       if (targets) {
-               free(targets);
-       }
-       free(target_offsets);
-
        return rv;
 }
 
@@ -11057,7 +11164,7 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info)
                if (dl_disk->index < 0)
                        continue;
 
-               if (dl_disk->fd < 0) {
+               if (!is_fd_valid(dl_disk->fd)) {
                        skipped_disks++;
                        continue;
                }
@@ -11400,8 +11507,10 @@ static int imsm_create_metadata_update_for_migration(
 {
        struct intel_super *super = st->sb;
        int update_memory_size;
+       int current_chunk_size;
        struct imsm_update_reshape_migration *u;
-       struct imsm_dev *dev;
+       struct imsm_dev *dev = get_imsm_dev(super, super->current_vol);
+       struct imsm_map *map = get_imsm_map(dev, MAP_0);
        int previous_level = -1;
 
        dprintf("(enter) New Level = %i\n", geo->level);
@@ -11418,23 +11527,15 @@ static int imsm_create_metadata_update_for_migration(
        u->new_disks[0] = -1;
        u->new_chunksize = -1;
 
-       dev = get_imsm_dev(super, u->subdev);
-       if (dev) {
-               struct imsm_map *map;
+       current_chunk_size = __le16_to_cpu(map->blocks_per_strip) / 2;
 
-               map = get_imsm_map(dev, MAP_0);
-               if (map) {
-                       int current_chunk_size =
-                               __le16_to_cpu(map->blocks_per_strip) / 2;
-
-                       if (geo->chunksize != current_chunk_size) {
-                               u->new_chunksize = geo->chunksize / 1024;
-                               dprintf("imsm: chunk size change from %i to %i\n",
-                                       current_chunk_size, u->new_chunksize);
-                       }
-                       previous_level = map->raid_level;
-               }
+       if (geo->chunksize != current_chunk_size) {
+               u->new_chunksize = geo->chunksize / 1024;
+               dprintf("imsm: chunk size change from %i to %i\n",
+                       current_chunk_size, u->new_chunksize);
        }
+       previous_level = map->raid_level;
+
        if (geo->level == 5 && previous_level == 0) {
                struct mdinfo *spares = NULL;
 
@@ -11502,7 +11603,7 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
        unsigned long long current_size;
        unsigned long long free_size;
        unsigned long long max_size;
-       int rv;
+       imsm_status_t rv;
 
        getinfo_super_imsm_volume(st, &info, NULL);
        if (geo->level != info.array.level && geo->level >= 0 &&
@@ -11621,9 +11722,10 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
                }
                /* check the maximum available size
                 */
-               rv =  imsm_get_free_size(st, dev->vol.map->num_members,
-                                        0, chunk, &free_size);
-               if (rv == 0)
+               rv = imsm_get_free_size(super, dev->vol.map->num_members,
+                                       0, chunk, &free_size);
+
+               if (rv != IMSM_STATUS_OK)
                        /* Cannot find maximum available space
                         */
                        max_size = 0;
@@ -11686,8 +11788,8 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
                struct imsm_super *mpb = super->anchor;
 
                if (mpb->num_raid_devs > 1) {
-                       pr_err("Error. Cannot perform operation on %s- for this operation it MUST be single array in container\n",
-                              geo->dev_name);
+                       pr_err("Error. Cannot perform operation on %s- for this operation "
+                              "it MUST be single array in container\n", geo->dev_name);
                        change = -1;
                }
        }
@@ -11760,7 +11862,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
@@ -11775,10 +11877,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);
@@ -11786,6 +11884,7 @@ static int imsm_fix_size_mismatch(struct supertype *st, int subarray_index)
                        st->update_tail = &st->updates;
                } else {
                        imsm_sync_metadata(st);
+                       free(update);
                }
        }
        ret_val = 0;
@@ -11981,7 +12080,7 @@ int wait_for_reshape_imsm(struct mdinfo *sra, int ndata)
        unsigned long long to_complete = sra->reshape_progress;
        unsigned long long position_to_set = to_complete / ndata;
 
-       if (fd < 0) {
+       if (!is_fd_valid(fd)) {
                dprintf("cannot open reshape_position\n");
                return 1;
        }
@@ -11993,7 +12092,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--);
@@ -12068,6 +12167,7 @@ int check_degradation_change(struct mdinfo *info,
                                continue;
                        if (sd->disk.state & (1<<MD_DISK_SYNC)) {
                                char sbuf[100];
+                               int raid_disk = sd->disk.raid_disk;
 
                                if (sysfs_get_str(info,
                                        sd, "state", sbuf, sizeof(sbuf)) < 0 ||
@@ -12075,13 +12175,8 @@ int check_degradation_change(struct mdinfo *info,
                                        strstr(sbuf, "in_sync") == NULL) {
                                        /* this device is dead */
                                        sd->disk.state = (1<<MD_DISK_FAULTY);
-                                       if (sd->disk.raid_disk >= 0 &&
-                                           sources[sd->disk.raid_disk] >= 0) {
-                                               close(sources[
-                                                       sd->disk.raid_disk]);
-                                               sources[sd->disk.raid_disk] =
-                                                       -1;
-                                       }
+                                       if (raid_disk >= 0)
+                                               close_fd(&sources[raid_disk]);
                                        new_degraded++;
                                }
                        }
@@ -12472,9 +12567,10 @@ static int validate_internal_bitmap_for_drive(struct supertype *st,
                return -1;
 
        fd = d->fd;
-       if (fd < 0) {
+       if (!is_fd_valid(fd)) {
                fd = open(d->devname, O_RDONLY, 0);
-               if (fd < 0) {
+
+               if (!is_fd_valid(fd)) {
                        dprintf("cannot open the device %s\n", d->devname);
                        goto abort;
                }
@@ -12498,8 +12594,9 @@ static int validate_internal_bitmap_for_drive(struct supertype *st,
 
        ret = 0;
 abort:
-       if ((d->fd < 0) && (fd >= 0))
-               close(fd);
+       if (!is_fd_valid(d->fd))
+               close_fd(&fd);
+
        if (read_buf)
                free(read_buf);
 
@@ -12523,9 +12620,6 @@ static int validate_internal_bitmap_imsm(struct supertype *st)
        unsigned long long offset;
        struct dl *d;
 
-       if (!dev)
-               return -1;
-
        if (dev->rwh_policy != RWH_BITMAP)
                return 0;
 
@@ -12571,16 +12665,8 @@ static int add_internal_bitmap_imsm(struct supertype *st, int *chunkp,
                return -1;
 
        dev = get_imsm_dev(super, vol_idx);
-
-       if (!dev) {
-               dprintf("cannot find the device for volume index %d\n",
-                       vol_idx);
-               return -1;
-       }
        dev->rwh_policy = RWH_BITMAP;
-
        *chunkp = calculate_bitmap_chunksize(st, dev);
-
        return 0;
 }