diff --git a/super-ddf.c b/super-ddf.c index 8bba70a..f73a63f 100644 --- a/super-ddf.c +++ b/super-ddf.c @@ -1581,6 +1581,7 @@ static void brief_examine_subarrays_ddf(struct supertype *st, int verbose) continue; memcpy(vcl.conf.guid, ve->guid, DDF_GUID_LEN); ddf->currentconf =&vcl; + vcl.vcnum = i; uuid_from_super_ddf(st, info.uuid); fname_from_uuid(st, &info, nbuf1, ':'); printf("ARRAY container=%s member=%d UUID=%s\n", @@ -1673,6 +1674,52 @@ static void detail_super_ddf(struct supertype *st, char *homehost) */ } +static const char *vendors_with_variable_volume_UUID[] = { + "LSI ", +}; + +static int volume_id_is_reliable(const struct ddf_super *ddf) +{ + int n = sizeof(vendors_with_variable_volume_UUID) / + sizeof(vendors_with_variable_volume_UUID[0]); + int i; + for (i = 0; i < n; i++) + if (!memcmp(ddf->controller.guid, + vendors_with_variable_volume_UUID[i], 8)) + return 0; + return 1; +} + +static void uuid_of_ddf_subarray(const struct ddf_super *ddf, + unsigned int vcnum, int uuid[4]) +{ + char buf[DDF_GUID_LEN+18], sha[20], *p; + struct sha1_ctx ctx; + if (volume_id_is_reliable(ddf)) { + uuid_from_ddf_guid(ddf->virt->entries[vcnum].guid, uuid); + return; + } + /* + * Some fake RAID BIOSes (in particular, LSI ones) change the + * VD GUID at every boot. These GUIDs are not suitable for + * identifying an array. Luckily the header GUID appears to + * remain constant. + * We construct a pseudo-UUID from the header GUID and those + * properties of the subarray that we expect to remain constant. + */ + memset(buf, 0, sizeof(buf)); + p = buf; + memcpy(p, ddf->anchor.guid, DDF_GUID_LEN); + p += DDF_GUID_LEN; + memcpy(p, ddf->virt->entries[vcnum].name, 16); + p += 16; + *((__u16 *) p) = vcnum; + sha1_init_ctx(&ctx); + sha1_process_bytes(buf, sizeof(buf), &ctx); + sha1_finish_ctx(&ctx, sha); + memcpy(uuid, sha, 4*4); +} + static void brief_detail_super_ddf(struct supertype *st) { struct mdinfo info; @@ -1684,7 +1731,7 @@ static void brief_detail_super_ddf(struct supertype *st) else if (vcnum == DDF_NOTFOUND) return; else - uuid_from_ddf_guid(ddf->virt->entries[vcnum].guid, info.uuid); + uuid_of_ddf_subarray(ddf, vcnum, info.uuid); fname_from_uuid(st, &info, nbuf,':'); printf(" UUID=%s", nbuf + 5); } @@ -1827,13 +1874,11 @@ static void uuid_from_super_ddf(struct supertype *st, int uuid[4]) */ struct ddf_super *ddf = st->sb; struct vcl *vcl = ddf->currentconf; - char *guid; if (vcl) - guid = vcl->conf.guid; + uuid_of_ddf_subarray(ddf, vcl->vcnum, uuid); else - guid = ddf->anchor.guid; - uuid_from_ddf_guid(guid, uuid); + uuid_from_ddf_guid(ddf->anchor.guid, uuid); } static void getinfo_super_ddf_bvd(struct supertype *st, struct mdinfo *info, char *map);