/* 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 */
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));
}
-
-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;
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;
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.
{
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]);
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);
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
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();
} 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));
"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;
}
}
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;
__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: {
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
*/
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;
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->type != sec->hba->type) {
+ fprintf(stderr,
+ "HBAs of devices does not match %s != %s\n",
+ get_sys_dev_type(first->hba->type),
+ get_sys_dev_type(sec->hba->type));
+ return 3;
+ }
+ }
/* if an anchor does not have num_raid_devs set then it is a free
* floating spare
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;
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;
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)
{
}
__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)
free(super->buf);
super->buf = NULL;
}
+ /* unlink capability description */
+ super->orom = NULL;
if (free_disks)
free_imsm_disks(super);
free_devlist(super);
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
struct intel_super *s = alloc_super();
char nm[32];
int dfd;
+ int rv;
err = 1;
if (!s)
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 */
sizeof(*super));
return 1;
}
+ rv = find_intel_hba_capability(fd, super, devname);
+ /* no orom/efi or non-intel hba of the disk */
+ if (rv != 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);
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);
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);
* 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)
{
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)
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;
}
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)
layout, level);
return 0;
}
-
return 1;
}
* 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)
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
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) ||
if (size == 0) {
size = maxsize;
if (chunk) {
- size /= chunk;
- size *= chunk;
+ size /= 2 * chunk;
+ size *= 2 * chunk;
}
}
}
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)
{
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);
}
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;
}
return 0;
}
-#endif /* MDASSEMBLE */
static int is_gen_migration(struct imsm_dev *dev)
{
return 0;
}
+#endif /* MDASSEMBLE */
static int is_rebuilding(struct imsm_dev *dev)
{
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 &&
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",
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;
}
/* 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;
}
__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);
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;
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)
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;
* 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;
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++;
}
}
*/
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.
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);
- }
+ }
}
}
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) {
super->updates_pending++;
}
- /* manage online capacity expansion/reshape */
- if ((a->curr_action != reshape) &&
- (a->prev_action == reshape)) {
- struct mdinfo *mdi;
-
- /* 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);
-
- /* check next volume reshape */
- imsm_progress_container_reshape(super);
- }
-
return consistent;
}
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) ||
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++) {
/* 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;
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;
*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;
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 */
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;
}
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;
}
__free_imsm_disk(dl);
}
}
-#endif /* MDASSEMBLE */
static char disk_by_path[] = "/dev/disk/by-path/";
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;
}
struct mdinfo info;
int change = -1;
int check_devs = 0;
+ int chunk;
getinfo_super_imsm_volume(st, &info, NULL);
switch (info.array.level) {
case 0:
if (geo->level == 5) {
- change = CH_LEVEL_MIGRATION;
+ change = CH_MIGRATION;
check_devs = 1;
}
if (geo->level == 10) {
}
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) {
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)) {
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;
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;
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);
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
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:
afd, sra, reshape, st, stripes,
fds, offsets, dests, destfd, destoffsets);
}
+#endif /* MDASSEMBLE */
struct superswitch super_imsm = {
#ifndef MDASSEMBLE
.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,
.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",