diff options
author | David Teigland <teigland@redhat.com> | 2019-09-11 16:09:34 -0500 |
---|---|---|
committer | David Teigland <teigland@redhat.com> | 2019-10-07 11:57:02 -0500 |
commit | 8190204fb2e1c7dbdf28d5a756f6f759ccf20517 (patch) | |
tree | eacacb3a81bd9691fba679fef6c74746428cdabb | |
parent | f2e5abd8069c8b8db8036c93ac6bdfb969a356a9 (diff) | |
download | lvm2-8190204fb2e1c7dbdf28d5a756f6f759ccf20517.tar.gz |
new command to replace a dm-cache cachevol
This command replaces the cachevol in a cache LV
with another LV. The replacement LV should contain
a repaired copy of the cachevol. When the main LV
is activated, it will use the replacement cachevol
for caching. The previous cachevol becomes a visible,
unused LV.
$ lvs -a vg
LV VG Attr LSize Pool Origin
[fast] vg Cwi---C--- 8.00g
fast2 vg -wi------- 8.00g
main vg Cwi---C--- 32.00g [fast] [main_corig]
[main_corig] vg owi---C--- 32.00g
$ lvconvert --replacecachevol fast mm/fast2
Replace current cachevol fast with fast2 for caching vg/main? [y/n]: y
LV vg/main is now using cachevol vg/fast2 for caching.
The previous cachevol vg/fast is now unused.
$ lvs -a vg
LV VG Attr LSize Pool Origin
fast vg -wi------- 8.00g
[fast2] vg Cwi---C--- 8.00g
main vg Cwi---C--- 32.00g [fast2] [main_corig]
[main_corig] vg owi---C--- 32.00g
-rw-r--r-- | tools/args.h | 8 | ||||
-rw-r--r-- | tools/command-lines.in | 12 | ||||
-rw-r--r-- | tools/lvconvert.c | 153 | ||||
-rw-r--r-- | tools/lvmcmdline.c | 1 | ||||
-rw-r--r-- | tools/tools.h | 1 |
5 files changed, 175 insertions, 0 deletions
diff --git a/tools/args.h b/tools/args.h index 16d0d9b18..c3ea96b77 100644 --- a/tools/args.h +++ b/tools/args.h @@ -556,6 +556,14 @@ arg(replace_ARG, '\0', "replace", pv_VAL, ARG_GROUPABLE, 0, "Multiple PVs can be replaced by repeating this option.\n" "See \\fBlvmraid\\fP(7) for more information.\n") +arg(replacecachevol_ARG, '\0', "replacecachevol", lv_VAL, 0, 0, + "Replace the specified cachevol LV with the LV named in the\n" + "command's position arg. The replacement LV should hold a\n" + "repaired copy of the cache. The current cachevol LV will be\n" + "detached from the main LV, and will become visible and unused.\n" + "The replacement LV will be attached to the main LV, becoming\n" + "a hidden cachevol, and used by the main LV for caching.\n") + arg(reportformat_ARG, '\0', "reportformat", reportformat_VAL, 0, 0, "Overrides current output format for reports which is defined globally by\n" "the report/output_format setting in lvm.conf.\n" diff --git a/tools/command-lines.in b/tools/command-lines.in index 03cf3452b..82b27ae63 100644 --- a/tools/command-lines.in +++ b/tools/command-lines.in @@ -728,6 +728,8 @@ DESC: Repair a cache pool. RULE: all not lv_is_locked lv_is_pvmove RULE: --poolmetadataspare and LV_cache LV_cachepool LV_thinpool +--- + lvconvert --repaircachevol LV LV OO: OO_LVCONVERT ID: lvconvert_repair_cachevol @@ -736,6 +738,16 @@ DESC: write repaired metadata to the destination LV (in first DESC: position arg), and copy cache data from the cachevol to DESC: the destination LV. +lvconvert --replacecachevol LV LV +OO: OO_LVCONVERT +ID: lvconvert_replace_cachevol +DESC: Replace the specified cachevol LV with the LV named +DESC: in the first position arg. The replacement LV should +DESC: hold a repaired copy of the cache. The LV that was +DESC: using cachevol for caching will use the replacement. + +--- + lvconvert --replace PV LV_raid OO: OO_LVCONVERT OP: PV ... diff --git a/tools/lvconvert.c b/tools/lvconvert.c index b735c86e3..145948a91 100644 --- a/tools/lvconvert.c +++ b/tools/lvconvert.c @@ -4312,6 +4312,159 @@ int lvconvert_repair_cachevol_cmd(struct cmd_context *cmd, int argc, char **argv return ret; } +static int _lvconvert_replace_cachevol_single(struct cmd_context *cmd, + struct logical_volume *lv, + struct processing_handle *handle) +{ + struct volume_group *vg = lv->vg; + struct logical_volume *cache_lv = NULL, *cachevol_lv, *lv_fast_old, *lv_fast_new; + struct lv_segment *cache_seg = first_seg(lv); + struct lv_list *lvl; + const char *cachevol_name; + + lv_fast_new = lv; + lv = NULL; + + /* command def should prevent this */ + if (!(cachevol_name = arg_str_value(cmd, replacecachevol_ARG, ""))) + return_ECMD_FAILED; + + if (!validate_lvname_param(cmd, &vg->name, &cachevol_name)) { + log_error("Invalid cachevol LV name %s.", cachevol_name); + return ECMD_FAILED; + } + + if (!(cachevol_lv = find_lv(vg, cachevol_name))) { + log_error("Failed to find cachevol LV %s.", cachevol_name); + return ECMD_FAILED; + } + + if (!lv_is_cache_vol(cachevol_lv)) { + log_error("LV %s is not a cachevol.", display_lvname(cachevol_lv)); + return 0; + } + + /* + * Find the cache LV using the cachevol. + */ + dm_list_iterate_items(lvl, &vg->lvs) { + if (!lv_is_cache(lvl->lv)) + continue; + + if (!(cache_seg = first_seg(lvl->lv))) + continue; + + if (!lv_is_cache_vol(cache_seg->pool_lv)) + continue; + + if (cache_seg->pool_lv != cachevol_lv) + continue; + + cache_lv = lvl->lv; + break; + } + + if (!cache_lv) { + log_error("Failed to find LV using cachevol %s.", display_lvname(cachevol_lv)); + return ECMD_FAILED; + } + + if (lv_is_active(cache_lv)) { + log_error("LV %s must be inactive.", display_lvname(cache_lv)); + return ECMD_FAILED; + } + + if (lv_is_active(cachevol_lv)) { + log_error("LV %s must be inactive.", display_lvname(cachevol_lv)); + return ECMD_FAILED; + } + + if (lv_is_active(lv_fast_new)) { + log_error("LV %s must be inactive.", display_lvname(lv_fast_new)); + return ECMD_FAILED; + } + + if (!dm_list_empty(&lv_fast_new->segs_using_this_lv)) { + log_error("LV %s is already in use.", display_lvname(lv_fast_new)); + return ECMD_FAILED; + } + + if (vg_is_shared(vg)) { + /* cache LV using the cachevol cannot be active elsewhere */ + if (!lockd_lv(cmd, cache_lv, "ex", 0)) + return_ECMD_FAILED; + + /* current cachevol LV cannot be active elsewhere. */ + if (!lockd_lv(cmd, cachevol_lv, "ex", 0)) + return_ECMD_FAILED; + + /* replacement LV cannot be elsewhere. */ + if (!lockd_lv(cmd, lv_fast_new, "ex", 0)) + return_ECMD_FAILED; + } + + if (!arg_is_set(cmd, yes_ARG) && + yes_no_prompt("Replace current cachevol %s with %s for caching %s? [y/n]: ", + cachevol_lv->name, + lv_fast_new->name, + display_lvname(cache_lv)) == 'n') { + return ECMD_FAILED; + } + + if (!archive(vg)) + return_0; + + /* remove cachevol_lv from the cachevol role */ + remove_seg_from_segs_using_this_lv(cachevol_lv, cache_seg); + cachevol_lv->status &= ~LV_CACHE_VOL; + lv_set_visible(cachevol_lv); + lv_fast_old = cachevol_lv; + cachevol_lv = NULL; + + /* put lv_fast_new into the cachevol role */ + lv_fast_new->status |= LV_CACHE_VOL; + cache_seg->pool_lv = lv_fast_new; + add_seg_to_segs_using_this_lv(lv_fast_new, cache_seg); + lv_set_hidden(lv_fast_new); + + if (!vg_write(vg) || !vg_commit(vg)) + return_0; + + log_print("LV %s is now using cachevol %s for caching.", + display_lvname(cache_lv), display_lvname(lv_fast_new)); + log_print("The previous cachevol %s is now unused.", display_lvname(lv_fast_old)); + + backup(vg); + return 1; +} + +int lvconvert_replace_cachevol_cmd(struct cmd_context *cmd, int argc, char **argv) +{ + + struct processing_handle *handle; + struct lvconvert_result lr = { 0 }; + int ret; + + if (!(handle = init_processing_handle(cmd, NULL))) { + log_error("Failed to initialize processing handle."); + return ECMD_FAILED; + } + + handle->custom_handle = &lr; + + cmd->cname->flags &= ~GET_VGNAME_FROM_OPTIONS; + + ret = process_each_lv(cmd, cmd->position_argc, cmd->position_argv, NULL, NULL, READ_FOR_UPDATE, handle, NULL, + &_lvconvert_replace_cachevol_single); + + destroy_processing_handle(cmd, handle); + + if (!ret) + log_error("Cache volume not replaced."); + + return ret; +} + static int _lvconvert_replace_pv_single(struct cmd_context *cmd, struct logical_volume *lv, struct processing_handle *handle) { diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c index 6d308b6d2..24c37d292 100644 --- a/tools/lvmcmdline.c +++ b/tools/lvmcmdline.c @@ -133,6 +133,7 @@ static const struct command_function _command_functions[CMD_COUNT] = { { lvconvert_split_and_keep_cache_CMD, lvconvert_split_cache_cmd }, { lvconvert_split_and_remove_cache_CMD, lvconvert_split_cache_cmd }, { lvconvert_repair_cachevol_CMD, lvconvert_repair_cachevol_cmd }, + { lvconvert_replace_cachevol_CMD, lvconvert_replace_cachevol_cmd }, /* lvconvert raid-related type conversions */ { lvconvert_raid_types_CMD, lvconvert_raid_types_cmd }, diff --git a/tools/tools.h b/tools/tools.h index 0064d018d..59c61bd7f 100644 --- a/tools/tools.h +++ b/tools/tools.h @@ -261,6 +261,7 @@ int lvconvert_to_pool_or_swap_metadata_cmd(struct cmd_context *cmd, int argc, ch int lvconvert_merge_thin_cmd(struct cmd_context *cmd, int argc, char **argv); int lvconvert_split_cache_cmd(struct cmd_context *cmd, int argc, char **argv); int lvconvert_repair_cachevol_cmd(struct cmd_context *cmd, int argc, char **argv); +int lvconvert_replace_cachevol_cmd(struct cmd_context *cmd, int argc, char **argv); int lvconvert_raid_types_cmd(struct cmd_context * cmd, int argc, char **argv); int lvconvert_split_mirror_images_cmd(struct cmd_context * cmd, int argc, char **argv); |