From f3871fdc6841a0505d3a987f4ea1cfb16f6cc201 Mon Sep 17 00:00:00 2001 From: Adam Kwolek Date: Fri, 13 Apr 2012 16:51:57 +0200 Subject: [PATCH] imsm: Add new metadata update for volume size expansion Add new meatdata update type imsm_update_size_change, and update metadata for volume size expansion operation. Signed-off-by: Adam Kwolek Signed-off-by: NeilBrown --- super-intel.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 124 insertions(+), 8 deletions(-) diff --git a/super-intel.c b/super-intel.c index 2e6a8991..ac8922f2 100644 --- a/super-intel.c +++ b/super-intel.c @@ -419,6 +419,7 @@ enum imsm_update_type { update_reshape_migration, update_takeover, update_general_migration_checkpoint, + update_size_change, }; struct imsm_update_activate_spare { @@ -471,6 +472,12 @@ struct imsm_update_reshape_migration { 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; @@ -6974,7 +6981,8 @@ 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) +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; @@ -6993,8 +7001,17 @@ static unsigned long long imsm_set_array_size(struct imsm_dev *dev) /* 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 */ @@ -7051,7 +7068,7 @@ static void imsm_progress_container_reshape(struct intel_super *super) 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++; } @@ -7941,7 +7958,7 @@ skip_disk_add: *tofree = *space_list; /* calculate new size */ - imsm_set_array_size(new_dev); + imsm_set_array_size(new_dev, -1); ret_val = 1; } @@ -7956,6 +7973,44 @@ error_disk_add: 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) @@ -8155,7 +8210,7 @@ static int apply_reshape_container_disks_update(struct imsm_update_reshape *u, 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; @@ -8363,6 +8418,12 @@ static void imsm_process_update(struct supertype *st, 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)) @@ -8757,6 +8818,9 @@ static void imsm_prepare_update(struct supertype *st, 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; @@ -9614,6 +9678,43 @@ abort: 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. @@ -10023,8 +10124,23 @@ static int imsm_reshape_super(struct supertype *st, long long size, int level, } break; case CH_ARRAY_SIZE: { - /* ToDo: Prepare metadata update here - */ + 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: -- 2.39.2