diff options
author | David Teigland <teigland@redhat.com> | 2016-12-07 16:59:58 -0600 |
---|---|---|
committer | David Teigland <teigland@redhat.com> | 2016-12-08 12:11:22 -0600 |
commit | 08cf602be1dfb87a3eee551463c13187d5fc1b30 (patch) | |
tree | 83edd0e0703d95d812c3cf7f1741d528ec930963 | |
parent | 072ef008ea7db2cb6cdbd11f580713c3c5c6c8d4 (diff) | |
download | lvm2-dev-dct-cmd-defs54.tar.gz |
lvconvert: use command defs for thin and cachedev-dct-cmd-defs54
-rw-r--r-- | tools/command-lines.in | 6 | ||||
-rw-r--r-- | tools/lvconvert.c | 349 | ||||
-rw-r--r-- | tools/lvmcmdline.c | 2 | ||||
-rw-r--r-- | tools/toollib.c | 6 | ||||
-rw-r--r-- | tools/toollib.h | 2 | ||||
-rw-r--r-- | tools/tools.h | 2 |
6 files changed, 362 insertions, 5 deletions
diff --git a/tools/command-lines.in b/tools/command-lines.in index 08e5a90a4..5768c9709 100644 --- a/tools/command-lines.in +++ b/tools/command-lines.in @@ -388,6 +388,8 @@ lvconvert --type thin --thinpool LV LV_linear_striped_raid OO: --thin, --originname LV_new, --zero Bool, OO_LVCONVERT_POOL, OO_LVCONVERT ID: lvconvert_to_thin_with_external DESC: Convert LV to type thin with an external origin. +RULE: all and lv_is_visible +RULE: all not lv_is_locked # alternate form of lvconvert --type thin lvconvert --thin --thinpool LV LV_linear_striped_raid @@ -396,6 +398,8 @@ ID: lvconvert_to_thin_with_external DESC: Convert LV to type thin with an external origin DESC: (variant, infers --type thin). FLAGS: SECONDARY_SYNTAX +RULE: all and lv_is_visible +RULE: all not lv_is_locked --- @@ -404,6 +408,7 @@ OO: --cache, --cachemode CacheMode, --cachepolicy String, --cachesettings String, --zero Bool, OO_LVCONVERT_POOL, OO_LVCONVERT ID: lvconvert_to_cache_vol DESC: Convert LV to type cache. +RULE: all and lv_is_visible # alternate form of lvconvert --type cache lvconvert --cache --cachepool LV LV_linear_striped_raid_thinpool @@ -412,6 +417,7 @@ OO: --type cache, --cachemode CacheMode, --cachepolicy String, ID: lvconvert_to_cache_vol DESC: Convert LV to type cache (variant, infers --type cache). FLAGS: SECONDARY_SYNTAX +RULE: all and lv_is_visible --- diff --git a/tools/lvconvert.c b/tools/lvconvert.c index 34e9f723a..629bd600b 100644 --- a/tools/lvconvert.c +++ b/tools/lvconvert.c @@ -2660,6 +2660,144 @@ revert_new_lv: return 0; } +static int _lvconvert_to_thin_with_external(struct cmd_context *cmd, + struct logical_volume *lv, + struct logical_volume *thinpool_lv) +{ + struct volume_group *vg = lv->vg; + struct logical_volume *thin_lv; + const char *origin_name; + + struct lvcreate_params lvc = { + .activate = CHANGE_AEY, + .alloc = ALLOC_INHERIT, + .major = -1, + .minor = -1, + .suppress_zero_warn = 1, /* Suppress warning for this thin */ + .permission = LVM_READ, + .pool_name = thinpool_lv->name, + .pvh = &vg->pvs, + .read_ahead = DM_READ_AHEAD_AUTO, + .stripes = 1, + .virtual_extents = lv->le_count, + }; + + if (lv == thinpool_lv) { + log_error("Can't use same LV %s for thin pool and thin volume.", + display_lvname(thinpool_lv)); + return 0; + } + + if ((origin_name = arg_str_value(cmd, originname_ARG, NULL))) + if (!validate_restricted_lvname_param(cmd, &vg->name, &origin_name)) + return_0; + + /* + * If NULL, an auto-generated 'lvol' name is used. + * If set, the lv create code checks the name isn't used. + */ + lvc.lv_name = origin_name; + + if (is_lockd_type(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.", + vg->lock_type); + return 0; + } + + dm_list_init(&lvc.tags); + + if (!pool_supports_external_origin(first_seg(thinpool_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. + * + * The new thin LV is created with the origin_name, or an autogenerated + * 'lvol' name. Then the names and ids are swapped between the thin LV + * and the original/external LV. So, the thin LV gets the name and id + * of the original LV arg, and the original LV arg gets the origin_name + * or the autogenerated name. + */ + + if (!(thin_lv = lv_create_single(vg, &lvc))) + return_0; + + if (!deactivate_lv(cmd, thin_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, thin_lv, lv)) { + stack; + goto revert_new_lv; + } + + /* Preserve read-write status of original LV here */ + thin_lv->status |= (lv->status & LVM_WRITE); + + if (!attach_thin_external_origin(first_seg(thin_lv), lv)) { + stack; + goto revert_new_lv; + } + + if (!lv_update_and_reload(thin_lv)) { + stack; + goto deactivate_and_revert_new_lv; + } + + log_print_unless_silent("Converted %s to thin volume with external origin %s.", + display_lvname(thin_lv), display_lvname(lv)); + + return 1; + +deactivate_and_revert_new_lv: + if (!swap_lv_identifiers(cmd, thin_lv, lv)) + stack; + + if (!deactivate_lv(cmd, thin_lv)) { + log_error("Unable to deactivate failed new LV. " + "Manual intervention required."); + return 0; + } + + if (!detach_thin_external_origin(first_seg(thin_lv))) + return_0; + +revert_new_lv: + /* FIXME Better to revert to backup of metadata? */ + if (!lv_remove(thin_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_update_pool_params(struct logical_volume *pool_lv, struct lvconvert_params *lp) { @@ -3779,6 +3917,44 @@ static int _lvconvert_cache(struct cmd_context *cmd, return 1; } +static int _lvconvert_to_cache_vol(struct cmd_context *cmd, + struct logical_volume *lv, + struct logical_volume *cachepool_lv) +{ + struct logical_volume *cache_lv; + cache_mode_t cache_mode = 0; + const char *policy_name = NULL; + struct dm_config_tree *policy_settings = NULL; + + if (!validate_lv_cache_create_pool(cachepool_lv)) + return_0; + + if (!get_cache_params(cmd, &cache_mode, &policy_name, &policy_settings)) + return_0; + + if (!archive(lv->vg)) + return_0; + + if (!(cache_lv = lv_cache_create(cachepool_lv, lv))) + return_0; + + if (!cache_set_cache_mode(first_seg(cache_lv), cache_mode)) + return_0; + + if (!cache_set_policy(first_seg(cache_lv), policy_name, 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; +} + /* * Functions called to perform a specific operation on a specific LV type. * @@ -5510,3 +5686,176 @@ int lvconvert_to_pool_noarg_cmd(struct cmd_context *cmd, int argc, char **argv) return lvconvert_to_pool_cmd(cmd, argc, argv); } +static int _lvconvert_to_cache_vol_single(struct cmd_context *cmd, + struct logical_volume *lv, + struct processing_handle *handle) +{ + struct volume_group *vg = lv->vg; + struct logical_volume *cachepool_lv; + const char *cachepool_name; + uint32_t chunk_size = 0; + + if (!(cachepool_name = arg_str_value(cmd, cachepool_ARG, NULL))) + goto_out; + + if (!validate_lvname_param(cmd, &vg->name, &cachepool_name)) + goto_out; + + if (!(cachepool_lv = find_lv(vg, cachepool_name))) { + log_error("Cache pool %s not found.", cachepool_name); + goto out; + } + + /* + * If cachepool_lv is not yet a cache pool, convert it to one. + * If using an existing cache pool, wipe it. + */ + + if (!lv_is_cache_pool(cachepool_lv)) { + int lvt_enum = get_lvt_enum(cachepool_lv); + struct lv_types *lvtype = get_lv_type(lvt_enum); + + if (lvt_enum != striped_LVT && lvt_enum != linear_LVT && lvt_enum != raid_LVT) { + log_error("LV %s with type %s cannot be converted to a cache pool.", + display_lvname(cachepool_lv), lvtype ? lvtype->name : "unknown"); + goto out; + } + + if (!_lvconvert_to_pool(cmd, cachepool_lv, 0, 1, &vg->pvs)) { + log_error("LV %s could not be converted to a cache pool.", + display_lvname(cachepool_lv)); + goto out; + } + + if (!(cachepool_lv = find_lv(vg, cachepool_name))) { + log_error("LV %s cannot be found.", display_lvname(cachepool_lv)); + goto out; + } + + if (!lv_is_cache_pool(cachepool_lv)) { + log_error("LV %s is not a cache pool.", display_lvname(cachepool_lv)); + goto out; + } + } else { + if (arg_is_set(cmd, chunksize_ARG)) + chunk_size = arg_uint_value(cmd, chunksize_ARG, 0); + if (!chunk_size) + chunk_size = first_seg(cachepool_lv)->chunk_size; + + /* FIXME: why is chunk_size read and checked if it's not used? */ + + if (!validate_lv_cache_chunk_size(cachepool_lv, chunk_size)) + goto_out; + + /* Note: requires rather deep know-how to skip zeroing */ + if (!arg_is_set(cmd, zero_ARG)) { + if (!arg_is_set(cmd, yes_ARG) && + yes_no_prompt("Do you want wipe existing metadata of cache pool %s? [y/n]: ", + display_lvname(cachepool_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!"); + goto out; + } + /* Wiping confirmed, go ahead */ + if (!wipe_cache_pool(cachepool_lv)) + goto_out; + } else if (arg_int_value(cmd, zero_ARG, 0)) { + if (!wipe_cache_pool(cachepool_lv)) + goto_out; + } else { + log_warn("WARNING: Reusing cache pool metadata %s for volume caching.", + display_lvname(cachepool_lv)); + } + + } + + /* When the lv arg is a thinpool, redirect command to data sub lv. */ + + if (lv_is_thin_pool(lv)) { + lv = seg_lv(first_seg(lv), 0); + log_verbose("Redirecting operation to data sub LV %s.", display_lvname(lv)); + } + + /* Convert lv to cache vol using cachepool_lv. */ + + if (!_lvconvert_to_cache_vol(cmd, lv, cachepool_lv)) + goto_out; + + return ECMD_PROCESSED; + +out: + return ECMD_FAILED; +} + +int lvconvert_to_cache_vol_cmd(struct cmd_context *cmd, int argc, char **argv) +{ + return process_each_lv(cmd, 1, cmd->position_argv, NULL, NULL, READ_FOR_UPDATE, + NULL, NULL, &_lvconvert_to_cache_vol_single); +} + +static int _lvconvert_to_thin_with_external_single(struct cmd_context *cmd, + struct logical_volume *lv, + struct processing_handle *handle) +{ + struct volume_group *vg = lv->vg; + struct logical_volume *thinpool_lv; + const char *thinpool_name; + + if (!(thinpool_name = arg_str_value(cmd, thinpool_ARG, NULL))) + goto_out; + + if (!validate_lvname_param(cmd, &vg->name, &thinpool_name)) + goto_out; + + if (!(thinpool_lv = find_lv(vg, thinpool_name))) { + log_error("Thin pool %s not found.", thinpool_name); + goto out; + } + + /* If thinpool_lv is not yet a thin pool, convert it to one. */ + + if (!lv_is_thin_pool(thinpool_lv)) { + int lvt_enum = get_lvt_enum(thinpool_lv); + struct lv_types *lvtype = get_lv_type(lvt_enum); + + if (lvt_enum != striped_LVT && lvt_enum != linear_LVT && lvt_enum != raid_LVT) { + log_error("LV %s with type %s cannot be converted to a thin pool.", + display_lvname(thinpool_lv), lvtype ? lvtype->name : "unknown"); + goto out; + } + + if (!_lvconvert_to_pool(cmd, thinpool_lv, 1, 0, &vg->pvs)) { + log_error("LV %s could not be converted to a thin pool.", + display_lvname(thinpool_lv)); + goto out; + } + + if (!(thinpool_lv = find_lv(vg, thinpool_name))) { + log_error("LV %s cannot be found.", display_lvname(thinpool_lv)); + goto out; + } + + if (!lv_is_thin_pool(thinpool_lv)) { + log_error("LV %s is not a thin pool.", display_lvname(thinpool_lv)); + goto out; + } + } + + /* Convert lv to thin with external origin using thinpool_lv. */ + + if (!_lvconvert_to_thin_with_external(cmd, lv, thinpool_lv)) + goto_out; + + return ECMD_PROCESSED; + + out: + return ECMD_FAILED; +} + +int lvconvert_to_thin_with_external_cmd(struct cmd_context *cmd, int argc, char **argv) +{ + return process_each_lv(cmd, 1, cmd->position_argv, NULL, NULL, READ_FOR_UPDATE, + NULL, NULL, &_lvconvert_to_thin_with_external_single); +} + diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c index 30aea5c92..390263c34 100644 --- a/tools/lvmcmdline.c +++ b/tools/lvmcmdline.c @@ -140,10 +140,8 @@ struct command_function command_functions[COMMAND_ID_COUNT] = { { lvconvert_to_thinpool_noarg_CMD, lvconvert_to_pool_noarg_cmd }, { lvconvert_to_cachepool_CMD, lvconvert_to_pool_cmd }, { lvconvert_to_cachepool_noarg_CMD, lvconvert_to_pool_noarg_cmd }, -#if 0 { lvconvert_to_thin_with_external_CMD, lvconvert_to_thin_with_external_cmd }, { lvconvert_to_cache_vol_CMD, lvconvert_to_cache_vol_cmd }, -#endif }; #if 0 diff --git a/tools/toollib.c b/tools/toollib.c index 55ac47ab7..17680b13f 100644 --- a/tools/toollib.c +++ b/tools/toollib.c @@ -2540,7 +2540,7 @@ static int _lv_is_type(struct cmd_context *cmd, struct logical_volume *lv, int l return 0; } -static int _get_lvt_enum(struct logical_volume *lv) +int get_lvt_enum(struct logical_volume *lv) { struct lv_segment *seg = first_seg(lv); @@ -2696,7 +2696,7 @@ static int _check_lv_types(struct cmd_context *cmd, struct logical_volume *lv, i ret = _lv_types_match(cmd, lv, cmd->command->required_pos_args[pos-1].def.lvt_bits, NULL, NULL); if (!ret) { - int lvt_enum = _get_lvt_enum(lv); + int lvt_enum = get_lvt_enum(lv); struct lv_types *type = get_lv_type(lvt_enum); log_warn("Operation on LV %s which has invalid type %s.", display_lvname(lv), type ? type->name : "unknown"); @@ -2719,7 +2719,7 @@ static int _check_lv_rules(struct cmd_context *cmd, struct logical_volume *lv) int ret = 1; int i; - lvt_enum = _get_lvt_enum(lv); + lvt_enum = get_lvt_enum(lv); if (lvt_enum) lvtype = get_lv_type(lvt_enum); diff --git a/tools/toollib.h b/tools/toollib.h index 67e45a2ec..504721e86 100644 --- a/tools/toollib.h +++ b/tools/toollib.h @@ -240,4 +240,6 @@ int validate_restricted_lvname_param(struct cmd_context *cmd, const char **vg_na int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv, struct processing_handle *handle __attribute__((unused))); +int get_lvt_enum(struct logical_volume *lv); + #endif diff --git a/tools/tools.h b/tools/tools.h index 95b9d6775..2ed3bb0bc 100644 --- a/tools/tools.h +++ b/tools/tools.h @@ -262,5 +262,7 @@ int lvconvert_start_poll_cmd(struct cmd_context *cmd, int argc, char **argv); int lvconvert_to_pool_cmd(struct cmd_context *cmd, int argc, char **argv); int lvconvert_to_pool_noarg_cmd(struct cmd_context *cmd, int argc, char **argv); +int lvconvert_to_cache_vol_cmd(struct cmd_context *cmd, int argc, char **argv); +int lvconvert_to_thin_with_external_cmd(struct cmd_context *cmd, int argc, char **argv); #endif |