summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Teigland <teigland@redhat.com>2016-11-18 13:16:04 -0600
committerDavid Teigland <teigland@redhat.com>2016-11-18 13:16:04 -0600
commit7a79dc8a638576587babd8f06d0a5c737580e38f (patch)
tree539a63ccfd4ddfce4f82f3dc8a677dc9c9f3c515
parentd7e9a10fb4e5ab4d18e8f1881f79e5dc2ddd6f9d (diff)
downloadlvm2-dev-dct-cmd-defs46.tar.gz
lvconvert: snapshot: use command definitionsdev-dct-cmd-defs46
Lift all the snapshot utilities (merge, split, combine) out of the monolithic lvconvert implementation, using the command definitions. The old code associated with these commands is now unused and will be removed separately.
-rw-r--r--test/shell/snapshot-merge.sh6
-rw-r--r--tools/args.h1
-rw-r--r--tools/command-lines.in14
-rw-r--r--tools/lvconvert.c281
-rw-r--r--tools/lvmcmdline.c11
-rw-r--r--tools/tools.h4
6 files changed, 201 insertions, 116 deletions
diff --git a/test/shell/snapshot-merge.sh b/test/shell/snapshot-merge.sh
index a301d229e..4decf5809 100644
--- a/test/shell/snapshot-merge.sh
+++ b/test/shell/snapshot-merge.sh
@@ -88,7 +88,7 @@ lvremove -f $vg/$lv1
# to make sure preload of origin's metadata is _not_ performed
setup_merge_ $vg $lv1
mount "$(lvdev_ $vg $lv1)" test_mnt
-lvconvert --merge $vg/$(snap_lv_name_ $lv1)
+lvconvert --mergesnapshot $vg/$(snap_lv_name_ $lv1)
# -- refresh LV while FS is still mounted (merge must not start),
# verify 'snapshot-origin' target is still being used
lvchange --refresh $vg/$lv1
@@ -99,7 +99,7 @@ lvremove -f $vg/$lv1
# test multiple snapshot merge; tests copy out that is driven by merge
setup_merge_ $vg $lv1 1
-lvconvert --merge $vg/$(snap_lv_name_ $lv1)
+lvconvert --mergesnapshot $vg/$(snap_lv_name_ $lv1)
lvremove -f $vg/$lv1
@@ -108,7 +108,7 @@ setup_merge_ $vg $lv1
setup_merge_ $vg $lv2
lvchange --addtag this_is_a_test $vg/$(snap_lv_name_ $lv1)
lvchange --addtag this_is_a_test $vg/$(snap_lv_name_ $lv2)
-lvconvert --merge @this_is_a_test
+lvconvert --mergesnapshot @this_is_a_test
lvs $vg | tee out
not grep $(snap_lv_name_ $lv1) out
not grep $(snap_lv_name_ $lv2) out
diff --git a/tools/args.h b/tools/args.h
index 8f5f0ec5a..a01531888 100644
--- a/tools/args.h
+++ b/tools/args.h
@@ -60,6 +60,7 @@ arg(locktype_ARG, '\0', "locktype", locktype_VAL, 0, 0)
arg(logonly_ARG, '\0', "logonly", 0, 0, 0)
arg(maxrecoveryrate_ARG, '\0', "maxrecoveryrate", sizekb_VAL, 0, 0)
arg(merge_ARG, '\0', "merge", 0, 0, 0)
+arg(mergesnapshot_ARG, '\0', "mergesnapshot", 0, 0, 0)
arg(mergedconfig_ARG, '\0', "mergedconfig", 0, 0, 0)
arg(metadatacopies_ARG, '\0', "metadatacopies", metadatacopies_VAL, 0, 0)
arg(metadataignore_ARG, '\0', "metadataignore", bool_VAL, 0, 0)
diff --git a/tools/command-lines.in b/tools/command-lines.in
index 76203e0f5..a54017b59 100644
--- a/tools/command-lines.in
+++ b/tools/command-lines.in
@@ -505,12 +505,17 @@ DESC: Merge thin LV into its origin LV.
DESC: Merge COW snapshot LV into its origin.
RULE: all not lv_is_merging_origin lv_is_virtual_origin lv_is_external_origin lv_is_merging_cow
+lvconvert --mergesnapshot LV_snapshot ...
+OO: --background, --interval Number, OO_LVCONVERT
+ID: lvconvert_merge_snapshot
+DESC: Merge LV that was previously split from a mirror.
+RULE: all not lv_is_merging_origin lv_is_virtual_origin lv_is_external_origin lv_is_merging_cow
+
---
-# FIXME: by using two different positional args, this is the
-# single violation of the standard method of using process_each_lv().
-# Before calling process_each, it steals the first positional arg
-# and adjusts argv/argc so it's not seen by process_each.
+# NB: an unsual use of position args here, where
+# the second position LV is the only one processed
+# by process_each_lv.
# alternate form of lvconvert --snapshot
lvconvert --type snapshot LV_linear_striped_raid LV_snapshot
@@ -561,6 +566,7 @@ lvconvert --splitsnapshot LV_snapshot
OO: OO_LVCONVERT
ID: lvconvert_split_cow_snapshot
DESC: Separate a COW snapshot from its origin LV.
+RULE: all not lv_is_origin lv_is_external_origin lv_is_merging_cow lv_is_vg_writable lv_is_pvmove
---
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 29e031e96..d724ebdc9 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -1992,37 +1992,16 @@ try_new_takeover_or_reshape:
return 0;
}
-static int _lvconvert_splitsnapshot(struct cmd_context *cmd, struct logical_volume *cow,
- struct lvconvert_params *lp)
+static int _lvconvert_splitsnapshot(struct cmd_context *cmd, struct logical_volume *cow)
{
struct volume_group *vg = cow->vg;
const char *cow_name = display_lvname(cow);
- if (!lv_is_cow(cow)) {
- log_error("%s is not a snapshot.", cow_name);
- return 0;
- }
-
- if (lv_is_origin(cow) || lv_is_external_origin(cow)) {
- log_error("Unable to split LV %s that is a snapshot origin.", cow_name);
- return 0;
- }
-
- if (lv_is_merging_cow(cow)) {
- log_error("Unable to split off snapshot %s being merged into its origin.", cow_name);
- return 0;
- }
-
if (lv_is_virtual_origin(origin_from_cow(cow))) {
log_error("Unable to split off snapshot %s with virtual origin.", cow_name);
return 0;
}
- if (lv_is_thin_pool(cow) || lv_is_pool_metadata_spare(cow)) {
- log_error("Unable to split off LV %s needed by thin volume(s).", cow_name);
- return 0;
- }
-
if (!(vg->fid->fmt->features & FMT_MDAS)) {
log_error("Unable to split off snapshot %s using old LVM1-style metadata.", cow_name);
return 0;
@@ -2034,19 +2013,12 @@ static int _lvconvert_splitsnapshot(struct cmd_context *cmd, struct logical_volu
return 0;
}
- if (!vg_check_status(vg, LVM_WRITE))
- return_0;
-
- if (lv_is_pvmove(cow) || lv_is_mirror_type(cow) || lv_is_raid_type(cow) || lv_is_thin_type(cow)) {
- log_error("LV %s type is unsupported with --splitsnapshot.", cow_name);
- return 0;
- }
-
if (lv_is_active_locally(cow)) {
if (!lv_check_not_in_use(cow, 1))
return_0;
- if ((lp->force == PROMPT) && !lp->yes &&
+ if ((arg_count(cmd, force_ARG) == PROMPT) &&
+ !arg_count(cmd, yes_ARG) &&
lv_is_visible(cow) &&
lv_is_active(cow)) {
if (yes_no_prompt("Do you really want to split off active "
@@ -2165,36 +2137,16 @@ static int _lvconvert_uncache(struct cmd_context *cmd,
static int _lvconvert_snapshot(struct cmd_context *cmd,
struct logical_volume *lv,
- struct lvconvert_params *lp)
+ const char *origin_name)
{
struct logical_volume *org;
const char *snap_name = display_lvname(lv);
+ uint32_t chunk_size;
+ int zero;
- if (lv_is_cache_type(lv)) {
- log_error("Snapshots are not yet supported with cache type LVs %s.",
- snap_name);
- return 0;
- }
-
- if (lv_is_mirrored(lv)) {
- log_error("Unable to convert mirrored LV %s into a snapshot.", snap_name);
- return 0;
- }
-
- if (lv_is_origin(lv)) {
- /* Unsupported stack */
- log_error("Unable to convert origin %s into a snapshot.", snap_name);
- return 0;
- }
-
- if (lv_is_pool(lv)) {
- log_error("Unable to convert pool LVs %s into a snapshot.", snap_name);
- return 0;
- }
-
- if (!(org = find_lv(lv->vg, lp->origin_name))) {
+ if (!(org = find_lv(lv->vg, origin_name))) {
log_error("Couldn't find origin volume %s in Volume group %s.",
- lp->origin_name, lv->vg->name);
+ origin_name, lv->vg->name);
return 0;
}
@@ -2203,22 +2155,23 @@ static int _lvconvert_snapshot(struct cmd_context *cmd,
return 0;
}
- if (!cow_has_min_chunks(lv->vg, lv->le_count, lp->chunk_size))
+ chunk_size = arg_uint_value(cmd, chunksize_ARG, 8);
+ if (chunk_size < 8 || chunk_size > 1024 || !is_power_of_2(chunk_size)) {
+ log_error("Chunk size must be a power of 2 in the range 4K to 512K.");
+ return 0;
+ }
+ log_verbose("Setting chunk size to %s.", display_size(cmd, chunk_size));
+
+ if (!cow_has_min_chunks(lv->vg, lv->le_count, chunk_size))
return_0;
- if (lv_is_locked(org) ||
- lv_is_cache_type(org) ||
- lv_is_thin_type(org) ||
- lv_is_pvmove(org) ||
- lv_is_mirrored(org) ||
- lv_is_cow(org)) {
+ /*
+ * lv_is_prop checks here cannot be automated by command definition
+ * rules because they are not done on the LV being processed.
+ */
+ if (lv_is_locked(org) || lv_is_pvmove(org)) {
log_error("Unable to convert an LV into a snapshot of a %s LV.",
- lv_is_locked(org) ? "locked" :
- lv_is_cache_type(org) ? "cache type" :
- lv_is_thin_type(org) ? "thin type" :
- lv_is_pvmove(org) ? "pvmove" :
- lv_is_mirrored(org) ? "mirrored" :
- "snapshot");
+ lv_is_locked(org) ? "locked" : "pvmove");
return 0;
}
@@ -2226,7 +2179,7 @@ static int _lvconvert_snapshot(struct cmd_context *cmd,
snap_name);
log_warn("THIS WILL DESTROY CONTENT OF LOGICAL VOLUME (filesystem etc.)");
- if (!lp->yes &&
+ if (!arg_count(cmd, yes_ARG) &&
yes_no_prompt("Do you really want to convert %s? [y/n]: ",
snap_name) == 'n') {
log_error("Conversion aborted.");
@@ -2238,7 +2191,12 @@ static int _lvconvert_snapshot(struct cmd_context *cmd,
return 0;
}
- if (!lp->zero || !(lv->status & LVM_WRITE))
+ if (first_seg(lv)->segtype->flags & SEG_CANNOT_BE_ZEROED)
+ zero = 0;
+ else
+ zero = arg_int_value(cmd, zero_ARG, 1);
+
+ if (!zero || !(lv->status & LVM_WRITE))
log_warn("WARNING: %s not zeroed.", snap_name);
else {
lv->status |= LV_TEMPORARY;
@@ -2258,7 +2216,7 @@ static int _lvconvert_snapshot(struct cmd_context *cmd,
if (!archive(lv->vg))
return_0;
- if (!vg_add_snapshot(org, lv, NULL, org->le_count, lp->chunk_size)) {
+ if (!vg_add_snapshot(org, lv, NULL, org->le_count, chunk_size)) {
log_error("Couldn't create snapshot.");
return 0;
}
@@ -2274,7 +2232,7 @@ static int _lvconvert_snapshot(struct cmd_context *cmd,
static int _lvconvert_merge_old_snapshot(struct cmd_context *cmd,
struct logical_volume *lv,
- struct lvconvert_params *lp)
+ struct logical_volume **lv_to_poll)
{
int merge_on_activate = 0;
struct logical_volume *origin = origin_from_cow(lv);
@@ -2282,29 +2240,6 @@ static int _lvconvert_merge_old_snapshot(struct cmd_context *cmd,
struct lvinfo info;
dm_percent_t snap_percent;
- /* Check if merge is possible */
- if (!lv_is_cow(lv)) {
- log_error("\"%s\" is not a mergeable logical volume.",
- lv->name);
- return 0;
- }
-
- if (lv_is_merging_cow(lv)) {
- log_error("Snapshot %s is already merging.", lv->name);
- return 0;
- }
-
- if (lv_is_merging_origin(origin)) {
- log_error("Snapshot %s is already merging into the origin.",
- find_snapshot(origin)->cow->name);
- return 0;
- }
-
- if (lv_is_virtual_origin(origin)) {
- log_error("Snapshot %s has virtual origin.", lv->name);
- return 0;
- }
-
if (lv_is_external_origin(origin_from_cow(lv))) {
log_error("Cannot merge snapshot \"%s\" into "
"the read-only external origin \"%s\".",
@@ -2368,8 +2303,7 @@ static int _lvconvert_merge_old_snapshot(struct cmd_context *cmd,
if (!lv_update_and_reload(origin))
return_0;
- lp->need_polling = 1;
- lp->lv_to_poll = origin;
+ *lv_to_poll = origin;
}
if (merge_on_activate)
@@ -3436,7 +3370,7 @@ static int _lvconvert_cache(struct cmd_context *cmd,
static int _convert_cow_snapshot_splitsnapshot(struct cmd_context *cmd, struct logical_volume *lv,
struct lvconvert_params *lp)
{
- return _lvconvert_splitsnapshot(cmd, lv, lp);
+ return _lvconvert_splitsnapshot(cmd, lv);
}
/*
@@ -3446,7 +3380,7 @@ static int _convert_cow_snapshot_splitsnapshot(struct cmd_context *cmd, struct l
static int _convert_cow_snapshot_merge(struct cmd_context *cmd, struct logical_volume *lv,
struct lvconvert_params *lp)
{
- return _lvconvert_merge_old_snapshot(cmd, lv, lp);
+ /* return _lvconvert_merge_old_snapshot(cmd, lv, lp); */
}
/*
@@ -3740,7 +3674,7 @@ static int _convert_raid_merge(struct cmd_context *cmd, struct logical_volume *l
static int _convert_raid_snapshot(struct cmd_context *cmd, struct logical_volume *lv,
struct lvconvert_params *lp)
{
- return _lvconvert_snapshot(cmd, lv, lp);
+ return _lvconvert_snapshot(cmd, lv, lp->origin_name);
}
/*
@@ -3879,7 +3813,7 @@ static int _convert_striped_merge(struct cmd_context *cmd, struct logical_volume
static int _convert_striped_snapshot(struct cmd_context *cmd, struct logical_volume *lv,
struct lvconvert_params *lp)
{
- return _lvconvert_snapshot(cmd, lv, lp);
+ return _lvconvert_snapshot(cmd, lv, lp->origin_name);
}
/*
@@ -4620,6 +4554,11 @@ struct lvconvert_result {
struct dm_list poll_idls;
};
+
+/*
+ * repair-related lvconvert utilities
+ */
+
static int _lvconvert_repair_pvs_mirror(struct cmd_context *cmd, struct logical_volume *lv,
struct processing_handle *handle,
struct dm_list *use_pvh)
@@ -4817,11 +4756,12 @@ int lvconvert_repair_pvs_or_thinpool_cmd(struct cmd_context *cmd, int argc, char
init_ignore_suspended_devices(saved_ignore_suspended_devices);
if (lr.need_polling) {
- dm_list_iterate_items(idl, &lr.poll_idls)
+ dm_list_iterate_items(idl, &lr.poll_idls) {
poll_ret = _lvconvert_poll_by_id(cmd, idl->id,
arg_is_set(cmd, background_ARG), 0, 0);
- if (poll_ret > ret)
- ret = poll_ret;
+ if (poll_ret > ret)
+ ret = poll_ret;
+ }
}
destroy_processing_handle(cmd, handle);
@@ -4895,3 +4835,134 @@ int lvconvert_replace_pv_cmd(struct cmd_context *cmd, int argc, char **argv)
return ret;
}
+
+/*
+ * snapshot-related lvconvert utilities
+ */
+
+
+/*
+ * Merge a COW snapshot LV into its origin.
+ */
+
+static int _lvconvert_merge_snapshot_single(struct cmd_context *cmd,
+ struct logical_volume *lv,
+ struct processing_handle *handle)
+{
+ struct lvconvert_result *lr = (struct lvconvert_result *) handle->custom_handle;
+ struct logical_volume *lv_to_poll = NULL;
+ struct convert_poll_id_list *idl;
+
+ if (!_lvconvert_merge_old_snapshot(cmd, lv, &lv_to_poll))
+ return_ECMD_FAILED;
+
+ if (lv_to_poll) {
+ if (!(idl = _convert_poll_id_list_create(cmd, lv)))
+ return_ECMD_FAILED;
+ dm_list_add(&lr->poll_idls, &idl->list);
+ lr->need_polling = 1;
+ }
+
+ return ECMD_PROCESSED;
+}
+
+int lvconvert_merge_snapshot_cmd(struct cmd_context *cmd, int argc, char **argv)
+{
+ struct processing_handle *handle;
+ struct lvconvert_result lr = { 0 };
+ struct convert_poll_id_list *idl;
+ int ret, poll_ret;
+
+ dm_list_init(&lr.poll_idls);
+
+ if (!(handle = init_processing_handle(cmd, NULL))) {
+ log_error("Failed to initialize processing handle.");
+ return ECMD_FAILED;
+ }
+
+ handle->custom_handle = &lr;
+
+ ret = process_each_lv(cmd, cmd->position_argc, cmd->position_argv, NULL, NULL, READ_FOR_UPDATE, handle,
+ _lvconvert_merge_snapshot_single);
+
+ if (lr.need_polling) {
+ dm_list_iterate_items(idl, &lr.poll_idls) {
+ poll_ret = _lvconvert_poll_by_id(cmd, idl->id,
+ arg_is_set(cmd, background_ARG), 0, 0);
+ if (poll_ret > ret)
+ ret = poll_ret;
+ }
+ }
+
+ destroy_processing_handle(cmd, handle);
+
+ return ret;
+}
+
+/*
+ * Separate a COW snapshot from its origin.
+ *
+ * lvconvert --splitsnapshot LV_snapshot
+ * lvconvert_split_cow_snapshot
+ */
+
+/*
+ * TODO: ensure that LV_snapshot implies that the LV cannot be thinpool,
+ * mirror_type, raid_type, thin_type
+ */
+
+static int _lvconvert_split_snapshot_single(struct cmd_context *cmd,
+ struct logical_volume *lv,
+ struct processing_handle *handle)
+{
+ if (!_lvconvert_splitsnapshot(cmd, lv))
+ return_ECMD_FAILED;
+
+ return ECMD_PROCESSED;
+}
+
+int lvconvert_split_snapshot_cmd(struct cmd_context *cmd, int argc, char **argv)
+{
+ return process_each_lv(cmd, 1, cmd->position_argv, NULL, NULL, READ_FOR_UPDATE, NULL,
+ _lvconvert_split_snapshot_single);
+}
+
+/*
+ * Combine an origin LV with a snapshot LV (cow) that was previously split from
+ * the origin using --splitsnapshot.
+ */
+
+/*
+ * TODO: ensure that LV_snapshot implies that the LV cannot be other types
+ * that were checked for: lv_is_cache_type lv_is_mirrored lv_is_pool lv_is_thick_origin
+ */
+
+static int _lvconvert_combine_split_snapshot_single(struct cmd_context *cmd,
+ struct logical_volume *lv,
+ struct processing_handle *handle)
+{
+ if (!_lvconvert_snapshot(cmd, lv, cmd->position_argv[0]))
+ return_ECMD_FAILED;
+
+ return ECMD_PROCESSED;
+}
+
+int lvconvert_combine_split_snapshot_cmd(struct cmd_context *cmd, int argc, char **argv)
+{
+ const char *origin_name;
+
+ origin_name = cmd->position_argv[0];
+ /* TODO: validate origin_name, see validate_restricted_lvname_param */
+
+ /*
+ * The command has unusual handling of position args. The first
+ * position arg is the origin name, and that LV is not processed by
+ * process_each_lv. The second position arg is the snapshot LV that's
+ * processed by process_each_lv. The single function can grab the
+ * origin LV from position_argv[0].
+ */
+
+ return process_each_lv(cmd, 1, cmd->position_argv + 1, NULL, NULL, READ_FOR_UPDATE, NULL,
+ _lvconvert_combine_split_snapshot_single);
+}
+
diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c
index d1c42a13c..e00a13880 100644
--- a/tools/lvmcmdline.c
+++ b/tools/lvmcmdline.c
@@ -123,9 +123,14 @@ struct command_function command_functions[COMMAND_ID_COUNT] = {
{ lvchange_poll_CMD, lvchange_monitor_poll_cmd },
{ lvchange_persistent_CMD, lvchange_persistent_cmd },
- /* lvconvert utilities related to snapshots and repair. */
+ /* lvconvert utilities related to repair. */
{ lvconvert_repair_pvs_or_thinpool_CMD, lvconvert_repair_pvs_or_thinpool_cmd },
{ lvconvert_replace_pv_CMD, lvconvert_replace_pv_cmd },
+
+ /* lvconvert utilities related to snapshots. */
+ { lvconvert_split_cow_snapshot_CMD, lvconvert_split_snapshot_cmd },
+ { lvconvert_merge_snapshot_CMD, lvconvert_merge_snapshot_cmd },
+ { lvconvert_combine_split_snapshot_CMD, lvconvert_combine_split_snapshot_cmd },
};
#if 0
/* all raid-related type conversions */
@@ -147,11 +152,9 @@ struct command_function command_functions[COMMAND_ID_COUNT] = {
{ lvconvert_split_and_delete_cachepool_CMD, lvconvert_split_and_delete_cachepool_fn },
{ lvconvert_swap_pool_metadata_CMD, lvconvert_swap_pool_metadata_fn },
- /* utilities related to snapshots and repair. */
+ /* other misc. */
{ lvconvert_merge_CMD, lvconvert_merge_fn },
- { lvconvert_combine_split_snapshot_CMD, lvconvert_combine_split_snapshot_fn },
- { lvconvert_split_cow_snapshot_CMD, lvconvert_split_cow_snapshot_fn },
{ lvconvert_poll_start_CMD, lvconvert_poll_start_fn },
#endif
diff --git a/tools/tools.h b/tools/tools.h
index ec4789d22..bff562b17 100644
--- a/tools/tools.h
+++ b/tools/tools.h
@@ -253,4 +253,8 @@ int lvchange_persistent_cmd(struct cmd_context *cmd, int argc, char **argv);
int lvconvert_repair_pvs_or_thinpool_cmd(struct cmd_context *cmd, int argc, char **argv);
int lvconvert_replace_pv_cmd(struct cmd_context *cmd, int argc, char **argv);
+int lvconvert_merge_snapshot_cmd(struct cmd_context *cmd, int argc, char **argv);
+int lvconvert_split_snapshot_cmd(struct cmd_context *cmd, int argc, char **argv);
+int lvconvert_combine_split_snapshot_cmd(struct cmd_context *cmd, int argc, char **argv);
+
#endif