summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Teigland <teigland@redhat.com>2016-12-08 16:22:26 -0600
committerDavid Teigland <teigland@redhat.com>2016-12-08 16:22:26 -0600
commit8922384099c2f9f11ec917f395ace6195ec80f15 (patch)
tree350585df589410a2d451cf3711a371a60893392b
parent4df2157c7262d17c021d274211d1a2859a824dc5 (diff)
downloadlvm2-dev-dct-cmd-defs55.tar.gz
lvconvert: use command defs for pool metadata swapdev-dct-cmd-defs55
-rw-r--r--test/shell/lvconvert-thin.sh18
-rw-r--r--tools/args.h1
-rw-r--r--tools/command-lines.in12
-rw-r--r--tools/lvconvert.c229
-rw-r--r--tools/lvmcmdline.c3
-rw-r--r--tools/tools.h1
6 files changed, 248 insertions, 16 deletions
diff --git a/test/shell/lvconvert-thin.sh b/test/shell/lvconvert-thin.sh
index 2144bd23b..f765591e1 100644
--- a/test/shell/lvconvert-thin.sh
+++ b/test/shell/lvconvert-thin.sh
@@ -81,9 +81,9 @@ grep "Pool zeroing and large" err
UUID=$(get lv_field $vg/$lv2 uuid)
# Fail is pool is active
# TODO maybe detect inactive pool and deactivate
-fail lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $lv2
+fail lvconvert --swapmetadata --yes --poolmetadata $lv2 $vg/$lv1
lvchange -an $vg
-lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $lv2
+lvconvert --swapmetadata --yes --poolmetadata $lv2 $vg/$lv1
check lv_field $vg/${lv1}_tmeta uuid "$UUID"
lvremove -f $vg
@@ -96,20 +96,20 @@ lvcreate -L1M -n $lv3 $vg
# chunk size is bigger then size of thin pool data
fail lvconvert --yes -c 1G --thinpool $vg/$lv3
# stripes can't be used with poolmetadata
-invalid lvconvert --stripes 2 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
+not lvconvert --stripes 2 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
# too small metadata (<2M)
fail lvconvert --yes -c 64 --thinpool $vg/$lv1 --poolmetadata $vg/$lv3
# too small chunk size fails
-invalid lvconvert -c 4 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
+not lvconvert -c 4 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
# too big chunk size fails
-invalid lvconvert -c 2G --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
+not lvconvert -c 2G --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
# negative chunk size fails
-invalid lvconvert -c -256 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
+not lvconvert -c -256 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
# non multiple of 64KiB fails
-invalid lvconvert -c 88 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
+not lvconvert -c 88 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
# cannot use same LV for pool and convertion
-invalid lvconvert --yes --thinpool $vg/$lv3 -T $vg/$lv3
+not lvconvert --yes --thinpool $vg/$lv3 -T $vg/$lv3
# Warning about smaller then suggested
lvconvert --yes -c 256 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2 2>&1 | tee err
@@ -129,7 +129,7 @@ if test "$TSIZE" = 64T; then
lvcreate -L24T -n $lv1 $vg
# Warning about bigger then needed (24T data and 16G -> 128K chunk)
lvconvert --yes -c 64 --thinpool $vg/$lv1 2>&1 | tee err
-grep "WARNING: Chunk size is too small" err
+grep "too small" err
lvremove -f $vg
fi
diff --git a/tools/args.h b/tools/args.h
index 3560c9c93..654f7189e 100644
--- a/tools/args.h
+++ b/tools/args.h
@@ -120,6 +120,7 @@ arg(showdeprecated_ARG, '\0', "showdeprecated", 0, 0, 0)
arg(showunsupported_ARG, '\0', "showunsupported", 0, 0, 0)
arg(startpoll_ARG, '\0', "startpoll", 0, 0, 0)
arg(stripes_long_ARG, '\0', "stripes", number_VAL, 0, 0)
+arg(swapmetadata_ARG, '\0', "swapmetadata", 0, 0, 0)
arg(syncaction_ARG, '\0', "syncaction", syncaction_VAL, 0, 0)
arg(sysinit_ARG, '\0', "sysinit", 0, 0, 0)
arg(systemid_ARG, '\0', "systemid", string_VAL, 0, 0)
diff --git a/tools/command-lines.in b/tools/command-lines.in
index 5768c9709..521dd8ded 100644
--- a/tools/command-lines.in
+++ b/tools/command-lines.in
@@ -481,10 +481,16 @@ DESC: Separate and delete the cache pool from a cache LV.
# FIXME: add a new option defining this operation, e.g. --swapmetadata
-lvconvert --poolmetadata LV LV_thinpool_cachepool
-OO: OO_LVCONVERT
+lvconvert --swapmetadata --poolmetadata LV LV_thinpool_cachepool
+OO: --chunksize SizeKB, OO_LVCONVERT
ID: lvconvert_swap_pool_metadata
-DESC: Swap metadata LV in a thin pool or cache pool (temporary command).
+DESC: Swap metadata LV in a thin pool or cache pool (for repair only).
+
+# alternate form, does not use explicit command option
+lvconvert --poolmetadata LV LV_thinpool_cachepool
+OO: --chunksize SizeKB, OO_LVCONVERT
+ID: lvconvert_swap_pool_metadata_deprecated
+DESC: Swap metadata LV in a thin pool or cache pool (variant, use --swapmetadata).
FLAGS: SECONDARY_SYNTAX
---
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 629bd600b..d66df7e6b 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -3373,6 +3373,143 @@ revert_new_lv:
#endif
}
+static int _lvconvert_swap_pool_metadata(struct cmd_context *cmd,
+ struct logical_volume *lv,
+ struct logical_volume *metadata_lv)
+{
+ struct volume_group *vg = lv->vg;
+ struct logical_volume *prev_metadata_lv;
+ struct lv_segment *seg;
+ struct lv_types *lvtype;
+ char meta_name[NAME_LEN];
+ const char *swap_name;
+ uint32_t chunk_size;
+ int is_thinpool;
+ int is_cachepool;
+ int lvt_enum;
+
+ is_thinpool = lv_is_thin_pool(lv);
+ is_cachepool = lv_is_cache_pool(lv);
+ lvt_enum = get_lvt_enum(metadata_lv);
+ 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 used as a metadata LV.",
+ display_lvname(metadata_lv), lvtype ? lvtype->name : "unknown");
+ return 0;
+ }
+
+ if (!lv_is_visible(metadata_lv)) {
+ log_error("Can't convert internal LV %s.",
+ display_lvname(metadata_lv));
+ return 0;
+ }
+
+ if (lv_is_locked(metadata_lv)) {
+ log_error("Can't convert locked LV %s.",
+ display_lvname(metadata_lv));
+ return 0;
+ }
+
+ if (lv_is_origin(metadata_lv) ||
+ lv_is_merging_origin(metadata_lv) ||
+ lv_is_external_origin(metadata_lv) ||
+ lv_is_virtual(metadata_lv)) {
+ log_error("Pool metadata LV %s is of an unsupported type.",
+ display_lvname(metadata_lv));
+ return 0;
+ }
+
+ /* FIXME cache pool */
+ if (is_thinpool && pool_is_active(lv)) {
+ /* If any volume referencing pool active - abort here */
+ log_error("Cannot convert pool %s with active volumes.",
+ display_lvname(lv));
+ return 0;
+ }
+
+ if ((dm_snprintf(meta_name, sizeof(meta_name), "%s%s", lv->name, is_cachepool ? "_cmeta" : "_tmeta") < 0)) {
+ log_error("Failed to create internal lv names, pool name is too long.");
+ return 0;
+ }
+
+ seg = first_seg(lv);
+
+ /* Normally do NOT change chunk size when swapping */
+
+ if (arg_is_set(cmd, chunksize_ARG)) {
+ chunk_size = arg_uint_value(cmd, chunksize_ARG, 0);
+
+ if ((chunk_size != seg->chunk_size) && !dm_list_empty(&lv->segs_using_this_lv)) {
+ if (arg_count(cmd, force_ARG) == PROMPT) {
+ log_error("Chunk size can be only changed with --force. Conversion aborted.");
+ return 0;
+ }
+
+ log_warn("WARNING: Changing chunk size %s to %s for %s pool volume.",
+ display_size(cmd, seg->chunk_size),
+ display_size(cmd, chunk_size),
+ display_lvname(lv));
+
+ /* Ok, user has likely some serious reason for this */
+ if (!arg_count(cmd, yes_ARG) &&
+ yes_no_prompt("Do you really want to change chunk size for %s pool volume? [y/n]: ",
+ display_lvname(lv)) == 'n') {
+ log_error("Conversion aborted.");
+ return 0;
+ }
+ }
+
+ seg->chunk_size = chunk_size;
+ }
+
+ if (!arg_count(cmd, yes_ARG) &&
+ yes_no_prompt("Do you want to swap metadata of %s pool with metadata volume %s? [y/n]: ",
+ display_lvname(lv),
+ display_lvname(metadata_lv)) == 'n') {
+ log_error("Conversion aborted.");
+ return 0;
+ }
+
+ if (!deactivate_lv(cmd, metadata_lv)) {
+ log_error("Aborting. Failed to deactivate %s.",
+ display_lvname(metadata_lv));
+ return 0;
+ }
+
+ if (!archive(vg))
+ return_0;
+
+ /* Swap names between old and new metadata LV */
+
+ if (!detach_pool_metadata_lv(seg, &prev_metadata_lv))
+ return_0;
+
+ swap_name = metadata_lv->name;
+
+ if (!lv_rename_update(cmd, metadata_lv, "pvmove_tmeta", 0))
+ return_0;
+
+ /* Give the previous metadata LV the name of the LV replacing it. */
+
+ if (!lv_rename_update(cmd, prev_metadata_lv, swap_name, 0))
+ return_0;
+
+ /* Rename deactivated metadata LV to have _tmeta suffix */
+
+ if (!lv_rename_update(cmd, metadata_lv, meta_name, 0))
+ return_0;
+
+ if (!attach_pool_metadata_lv(seg, metadata_lv))
+ return_0;
+
+ if (!vg_write(vg) || !vg_commit(vg))
+ return_0;
+
+ backup(vg);
+ return 1;
+}
+
/*
* Create a new pool LV, using the lv arg as the data sub LV.
* The metadata sub LV is either a new LV created here, or an
@@ -3552,12 +3689,25 @@ static int _lvconvert_to_pool(struct cmd_context *cmd,
return_0;
}
+ /* FIXME: inconsistent units */
+
+ if ((uint64_t)chunk_size > ((uint64_t)lv->le_count * vg->extent_size)) {
+ log_error("Pool data LV %s is too small (%s extents) for specified chunk size (%s).",
+ display_lvname(lv),
+ display_size(cmd, lv->le_count),
+ display_size(cmd, chunk_size));
+ return 0;
+ }
+
if (metadata_lv && (meta_extents > metadata_lv->le_count)) {
- log_error("Logical volume %s is too small for metadata.",
- display_lvname(metadata_lv));
+ log_error("Pool metadata LV %s is too small (%s extents) for required metadata (%s extents).",
+ display_lvname(metadata_lv),
+ display_size(cmd, metadata_lv->le_count),
+ display_size(cmd, meta_extents));
+ return 0;
}
- log_warn("Pool metadata extents %u chunk_size %u", meta_extents, chunk_size);
+ log_verbose("Pool metadata extents %u chunk_size %u", meta_extents, chunk_size);
/*
@@ -5859,3 +6009,76 @@ int lvconvert_to_thin_with_external_cmd(struct cmd_context *cmd, int argc, char
NULL, NULL, &_lvconvert_to_thin_with_external_single);
}
+static int _lvconvert_swap_pool_metadata_single(struct cmd_context *cmd,
+ struct logical_volume *lv,
+ struct processing_handle *handle)
+{
+ struct volume_group *vg = lv->vg;
+ struct logical_volume *metadata_lv;
+ const char *metadata_name;
+
+ if (!(metadata_name = arg_str_value(cmd, poolmetadata_ARG, NULL)))
+ goto_out;
+
+ if (!validate_lvname_param(cmd, &vg->name, &metadata_name))
+ goto_out;
+
+ if (!(metadata_lv = find_lv(vg, metadata_name))) {
+ log_error("Metadata LV %s not found.", metadata_name);
+ goto out;
+ }
+
+ if (metadata_lv == lv) {
+ log_error("Can't use same LV for pool data and metadata LV %s.",
+ display_lvname(metadata_lv));
+ goto out;
+ }
+
+ if (!_lvconvert_swap_pool_metadata(cmd, lv, metadata_lv))
+ goto_out;
+
+ return ECMD_PROCESSED;
+
+out:
+ return ECMD_FAILED;
+}
+
+int lvconvert_swap_pool_metadata_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_swap_pool_metadata_single);
+}
+
+#if 0
+int lvconvert_swap_pool_metadata_noarg_cmd(struct cmd_context *cmd, int argc, char **argv)
+{
+ struct command *new_command;
+ char *pool_name;
+
+ switch (cmd->command->command_line_enum) {
+ case lvconvert_swap_thinpool_metadata_CMD:
+ pool_name = (char *)arg_str_value(cmd, thinpool_ARG, NULL);
+ break;
+ case lvconvert_swap_cachepool_metadata_CMD:
+ pool_name = (char *)arg_str_value(cmd, cachepool_ARG, NULL);
+ break;
+ default:
+ log_error(INTERNAL_ERROR "Unknown pool conversion.");
+ return 0;
+ };
+
+ new_command = get_command(lvconvert_swap_pool_metadata_CMD);
+
+ log_debug("Changing command line id %s %d to standard form %s %d",
+ cmd->command->command_line_id, cmd->command->command_line_enum,
+ new_command->command_line_id, new_command->command_line_enum);
+
+ /* Make the LV the first position arg. */
+
+ cmd->position_argv[0] = pool_name;
+ cmd->position_argc++;
+ cmd->command = new_command;
+
+ return lvconvert_swap_pool_metadata_cmd(cmd, argc, argv);
+}
+#endif
diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c
index 390263c34..857147768 100644
--- a/tools/lvmcmdline.c
+++ b/tools/lvmcmdline.c
@@ -142,6 +142,8 @@ struct command_function command_functions[COMMAND_ID_COUNT] = {
{ lvconvert_to_cachepool_noarg_CMD, lvconvert_to_pool_noarg_cmd },
{ lvconvert_to_thin_with_external_CMD, lvconvert_to_thin_with_external_cmd },
{ lvconvert_to_cache_vol_CMD, lvconvert_to_cache_vol_cmd },
+ { lvconvert_swap_pool_metadata_CMD, lvconvert_swap_pool_metadata_cmd },
+ { lvconvert_swap_pool_metadata_deprecated_CMD, lvconvert_swap_pool_metadata_cmd },
};
#if 0
@@ -155,7 +157,6 @@ struct command_function command_functions[COMMAND_ID_COUNT] = {
/* utilities for creating/maintaining thin and cache objects. */
{ lvconvert_split_and_keep_cachepool_CMD, lvconvert_split_and_keep_cachepool_fn },
{ lvconvert_split_and_delete_cachepool_CMD, lvconvert_split_and_delete_cachepool_fn },
- { lvconvert_swap_pool_metadata_CMD, lvconvert_swap_pool_metadata_fn },
/* directed to one of the other merges (snap,thin,mirror) when all are implemented */
{ lvconvert_merge_CMD, lvconvert_merge_fn },
diff --git a/tools/tools.h b/tools/tools.h
index 2ed3bb0bc..de672b68a 100644
--- a/tools/tools.h
+++ b/tools/tools.h
@@ -264,5 +264,6 @@ 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);
+int lvconvert_swap_pool_metadata_cmd(struct cmd_context *cmd, int argc, char **argv);
#endif