diff options
author | David Teigland <teigland@redhat.com> | 2019-04-16 14:26:18 -0500 |
---|---|---|
committer | David Teigland <teigland@redhat.com> | 2019-04-17 12:59:14 -0500 |
commit | a8d73d28bff88bccce33e0af2fdc32157c040160 (patch) | |
tree | 016178e16c62cd2cfcbfa676bb83fb6fb553e229 | |
parent | abba3efe9e90618e554aae834efd287efc40d6f4 (diff) | |
download | lvm2-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.h | 7 | ||||
-rw-r--r-- | tools/command-lines.in | 7 | ||||
-rw-r--r-- | tools/lvconvert.c | 113 | ||||
-rw-r--r-- | tools/lvmcmdline.c | 1 | ||||
-rw-r--r-- | tools/tools.h | 1 |
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); |