]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
FIX: imsm: OROM does not recognize degraded arrays (V2)
authorKrzysztof Wojcik <krzysztof.wojcik@intel.com>
Fri, 25 Feb 2011 01:17:18 +0000 (02:17 +0100)
committerNeilBrown <neilb@suse.de>
Sun, 27 Feb 2011 06:13:10 +0000 (17:13 +1100)
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>
super-intel.c

index c101dca744a776c50677c0eada566eb5c2b52639..1a7be7130f4c7919e798678242987ca1dd75dae5 100644 (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;
        }