diff options
Diffstat (limited to 'super-intel.c')
-rw-r--r-- | super-intel.c | 153 |
1 files changed, 108 insertions, 45 deletions
diff --git a/super-intel.c b/super-intel.c index d7383fbd..07b0b906 100644 --- a/super-intel.c +++ b/super-intel.c @@ -64,7 +64,6 @@ struct imsm_disk { #define SPARE_DISK __cpu_to_le32(0x01) /* Spare */ #define CONFIGURED_DISK __cpu_to_le32(0x02) /* Member of some RaidDev */ #define FAILED_DISK __cpu_to_le32(0x04) /* Permanent failure */ -#define USABLE_DISK __cpu_to_le32(0x08) /* Fully usable unless FAILED_DISK is set */ __u32 status; /* 0xF0 - 0xF3 */ __u32 owner_cfg_num; /* which config 0,1,2... owns this disk */ #define IMSM_DISK_FILLERS 4 @@ -247,6 +246,7 @@ struct intel_super { int creating_imsm; /* flag to indicate container creation */ int current_vol; /* index of raid device undergoing creation */ __u32 create_offset; /* common start for 'current_vol' */ + __u32 random; /* random data for seeding new family numbers */ struct intel_dev *devlist; struct dl { struct dl *next; @@ -686,10 +686,9 @@ static void print_imsm_disk(struct imsm_super *mpb, int index, __u32 reserved) snprintf(str, MAX_RAID_SERIAL_LEN + 1, "%s", disk->serial); printf(" Disk%02d Serial : %s\n", index, str); s = disk->status; - printf(" State :%s%s%s%s\n", s&SPARE_DISK ? " spare" : "", + printf(" State :%s%s%s\n", s&SPARE_DISK ? " spare" : "", s&CONFIGURED_DISK ? " active" : "", - s&FAILED_DISK ? " failed" : "", - s&USABLE_DISK ? " usable" : ""); + s&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, @@ -714,6 +713,7 @@ static void examine_super_imsm(struct supertype *st, char *homehost) printf(" Magic : %s\n", str); snprintf(str, strlen(MPB_VERSION_RAID0), "%s", get_imsm_version(mpb)); printf(" Version : %s\n", get_imsm_version(mpb)); + printf(" Orig Family : %08x\n", __le32_to_cpu(mpb->orig_family_num)); printf(" Family : %08x\n", __le32_to_cpu(mpb->family_num)); printf(" Generation : %08x\n", __le32_to_cpu(mpb->generation_num)); getinfo_super_imsm(st, &info); @@ -759,6 +759,23 @@ static void brief_examine_super_imsm(struct supertype *st, int verbose) /* We just write a generic IMSM ARRAY entry */ struct mdinfo info; char nbuf[64]; + struct intel_super *super = st->sb; + + if (!super->anchor->num_raid_devs) { + printf("ARRAY metadata=imsm\n"); + return; + } + + getinfo_super_imsm(st, &info); + fname_from_uuid(st, &info, nbuf, ':'); + printf("ARRAY metadata=imsm UUID=%s\n", nbuf + 5); +} + +static void brief_examine_subarrays_imsm(struct supertype *st, int verbose) +{ + /* We just write a generic IMSM ARRAY entry */ + struct mdinfo info; + char nbuf[64]; char nbuf1[64]; struct intel_super *super = st->sb; int i; @@ -768,15 +785,13 @@ static void brief_examine_super_imsm(struct supertype *st, int verbose) getinfo_super_imsm(st, &info); fname_from_uuid(st, &info, nbuf, ':'); - printf("ARRAY metadata=imsm auto=md UUID=%s\n", nbuf + 5); for (i = 0; i < super->anchor->num_raid_devs; i++) { struct imsm_dev *dev = get_imsm_dev(super, i); super->current_vol = i; getinfo_super_imsm(st, &info); fname_from_uuid(st, &info, nbuf1, ':'); - printf("ARRAY /dev/md/%.16s container=%s\n" - " member=%d auto=mdp UUID=%s\n", + printf("ARRAY /dev/md/%.16s container=%s member=%d UUID=%s\n", dev->volume, nbuf + 5, i, nbuf1 + 5); } } @@ -1090,7 +1105,7 @@ static int match_home_imsm(struct supertype *st, char *homehost) /* the imsm metadata format does not specify any host * identification information. We return -1 since we can never * confirm nor deny whether a given array is "meant" for this - * host. We rely on compare_super and the 'family_num' field to + * host. We rely on compare_super and the 'family_num' fields to * exclude member disks that do not belong, and we rely on * mdadm.conf to specify the arrays that should be assembled. * Auto-assembly may still pick up "foreign" arrays. @@ -1118,7 +1133,7 @@ static void uuid_from_super_imsm(struct supertype *st, int uuid[4]) */ /* imsm does not track uuid's so we synthesis one using sha1 on * - The signature (Which is constant for all imsm array, but no matter) - * - the family_num of the container + * - the orig_family_num of the container * - the index number of the volume * - the 'serial' number of the volume. * Hopefully these are all constant. @@ -1128,10 +1143,18 @@ static void uuid_from_super_imsm(struct supertype *st, int uuid[4]) char buf[20]; struct sha1_ctx ctx; struct imsm_dev *dev = NULL; + __u32 family_num; + /* some mdadm versions failed to set ->orig_family_num, in which + * case fall back to ->family_num. orig_family_num will be + * fixed up with the first metadata update. + */ + family_num = super->anchor->orig_family_num; + if (family_num == 0) + family_num = super->anchor->family_num; sha1_init_ctx(&ctx); sha1_process_bytes(super->anchor->sig, MPB_SIG_LEN, &ctx); - sha1_process_bytes(&super->anchor->family_num, sizeof(__u32), &ctx); + sha1_process_bytes(&family_num, sizeof(__u32), &ctx); if (super->current_vol >= 0) dev = get_imsm_dev(super, super->current_vol); if (dev) { @@ -1257,7 +1280,11 @@ static void fixup_container_spare_uuid(struct mdinfo *inf) struct supertype *_cst; /* container supertype */ _cst = array_list->st; - _sst = _cst->ss->match_metadata_desc(inf->text_version); + if (_cst) + _sst = _cst->ss->match_metadata_desc(inf->text_version); + else + _sst = NULL; + if (_sst) { memcpy(inf->uuid, array_list->uuid, sizeof(int[4])); free(_sst); @@ -1439,7 +1466,8 @@ static int compare_super_imsm(struct supertype *st, struct supertype *tst) */ if (first->anchor->num_raid_devs > 0 && sec->anchor->num_raid_devs > 0) { - if (first->anchor->family_num != sec->anchor->family_num) + if (first->anchor->orig_family_num != sec->anchor->orig_family_num || + first->anchor->family_num != sec->anchor->family_num) return 3; } @@ -1469,17 +1497,17 @@ static int compare_super_imsm(struct supertype *st, struct supertype *tst) dv->next = first->devlist; first->devlist = dv; } - if (i <= sec->anchor->num_raid_devs) { + if (i < sec->anchor->num_raid_devs) { /* allocation failure */ free_devlist(first); fprintf(stderr, "imsm: failed to associate spare\n"); return 3; } - for (i = 0; i < sec->anchor->num_raid_devs; i++) - imsm_copy_dev(get_imsm_dev(first, i), get_imsm_dev(sec, i)); - first->anchor->num_raid_devs = sec->anchor->num_raid_devs; + first->anchor->orig_family_num = sec->anchor->orig_family_num; first->anchor->family_num = sec->anchor->family_num; + for (i = 0; i < sec->anchor->num_raid_devs; i++) + imsm_copy_dev(get_imsm_dev(first, i), get_imsm_dev(sec, i)); } return 0; @@ -2168,8 +2196,10 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp, if (st->subarray[0]) { if (atoi(st->subarray) <= super->anchor->num_raid_devs) super->current_vol = atoi(st->subarray); - else + else { + free_imsm(super); return 1; + } } *sbp = super; @@ -2194,8 +2224,8 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname) if (load_super_imsm_all(st, fd, &st->sb, devname, 1) == 0) return 0; #endif - if (st->subarray[0]) - return 1; /* FIXME */ + + free_super_imsm(st); super = alloc_super(0); if (!super) { @@ -2216,6 +2246,15 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname) return rv; } + if (st->subarray[0]) { + if (atoi(st->subarray) <= super->anchor->num_raid_devs) + super->current_vol = atoi(st->subarray); + else { + free_imsm(super); + return 1; + } + } + st->sb = super; if (st->ss == NULL) { st->ss = &super_imsm; @@ -2405,13 +2444,16 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info, "in a raid1 volume\n"); return 0; } + + map->raid_level = info->level; if (info->level == 10) { map->raid_level = 1; map->num_domains = info->raid_disks / 2; - } else { - map->raid_level = info->level; + } else if (info->level == 1) + map->num_domains = info->raid_disks; + else map->num_domains = 1; - } + num_data_stripes = info_to_num_data_stripes(info, map->num_domains); map->num_data_stripes = __cpu_to_le32(num_data_stripes); @@ -2524,7 +2566,7 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk, super->anchor->num_disks++; } set_imsm_ord_tbl_ent(map, dk->number, dl->index); - dl->disk.status = CONFIGURED_DISK | USABLE_DISK; + dl->disk.status = CONFIGURED_DISK; /* if we are creating the first raid device update the family number */ if (super->current_vol == 0) { @@ -2534,8 +2576,10 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk, *_dev = *dev; *_disk = dl->disk; - sum = __gen_imsm_checksum(mpb); + sum = random32(); + sum += __gen_imsm_checksum(mpb); mpb->family_num = __cpu_to_le32(sum); + mpb->orig_family_num = mpb->family_num; } return 0; @@ -2590,7 +2634,7 @@ static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk, size /= 512; serialcpy(dd->disk.serial, dd->serial); dd->disk.total_blocks = __cpu_to_le32(size); - dd->disk.status = USABLE_DISK | SPARE_DISK; + dd->disk.status = SPARE_DISK; if (sysfs_disk_to_scsi_id(fd, &id) == 0) dd->disk.scsi_id = __cpu_to_le32(id); else @@ -2632,6 +2676,7 @@ static int write_super_imsm_spares(struct intel_super *super, int doclose) mpb->disk[0] = d->disk; sum = __gen_imsm_checksum(mpb); mpb->family_num = __cpu_to_le32(sum); + mpb->orig_family_num = 0; sum = __gen_imsm_checksum(mpb); mpb->check_sum = __cpu_to_le32(sum); @@ -2666,6 +2711,12 @@ static int write_super_imsm(struct intel_super *super, int doclose) generation++; mpb->generation_num = __cpu_to_le32(generation); + /* fix up cases where previous mdadm releases failed to set + * orig_family_num + */ + if (mpb->orig_family_num == 0) + mpb->orig_family_num = mpb->family_num; + mpb_size += sizeof(struct imsm_disk) * mpb->num_disks; for (d = super->disks; d; d = d->next) { if (d->index == -1) @@ -2709,17 +2760,16 @@ static int write_super_imsm(struct intel_super *super, int doclose) } -static int create_array(struct supertype *st) +static int create_array(struct supertype *st, int dev_idx) { size_t len; struct imsm_update_create_array *u; struct intel_super *super = st->sb; - struct imsm_dev *dev = get_imsm_dev(super, super->current_vol); + struct imsm_dev *dev = get_imsm_dev(super, dev_idx); struct imsm_map *map = get_imsm_map(dev, 0); struct disk_info *inf; struct imsm_disk *disk; int i; - int idx; len = sizeof(*u) - sizeof(*dev) + sizeof_imsm_dev(dev, 0) + sizeof(*inf) * map->num_members; @@ -2731,11 +2781,12 @@ static int create_array(struct supertype *st) } u->type = update_create_array; - u->dev_idx = super->current_vol; + u->dev_idx = dev_idx; imsm_copy_dev(&u->dev, dev); inf = get_disk_info(u); for (i = 0; i < map->num_members; i++) { - idx = get_imsm_disk_idx(dev, i); + int idx = get_imsm_disk_idx(dev, i); + disk = get_imsm_disk(super, idx); serialcpy(inf[i].serial, disk->serial); } @@ -2769,21 +2820,26 @@ static int _add_disk(struct supertype *st) static int write_init_super_imsm(struct supertype *st) { + struct intel_super *super = st->sb; + int current_vol = super->current_vol; + + /* we are done with current_vol reset it to point st at the container */ + super->current_vol = -1; + if (st->update_tail) { /* queue the recently created array / added disk * as a metadata update */ - struct intel_super *super = st->sb; struct dl *d; int rv; /* determine if we are creating a volume or adding a disk */ - if (super->current_vol < 0) { + if (current_vol < 0) { /* in the add disk case we are running in mdmon * context, so don't close fd's */ return _add_disk(st); } else - rv = create_array(st); + rv = create_array(st, current_vol); for (d = super->disks; d ; d = d->next) { close(d->fd); @@ -3404,8 +3460,6 @@ static struct mdinfo *container_content_imsm(struct supertype *st) s = d ? d->disk.status : 0; if (s & FAILED_DISK) skip = 1; - if (!(s & USABLE_DISK)) - skip = 1; if (ord & IMSM_ORD_REBUILD) skip = 1; @@ -3626,8 +3680,9 @@ static int mark_failure(struct imsm_dev *dev, struct imsm_disk *disk, int idx) return 0; disk->status |= FAILED_DISK; + disk->status &= ~CONFIGURED_DISK; set_imsm_ord_tbl_ent(map, slot, idx | IMSM_ORD_REBUILD); - if (map->failed_disk_num == ~0) + if (~map->failed_disk_num == 0) map->failed_disk_num = slot; return 1; } @@ -3838,14 +3893,13 @@ static struct dl *imsm_add_spare(struct intel_super *super, int slot, int idx = get_imsm_disk_idx(dev, slot); struct imsm_super *mpb = super->anchor; struct imsm_map *map; - unsigned long long esize; unsigned long long pos; struct mdinfo *d; struct extent *ex; int i, j; int found; __u32 array_start; - __u32 blocks; + __u32 array_end; struct dl *dl; for (dl = super->disks; dl; dl = dl->next) { @@ -3897,15 +3951,14 @@ static struct dl *imsm_add_spare(struct intel_super *super, int slot, j = 0; pos = 0; array_start = __le32_to_cpu(map->pba_of_lba0); - blocks = __le32_to_cpu(map->blocks_per_member); + array_end = array_start + + __le32_to_cpu(map->blocks_per_member) - 1; do { /* check that we can start at pba_of_lba0 with * blocks_per_member of space */ - esize = ex[j].start - pos; - if (array_start >= pos && - array_start + blocks < ex[j].start) { + if (array_start >= pos && array_end < ex[j].start) { found = 1; break; } @@ -3919,9 +3972,8 @@ static struct dl *imsm_add_spare(struct intel_super *super, int slot, free(ex); if (i < mpb->num_raid_devs) { - dprintf("%x:%x does not have %u at %u\n", - dl->major, dl->minor, - blocks, array_start); + dprintf("%x:%x does not have %u to %u available\n", + dl->major, dl->minor, array_start, array_end); /* No room */ continue; } @@ -4023,6 +4075,7 @@ static struct mdinfo *imsm_activate_spare(struct active_array *a, di->data_offset = __le32_to_cpu(map->pba_of_lba0); di->component_size = a->info.component_size; di->container_member = inst; + super->random = random32(); di->next = rv; rv = di; num_spares++; @@ -4189,6 +4242,15 @@ static void imsm_process_update(struct supertype *st, set_imsm_ord_tbl_ent(map, u->slot, dl->index); set_imsm_ord_tbl_ent(migr_map, u->slot, dl->index | IMSM_ORD_REBUILD); + /* update the family_num to mark a new container + * generation, being careful to record the existing + * family_num in orig_family_num to clean up after + * earlier mdadm versions that neglected to set it. + */ + if (mpb->orig_family_num == 0) + mpb->orig_family_num = mpb->family_num; + mpb->family_num += super->random; + /* count arrays using the victim in the metadata */ found = 0; for (a = st->arrays; a ; a = a->next) { @@ -4502,6 +4564,7 @@ struct superswitch super_imsm = { #ifndef MDASSEMBLE .examine_super = examine_super_imsm, .brief_examine_super = brief_examine_super_imsm, + .brief_examine_subarrays = brief_examine_subarrays_imsm, .export_examine_super = export_examine_super_imsm, .detail_super = detail_super_imsm, .brief_detail_super = brief_detail_super_imsm, |