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

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

am 25.02.2011 02:17:18 von krzysztof.wojcik

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
---
super-intel.c | 30 ++++++++++++++++++------------
1 files changed, 18 insertions(+), 12 deletions(-)

diff --git a/super-intel.c b/super-intel.c
index c101dca..1a7be71 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -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;
}


--
To unsubscribe from this list: send the line "unsubscribe linux-raid" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html