FIX: imsm: OROM does not recognize degraded arrays (V2)

Defect description:
When we create an redundant array in mdadm and then degrade it
by disk removing, Option ROM and Windows OS does not detect any array.
Reason:
Metadata created and updated after degrading array is not compatible
with IMSM standard.

This patch synchronizes the metadata according IMSM requirements.
Following inconsistencies have been fixed:
- reset all fields in imsm_dev during creation to avoid random values
- init dev status during creation to proper state
- not reset CONFIGURED_DISK flag when disk is missing
- add ":0" suffix to the serial number for missing/failed disks
- update medatada signature after takeover operation
- mark map state as degraded after raid0->raid10 takeover

Note:
Patch reworked after Dan Willams review.

Signed-off-by: Krzysztof Wojcik <krzysztof.wojcik@intel.com>
Signed-off-by: NeilBrown <neilb@suse.de>
This commit is contained in:
Krzysztof Wojcik 2011-02-25 02:17:18 +01:00 committed by NeilBrown
parent 75156c4690
commit 1a2487c2cb
1 changed files with 18 additions and 12 deletions

View File

@ -3431,12 +3431,13 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
fprintf(stderr, Name ": failed to allocate device list entry\n");
return 0;
}
dev = malloc(sizeof(*dev) + sizeof(__u32) * (info->raid_disks - 1));
dev = calloc(1, sizeof(*dev) + sizeof(__u32) * (info->raid_disks - 1));
if (!dev) {
free(dv);
fprintf(stderr, Name": could not allocate raid device\n");
return 0;
}
strncpy((char *) dev->volume, name, MAX_RAID_SERIAL_LEN);
if (info->level == 1)
array_blocks = info_to_blocks_per_member(info);
@ -3449,8 +3450,7 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
dev->size_low = __cpu_to_le32((__u32) array_blocks);
dev->size_high = __cpu_to_le32((__u32) (array_blocks >> 32));
dev->status = __cpu_to_le32(0);
dev->reserved_blocks = __cpu_to_le32(0);
dev->status = (DEV_READ_COALESCING | DEV_WRITE_COALESCING);
vol = &dev->vol;
vol->migr_state = 0;
set_migr_type(dev, MIGR_INIT);
@ -5046,6 +5046,8 @@ static int mark_failure(struct imsm_dev *dev, struct imsm_disk *disk, int idx)
__u32 ord;
int slot;
struct imsm_map *map;
char buf[MAX_RAID_SERIAL_LEN+3];
unsigned int len, shift = 0;
/* new failures are always set in map[0] */
map = get_imsm_map(dev, 0);
@ -5058,8 +5060,12 @@ static int mark_failure(struct imsm_dev *dev, struct imsm_disk *disk, int idx)
if (is_failed(disk) && (ord & IMSM_ORD_REBUILD))
return 0;
sprintf(buf, "%s:0", disk->serial);
if ((len = strlen(buf)) >= MAX_RAID_SERIAL_LEN)
shift = len - MAX_RAID_SERIAL_LEN + 1;
strncpy((char *)disk->serial, &buf[shift], MAX_RAID_SERIAL_LEN);
disk->status |= FAILED_DISK;
disk->status &= ~CONFIGURED_DISK;
set_imsm_ord_tbl_ent(map, slot, idx | IMSM_ORD_REBUILD);
if (map->failed_disk_num == 0xff)
map->failed_disk_num = slot;
@ -6063,8 +6069,6 @@ static int apply_takeover_update(struct imsm_update_takeover *u,
*space_list = *space;
du = (void *)space;
memcpy(du, super->disks, sizeof(*du));
du->disk.status = FAILED_DISK;
du->disk.scsi_id = 0;
du->fd = -1;
du->minor = 0;
du->major = 0;
@ -6085,9 +6089,8 @@ static int apply_takeover_update(struct imsm_update_takeover *u,
memcpy(dev_new, dev, sizeof(*dev));
/* update new map */
map = get_imsm_map(dev_new, 0);
map->failed_disk_num = map->num_members;
map->num_members = map->num_members * 2;
map->map_state = IMSM_T_STATE_NORMAL;
map->map_state = IMSM_T_STATE_DEGRADED;
map->num_domains = 2;
map->raid_level = 1;
/* replace dev<->dev_new */
@ -6098,9 +6101,10 @@ static int apply_takeover_update(struct imsm_update_takeover *u,
if (du->index >= 0)
set_imsm_ord_tbl_ent(map, du->index, du->index);
for (du = super->missing; du; du = du->next)
if (du->index >= 0)
set_imsm_ord_tbl_ent(map, du->index,
du->index | IMSM_ORD_REBUILD);
if (du->index >= 0) {
set_imsm_ord_tbl_ent(map, du->index, du->index);
mark_missing(dev_new, &du->disk, du->index);
}
return 1;
}
@ -6149,8 +6153,10 @@ static void imsm_process_update(struct supertype *st,
switch (type) {
case update_takeover: {
struct imsm_update_takeover *u = (void *)update->buf;
if (apply_takeover_update(u, super, &update->space_list))
if (apply_takeover_update(u, super, &update->space_list)) {
imsm_update_version_info(super);
super->updates_pending++;
}
break;
}