summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Teigland <teigland@redhat.com>2019-04-16 14:26:18 -0500
committerDavid Teigland <teigland@redhat.com>2019-04-17 12:59:14 -0500
commita8d73d28bff88bccce33e0af2fdc32157c040160 (patch)
tree016178e16c62cd2cfcbfa676bb83fb6fb553e229
parentabba3efe9e90618e554aae834efd287efc40d6f4 (diff)
downloadlvm2-a8d73d28bff88bccce33e0af2fdc32157c040160.tar.gz
lvconvert: add command to replace a cachevol
The new command: lvconvert --replace-cachevol LV LV_cache replaces the current cachevol LV with the new LV named by the option. This is used to replace a damaged cachevol with a repaired copy. (A cachevol LV is a single LV that holds both metadata and data for dm-cache.) The LV named by --replace-cachevol should contain a full, repaired copy of the cachevol LV that is currently attached to the main LV. The repaired copy should have been made by copying the current cachevol LV to the new cachevol LV, and then running cache_repair on the new cachevol LV. If cache_repair was successful, then this command is used to replace the current damaged cachevol with the repaired copy. Example where the current cachevol "fast" is damanged, and a repaired copy of fast has been made on "fast2": $ lvs -a vg -o+segtype LV VG Attr LSize Pool Origin Type [fast] vg Cwi---C--- 32.00m linear fast2 vg -wi------- 32.00m linear main vg Cwi---C--- 1.00g [fast] [main_corig] cache [main_corig] vg owi---C--- 1.00g linear $ lvconvert --replacecachevol fast2 vg/main 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 -o+segtype LV VG Attr LSize Pool Origin Type fast vg -wi------- 32.00m linear [fast2] vg Cwi---C--- 32.00m linear main vg Cwi---C--- 1.00g [fast2] [main_corig] cache [main_corig] vg owi---C--- 1.00g linear
-rw-r--r--tools/args.h7
-rw-r--r--tools/command-lines.in7
-rw-r--r--tools/lvconvert.c113
-rw-r--r--tools/lvmcmdline.c1
-rw-r--r--tools/tools.h1
5 files changed, 129 insertions, 0 deletions
diff --git a/tools/args.h b/tools/args.h
index 3d72e8a20..0f4da195e 100644
--- a/tools/args.h
+++ b/tools/args.h
@@ -543,6 +543,13 @@ 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 current cachevol LV with the LV named by this"
+ "option. The current cachevol LV will be detached from the"
+ "main LV, and will become visible and unused. The replacement"
+ "cachevol LV will be attached to the main LV, and will become"
+ "hidden and used for caching.")
+
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 0de3de71e..5d0d81969 100644
--- a/tools/command-lines.in
+++ b/tools/command-lines.in
@@ -612,6 +612,13 @@ FLAGS: SECONDARY_SYNTAX
---
+lvconvert --replacecachevol LV LV_cache
+OO: OO_LVCONVERT
+ID: lvconvert_replace_cachevol
+DESC: Replace the current cachevol with the named LV.
+
+---
+
# lvconvert --merge is an extremely ambiguous command.
# It can do very different operations, but which one depends
# on knowing the LV type. So, the command doesn't know what
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 24db8d20f..5a4455bf0 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -5643,6 +5643,119 @@ int lvconvert_to_cache_with_cachevol_cmd(struct cmd_context *cmd, int argc, char
return ret;
}
+static int _lvconvert_cachevol_replace_single(struct cmd_context *cmd,
+ struct logical_volume *lv,
+ struct processing_handle *handle)
+{
+ struct volume_group *vg = lv->vg;
+ struct logical_volume *lv_fast_old = first_seg(lv)->pool_lv;
+ struct logical_volume *lv_fast_new;
+ struct lv_segment *cache_seg = first_seg(lv);
+ const char *fast_new_name;
+
+ if (!lv_is_cache(lv)) {
+ log_error("LV %s is not being cached.", display_lvname(lv));
+ return 0;
+ }
+
+ if (!lv_fast_old) {
+ log_error("LV %s has no cachevol.", display_lvname(lv));
+ return 0;
+ }
+
+ if (!lv_is_cache_vol(lv_fast_old)) {
+ log_error("LV %s is not a cachevol.", display_lvname(lv_fast_old));
+ return 0;
+ }
+
+ if (lv_is_active(lv)) {
+ log_error("LV %s must be inactive.", display_lvname(lv));
+ return 0;
+ }
+
+ if (lv_is_active(lv_fast_old)) {
+ log_error("LV %s must be inactive.", display_lvname(lv_fast_old));
+ return 0;
+ }
+
+ fast_new_name = arg_str_value(cmd, replacecachevol_ARG, "");
+
+ if (!(lv_fast_new = find_lv(vg, fast_new_name))) {
+ log_error("LV %s not found.", fast_new_name);
+ return 0;
+ }
+
+ if (lv_is_active(lv_fast_new)) {
+ log_error("LV %s must be inactive.", display_lvname(lv_fast_new));
+ return 0;
+ }
+
+ 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 0;
+ }
+
+ if (!arg_is_set(cmd, yes_ARG) &&
+ yes_no_prompt("Replace current cachevol %s with %s for caching %s? [y/n]: ",
+ lv_fast_old->name,
+ lv_fast_new->name,
+ display_lvname(lv)) == 'n') {
+ return 0;
+ }
+
+ if (!archive(vg))
+ return_0;
+
+
+ /* remove lv_fast_old from the cachevol role */
+ remove_seg_from_segs_using_this_lv(lv_fast_old, cache_seg);
+ lv_fast_old->status &= ~LV_CACHE_VOL;
+ lv_set_visible(lv_fast_old);
+
+ /* 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(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_cachevol_replace_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_cachevol_replace_single);
+
+ destroy_processing_handle(cmd, handle);
+
+ if (!ret)
+ log_error("Cache volume not replaced.");
+
+ return ret;
+}
+
/*
* All lvconvert command defs have their own function,
* so the generic function name is unused.
diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c
index 1e3b1e382..ddc022d63 100644
--- a/tools/lvmcmdline.c
+++ b/tools/lvmcmdline.c
@@ -132,6 +132,7 @@ static const struct command_function _command_functions[CMD_COUNT] = {
{ lvconvert_merge_thin_CMD, lvconvert_merge_thin_cmd },
{ lvconvert_split_and_keep_cache_CMD, lvconvert_split_cache_cmd },
{ lvconvert_split_and_remove_cache_CMD, lvconvert_split_cache_cmd },
+ { lvconvert_replace_cachevol_CMD, lvconvert_cachevol_replace_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 69132a561..36882c3e1 100644
--- a/tools/tools.h
+++ b/tools/tools.h
@@ -258,6 +258,7 @@ int lvconvert_swap_pool_metadata_cmd(struct cmd_context *cmd, int argc, char **a
int lvconvert_to_pool_or_swap_metadata_cmd(struct cmd_context *cmd, int argc, char **argv);
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_cachevol_replace_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);