1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-01-03 05:18:29 +03:00

lvconvert: use command defs for pool metadata swap

This commit is contained in:
David Teigland 2016-12-08 16:22:26 -06:00
parent 4df2157c72
commit 8922384099
6 changed files with 249 additions and 17 deletions

View File

@ -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

View File

@ -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)

View File

@ -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
---

View File

@ -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;
}
if (metadata_lv && (meta_extents > metadata_lv->le_count)) {
log_error("Logical volume %s is too small for metadata.",
display_lvname(metadata_lv));
/* 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;
}
log_warn("Pool metadata extents %u chunk_size %u", meta_extents, chunk_size);
if (metadata_lv && (meta_extents > metadata_lv->le_count)) {
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_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

View File

@ -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 },

View File

@ -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