]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - super-intel.c
fix: segfault when killing subarray of non-existent container
[thirdparty/mdadm.git] / super-intel.c
index 2f1169807f177c08b663c98fa63ce4467a88dc1d..a78d7238a755aefaa88353db44719736e8bed163 100644 (file)
@@ -833,7 +833,16 @@ static struct extent *get_extents(struct intel_super *super, struct dl *dl)
        struct extent *rv, *e;
        int i;
        int memberships = count_memberships(dl, super);
-       __u32 reservation = MPB_SECTOR_CNT + IMSM_RESERVED_SECTORS;
+       __u32 reservation;
+
+       /* trim the reserved area for spares, so they can join any array
+        * regardless of whether the OROM has assigned sectors from the
+        * IMSM_RESERVED_SECTORS region
+        */
+       if (dl->index == -1)
+               reservation = MPB_SECTOR_CNT;
+       else
+               reservation = MPB_SECTOR_CNT + IMSM_RESERVED_SECTORS;
 
        rv = malloc(sizeof(struct extent) * (memberships + 1));
        if (!rv)
@@ -1059,18 +1068,20 @@ static void print_imsm_dev(struct intel_super *super,
        printf("    Dirty State : %s\n", dev->vol.dirty ? "dirty" : "clean");
 }
 
-static void print_imsm_disk(struct imsm_super *mpb, int index, __u32 reserved)
+static void print_imsm_disk(struct imsm_disk *disk, int index, __u32 reserved)
 {
-       struct imsm_disk *disk = __get_imsm_disk(mpb, index);
        char str[MAX_RAID_SERIAL_LEN + 1];
        __u64 sz;
 
-       if (index < 0 || !disk)
+       if (index < -1 || !disk)
                return;
 
        printf("\n");
        snprintf(str, MAX_RAID_SERIAL_LEN + 1, "%s", disk->serial);
-       printf("  Disk%02d Serial : %s\n", index, str);
+       if (index >= 0)
+               printf("  Disk%02d Serial : %s\n", index, str);
+       else
+               printf("    Disk Serial : %s\n", str);
        printf("          State :%s%s%s\n", is_spare(disk) ? " spare" : "",
                                            is_configured(disk) ? " active" : "",
                                            is_failed(disk) ? " failed" : "");
@@ -1254,7 +1265,7 @@ static void examine_super_imsm(struct supertype *st, char *homehost)
        printf("    MPB Sectors : %d\n", mpb_sectors(mpb));
        printf("          Disks : %d\n", mpb->num_disks);
        printf("   RAID Devices : %d\n", mpb->num_raid_devs);
-       print_imsm_disk(mpb, super->disks->index, reserved);
+       print_imsm_disk(__get_imsm_disk(mpb, super->disks->index), super->disks->index, reserved);
        if (super->bbm_log) {
                struct bbm_log *log = super->bbm_log;
 
@@ -1279,28 +1290,12 @@ static void examine_super_imsm(struct supertype *st, char *homehost)
        for (i = 0; i < mpb->num_disks; i++) {
                if (i == super->disks->index)
                        continue;
-               print_imsm_disk(mpb, i, reserved);
+               print_imsm_disk(__get_imsm_disk(mpb, i), i, reserved);
        }
-       for (dl = super->disks ; dl; dl = dl->next) {
-               struct imsm_disk *disk;
-               char str[MAX_RAID_SERIAL_LEN + 1];
-               __u64 sz;
 
-               if (dl->index >= 0)
-                       continue;
-
-               disk = &dl->disk;
-               printf("\n");
-               snprintf(str, MAX_RAID_SERIAL_LEN + 1, "%s", disk->serial);
-               printf("    Disk Serial : %s\n", str);
-               printf("          State :%s%s%s\n", is_spare(disk) ? " spare" : "",
-                      is_configured(disk) ? " active" : "",
-                      is_failed(disk) ? " failed" : "");
-               printf("             Id : %08x\n", __le32_to_cpu(disk->scsi_id));
-               sz = __le32_to_cpu(disk->total_blocks) - reserved;
-               printf("    Usable Size : %llu%s\n", (unsigned long long)sz,
-                      human_size(sz * 512));
-       }
+       for (dl = super->disks; dl; dl = dl->next)
+               if (dl->index == -1)
+                       print_imsm_disk(&dl->disk, -1, reserved);
 
        examine_migr_rec_imsm(super);
 }
@@ -2880,7 +2875,6 @@ 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;
@@ -2891,7 +2885,6 @@ 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)
@@ -3449,7 +3442,6 @@ static int find_intel_hba_capability(int fd, struct intel_super *super, char *de
        return 0;
 }
 
-#ifndef MDASSEMBLE
 /* find_missing - helper routine for load_super_imsm_all that identifies
  * disks that have disappeared from the system.  This routine relies on
  * the mpb being uptodate, which it is at load time.
@@ -3485,6 +3477,7 @@ static int find_missing(struct intel_super *super)
        return 0;
 }
 
+#ifndef MDASSEMBLE
 static struct intel_disk *disk_list_get(__u8 *serial, struct intel_disk *disk_list)
 {
        struct intel_disk *idisk = disk_list;
@@ -4138,12 +4131,40 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
                memset(mpb_new + size_old, 0, size_round - size_old);
        }
        super->current_vol = idx;
-       /* when creating the first raid device in this container set num_disks
-        * to zero, i.e. delete this spare and add raid member devices in
-        * add_to_super_imsm_volume()
+
+       /* handle 'failed_disks' by either:
+        * a) create dummy disk entries in the table if this the first
+        *    volume in the array.  We add them here as this is the only
+        *    opportunity to add them. add_to_super_imsm_volume()
+        *    handles the non-failed disks and continues incrementing
+        *    mpb->num_disks.
+        * b) validate that 'failed_disks' matches the current number
+        *    of missing disks if the container is populated
         */
-       if (super->current_vol == 0)
+       if (super->current_vol == 0) {
                mpb->num_disks = 0;
+               for (i = 0; i < info->failed_disks; i++) {
+                       struct imsm_disk *disk;
+
+                       mpb->num_disks++;
+                       disk = __get_imsm_disk(mpb, i);
+                       disk->status = CONFIGURED_DISK | FAILED_DISK;
+                       disk->scsi_id = __cpu_to_le32(~(__u32)0);
+                       snprintf((char *) disk->serial, MAX_RAID_SERIAL_LEN,
+                                "missing:%d", i);
+               }
+               find_missing(super);
+       } else {
+               int missing = 0;
+               struct dl *d;
+
+               for (d = super->missing; d; d = d->next)
+                       missing++;
+               if (info->failed_disks > missing) {
+                       fprintf(stderr, Name": unable to add 'missing' disk to container\n");
+                       return 0;
+               }
+       }
 
        if (!check_name(super, name, 0))
                return 0;
@@ -4175,15 +4196,14 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
        vol = &dev->vol;
        vol->migr_state = 0;
        set_migr_type(dev, MIGR_INIT);
-       vol->dirty = 0;
+       vol->dirty = !info->state;
        vol->curr_migr_unit = 0;
        map = get_imsm_map(dev, 0);
        map->pba_of_lba0 = __cpu_to_le32(super->create_offset);
        map->blocks_per_member = __cpu_to_le32(info_to_blocks_per_member(info));
        map->blocks_per_strip = __cpu_to_le16(info_to_blocks_per_strip(info));
        map->failed_disk_num = ~0;
-       map->map_state = info->level ? IMSM_T_STATE_UNINITIALIZED :
-                                      IMSM_T_STATE_NORMAL;
+       map->map_state = info->failed_disks ? IMSM_T_STATE_DEGRADED : IMSM_T_STATE_NORMAL;
        map->ddf = 1;
 
        if (info->level == 1 && info->raid_disks > 2) {
@@ -4291,9 +4311,10 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
 {
        struct intel_super *super = st->sb;
        struct imsm_super *mpb = super->anchor;
-       struct dl *dl;
+       struct imsm_disk *_disk;
        struct imsm_dev *dev;
        struct imsm_map *map;
+       struct dl *dl, *df;
        int slot;
 
        dev = get_imsm_dev(super, super->current_vol);
@@ -4340,12 +4361,37 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
        set_imsm_ord_tbl_ent(map, dk->raid_disk, dl->index);
        dl->disk.status = CONFIGURED_DISK;
 
+       /* update size of 'missing' disks to be at least as large as the
+        * largest acitve member (we only have dummy missing disks when
+        * creating the first volume)
+        */
+       if (super->current_vol == 0) {
+               for (df = super->missing; df; df = df->next) {
+                       if (dl->disk.total_blocks > df->disk.total_blocks)
+                               df->disk.total_blocks = dl->disk.total_blocks;
+                       _disk = __get_imsm_disk(mpb, df->index);
+                       *_disk = df->disk;
+               }
+       }
+
+       /* refresh unset/failed slots to point to valid 'missing' entries */
+       for (df = super->missing; df; df = df->next)
+               for (slot = 0; slot < mpb->num_disks; slot++) {
+                       __u32 ord = get_imsm_ord_tbl_ent(dev, slot, -1);
+
+                       if ((ord & IMSM_ORD_REBUILD) == 0)
+                               continue;
+                       set_imsm_ord_tbl_ent(map, slot, df->index | IMSM_ORD_REBUILD);
+                       dprintf("set slot:%d to missing disk:%d\n", slot, df->index);
+                       break;
+               }
+
        /* if we are creating the first raid device update the family number */
        if (super->current_vol == 0) {
                __u32 sum;
                struct imsm_dev *_dev = __get_imsm_dev(mpb, 0);
-               struct imsm_disk *_disk = __get_imsm_disk(mpb, dl->index);
 
+               _disk = __get_imsm_disk(mpb, dl->index);
                if (!_dev || !_disk) {
                        fprintf(stderr, Name ": BUG mpb setup error\n");
                        return 1;