summaryrefslogtreecommitdiff
path: root/super-intel.c
diff options
context:
space:
mode:
Diffstat (limited to 'super-intel.c')
-rw-r--r--super-intel.c153
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,