]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - super-intel.c
Fix required to enable RAID arrays on SAS disks.
[thirdparty/mdadm.git] / super-intel.c
index 0e3ed89416a85157e022555647c7c0953f0d8725..325630f0927991b186726f24caab6b64ed327129 100644 (file)
@@ -318,6 +318,8 @@ static struct supertype *match_metadata_desc_imsm(char *arg)
                return NULL;
 
        st = malloc(sizeof(*st));
+       if (!st)
+               return NULL;
        memset(st, 0, sizeof(*st));
        st->ss = &super_imsm;
        st->max_devs = IMSM_MAX_DEVICES;
@@ -619,7 +621,6 @@ static __u32 imsm_reserved_sectors(struct intel_super *super, struct dl *dl)
        return rv;
 }
 
-#ifndef MDASSEMBLE
 static int is_spare(struct imsm_disk *disk)
 {
        return (disk->status & SPARE_DISK) == SPARE_DISK;
@@ -635,6 +636,7 @@ static int is_failed(struct imsm_disk *disk)
        return (disk->status & FAILED_DISK) == FAILED_DISK;
 }
 
+#ifndef MDASSEMBLE
 static void print_imsm_dev(struct imsm_dev *dev, char *uuid, int disk_idx)
 {
        __u64 sz;
@@ -701,7 +703,7 @@ static void print_imsm_disk(struct imsm_super *mpb, int index, __u32 reserved)
        char str[MAX_RAID_SERIAL_LEN + 1];
        __u64 sz;
 
-       if (index < 0)
+       if (index < 0 || !disk)
                return;
 
        printf("\n");
@@ -959,6 +961,12 @@ static int imsm_enumerate_ports(const char *hba_path, int port_count, int host_b
 
                /* chop device path to 'host%d' and calculate the port number */
                c = strchr(&path[hba_len], '/');
+               if (!c) {
+                       if (verbose)
+                               fprintf(stderr, Name ": %s - invalid path name\n", path + hba_len);
+                       err = 2;
+                       break;
+               }
                *c = '\0';
                if (sscanf(&path[hba_len], "host%d", &port) == 1)
                        port -= host_base;
@@ -1236,6 +1244,7 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info)
        struct imsm_dev *dev = get_imsm_dev(super, super->current_vol);
        struct imsm_map *map = get_imsm_map(dev, 0);
        struct dl *dl;
+       char *devname;
 
        for (dl = super->disks; dl; dl = dl->next)
                if (dl->raiddisk == info->disk.raid_disk)
@@ -1277,9 +1286,11 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info)
 
        info->array.major_version = -1;
        info->array.minor_version = -2;
-       sprintf(info->text_version, "/%s/%d",
-               devnum2devname(st->container_dev),
-               info->container_member);
+       devname = devnum2devname(st->container_dev);
+       *info->text_version = '\0';
+       if (devname)
+               sprintf(info->text_version, "/%s/%d", devname, info->container_member);
+       free(devname);
        info->safe_mode_delay = 4000;  /* 4 secs like the Matrix driver */
        uuid_from_super_imsm(st, info->uuid);
 }
@@ -1378,8 +1389,6 @@ static int update_super_imsm(struct supertype *st, struct mdinfo *info,
                             char *update, char *devname, int verbose,
                             int uuid_set, char *homehost)
 {
-       /* FIXME */
-
        /* For 'assemble' and 'force' we need to return non-zero if any
         * change was made.  For others, the return value is ignored.
         * Update options are:
@@ -1395,26 +1404,55 @@ static int update_super_imsm(struct supertype *st, struct mdinfo *info,
         *              linear only
         *  resync: mark as dirty so a resync will happen.
         *  name:  update the name - preserving the homehost
+        *  uuid:  Change the uuid of the array to match watch is given
         *
         * Following are not relevant for this imsm:
         *  sparc2.2 : update from old dodgey metadata
         *  super-minor: change the preferred_minor number
         *  summaries:  update redundant counters.
-        *  uuid:  Change the uuid of the array to match watch is given
         *  homehost:  update the recorded homehost
         *  _reshape_progress: record new reshape_progress position.
         */
-       int rv = 0;
-       //struct intel_super *super = st->sb;
-       //struct imsm_super *mpb = super->mpb;
+       int rv = 1;
+       struct intel_super *super = st->sb;
+       struct imsm_super *mpb;
 
-       if (strcmp(update, "grow") == 0) {
-       }
-       if (strcmp(update, "resync") == 0) {
-               /* dev->vol.dirty = 1; */
-       }
+       /* we can only update container info */
+       if (!super || super->current_vol >= 0 || !super->anchor)
+               return 1;
+
+       mpb = super->anchor;
+
+       if (strcmp(update, "uuid") == 0 && uuid_set && !info->update_private)
+               fprintf(stderr,
+                       Name ": '--uuid' not supported for imsm metadata\n");
+       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 (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;
+                       rv = 0;
+               }
+       } else if (strcmp(update, "assemble") == 0)
+               rv = 0;
+       else
+               fprintf(stderr,
+                       Name ": '--update=%s' not supported for imsm metadata\n",
+                       update);
 
-       /* IMSM has no concept of UUID or homehost */
+       /* successful update? recompute checksum */
+       if (rv == 0)
+               mpb->check_sum = __le32_to_cpu(__gen_imsm_checksum(mpb));
 
        return rv;
 }
@@ -1550,7 +1588,7 @@ static void fd2devname(int fd, char *name)
 {
        struct stat st;
        char path[256];
-       char dname[100];
+       char dname[PATH_MAX];
        char *nm;
        int rv;
 
@@ -1652,6 +1690,7 @@ static void serialcpy(__u8 *dest, __u8 *src)
        strncpy((char *) dest, (char *) src, MAX_RAID_SERIAL_LEN);
 }
 
+#ifndef MDASSEMBLE
 static struct dl *serial_to_dl(__u8 *serial, struct intel_super *super)
 {
        struct dl *dl;
@@ -1662,6 +1701,7 @@ static struct dl *serial_to_dl(__u8 *serial, struct intel_super *super)
 
        return dl;
 }
+#endif
 
 static struct imsm_disk *
 __serial_to_disk(__u8 *serial, struct imsm_super *mpb, int *idx)
@@ -2458,13 +2498,14 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
 
        if (sra->array.major_version != -1 ||
            sra->array.minor_version != -2 ||
-           strcmp(sra->text_version, "imsm") != 0)
-               return 1;
-
+           strcmp(sra->text_version, "imsm") != 0) {
+               err = 1;
+               goto error;
+       }
        /* load all mpbs */
        for (sd = sra->devs, i = 0; sd; sd = sd->next, i++) {
                struct intel_super *s = alloc_super(0);
-               char nm[20];
+               char nm[32];
                int dfd;
 
                err = 1;
@@ -2526,6 +2567,7 @@ 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;
@@ -2768,6 +2810,8 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
        map->ddf = 1;
 
        if (info->level == 1 && info->raid_disks > 2) {
+               free(dev);
+               free(dv);
                fprintf(stderr, Name": imsm does not support more than 2 disks"
                                "in a raid1 volume\n");
                return 0;
@@ -2819,24 +2863,33 @@ static int init_super_imsm(struct supertype *st, mdu_array_info_t *info,
        size_t mpb_size;
        char *version;
 
-       if (!info) {
-               st->sb = NULL;
-               return 0;
-       }
        if (st->sb)
-               return init_super_imsm_volume(st, info, size, name, homehost,
-                                             uuid);
+               return init_super_imsm_volume(st, info, size, name, homehost, uuid);
+
+       if (info)
+               mpb_size = disks_to_mpb_size(info->nr_disks);
+       else
+               mpb_size = 512;
 
        super = alloc_super(1);
-       if (!super)
-               return 0;
-       mpb_size = disks_to_mpb_size(info->nr_disks);
-       if (posix_memalign(&super->buf, 512, mpb_size) != 0) {
+       if (super && posix_memalign(&super->buf, 512, mpb_size) != 0) {
                free(super);
+               super = NULL;
+       }
+       if (!super) {
+               fprintf(stderr, Name
+                       ": %s could not allocate superblock\n", __func__);
                return 0;
        }
+       memset(super->buf, 0, mpb_size);
        mpb = super->buf;
-       memset(mpb, 0, mpb_size); 
+       mpb->mpb_size = __cpu_to_le32(mpb_size);
+       st->sb = super;
+
+       if (info == NULL) {
+               /* zeroing superblock */
+               return 0;
+       }
 
        mpb->attributes = MPB_ATTRIB_CHECKSUM_VERIFY;
 
@@ -2844,9 +2897,7 @@ static int init_super_imsm(struct supertype *st, mdu_array_info_t *info,
        strcpy(version, MPB_SIGNATURE);
        version += strlen(MPB_SIGNATURE);
        strcpy(version, MPB_VERSION_RAID0);
-       mpb->mpb_size = mpb_size;
 
-       st->sb = super;
        return 1;
 }
 
@@ -2902,6 +2953,10 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
                struct imsm_dev *_dev = __get_imsm_dev(mpb, 0);
                struct imsm_disk *_disk = __get_imsm_disk(mpb, dl->index);
 
+               if (!_dev || !_disk) {
+                       fprintf(stderr, Name ": BUG mpb setup error\n");
+                       return 1;
+               }
                *_dev = *dev;
                *_disk = dl->disk;
                sum = random32();
@@ -3188,24 +3243,19 @@ static int write_init_super_imsm(struct supertype *st)
 }
 #endif
 
-static int store_zero_imsm(struct supertype *st, int fd)
+static int store_super_imsm(struct supertype *st, int fd)
 {
-       unsigned long long dsize;
-       void *buf;
-
-       get_dev_size(fd, NULL, &dsize);
-
-       /* first block is stored on second to last sector of the disk */
-       if (lseek64(fd, dsize - (512 * 2), SEEK_SET) < 0)
-               return 1;
+       struct intel_super *super = st->sb;
+       struct imsm_super *mpb = super ? super->anchor : NULL;
 
-       if (posix_memalign(&buf, 512, 512) != 0)
+       if (!mpb)
                return 1;
 
-       memset(buf, 0, 512);
-       if (write(fd, buf, 512) != 512)
-               return 1;
-       return 0;
+#ifndef MDASSEMBLE
+       return store_imsm_mpb(fd, mpb);
+#else
+       return 1;
+#endif
 }
 
 static int imsm_bbm_log_size(struct imsm_super *mpb)
@@ -3395,7 +3445,7 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
 {
        struct stat stb;
        struct intel_super *super = st->sb;
-       struct imsm_super *mpb = super->anchor;
+       struct imsm_super *mpb;
        struct dl *dl;
        unsigned long long pos = 0;
        unsigned long long maxsize;
@@ -3405,6 +3455,7 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
        /* We must have the container info already read in. */
        if (!super)
                return 0;
+       mpb = super->anchor;
 
        if (!is_raid_level_supported(super->orom, level, raiddisks)) {
                pr_vrb(": platform does not support raid%d with %d disk%s\n",
@@ -3633,6 +3684,7 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
 {
        int fd, cfd;
        struct mdinfo *sra;
+       int is_member = 0;
 
        /* if given unused devices create a container 
         * if given given devices in a container create a member volume
@@ -3673,8 +3725,11 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
                case 1:
                case 10:
                case 5:
-                       break;
+                       return 0;
                default:
+                       if (verbose)
+                               fprintf(stderr, Name
+                                       ": IMSM only supports levels 0,1,5,10\n");
                        return 1;
                }
 
@@ -3696,17 +3751,19 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
        }
        /* Well, it is in use by someone, maybe an 'imsm' container. */
        cfd = open_container(fd);
+       close(fd);
        if (cfd < 0) {
-               close(fd);
                if (verbose)
                        fprintf(stderr, Name ": Cannot use %s: It is busy\n",
                                dev);
                return 0;
        }
        sra = sysfs_read(cfd, 0, GET_VERSION);
-       close(fd);
        if (sra && sra->array.major_version == -1 &&
-           strcmp(sra->text_version, "imsm") == 0) {
+           strcmp(sra->text_version, "imsm") == 0)
+               is_member = 1;
+       sysfs_free(sra);
+       if (is_member) {
                /* This is a member of a imsm container.  Load the container
                 * and try to create a volume
                 */
@@ -3721,11 +3778,13 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
                                                             size, dev,
                                                             freesize, verbose);
                }
-               close(cfd);
-       } else /* may belong to another container */
-               return 0;
+       }
 
-       return 1;
+       if (verbose)
+               fprintf(stderr, Name ": failed container membership check\n");
+
+       close(cfd);
+       return 0;
 }
 #endif /* MDASSEMBLE */
 
@@ -3770,6 +3829,11 @@ static struct mdinfo *container_content_imsm(struct supertype *st)
                }
 
                this = malloc(sizeof(*this));
+               if (!this) {
+                       fprintf(stderr, Name ": failed to allocate %lu bytes\n",
+                               sizeof(*this));
+                       break;
+               }
                memset(this, 0, sizeof(*this));
                this->next = rest;
 
@@ -3787,7 +3851,7 @@ static struct mdinfo *container_content_imsm(struct supertype *st)
                        ord = get_imsm_ord_tbl_ent(dev, slot); 
                        for (d = super->disks; d ; d = d->next)
                                if (d->index == idx)
-                                        break;
+                                       break;
 
                        if (d == NULL)
                                skip = 1;
@@ -3829,8 +3893,6 @@ static struct mdinfo *container_content_imsm(struct supertype *st)
                        info_d->events = __le32_to_cpu(mpb->generation_num);
                        info_d->data_offset = __le32_to_cpu(map->pba_of_lba0);
                        info_d->component_size = __le32_to_cpu(map->blocks_per_member);
-                       if (d->devname)
-                               strcpy(info_d->name, d->devname);
                }
                rest = this;
        }
@@ -4914,7 +4976,7 @@ struct superswitch super_imsm = {
 
        .load_super     = load_super_imsm,
        .init_super     = init_super_imsm,
-       .store_super    = store_zero_imsm,
+       .store_super    = store_super_imsm,
        .free_super     = free_super_imsm,
        .match_metadata_desc = match_metadata_desc_imsm,
        .container_content = container_content_imsm,