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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxx>
---
 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@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux RAID Wiki]     [ATA RAID]     [Linux SCSI Target Infrastructure]     [Linux Block]     [Linux IDE]     [Linux SCSI]     [Linux Hams]     [Device Mapper]     [Device Mapper Cryptographics]     [Kernel]     [Linux Admin]     [Linux Net]     [GFS]     [RPM]     [git]     [Yosemite Forum]


  Powered by Linux