]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - super-intel.c
imsm: load_super_imsm_all function refactoring
[thirdparty/mdadm.git] / super-intel.c
index 3a34f5a7687d6e598c1207dfb0e0ddddde590260..733d089b7b97827039091f7c62536419d11850d7 100644 (file)
@@ -2791,25 +2791,30 @@ static int update_super_imsm(struct supertype *st, struct mdinfo *info,
 
        mpb = super->anchor;
 
-       if (strcmp(update, "uuid") == 0 && uuid_set && !info->update_private)
-               rv = -1;
-       else if (strcmp(update, "uuid") == 0 && uuid_set && info->update_private) {
-               mpb->orig_family_num = *((__u32 *) info->update_private);
-               rv = 0;
-       } else if (strcmp(update, "uuid") == 0) {
-               __u32 *new_family = malloc(sizeof(*new_family));
-
-               /* update orig_family_number with the incoming random
-                * data, report the new effective uuid, and store the
-                * new orig_family_num for future updates.
+       if (strcmp(update, "uuid") == 0) {
+               /* 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
+                * know if one was.
+                * So if !uuid_set we know the current uuid is random and just used
+                * the first 'int' and copy it to the other 3 positions.
+                * Otherwise we require the 4 'int's to be the same as would be the
+                * case if we are using a random uuid.  So an explicit uuid will be
+                * accepted as long as all for ints are the same... which shouldn't hurt
                 */
-               if (new_family) {
-                       memcpy(&mpb->orig_family_num, info->uuid, sizeof(__u32));
-                       uuid_from_super_imsm(st, info->uuid);
-                       *new_family = mpb->orig_family_num;
-                       info->update_private = new_family;
+               if (!uuid_set) {
+                       info->uuid[1] = info->uuid[2] = info->uuid[3] = info->uuid[0];
                        rv = 0;
+               } else {
+                       if (info->uuid[0] != info->uuid[1] ||
+                           info->uuid[1] != info->uuid[2] ||
+                           info->uuid[2] != info->uuid[3])
+                               rv = -1;
+                       else
+                               rv = 0;
                }
+               if (rv == 0)
+                       mpb->orig_family_num = info->uuid[0];
        } else if (strcmp(update, "assemble") == 0)
                rv = 0;
        else
@@ -2980,7 +2985,7 @@ static void fd2devname(int fd, char *name)
        rv = readlink(path, dname, sizeof(dname)-1);
        if (rv <= 0)
                return;
-       
+
        dname[rv] = '\0';
        nm = strrchr(dname, '/');
        if (nm) {
@@ -4004,67 +4009,28 @@ imsm_thunderdome(struct intel_super **super_list, int len)
        return champion;
 }
 
+
+static int
+get_sra_super_block(int fd, struct intel_super **super_list, char *devname, int *max, int keep_fd);
+
+static int get_super_block(struct intel_super **super_list, int devnum, char *devname,
+                          int major, int minor, int keep_fd);
+
 static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
-                              char *devname)
+                              char *devname, int keep_fd)
 {
-       struct mdinfo *sra;
        struct intel_super *super_list = NULL;
        struct intel_super *super = NULL;
-       int devnum = fd2devnum(fd);
-       struct mdinfo *sd;
-       int retry;
        int err = 0;
-       int i;
+       int i = 0;
 
-       /* check if 'fd' an opened container */
-       sra = sysfs_read(fd, 0, GET_LEVEL|GET_VERSION|GET_DEVS|GET_STATE);
-       if (!sra)
+       if (fd >= 0)
+               /* 'fd' is an opened container */
+               err = get_sra_super_block(fd, &super_list, devname, &i, keep_fd);
+       else
                return 1;
-
-       if (sra->array.major_version != -1 ||
-           sra->array.minor_version != -2 ||
-           strcmp(sra->text_version, "imsm") != 0) {
-               err = 1;
+       if (err)
                goto error;
-       }
-       /* load all mpbs */
-       for (sd = sra->devs, i = 0; sd; sd = sd->next, i++) {
-               struct intel_super *s = alloc_super();
-               char nm[32];
-               int dfd;
-               int rv;
-
-               err = 1;
-               if (!s)
-                       goto error;
-               s->next = super_list;
-               super_list = s;
-
-               err = 2;
-               sprintf(nm, "%d:%d", sd->disk.major, sd->disk.minor);
-               dfd = dev_open(nm, O_RDWR);
-               if (dfd < 0)
-                       goto error;
-
-               rv = find_intel_hba_capability(dfd, s, devname);
-               /* no orom/efi or non-intel hba of the disk */
-               if (rv != 0)
-                       goto error;
-
-               err = load_and_parse_mpb(dfd, s, NULL, 1);
-
-               /* retry the load if we might have raced against mdmon */
-               if (err == 3 && mdmon_running(devnum))
-                       for (retry = 0; retry < 3; retry++) {
-                               usleep(3000);
-                               err = load_and_parse_mpb(dfd, s, NULL, 1);
-                               if (err != 3)
-                                       break;
-                       }
-               if (err)
-                       goto error;
-       }
-
        /* all mpbs enter, maybe one leaves */
        super = imsm_thunderdome(&super_list, i);
        if (!super) {
@@ -4109,13 +4075,16 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
                super_list = super_list->next;
                free_imsm(s);
        }
-       sysfs_free(sra);
+
 
        if (err)
                return err;
 
        *sbp = super;
-       st->container_dev = devnum;
+       if (fd >= 0)
+               st->container_dev = fd2devnum(fd);
+       else
+               st->container_dev = NoMdDev;
        if (err == 0 && st->ss == NULL) {
                st->ss = &super_imsm;
                st->minor_version = 0;
@@ -4124,9 +4093,101 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
        return 0;
 }
 
+
+
+
+static int get_super_block(struct intel_super **super_list, int devnum, char *devname,
+                          int major, int minor, int keep_fd)
+{
+       struct intel_super*s = NULL;
+       char nm[32];
+       int dfd = -1;
+       int rv;
+       int err = 0;
+       int retry;
+
+       s = alloc_super();
+       if (!s) {
+               err = 1;
+               goto error;
+       }
+
+       sprintf(nm, "%d:%d", major, minor);
+       dfd = dev_open(nm, O_RDWR);
+       if (dfd < 0) {
+               err = 2;
+               goto error;
+       }
+
+       rv = find_intel_hba_capability(dfd, s, devname);
+       /* no orom/efi or non-intel hba of the disk */
+       if (rv != 0) {
+               err = 4;
+               goto error;
+       }
+
+       err = load_and_parse_mpb(dfd, s, NULL, keep_fd);
+
+       /* retry the load if we might have raced against mdmon */
+       if (err == 3 && (devnum != -1) && mdmon_running(devnum))
+               for (retry = 0; retry < 3; retry++) {
+                       usleep(3000);
+                       err = load_and_parse_mpb(dfd, s, NULL, keep_fd);
+                       if (err != 3)
+                               break;
+               }
+ error:
+       if (!err) {
+               s->next = *super_list;
+               *super_list = s;
+       } else {
+               if (s)
+                       free(s);
+               if (dfd)
+                       close(dfd);
+       }
+       if ((dfd >= 0) && (!keep_fd))
+               close(dfd);
+       return err;
+
+}
+
+static int
+get_sra_super_block(int fd, struct intel_super **super_list, char *devname, int *max, int keep_fd)
+{
+       struct mdinfo *sra;
+       int devnum;
+       struct mdinfo *sd;
+       int err = 0;
+       int i = 0;
+       sra = sysfs_read(fd, 0, GET_LEVEL|GET_VERSION|GET_DEVS|GET_STATE);
+       if (!sra)
+               return 1;
+
+       if (sra->array.major_version != -1 ||
+           sra->array.minor_version != -2 ||
+           strcmp(sra->text_version, "imsm") != 0) {
+               err = 1;
+               goto error;
+       }
+       /* load all mpbs */
+       devnum = fd2devnum(fd);
+       for (sd = sra->devs, i = 0; sd; sd = sd->next, i++) {
+               if (get_super_block(super_list, devnum, devname,
+                                   sd->disk.major, sd->disk.minor, keep_fd) != 0) {
+                       err = 7;
+                       goto error;
+               }
+       }
+ error:
+       sysfs_free(sra);
+       *max = i;
+       return err;
+}
+
 static int load_container_imsm(struct supertype *st, int fd, char *devname)
 {
-       return load_super_imsm_all(st, fd, &st->sb, devname);
+       return load_super_imsm_all(st, fd, &st->sb, devname, 1);
 }
 #endif
 
@@ -5309,12 +5370,6 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
 
        mpb = super->anchor;
 
-       if (mpb->num_raid_devs > 0 && mpb->num_disks != raiddisks) {
-               fprintf(stderr, Name ": the option-rom requires all "
-                       "member disks to be a member of all volumes.\n");
-               return 0;
-       }
-
        if (!validate_geometry_imsm_orom(super, level, layout, raiddisks, chunk, verbose)) {
                fprintf(stderr, Name ": RAID gemetry validation failed. "
                        "Cannot proceed with the action(s).\n");
@@ -5393,6 +5448,11 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
                fprintf(stderr, Name ": The option-rom requires all member"
                        " disks to be a member of all volumes\n");
                return 0;
+       } else if (super->orom && mpb->num_raid_devs > 0 &&
+                  mpb->num_disks != raiddisks) {
+               fprintf(stderr, Name ": The option-rom requires all member"
+                       " disks to be a member of all volumes\n");
+               return 0;
        }
 
        /* retrieve the largest free space block */
@@ -5441,9 +5501,16 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
        }
 
        if (maxsize < size || maxsize == 0) {
-               if (verbose)
-                       fprintf(stderr, Name ": not enough space after merge (%llu < %llu)\n",
-                               maxsize, size);
+               if (verbose) {
+                       if (maxsize == 0)
+                               fprintf(stderr, Name ": no free space"
+                                               " left on device. Aborting...\n");
+                       else
+                               fprintf(stderr, Name ": not enough space"
+                                               " to create volume of given size"
+                                               " (%llu < %llu). Aborting...\n",
+                                               maxsize, size);
+               }
                return 0;
        }
 
@@ -5547,7 +5614,7 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
                                                        dev, freesize,
                                                        verbose);
        }
-       
+
        if (!dev) {
                if (st->sb) {
                        if (!validate_geometry_imsm_orom(st->sb, level, layout,
@@ -5611,7 +5678,7 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
                 */
                struct intel_super *super;
 
-               if (load_super_imsm_all(st, cfd, (void **) &super, NULL) == 0) {
+               if (load_super_imsm_all(st, cfd, (void **) &super, NULL, 1) == 0) {
                        st->sb = super;
                        st->container_dev = fd2devnum(cfd);
                        close(cfd);
@@ -6187,7 +6254,7 @@ static int imsm_open_new(struct supertype *c, struct active_array *a,
 {
        struct intel_super *super = c->sb;
        struct imsm_super *mpb = super->anchor;
-       
+
        if (atoi(inst) >= mpb->num_raid_devs) {
                fprintf(stderr, "%s: subarry index %d, out of range\n",
                        __func__, atoi(inst));
@@ -9050,8 +9117,10 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
        int change = -1;
        int check_devs = 0;
        int chunk;
-       int devNumChange=0;
-       int layout = -1;
+       /* number of added/removed disks in operation result */
+       int devNumChange = 0;
+       /* imsm compatible layout value for array geometry verification */
+       int imsm_layout = -1;
 
        getinfo_super_imsm_volume(st, &info, NULL);
        if ((geo->level != info.array.level) &&
@@ -9069,14 +9138,14 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
                                        change = -1;
                                        goto analyse_change_exit;
                                }
-                               layout =  geo->layout;
+                               imsm_layout =  geo->layout;
                                check_devs = 1;
                                devNumChange = 1; /* parity disk added */
                        } else if (geo->level == 10) {
                                change = CH_TAKEOVER;
                                check_devs = 1;
                                devNumChange = 2; /* two mirrors added */
-                               layout = 0x102; /* imsm supported layout */
+                               imsm_layout = 0x102; /* imsm supported layout */
                        }
                        break;
                case 1:
@@ -9085,7 +9154,7 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
                                change = CH_TAKEOVER;
                                check_devs = 1;
                                devNumChange = -(geo->raid_disks/2);
-                               layout = 0; /* imsm raid0 layout */
+                               imsm_layout = 0; /* imsm raid0 layout */
                        }
                        break;
                }
@@ -9120,8 +9189,11 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
                        change = -1;
                        goto analyse_change_exit;
                }
-       } else
+       } else {
                geo->layout = info.array.layout;
+               if (imsm_layout == -1)
+                       imsm_layout = info.array.layout;
+       }
 
        if ((geo->chunksize > 0) && (geo->chunksize != UnSet)
            && (geo->chunksize != info.array.chunk_size))
@@ -9132,7 +9204,7 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
        chunk = geo->chunksize / 1024;
        if (!validate_geometry_imsm(st,
                                    geo->level,
-                                   layout,
+                                   imsm_layout,
                                    geo->raid_disks + devNumChange,
                                    &chunk,
                                    geo->size,