diff options
author | David Teigland <teigland@redhat.com> | 2016-12-20 15:17:48 -0600 |
---|---|---|
committer | David Teigland <teigland@redhat.com> | 2016-12-22 13:40:35 -0600 |
commit | 0e525225ed668b9f7676def744f86d26127c794c (patch) | |
tree | 1abca2bad26fb5641dd696a1dbb9f224a12f38b0 | |
parent | 0dcb767fec6749fb324a3fe58af0b0e19e680319 (diff) | |
download | lvm2-dev-dct-cmd-defs65.tar.gz |
lvconvert: remove unused codedev-dct-cmd-defs65
-rw-r--r-- | tools/lvconvert.c | 2056 |
1 files changed, 325 insertions, 1731 deletions
diff --git a/tools/lvconvert.c b/tools/lvconvert.c index e65e49799..4070a6045 100644 --- a/tools/lvconvert.c +++ b/tools/lvconvert.c @@ -19,25 +19,6 @@ #include "lvconvert_poll.h" #include "command-lines-count.h" -/* - * Guidelines for mapping options to operations. - * - * There should be a clear and unique correspondence between an option - * name and the operation to be performed. - * - * An option with a given name should always perform the same operation. - * If the same operation applies to two types of LV, then the same option - * name can be used with both LV types. But, a given option name should - * not be used to perform different operations depending on the LV type it - * is used with. - * - * --merge and --split are examples where a single option name has been - * overloaded with different operations. The case of --split has been - * corrected with the clear and unique variations --splitcache, - * --splitsnapshot, --splitmirror, which should allow --split to be - * deprecated. (The same is still needed for --merge.) - */ - typedef enum { /* Split: * For a mirrored or raid LV, split mirror into two mirrors, optionally tracking @@ -52,23 +33,13 @@ typedef enum { struct lvconvert_params { /* Exactly one of these 12 command categories is determined */ - int merge; /* 1 */ - int split; /* 2 */ - int splitsnapshot; /* 3 */ - int splitcache; /* 4 */ - int keep_mimages; /* 5 */ /* --splitmirrors */ - int cache; /* 6 */ - int uncache; /* 7 */ - int snapshot; /* 8 */ - int thin; /* 11 */ - /* other */ /* 12 */ + int split; /* 1 */ + int keep_mimages; /* 2 */ /* --splitmirrors */ + /* other */ /* 3 */ /* FIXME Eliminate all cases where more than one of the above are set then use conv_type instead */ conversion_type_t conv_type; - int merge_snapshot; /* CONV_MERGE is set */ - int merge_mirror; /* CONV_MERGE is set */ - int track_changes; /* CONV_SPLIT_MIRRORS is set */ int corelog; /* Equivalent to --mirrorlog core */ @@ -80,7 +51,6 @@ struct lvconvert_params { const struct segment_type *segtype; /* Holds what segment type you will get */ - int poolmetadataspare; int force; int yes; int zero; @@ -92,8 +62,6 @@ struct lvconvert_params { int wait_completion; int need_polling; - int thin_chunk_size_calc_policy; - uint32_t chunk_size; uint32_t region_size; uint32_t mirrors; @@ -103,9 +71,6 @@ struct lvconvert_params { unsigned stripes_supplied; unsigned stripe_size_supplied; uint32_t read_ahead; - cache_mode_t cache_mode; /* cache */ - const char *policy_name; /* cache */ - struct dm_config_tree *policy_settings; /* cache */ unsigned target_attr; @@ -118,15 +83,7 @@ struct lvconvert_params { struct logical_volume *lv_to_poll; struct dm_list idls; - uint32_t pool_metadata_extents; - int passed_args; - uint64_t pool_metadata_size; const char *origin_name; - const char *pool_data_name; - struct logical_volume *pool_data_lv; - const char *pool_metadata_name; - struct logical_volume *pool_metadata_lv; - thin_discards_t discards; }; struct convert_poll_id_list { @@ -145,12 +102,6 @@ static void _set_conv_type(struct lvconvert_params *lp, int conv_type) lp->conv_type = conv_type; } -/* -s/--snapshot and --type snapshot are synonyms */ -static int _snapshot_type_requested(struct cmd_context *cmd, const char *type_str) -{ - return (arg_is_set(cmd, snapshot_ARG) || !strcmp(type_str, SEG_TYPE_NAME_SNAPSHOT)); -} - static int _raid0_type_requested(const char *type_str) { return (!strcmp(type_str, SEG_TYPE_NAME_RAID0) || !strcmp(type_str, SEG_TYPE_NAME_RAID0_META)); @@ -1282,11 +1233,6 @@ static int _lvconvert_mirrors(struct cmd_context *cmd, return 0; } - if (lp->merge_mirror) { - log_error("Unable to merge mirror images of segment type 'mirror'."); - return 0; - } - if (!_lvconvert_validate_thin(lv, lp)) return_0; @@ -1424,7 +1370,7 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l if (!_is_valid_raid_conversion(seg->segtype, lp->segtype)) goto try_new_takeover_or_reshape; - if (seg_is_linear(seg) && !lp->merge_mirror && !lp->mirrors_supplied) { + if (seg_is_linear(seg) && !lp->mirrors_supplied) { if (_raid0_type_requested(lp->type_str)) { log_error("Linear LV %s cannot be converted to %s.", display_lvname(lv), lp->type_str); @@ -1466,9 +1412,6 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l return 0; } - if (lp->merge_mirror) - return lv_raid_merge(lv); - if (lp->track_changes) return lv_raid_split_and_track(lv, lp->pvh); @@ -1555,6 +1498,322 @@ try_new_takeover_or_reshape: return 0; } +/* + * Functions called to perform a specific operation on a specific LV type. + * + * _convert_<lvtype>_<operation> + * + * For cases where an operation does not apply to the LV itself, but + * is implicitly redirected to a sub-LV, these functions locate the + * correct sub-LV and call the operation on that sub-LV. If a sub-LV + * of the proper type is not found, these functions report the error. + * + * FIXME: the _lvconvert_foo() functions can be cleaned up since they + * are now only called for valid combinations of LV type and operation. + * After that happens, the code remaining in those functions can be + * moved into the _convert_lvtype_operation() functions below. + */ + +/* + * Change the number of images in a mirror LV. + * lvconvert --mirrors Number LV + */ +static int _convert_mirror_number(struct cmd_context *cmd, struct logical_volume *lv, + struct lvconvert_params *lp) +{ + return _lvconvert_mirrors(cmd, lv, lp); +} + +/* + * Split images from a mirror LV and use them to create a new LV. + * lvconvert --splitmirrors Number LV + * + * Required options: + * --name Name + */ + +static int _convert_mirror_splitmirrors(struct cmd_context *cmd, struct logical_volume *lv, + struct lvconvert_params *lp) +{ + return _lvconvert_mirrors(cmd, lv, lp); +} + +/* + * Change the type of log used by a mirror LV. + * lvconvert --mirrorlog Type LV + */ +static int _convert_mirror_log(struct cmd_context *cmd, struct logical_volume *lv, + struct lvconvert_params *lp) +{ + return _lvconvert_mirrors(cmd, lv, lp); +} + +/* + * Convert mirror LV to linear LV. + * lvconvert --type linear LV + * + * Alternate syntax: + * lvconvert --mirrors 0 LV + */ +static int _convert_mirror_linear(struct cmd_context *cmd, struct logical_volume *lv, + struct lvconvert_params *lp) +{ + return _lvconvert_mirrors(cmd, lv, lp); +} + +/* + * Convert mirror LV to raid1 LV. + * lvconvert --type raid1 LV + */ +static int _convert_mirror_raid(struct cmd_context *cmd, struct logical_volume *lv, + struct lvconvert_params *lp) +{ + return _lvconvert_raid(lv, lp); +} + +/* + * Change the number of images in a raid1 LV. + * lvconvert --mirrors Number LV + */ +static int _convert_raid_number(struct cmd_context *cmd, struct logical_volume *lv, + struct lvconvert_params *lp) +{ + return _lvconvert_raid(lv, lp); +} + +/* + * Split images from a raid1 LV and use them to create a new LV. + * lvconvert --splitmirrors Number LV + * + * Required options: + * --trackchanges | --name Name + */ +static int _convert_raid_splitmirrors(struct cmd_context *cmd, struct logical_volume *lv, + struct lvconvert_params *lp) +{ + /* FIXME: split the splitmirrors section out of _lvconvert_raid and call it here. */ + return _lvconvert_raid(lv, lp); +} + +/* + * Convert a raid* LV to use a different raid level. + * lvconvert --type raid* LV + */ +static int _convert_raid_raid(struct cmd_context *cmd, struct logical_volume *lv, + struct lvconvert_params *lp) +{ + return _lvconvert_raid(lv, lp); +} + +/* + * Convert a raid* LV to a mirror LV. + * lvconvert --type mirror LV + */ +static int _convert_raid_mirror(struct cmd_context *cmd, struct logical_volume *lv, + struct lvconvert_params *lp) +{ + return _lvconvert_raid(lv, lp); +} + +/* + * Convert a raid* LV to a striped LV. + * lvconvert --type striped LV + */ +static int _convert_raid_striped(struct cmd_context *cmd, struct logical_volume *lv, + struct lvconvert_params *lp) +{ + return _lvconvert_raid(lv, lp); +} + +/* + * Convert a raid* LV to a linear LV. + * lvconvert --type linear LV + */ +static int _convert_raid_linear(struct cmd_context *cmd, struct logical_volume *lv, + struct lvconvert_params *lp) +{ + return _lvconvert_raid(lv, lp); +} + +/* + * Convert a striped/linear LV to a mirror LV. + * lvconvert --type mirror LV + * + * Required options: + * --mirrors Number + * + * Alternate syntax: + * This is equivalent to above when global/mirror_segtype_default="mirror". + * lvconvert --mirrors Number LV + */ +static int _convert_striped_mirror(struct cmd_context *cmd, struct logical_volume *lv, + struct lvconvert_params *lp) +{ + return _lvconvert_mirrors(cmd, lv, lp); +} + +/* + * Convert a striped/linear LV to a raid* LV. + * lvconvert --type raid* LV + * + * Required options: + * --mirrors Number + * + * Alternate syntax: + * This is equivalent to above when global/mirror_segtype_default="raid1". + * lvconvert --mirrors Number LV + */ +static int _convert_striped_raid(struct cmd_context *cmd, struct logical_volume *lv, + struct lvconvert_params *lp) +{ + return _lvconvert_raid(lv, lp); +} + +static int _convert_mirror(struct cmd_context *cmd, struct logical_volume *lv, + struct lvconvert_params *lp) +{ + if (arg_is_set(cmd, mirrors_ARG)) + return _convert_mirror_number(cmd, lv, lp); + + if (arg_is_set(cmd, splitmirrors_ARG)) + return _convert_mirror_splitmirrors(cmd, lv, lp); + + if (arg_is_set(cmd, mirrorlog_ARG) || arg_is_set(cmd, corelog_ARG)) + return _convert_mirror_log(cmd, lv, lp); + + if (_linear_type_requested(lp->type_str)) + return _convert_mirror_linear(cmd, lv, lp); + + if (segtype_is_raid(lp->segtype)) + return _convert_mirror_raid(cmd, lv, lp); + + log_error("Unknown operation on mirror LV %s.", display_lvname(lv)); + return 0; +} + +static int _convert_raid(struct cmd_context *cmd, struct logical_volume *lv, + struct lvconvert_params *lp) +{ + if (arg_is_set(cmd, mirrors_ARG)) + return _convert_raid_number(cmd, lv, lp); + + if (arg_is_set(cmd, splitmirrors_ARG)) + return _convert_raid_splitmirrors(cmd, lv, lp); + + if (segtype_is_raid(lp->segtype)) + return _convert_raid_raid(cmd, lv, lp); + + if (segtype_is_mirror(lp->segtype)) + return _convert_raid_mirror(cmd, lv, lp); + + if (!strcmp(lp->type_str, SEG_TYPE_NAME_STRIPED)) + return _convert_raid_striped(cmd, lv, lp); + + if (_linear_type_requested(lp->type_str)) + return _convert_raid_linear(cmd, lv, lp); + + log_error("Unknown operation on raid LV %s.", display_lvname(lv)); + return 0; +} + +static int _convert_striped(struct cmd_context *cmd, struct logical_volume *lv, + struct lvconvert_params *lp) +{ + const char *mirrors_type = find_config_tree_str(cmd, global_mirror_segtype_default_CFG, NULL); + + if (!strcmp(lp->type_str, SEG_TYPE_NAME_MIRROR)) + return _convert_striped_mirror(cmd, lv, lp); + + if (segtype_is_raid(lp->segtype)) + return _convert_striped_raid(cmd, lv, lp); + + /* --mirrors can mean --type mirror or --type raid1 depending on config setting. */ + + if (arg_is_set(cmd, mirrors_ARG) && mirrors_type && !strcmp(mirrors_type, SEG_TYPE_NAME_MIRROR)) + return _convert_striped_mirror(cmd, lv, lp); + + if (arg_is_set(cmd, mirrors_ARG) && mirrors_type && !strcmp(mirrors_type, SEG_TYPE_NAME_RAID1)) + return _convert_striped_raid(cmd, lv, lp); + + log_error("Unknown operation on striped or linear LV %s.", display_lvname(lv)); + return 0; +} + +static int _lvconvert_raid_types(struct cmd_context *cmd, struct logical_volume *lv, + struct lvconvert_params *lp) +{ + struct lv_segment *seg = first_seg(lv); + int ret = 0; + + /* Set up segtype either from type_str or else to match the existing one. */ + if (!*lp->type_str) + lp->segtype = seg->segtype; + else if (!(lp->segtype = get_segtype_from_string(cmd, lp->type_str))) + goto_out; + + if (!strcmp(lp->type_str, SEG_TYPE_NAME_MIRROR)) { + if (!lp->mirrors_supplied && !seg_is_raid1(seg)) { + log_error("Conversions to --type mirror require -m/--mirrors"); + goto out; + } + } + + /* lv->segtype can't be NULL */ + if (activation() && lp->segtype->ops->target_present && + !lp->segtype->ops->target_present(cmd, NULL, &lp->target_attr)) { + log_error("%s: Required device-mapper target(s) not " + "detected in your kernel.", lp->segtype->name); + goto out; + } + + /* Process striping parameters */ + /* FIXME This is incomplete */ + if (_mirror_or_raid_type_requested(cmd, lp->type_str) || _raid0_type_requested(lp->type_str) || + _striped_type_requested(lp->type_str) || lp->mirrorlog || lp->corelog) { + /* FIXME Handle +/- adjustments too? */ + if (!get_stripe_params(cmd, lp->segtype, &lp->stripes, &lp->stripe_size, &lp->stripes_supplied, &lp->stripe_size_supplied)) + goto_out; + + if (_raid0_type_requested(lp->type_str) || _striped_type_requested(lp->type_str)) + /* FIXME Shouldn't need to override get_stripe_params which defaults to 1 stripe (i.e. linear)! */ + /* The default keeps existing number of stripes, handled inside the library code */ + if (!arg_is_set(cmd, stripes_long_ARG)) + lp->stripes = 0; + } + + if (lv_is_cache(lv)) + lv = seg_lv(first_seg(lv), 0); + + if (lv_is_mirror(lv)) { + ret = _convert_mirror(cmd, lv, lp); + goto out; + } + + if (lv_is_raid(lv)) { + ret = _convert_raid(cmd, lv, lp); + goto out; + } + + /* + * FIXME: add lv_is_striped() and lv_is_linear()? + * This does not include raid0 which is caught by the test above. + * If operations differ between striped and linear, split this case. + */ + if (segtype_is_striped(seg->segtype) || segtype_is_linear(seg->segtype)) { + ret = _convert_striped(cmd, lv, lp); + goto out; + } + + /* + * The intention is to explicitly check all cases above and never + * reach here, but this covers anything that was missed. + */ + log_error("Cannot convert LV %s.", display_lvname(lv)); + +out: + return ret ? ECMD_PROCESSED : ECMD_FAILED; +} + static int _lvconvert_splitsnapshot(struct cmd_context *cmd, struct logical_volume *cow) { struct volume_group *vg = cow->vg; @@ -2164,142 +2423,6 @@ deactivate_pmslv: return 1; } -/* Currently converts only to thin volume with external origin */ -static int _lvconvert_thin(struct cmd_context *cmd, - struct logical_volume *lv, - struct lvconvert_params *lp) -{ - struct logical_volume *torigin_lv, *pool_lv = lp->pool_data_lv; - struct volume_group *vg = lv->vg; - struct lvcreate_params lvc = { - .activate = CHANGE_AEY, - .alloc = ALLOC_INHERIT, - .lv_name = lp->origin_name, - .major = -1, - .minor = -1, - .suppress_zero_warn = 1, /* Suppress warning for this thin */ - .permission = LVM_READ, - .pool_name = pool_lv->name, - .pvh = &vg->pvs, - .read_ahead = DM_READ_AHEAD_AUTO, - .stripes = 1, - .virtual_extents = lv->le_count, - }; - - if (lv == pool_lv) { - log_error("Can't use same LV %s for thin pool and thin volume.", - display_lvname(pool_lv)); - return 0; - } - - if (lv_is_locked(lv) || - !lv_is_visible(lv) || - lv_is_cow(lv) || - lv_is_pool(lv) || - lv_is_pool_data(lv) || - lv_is_pool_metadata(lv)) { - log_error("Can't use%s%s %s %s as external origin.", - lv_is_locked(lv) ? " locked" : "", - lv_is_visible(lv) ? "" : " hidden", - lvseg_name(first_seg(lv)), - display_lvname(lv)); - return 0; - } - - if (is_lockd_type(lv->vg->lock_type)) { - /* - * FIXME: external origins don't work in lockd VGs. - * Prior to the lvconvert, there's a lock associated with - * the uuid of the external origin LV. After the convert, - * that uuid belongs to the new thin LV, and a new LV with - * a new uuid exists as the non-thin, readonly external LV. - * We'd need to remove the lock for the previous uuid - * (the new thin LV will have no lock), and create a new - * lock for the new LV uuid used by the external LV. - */ - log_error("Can't use lock_type %s LV as external origin.", - lv->vg->lock_type); - return 0; - } - - dm_list_init(&lvc.tags); - - if (!pool_supports_external_origin(first_seg(pool_lv), lv)) - return_0; - - if (!(lvc.segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_THIN))) - return_0; - - if (!archive(vg)) - return_0; - - /* New thin LV needs to be created (all messages sent to pool) - * In this case thin volume is created READ-ONLY and - * also warn about not zeroing is suppressed. */ - if (!(torigin_lv = lv_create_single(vg, &lvc))) - return_0; - - /* Deactivate prepared Thin LV */ - if (!deactivate_lv(cmd, torigin_lv)) { - log_error("Aborting. Unable to deactivate new LV. " - "Manual intervention required."); - return 0; - } - - /* - * Crashing till this point will leave plain thin volume - * which could be easily removed by the user after i.e. power-off - */ - - if (!swap_lv_identifiers(cmd, torigin_lv, lv)) { - stack; - goto revert_new_lv; - } - - /* Preserve read-write status of original LV here */ - torigin_lv->status |= (lv->status & LVM_WRITE); - - if (!attach_thin_external_origin(first_seg(torigin_lv), lv)) { - stack; - goto revert_new_lv; - } - - if (!lv_update_and_reload(torigin_lv)) { - stack; - goto deactivate_and_revert_new_lv; - } - - log_print_unless_silent("Converted %s to thin volume with " - "external origin %s.", - display_lvname(torigin_lv), - display_lvname(lv)); - - return 1; - -deactivate_and_revert_new_lv: - if (!swap_lv_identifiers(cmd, torigin_lv, lv)) - stack; - - if (!deactivate_lv(cmd, torigin_lv)) { - log_error("Unable to deactivate failed new LV. " - "Manual intervention required."); - return 0; - } - - if (!detach_thin_external_origin(first_seg(torigin_lv))) - return_0; - -revert_new_lv: - /* FIXME Better to revert to backup of metadata? */ - if (!lv_remove(torigin_lv) || !vg_write(vg) || !vg_commit(vg)) - log_error("Manual intervention may be required to remove " - "abandoned LV(s) before retrying."); - else - backup(vg); - - return 0; -} - static int _lvconvert_to_thin_with_external(struct cmd_context *cmd, struct logical_volume *lv, struct logical_volume *thinpool_lv) @@ -2438,581 +2561,6 @@ revert_new_lv: return 0; } -static int _lvconvert_update_pool_params(struct logical_volume *pool_lv, - struct lvconvert_params *lp) -{ - if (lp->pool_metadata_size && - !(lp->pool_metadata_extents = - extents_from_size(pool_lv->vg->cmd, lp->pool_metadata_size, pool_lv->vg->extent_size))) - return_0; - - return update_pool_params(lp->segtype, - pool_lv->vg, - lp->target_attr, - lp->passed_args, - pool_lv->le_count, - &lp->pool_metadata_extents, - &lp->thin_chunk_size_calc_policy, - &lp->chunk_size, - &lp->discards, - &lp->zero); -} - -/* - * Converts a data lv and a metadata lv into a thin or cache pool lv. - * - * Thin lvconvert version which - * rename metadata - * convert/layers thinpool over data - * attach metadata - * - * pool_lv might or might not already be a pool. - */ -static int _lvconvert_pool(struct cmd_context *cmd, - struct logical_volume *pool_lv, - struct lvconvert_params *lp) -{ - int r = 0; - const char *old_name; - struct lv_segment *seg; - struct volume_group *vg = pool_lv->vg; - struct logical_volume *data_lv; - struct logical_volume *metadata_lv = NULL; - struct logical_volume *pool_metadata_lv; - char *lockd_data_args = NULL; - char *lockd_meta_args = NULL; - char *lockd_data_name = NULL; - char *lockd_meta_name = NULL; - struct id lockd_data_id; - struct id lockd_meta_id; - char metadata_name[NAME_LEN], data_name[NAME_LEN]; - int zero_metadata = 1; - int activate_pool; - - if (lp->pool_data_name) { - if ((lp->thin || lp->cache) && - !strcmp(lp->pool_data_name, pool_lv->name)) { - log_error("Converted volume %s and pool volume must differ.", - display_lvname(pool_lv)); - return 0; - } - if (!(pool_lv = find_lv(vg, lp->pool_data_name))) { - log_error("Unknown pool data LV %s.", lp->pool_data_name); - return 0; - } - } - - /* An existing LV needs to have its lock freed once it becomes a data LV. */ - if (is_lockd_type(vg->lock_type) && !lv_is_pool(pool_lv) && pool_lv->lock_args) { - lockd_data_args = dm_pool_strdup(cmd->mem, pool_lv->lock_args); - lockd_data_name = dm_pool_strdup(cmd->mem, pool_lv->name); - memcpy(&lockd_data_id, &pool_lv->lvid.id[1], sizeof(struct id)); - } - - if (!lv_is_visible(pool_lv)) { - log_error("Can't convert internal LV %s.", display_lvname(pool_lv)); - return 0; - } - - if (lv_is_locked(pool_lv)) { - log_error("Can't convert locked LV %s.", display_lvname(pool_lv)); - return 0; - } - - if (lv_is_thin_pool(pool_lv) && (segtype_is_cache_pool(lp->segtype) || lp->cache)) { - log_error("Can't convert thin pool LV %s.", display_lvname(pool_lv)); - return 0; - } - - if (lv_is_cache(pool_lv) && !segtype_is_thin_pool(lp->segtype)) { - log_error("Cached LV %s could be only converted into a thin pool volume.", - display_lvname(pool_lv)); - return 0; - } - - if (lv_is_cache_pool(pool_lv) && (segtype_is_thin_pool(lp->segtype) || lp->thin)) { - log_error("Cannot convert cache pool %s as pool data volume.", - display_lvname(pool_lv)); - return 0; - } - - if (lv_is_mirror(pool_lv)) { - log_error("Mirror logical volumes cannot be used as pools."); - log_print_unless_silent("Try \"%s\" segment type instead.", SEG_TYPE_NAME_RAID1); - return 0; - } - - /* - * Only linear, striped and raid supported. - * FIXME Tidy up all these type restrictions. - */ - if (!lv_is_pool(pool_lv) && - (lv_is_thin_type(pool_lv) || - lv_is_cow(pool_lv) || lv_is_merging_cow(pool_lv) || - lv_is_origin(pool_lv) ||lv_is_merging_origin(pool_lv) || - lv_is_external_origin(pool_lv) || - lv_is_virtual(pool_lv))) { - log_error("Pool data LV %s is of an unsupported type.", display_lvname(pool_lv)); - return 0; - } - - if (lp->pool_metadata_name) { - if (!(lp->pool_metadata_lv = find_lv(vg, lp->pool_metadata_name))) { - log_error("Unknown pool metadata LV %s.", lp->pool_metadata_name); - return 0; - } - lp->pool_metadata_extents = lp->pool_metadata_lv->le_count; - metadata_lv = lp->pool_metadata_lv; - - /* An existing LV needs to have its lock freed once it becomes a meta LV. */ - if (is_lockd_type(vg->lock_type) && metadata_lv->lock_args) { - lockd_meta_args = dm_pool_strdup(cmd->mem, metadata_lv->lock_args); - lockd_meta_name = dm_pool_strdup(cmd->mem, metadata_lv->name); - memcpy(&lockd_meta_id, &metadata_lv->lvid.id[1], sizeof(struct id)); - } - - if (metadata_lv == pool_lv) { - log_error("Can't use same LV for pool data and metadata LV %s.", - display_lvname(metadata_lv)); - return 0; - } - - if (!lv_is_visible(metadata_lv)) { - log_error("Can't convert internal LV %s.", - display_lvname(metadata_lv)); - return 0; - } - - if (lv_is_locked(metadata_lv)) { - log_error("Can't convert locked LV %s.", - display_lvname(metadata_lv)); - return 0; - } - - if (lv_is_mirror(metadata_lv)) { - log_error("Mirror logical volumes cannot be used for pool metadata."); - log_print_unless_silent("Try \"%s\" segment type instead.", SEG_TYPE_NAME_RAID1); - return 0; - } - - /* FIXME Tidy up all these type restrictions. */ - if (lv_is_cache_type(metadata_lv) || - lv_is_thin_type(metadata_lv) || - lv_is_cow(metadata_lv) || lv_is_merging_cow(metadata_lv) || - lv_is_origin(metadata_lv) || lv_is_merging_origin(metadata_lv) || - lv_is_external_origin(metadata_lv) || - lv_is_virtual(metadata_lv)) { - log_error("Pool metadata LV %s is of an unsupported type.", - display_lvname(metadata_lv)); - return 0; - } - - if (!lv_is_pool(pool_lv)) { - if (!_lvconvert_update_pool_params(pool_lv, lp)) - return_0; - - if (lp->pool_metadata_extents > metadata_lv->le_count) { - log_error("Logical volume %s is too small for metadata.", - display_lvname(metadata_lv)); - return 0; - } - } - } - - if (lv_is_pool(pool_lv)) { - lp->pool_data_lv = pool_lv; - - if (!metadata_lv) { - if (arg_from_list_is_set(cmd, "is invalid with existing pool", - discards_ARG, - poolmetadatasize_ARG, -1)) - return_0; - - if (lp->thin && - arg_from_list_is_set(cmd, "is invalid with existing thin pool", - chunksize_ARG, zero_ARG, -1)) - return_0; - - if (lp->cache) { - if (!lp->chunk_size) - lp->chunk_size = first_seg(pool_lv)->chunk_size; - - if (!validate_lv_cache_chunk_size(pool_lv, lp->chunk_size)) - return_0; - - /* Check is user requested zeroing logic via [-Z y|n] */ - if (!arg_is_set(cmd, zero_ARG)) { - /* Note: requires rather deep know-how to skip zeroing */ - if (!lp->yes && - yes_no_prompt("Do you want wipe existing metadata of " - "cache pool volume %s? [y/n]: ", - display_lvname(pool_lv)) == 'n') { - log_error("Conversion aborted."); - log_error("To preserve cache metadata add option \"--zero n\"."); - log_warn("WARNING: Reusing mismatched cache pool metadata " - "MAY DESTROY YOUR DATA!"); - return 0; - } - /* Wiping confirmed, go ahead */ - if (!wipe_cache_pool(pool_lv)) - return_0; - } else if (arg_int_value(cmd, zero_ARG, 0)) { - if (!wipe_cache_pool(pool_lv)) /* Wipe according to -Z y|n */ - return_0; - } else - log_warn("WARNING: Reusing cache pool metadata %s " - "for volume caching.", display_lvname(pool_lv)); - } - - if (lp->thin || lp->cache) - /* already pool, can continue converting volume */ - return 1; - - log_error("LV %s is already pool.", display_lvname(pool_lv)); - return 0; - } - - if (lp->thin || lp->cache) { - log_error("--%s and pool metadata swap is not supported.", - lp->thin ? "thin" : "cache"); - return 0; - } - - /* FIXME cache pool */ - if (lv_is_thin_pool(pool_lv) && pool_is_active(pool_lv)) { - /* If any volume referencing pool active - abort here */ - log_error("Cannot convert pool %s with active volumes.", - display_lvname(pool_lv)); - return 0; - } - - lp->passed_args |= PASS_ARG_CHUNK_SIZE | PASS_ARG_DISCARDS | PASS_ARG_ZERO; - seg = first_seg(pool_lv); - - /* Normally do NOT change chunk size when swapping */ - if (arg_is_set(cmd, chunksize_ARG) && - (lp->chunk_size != seg->chunk_size) && - !dm_list_empty(&pool_lv->segs_using_this_lv)) { - if (lp->force == PROMPT) { - log_error("Chunk size can be only changed with --force. Conversion aborted."); - return 0; - } - log_warn("WARNING: Changing chunk size %s to " - "%s for %s pool volume.", - display_size(cmd, seg->chunk_size), - display_size(cmd, lp->chunk_size), - display_lvname(pool_lv)); - /* Ok, user has likely some serious reason for this */ - if (!lp->yes && - yes_no_prompt("Do you really want to change chunk size " - "for %s pool volume? [y/n]: ", - display_lvname(pool_lv)) == 'n') { - log_error("Conversion aborted."); - return 0; - } - } else - lp->chunk_size = seg->chunk_size; - - if (!_lvconvert_update_pool_params(pool_lv, lp)) - return_0; - - if (metadata_lv->le_count < lp->pool_metadata_extents) - log_print_unless_silent("Continuing with swap..."); - - if (!arg_is_set(cmd, discards_ARG)) - lp->discards = seg->discards; - if (!arg_is_set(cmd, zero_ARG)) - lp->zero = seg->zero_new_blocks; - - if (!lp->yes && - yes_no_prompt("Do you want to swap metadata of %s " - "pool with metadata volume %s? [y/n]: ", - display_lvname(pool_lv), - display_lvname(metadata_lv)) == 'n') { - log_error("Conversion aborted."); - return 0; - } - } else { - /* Only cache pool conversion may suppress metadata zeroing - * TODO: Maybe similar support could be useful for thin-pool, but --zero - * is already overloade and we would also need to possibly match transaction Id. */ - if (segtype_is_cache_pool(lp->segtype) && metadata_lv) - /* Check is user requested zeroing logic via [-Z y|n] (default is yes) */ - zero_metadata = arg_int_value(cmd, zero_ARG, 1); - - log_warn("WARNING: Converting logical volume %s%s%s to %s pool's data%s %s metadata wiping.", - display_lvname(pool_lv), - metadata_lv ? " and " : "", - metadata_lv ? display_lvname(metadata_lv) : "", - segtype_is_cache_pool(lp->segtype) ? "cache" : "thin", - metadata_lv ? " and metadata volumes" : " volume", - zero_metadata ? "with" : "WITHOUT"); - - if (zero_metadata) - log_warn("THIS WILL DESTROY CONTENT OF LOGICAL VOLUME (filesystem etc.)"); - else /* ATM supported only for cache pools */ - log_warn("WARNING: Using mismatched cache pool metadata " - "MAY DESTROY YOUR DATA!"); - - if (!lp->yes && - yes_no_prompt("Do you really want to convert %s%s%s? [y/n]: ", - display_lvname(pool_lv), - metadata_lv ? " and " : "", - metadata_lv ? display_lvname(metadata_lv) : "") == 'n') { - log_error("Conversion aborted."); - return 0; - } - } - - if (segtype_is_cache_pool(lp->segtype)) - activate_pool = 0; /* Cannot activate cache pool */ - else - /* Allow to have only thinpool active and restore it's active state */ - activate_pool = lv_is_active(pool_lv); - - if ((dm_snprintf(metadata_name, sizeof(metadata_name), "%s%s", - pool_lv->name, - (segtype_is_cache_pool(lp->segtype)) ? - "_cmeta" : "_tmeta") < 0) || - (dm_snprintf(data_name, sizeof(data_name), "%s%s", - pool_lv->name, - (segtype_is_cache_pool(lp->segtype)) ? - "_cdata" : "_tdata") < 0)) { - log_error("Failed to create internal lv names, " - "pool name is too long."); - return 0; - } - - if (!metadata_lv) { - if (!_lvconvert_update_pool_params(pool_lv, lp)) - return_0; - - if (!get_stripe_params(cmd, get_segtype_from_string(cmd, SEG_TYPE_NAME_STRIPED), - &lp->stripes, &lp->stripe_size, &lp->stripes_supplied, &lp->stripe_size_supplied)) - return_0; - - if (!archive(vg)) - return_0; - - if (!(metadata_lv = alloc_pool_metadata(pool_lv, metadata_name, - lp->read_ahead, lp->stripes, - lp->stripe_size, - lp->pool_metadata_extents, - lp->alloc, lp->pvh))) - return_0; - } else { - if (!deactivate_lv(cmd, metadata_lv)) { - log_error("Aborting. Failed to deactivate %s.", - display_lvname(metadata_lv)); - return 0; - } - - if (!archive(vg)) - return_0; - - /* Swap normal LV with pool's metadata LV ? */ - if (lv_is_pool(pool_lv)) { - /* Swap names between old and new metadata LV */ - seg = first_seg(pool_lv); - if (!detach_pool_metadata_lv(seg, &pool_metadata_lv)) - return_0; - old_name = metadata_lv->name; - if (!lv_rename_update(cmd, metadata_lv, "pvmove_tmeta", 0)) - return_0; - if (!lv_rename_update(cmd, pool_metadata_lv, old_name, 0)) - return_0; - - goto mda_write; - } - - if (zero_metadata) { - metadata_lv->status |= LV_TEMPORARY; - if (!activate_lv_local(cmd, metadata_lv)) { - log_error("Aborting. Failed to activate metadata lv."); - return 0; - } - - if (!wipe_lv(metadata_lv, (struct wipe_params) { .do_zero = 1 })) { - log_error("Aborting. Failed to wipe metadata lv."); - return 0; - } - } - } - - /* We are changing target type, so deactivate first */ - if (!deactivate_lv(cmd, metadata_lv)) { - log_error("Aborting. Failed to deactivate metadata lv. " - "Manual intervention required."); - return 0; - } - - if (!deactivate_lv(cmd, pool_lv)) { - log_error("Aborting. Failed to deactivate logical volume %s.", - display_lvname(pool_lv)); - return 0; - } - - data_lv = pool_lv; - old_name = data_lv->name; /* Use for pool name */ - /* - * Since we wish to have underlaying devs to match _[ct]data - * rename data LV to match pool LV subtree first, - * also checks for visible LV. - */ - /* FIXME: any more types prohibited here? */ - if (!lv_rename_update(cmd, data_lv, data_name, 0)) - return_0; - - if (!(pool_lv = lv_create_empty(old_name, NULL, - ((segtype_is_cache_pool(lp->segtype)) ? - CACHE_POOL : THIN_POOL) | - VISIBLE_LV | LVM_READ | LVM_WRITE, - ALLOC_INHERIT, vg))) { - log_error("Creation of pool LV failed."); - return 0; - } - - /* Allocate a new pool segment */ - if (!(seg = alloc_lv_segment(lp->segtype, pool_lv, 0, data_lv->le_count, - pool_lv->status, 0, NULL, 1, - data_lv->le_count, 0, 0, 0, NULL))) - return_0; - - /* Add the new segment to the layer LV */ - dm_list_add(&pool_lv->segments, &seg->list); - pool_lv->le_count = data_lv->le_count; - pool_lv->size = data_lv->size; - - if (!attach_pool_data_lv(seg, data_lv)) - return_0; - - /* - * Create a new lock for a thin pool LV. A cache pool LV has no lock. - * Locks are removed from existing LVs that are being converted to - * data and meta LVs (they are unlocked and deleted below.) - */ - if (is_lockd_type(vg->lock_type)) { - if (segtype_is_cache_pool(lp->segtype)) { - data_lv->lock_args = NULL; - metadata_lv->lock_args = NULL; - } else { - data_lv->lock_args = NULL; - metadata_lv->lock_args = NULL; - - if (!strcmp(vg->lock_type, "sanlock")) - pool_lv->lock_args = "pending"; - else if (!strcmp(vg->lock_type, "dlm")) - pool_lv->lock_args = "dlm"; - /* The lock_args will be set in vg_write(). */ - } - } - - /* FIXME: revert renamed LVs in fail path? */ - /* FIXME: any common code with metadata/thin_manip.c extend_pool() ? */ - - seg->transaction_id = 0; - -mda_write: - seg->chunk_size = lp->chunk_size; - seg->discards = lp->discards; - seg->zero_new_blocks = lp->zero ? 1 : 0; - - if (lp->cache_mode && - !cache_set_cache_mode(seg, lp->cache_mode)) - return_0; - - if ((lp->policy_name || lp->policy_settings) && - !cache_set_policy(seg, lp->policy_name, lp->policy_settings)) - return_0; - - /* Rename deactivated metadata LV to have _tmeta suffix */ - /* Implicit checks if metadata_lv is visible */ - if (lp->pool_metadata_name && - !lv_rename_update(cmd, metadata_lv, metadata_name, 0)) - return_0; - - if (!attach_pool_metadata_lv(seg, metadata_lv)) - return_0; - - if (!handle_pool_metadata_spare(vg, metadata_lv->le_count, - lp->pvh, lp->poolmetadataspare)) - return_0; - - if (!vg_write(vg) || !vg_commit(vg)) - return_0; - - if (seg->zero_new_blocks && - seg->chunk_size >= DEFAULT_THIN_POOL_CHUNK_SIZE_PERFORMANCE * 2) - log_warn("WARNING: Pool zeroing and large %s chunk size slows down " - "provisioning.", display_size(cmd, seg->chunk_size)); - - if (activate_pool && !lockd_lv(cmd, pool_lv, "ex", LDLV_PERSISTENT)) { - log_error("Failed to lock pool LV %s.", display_lvname(pool_lv)); - goto out; - } - - if (activate_pool && - !activate_lv_excl(cmd, pool_lv)) { - log_error("Failed to activate pool logical volume %s.", - display_lvname(pool_lv)); - /* Deactivate subvolumes */ - if (!deactivate_lv(cmd, seg_lv(seg, 0))) - log_error("Failed to deactivate pool data logical volume %s.", - display_lvname(seg_lv(seg, 0))); - if (!deactivate_lv(cmd, seg->metadata_lv)) - log_error("Failed to deactivate pool metadata logical volume %s.", - display_lvname(seg->metadata_lv)); - goto out; - } - - r = 1; - lp->pool_data_lv = pool_lv; - -out: - backup(vg); - - if (r) - log_print_unless_silent("Converted %s to %s pool.", - display_lvname(pool_lv), - (segtype_is_cache_pool(lp->segtype)) ? - "cache" : "thin"); - - /* - * Unlock and free the locks from existing LVs that became pool data - * and meta LVs. - */ - if (lockd_data_name) { - if (!lockd_lv_name(cmd, vg, lockd_data_name, &lockd_data_id, lockd_data_args, "un", LDLV_PERSISTENT)) - log_error("Failed to unlock pool data LV %s/%s", vg->name, lockd_data_name); - lockd_free_lv(cmd, vg, lockd_data_name, &lockd_data_id, lockd_data_args); - } - - if (lockd_meta_name) { - if (!lockd_lv_name(cmd, vg, lockd_meta_name, &lockd_meta_id, lockd_meta_args, "un", LDLV_PERSISTENT)) - log_error("Failed to unlock pool metadata LV %s/%s", vg->name, lockd_meta_name); - lockd_free_lv(cmd, vg, lockd_meta_name, &lockd_meta_id, lockd_meta_args); - } - - return r; -#if 0 -revert_new_lv: - /* TBD */ - if (!lp->pool_metadata_lv_name) { - if (!deactivate_lv(cmd, metadata_lv)) { - log_error("Failed to deactivate metadata lv."); - return 0; - } - if (!lv_remove(metadata_lv) || !vg_write(vg) || !vg_commit(vg)) - log_error("Manual intervention may be required to remove " - "abandoned LV(s) before retrying."); - else - backup(vg); - } - - return 0; -#endif -} - static int _lvconvert_swap_pool_metadata(struct cmd_context *cmd, struct logical_volume *lv, struct logical_volume *metadata_lv) @@ -3673,42 +3221,6 @@ revert_new_lv: #endif } -/* - * Convert origin into a cache LV by attaching a cache pool. - */ -static int _lvconvert_cache(struct cmd_context *cmd, - struct logical_volume *origin_lv, - struct lvconvert_params *lp) -{ - struct logical_volume *pool_lv = lp->pool_data_lv; - struct logical_volume *cache_lv; - - if (!validate_lv_cache_create_pool(pool_lv)) - return_0; - - if (!archive(origin_lv->vg)) - return_0; - - if (!(cache_lv = lv_cache_create(pool_lv, origin_lv))) - return_0; - - if (!cache_set_cache_mode(first_seg(cache_lv), lp->cache_mode)) - return_0; - - if (!cache_set_policy(first_seg(cache_lv), lp->policy_name, lp->policy_settings)) - return_0; - - cache_check_for_warns(first_seg(cache_lv)); - - if (!lv_update_and_reload(cache_lv)) - return_0; - - log_print_unless_silent("Logical volume %s is now cached.", - display_lvname(cache_lv)); - - return 1; -} - static int _lvconvert_to_cache_vol(struct cmd_context *cmd, struct logical_volume *lv, struct logical_volume *cachepool_lv) @@ -3750,919 +3262,6 @@ static int _lvconvert_to_cache_vol(struct cmd_context *cmd, return 1; } -/* - * Functions called to perform a specific operation on a specific LV type. - * - * _convert_<lvtype>_<operation> - * - * For cases where an operation does not apply to the LV itself, but - * is implicitly redirected to a sub-LV, these functions locate the - * correct sub-LV and call the operation on that sub-LV. If a sub-LV - * of the proper type is not found, these functions report the error. - * - * FIXME: the _lvconvert_foo() functions can be cleaned up since they - * are now only called for valid combinations of LV type and operation. - * After that happens, the code remaining in those functions can be - * moved into the _convert_lvtype_operation() functions below. - */ - -/* - * Separate a COW snapshot LV from its origin. - * lvconvert --splitsnapshot LV - */ -static int _convert_cow_snapshot_splitsnapshot(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - return _lvconvert_splitsnapshot(cmd, lv); -} - -/* - * Merge a COW snapshot LV into its origin. - * lvconvert --merge LV - */ -static int _convert_cow_snapshot_merge(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - /* return _lvconvert_merge_old_snapshot(cmd, lv, lp); */ -} - -/* - * Merge a snapshot thin LV into its origin. - * lvconvert --merge LV - */ - -static int _convert_thin_volume_merge(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - return _lvconvert_merge_thin_snapshot(cmd, lv); -} - -/* - * Split and preserve a cache pool from the data portion of a thin pool LV. - * lvconvert --splitcache LV - */ -static int _convert_thin_pool_splitcache(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - struct logical_volume *sublv1; - - sublv1 = seg_lv(first_seg(lv), 0); /* cached _tdata ? */ - - if (!lv_is_cache(sublv1)) { - log_error("Sub LV %s must be cache.", display_lvname(sublv1)); - return 0; - } - - /* return _lvconvert_split_cached(cmd, sublv1); */ - return 0; -} - -/* - * Split and remove a cache pool from the data portion of a thin pool LV. - * lvconvert --uncache LV - */ -static int _convert_thin_pool_uncache(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - struct logical_volume *sublv1 = NULL; - - sublv1 = seg_lv(first_seg(lv), 0); /* cached _tdata ? */ - - if (!lv_is_cache(sublv1)) { - log_error("Sub LV %s must be cache.", display_lvname(sublv1)); - return 0; - } - - /* return _lvconvert_uncache(cmd, sublv1, lp); */ - return 0; -} - -/* - * Convert the data portion of a thin pool LV to a cache LV. - * lvconvert --type cache LV - * - * Required options: - * --cachepool LV - * - * Auxiliary operation: - * Converts the --cachepool arg to a cache pool if it is not already. - * - * Alternate syntax: - * lvconvert --cache LV - */ -static int _convert_thin_pool_cache(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - /* lvconvert --type cache includes an implicit conversion of the cachepool arg to type cache-pool. */ - if (!_lvconvert_pool(cmd, lv, lp)) { - log_error("Implicit conversion of --cachepool arg to type cache-pool failed."); - return 0; - } - - /* Do we need to grab the tdata sub LV to pass on? */ - - return _lvconvert_cache(cmd, lv, lp); -} - -/* - * Replace the metadata LV in a thin pool LV. - * lvconvert --poolmetadata NewLV --thinpool LV - * FIXME: this will change so --swap-poolmetadata defines the operation. - * FIXME: should be lvconvert --swap-poolmetadata NewLV LV - */ -static int _convert_thin_pool_swapmetadata(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - return _lvconvert_pool(cmd, lv, lp); -} - -/* - * Split and preserve a cache pool from a cache LV. - * lvconvert --splitcache LV - */ -static int _convert_cache_volume_splitcache(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - /* return _lvconvert_split_cached(cmd, lv); */ - return 0; -} - -/* - * Split and remove a cache pool from a cache LV. - * lvconvert --uncache LV - */ -static int _convert_cache_volume_uncache(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - /* return _lvconvert_uncache(cmd, lv, lp); */ - return 0; -} - -/* - * Split images from the raid1|mirror origin of a cache LV and use them to create a new LV. - * lvconvert --splitmirrors Number LV - * - * Required options: - * --trackchanges | --name Name - */ -static int _convert_cache_volume_splitmirrors(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - struct logical_volume *sublv1; - - sublv1 = seg_lv(first_seg(lv), 0); - - if (lv_is_raid(sublv1)) - return _lvconvert_raid(sublv1, lp); - - if (lv_is_mirror(sublv1)) - return _lvconvert_mirrors(cmd, lv, lp); - - log_error("Sub LV %s must be raid or mirror.", display_lvname(sublv1)); - return 0; -} - -/* - * Convert a cache LV to a thin pool (using the cache LV for thin pool data). - * lvconvert --type thin-pool LV - * - * Convert a cache LV to a thin volume with cached external origin using given - * thinpool tpLV (when not yet Thinpool convert it to thin-pool first). - * Conversion is 2-step process in this case. - * Only writethrough cacheLV can be converted as external origin is read-only. - * lvconvert --thin cacheLV --thinpool tpLV - * - * Alternate syntax: - * This is equivalent to above, but not preferred because it's ambiguous and inconsistent. - * lvconvert --thinpool LV - */ -static int _convert_cache_volume_thin_pool(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - int is_clean; - const struct lv_segment *pool_seg; - - if (!_lvconvert_pool(cmd, lv, lp)) - return_0; - - if (lv_is_cache(lv) && !lv_is_pool_data(lv)) { - pool_seg = first_seg(first_seg(lv)->pool_lv); - if (pool_seg->cache_mode != CACHE_MODE_WRITETHROUGH) { - log_error("Cannot convert cache volume %s with %s cache mode to external origin.", - display_lvname(lv), - get_cache_mode_name(pool_seg)); - log_error("To proceed, run 'lvchange --cachemode writethrough %s'.", - display_lvname(lv)); - return 0; - } - - if (!lv_cache_wait_for_clean(lv, &is_clean)) - return_0; - - if (!is_clean) { - log_error("Cache %s is not clean, refusing to convert to external origin.", - display_lvname(lv)); - return 0; - } - - if (!_lvconvert_thin(cmd, lv, lp)) - return_0; - } - - return 1; -} - -/* - * Convert/Recombine cacheLV to be an origin for snapshot - * lvconvert --type snapshot cacheLV snapshotLV - */ -static int _convert_cache_volume_snapshot(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - return _lvconvert_snapshot(cmd, lv, lp->origin_name); -} - -/* - * Split a cache volume from a cache pool LV. - * lvconvert --splitcache LV - */ -static int _convert_cache_pool_splitcache(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - struct logical_volume *sublv1; - struct lv_segment *seg; - - /* When passed used cache-pool of used cached LV -> split cached LV */ - - if ((dm_list_size(&lv->segs_using_this_lv) == 1) && - (seg = get_only_segment_using_this_lv(lv)) && - seg_is_cache(seg)) - sublv1 = seg->lv; - else { - log_error("Sub LV of cache type not found."); - return 0; - } - - if (!lv_is_cache(sublv1)) { - log_error("Sub LV %s must be cache.", display_lvname(sublv1)); - return 0; - } - - /* return _lvconvert_split_cached(cmd, sublv1); */ - return 0; -} - -/* - * Replace the metadata LV in a cache pool LV. - * lvconvert --poolmetadata NewLV --cachepool LV - * FIXME: this will change so --swap-poolmetadata defines the operation. - * FIXME: should be lvconvert --swap-poolmetadata NewLV LV - */ -static int _convert_cache_pool_swapmetadata(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - return _lvconvert_pool(cmd, lv, lp); -} - -/* - * Change the number of images in a mirror LV. - * lvconvert --mirrors Number LV - */ -static int _convert_mirror_number(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - return _lvconvert_mirrors(cmd, lv, lp); -} - -/* - * Split images from a mirror LV and use them to create a new LV. - * lvconvert --splitmirrors Number LV - * - * Required options: - * --name Name - */ - -static int _convert_mirror_splitmirrors(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - return _lvconvert_mirrors(cmd, lv, lp); -} - -/* - * Change the type of log used by a mirror LV. - * lvconvert --mirrorlog Type LV - */ -static int _convert_mirror_log(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - return _lvconvert_mirrors(cmd, lv, lp); -} - -/* - * Convert mirror LV to linear LV. - * lvconvert --type linear LV - * - * Alternate syntax: - * lvconvert --mirrors 0 LV - */ -static int _convert_mirror_linear(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - return _lvconvert_mirrors(cmd, lv, lp); -} - -/* - * Convert mirror LV to raid1 LV. - * lvconvert --type raid1 LV - */ -static int _convert_mirror_raid(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - return _lvconvert_raid(lv, lp); -} - -/* - * Change the number of images in a raid1 LV. - * lvconvert --mirrors Number LV - */ -static int _convert_raid_number(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - return _lvconvert_raid(lv, lp); -} - -/* - * Split images from a raid1 LV and use them to create a new LV. - * lvconvert --splitmirrors Number LV - * - * Required options: - * --trackchanges | --name Name - */ -static int _convert_raid_splitmirrors(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - /* FIXME: split the splitmirrors section out of _lvconvert_raid and call it here. */ - return _lvconvert_raid(lv, lp); -} - -/* - * Merge a raid1 LV into originalLV if the raid1 LV was - * previously split from the originalLV using --trackchanges. - * lvconvert --merge LV - */ -static int _convert_raid_merge(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - /* FIXME: split the merge section out of _lvconvert_raid and call it here. */ - return _lvconvert_raid(lv, lp); -} - -/* - * Combine a raid* LV with a snapshot LV that was previously - * split from the raid* LV using --splitsnapshot. - * lvconvert --type snapshot LV SnapshotLV - * - * Alternate syntax: - * lvconvert --snapshot LV SnapshotLV - */ -static int _convert_raid_snapshot(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - return _lvconvert_snapshot(cmd, lv, lp->origin_name); -} - -/* - * Convert a raid* LV to a thin LV with an external origin. - * lvconvert --type thin LV - * - * Required options: - * --thinpool LV - * - * Auxiliary operation: - * Converts the --thinpool arg to a thin pool if it is not already. - * - * Alternate syntax: - * lvconvert --thin LV - */ -static int _convert_raid_thin(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - /* lvconvert --thin includes an implicit conversion of the thinpool arg to type thin-pool. */ - if (!_lvconvert_pool(cmd, lv, lp)) { - log_error("Implicit conversion of --thinpool arg to type thin-pool failed."); - return 0; - } - - return _lvconvert_thin(cmd, lv, lp); -} - -/* - * Convert a raid* LV to a cache LV. - * lvconvert --type cache LV - * - * Required options: - * --cachepool LV - * - * Auxiliary operation: - * Converts the --cachepool arg to a cache pool if it is not already. - * - * Alternate syntax: - * lvconvert --cache LV - */ -static int _convert_raid_cache(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - /* lvconvert --type cache includes an implicit conversion of the cachepool arg to type cache-pool. */ - if (!_lvconvert_pool(cmd, lv, lp)) { - log_error("Implicit conversion of --cachepool arg to type cache-pool failed."); - return 0; - } - - return _lvconvert_cache(cmd, lv, lp); -} - -/* - * Convert a raid* LV to a thin-pool LV. - * lvconvert --type thin-pool LV - * - * Alternate syntax: - * This is equivalent to above, but not preferred because it's ambiguous and inconsistent. - * lvconvert --thinpool LV - */ -static int _convert_raid_thin_pool(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - return _lvconvert_pool(cmd, lv, lp); -} - -/* - * Convert a raid* LV to cache-pool LV. - * lvconvert --type cache-pool LV - */ -static int _convert_raid_cache_pool(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - return _lvconvert_pool(cmd, lv, lp); -} - -/* - * Convert a raid* LV to use a different raid level. - * lvconvert --type raid* LV - */ -static int _convert_raid_raid(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - return _lvconvert_raid(lv, lp); -} - -/* - * Convert a raid* LV to a mirror LV. - * lvconvert --type mirror LV - */ -static int _convert_raid_mirror(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - return _lvconvert_raid(lv, lp); -} - -/* - * Convert a raid* LV to a striped LV. - * lvconvert --type striped LV - */ -static int _convert_raid_striped(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - return _lvconvert_raid(lv, lp); -} - -/* - * Convert a raid* LV to a linear LV. - * lvconvert --type linear LV - */ -static int _convert_raid_linear(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - return _lvconvert_raid(lv, lp); -} - -/* - * Merge a striped/linear LV into a raid1 LV if the striped/linear LV was - * previously split from the raid1 LV using --trackchanges. - * lvconvert --merge LV - */ -static int _convert_striped_merge(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - return _lvconvert_raid(lv, lp); -} - -/* - * Combine a linear/striped LV with a snapshot LV that was previously - * split from the linear/striped LV using --splitsnapshot. - * lvconvert --type snapshot LV SnapshotLV - * - * Alternate syntax: - * lvconvert --snapshot LV SnapshotLV - */ -static int _convert_striped_snapshot(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - return _lvconvert_snapshot(cmd, lv, lp->origin_name); -} - -/* - * Convert a striped/linear LV to a thin LV with an external origin. - * lvconvert --type thin LV - * - * Required options: - * --thinpool LV - * - * Auxiliary operation: - * Converts the --thinpool arg to a thin pool if it is not already. - * - * Alternate syntax: - * lvconvert --thin LV - */ -static int _convert_striped_thin(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - /* lvconvert --thin includes an implicit conversion of the thinpool arg to type thin-pool. */ - if (!_lvconvert_pool(cmd, lv, lp)) { - log_error("Conversion of --thinpool arg to type thin-pool failed."); - return 0; - } - - return _lvconvert_thin(cmd, lv, lp); -} - -/* - * Convert a striped/linear LV to a cache LV. - * lvconvert --type cache LV - * - * Required options: - * --cachepool LV - * - * Auxiliary operation: - * Converts the --cachepool arg to a cache pool if it is not already. - * - * Alternate syntax: - * lvconvert --cache LV - */ - -static int _convert_striped_cache(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - /* lvconvert --cache includes an implicit conversion of the cachepool arg to type cache-pool. */ - if (!_lvconvert_pool(cmd, lv, lp)) { - log_error("Conversion of --cachepool arg to type cache-pool failed."); - return 0; - } - - return _lvconvert_cache(cmd, lv, lp); -} - -/* - * Convert a striped/linear LV to a thin-pool LV. - * lvconvert --type thin-pool LV - * - * Alternate syntax: - * This is equivalent to above, but not preferred because it's ambiguous and inconsistent. - * lvconvert --thinpool LV - */ -static int _convert_striped_thin_pool(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - return _lvconvert_pool(cmd, lv, lp); -} - -/* - * Convert a striped/linear LV to a cache-pool LV. - * lvconvert --type cache-pool LV - */ -static int _convert_striped_cache_pool(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - return _lvconvert_pool(cmd, lv, lp); -} - -/* - * Convert a striped/linear LV to a mirror LV. - * lvconvert --type mirror LV - * - * Required options: - * --mirrors Number - * - * Alternate syntax: - * This is equivalent to above when global/mirror_segtype_default="mirror". - * lvconvert --mirrors Number LV - */ -static int _convert_striped_mirror(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - return _lvconvert_mirrors(cmd, lv, lp); -} - -/* - * Convert a striped/linear LV to a raid* LV. - * lvconvert --type raid* LV - * - * Required options: - * --mirrors Number - * - * Alternate syntax: - * This is equivalent to above when global/mirror_segtype_default="raid1". - * lvconvert --mirrors Number LV - */ -static int _convert_striped_raid(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - return _lvconvert_raid(lv, lp); -} - -/* - * Functions called to perform all valid operations on a given LV type. - * - * _convert_<lvtype> - */ -static int _convert_cow_snapshot(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - if (lp->splitsnapshot) - return _convert_cow_snapshot_splitsnapshot(cmd, lv, lp); - - /* FIXME: add --merge-snapshot to make this distinct from --merge-mirror. */ - if (lp->merge) - return _convert_cow_snapshot_merge(cmd, lv, lp); - - log_error("Operation not permitted on COW snapshot LV %s.", display_lvname(lv)); - log_error("Operations permitted on a COW snapshot LV are:\n" - " --splitsnapshot\n" - " --merge\n"); - return 0; -} - -static int _convert_thin_volume(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - /* FIXME: add --merge-snapshot to make this distinct from --merge-mirror. */ - if (lp->merge) - return _convert_thin_volume_merge(cmd, lv, lp); - - log_error("Operation not permitted on thin LV %s.", display_lvname(lv)); - log_error("Operations permitted on a thin LV are:\n" - " --merge\n"); - return 0; -} - -static int _convert_thin_pool(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - if (lp->splitcache) - return _convert_thin_pool_splitcache(cmd, lv, lp); - - if (lp->split) - return _convert_thin_pool_splitcache(cmd, lv, lp); - - if (lp->uncache) - return _convert_thin_pool_uncache(cmd, lv, lp); - - if (lp->cache) - return _convert_thin_pool_cache(cmd, lv, lp); - - /* FIXME: swapping the thin pool metadata LV needs a specific option like --swapmetadata */ - if (arg_is_set(cmd, poolmetadata_ARG)) - return _convert_thin_pool_swapmetadata(cmd, lv, lp); - - /* FIXME: add --swapmetadata to list of permitted operations. */ - - log_error("Operation not permitted on thin pool LV %s.", display_lvname(lv)); - log_error("Operations permitted on a thin pool LV are:\n" - " --splitcache (operates on cache sub LV)\n" - " --uncache (operates on cache sub LV)\n" - " --type cache (operates on data sub LV)\n" - " --repair\n"); - return 0; -} - -static int _convert_cache_volume(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - if (lp->splitcache) - return _convert_cache_volume_splitcache(cmd, lv, lp); - - if (lp->split) - return _convert_cache_volume_splitcache(cmd, lv, lp); - - if (lp->uncache) - return _convert_cache_volume_uncache(cmd, lv, lp); - - if (arg_is_set(cmd, splitmirrors_ARG)) - return _convert_cache_volume_splitmirrors(cmd, lv, lp); - - if (!strcmp(lp->type_str, SEG_TYPE_NAME_THIN_POOL) || - arg_is_set(cmd, thinpool_ARG)) - return _convert_cache_volume_thin_pool(cmd, lv, lp); - - if (!strcmp(lp->type_str, SEG_TYPE_NAME_SNAPSHOT) || - arg_is_set(cmd, snapshot_ARG)) - return _convert_cache_volume_snapshot(cmd, lv, lp); - - /* The --thinpool alternative for --type thin-pool is not preferred, so not shown. */ - - log_error("Operation not permitted on cache LV %s.", display_lvname(lv)); - log_error("Operations permitted on a cache LV are:\n" - " --splitcache\n" - " --uncache\n" - " --splitmirrors (operates on mirror or raid sub LV)\n" - " --type thin-pool\n"); - return 0; -} - -static int _convert_cache_pool(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - if (lp->splitcache) - return _convert_cache_pool_splitcache(cmd, lv, lp); - - if (lp->split) - return _convert_cache_pool_splitcache(cmd, lv, lp); - - /* FIXME: swapping the cache pool metadata LV needs a specific option like --swapmetadata */ - if (arg_is_set(cmd, poolmetadata_ARG)) - return _convert_cache_pool_swapmetadata(cmd, lv, lp); - - /* FIXME: add --swapmetadata to list of permitted operations. */ - - log_error("Operation not permitted on cache pool LV %s.", display_lvname(lv)); - log_error("Operations permitted on a cache pool LV are:\n" - " --splitcache (operates on cache LV)\n"); - return 0; -} - -static int _convert_mirror(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - if (arg_is_set(cmd, mirrors_ARG)) - return _convert_mirror_number(cmd, lv, lp); - - if (arg_is_set(cmd, splitmirrors_ARG)) - return _convert_mirror_splitmirrors(cmd, lv, lp); - - if (arg_is_set(cmd, mirrorlog_ARG) || arg_is_set(cmd, corelog_ARG)) - return _convert_mirror_log(cmd, lv, lp); - - if (_linear_type_requested(lp->type_str)) - return _convert_mirror_linear(cmd, lv, lp); - - if (segtype_is_raid(lp->segtype)) - return _convert_mirror_raid(cmd, lv, lp); - - log_error("Unknown operation on mirror LV %s.", display_lvname(lv)); - return 0; -} - -static int _convert_raid(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - if (arg_is_set(cmd, mirrors_ARG)) - return _convert_raid_number(cmd, lv, lp); - - if (arg_is_set(cmd, splitmirrors_ARG)) - return _convert_raid_splitmirrors(cmd, lv, lp); - - if (segtype_is_raid(lp->segtype)) - return _convert_raid_raid(cmd, lv, lp); - - if (segtype_is_mirror(lp->segtype)) - return _convert_raid_mirror(cmd, lv, lp); - - if (!strcmp(lp->type_str, SEG_TYPE_NAME_STRIPED)) - return _convert_raid_striped(cmd, lv, lp); - - if (_linear_type_requested(lp->type_str)) - return _convert_raid_linear(cmd, lv, lp); - - log_error("Unknown operation on raid LV %s.", display_lvname(lv)); - return 0; -} - -static int _convert_striped(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - const char *mirrors_type = find_config_tree_str(cmd, global_mirror_segtype_default_CFG, NULL); - - if (!strcmp(lp->type_str, SEG_TYPE_NAME_MIRROR)) - return _convert_striped_mirror(cmd, lv, lp); - - if (segtype_is_raid(lp->segtype)) - return _convert_striped_raid(cmd, lv, lp); - - /* --mirrors can mean --type mirror or --type raid1 depending on config setting. */ - - if (arg_is_set(cmd, mirrors_ARG) && mirrors_type && !strcmp(mirrors_type, SEG_TYPE_NAME_MIRROR)) - return _convert_striped_mirror(cmd, lv, lp); - - if (arg_is_set(cmd, mirrors_ARG) && mirrors_type && !strcmp(mirrors_type, SEG_TYPE_NAME_RAID1)) - return _convert_striped_raid(cmd, lv, lp); - - log_error("Unknown operation on striped or linear LV %s.", display_lvname(lv)); - return 0; -} - -/* - * Main entry point. - * lvconvert performs a specific <operation> on a specific <lv_type>. - * - * The <operation> is specified by command line args. - * The <lv_type> is found using lv_is_foo(lv) functions. - * - * for each lvtype, - * _convert_lvtype(); - * for each arg_is_set(operation) - * _convert_lvtype_operation(); - * - * FIXME: this code (identifying/routing each unique operation through - * _convert_lvtype_op) was designed to work based on the new type that - * the user entered after --type, not the final segment type in lp->type_str. - * Sometimes the two differ because tricks are played with lp->type_str. - * So, when the use of arg_type_str(type_ARG) here was replaced with - * lp->type_str, some commands are no longer identified/routed correctly. - */ -static int _lvconvert(struct cmd_context *cmd, struct logical_volume *lv, - struct lvconvert_params *lp) -{ - struct lv_segment *seg = first_seg(lv); - int ret = 0; - - /* Set up segtype either from type_str or else to match the existing one. */ - if (!*lp->type_str) - lp->segtype = seg->segtype; - else if (!(lp->segtype = get_segtype_from_string(cmd, lp->type_str))) - goto_out; - - if (!strcmp(lp->type_str, SEG_TYPE_NAME_MIRROR)) { - if (!lp->mirrors_supplied && !seg_is_raid1(seg)) { - log_error("Conversions to --type mirror require -m/--mirrors"); - goto out; - } - } - - /* lv->segtype can't be NULL */ - if (activation() && lp->segtype->ops->target_present && - !lp->segtype->ops->target_present(cmd, NULL, &lp->target_attr)) { - log_error("%s: Required device-mapper target(s) not " - "detected in your kernel.", lp->segtype->name); - goto out; - } - - /* Process striping parameters */ - /* FIXME This is incomplete */ - if (_mirror_or_raid_type_requested(cmd, lp->type_str) || _raid0_type_requested(lp->type_str) || - _striped_type_requested(lp->type_str) || lp->mirrorlog || lp->corelog) { - /* FIXME Handle +/- adjustments too? */ - if (!get_stripe_params(cmd, lp->segtype, &lp->stripes, &lp->stripe_size, &lp->stripes_supplied, &lp->stripe_size_supplied)) - goto_out; - - if (_raid0_type_requested(lp->type_str) || _striped_type_requested(lp->type_str)) - /* FIXME Shouldn't need to override get_stripe_params which defaults to 1 stripe (i.e. linear)! */ - /* The default keeps existing number of stripes, handled inside the library code */ - if (!arg_is_set(cmd, stripes_long_ARG)) - lp->stripes = 0; - } - - if (lv_is_cache(lv)) - lv = seg_lv(first_seg(lv), 0); - - if (lv_is_mirror(lv)) { - ret = _convert_mirror(cmd, lv, lp); - goto out; - } - - if (lv_is_raid(lv)) { - ret = _convert_raid(cmd, lv, lp); - goto out; - } - - /* - * FIXME: add lv_is_striped() and lv_is_linear()? - * This does not include raid0 which is caught by the test above. - * If operations differ between striped and linear, split this case. - */ - if (segtype_is_striped(seg->segtype) || segtype_is_linear(seg->segtype)) { - ret = _convert_striped(cmd, lv, lp); - goto out; - } - - /* - * The intention is to explicitly check all cases above and never - * reach here, but this covers anything that was missed. - */ - log_error("Cannot convert LV %s.", display_lvname(lv)); - -out: - return ret ? ECMD_PROCESSED : ECMD_FAILED; -} - static struct convert_poll_id_list* _convert_poll_id_list_create(struct cmd_context *cmd, const struct logical_volume *lv) { @@ -4975,11 +3574,6 @@ int lvconvert_replace_pv_cmd(struct cmd_context *cmd, int argc, char **argv) /* - * snapshot-related lvconvert utilities - */ - - -/* * Merge a COW snapshot LV into its origin. */ @@ -5646,7 +4240,7 @@ static int _lvconvert_raid_types_single(struct cmd_context *cmd, struct logical_ lp->lv_to_poll = lv; - ret = _lvconvert(cmd, lv, lp); + ret = _lvconvert_raid_types(cmd, lv, lp); if (ret != ECMD_PROCESSED) return_ECMD_FAILED; @@ -5790,8 +4384,8 @@ static int _lvconvert_change_mirrorlog_single(struct cmd_context *cmd, struct lo lp->pvh = use_pvh; - /* FIXME: extract the mirrorlog functionality out of _lvconvert()? */ - return _lvconvert(cmd, lv, lp); + /* FIXME: extract the mirrorlog functionality out of _lvconvert_raid_types()? */ + return _lvconvert_raid_types(cmd, lv, lp); } int lvconvert_change_mirrorlog_cmd(struct cmd_context * cmd, int argc, char **argv) @@ -5846,8 +4440,8 @@ static int _lvconvert_split_mirror_images_single(struct cmd_context *cmd, struct lp->pvh = use_pvh; - /* FIXME: extract the split functionality out of _lvconvert()? */ - return _lvconvert(cmd, lv, lp); + /* FIXME: extract the split functionality out of _lvconvert_raid_types()? */ + return _lvconvert_raid_types(cmd, lv, lp); } int lvconvert_split_mirror_images_cmd(struct cmd_context * cmd, int argc, char **argv) |