]> 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 cd1f1e3d85f405d2e824e4942fa1f0c08874dc77..1f5f6eda6d22d22503214ce118e33ed0035d13e8 100644 (file)
@@ -3893,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.
@@ -3930,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
@@ -3954,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)
@@ -5275,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;
@@ -5377,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;
@@ -5789,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);
@@ -5799,25 +5808,32 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
                return 1;
        }
 
-       if (!is_fd_valid(fd)) {
-               /* we're doing autolayout so grab the pre-marked (in
-                * validate_geometry) raid_disk
-                */
-               for (dl = super->disks; dl; dl = dl->next)
+       for (dl = super->disks; dl ; dl = dl->next) {
+               if (autolayout) {
                        if (dl->raiddisk == dk->raid_disk)
                                break;
-       } else {
-               for (dl = super->disks; dl ; dl = dl->next)
-                       if (dl->major == dk->major &&
-                           dl->minor == dk->minor)
-                               break;
+               } else if (dl->major == dk->major && dl->minor == dk->minor)
+                       break;
        }
 
        if (!dl) {
-               pr_err("%s is not a member of the same container\n", devname);
+               if (!autolayout)
+                       pr_err("%s is not a member of the same container.\n",
+                              devname);
                return 1;
        }
 
+       if (!autolayout && super->current_vol > 0) {
+               int _slot = get_disk_slot_in_dev(super, 0, dl->index);
+
+               if (_slot != dk->raid_disk) {
+                       pr_err("Member %s is in %d slot for the first volume, but is in %d slot for a new volume.\n",
+                              dl->devname, _slot, dk->raid_disk);
+                       pr_err("Raid members are in different order than for the first volume, aborting.\n");
+                       return 1;
+               }
+       }
+
        if (mpb->num_disks == 0)
                if (!get_dev_sector_size(dl->fd, dl->devname,
                                         &super->sector_size))
@@ -6522,7 +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 {
@@ -6716,7 +6732,7 @@ static int validate_geometry_imsm_container(struct supertype *st, int level,
        struct intel_super *super = NULL;
        int rv = 0;
 
-       if (level != LEVEL_CONTAINER)
+       if (!is_container(level))
                return 0;
        if (!dev)
                return 1;
@@ -7522,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;
@@ -7570,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) {
@@ -7588,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,
@@ -7635,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,
@@ -7654,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;
        }
@@ -7832,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;
 
@@ -7891,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);
@@ -11538,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 &&
@@ -11657,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;
@@ -11796,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
@@ -11811,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);
@@ -12030,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--);