lvm2app: Possible lvm_lv_resize impl (V2)
cover lvm2app: Possible lvm_lv_resize impl (V2)
This patch set implements lvm_lv_resize for the lvm2app API.
As this patch set is pretty large and touches a number of different areas I would appreciate folks to review. Specifically the first patch where I added a flag to lv to do additional steps on a vg_commit. In addition as users of the API are unable to interact the re-size has a implicit force, so users could potentially lose data if they reduce the size of the lv.
Proposed changes pass local unit testing.
V2 - Removed automatic whitespace cleanup so patches are easier to
read.
Tony Asleson (3):
liblvm: Breakout required operations for re-size into vg_commit
liblvm: Move core lv re-size to lv_manip.c
lvm2app: Implement lvm_lv_resize
lib/format_text/flags.c | 1 + lib/metadata/lv_manip.c | 665 +++++++++++++++++++++++++++++++ lib/metadata/metadata-exported.h | 76 ++++- lib/metadata/metadata.c | 87 ++++- lib/misc/lvm-percent.c | 5 + lib/misc/lvm-percent.h | 2 + liblvm/lvm_lv.c | 19 +- tools/lvresize.c | 811 +++----------------------------------- tools/toollib.c | 6 - tools/tools.h | 17 - 10 files changed, 902 insertions(+), 787 deletions(-)
PATCH 1/3 liblvm: Breakout required operations for re-size into vg_commit
When re-sizing a LV with the command line, after the re-size occurs the code used to do a vg_write and then a number of operations before and after the commit. As the API requires the ability to have the re-size done independantly of the write and commit a flag was added so that when we go through vg_commit we will do the same required steps to commit the lv size change regardless if it was done through the command line or the API.
--- lib/format_text/flags.c | 1 + lib/metadata/metadata-exported.h | 3 +- lib/metadata/metadata.c | 87 +++++++++++++++++++++++++++++++++++++- tools/lvresize.c | 84 ++++++++++-------------------------- 4 files changed, 113 insertions(+), 62 deletions(-)
lib/format_text/flags.c +1 -0
@@ -77,6 +77,7 @@ static const struct flag _lv_flags[] = { {THIN_POOL, NULL, 0}, {THIN_POOL_DATA, NULL, 0}, {THIN_POOL_METADATA, NULL, 0}, + {LV_RESIZE, NULL, 0}, {0, NULL, 0} };
lib/metadata/metadata-exported.h +2 -1
@@ -62,8 +62,9 @@#define MIRROR_LOG UINT64_C(0x00020000)/* LV */ #define MIRROR_IMAGE UINT64_C(0x00040000)/* LV */ -#define LV_NOTSYNCED UINT64_C(0x00080000)/* LV */ +#define LV_NOTSYNCED UINT64_C(0x00080000)/* LV */ #define LV_REBUILD UINT64_C(0x00100000)/* LV */ +#define LV_RESIZE UINT64_C(0x00200000)/* LV - internal use only */ //#define PRECOMMITTED UINT64_C(0x00200000) /* VG - internal use only */ #define CONVERTING UINT64_C(0x00400000)/* LV */
lib/metadata/metadata.c +86 -1
107 lines not on this page · raw message
tools/lvresize.c +24 -60
103 lines not on this page · raw message
Signature · 1 line
1.7.1
PATCH 2/3 liblvm: Move core lv re-size to lv_manip.c
In reply to Tony AslesonMoved the core function to lv_manip so that the command line and the API could call it. To make this work all the argument parsing functions are being done in tools/lv_resize.c and all the parameters are expected to be passed in with the struct lvresize_params.
--- lib/metadata/lv_manip.c | 665 ++++++++++++++++++++++++++++++++++ lib/metadata/metadata-exported.h | 73 ++++ lib/misc/lvm-percent.c | 5 + lib/misc/lvm-percent.h | 2 + tools/lvresize.c | 737 ++------------------------------------ tools/toollib.c | 6 - tools/tools.h | 17 - 7 files changed, 778 insertions(+), 727 deletions(-)
lib/metadata/lv_manip.c +665 -0
@@ -27,6 +27,7 @@#include "activate.h" #include "str_list.h" #include "defaults.h" +#include "lvm-exec.h" typedef enum { PREFERRED,
@@ -3041,6 +3042,670 @@ int lv_rename(struct cmd_context *cmd, struct logical_volume *lv,return lv_rename_update (cmd, lv, new_name,1 ); } +static uint32_t lvseg_get_stripes (struct lv_segment *seg,uint32_t *stripesize) +{ +uint32_t s; +struct lv_segment *seg_mirr; + +/* If segment mirrored, check if images are striped */ +if (seg_is_mirrored (seg)) +for (s =0 ; s < seg->area_count; s++) { +if (seg_type (seg, s) !=AREA_LV ) +continue ; + seg_mirr =first_seg (seg_lv (seg, s)); + +if (seg_is_striped (seg_mirr)) { + seg = seg_mirr; +break ; + } + } + + +if (seg_is_striped (seg)) { + *stripesize = seg->stripe_size; +return seg->area_count; + } + + *stripesize =0 ; +return 0 ; +} + +static int _validate_stripesize (struct cmd_context *cmd, +const struct volume_group *vg, +struct lvresize_params *lp) +{ + +if ( lp->ac_stripesize_value >STRIPE_SIZE_LIMIT *2 ) { +log_error ("Stripe size cannot be larger than %s" , +display_size (cmd, (uint64_t )STRIPE_SIZE_LIMIT )); +return 0 ; + } + +if (!(vg->fid->fmt->features &FMT_SEGMENTS )) +log_warn ("Varied stripesize not supported. Ignoring." ); +else if (lp->ac_stripesize_value > (uint64_t ) vg->extent_size *2 ) { +log_error ("Reducing stripe size %s to maximum, " +"physical extent size %s" , +display_size (cmd,lp->ac_stripesize_value), +display_size (cmd, (uint64_t ) vg->extent_size)); + lp->stripe_size = vg->extent_size; + }else + lp->stripe_size = lp->ac_stripesize_value; + +if (lp->stripe_size & (lp->stripe_size -1 )) { +log_error ("Stripe size must be power of 2" ); +return 0 ; + } + +return 1 ; +} + +static int _request_confirmation (struct cmd_context *cmd, +const struct volume_group *vg, +const struct logical_volume *lv, +const struct lvresize_params *lp) +{ +struct lvinfo info = {0 }; + +if (!lv_info (cmd, lv,0 , &info,1 ,0 ) &&driver_version (NULL ,0 )) { +log_error ("lv_info failed: aborting" ); +return 0 ; + } + +if (lp->resizefs) { +if (!info.exists) { +log_error ("Logical volume %s must be activated " +"before resizing filesystem" , lp->lv_name); +return 0 ; + } +return 1 ; + } + +if (!info.exists) +return 1 ; + +log_warn ("WARNING: Reducing active%s logical volume to %s" , + info.open_count ?" and open" :"" , +display_size (cmd, (uint64_t ) lp->extents * vg->extent_size)); + +log_warn ("THIS MAY DESTROY YOUR DATA (filesystem etc.)" ); + +if (!lp->ac_force) { +if (yes_no_prompt ("Do you really want to reduce %s? [y/n]: " , + lp->lv_name) =='n' ) { +log_error ("Logical volume %s NOT reduced" , lp->lv_name); +return 0 ; + } +if (sigint_caught ()) +return 0 ; + } + +return 1 ; +} + +static int _adjust_policy_params (struct cmd_context *cmd, +struct logical_volume *lv,struct lvresize_params *lp) +{ +percent_t percent; +int policy_threshold, policy_amount; + +if (lv_is_thin_pool (lv)) { + policy_threshold = +find_config_tree_int (cmd,"activation/thin_pool_autoextend_threshold" , +DEFAULT_THIN_POOL_AUTOEXTEND_THRESHOLD ) *PERCENT_1 ; + policy_amount = +find_config_tree_int (cmd,"activation/thin_pool_autoextend_percent" , +DEFAULT_THIN_POOL_AUTOEXTEND_PERCENT ); +if (!policy_amount && policy_threshold <PERCENT_100 ) +return 0 ; + }else { + policy_threshold = +find_config_tree_int (cmd,"activation/snapshot_autoextend_threshold" , +DEFAULT_SNAPSHOT_AUTOEXTEND_THRESHOLD ) *PERCENT_1 ; + policy_amount = +find_config_tree_int (cmd,"activation/snapshot_autoextend_percent" , +DEFAULT_SNAPSHOT_AUTOEXTEND_PERCENT ); + } + +if (policy_threshold >=PERCENT_100 ) +return 1 ;/* nothing to do */ + +if (lv_is_thin_pool (lv)) { +if (!lv_thin_pool_percent (lv,1 , &percent)) + return_0; +if (percent > policy_threshold) { +/* FIXME: metadata resize support missing */ +log_error ("Resize for %s/%s is not yet supported." , + lp->vg_name, lp->lv_name); +return ECMD_FAILED ; + } + +if (!lv_thin_pool_percent (lv,0 , &percent)) + return_0; +if (!(PERCENT_0 < percent && percent <=PERCENT_100 ) || + percent <= policy_threshold) +return 1 ;/* nothing to do */ + }else { +if (!lv_snapshot_percent (lv, &percent)) + return_0; +if (!(PERCENT_0 < percent && percent <PERCENT_100 ) || percent <= policy_threshold) +return 1 ;/* nothing to do */ + } + + lp->extents = policy_amount; + +return 1 ; +} + +/* +* FSADM_CMD --dry-run --verbose --force check lv_path +* FSADM_CMD --dry-run --verbose --force resize lv_path size +*/ +int fsadm_cmd (struct cmd_context *cmd, +const struct volume_group *vg, +const struct lvresize_params *lp, +enum fsadm_cmd_e fcmd, +int *status) +{ +char lv_path[PATH_MAX ]; +char size_buf[SIZE_BUF ]; +const char *argv[FSADM_CMD_MAX_ARGS +2 ]; +unsigned i =0 ; + + argv[i++] =FSADM_CMD ; + +if (test_mode ()) + argv[i++] ="--dry-run" ; + +if (verbose_level () >= _LOG_NOTICE) + argv[i++] ="--verbose" ; + +if (lp->ac_force) + argv[i++] ="--force" ; + + argv[i++] = (fcmd ==FSADM_CMD_RESIZE ) ?"resize" :"check" ; + +if (status) + *status =-1 ; + +if (dm_snprintf (lv_path,PATH_MAX ,"%s%s/%s" , cmd->dev_dir, lp->vg_name, + lp->lv_name) <0 ) { +log_error ("Couldn't create LV path for %s" , lp->lv_name); +return 0 ; + } + + argv[i++] = lv_path; + +if (fcmd ==FSADM_CMD_RESIZE ) { +if (dm_snprintf (size_buf,SIZE_BUF ,"%" PRIu64"K" , + (uint64_t ) lp->extents * vg->extent_size /2 ) <0 ) { +log_error ("Couldn't generate new LV size string" ); +return 0 ; + } + + argv[i++] = size_buf; + } + + argv[i] =NULL ; + +return exec_cmd (cmd, argv, status,1 ); +} + +int _lvresize (struct cmd_context *cmd,struct volume_group *vg, +struct lvresize_params *lp,struct dm_list *pvh) +{ +struct logical_volume *lv; +struct lvinfo info; +uint32_t stripesize_extents; +uint32_t seg_stripes =0 , seg_stripesize =0 , seg_size; +uint32_t seg_mirrors =0 ; +uint32_t extents_used; +uint32_t size_rest; +uint32_t pv_extent_count; +alloc_policy_t alloc; +struct lv_list *lvl; +struct lv_segment *seg, *uninitialized_var (mirr_seg ); +uint32_t seg_extents; +uint32_t sz, str; +int status; + +/* does LV exist? */ +if (!(lvl =find_lv_in_vg (vg, lp->lv_name))) { +log_error ("Logical volume %s not found in volume group %s" , + lp->lv_name, lp->vg_name); +return ECMD_FAILED ; + } + +if (lvl->lv->status & (RAID_IMAGE |RAID_META )) { +log_error ("Cannot resize a RAID %s directly" , + (lvl->lv->status &RAID_IMAGE ) ?"image" : +"metadata area" ); +return ECMD_FAILED ; + } + +if (lv_is_raid_with_tracking (lvl->lv)) { +log_error ("Cannot resize %s while it is tracking a split image" , + lvl->lv->name); +return ECMD_FAILED ; + } + +if (lp->ac_stripes) { +if (vg->fid->fmt->features &FMT_SEGMENTS ) + lp->stripes = lp->ac_stripes_value; +else +log_warn ("Varied striping not supported. Ignoring." ); + } + +if (lp->ac_mirrors) { +if (vg->fid->fmt->features &FMT_SEGMENTS ) + lp->mirrors = lp->ac_mirrors_value; +else +log_warn ("Mirrors not supported. Ignoring." ); + } + +if (lp->ac_stripesize && + !_validate_stripesize (cmd, vg, lp)) +return EINVALID_CMD_LINE ; + + lv = lvl->lv; + +if (lp->ac_policy) { +if (!lv_is_cow (lv) && + !lv_is_thin_pool (lv)) { +log_error ("Policy-based resize is supported only for snapshot and thin pool volumes." ); +return ECMD_FAILED ; + } +if (!_adjust_policy_params (cmd, lv, lp)) +return ECMD_FAILED ; + } + +if (!lv_is_visible (lv)) { +log_error ("Can't resize internal logical volume %s" , lv->name); +return ECMD_FAILED ; + } + +if (lv->status &LOCKED ) { +log_error ("Can't resize locked LV %s" , lv->name); +return ECMD_FAILED ; + } + +if (lv->status &CONVERTING ) { +log_error ("Can't resize %s while lvconvert in progress" , lv->name); +return ECMD_FAILED ; + } + + alloc = (alloc_policy_t)(lp->ac_alloc)?lp->ac_alloc: lv->alloc; + +/* +* First adjust to an exact multiple of extent size. +* When extending by a relative amount we round that amount up. +* When reducing by a relative amount we remove at most that amount. +* When changing to an absolute size, we round that size up. +*/ +if (lp->size) { +if (lp->size % vg->extent_size) { +if (lp->sign ==SIGN_MINUS ) + lp->size -= lp->size % vg->extent_size; +else + lp->size += vg->extent_size - + (lp->size % vg->extent_size); + +log_print_unless_silent ("Rounding size to boundary between physical extents: %s" , +display_size (cmd, lp->size)); + } + + lp->extents = lp->size / vg->extent_size; + } + +switch (lp->percent) { +case PERCENT_VG : + lp->extents =percent_of_extents (lp->extents, vg->extent_count, + (lp->sign !=SIGN_MINUS )); +break ; +case PERCENT_FREE : + lp->extents =percent_of_extents (lp->extents, vg->free_count, + (lp->sign !=SIGN_MINUS )); +break ; +case PERCENT_LV : + lp->extents =percent_of_extents (lp->extents, lv->le_count, + (lp->sign !=SIGN_MINUS )); +break ; +case PERCENT_PVS : +if (lp->argc) { + pv_extent_count =pv_list_extents_free (pvh); + lp->extents =percent_of_extents (lp->extents, pv_extent_count, + (lp->sign !=SIGN_MINUS )); + }else + lp->extents =percent_of_extents (lp->extents, vg->extent_count, + (lp->sign !=SIGN_MINUS )); +break ; +case PERCENT_ORIGIN : +if (!lv_is_cow (lv)) { +log_error ("Specified LV does not have an origin LV." ); +return EINVALID_CMD_LINE ; + } + lp->extents =percent_of_extents (lp->extents,origin_from_cow (lv)->le_count, + (lp->sign !=SIGN_MINUS )); +break ; +case PERCENT_NONE : +break ; + } + +if (lp->sign ==SIGN_PLUS ) { +if (lp->extents >= (MAX_EXTENT_COUNT - lv->le_count)) { +log_error ("Unable to extend %s by %u extents, exceeds limit (%u)." , + lp->lv_name, lv->le_count,MAX_EXTENT_COUNT ); +return EINVALID_CMD_LINE ; + } + lp->extents += lv->le_count; + } + +if (lp->sign ==SIGN_MINUS ) { +if (lp->extents >= lv->le_count) { +log_error ("Unable to reduce %s below 1 extent" , + lp->lv_name); +return EINVALID_CMD_LINE ; + } + + lp->extents = lv->le_count - lp->extents; + } + +if (!lp->extents) { +log_error ("New size of 0 not permitted" ); +return EINVALID_CMD_LINE ; + } + +if (lp->extents == lv->le_count) { +if (lp->ac_policy) +return ECMD_PROCESSED ;/* Nothing to do. */ +if (!lp->resizefs) { +log_error ("New size (%d extents) matches existing size " +"(%d extents)" , lp->extents, lv->le_count); +return EINVALID_CMD_LINE ; + } + lp->resize =LV_EXTEND ;/* lets pretend zero size extension */ + } + + seg_size = lp->extents - lv->le_count; + +/* Use segment type of last segment */ + dm_list_iterate_items(seg, &lv->segments) { + lp->segtype = seg->segtype; + } + +/* FIXME Support LVs with mixed segment types */ +if (lp->segtype != +get_segtype_from_string (cmd, (lp->ac_type)?lp->ac_type:lp->segtype->name)) { +log_error ("VolumeType does not match (%s)" , lp->segtype->name); +return EINVALID_CMD_LINE ; + } + +/* If extending, find mirrors of last segment */ +if ((lp->extents > lv->le_count)) { +/* +* Has the user specified that they would like the additional +* extents of a mirror not to have an initial sync? +*/ +if (seg_is_mirrored (first_seg (lv)) && lp->ac_no_sync) + lv->status |=LV_NOTSYNCED ; + + dm_list_iterate_back_items(mirr_seg, &lv->segments) { +if (seg_is_mirrored (mirr_seg)) + seg_mirrors =lv_mirror_count (mirr_seg->lv); +else + seg_mirrors =0 ; +break ; + } + +if (!lp->ac_mirrors && seg_mirrors) { +log_print_unless_silent ("Extending %" PRIu32" mirror images." , + seg_mirrors); + lp->mirrors = seg_mirrors; + } +if ((lp->ac_mirrors || seg_mirrors) && + (lp->mirrors != seg_mirrors)) { +log_error ("Cannot vary number of mirrors in LV yet." ); +return EINVALID_CMD_LINE ; + } + +if (seg_mirrors && !strcmp (mirr_seg->segtype->name,"raid10" )) { + lp->stripes = mirr_seg->area_count / seg_mirrors; + lp->stripe_size = mirr_seg->stripe_size; + } + } + +/* If extending, find stripes, stripesize & size of last segment */ +if ((lp->extents > lv->le_count) && + !(lp->stripes ==1 || (lp->stripes >1 && lp->stripe_size)) && +strcmp (mirr_seg->segtype->name,"raid10" )) { +/* FIXME Don't assume mirror seg will always be AREA_LV */ +/* FIXME We will need to support resize for metadata LV as well, +* and data LV could be any type (i.e. mirror)) */ +dm_list_iterate_items (seg, seg_mirrors ? &seg_lv (mirr_seg,0 )->segments : + lv_is_thin_pool(lv) ? &seg_lv(first_seg(lv), 0)->segments : &lv->segments) { +/* Allow through "striped" and RAID 4/5/6/10 */ +if (!seg_is_striped (seg) && + (!seg_is_raid (seg) ||seg_is_mirrored (seg)) && +strcmp (seg->segtype->name,"raid10" )) +continue ; + + sz = seg->stripe_size; + str = seg->area_count - lp->segtype->parity_devs; + +if ((seg_stripesize && seg_stripesize != sz && + sz && !lp->stripe_size) || + (seg_stripes && seg_stripes != str && !lp->stripes)) { +log_error ("Please specify number of " +"stripes (-i) and stripesize (-I)" ); +return EINVALID_CMD_LINE ; + } + + seg_stripesize = sz; + seg_stripes = str; + } + +if (!lp->stripes) + lp->stripes = seg_stripes; +else if (seg_is_raid (first_seg (lv)) && + (lp->stripes != seg_stripes)) { +log_error ("Unable to extend \"%s\" segment type with different number of stripes." ,first_seg (lv)->segtype->ops->name (first_seg (lv))); +return ECMD_FAILED ; + } + +if (!lp->stripe_size && lp->stripes >1 ) { +if (seg_stripesize) { +log_print_unless_silent ("Using stripesize of last segment %s" , +display_size (cmd, (uint64_t ) seg_stripesize)); + lp->stripe_size = seg_stripesize; + }else { + lp->stripe_size = +find_config_tree_int (cmd, +"metadata/stripesize" , +DEFAULT_STRIPESIZE ) *2 ; +log_print_unless_silent ("Using default stripesize %s" , +display_size (cmd, (uint64_t ) lp->stripe_size)); + } + } + } + +/* If reducing, find stripes, stripesize & size of last segment */ +if (lp->extents < lv->le_count) { + extents_used =0 ; + +if (lp->stripes || lp->stripe_size || lp->mirrors) +log_error ("Ignoring stripes, stripesize and mirrors " +"arguments when reducing" ); + + dm_list_iterate_items(seg, &lv->segments) { + seg_extents = seg->len; + +/* Check for underlying stripe sizes */ + seg_stripes =lvseg_get_stripes (seg, &seg_stripesize); + +if (seg_is_mirrored (seg)) + seg_mirrors =lv_mirror_count (seg->lv); +else + seg_mirrors =0 ; + +if (lp->extents <= extents_used + seg_extents) +break ; + + extents_used += seg_extents; + } + + seg_size = lp->extents - extents_used; + lp->stripe_size = seg_stripesize; + lp->stripes = seg_stripes; + lp->mirrors = seg_mirrors; + } + +if (lp->stripes >1 && !lp->stripe_size) { +log_error ("Stripesize for striped segment should not be 0!" ); +return EINVALID_CMD_LINE ; + } + +if (lp->stripes >1 ) { +if (lp->stripe_size <STRIPE_SIZE_MIN ) { +log_error ("Invalid stripe size %s" , +display_size (cmd, (uint64_t ) lp->stripe_size)); +return EINVALID_CMD_LINE ; + } + +if (!(stripesize_extents = lp->stripe_size / vg->extent_size)) + stripesize_extents =1 ; + + size_rest = seg_size % (lp->stripes * stripesize_extents); +/* Round toward the original size. */ +if (size_rest && + ((lp->extents < lv->le_count) || + !lp->percent || + (vg->free_count >= (lp->extents - lv->le_count - size_rest + + (lp->stripes * stripesize_extents))))) { +log_print_unless_silent ("Rounding size (%d extents) up to stripe " +"boundary size for segment (%d extents)" , + lp->extents, lp->extents - size_rest + + (lp->stripes * stripesize_extents)); + lp->extents = lp->extents - size_rest + + (lp->stripes * stripesize_extents); + }else if (size_rest) { +log_print_unless_silent ("Rounding size (%d extents) down to stripe " +"boundary size for segment (%d extents)" , + lp->extents, lp->extents - size_rest); + lp->extents = lp->extents - size_rest; + } + } + +if (lp->extents < lv->le_count) { +if (lp->resize ==LV_EXTEND ) { +log_error ("New size given (%d extents) not larger " +"than existing size (%d extents)" , + lp->extents, lv->le_count); +return EINVALID_CMD_LINE ; + } + lp->resize =LV_REDUCE ; + }else if (lp->extents > lv->le_count) { +if (lp->resize ==LV_REDUCE ) { +log_error ("New size given (%d extents) not less than " +"existing size (%d extents)" , lp->extents, + lv->le_count); +return EINVALID_CMD_LINE ; + } + lp->resize =LV_EXTEND ; + }else if (lp->extents == lv->le_count) { +if (lp->ac_policy) +return ECMD_PROCESSED ;/* Nothing to do. */ +if (!lp->resizefs) { +log_error ("New size (%d extents) matches existing size " +"(%d extents)" , lp->extents, lv->le_count); +return EINVALID_CMD_LINE ; + } + lp->resize =LV_EXTEND ; + } + +if (lv_is_origin (lv)) { +if (lp->resize ==LV_REDUCE ) { +log_error ("Snapshot origin volumes cannot be reduced " +"in size yet." ); +return ECMD_FAILED ; + } + +if (lv_info (cmd, lv,0 , &info,0 ,0 ) && info.exists) { +log_error ("Snapshot origin volumes can be resized " +"only while inactive: try lvchange -an" ); +return ECMD_FAILED ; + } + } + +if (lv_is_thin_pool (lv)) { +if (lp->resize ==LV_REDUCE ) { +log_error ("Thin pool volumes cannot be reduced in size yet." ); +return ECMD_FAILED ; + } + +if (lp->resizefs) { +log_warn ("Thin pool volumes do not have filesystem." ); + lp->resizefs =0 ; + } + } + +if ((lp->resize ==LV_REDUCE ) && lp->argc) +log_warn ("Ignoring PVs on command line when reducing" ); + +/* Request confirmation before operations that are often mistakes. */ +if ((lp->resizefs || (lp->resize ==LV_REDUCE )) && + !_request_confirmation (cmd, vg, lv, lp)) { + stack; +return ECMD_FAILED ; + } + +if (lp->resizefs) { +if (!lp->nofsck && + !fsadm_cmd (cmd, vg, lp,FSADM_CMD_CHECK , &status)) { +if (status !=FSADM_CHECK_FAILS_FOR_MOUNTED ) { +log_error ("Filesystem check failed." ); +return ECMD_FAILED ; + } +/* some filesystems supports online resize */ + } + +if ((lp->resize ==LV_REDUCE ) && + !fsadm_cmd (cmd, vg, lp,FSADM_CMD_RESIZE ,NULL )) { +log_error ("Filesystem resize failed." ); +return ECMD_FAILED ; + } + } + +if (!archive (vg)) { + stack; +return ECMD_FAILED ; + } + +log_print_unless_silent ("%sing logical volume %s to %s" , + (lp->resize ==LV_REDUCE ) ?"Reduc" :"Extend" , + lp->lv_name, +display_size (cmd, (uint64_t ) lp->extents * vg->extent_size)); + +if (lp->resize ==LV_REDUCE ) { +if (!lv_reduce (lv, lv->le_count - lp->extents)) { + stack; +return ECMD_FAILED ; + } + }else if ((lp->extents > lv->le_count) &&/* Ensure we extend */ + !lv_extend (lv, lp->segtype, + lp->stripes, lp->stripe_size, + lp->mirrors,first_seg (lv)->region_size, + lp->extents - lv->le_count,NULL , + pvh, alloc)) { + stack; +return ECMD_FAILED ; + } + +/* Set the flag to tell commit that we have addl. work todo*/ + lv->status |=LV_RESIZE ; + +return ECMD_PROCESSED ; +} +char *generate_lv_name (struct volume_group *vg,const char *format,char *buffer,size_t len) {
lib/metadata/metadata-exported.h +73 -0
91 lines not on this page · raw message
lib/misc/lvm-percent.c +5 -0
@@ -38,3 +38,8 @@ percent_t make_percent(uint64_t numerator, uint64_t denominator) } } +uint32_t percent_of_extents (uint32_t percents,uint32_t count,int roundup) +{ +return (uint32_t )(((uint64_t )percents * (uint64_t )count + + ((roundup) ?99 :0 )) /100 ); +}
lib/misc/lvm-percent.h +2 -0
@@ -41,4 +41,6 @@ typedef enum {float percent_to_float (percent_t v);percent_t make_percent (uint64_t numerator,uint64_t denominator); +uint32_t percent_of_extents (uint32_t percents,uint32_t count,int roundup); +#endif
tools/lvresize.c +33 -704
783 lines not on this page · raw message
tools/toollib.c +0 -6
@@ -1624,9 +1624,3 @@ int change_tag(struct cmd_context *cmd, struct volume_group *vg,return 1 ; } -/* Return percents of extents and avoid overflow, with optional roundup */ -uint32_t percent_of_extents (uint32_t percents,uint32_t count,int roundup) -{ -return (uint32_t )(((uint64_t )percents * (uint64_t )count + - ((roundup) ?99 :0 )) /100 ); -}
tools/tools.h +0 -17
@@ -34,7 +34,6 @@#include "dev-cache.h" #include "device.h" #include "display.h" -#include "errors.h" #include "filter.h" #include "filter-composite.h" #include "filter-persistent.h"
@@ -73,21 +72,6 @@ enum {#undef arg }; -typedef enum { -SIGN_NONE =0 , -SIGN_PLUS =1 , -SIGN_MINUS =2 -}sign_t ; - -typedef enum { -PERCENT_NONE =0 , -PERCENT_VG , -PERCENT_FREE , -PERCENT_LV , -PERCENT_PVS , -PERCENT_ORIGIN -}percent_type_t ; -#define ARG_COUNTABLE 0x00000001/* E.g. -vvvv */ #define ARG_GROUPABLE 0x00000002/* E.g. --addtag */
@@ -187,7 +171,6 @@ int lvconvert_poll(struct cmd_context *cmd, struct logical_volume *lv, unsignedint mirror_remove_missing (struct cmd_context *cmd,struct logical_volume *lv,int force); -uint32_t percent_of_extents (uint32_t percents,uint32_t count,int roundup);int vgchange_activate (struct cmd_context *cmd,struct volume_group *vg,activation_change_t activate);
Signature · 1 line
1.7.1
PATCH 3/3 lvm2app: Implement lvm_lv_resize
In reply to Tony AslesonAdditionally, renamed _lvresize to lv_resize.
--- lib/metadata/lv_manip.c | 2 +- lib/metadata/metadata-exported.h | 2 +- liblvm/lvm_lv.c | 19 ++++++++++++++++--- tools/lvresize.c | 2 +- 4 files changed, 19 insertions(+), 6 deletions(-)
lib/metadata/lv_manip.c +1 -1
@@ -3251,7 +3251,7 @@ int fsadm_cmd(struct cmd_context *cmd,return exec_cmd (cmd, argv, status,1 ); } -int _lvresize (struct cmd_context *cmd,struct volume_group *vg, +int lv_resize (struct cmd_context *cmd,struct volume_group *vg,struct lvresize_params *lp,struct dm_list *pvh) {struct logical_volume *lv;
lib/metadata/metadata-exported.h +1 -1
@@ -520,7 +520,7 @@ int vgs_are_compatible(struct cmd_context *cmd, struct volume_group *vg_to);uint32_t vg_lock_newname (struct cmd_context *cmd,const char *vgname); -int _lvresize (struct cmd_context *cmd,struct volume_group *vg, +int lv_resize (struct cmd_context *cmd,struct volume_group *vg,struct lvresize_params *lp,struct dm_list *pvh); int fsadm_cmd(struct cmd_context *cmd,
liblvm/lvm_lv.c +16 -3
@@ -304,7 +304,20 @@ int lvm_lv_rename(lv_t lv, const char *new_name)int lvm_lv_resize (const lv_t lv,uint64_t new_size) { -/* FIXME: add lv resize code here */ -log_error ("NOT IMPLEMENTED YET" ); -return -1 ; +struct lvresize_params lp = {0 }; + + lp.vg_name = lv->vg->name; + lp.lv_name = lv->name; + lp.sign =SIGN_NONE ; + lp.percent =PERCENT_NONE ; + lp.resize =LV_ANY ; + lp.size = new_size >>SECTOR_SHIFT ; + lp.ac_force =1 ;/* Assume the user has a good backup? */ + +if (ECMD_PROCESSED !=lv_resize (lv->vg->cmd, lv->vg, &lp, &lv->vg->pvs)) { +log_verbose ("LV Re-size failed." ); +return -1 ; + } + +return 0 ; }
tools/lvresize.c +1 -1
@@ -175,7 +175,7 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv) goto out; } - r =_lvresize (cmd, vg, &lp, pvh); + r =lv_resize (cmd, vg, &lp, pvh);if (ECMD_PROCESSED == r) {if (!vg_write (vg)) {
Signature · 1 line
1.7.1
cover lvm2app: Possible lvm_lv_resize impl (V2)
In reply to Tony AslesonDne 2.11.2012 21:33, Tony Asleson napsal(a):
Quoted 8 lines
This patch set implements
lvm_lv_resizefor the lvm2app API.As this patch set is pretty large and touches a number of different areas I would appreciate folks to review. Specifically the first patch where I added a flag to lv to do additional steps on a
vg_commit. In addition as users of the API are unable to interact the re-size has a implicit force, so users could potentially lose data if they reduce the size of the lv.
Quoted 4 lines
Proposed changes pass local unit testing.
V2 - Removed automatic whitespace cleanup so patches are easier to
read.
I think at this point the library is not ready for this change, and needs some more decisions to be made before we start to make such steps.
I'd like to first see how the external API would look like at python 'user' level.
How do you want to make python developer let use the lvm object?
Do you want to give him 'power of vg_write/vg_commit' to his hands ?
So far design allowed to control objects on VG level - which has many aspects of consistency across cluster, it's basic unit of locking.
If we release the very strict and tight rules that are hard coded via many hacks within liblvm internal (and admitelly many of them are not even docuemted) - we have to be sure what we lose and what we gain from such moves.
How do you want to control thing like 'lvcreate' args for python user - since a lot of changes happens at this place (and lot will happen when new targets are added).
I cannot really imagine any 'stable' API you might give python user - unless you would simply allow to pass string parameter like you give for lvcreate cmdline now. Python needs to go via complex tools/lvcreate source file - there is currently no way to have the smartness of args parsing in lib/metadata subdir.
Here is just one of many examples which comes to my head -
While it might look ok to create multiple linear LVs at once, you would get into seriuos problem if you would want to create thin pool and thin LVs at the same commit.
How do we plan to have consistent API changes in python and rest of lvm - i.e. adding new supported target type usually (with current code stage) leads to many changes across whole code base - including /tools subdir. If the python binding binds to /lib and skips /tools interface, we would have yet another place to keep in sync (and think of more supported interfaces - i.e. ruby)
From codding point -
I do not think it's good plan to move all the functionality from /tools and /lib for liblvm2api - why not rather link libcmdlib with API if you want to make all the command externally available for python?
For now it seems like you want need to move all functions from tools to lv_manip which is already pretty large source file. It's probably better to keep functionality in separate files.
The current stage of lvm2 library is not really object oriented in terms, you could manipulate with internal data structures easily - since there is rather a lot of cached things connected together (and cache must stay intact - there are even extra debug options to control and check its consistency)
So to see how to make things towards supporting non-lvmcmd user we need to consider many things together.
Is the python API designed to working only in 'anaconda' like environment, (where you've not strict memory rules) or is it supposed to work anytime ?
Zdenek
cover lvm2app: Possible lvm_lv_resize impl (V2)
Quoted 18 lines · Zdenek Kabelac
Dne 2.11.2012 21:33, Tony Asleson napsal(a):
Quoted 9 lines
This patch set implements
lvm_lv_resizefor the lvm2app API.As this patch set is pretty large and touches a number of different areas I would appreciate folks to review. Specifically the first patch where I added a flag to lv to do additional steps on a
vg_commit. In addition as users of the API are unable to interact the re-size has a implicit force, so
users could potentially lose data if they reduce the size of the lv.Quoted 4 lines
Proposed changes pass local unit testing.
V2 - Removed automatic whitespace cleanup so patches are easier to
read.I think at this point the library is not ready for this change, and needs some more decisions to be made before we start to make such steps.
Quoted 6 lines
I'd like to first see how the external API would look like at python 'user' level.
How do you want to make python developer let use the lvm object?
Do you want to give him 'power of vg_write/vg_commit' to his hands ?
I was only trying to maintain the same level of functionality that the C lvm2app library exposes today for other calls. Thus the reason I kept it for lv re-size. If this type of functionality is concerning, then we can certainly re-visit the design of the library.
The python bindings don't actually expose lvm_vg_write, so for all functionality in the python bindings, each operation is atomic as it is in lvm command line.
My preference would be to change the liblvm by taking out the lvm_vg_commit function and making each change atomic, like the python bindings do. Then introduce a dry run functionality for those users that want to try out configuration before writing them to disk, like anaconda would want at install time. Having both seems redundant and exposes the user and the code base to unneeded complexity.
Quoted 23 lines
So far design allowed to control objects on VG level - which has many aspects of consistency across cluster, it's basic unit of locking.
If we release the very strict and tight rules that are hard coded via many hacks within liblvm internal (and admitelly many of them are not even docuemted) - we have to be sure what we lose and what we gain from such moves.
How do you want to control thing like 'lvcreate' args for python user - since a lot of changes happens at this place (and lot will happen when new targets are added).
I cannot really imagine any 'stable' API you might give python user - unless you would simply allow to pass string parameter like you give for lvcreate cmdline now. Python needs to go via complextools/lvcreatesource file - there is currently no way to have the smartness of args parsing in lib/metadata subdir.Here is just one of many examples which comes to my head -
While it might look ok to create multiple linear LVs at once, you would get into seriuos problem if you would want to create thin pool and thin LVs at the same commit.
Quoted 6 lines
How do we plan to have consistent API changes in python and rest of lvm - i.e. adding new supported target type usually (with current code stage) leads to many changes across whole code base - including /tools subdir. If the python binding binds to /lib and skips /tools interface, we would have yet another place to keep in sync (and think of more supported interfaces - i.e. ruby)
This patch presents only one code path for the lv-resize (well, that was my intent). Both the cmd line and the API call into the same function to perform the re-size so there should be no duplicate code paths. Yes, the command line argument processing is in separate code, but it should be. We need to separate the processing of the command line from the actual code doing the operation. As many of the features of lvm have a plethora of options this is a lot of data to collect. Many of the functions have their own structure for placing the parsed values into, but they also include argc and argv, which seems wrong. Why should the lower levels need access to argc/argv? Certainly complicates re-using the same code for a library.
I believe we should re-factor the code over time so that we slowly move towards the command line using the same code that liblvm uses. Core logic in one place with the ability to call into it from the command line or C library bindings etc.
Quoted 5 lines
From codding point -
I do not think it's good plan to move all the functionality from /tools and /lib for liblvm2api - why not rather link libcmdlib with API if you want to make all the command externally available for python?
I took what was done before me and used it as a template of how thing should be done. Other liblvm implemented features have a similar library code structure and break down. If this separation is incorrect then we can surely re-arrange and correct it.
Quoted 10 lines
For now it seems like you want need to move all functions from tools to
lv_manipwhich is already pretty large source file. It's probably better to keep functionality in separate files.The current stage of lvm2 library is not really object oriented in terms, you could manipulate with internal data structures easily - since there is rather a lot of cached things connected together (and cache must stay intact - there are even extra debug options to control and check its consistency)
Quoted 5 lines
So to see how to make things towards supporting non-lvmcmd user we need to consider many things together.
Is the python API designed to working only in 'anaconda' like environment, (where you've not strict memory rules) or is it supposed to work anytime ?
I would think that if a user is in a memory constrained environment, they would not be using a python interpreter. However, we should strive to have a smaller resource foot print running python bindings with lvm than having the python interpreter create a new process to run the lvm command line in.
Thanks for taking the time to look at the patch and responding!
Regards,
Tony