X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=super-intel.c;h=2b41e086bf19d73c4d240160ff106cb3ce47b501;hb=ea2bc72b0049f7d02156bae8f21736ddd93e731e;hp=8484df65be9517c8bb5268182961e10d785eb468;hpb=d098291aec0152a52b4f80d7cb4486b5abe1e0d4;p=thirdparty%2Fmdadm.git diff --git a/super-intel.c b/super-intel.c index 8484df65..2b41e086 100644 --- a/super-intel.c +++ b/super-intel.c @@ -294,8 +294,7 @@ struct extent { /* definitions of reshape process types */ enum imsm_reshape_type { CH_TAKEOVER, - CH_CHUNK_MIGR, - CH_LEVEL_MIGRATION + CH_MIGRATION, }; /* definition of messages passed to imsm_process_update */ @@ -384,6 +383,7 @@ const char *get_sys_dev_type(enum sys_dev_type type) return _sys_dev_type[type]; } +#ifndef MDASSEMBLE static struct intel_hba * alloc_intel_hba(struct sys_dev *device) { struct intel_hba *result = malloc(sizeof(*result)); @@ -408,9 +408,7 @@ static struct intel_hba * find_intel_hba(struct intel_hba *hba, struct sys_dev * } - -static int attach_hba_to_super(struct intel_super *super, struct sys_dev *device, - const char *devname) +static int attach_hba_to_super(struct intel_super *super, struct sys_dev *device) { struct intel_hba *hba; @@ -475,8 +473,12 @@ static struct sys_dev* find_disk_attached_hba(int fd, const char *devname) return NULL; } +#endif /* MDASSEMBLE */ +static int find_intel_hba_capability(int fd, struct intel_super *super, + char *devname); + static struct supertype *match_metadata_desc_imsm(char *arg) { struct supertype *st; @@ -564,17 +566,24 @@ static size_t sizeof_imsm_map(struct imsm_map *map) struct imsm_map *get_imsm_map(struct imsm_dev *dev, int second_map) { + /* A device can have 2 maps if it is in the middle of a migration. + * If second_map is: + * 0 - we return the first map + * 1 - we return the second map if it exists, else NULL + * -1 - we return the second map if it exists, else the first + */ struct imsm_map *map = &dev->vol.map[0]; - if (second_map && !dev->vol.migr_state) + if (second_map == 1 && !dev->vol.migr_state) return NULL; - else if (second_map) { + else if (second_map == 1 || + (second_map < 0 && dev->vol.migr_state)) { void *ptr = map; return ptr + sizeof_imsm_map(map); } else return map; - + } /* return the size of the device. @@ -653,14 +662,7 @@ static __u32 get_imsm_ord_tbl_ent(struct imsm_dev *dev, { struct imsm_map *map; - if (second_map == -1) { - if (dev->vol.migr_state) - map = get_imsm_map(dev, 1); - else - map = get_imsm_map(dev, 0); - } else { - map = get_imsm_map(dev, second_map); - } + map = get_imsm_map(dev, second_map); /* top byte identifies disk under rebuild */ return __le32_to_cpu(map->disk_ord_tbl[slot]); @@ -897,6 +899,12 @@ static void print_imsm_dev(struct imsm_dev *dev, char *uuid, int disk_idx) printf("]"); } printf("\n"); + printf(" Failed disk : "); + if (map->failed_disk_num == 0xff) + printf("none"); + else + printf("%i", map->failed_disk_num); + printf("\n"); slot = get_imsm_disk_slot(map, disk_idx); if (slot >= 0) { ord = get_imsm_ord_tbl_ent(dev, slot, -1); @@ -1341,6 +1349,39 @@ static int ahci_get_port_count(const char *hba_path, int *port_count) return host_base; } +static void print_imsm_capability(const struct imsm_orom *orom) +{ + printf(" Platform : Intel(R) Matrix Storage Manager\n"); + printf(" Version : %d.%d.%d.%d\n", orom->major_ver, orom->minor_ver, + orom->hotfix_ver, orom->build); + printf(" RAID Levels :%s%s%s%s%s\n", + imsm_orom_has_raid0(orom) ? " raid0" : "", + imsm_orom_has_raid1(orom) ? " raid1" : "", + imsm_orom_has_raid1e(orom) ? " raid1e" : "", + imsm_orom_has_raid10(orom) ? " raid10" : "", + imsm_orom_has_raid5(orom) ? " raid5" : ""); + printf(" Chunk Sizes :%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + imsm_orom_has_chunk(orom, 2) ? " 2k" : "", + imsm_orom_has_chunk(orom, 4) ? " 4k" : "", + imsm_orom_has_chunk(orom, 8) ? " 8k" : "", + imsm_orom_has_chunk(orom, 16) ? " 16k" : "", + imsm_orom_has_chunk(orom, 32) ? " 32k" : "", + imsm_orom_has_chunk(orom, 64) ? " 64k" : "", + imsm_orom_has_chunk(orom, 128) ? " 128k" : "", + imsm_orom_has_chunk(orom, 256) ? " 256k" : "", + imsm_orom_has_chunk(orom, 512) ? " 512k" : "", + imsm_orom_has_chunk(orom, 1024*1) ? " 1M" : "", + imsm_orom_has_chunk(orom, 1024*2) ? " 2M" : "", + imsm_orom_has_chunk(orom, 1024*4) ? " 4M" : "", + imsm_orom_has_chunk(orom, 1024*8) ? " 8M" : "", + imsm_orom_has_chunk(orom, 1024*16) ? " 16M" : "", + imsm_orom_has_chunk(orom, 1024*32) ? " 32M" : "", + imsm_orom_has_chunk(orom, 1024*64) ? " 64M" : ""); + printf(" Max Disks : %d\n", orom->tds); + printf(" Max Volumes : %d\n", orom->vpa); + return; +} + static int detail_platform_imsm(int verbose, int enumerate_only) { /* There are two components to imsm platform support, the ahci SATA @@ -1361,9 +1402,20 @@ static int detail_platform_imsm(int verbose, int enumerate_only) int result=0; if (enumerate_only) { - if (check_env("IMSM_NO_PLATFORM") || find_imsm_orom()) + if (check_env("IMSM_NO_PLATFORM")) return 0; - return 2; + list = find_intel_devices(); + if (!list) + return 2; + for (hba = list; hba; hba = hba->next) { + orom = find_imsm_capability(hba->type); + if (!orom) { + result = 2; + break; + } + } + free_sys_dev(&list); + return result; } list = find_intel_devices(); @@ -1376,43 +1428,15 @@ static int detail_platform_imsm(int verbose, int enumerate_only) } else if (verbose) print_found_intel_controllers(list); - orom = find_imsm_orom(); - if (!orom) { - free_sys_dev(&list); - if (verbose) - fprintf(stderr, Name ": imsm option-rom not found\n"); - return 2; + for (hba = list; hba; hba = hba->next) { + orom = find_imsm_capability(hba->type); + if (!orom) + fprintf(stderr, Name ": imsm capabilities not found for controller: %s (type %s)\n", + hba->path, get_sys_dev_type(hba->type)); + else + print_imsm_capability(orom); } - printf(" Platform : Intel(R) Matrix Storage Manager\n"); - printf(" Version : %d.%d.%d.%d\n", orom->major_ver, orom->minor_ver, - orom->hotfix_ver, orom->build); - printf(" RAID Levels :%s%s%s%s%s\n", - imsm_orom_has_raid0(orom) ? " raid0" : "", - imsm_orom_has_raid1(orom) ? " raid1" : "", - imsm_orom_has_raid1e(orom) ? " raid1e" : "", - imsm_orom_has_raid10(orom) ? " raid10" : "", - imsm_orom_has_raid5(orom) ? " raid5" : ""); - printf(" Chunk Sizes :%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", - imsm_orom_has_chunk(orom, 2) ? " 2k" : "", - imsm_orom_has_chunk(orom, 4) ? " 4k" : "", - imsm_orom_has_chunk(orom, 8) ? " 8k" : "", - imsm_orom_has_chunk(orom, 16) ? " 16k" : "", - imsm_orom_has_chunk(orom, 32) ? " 32k" : "", - imsm_orom_has_chunk(orom, 64) ? " 64k" : "", - imsm_orom_has_chunk(orom, 128) ? " 128k" : "", - imsm_orom_has_chunk(orom, 256) ? " 256k" : "", - imsm_orom_has_chunk(orom, 512) ? " 512k" : "", - imsm_orom_has_chunk(orom, 1024*1) ? " 1M" : "", - imsm_orom_has_chunk(orom, 1024*2) ? " 2M" : "", - imsm_orom_has_chunk(orom, 1024*4) ? " 4M" : "", - imsm_orom_has_chunk(orom, 1024*8) ? " 8M" : "", - imsm_orom_has_chunk(orom, 1024*16) ? " 16M" : "", - imsm_orom_has_chunk(orom, 1024*32) ? " 32M" : "", - imsm_orom_has_chunk(orom, 1024*64) ? " 64M" : ""); - printf(" Max Disks : %d\n", orom->tds); - printf(" Max Volumes : %d\n", orom->vpa); - for (hba = list; hba; hba = hba->next) { printf(" I/O Controller : %s (%s)\n", hba->path, get_sys_dev_type(hba->type)); @@ -1425,11 +1449,6 @@ static int detail_platform_imsm(int verbose, int enumerate_only) "ports on SATA controller at %s.", hba->pci_id); result |= 2; } - } else if (hba->type == SYS_DEV_SAS) { - if (verbose) - fprintf(stderr, Name ": failed to enumerate " - "devices on SAS controller at %s.", hba->pci_id); - result |= 2; } } @@ -1750,14 +1769,53 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info, info->custom_array_size = __le32_to_cpu(dev->size_high); info->custom_array_size <<= 32; info->custom_array_size |= __le32_to_cpu(dev->size_low); - if (prev_map) { + if (prev_map && map->map_state == prev_map->map_state) { + info->reshape_active = 1; info->new_level = get_imsm_raid_level(map); info->new_layout = imsm_level_to_layout(info->new_level); info->new_chunk = __le16_to_cpu(map->blocks_per_strip) << 9; + info->delta_disks = map->num_members - prev_map->num_members; + if (info->delta_disks) { + /* this needs to be applied to every array + * in the container. + */ + info->reshape_active = 2; + } + /* We shape information that we give to md might have to be + * modify to cope with md's requirement for reshaping arrays. + * For example, when reshaping a RAID0, md requires it to be + * presented as a degraded RAID4. + * Also if a RAID0 is migrating to a RAID5 we need to specify + * the array as already being RAID5, but the 'before' layout + * is a RAID4-like layout. + */ + switch (info->array.level) { + case 0: + switch(info->new_level) { + case 0: + /* conversion is happening as RAID4 */ + info->array.level = 4; + info->array.raid_disks += 1; + break; + case 5: + /* conversion is happening as RAID5 */ + info->array.level = 5; + info->array.layout = ALGORITHM_PARITY_N; + info->array.raid_disks += 1; + info->delta_disks -= 1; + break; + default: + /* FIXME error message */ + info->array.level = UnSet; + break; + } + break; + } } else { info->new_level = UnSet; info->new_layout = UnSet; info->new_chunk = info->array.chunk_size; + info->delta_disks = 0; } info->disk.major = 0; info->disk.minor = 0; @@ -1771,16 +1829,14 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info, __le32_to_cpu(map_to_analyse->blocks_per_member); memset(info->uuid, 0, sizeof(info->uuid)); info->recovery_start = MaxSector; - info->reshape_active = (prev_map != NULL); - if (info->reshape_active) - info->delta_disks = map->num_members - prev_map->num_members; - else - info->delta_disks = 0; + info->reshape_progress = 0; + info->resync_start = MaxSector; if (map_to_analyse->map_state == IMSM_T_STATE_UNINITIALIZED || dev->vol.dirty) { info->resync_start = 0; - } else if (dev->vol.migr_state) { + } + if (dev->vol.migr_state) { switch (migr_type(dev)) { case MIGR_REPAIR: case MIGR_INIT: { @@ -1790,6 +1846,34 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info, info->resync_start = blocks_per_unit * units; break; } + case MIGR_GEN_MIGR: { + __u64 blocks_per_unit = blocks_per_migr_unit(dev); + __u64 units = __le32_to_cpu(dev->vol.curr_migr_unit); + unsigned long long array_blocks; + int used_disks; + + info->reshape_progress = blocks_per_unit * units; + + /* checkpoint is written per disks unit + * recalculate it to reshape position + */ + used_disks = imsm_num_data_members(dev, 0); + info->reshape_progress *= used_disks; + dprintf("IMSM: General Migration checkpoint : %llu " + "(%llu) -> read reshape progress : %llu\n", + units, blocks_per_unit, info->reshape_progress); + + used_disks = imsm_num_data_members(dev, 1); + if (used_disks > 0) { + array_blocks = map->blocks_per_member * + used_disks; + /* round array size down to closest MB + */ + info->custom_array_size = (array_blocks + >> SECT_PER_MB_SHIFT) + << SECT_PER_MB_SHIFT; + } + } case MIGR_VERIFY: /* we could emulate the checkpointing of * 'sync_action=check' migrations, but for now @@ -1797,15 +1881,13 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info, */ case MIGR_REBUILD: /* this is handled by container_content_imsm() */ - case MIGR_GEN_MIGR: case MIGR_STATE_CHANGE: /* FIXME handle other migrations */ default: /* we are not dirty, so... */ info->resync_start = MaxSector; } - } else - info->resync_start = MaxSector; + } strncpy(info->name, (char *) dev->volume, MAX_RAID_SERIAL_LEN); info->name[MAX_RAID_SERIAL_LEN] = 0; @@ -2132,6 +2214,19 @@ static int compare_super_imsm(struct supertype *st, struct supertype *tst) tst->sb = NULL; return 0; } + /* in platform dependent environment test if the disks + * use the same Intel hba + */ + if (!check_env("IMSM_NO_PLATFORM")) { + if (!first->hba || !sec->hba || + (first->hba->type != sec->hba->type)) { + fprintf(stderr, + "HBAs of devices does not match %s != %s\n", + first->hba ? get_sys_dev_type(first->hba->type) : NULL, + sec->hba ? get_sys_dev_type(sec->hba->type) : NULL); + return 3; + } + } /* if an anchor does not have num_raid_devs set then it is a free * floating spare @@ -2471,6 +2566,7 @@ static int parse_raid_devices(struct intel_super *super) int i; struct imsm_dev *dev_new; size_t len, len_migr; + size_t max_len = 0; size_t space_needed = 0; struct imsm_super *mpb = super->anchor; @@ -2486,7 +2582,11 @@ static int parse_raid_devices(struct intel_super *super) dv = malloc(sizeof(*dv)); if (!dv) return 1; - dev_new = malloc(len_migr); + if (max_len < len_migr) + max_len = len_migr; + if (max_len > len_migr) + space_needed += max_len - len_migr; + dev_new = malloc(max_len); if (!dev_new) { free(dv); return 1; @@ -2534,7 +2634,7 @@ struct bbm_log *__get_imsm_bbm_log(struct imsm_super *mpb) static void __free_imsm(struct intel_super *super, int free_disks); /* load_imsm_mpb - read matrix metadata - * allocates super->mpb to be freed by free_super + * allocates super->mpb to be freed by free_imsm */ static int load_imsm_mpb(int fd, struct intel_super *super, char *devname) { @@ -2586,6 +2686,10 @@ static int load_imsm_mpb(int fd, struct intel_super *super, char *devname) } __free_imsm(super, 0); + /* reload capability and hba */ + + /* capability and hba must be updated with new super allocation */ + find_intel_hba_capability(fd, super, devname); super->len = ROUND_UP(anchor->mpb_size, 512); if (posix_memalign(&super->buf, 512, super->len) != 0) { if (devname) @@ -2709,6 +2813,8 @@ static void __free_imsm(struct intel_super *super, int free_disks) free(super->buf); super->buf = NULL; } + /* unlink capability description */ + super->orom = NULL; if (free_disks) free_imsm_disks(super); free_devlist(super); @@ -2748,13 +2854,66 @@ static struct intel_super *alloc_super(void) memset(super, 0, sizeof(*super)); super->current_vol = -1; super->create_offset = ~((__u32 ) 0); - if (!check_env("IMSM_NO_PLATFORM")) - super->orom = find_imsm_orom(); } - return super; } +/* + * find and allocate hba and OROM/EFI based on valid fd of RAID component device + */ +static int find_intel_hba_capability(int fd, struct intel_super *super, char *devname) +{ + struct sys_dev *hba_name; + int rv = 0; + + if ((fd < 0) || check_env("IMSM_NO_PLATFORM")) { + super->orom = NULL; + super->hba = NULL; + return 0; + } + hba_name = find_disk_attached_hba(fd, NULL); + if (!hba_name) { + if (devname) + fprintf(stderr, + Name ": %s is not attached to Intel(R) RAID controller.\n", + devname); + return 1; + } + rv = attach_hba_to_super(super, hba_name); + if (rv == 2) { + if (devname) { + struct intel_hba *hba = super->hba; + + fprintf(stderr, Name ": %s is attached to Intel(R) %s RAID " + "controller (%s),\n" + " but the container is assigned to Intel(R) " + "%s RAID controller (", + devname, + hba_name->path, + hba_name->pci_id ? : "Err!", + get_sys_dev_type(hba_name->type)); + + while (hba) { + fprintf(stderr, "%s", hba->pci_id ? : "Err!"); + if (hba->next) + fprintf(stderr, ", "); + hba = hba->next; + } + + fprintf(stderr, ").\n" + " Mixing devices attached to different controllers " + "is not allowed.\n"); + } + free_sys_dev(&hba_name); + return 2; + } + super->orom = find_imsm_capability(hba_name->type); + free_sys_dev(&hba_name); + if (!super->orom) + return 3; + 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 @@ -3135,6 +3294,7 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp, struct intel_super *s = alloc_super(); char nm[32]; int dfd; + int rv; err = 1; if (!s) @@ -3148,6 +3308,11 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp, if (dfd < 0) goto error; + rv = find_intel_hba_capability(dfd, s, devname); + /* no orom/efi or non-intel hba of the disk */ + if (rv != 0) + goto error; + err = load_and_parse_mpb(dfd, s, NULL, 1); /* retry the load if we might have raced against mdmon */ @@ -3222,7 +3387,19 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname) sizeof(*super)); return 1; } - + /* Load hba and capabilities if they exist. + * But do not preclude loading metadata in case capabilities or hba are + * non-compliant and ignore_hw_compat is set. + */ + rv = find_intel_hba_capability(fd, super, devname); + /* no orom/efi or non-intel hba of the disk */ + if ((rv != 0) && (st->ignore_hw_compat == 0)) { + if (devname) + fprintf(stderr, + Name ": No OROM/EFI properties for %s\n", devname); + free_imsm(super); + return 2; + } rv = load_and_parse_mpb(fd, super, devname, 0); if (rv) { @@ -3397,12 +3574,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); @@ -3415,8 +3593,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); @@ -3615,43 +3792,12 @@ static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk, * We do not need to test disks attachment for container based additions, * they shall be already tested when container was created/assembled. */ - if ((fd != -1) && !check_env("IMSM_NO_PLATFORM")) { - struct sys_dev *hba_name; - struct intel_hba *hba; - - hba_name = find_disk_attached_hba(fd, NULL); - if (!hba_name) { - fprintf(stderr, - Name ": %s is not attached to Intel(R) RAID controller.\n", - devname ? : "disk"); - return 1; - } - rv = attach_hba_to_super(super, hba_name, devname); - switch (rv) { - case 2: - fprintf(stderr, Name ": %s is attached to Intel(R) %s RAID " - "controller (%s),\n but the container is assigned to Intel(R) " - "%s RAID controller (", - devname, - get_sys_dev_type(hba_name->type), - hba_name->pci_id ? : "Err!", - get_sys_dev_type(hba_name->type)); - - hba = super->hba; - while (hba) { - fprintf(stderr, "%s", hba->pci_id ? : "Err!"); - if (hba->next) - fprintf(stderr, ", "); - hba = hba->next; - } - - fprintf(stderr, ").\n" - " Mixing devices attached to different controllers " - "is not allowed.\n"); - free_sys_dev(&hba_name); - return 1; - } - free_sys_dev(&hba_name); + rv = find_intel_hba_capability(fd, super, devname); + /* no orom/efi or non-intel hba of the disk */ + if (rv != 0) { + dprintf("capability: %p fd: %d ret: %d\n", + super->orom, fd, rv); + return 1; } if (super->current_vol >= 0) @@ -3696,6 +3842,7 @@ static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk, } else { dd->next = super->disks; super->disks = dd; + super->updates_pending++; } return 0; @@ -3983,25 +4130,14 @@ static int validate_geometry_imsm_container(struct supertype *st, int level, { int fd; unsigned long long ldsize; - const struct imsm_orom *orom; + struct intel_super *super=NULL; + int rv = 0; if (level != LEVEL_CONTAINER) return 0; if (!dev) return 1; - if (check_env("IMSM_NO_PLATFORM")) - orom = NULL; - else - orom = find_imsm_orom(); - if (orom && raiddisks > orom->tds) { - if (verbose) - fprintf(stderr, Name ": %d exceeds maximum number of" - " platform supported disks: %d\n", - raiddisks, orom->tds); - return 0; - } - fd = open(dev, O_RDONLY|O_EXCL, 0); if (fd < 0) { if (verbose) @@ -4013,9 +4149,45 @@ static int validate_geometry_imsm_container(struct supertype *st, int level, close(fd); return 0; } + + /* capabilities retrieve could be possible + * note that there is no fd for the disks in array. + */ + super = alloc_super(); + if (!super) { + fprintf(stderr, + Name ": malloc of %zu failed.\n", + sizeof(*super)); + close(fd); + return 0; + } + + rv = find_intel_hba_capability(fd, super, verbose ? dev : NULL); + if (rv != 0) { +#if DEBUG + char str[256]; + fd2devname(fd, str); + dprintf("validate_geometry_imsm_container: fd: %d %s orom: %p rv: %d raiddisk: %d\n", + fd, str, super->orom, rv, raiddisks); +#endif + /* no orom/efi or non-intel hba of the disk */ + close(fd); + free_imsm(super); + return 0; + } close(fd); + if (super->orom && raiddisks > super->orom->tds) { + if (verbose) + fprintf(stderr, Name ": %d exceeds maximum number of" + " platform supported disks: %d\n", + raiddisks, super->orom->tds); + + free_imsm(super); + return 0; + } *freesize = avail_size_imsm(st, ldsize >> 9); + free_imsm(super); return 1; } @@ -4150,20 +4322,42 @@ static int is_raid_level_supported(const struct imsm_orom *orom, int level, int return 0; } + #define pr_vrb(fmt, arg...) (void) (verbose && fprintf(stderr, Name fmt, ##arg)) +/* + * validate volume parameters with OROM/EFI capabilities + */ static int validate_geometry_imsm_orom(struct intel_super *super, int level, int layout, - int raiddisks, int chunk, int verbose) + int raiddisks, int *chunk, int verbose) { - if (!is_raid_level_supported(super->orom, level, raiddisks)) { +#if DEBUG + verbose = 1; +#endif + /* validate container capabilities */ + if (super->orom && raiddisks > super->orom->tds) { + if (verbose) + fprintf(stderr, Name ": %d exceeds maximum number of" + " platform supported disks: %d\n", + raiddisks, super->orom->tds); + return 0; + } + + /* capabilities of OROM tested - copied from validate_geometry_imsm_volume */ + if (super->orom && (!is_raid_level_supported(super->orom, level, + raiddisks))) { pr_vrb(": platform does not support raid%d with %d disk%s\n", level, raiddisks, raiddisks > 1 ? "s" : ""); return 0; } - if (super->orom && level != 1 && - !imsm_orom_has_chunk(super->orom, chunk)) { - pr_vrb(": platform does not support a chunk size of: %d\n", chunk); - return 0; + if (super->orom && level != 1) { + if (chunk && (*chunk == 0 || *chunk == UnSet)) + *chunk = imsm_orom_default_chunk(super->orom); + else if (chunk && !imsm_orom_has_chunk(super->orom, *chunk)) { + pr_vrb(": platform does not support a chunk size of: " + "%d\n", *chunk); + return 0; + } } if (layout != imsm_level_to_layout(level)) { if (level == 5) @@ -4175,7 +4369,6 @@ validate_geometry_imsm_orom(struct intel_super *super, int level, int layout, layout, level); return 0; } - return 1; } @@ -4183,7 +4376,7 @@ validate_geometry_imsm_orom(struct intel_super *super, int level, int layout, * FIX ME add ahci details */ static int validate_geometry_imsm_volume(struct supertype *st, int level, - int layout, int raiddisks, int chunk, + int layout, int raiddisks, int *chunk, unsigned long long size, char *dev, unsigned long long *freesize, int verbose) @@ -4201,9 +4394,11 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level, if (!super) return 0; - if (!validate_geometry_imsm_orom(super, level, layout, raiddisks, chunk, verbose)) + if (!validate_geometry_imsm_orom(super, level, layout, raiddisks, chunk, verbose)) { + fprintf(stderr, Name ": RAID gemetry validation failed. " + "Cannot proceed with the action(s).\n"); return 0; - + } if (!dev) { /* General test: make sure there is space for * 'raiddisks' device extents of size 'size' at a given @@ -4372,7 +4567,8 @@ static int reserve_space(struct supertype *st, int raiddisks, maxsize = merge_extents(super, extent_cnt); minsize = size; if (size == 0) - minsize = chunk; + /* chunk is in K */ + minsize = chunk * 2; if (cnt < raiddisks || (super->orom && used && used != raiddisks) || @@ -4385,8 +4581,8 @@ static int reserve_space(struct supertype *st, int raiddisks, if (size == 0) { size = maxsize; if (chunk) { - size /= chunk; - size *= chunk; + size /= 2 * chunk; + size *= 2 * chunk; } } @@ -4401,7 +4597,7 @@ static int reserve_space(struct supertype *st, int raiddisks, } static int validate_geometry_imsm(struct supertype *st, int level, int layout, - int raiddisks, int chunk, unsigned long long size, + int raiddisks, int *chunk, unsigned long long size, char *dev, unsigned long long *freesize, int verbose) { @@ -4409,13 +4605,15 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout, struct mdinfo *sra; int is_member = 0; - /* if given unused devices create a container + /* load capability + * if given unused devices create a container * if given given devices in a container create a member volume */ if (level == LEVEL_CONTAINER) { /* Must be a fresh device to add to a container */ return validate_geometry_imsm_container(st, level, layout, - raiddisks, chunk, size, + raiddisks, + chunk?*chunk:0, size, dev, freesize, verbose); } @@ -4434,7 +4632,8 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout, raiddisks, chunk, verbose)) return 0; - return reserve_space(st, raiddisks, size, chunk, freesize); + return reserve_space(st, raiddisks, size, + chunk?*chunk:0, freesize); } return 1; } @@ -4641,7 +4840,6 @@ static int update_subarray_imsm(struct supertype *st, char *subarray, return 0; } -#endif /* MDASSEMBLE */ static int is_gen_migration(struct imsm_dev *dev) { @@ -4653,6 +4851,7 @@ static int is_gen_migration(struct imsm_dev *dev) return 0; } +#endif /* MDASSEMBLE */ static int is_rebuilding(struct imsm_dev *dev) { @@ -4719,17 +4918,25 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra struct mdinfo *rest = NULL; unsigned int i; int bbm_errors = 0; + struct dl *d; + int spare_disks = 0; /* check for bad blocks */ if (imsm_bbm_log_size(super->anchor)) bbm_errors = 1; + /* count spare devices, not used in maps + */ + for (d = super->disks; d; d = d->next) + if (d->index == -1) + spare_disks++; + for (i = 0; i < mpb->num_raid_devs; i++) { struct imsm_dev *dev; struct imsm_map *map; struct imsm_map *map2; struct mdinfo *this; - int slot; + int slot, chunk; char *ep; if (subarray && @@ -4750,7 +4957,21 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra dev->volume); continue; } + /* do not publish arrays that are not support by controller's + * OROM/EFI + */ + chunk = __le16_to_cpu(map->blocks_per_strip) >> 1; + if (!validate_geometry_imsm_orom(super, + get_imsm_raid_level(map), /* RAID level */ + imsm_level_to_layout(get_imsm_raid_level(map)), + map->num_members, /* raid disks */ + &chunk, + 1 /* verbose */)) { + fprintf(stderr, Name ": RAID gemetry validation failed. " + "Cannot proceed with the action(s).\n"); + continue; + } this = malloc(sizeof(*this)); if (!this) { fprintf(stderr, Name ": failed to allocate %zu bytes\n", @@ -4772,7 +4993,7 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra skip = 0; idx = get_imsm_disk_idx(dev, slot, 0); - ord = get_imsm_ord_tbl_ent(dev, slot, 0); + ord = get_imsm_ord_tbl_ent(dev, slot, -1); for (d = super->disks; d ; d = d->next) if (d->index == idx) break; @@ -4840,6 +5061,7 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra } /* now that the disk list is up-to-date fixup recovery_start */ update_recovery_start(dev, this); + this->array.spare_disks += spare_disks; rest = this; } @@ -4996,6 +5218,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); @@ -5008,8 +5232,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; @@ -5045,6 +5273,37 @@ static void handle_missing(struct intel_super *super, struct imsm_dev *dev) super->updates_pending++; } +static unsigned long long imsm_set_array_size(struct imsm_dev *dev) +{ + int used_disks = imsm_num_data_members(dev, 0); + unsigned long long array_blocks; + struct imsm_map *map; + + if (used_disks == 0) { + /* when problems occures + * return current array_blocks value + */ + array_blocks = __le32_to_cpu(dev->size_high); + array_blocks = array_blocks << 32; + array_blocks += __le32_to_cpu(dev->size_low); + + return array_blocks; + } + + /* set array size in metadata + */ + map = get_imsm_map(dev, 0); + array_blocks = map->blocks_per_member * used_disks; + + /* round array size down to closest MB + */ + array_blocks = (array_blocks >> SECT_PER_MB_SHIFT) << SECT_PER_MB_SHIFT; + dev->size_low = __cpu_to_le32((__u32)array_blocks); + dev->size_high = __cpu_to_le32((__u32)(array_blocks >> 32)); + + return array_blocks; +} + static void imsm_set_disk(struct active_array *a, int n, int state); static void imsm_progress_container_reshape(struct intel_super *super) @@ -5057,13 +5316,13 @@ static void imsm_progress_container_reshape(struct intel_super *super) struct imsm_super *mpb = super->anchor; int prev_disks = -1; int i; + int copy_map_size; for (i = 0; i < mpb->num_raid_devs; i++) { struct imsm_dev *dev = get_imsm_dev(super, i); struct imsm_map *map = get_imsm_map(dev, 0); struct imsm_map *map2; int prev_num_members; - int used_disks; if (dev->vol.migr_state) return; @@ -5077,6 +5336,7 @@ static void imsm_progress_container_reshape(struct intel_super *super) * i.e it needs a migr_state */ + copy_map_size = sizeof_imsm_map(map); prev_num_members = map->num_members; map->num_members = prev_disks; dev->vol.migr_state = 1; @@ -5087,29 +5347,10 @@ static void imsm_progress_container_reshape(struct intel_super *super) set_imsm_ord_tbl_ent(map, i, i); map2 = get_imsm_map(dev, 1); /* Copy the current map */ - memcpy(map2, map, sizeof_imsm_map(map)); + memcpy(map2, map, copy_map_size); map2->num_members = prev_num_members; - /* calculate new size - */ - used_disks = imsm_num_data_members(dev, 0); - if (used_disks) { - unsigned long long array_blocks; - - array_blocks = - map->blocks_per_member - * used_disks; - /* round array size down to closest MB - */ - array_blocks = (array_blocks - >> SECT_PER_MB_SHIFT) - << SECT_PER_MB_SHIFT; - dev->size_low = - __cpu_to_le32((__u32)array_blocks); - dev->size_high = - __cpu_to_le32( - (__u32)(array_blocks >> 32)); - } + imsm_set_array_size(dev); super->updates_pending++; } } @@ -5139,18 +5380,7 @@ static int imsm_set_array_state(struct active_array *a, int consistent) */ if (a->curr_action == reshape) { /* still reshaping, maybe update curr_migr_unit */ - long long blocks_per_unit = blocks_per_migr_unit(dev); - long long unit = a->last_checkpoint; - if (blocks_per_unit) { - unit /= blocks_per_unit; - if (unit > - __le32_to_cpu(dev->vol.curr_migr_unit)) { - dev->vol.curr_migr_unit = - __cpu_to_le32(unit); - super->updates_pending++; - } - } - return 0; + goto mark_checkpoint; } else { if (a->last_checkpoint == 0 && a->prev_action == reshape) { /* for some reason we aborted the reshape. @@ -5166,25 +5396,33 @@ static int imsm_set_array_state(struct active_array *a, int consistent) if (a->last_checkpoint >= a->info.component_size) { unsigned long long array_blocks; int used_disks; - /* it seems the reshape is all done */ - dev->vol.migr_state = 0; - dev->vol.migr_type = 0; - dev->vol.curr_migr_unit = 0; + struct mdinfo *mdi; + + used_disks = imsm_num_data_members(dev, 0); + if (used_disks > 0) { + array_blocks = + map->blocks_per_member * + used_disks; + /* round array size down to closest MB + */ + array_blocks = (array_blocks + >> SECT_PER_MB_SHIFT) + << SECT_PER_MB_SHIFT; + a->info.custom_array_size = array_blocks; + /* encourage manager to update array + * size + */ + + a->check_reshape = 1; + } + /* finalize online capacity expansion/reshape */ + for (mdi = a->info.devs; mdi; mdi = mdi->next) + imsm_set_disk(a, + mdi->disk.raid_disk, + mdi->curr_state); - used_disks = imsm_num_data_members(dev, -1); - array_blocks = map->blocks_per_member * used_disks; - /* round array size down to closest MB */ - array_blocks = (array_blocks >> SECT_PER_MB_SHIFT) - << SECT_PER_MB_SHIFT; - dev->size_low = __cpu_to_le32((__u32) array_blocks); - dev->size_high = __cpu_to_le32((__u32) (array_blocks >> 32)); - a->info.custom_array_size = array_blocks; - a->check_reshape = 1; /* encourage manager to update - * array size - */ - super->updates_pending++; imsm_progress_container_reshape(super); - } + } } } @@ -5219,6 +5457,7 @@ static int imsm_set_array_state(struct active_array *a, int consistent) super->updates_pending++; } +mark_checkpoint: /* check if we can update curr_migr_unit from resync_start, recovery_start */ blocks_per_unit = blocks_per_migr_unit(dev); if (blocks_per_unit) { @@ -5249,15 +5488,6 @@ static int imsm_set_array_state(struct active_array *a, int consistent) super->updates_pending++; } - /* finalize online capacity expansion/reshape */ - if ((a->curr_action != reshape) && - (a->prev_action == reshape)) { - struct mdinfo *mdi; - - for (mdi = a->info.devs; mdi; mdi = mdi->next) - imsm_set_disk(a, mdi->disk.raid_disk, mdi->curr_state); - } - return consistent; } @@ -5850,15 +6080,15 @@ static int apply_reshape_container_disks_update(struct imsm_update_reshape *u, int ret_val = 0; unsigned int dev_id; - dprintf("imsm: imsm_process_update() for update_reshape\n"); + dprintf("imsm: apply_reshape_container_disks_update()\n"); /* enable spares to use in array */ for (i = 0; i < delta_disks; i++) { new_disk = get_disk_super(super, major(u->new_disks[i]), minor(u->new_disks[i])); - dprintf("imsm: imsm_process_update(): new disk " - "for reshape is: %i:%i (%p, index = %i)\n", + dprintf("imsm: new disk for reshape is: %i:%i " + "(%p, index = %i)\n", major(u->new_disks[i]), minor(u->new_disks[i]), new_disk, new_disk->index); if ((new_disk == NULL) || @@ -5874,8 +6104,8 @@ static int apply_reshape_container_disks_update(struct imsm_update_reshape *u, new_disk->disk.status &= ~SPARE_DISK; } - dprintf("imsm: process_update(): update_reshape: volume set" - " mpb->num_raid_devs = %i\n", mpb->num_raid_devs); + dprintf("imsm: volume set mpb->num_raid_devs = %i\n", + mpb->num_raid_devs); /* manage changes in volume */ for (dev_id = 0; dev_id < mpb->num_raid_devs; dev_id++) { @@ -5902,10 +6132,8 @@ static int apply_reshape_container_disks_update(struct imsm_update_reshape *u, /* update one device only */ if (devices_to_reshape) { - int used_disks; - - dprintf("process_update(): modifying " - "subdev: %i\n", id->index); + dprintf("imsm: modifying subdev: %i\n", + id->index); devices_to_reshape--; newdev->vol.migr_state = 1; newdev->vol.curr_migr_unit = 0; @@ -5921,24 +6149,7 @@ static int apply_reshape_container_disks_update(struct imsm_update_reshape *u, newmap = get_imsm_map(newdev, 1); memcpy(newmap, oldmap, sizeof_imsm_map(oldmap)); - /* calculate new size - */ - used_disks = imsm_num_data_members(newdev, 0); - if (used_disks) { - unsigned long long array_blocks; - - array_blocks = - newmap->blocks_per_member * used_disks; - /* round array size down to closest MB - */ - array_blocks = (array_blocks - >> SECT_PER_MB_SHIFT) - << SECT_PER_MB_SHIFT; - newdev->size_low = - __cpu_to_le32((__u32)array_blocks); - newdev->size_high = - __cpu_to_le32((__u32)(array_blocks >> 32)); - } + imsm_set_array_size(newdev); } sp = (void **)id->dev; @@ -6020,8 +6231,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; @@ -6042,9 +6251,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 */ @@ -6055,9 +6263,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; } @@ -6106,8 +6315,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; } @@ -6628,7 +6839,6 @@ static void imsm_delete(struct intel_super *super, struct dl **dlp, unsigned ind __free_imsm_disk(dl); } } -#endif /* MDASSEMBLE */ static char disk_by_path[] = "/dev/disk/by-path/"; @@ -6837,7 +7047,8 @@ static int imsm_create_metadata_update_for_reshape( if (spares == NULL || delta_disks > spares->array.spare_disks) { - dprintf("imsm: ERROR: Cannot get spare devices.\n"); + fprintf(stderr, Name ": imsm: ERROR: Cannot get spare devices " + "for %s.\n", geo->dev_name); goto abort; } @@ -6911,6 +7122,7 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st, struct mdinfo info; int change = -1; int check_devs = 0; + int chunk; getinfo_super_imsm_volume(st, &info, NULL); @@ -6920,7 +7132,7 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st, switch (info.array.level) { case 0: if (geo->level == 5) { - change = CH_LEVEL_MIGRATION; + change = CH_MIGRATION; check_devs = 1; } if (geo->level == 10) { @@ -6935,8 +7147,8 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st, } break; case 5: - if (geo->level != 0) - change = CH_LEVEL_MIGRATION; + if (geo->level == 0) + change = CH_MIGRATION; break; case 10: if (geo->level == 0) { @@ -6957,7 +7169,7 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st, if ((geo->layout != info.array.layout) && ((geo->layout != UnSet) && (geo->layout != -1))) { - change = CH_LEVEL_MIGRATION; + change = CH_MIGRATION; if ((info.array.layout == 0) && (info.array.level == 5) && (geo->layout == 5)) { @@ -6981,15 +7193,16 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st, if ((geo->chunksize > 0) && (geo->chunksize != UnSet) && (geo->chunksize != info.array.chunk_size)) - change = CH_CHUNK_MIGR; + change = CH_MIGRATION; else geo->chunksize = info.array.chunk_size; + chunk = geo->chunksize / 1024; if (!validate_geometry_imsm(st, geo->level, geo->layout, geo->raid_disks, - (geo->chunksize / 1024), + &chunk, geo->size, 0, 0, 1)) change = -1; @@ -7048,14 +7261,15 @@ int imsm_takeover(struct supertype *st, struct geo_params *geo) static int imsm_reshape_super(struct supertype *st, long long size, int level, int layout, int chunksize, int raid_disks, - char *backup, char *dev, int verbose) + int delta_disks, char *backup, char *dev, + int verbose) { int ret_val = 1; struct geo_params geo; dprintf("imsm: reshape_super called.\n"); - memset(&geo, sizeof(struct geo_params), 0); + memset(&geo, 0, sizeof(struct geo_params)); geo.dev_name = dev; geo.dev_id = st->devnum; @@ -7064,6 +7278,8 @@ static int imsm_reshape_super(struct supertype *st, long long size, int level, geo.layout = layout; geo.chunksize = chunksize; geo.raid_disks = raid_disks; + if (delta_disks != UnSet) + geo.raid_disks += delta_disks; dprintf("\tfor level : %i\n", geo.level); dprintf("\tfor raid_disks : %i\n", geo.raid_disks); @@ -7098,8 +7314,8 @@ static int imsm_reshape_super(struct supertype *st, long long size, int level, free(u); } else { - fprintf(stderr, Name "imsm: Operation is not allowed " - "on this container\n"); + fprintf(stderr, Name ": (imsm) Operation " + "is not allowed on this container\n"); } } else { /* On volume level we support following operations @@ -7129,10 +7345,7 @@ static int imsm_reshape_super(struct supertype *st, long long size, int level, case CH_TAKEOVER: ret_val = imsm_takeover(st, &geo); break; - case CH_CHUNK_MIGR: - ret_val = 0; - break; - case CH_LEVEL_MIGRATION: + case CH_MIGRATION: ret_val = 0; break; default: @@ -7156,6 +7369,7 @@ static int imsm_manage_reshape( afd, sra, reshape, st, stripes, fds, offsets, dests, destfd, destoffsets); } +#endif /* MDASSEMBLE */ struct superswitch super_imsm = { #ifndef MDASSEMBLE @@ -7173,6 +7387,10 @@ struct superswitch super_imsm = { .kill_subarray = kill_subarray_imsm, .update_subarray = update_subarray_imsm, .load_container = load_container_imsm, + .default_geometry = default_geometry_imsm, + .get_disk_controller_domain = imsm_get_disk_controller_domain, + .reshape_super = imsm_reshape_super, + .manage_reshape = imsm_manage_reshape, #endif .match_home = match_home_imsm, .uuid_from_super= uuid_from_super_imsm, @@ -7191,10 +7409,6 @@ struct superswitch super_imsm = { .free_super = free_super_imsm, .match_metadata_desc = match_metadata_desc_imsm, .container_content = container_content_imsm, - .default_geometry = default_geometry_imsm, - .get_disk_controller_domain = imsm_get_disk_controller_domain, - .reshape_super = imsm_reshape_super, - .manage_reshape = imsm_manage_reshape, .external = 1, .name = "imsm",