summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Teigland <teigland@redhat.com>2019-09-11 16:09:34 -0500
committerDavid Teigland <teigland@redhat.com>2019-10-07 11:57:02 -0500
commit8190204fb2e1c7dbdf28d5a756f6f759ccf20517 (patch)
treeeacacb3a81bd9691fba679fef6c74746428cdabb
parentf2e5abd8069c8b8db8036c93ac6bdfb969a356a9 (diff)
downloadlvm2-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.h8
-rw-r--r--tools/command-lines.in12
-rw-r--r--tools/lvconvert.c153
-rw-r--r--tools/lvmcmdline.c1
-rw-r--r--tools/tools.h1
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);