From 3960e579bfe77b3e16a4a6d8546019ff794eb515 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 30 Aug 2011 13:11:42 +1000 Subject: imsm: support 'missing' devices at Create Specifying missing devices at create is very useful for array recovery. For imsm create dummy disk entries at init_super_imsm time, and then use them to fill in unoccupied slots in the final array (if the container is unpopulated). If the container is already populated (has a subarray) 'missing' disks must be in reference to already recorded missing devices in the metadata. Also add support for --assume-clean for imsm arrays. Cc: Dave Jiang Signed-off-by: Dan Williams Signed-off-by: NeilBrown --- super-intel.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 63 insertions(+), 12 deletions(-) (limited to 'super-intel.c') diff --git a/super-intel.c b/super-intel.c index 193e0d04..a78d7238 100644 --- a/super-intel.c +++ b/super-intel.c @@ -2875,7 +2875,6 @@ static void serialcpy(__u8 *dest, __u8 *src) strncpy((char *) dest, (char *) src, MAX_RAID_SERIAL_LEN); } -#ifndef MDASSEMBLE static struct dl *serial_to_dl(__u8 *serial, struct intel_super *super) { struct dl *dl; @@ -2886,7 +2885,6 @@ static struct dl *serial_to_dl(__u8 *serial, struct intel_super *super) return dl; } -#endif static struct imsm_disk * __serial_to_disk(__u8 *serial, struct imsm_super *mpb, int *idx) @@ -3444,7 +3442,6 @@ static int find_intel_hba_capability(int fd, struct intel_super *super, char *de return 0; } -#ifndef MDASSEMBLE /* find_missing - helper routine for load_super_imsm_all that identifies * disks that have disappeared from the system. This routine relies on * the mpb being uptodate, which it is at load time. @@ -3480,6 +3477,7 @@ static int find_missing(struct intel_super *super) return 0; } +#ifndef MDASSEMBLE static struct intel_disk *disk_list_get(__u8 *serial, struct intel_disk *disk_list) { struct intel_disk *idisk = disk_list; @@ -4133,12 +4131,40 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info, memset(mpb_new + size_old, 0, size_round - size_old); } super->current_vol = idx; - /* when creating the first raid device in this container set num_disks - * to zero, i.e. delete this spare and add raid member devices in - * add_to_super_imsm_volume() + + /* handle 'failed_disks' by either: + * a) create dummy disk entries in the table if this the first + * volume in the array. We add them here as this is the only + * opportunity to add them. add_to_super_imsm_volume() + * handles the non-failed disks and continues incrementing + * mpb->num_disks. + * b) validate that 'failed_disks' matches the current number + * of missing disks if the container is populated */ - if (super->current_vol == 0) + if (super->current_vol == 0) { mpb->num_disks = 0; + for (i = 0; i < info->failed_disks; i++) { + struct imsm_disk *disk; + + mpb->num_disks++; + disk = __get_imsm_disk(mpb, i); + disk->status = CONFIGURED_DISK | FAILED_DISK; + disk->scsi_id = __cpu_to_le32(~(__u32)0); + snprintf((char *) disk->serial, MAX_RAID_SERIAL_LEN, + "missing:%d", i); + } + find_missing(super); + } else { + int missing = 0; + struct dl *d; + + for (d = super->missing; d; d = d->next) + missing++; + if (info->failed_disks > missing) { + fprintf(stderr, Name": unable to add 'missing' disk to container\n"); + return 0; + } + } if (!check_name(super, name, 0)) return 0; @@ -4170,15 +4196,14 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info, vol = &dev->vol; vol->migr_state = 0; set_migr_type(dev, MIGR_INIT); - vol->dirty = 0; + vol->dirty = !info->state; vol->curr_migr_unit = 0; map = get_imsm_map(dev, 0); map->pba_of_lba0 = __cpu_to_le32(super->create_offset); map->blocks_per_member = __cpu_to_le32(info_to_blocks_per_member(info)); map->blocks_per_strip = __cpu_to_le16(info_to_blocks_per_strip(info)); map->failed_disk_num = ~0; - map->map_state = info->level ? IMSM_T_STATE_UNINITIALIZED : - IMSM_T_STATE_NORMAL; + map->map_state = info->failed_disks ? IMSM_T_STATE_DEGRADED : IMSM_T_STATE_NORMAL; map->ddf = 1; if (info->level == 1 && info->raid_disks > 2) { @@ -4286,9 +4311,10 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk, { struct intel_super *super = st->sb; struct imsm_super *mpb = super->anchor; - struct dl *dl; + struct imsm_disk *_disk; struct imsm_dev *dev; struct imsm_map *map; + struct dl *dl, *df; int slot; dev = get_imsm_dev(super, super->current_vol); @@ -4335,12 +4361,37 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk, set_imsm_ord_tbl_ent(map, dk->raid_disk, dl->index); dl->disk.status = CONFIGURED_DISK; + /* update size of 'missing' disks to be at least as large as the + * largest acitve member (we only have dummy missing disks when + * creating the first volume) + */ + if (super->current_vol == 0) { + for (df = super->missing; df; df = df->next) { + if (dl->disk.total_blocks > df->disk.total_blocks) + df->disk.total_blocks = dl->disk.total_blocks; + _disk = __get_imsm_disk(mpb, df->index); + *_disk = df->disk; + } + } + + /* refresh unset/failed slots to point to valid 'missing' entries */ + for (df = super->missing; df; df = df->next) + for (slot = 0; slot < mpb->num_disks; slot++) { + __u32 ord = get_imsm_ord_tbl_ent(dev, slot, -1); + + if ((ord & IMSM_ORD_REBUILD) == 0) + continue; + set_imsm_ord_tbl_ent(map, slot, df->index | IMSM_ORD_REBUILD); + dprintf("set slot:%d to missing disk:%d\n", slot, df->index); + break; + } + /* if we are creating the first raid device update the family number */ if (super->current_vol == 0) { __u32 sum; struct imsm_dev *_dev = __get_imsm_dev(mpb, 0); - struct imsm_disk *_disk = __get_imsm_disk(mpb, dl->index); + _disk = __get_imsm_disk(mpb, dl->index); if (!_dev || !_disk) { fprintf(stderr, Name ": BUG mpb setup error\n"); return 1; -- cgit v1.2.3