enum imsm_reshape_type {
CH_TAKEOVER,
CH_MIGRATION,
+ CH_ARRAY_SIZE,
};
/* definition of messages passed to imsm_process_update */
update_reshape_migration,
update_takeover,
update_general_migration_checkpoint,
+ update_size_change,
};
struct imsm_update_activate_spare {
int new_disks[1]; /* new_raid_disks - old_raid_disks makedev number */
};
+struct imsm_update_size_change {
+ enum imsm_update_type type;
+ int subdev;
+ long long new_size;
+};
+
struct imsm_update_general_migration_checkpoint {
enum imsm_update_type type;
__u32 curr_migr_unit;
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);
printf(" 2TB volumes :%s supported\n",
(orom->attr & IMSM_OROM_ATTR_2TB)?"":" not");
printf(" 2TB disks :%s supported\n",
(orom->attr & IMSM_OROM_ATTR_2TB_DISK)?"":" not");
+ printf(" Max Disks : %d\n", orom->tds);
+ printf(" Max Volumes : %d per array, %d per controller\n",
+ orom->vpa, orom->vphba);
return;
}
switch (get_imsm_raid_level(map)) {
case 0:
+ return map->num_members;
+ break;
case 1:
case 10:
- return map->num_members;
+ return map->num_members/2;
case 5:
return map->num_members - 1;
default:
int count = count_volumes(super->hba->path,
super->orom->dpa, verbose);
if (super->orom->vphba <= count) {
- pr_vrb(": platform does not support more then %d raid volumes.\n",
+ pr_vrb(": platform does not support more than %d raid volumes.\n",
super->orom->vphba);
return 0;
}
super->orom->dpa, verbose);
if (super->orom->vphba <= count) {
pr_vrb(": platform does not support more"
- "then %d raid volumes.\n",
+ " than %d raid volumes.\n",
super->orom->vphba);
return 0;
}
super->updates_pending++;
}
-static unsigned long long imsm_set_array_size(struct imsm_dev *dev)
+static unsigned long long imsm_set_array_size(struct imsm_dev *dev,
+ long long new_size)
{
int used_disks = imsm_num_data_members(dev, MAP_0);
unsigned long long array_blocks;
/* set array size in metadata
*/
- map = get_imsm_map(dev, MAP_0);
- array_blocks = blocks_per_member(map) * used_disks;
+ if (new_size <= 0) {
+ /* OLCE size change is caused by added disks
+ */
+ map = get_imsm_map(dev, MAP_0);
+ array_blocks = blocks_per_member(map) * used_disks;
+ } else {
+ /* Online Volume Size Change
+ * Using available free space
+ */
+ array_blocks = new_size;
+ }
/* round array size down to closest MB
*/
memcpy(map2, map, copy_map_size);
map2->num_members = prev_num_members;
- imsm_set_array_size(dev);
+ imsm_set_array_size(dev, -1);
super->clean_migration_record_by_mdmon = 1;
super->updates_pending++;
}
*tofree = *space_list;
/* calculate new size
*/
- imsm_set_array_size(new_dev);
+ imsm_set_array_size(new_dev, -1);
ret_val = 1;
}
return ret_val;
}
+static int apply_size_change_update(struct imsm_update_size_change *u,
+ struct intel_super *super)
+{
+ struct intel_dev *id;
+ int ret_val = 0;
+
+ dprintf("apply_size_change_update()\n");
+ if ((u->subdev < 0) ||
+ (u->subdev > 1)) {
+ dprintf("imsm: Error: Wrong subdev: %i\n", u->subdev);
+ return ret_val;
+ }
+
+ for (id = super->devlist ; id; id = id->next) {
+ if (id->index == (unsigned)u->subdev) {
+ struct imsm_dev *dev = get_imsm_dev(super, u->subdev);
+ struct imsm_map *map = get_imsm_map(dev, MAP_0);
+ int used_disks = imsm_num_data_members(dev, MAP_0);
+ unsigned long long blocks_per_member;
+
+ /* calculate new size
+ */
+ blocks_per_member = u->new_size / used_disks;
+ dprintf("imsm: apply_size_change_update(size: %llu, "
+ "blocks per member: %llu)\n",
+ u->new_size, blocks_per_member);
+ set_blocks_per_member(map, blocks_per_member);
+ imsm_set_array_size(dev, u->new_size);
+
+ ret_val = 1;
+ break;
+ }
+ }
+
+ return ret_val;
+}
+
+
static int apply_update_activate_spare(struct imsm_update_activate_spare *u,
struct intel_super *super,
struct active_array *active_array)
newmap = get_imsm_map(newdev, MAP_1);
memcpy(newmap, oldmap, sizeof_imsm_map(oldmap));
- imsm_set_array_size(newdev);
+ imsm_set_array_size(newdev, -1);
}
sp = (void **)id->dev;
super->updates_pending++;
break;
}
+ case update_size_change: {
+ struct imsm_update_size_change *u = (void *)update->buf;
+ if (apply_size_change_update(u, super))
+ super->updates_pending++;
+ break;
+ }
case update_activate_spare: {
struct imsm_update_activate_spare *u = (void *) update->buf;
if (apply_update_activate_spare(u, super, st->arrays))
dprintf("New anchor length is %llu\n", (unsigned long long)len);
break;
}
+ case update_size_change: {
+ break;
+ }
case update_create_array: {
struct imsm_update_create_array *u = (void *) update->buf;
struct intel_dev *dv;
return 0;
}
+
+/******************************************************************************
+ * function: imsm_create_metadata_update_for_size_change()
+ * Creates update for IMSM array for array size change.
+ *
+ ******************************************************************************/
+static int imsm_create_metadata_update_for_size_change(
+ struct supertype *st,
+ struct geo_params *geo,
+ struct imsm_update_size_change **updatep)
+{
+ struct intel_super *super = st->sb;
+ int update_memory_size = 0;
+ struct imsm_update_size_change *u = NULL;
+
+ dprintf("imsm_create_metadata_update_for_size_change(enter)"
+ " New size = %llu\n", geo->size);
+
+ /* size of all update data without anchor */
+ update_memory_size = sizeof(struct imsm_update_size_change);
+
+ u = calloc(1, update_memory_size);
+ if (u == NULL) {
+ dprintf("error: cannot get memory for "
+ "imsm_create_metadata_update_for_size_change\n");
+ return 0;
+ }
+ u->type = update_size_change;
+ u->subdev = super->current_vol;
+ u->new_size = geo->size;
+
+ dprintf("imsm: reshape update preparation : OK\n");
+ *updatep = u;
+
+ return update_memory_size;
+}
+
/******************************************************************************
* function: imsm_create_metadata_update_for_migration()
* Creates update for IMSM array.
int devNumChange = 0;
/* imsm compatible layout value for array geometry verification */
int imsm_layout = -1;
+ int data_disks;
+ struct imsm_dev *dev;
+ struct intel_super *super;
+ long long current_size;
getinfo_super_imsm_volume(st, &info, NULL);
if ((geo->level != info.array.level) &&
geo->chunksize = info.array.chunk_size;
chunk = geo->chunksize / 1024;
+
+ super = st->sb;
+ dev = get_imsm_dev(super, super->current_vol);
+ data_disks = imsm_num_data_members(dev , MAP_0);
+ /* compute current size in K per disk member
+ */
+ current_size = info.custom_array_size / 2 / data_disks;
+
+ if ((current_size != geo->size) && (geo->size > 0)) {
+ if (change != -1) {
+ fprintf(stderr,
+ Name " Error. Size change should be the only "
+ "one at a time.\n");
+ change = -1;
+ goto analyse_change_exit;
+ }
+ if ((super->current_vol + 1) != super->anchor->num_raid_devs) {
+ fprintf(stderr,
+ Name " Error. The last volume in container "
+ "can be expanded only (%i/%i).\n",
+ super->current_vol, st->devnum);
+ goto analyse_change_exit;
+ }
+ geo->size *= 2;
+ /* round size due to metadata compatibility
+ */
+ geo->size = (geo->size >> SECT_PER_MB_SHIFT)
+ << SECT_PER_MB_SHIFT;
+ dprintf("Prepare update for size change to %llu\n", geo->size );
+ if (current_size >= geo->size) {
+ fprintf(stderr,
+ Name " Error. Size expanssion is supported only"
+ " (current size is %llu, requested size "
+ "/rounded/ is %llu).\n",
+ current_size, geo->size);
+ goto analyse_change_exit;
+ }
+ geo->size *= data_disks;
+ geo->raid_disks = dev->vol.map->num_members;
+ change = CH_ARRAY_SIZE;
+ }
if (!validate_geometry_imsm(st,
geo->level,
imsm_layout,
static int imsm_reshape_super(struct supertype *st, long long size, int level,
int layout, int chunksize, int raid_disks,
int delta_disks, char *backup, char *dev,
- int verbose)
+ int direction, int verbose)
{
int ret_val = 1;
struct geo_params geo;
free(u);
}
break;
+ case CH_ARRAY_SIZE: {
+ struct imsm_update_size_change *u = NULL;
+ int len =
+ imsm_create_metadata_update_for_size_change(
+ st, &geo, &u);
+ if (len < 1) {
+ dprintf("imsm: "
+ "Cannot prepare update\n");
+ break;
+ }
+ ret_val = 0;
+ /* update metadata locally */
+ imsm_update_metadata_locally(st, u, len);
+ /* and possibly remotely */
+ if (st->update_tail)
+ append_metadata_update(st, u, len);
+ else
+ free(u);
+ }
+ break;
default:
ret_val = 1;
}