unsigned long long start, size;
};
+/* definitions of reshape process types */
+enum imsm_reshape_type {
+ CH_TAKEOVER,
+ CH_CHUNK_MIGR,
+ CH_LEVEL_MIGRATION
+};
+
/* definition of messages passed to imsm_process_update */
enum imsm_update_type {
update_activate_spare,
update_rename_array,
update_add_remove_disk,
update_reshape_container_disks,
+ update_takeover
};
struct imsm_update_activate_spare {
int raid_disks;
};
+enum takeover_direction {
+ R10_TO_R0,
+ R0_TO_R10
+};
+struct imsm_update_takeover {
+ enum imsm_update_type type;
+ int subarray;
+ enum takeover_direction direction;
+};
struct imsm_update_reshape {
enum imsm_update_type type;
if (st->update_tail) {
/* queue the recently created array / added disk
* as a metadata update */
- struct dl *d;
int rv;
/* determine if we are creating a volume or adding a disk */
} else
rv = create_array(st, current_vol);
- for (d = super->disks; d ; d = d->next) {
- close(d->fd);
- d->fd = -1;
- }
-
return rv;
} else {
struct dl *d;
return ret_val;
}
+static int apply_takeover_update(struct imsm_update_takeover *u,
+ struct intel_super *super)
+{
+ struct imsm_dev *dev = NULL;
+ struct imsm_map *map;
+ struct dl *dm, *du;
+ struct intel_dev *dv;
+
+ for (dv = super->devlist; dv; dv = dv->next)
+ if (dv->index == (unsigned int)u->subarray) {
+ dev = dv->dev;
+ break;
+ }
+
+ if (dev == NULL)
+ return 0;
+
+ map = get_imsm_map(dev, 0);
+
+ if (u->direction == R10_TO_R0) {
+ /* iterate through devices to mark removed disks as spare */
+ for (dm = super->disks; dm; dm = dm->next) {
+ if (dm->disk.status & FAILED_DISK) {
+ int idx = dm->index;
+ /* update indexes on the disk list */
+/* FIXME this loop-with-the-loop looks wrong, I'm not convinced
+ the index values will end up being correct.... NB */
+ for (du = super->disks; du; du = du->next)
+ if (du->index > idx)
+ du->index--;
+ /* mark as spare disk */
+ dm->disk.status = SPARE_DISK;
+ dm->index = -1;
+ }
+ }
+
+ /* update map */
+ map->num_members = map->num_members / 2;
+ map->map_state = IMSM_T_STATE_NORMAL;
+ map->num_domains = 1;
+ map->raid_level = 0;
+ map->failed_disk_num = -1;
+ }
+
+ /* update disk order table */
+ for (du = super->disks; du; du = du->next)
+ if (du->index >= 0)
+ set_imsm_ord_tbl_ent(map, du->index, du->index);
+
+ return 1;
+}
+
static void imsm_process_update(struct supertype *st,
struct metadata_update *update)
{
mpb = super->anchor;
switch (type) {
+ case update_takeover: {
+ struct imsm_update_takeover *u = (void *)update->buf;
+ if (apply_takeover_update(u, super))
+ super->updates_pending++;
+ break;
+ }
+
case update_reshape_container_disks: {
struct imsm_update_reshape *u = (void *)update->buf;
if (apply_reshape_container_disks_update(
struct geo_params *geo,
int *old_raid_disks)
{
+ /* currently we only support increasing the number of devices
+ * for a container. This increases the number of device for each
+ * member array. They must all be RAID0 or RAID5.
+ */
int ret_val = 0;
struct mdinfo *info, *member;
int devices_that_can_grow = 0;
}
}
+/***************************************************************************
+* Function: imsm_analyze_change
+* Description: Function analyze change for single volume
+* and validate if transition is supported
+* Parameters: Geometry parameters, supertype structure
+* Returns: Operation type code on success, -1 if fail
+****************************************************************************/
+enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
+ struct geo_params *geo)
+{
+ struct mdinfo info;
+ int change = -1;
+ int check_devs = 0;
+
+ getinfo_super_imsm_volume(st, &info, NULL);
+
+ if ((geo->level != info.array.level) &&
+ (geo->level >= 0) &&
+ (geo->level != UnSet)) {
+ switch (info.array.level) {
+ case 0:
+ if (geo->level == 5) {
+ change = CH_LEVEL_MIGRATION;
+ check_devs = 1;
+ }
+ if (geo->level == 10) {
+ change = CH_TAKEOVER;
+ check_devs = 1;
+ }
+ break;
+ case 5:
+ if (geo->level != 0)
+ change = CH_LEVEL_MIGRATION;
+ break;
+ case 10:
+ if (geo->level == 0) {
+ change = CH_TAKEOVER;
+ check_devs = 1;
+ }
+ break;
+ }
+ if (change == -1) {
+ fprintf(stderr,
+ Name " Error. Level Migration from %d to %d "
+ "not supported!\n",
+ info.array.level, geo->level);
+ goto analyse_change_exit;
+ }
+ } else
+ geo->level = info.array.level;
+
+ if ((geo->layout != info.array.layout)
+ && ((geo->layout != UnSet) && (geo->layout != -1))) {
+ change = CH_LEVEL_MIGRATION;
+ if ((info.array.layout == 0)
+ && (info.array.level == 5)
+ && (geo->layout == 5)) {
+ /* reshape 5 -> 4 */
+ } else if ((info.array.layout == 5)
+ && (info.array.level == 5)
+ && (geo->layout == 0)) {
+ /* reshape 4 -> 5 */
+ geo->layout = 0;
+ geo->level = 5;
+ } else {
+ fprintf(stderr,
+ Name " Error. Layout Migration from %d to %d "
+ "not supported!\n",
+ info.array.layout, geo->layout);
+ change = -1;
+ goto analyse_change_exit;
+ }
+ } else
+ geo->layout = info.array.layout;
+
+ if ((geo->chunksize > 0) && (geo->chunksize != UnSet)
+ && (geo->chunksize != info.array.chunk_size))
+ change = CH_CHUNK_MIGR;
+ else
+ geo->chunksize = info.array.chunk_size;
+
+ if (!validate_geometry_imsm(st,
+ geo->level,
+ geo->layout,
+ geo->raid_disks,
+ (geo->chunksize / 1024),
+ geo->size,
+ 0, 0, 1))
+ change = -1;
+
+ if (check_devs) {
+ struct intel_super *super = st->sb;
+ struct imsm_super *mpb = super->anchor;
+
+ if (mpb->num_raid_devs > 1) {
+ fprintf(stderr,
+ Name " Error. Cannot perform operation on %s"
+ "- for this operation it MUST be single "
+ "array in container\n",
+ geo->dev_name);
+ change = -1;
+ }
+ }
+
+analyse_change_exit:
+
+ return change;
+}
+
+int imsm_takeover(struct supertype *st, struct geo_params *geo)
+{
+ struct intel_super *super = st->sb;
+ struct imsm_update_takeover *u;
+
+ u = malloc(sizeof(struct imsm_update_takeover));
+ if (u == NULL)
+ return 1;
+
+ u->type = update_takeover;
+ u->subarray = super->current_vol;
+
+ /* 10->0 transition */
+ if (geo->level == 0)
+ u->direction = R10_TO_R0;
+
+ /* update metadata locally */
+ imsm_update_metadata_locally(st, u,
+ sizeof(struct imsm_update_takeover));
+ /* and possibly remotely */
+ if (st->update_tail)
+ append_metadata_update(st, u,
+ sizeof(struct imsm_update_takeover));
+ else
+ free(u);
+
+ return 0;
+}
+
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)
{
- /* currently we only support increasing the number of devices
- * for a container. This increases the number of device for each
- * member array. They must all be RAID0 or RAID5.
- */
-
int ret_val = 1;
struct geo_params geo;
memset(&geo, sizeof(struct geo_params), 0);
geo.dev_name = dev;
+ geo.dev_id = st->devnum;
geo.size = size;
geo.level = level;
geo.layout = layout;
if (experimental() == 0)
return ret_val;
- /* verify reshape conditions
- * on container level we can only increase number of devices.
- */
if (st->container_dev == st->devnum) {
- /* check for delta_disks > 0
- * and supported raid levels 0 and 5 only in container
- */
+ /* On container level we can only increase number of devices. */
+ dprintf("imsm: info: Container operation\n");
int old_raid_disks = 0;
if (imsm_reshape_is_allowed_on_container(
st, &geo, &old_raid_disks)) {
else
free(u);
- } else
+ } else {
fprintf(stderr, Name "imsm: Operation is not allowed "
"on this container\n");
- } else
- fprintf(stderr, Name "imsm: not a container operation\n");
+ }
+ } else {
+ /* On volume level we support following operations
+ * - takeover: raid10 -> raid0; raid0 -> raid10
+ * - chunk size migration
+ * - migration: raid5 -> raid0; raid0 -> raid5
+ */
+ struct intel_super *super = st->sb;
+ struct intel_dev *dev = super->devlist;
+ int change, devnum;
+ dprintf("imsm: info: Volume operation\n");
+ /* find requested device */
+ while (dev) {
+ imsm_find_array_minor_by_subdev(dev->index, st->container_dev, &devnum);
+ if (devnum == geo.dev_id)
+ break;
+ dev = dev->next;
+ }
+ if (dev == NULL) {
+ fprintf(stderr, Name " Cannot find %s (%i) subarray\n",
+ geo.dev_name, geo.dev_id);
+ goto exit_imsm_reshape_super;
+ }
+ super->current_vol = dev->index;
+ change = imsm_analyze_change(st, &geo);
+ switch (change) {
+ case CH_TAKEOVER:
+ ret_val = imsm_takeover(st, &geo);
+ break;
+ case CH_CHUNK_MIGR:
+ ret_val = 0;
+ break;
+ case CH_LEVEL_MIGRATION:
+ ret_val = 0;
+ break;
+ default:
+ ret_val = 1;
+ }
+ }
exit_imsm_reshape_super:
dprintf("imsm: reshape_super Exit code = %i\n", ret_val);