From: <mik...@us...> - 2003-06-27 20:23:52
|
Update of /cvsroot/evms/evms2/engine/plugins/md In directory sc8-pr-cvs1:/tmp/cvs-serv18029a Modified Files: linear_mgr.h linear_mgr.c Log Message: Add expand and shrink capabilities to MD Linear Personality Notes: - Now can expand by expanding the last disk - Now can expand by adding one or more new disks - Now can shrink by shrinking the last disk - Still need to code to shrink by removing child(ren) from linear array, return ENOSYS for now Index: linear_mgr.h =================================================================== RCS file: /cvsroot/evms/evms2/engine/plugins/md/linear_mgr.h,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- linear_mgr.h 4 Feb 2003 19:13:40 -0000 1.1 +++ linear_mgr.h 27 Jun 2003 20:23:49 -0000 1.2 @@ -29,5 +29,8 @@ #define MD_LINEAR_FUNCTION_COUNT 2 +// Linear region manager flags +#define MD_LINEAR_CONFIG_CHANGE_PENDING (1<<0) + #endif Index: linear_mgr.c =================================================================== RCS file: /cvsroot/evms/evms2/engine/plugins/md/linear_mgr.c,v retrieving revision 1.18 retrieving revision 1.19 diff -u -d -r1.18 -r1.19 --- linear_mgr.c 25 Jun 2003 20:15:30 -0000 1.18 +++ linear_mgr.c 27 Jun 2003 20:23:49 -0000 1.19 @@ -36,7 +36,130 @@ // Global variables +static BOOLEAN linear_can_change_region_configuration( storage_object_t *region ) +{ + BOOLEAN rc = TRUE; + md_volume_t * volume = (md_volume_t *)region->private_data; + + if (volume->region_mgr_flags & MD_LINEAR_CONFIG_CHANGE_PENDING) { + rc = FALSE; + } + RETURN(rc); +} + +static void linear_calculate_and_update_size(storage_object_t *region) +{ + md_volume_t * volume = (md_volume_t *)region->private_data; + int i, count; + + /* Recalculate size */ + region->size = 0; + for (i = 0, count = 0; count < volume->nr_disks; i++ ) { + if (volume->child_object[i] && volume->super_array[i]) { + region->size += MD_NEW_SIZE_SECTORS(volume->child_object[i]->size); + ++count; + } + } + + /* Update master superblock and children's superblock */ + volume->super_block->size = region->size / 2; + for (i = 0, count = 0; count < volume->nr_disks; i++ ) { + if (volume->child_object[i] && volume->super_array[i]) { + volume->super_array[i]->size = volume->super_block->size; + ++count; + } + } + +} +/* + * Returns the current object in the specified DLIST. This call should + * be preceeded by the get_first_object_in_list() call or the caller + * should position the DLIST current pointer themselves. Note, this call + * will not modify anything in the DLIST, including the CURRENT_ITEM ptr + * and so it will not advance in the DLIST. + */ +static storage_object_t * linear_get_object_from_list( dlist_t list ) +{ + int rc; + storage_object_t *obj; + storage_object_t *object_from_list = NULL; + TAG tag; + + rc = BlindGetObject( list, &tag, NULL, FALSE, (void **)&obj ); + if (rc == DLIST_SUCCESS) { + object_from_list = obj; + } + + return object_from_list; +} + +static int linear_add_new_disk(md_volume_t * volume, storage_object_t *new_disk) { + + int rc= 0,i; + mdp_disk_t disk; + + LOG_ENTRY; + + rc = md_clone_superblock(volume, volume->nr_disks); + if (rc) { + RETURN(rc); + } + i = volume->nr_disks; + + volume->child_object[i] = new_disk; + md_append_region_to_object(volume->region, new_disk); + + disk.major = new_disk->dev_major; + disk.minor = new_disk->dev_minor; + disk.number = i; + disk.raid_disk = disk.number; + disk.state = (1<<MD_DISK_PENDING_ACTIVE) | (1 << MD_DISK_ACTIVE) | (1 << MD_DISK_SYNC); + memcpy(&volume->super_block->disks[i], &disk, sizeof(mdp_disk_t)); + volume->super_block->active_disks++; + volume->super_block->working_disks++; + volume->super_block->raid_disks++; + volume->super_block->nr_disks++; + volume->nr_disks++; + + linear_calculate_and_update_size(volume->region); + + RETURN(rc); +} + +static int linear_remove_last_disk(md_volume_t * volume, storage_object_t *child) { + + int rc = 0, i; + + LOG_ENTRY; + i = volume->nr_disks - 1; + if (volume->child_object[i] == child) { + + md_remove_region_from_object(volume->region, child); + + /* If we are unwinding expansion, don't clear the superblock */ + if ((volume->super_block->disks[i].state & (1<<MD_DISK_PENDING_ACTIVE)) == 0 ) + KILL_SECTORS(child, MD_NEW_SIZE_SECTORS(child->size),MD_RESERVED_SECTORS); + + EngFncs->engine_free(volume->super_array[i]); + volume->super_array[i] = NULL; + + memset(&volume->super_block->disks[i], 0, sizeof(mdp_disk_t)); //NULL out now empty disk entry + + volume->super_block->raid_disks--; + volume->super_block->active_disks--; + volume->super_block->working_disks--; + volume->super_block->nr_disks--; + volume->nr_disks--; + + linear_calculate_and_update_size(volume->region); + } else { + LOG_ERROR(" %s is not the last disk of the %s region\n", child->name, volume->region->name); + rc = EINVAL; + } + + RETURN(rc); +} /* Function: linear_setup_evms_plugin * @@ -85,19 +208,113 @@ RETURN(0); } +/* Function: linear_can_last_child_expand + * + * Notes: This function returns error code not BOOLEAN + */ +static int linear_can_last_child_expand(storage_object_t *region, + u_int64_t *expand_limit, + dlist_t expansion_points ) +{ + int rc = 0; + storage_object_t *child; + md_volume_t * volume = (md_volume_t *)region->private_data; + LOG_ENTRY; + + child = volume->child_object[volume->super_block->nr_disks-1]; + if (!child) { + RETURN(ENODEV); + } + + rc = child->plugin->functions.plugin->can_expand(child, expand_limit, expansion_points); + + RETURN(rc); +} + +/* Function: linear_can_last_child_expand + * + * Notes: This function returns error code not BOOLEAN + */ +static int linear_can_last_child_shrink(storage_object_t *region, + u_int64_t *shrink_limit, + dlist_t shrink_points ) +{ + int rc = 0; + storage_object_t *child; + md_volume_t * volume = (md_volume_t *)region->private_data; + LOG_ENTRY; + + child = volume->child_object[volume->super_block->nr_disks-1]; + if (!child) { + RETURN(ENODEV); + } + + rc = child->plugin->functions.plugin->can_shrink(child, shrink_limit, shrink_points); + + RETURN(rc); +} /* Function: linear_can_expand * - * Can this region be expanded? If so, - * add the region to the expansion_points output list. else, just - * return 0 to allow those above us to do as they please + * This region can be expanded if: + * The last child can be expanded -OR- + * There is at least 1 available object */ -static int linear_can_expand(storage_object_t * region, - u_int64_t * expand_limit, - dlist_t expansion_points ) +static int linear_can_expand(storage_object_t *region, + u_int64_t *expand_limit, + dlist_t expansion_points) { + int rc = 0; + uint count; + dlist_t tmp_list; + expand_object_info_t * expand_object; + void *handle; + LOG_ENTRY; - RETURN(0); + + if (!linear_can_change_region_configuration(region)) + RETURN(EBUSY); + + /* Allow the last child to add expansion point */ + linear_can_last_child_expand(region, expand_limit, expansion_points); + + /* get a list of all valid input disks, segments, and regions. */ + EngFncs->get_object_list(DISK | SEGMENT | REGION, + DATA_TYPE, + NULL, + NULL, + VALID_INPUT_OBJECT, + &tmp_list); + + /* Remove this MD object from the list */ + DeleteObject(tmp_list, region); + + GetListSize(tmp_list, &count); + + DestroyList(&tmp_list, FALSE); + + if (count) { + expand_object = (expand_object_info_t *) EngFncs->engine_alloc( sizeof(expand_object_info_t) ); + if (expand_object) { + expand_object->object = region; + expand_object->max_expand_size = -1; + rc = InsertObject ( (dlist_t) expansion_points, + (void *) expand_object, + (TAG) EXPAND_OBJECT_TAG, + (void *) NULL, + (Insertion_Modes) AppendToList, + (BOOLEAN) TRUE, + (void **) &handle ); + if (rc) { + EngFncs->engine_free( expand_object ); + rc = EPERM; + } + } else { + rc = ENOMEM; + } + } + + RETURN(rc); } @@ -111,20 +328,55 @@ u_int64_t * size ) { LOG_ENTRY; - RETURN(ENOSYS); + RETURN(0); } /* Function: linear_can_shrink * - * Just like can_expand, but in the opposite direction. + * This region can be expanded if: + * The last child can be shrunk -OR- + * This region has more than 1 disk */ static int linear_can_shrink(storage_object_t * region, u_int64_t * shrink_limit, dlist_t shrink_points ) { + int rc = 0; + md_volume_t *volume = (md_volume_t *)region->private_data; + shrink_object_info_t * shrink_object; + void *handle; + LOG_ENTRY; - RETURN(0); + + if (!linear_can_change_region_configuration(region)) + RETURN(EBUSY); + + /* Allow the last child to add shrink point */ + linear_can_last_child_shrink(region, shrink_limit, shrink_points); + + if (volume->nr_disks > 1) { + shrink_object = (shrink_object_info_t *) EngFncs->engine_alloc( sizeof(shrink_object_info_t) ); + if (shrink_object) { + shrink_object->object = region; + shrink_object->max_shrink_size = region->size - MD_NEW_SIZE_SECTORS(volume->child_object[0]->size); + rc = InsertObject ( (dlist_t) shrink_points, + (void *) shrink_object, + (TAG) SHRINK_OBJECT_TAG, + (void *) NULL, + (Insertion_Modes) AppendToList, + (BOOLEAN) TRUE, + (void **) &handle ); + if (rc) { + EngFncs->engine_free( shrink_object ); + rc = EPERM; + } + } else { + rc = ENOMEM; + } + } + + RETURN(rc); } @@ -138,7 +390,7 @@ u_int64_t * size ) { LOG_ENTRY; - RETURN(ENOSYS); + RETURN(0); } @@ -290,16 +542,150 @@ } -/* Function: linear_expand +/* Function: linear_expand_last_child + * + * Call expand() on the last child of the MD linear array to expand. */ +static int linear_expand_last_child(storage_object_t *region, + storage_object_t *expand_object, + dlist_t input_objects, + option_array_t *options ) +{ + int rc=0; + md_volume_t *volume = (md_volume_t *)region->private_data; + storage_object_t *child; + u_int64_t cur_size; + LOG_ENTRY; -static int linear_expand(storage_object_t * region, + child = volume->child_object[volume->nr_disks-1]; + if (child != expand_object) { + LOG_ERROR(" Error, expand obj (%s) is not the last child!\n", expand_object->name); + rc = EINVAL; + RETURN(rc); + } + + cur_size = child->size; + LOG_DEBUG(" %s's current size = %"PRIu64" sectors.\n", child->name, child->size); + KILL_SECTORS(child, MD_NEW_SIZE_SECTORS(child->size), MD_RESERVED_SECTORS); + + rc = child->plugin->functions.plugin->expand(child, expand_object, input_objects, options); + if (!rc) { + LOG_DEBUG(" %s's new size = %"PRIu64" sectors.\n", child->name, child->size); + if (child->size > cur_size) { + linear_calculate_and_update_size(region); + region->flags |= SOFLAG_DIRTY; + region->flags |= SOFLAG_NEEDS_DEACTIVATE; + } + } + + RETURN(rc); +} + +/* Function: linear_shrink_last_child + * + * Call shrink() on the last child of the MD linear array to shrink. + */ +static int linear_shrink_last_child(storage_object_t *region, + storage_object_t *shrink_object, + dlist_t input_objects, + option_array_t *options ) +{ + int rc=0; + md_volume_t *volume = (md_volume_t *)region->private_data; + storage_object_t *child; + u_int64_t cur_size; + LOG_ENTRY; + + child = volume->child_object[volume->nr_disks-1]; + if (child != shrink_object) { + LOG_ERROR(" Error, shrink obj (%s) is not the last child!\n", shrink_object->name); + rc = EINVAL; + RETURN(rc); + } + + cur_size = child->size; + LOG_DEBUG(" %s's current size = %"PRIu64" sectors.\n", child->name, child->size); + KILL_SECTORS(child, MD_NEW_SIZE_SECTORS(child->size), MD_RESERVED_SECTORS); + + rc = child->plugin->functions.plugin->shrink(child, shrink_object, input_objects, options); + if (!rc) { + LOG_DEBUG(" %s's new size = %"PRIu64" sectors.\n", child->name, child->size); + if (child->size < cur_size) { + linear_calculate_and_update_size(region); + region->flags |= SOFLAG_DIRTY; + region->flags |= SOFLAG_NEEDS_DEACTIVATE; + } + } + + RETURN(rc); +} + + +/* + * Function: linear_expand + * + * If the last child is the target for this call, + * let it handle the expansion. Otherwise, add one disk at a time. + */ + +static int linear_expand(storage_object_t *region, storage_object_t * expand_object, dlist_t input_objects, option_array_t * options ) { + int rc = 0; + md_volume_t *volume; + int saved_nr_disks; + storage_object_t *candidate; + LOG_ENTRY; - RETURN(ENOSYS); + + if (region != expand_object) { + rc = linear_expand_last_child(region, expand_object, input_objects, options); + } else { + + /* We about to perform the expansion */ + + volume = (md_volume_t *)region->private_data; + + saved_nr_disks = volume->nr_disks; /* just in case... */ + + rc = GoToStartOfList( input_objects ); + while (rc == DLIST_SUCCESS) { + + candidate = linear_get_object_from_list( input_objects ); + if (candidate) { + + rc = linear_add_new_disk(volume, candidate); + if (!rc) { + rc = NextItem(input_objects); + } + } else { + rc = DLIST_END_OF_LIST; + } + } + + /* throw away errors like ... DLIST_END_OF_LIST ... which are not real errors */ + if ( ( rc == DLIST_EMPTY ) || ( rc == DLIST_END_OF_LIST ) ) { + rc = DLIST_SUCCESS; + } + + if (!rc) { + /* Expansion was successful */ + region->flags |= (SOFLAG_DIRTY | SOFLAG_NEEDS_DEACTIVATE); + } else { + /* There was an error, unwind the expand */ + int last_idx; + for (last_idx = volume->nr_disks-1; + last_idx >= saved_nr_disks; last_idx--) { + if (volume->child_object[last_idx]) { + linear_remove_last_disk(volume, volume->child_object[last_idx]); + } + } + } + } + + RETURN(rc); } @@ -310,8 +696,15 @@ dlist_t input_objects, option_array_t * options ) { + int rc = 0; LOG_ENTRY; - RETURN(ENOSYS); + + if (region != shrink_object) { + rc = linear_shrink_last_child(region, shrink_object, input_objects, options); + } else { + rc = ENOSYS; + } + RETURN(rc); } @@ -478,6 +871,13 @@ case EVMS_Task_Create: count = 0; break; + case EVMS_Task_Expand: + count = 0; + break; + case EVMS_Task_Shrink: + count = 0; + break; + default: count = 0; break; @@ -496,6 +896,7 @@ { int rc = 0; dlist_t tmp_list; + md_volume_t * volume; LOG_ENTRY; @@ -520,6 +921,29 @@ context->max_selected_objects = MAX_MD_DEVICES; break; + case EVMS_Task_Expand: + + volume = (md_volume_t *) context->object->private_data; + context->option_descriptors->count = 0; + + /* get a list of all valid input disks, segments, and regions. */ + EngFncs->get_object_list(DISK | SEGMENT | REGION, + DATA_TYPE, + NULL, + NULL, + VALID_INPUT_OBJECT, + &tmp_list); + + /* Remove this MD object from the list */ + DeleteObject(tmp_list, context->object); + + /* move these items to the acceptable objects list. */ + md_transfer_list(tmp_list, context->acceptable_objects); + DestroyList(&tmp_list, FALSE); + context->min_selected_objects = 1; + context->max_selected_objects = MAX_MD_DEVICES - volume->super_block->nr_disks; + break; + case MD_LINEAR_FUNCTION_FIX: context->min_selected_objects = 0; context->max_selected_objects = 0; @@ -564,6 +988,14 @@ case EVMS_Task_Create: // no options, just return 0 break; + + case EVMS_Task_Expand: + // no options, just return 0 + break; + + case EVMS_Task_Shrink: + // no options, just return 0 + break; default: break; @@ -571,12 +1003,127 @@ RETURN(rc); } +/* + * Validate the objects in the source and target dlists in the context + * record. Remove from the selected objects lists any objects which are no + * longer acceptable. Return all acceptable objects in the parameter + * dlists. Also, for any object which is removed from the selected dlists, + * or is otherwise not acceptable, create a declined_handle_t struct with + * reason why not acceptable and add to the declined_objects dlist. + */ +static int linear_set_expand_object( task_context_t * context, + dlist_t declined_objects, + task_effect_t * effect ) +{ + int rc=0; + storage_object_t *obj=NULL; + void *handle; + declined_object_t *declined_object=NULL; + int selected_objects_count=0; + int declined_object_count=0; + int max_objects_allowed=0; + md_volume_t *volume = (md_volume_t *)context->object->private_data; + + + LOG_ENTRY; + + /* determine how many disks we can add */ + if (context) { + max_objects_allowed = MAX_MD_DEVICES - volume->super_block->nr_disks; + if (max_objects_allowed > 0) { + rc = GoToStartOfList( context->selected_objects ); + if (rc) { + LOG_ERROR("error, selected objects list is corrupt\n"); + rc = EINVAL; + } + } + } + + while (rc == DLIST_SUCCESS) { + + obj = linear_get_object_from_list( context->selected_objects ); + if (obj) { + + if ( max_objects_allowed > selected_objects_count ) { + + ++selected_objects_count; + *effect |= EVMS_Effect_Reload_Options; + rc = NextItem(context->selected_objects); + + } + else { + + LOG_WARNING("declining object (%s)\n", obj->name); + + ++declined_object_count; + + declined_object = EngFncs->engine_alloc( sizeof(declined_object_t)); + + + if (declined_object) { + + declined_object->object = obj; + declined_object->reason = rc; + + rc = InsertObject ( declined_objects, + declined_object, + DECLINED_OBJECT_TAG, + NULL, + AppendToList, + TRUE, + &handle ); + + if (rc == DLIST_SUCCESS) { + *effect |= EVMS_Effect_Reload_Objects; + rc = NextItem(context->selected_objects); + } + else { + EngFncs->engine_free(declined_object); + LOG_ERROR("error, unable to insert declined object in engine dlist\n"); + } + + } + else { + LOG_ERROR("unable to malloc a declined object struct\n"); + rc = ENOMEM; + } + + } + } + else { + rc = DLIST_END_OF_LIST; + } + + }; + + + // throw away errors like ... DLIST_END_OF_LIST ... which are not real errors + if ( ( rc == DLIST_EMPTY )||( rc == DLIST_END_OF_LIST )) { + rc = DLIST_SUCCESS; + } + + if (declined_object_count) { + *effect = EVMS_Effect_Reload_Objects; + } + + RETURN(rc); +} + /* Function: linear_set_objects + * + * Validate the objects in the selected_objects dlist in the task context. + * Remove from the selected objects lists any objects which are not + * acceptable. * - * Determine the type of task, and then validate that the objects on the - * "selected" list are valid for that task. If so, adjust the option - * descriptor as appropriate. + * For unacceptable objects, create a declined_handle_t structure with the + * reason why it is not acceptable, and add it to the declined_objects dlist. + * Modify the accepatble_objects dlist in the task context as necessary + * based on the selected objects and the current settings of the options. + * + * Modify any option settings as necessary based on the selected objects. + * Return the appropriate task_effect_t settings if the object list(s), + * minimum or maximum objects selected, or option settings have changed. */ static int linear_set_objects( task_context_t * context, dlist_t declined_objects, @@ -589,6 +1136,16 @@ switch(context->action) { case EVMS_Task_Create: + // since this is within task context, and we provided the initial list + // do we need any further validation here? + rc = 0; + break; + + case EVMS_Task_Expand: + rc = linear_set_expand_object( context, declined_objects, effect ); + break; + + case EVMS_Task_Shrink: // since this is within task context, and we provided the initial list // do we need any further validation here? rc = 0; |