summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Teigland <teigland@redhat.com>2016-12-14 14:39:53 -0600
committerDavid Teigland <teigland@redhat.com>2016-12-14 15:01:25 -0600
commit02965225da48f3b20529a1b1cb5a88521ebd617e (patch)
tree3d3dd001fa7b06c2dab26ba745b6ee34a75a7941
parent720c0e326c6972a3226e208399682ed460986c5d (diff)
downloadlvm2-dev-dct-cmd-defs60.tar.gz
lvconvert: use command defs for raid/mirror typesdev-dct-cmd-defs60
-rw-r--r--tools/command-lines.in7
-rw-r--r--tools/lvconvert.c710
-rw-r--r--tools/lvmcmdline.c13
-rw-r--r--tools/tools.h3
4 files changed, 386 insertions, 347 deletions
diff --git a/tools/command-lines.in b/tools/command-lines.in
index c45371618..460e35cf7 100644
--- a/tools/command-lines.in
+++ b/tools/command-lines.in
@@ -337,24 +337,28 @@ OO: OO_LVCONVERT_RAID, OO_LVCONVERT
OP: PV ...
ID: lvconvert_raid_types
DESC: Convert LV to striped.
+RULE: all not lv_is_locked lv_is_pvmove
lvconvert --type mirror LV
OO: OO_LVCONVERT_RAID, OO_LVCONVERT, --mirrorlog MirrorLog
OP: PV ...
ID: lvconvert_raid_types
DESC: Convert LV to type mirror (also see type raid1).
+RULE: all not lv_is_locked lv_is_pvmove
lvconvert --type raid LV
OO: OO_LVCONVERT_RAID, OO_LVCONVERT
OP: PV ...
ID: lvconvert_raid_types
DESC: Convert LV to raid.
+RULE: all not lv_is_locked lv_is_pvmove
lvconvert --mirrors SNumber LV
OO: OO_LVCONVERT_RAID, OO_LVCONVERT, --mirrorlog MirrorLog
OP: PV ...
ID: lvconvert_raid_types
DESC: Convert LV to raid1 or mirror, or change number of mirror images.
+RULE: all not lv_is_locked lv_is_pvmove
---
@@ -366,12 +370,14 @@ OO: OO_LVCONVERT
OP: PV ...
ID: lvconvert_split_mirror_images
DESC: Split images from a raid1 or mirror LV and use them to create a new LV.
+RULE: all not lv_is_locked lv_is_pvmove
lvconvert --splitmirrors Number --trackchanges LV_raid1_cache
OO: OO_LVCONVERT
OP: PV ...
ID: lvconvert_split_mirror_images
DESC: Split images from a raid1 LV and track changes to origin.
+RULE: all not lv_is_locked lv_is_pvmove
lvconvert --mergemirrors LV_linear_raid|VG|Tag ...
OO: OO_LVCONVERT
@@ -384,6 +390,7 @@ OO: OO_LVCONVERT
OP: PV ...
ID: lvconvert_change_mirrorlog
DESC: Change the type of mirror log used by a mirror LV.
+RULE: all not lv_is_locked lv_is_pvmove
---
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index d7f789e6f..f16a31ad3 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -24,18 +24,18 @@ typedef enum {
* For a mirrored or raid LV, split mirror into two mirrors, optionally tracking
* future changes to the main mirror to allow future recombination.
*/
- CONV_SPLIT = 2,
- CONV_SPLIT_MIRRORS = 5,
+ CONV_SPLIT = 1,
+ CONV_SPLIT_MIRRORS = 2,
/* Every other segment type or mirror log conversion we haven't separated out */
- CONV_OTHER = 12,
+ CONV_OTHER = 3,
} conversion_type_t;
struct lvconvert_params {
- /* Exactly one of these 12 command categories is determined */
- int split; /* 2 */
- int keep_mimages; /* 5 */ /* --splitmirrors */
- /* other */ /* 12 */
+ /* Exactly one of these command categories is determined */
+ int split; /* 1 */
+ int keep_mimages; /* 2 */ /* --splitmirrors */
+ /* other */ /* 3 */
/* FIXME Eliminate all cases where more than one of the above are set then use conv_type instead */
conversion_type_t conv_type;
@@ -55,12 +55,7 @@ struct lvconvert_params {
int yes;
int zero;
- const char *lv_name;
const char *lv_split_name;
- const char *lv_name_full;
- const char *vg_name;
- int wait_completion;
- int need_polling;
uint32_t region_size;
@@ -77,13 +72,12 @@ struct lvconvert_params {
alloc_policy_t alloc;
int pv_count;
- char **pvs;
struct dm_list *pvh;
+ int wait_completion;
+ int need_polling;
struct logical_volume *lv_to_poll;
struct dm_list idls;
-
- const char *origin_name;
};
@@ -96,73 +90,6 @@ static void _set_conv_type(struct lvconvert_params *lp, int conv_type)
lp->conv_type = conv_type;
}
-static int _lvconvert_name_params(struct lvconvert_params *lp,
- struct cmd_context *cmd,
- int *pargc, char ***pargv)
-{
- if (!*pargc) {
- if (lp->split) {
- log_error("Logical volume for split is missing.");
- return 0;
- }
- if (!lp->lv_name_full) {
- log_error("Please provide logical volume path.");
- return 0;
- }
- } else if (!lp->lv_name_full) {
- lp->lv_name_full = (*pargv)[0];
- (*pargv)++, (*pargc)--;
- }
-
- if (!validate_restricted_lvname_param(cmd, &lp->vg_name, &lp->origin_name))
- return_0;
-
- if (!validate_restricted_lvname_param(cmd, &lp->vg_name, &lp->lv_split_name))
- return_0;
-
- if (!lp->vg_name && !strchr(lp->lv_name_full, '/')) {
- /* Check for $LVM_VG_NAME */
- if (!(lp->vg_name = extract_vgname(cmd, NULL))) {
- log_error("Please specify a logical volume path.");
- return 0;
- }
- }
-
- if (!validate_lvname_param(cmd, &lp->vg_name, &lp->lv_name_full))
- return_0;
-
- lp->lv_name = lp->lv_name_full;
-
- if (!validate_name(lp->vg_name)) {
- log_error("Please provide a valid volume group name");
- return 0;
- }
-
- /*
- * FIXME: avoid this distinct validation out of scope of _convert_*()
- *
- * We should not rely on namespace here any more!
- * It is the duty of lvcreate/lvrename to avoid reserved names.
- */
- if (!lp->keep_mimages &&
- !strstr(lp->lv_name, "_tdata") &&
- !strstr(lp->lv_name, "_tmeta") &&
- !strstr(lp->lv_name, "_cdata") &&
- !strstr(lp->lv_name, "_cmeta") &&
- !strstr(lp->lv_name, "_corig") &&
- !apply_lvname_restrictions(lp->lv_name))
- return_0;
-
- if (*pargc) {
- if (lp->split) {
- log_error("Too many arguments provided with --split.");
- return 0;
- }
- }
-
- return 1;
-}
-
static int _raid0_type_requested(const char *type_str)
{
return (!strcmp(type_str, SEG_TYPE_NAME_RAID0) || !strcmp(type_str, SEG_TYPE_NAME_RAID0_META));
@@ -207,9 +134,9 @@ static int _read_conversion_type(struct cmd_context *cmd,
return 0;
}
-static int _read_params(struct cmd_context *cmd, int argc, char **argv,
- struct lvconvert_params *lp)
+static int _read_params(struct cmd_context *cmd, struct lvconvert_params *lp)
{
+ const char *vg_name = NULL;
int region_size;
int pagesize = lvm_getpagesize();
@@ -245,7 +172,11 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
lp->track_changes = 1;
if (lp->split) {
- lp->lv_split_name = arg_str_value(cmd, name_ARG, NULL);
+ if ((lp->lv_split_name = arg_str_value(cmd, name_ARG, NULL))) {
+ if (!validate_restricted_lvname_param(cmd, &vg_name, &lp->lv_split_name))
+ return_0;
+ }
+
/*
* The '--splitmirrors n' argument is equivalent to '--mirrors -n'
@@ -265,7 +196,11 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
return 0;
}
- lp->lv_split_name = arg_str_value(cmd, name_ARG, NULL);
+ if ((lp->lv_split_name = arg_str_value(cmd, name_ARG, NULL))) {
+ if (!validate_restricted_lvname_param(cmd, &vg_name, &lp->lv_split_name))
+ return_0;
+ }
+
lp->keep_mimages = 1;
_set_conv_type(lp, CONV_SPLIT_MIRRORS);
lp->mirrors = arg_uint_value(cmd, splitmirrors_ARG, 0);
@@ -391,12 +326,6 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
lp->force = arg_count(cmd, force_ARG);
lp->yes = arg_count(cmd, yes_ARG);
- if (!_lvconvert_name_params(lp, cmd, &argc, &argv))
- return_0;
-
- lp->pv_count = argc;
- lp->pvs = argv;
-
return 1;
}
@@ -675,22 +604,6 @@ static int _lvconvert_mirrors_parse_params(struct cmd_context *cmd,
}
/*
- * Collapsing a stack of mirrors:
- *
- * If called with no argument, try collapsing the resync layers
- */
- if (!lp->mirrors_supplied && !lp->mirrorlog &&
- !lp->corelog && !arg_is_set(cmd, regionsize_ARG) &&
- !lp->keep_mimages) {
- *new_mimage_count = *old_mimage_count;
- *new_log_count = *old_log_count;
-
- if (find_temporary_mirror(lv) || lv_is_converting(lv))
- lp->need_polling = 1;
- return 1;
- }
-
- /*
* Adjusting mimage count?
*/
if (!lp->mirrors_supplied && !lp->keep_mimages)
@@ -1403,128 +1316,6 @@ try_new_takeover_or_reshape:
return 0;
}
-int lvconvert_repair_pvs_mirror(struct cmd_context *cmd, struct logical_volume *lv,
- struct processing_handle *handle,
- struct dm_list *use_pvh)
-{
- struct lvconvert_result *lr = (struct lvconvert_result *) handle->custom_handle;
- struct lvconvert_params lp = { 0 };
- struct convert_poll_id_list *idl;
- struct lvinfo info;
- int ret;
-
- /*
- * FIXME: temporary use of lp because _lvconvert_mirrors_repair()
- * and _aux() still use lp fields everywhere.
- * Migrate them away from using lp (for the most part just use
- * local variables, and check arg_values directly).
- */
-
- /*
- * Fill in any lp fields here that this fn expects to be set before
- * it's called. It's hard to tell what the old code expects in lp
- * for repair; it doesn't take the stripes option, but it seems to
- * expect lp.stripes to be set to 1.
- */
- lp.alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, ALLOC_INHERIT);
- lp.stripes = 1;
-
- ret = _lvconvert_mirrors_repair(cmd, lv, &lp, use_pvh);
-
- if (lp.need_polling) {
- if (!lv_info(cmd, lv, 0, &info, 0, 0) || !info.exists)
- log_print_unless_silent("Conversion starts after activation.");
- else {
- if (!(idl = convert_poll_id_list_create(cmd, lv)))
- return 0;
- dm_list_add(&lr->poll_idls, &idl->list);
- }
- lr->need_polling = 1;
- }
-
- return ret;
-}
-
-static void _lvconvert_repair_pvs_raid_ask(struct cmd_context *cmd, int *do_it)
-{
- const char *dev_policy;
-
- *do_it = 1;
-
- if (arg_is_set(cmd, usepolicies_ARG)) {
- dev_policy = find_config_tree_str(cmd, activation_raid_fault_policy_CFG, NULL);
-
- if (!strcmp(dev_policy, "allocate") ||
- !strcmp(dev_policy, "replace"))
- return;
-
- /* else if (!strcmp(dev_policy, "anything_else")) -- no replace */
- *do_it = 0;
- return;
- }
-
- if (!arg_count(cmd, yes_ARG) &&
- yes_no_prompt("Attempt to replace failed RAID images "
- "(requires full device resync)? [y/n]: ") == 'n') {
- *do_it = 0;
- }
-}
-
-int lvconvert_repair_pvs_raid(struct cmd_context *cmd, struct logical_volume *lv,
- struct processing_handle *handle,
- struct dm_list *use_pvh)
-{
- struct dm_list *failed_pvs;
- int do_it;
-
- if (!lv_is_active_exclusive_locally(lv_lock_holder(lv))) {
- log_error("%s must be active %sto perform this operation.",
- display_lvname(lv),
- vg_is_clustered(lv->vg) ?
- "exclusive locally " : "");
- return 0;
- }
-
- _lvconvert_repair_pvs_raid_ask(cmd, &do_it);
-
- if (do_it) {
- if (!(failed_pvs = failed_pv_list(lv->vg)))
- return_0;
-
- if (!lv_raid_replace(lv, arg_count(cmd, force_ARG), failed_pvs, use_pvh)) {
- log_error("Failed to replace faulty devices in %s.",
- display_lvname(lv));
- return 0;
- }
-
- log_print_unless_silent("Faulty devices in %s successfully replaced.",
- display_lvname(lv));
- return 1;
- }
-
- /* "warn" if policy not set to replace */
- if (arg_is_set(cmd, usepolicies_ARG))
- log_warn("Use 'lvconvert --repair %s' to replace "
- "failed device.", display_lvname(lv));
- return 1;
-}
-
-/*
- * Functions called to perform a specific operation on a specific LV type.
- *
- * _convert_<lvtype>_<operation>
- *
- * For cases where an operation does not apply to the LV itself, but
- * is implicitly redirected to a sub-LV, these functions locate the
- * correct sub-LV and call the operation on that sub-LV. If a sub-LV
- * of the proper type is not found, these functions report the error.
- *
- * FIXME: the _lvconvert_foo() functions can be cleaned up since they
- * are now only called for valid combinations of LV type and operation.
- * After that happens, the code remaining in those functions can be
- * moved into the _convert_lvtype_operation() functions below.
- */
-
/*
* Change the number of images in a mirror LV.
* lvconvert --mirrors Number LV
@@ -1704,51 +1495,21 @@ static int _convert_mirror(struct cmd_context *cmd, struct logical_volume *lv,
if (segtype_is_raid(lp->segtype))
return _convert_mirror_raid(cmd, lv, lp);
- log_error("Operation not permitted on mirror LV %s.", display_lvname(lv));
- log_error("Operations permitted on a mirror LV are:\n"
- " --mirrors\n"
- " --splitmirrors\n"
- " --mirrorlog\n"
- " --type linear\n"
- " --type raid*\n");
-
+ log_error("Unknown operation on mirror LV %s.", display_lvname(lv));
return 0;
}
static int _convert_raid(struct cmd_context *cmd, struct logical_volume *lv,
struct lvconvert_params *lp)
{
- /* Permitted convert options on visible or hidden RaidLVs */
- const char *permitted_options = lv_is_visible(lv) ?
- " --mirrors\n"
- " --splitmirrors\n"
- " --type raid*\n"
- " --type mirror\n"
- " --type striped\n"
- " --type linear\n"
- :
- " --mirrors\n"
- " --splitmirrors\n"
- " --replace\n"
- " --type raid*\n"
- " --type mirror\n"
- " --type striped\n"
- " --type linear\n";
-
- /* Applicable to any hidden _or_ visible LVs. */
if (arg_is_set(cmd, mirrors_ARG))
return _convert_raid_number(cmd, lv, lp);
if (arg_is_set(cmd, splitmirrors_ARG))
return _convert_raid_splitmirrors(cmd, lv, lp);
- if (segtype_is_raid(lp->segtype)) {
- /* Only --type allowed on hidden RaidLV. */
- if (!lv_is_visible(lv) && !arg_is_set(cmd, type_ARG))
- goto out;
-
+ if (segtype_is_raid(lp->segtype))
return _convert_raid_raid(cmd, lv, lp);
- }
if (segtype_is_mirror(lp->segtype))
return _convert_raid_mirror(cmd, lv, lp);
@@ -1759,10 +1520,7 @@ static int _convert_raid(struct cmd_context *cmd, struct logical_volume *lv,
if (_linear_type_requested(lp->type_str))
return _convert_raid_linear(cmd, lv, lp);
-out:
- log_error("Operation not permitted on raid LV %s.", display_lvname(lv));
- log_error("Operations permitted on a raid LV are:\n%s", permitted_options);
-
+ log_error("Unknown operation on raid LV %s.", display_lvname(lv));
return 0;
}
@@ -1785,11 +1543,7 @@ static int _convert_striped(struct cmd_context *cmd, struct logical_volume *lv,
if (arg_is_set(cmd, mirrors_ARG) && mirrors_type && !strcmp(mirrors_type, SEG_TYPE_NAME_RAID1))
return _convert_striped_raid(cmd, lv, lp);
- log_error("Operation not permitted on striped or linear LV %s.", display_lvname(lv));
- log_error("Operations permitted on a striped or linear LV are:\n"
- " --type mirror\n"
- " --type raid*\n");
-
+ log_error("Unknown operation on striped or linear LV %s.", display_lvname(lv));
return 0;
}
@@ -1818,39 +1572,6 @@ static int _lvconvert(struct cmd_context *cmd, struct logical_volume *lv,
struct lv_segment *seg = first_seg(lv);
int ret = 0;
- /*
- * Check some conditions that can never be processed.
- */
-
- if (lv_is_locked(lv)) {
- log_error("Cannot convert locked LV %s.", display_lvname(lv));
- goto out;
- }
-
- if (lv_is_pvmove(lv)) {
- log_error("Cannot convert pvmove LV %s.", display_lvname(lv));
- goto out;
- }
-
- if (!lv_is_visible(lv)) {
- /*
- * FIXME: there are some exceptions to the rule of only
- * operating on visible LVs. These should be fixed by running
- * the command on the visible LV with an option indicating
- * which sub LV is intended rather than naming the !visible LV.
- */
- if (!lv_is_cache_pool_metadata(lv) &&
- !lv_is_cache_pool_data(lv) &&
- !lv_is_thin_pool_metadata(lv) &&
- !lv_is_thin_pool_data(lv) &&
- !lv_is_used_cache_pool(lv) &&
- !lv_is_mirrored(lv) &&
- !lv_is_raid(lv)) {
- log_error("Cannot convert internal LV %s.", display_lvname(lv));
- goto out;
- }
- }
-
/* Set up segtype either from type_str or else to match the existing one. */
if (!*lp->type_str)
lp->segtype = seg->segtype;
@@ -1925,18 +1646,42 @@ out:
return ret ? ECMD_PROCESSED : ECMD_FAILED;
}
-static int _lvconvert_and_add_to_poll_list(struct cmd_context *cmd,
- struct lvconvert_params *lp,
- struct logical_volume *lv)
+/*
+ * Change LV between raid/mirror/linear/striped
+ */
+
+static int _lvconvert_raid_types_single(struct cmd_context *cmd, struct logical_volume *lv,
+ struct processing_handle *handle)
{
- int ret;
- struct lvinfo info;
+ struct lvconvert_params *lp = (struct lvconvert_params *) handle->custom_handle;
+ struct dm_list *use_pvh;
struct convert_poll_id_list *idl;
+ struct lvinfo info;
+ int ret;
+
+ /*
+ * lp->pvh holds the list of PVs available for allocation or removal
+ */
+
+ if (cmd->position_argc > 1) {
+ /* First pos arg is required LV, remaining are optional PVs. */
+ if (!(use_pvh = create_pv_list(cmd->mem, lv->vg, cmd->position_argc - 1, cmd->position_argv + 1, 0)))
+ return_ECMD_FAILED;
+ lp->pv_count = cmd->position_argc - 1;
+ } else
+ use_pvh = &lv->vg->pvs;
+
+ lp->pvh = use_pvh;
+
+ lp->lv_to_poll = lv;
+
+ ret = _lvconvert(cmd, lv, lp);
- /* _lvconvert() call may alter the reference in lp->lv_to_poll */
- if ((ret = _lvconvert(cmd, lv, lp)) != ECMD_PROCESSED)
- stack;
- else if (lp->need_polling) {
+ if (ret != ECMD_PROCESSED)
+ return_ECMD_FAILED;
+
+ if (lp->need_polling) {
+ /* _lvconvert() call may alter the reference in lp->lv_to_poll */
if (!lv_info(cmd, lp->lv_to_poll, 0, &info, 0, 0) || !info.exists)
log_print_unless_silent("Conversion starts after activation.");
else {
@@ -1946,65 +1691,86 @@ static int _lvconvert_and_add_to_poll_list(struct cmd_context *cmd,
}
}
- return ret;
+ return ECMD_PROCESSED;
}
-static int _lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv,
- struct processing_handle *handle)
+static int _lvconvert_raid_types_check(struct cmd_context *cmd, struct logical_volume *lv,
+ struct processing_handle *handle,
+ int lv_is_named_arg)
{
- struct lvconvert_params *lp = (struct lvconvert_params *) handle->custom_handle;
- struct volume_group *vg = lv->vg;
+ struct lv_types *lvtype;
+ int lvt_enum;
- if (test_mode() && is_lockd_type(vg->lock_type)) {
- log_error("Test mode is not yet supported with lock type %s.",
- vg->lock_type);
- return ECMD_FAILED;
+ if (!lv_is_visible(lv)) {
+ if (!lv_is_cache_pool_metadata(lv) &&
+ !lv_is_cache_pool_data(lv) &&
+ !lv_is_thin_pool_metadata(lv) &&
+ !lv_is_thin_pool_data(lv) &&
+ !lv_is_used_cache_pool(lv) &&
+ !lv_is_mirrored(lv) &&
+ !lv_is_raid(lv))
+ goto fail_hidden;
}
+ lvt_enum = get_lvt_enum(lv);
+ if (lvt_enum)
+ lvtype = get_lv_type(lvt_enum);
+
/*
- * lp->pvh holds the list of PVs available for allocation or removal
+ * FIXME: this validation could be done by command defs.
+ *
+ * Outside the standard linear/striped/mirror/raid LV
+ * types, cache is the only special LV type that is handled
+ * (the command is redirected to origin).
*/
- if (lp->pv_count) {
- if (!(lp->pvh = create_pv_list(cmd->mem, vg, lp->pv_count, lp->pvs, 0)))
- return_ECMD_FAILED;
- } else
- lp->pvh = &vg->pvs;
+ switch (lvt_enum) {
+ case thin_LVT:
+ case thinpool_LVT:
+ case cachepool_LVT:
+ case snapshot_LVT:
+ log_error("Operation not permitted (%s %d) on LV %s type %s.",
+ cmd->command->command_line_id, cmd->command->command_line_enum,
+ display_lvname(lv), lvtype ? lvtype->name : "unknown");
+ return 0;
+ }
- lp->lv_to_poll = lv;
+ return 1;
- return _lvconvert_and_add_to_poll_list(cmd, lp, lv);
+ fail_hidden:
+ log_error("Operation not permitted (%s %d) on hidden LV %s.",
+ cmd->command->command_line_id, cmd->command->command_line_enum,
+ display_lvname(lv));
+ return 0;
}
-int lvconvert(struct cmd_context * cmd, int argc, char **argv)
+int lvconvert_raid_types_cmd(struct cmd_context * cmd, int argc, char **argv)
{
int poll_ret, ret;
int saved_ignore_suspended_devices;
+ struct processing_handle *handle;
struct convert_poll_id_list *idl;
struct lvconvert_params lp = {
.conv_type = CONV_OTHER,
.target_attr = ~0,
.idls = DM_LIST_HEAD_INIT(lp.idls),
};
- struct processing_handle *handle = init_processing_handle(cmd, NULL);
- cmd->command->flags &= ~GET_VGNAME_FROM_OPTIONS;
-
- if (!handle) {
+ if (!(handle = init_processing_handle(cmd, NULL))) {
log_error("Failed to initialize processing handle.");
return ECMD_FAILED;
}
handle->custom_handle = &lp;
- if (!_read_params(cmd, argc, argv, &lp)) {
+ if (!_read_params(cmd, &lp)) {
ret = EINVALID_CMD_LINE;
goto_out;
}
saved_ignore_suspended_devices = ignore_suspended_devices();
- ret = process_each_lv(cmd, 0, NULL, lp.vg_name, lp.lv_name, READ_FOR_UPDATE,
- handle, NULL, &_lvconvert_single);
+ ret = process_each_lv(cmd, 1, cmd->position_argv, NULL, NULL, READ_FOR_UPDATE,
+ handle, &_lvconvert_raid_types_check, &_lvconvert_raid_types_single);
init_ignore_suspended_devices(saved_ignore_suspended_devices);
@@ -2023,6 +1789,148 @@ out:
return ret;
}
+/*
+ * change mirror log
+ */
+
+static int _lvconvert_visible_check(struct cmd_context *cmd, struct logical_volume *lv,
+ struct processing_handle *handle,
+ int lv_is_named_arg)
+{
+ if (!lv_is_visible(lv)) {
+ log_error("Operation not permitted (%s %d) on hidden LV %s.",
+ cmd->command->command_line_id, cmd->command->command_line_enum,
+ display_lvname(lv));
+ return 0;
+ }
+
+ return 1;
+}
+
+static int _lvconvert_change_mirrorlog_single(struct cmd_context *cmd, struct logical_volume *lv,
+ struct processing_handle *handle)
+{
+ struct lvconvert_params *lp = (struct lvconvert_params *) handle->custom_handle;
+ struct dm_list *use_pvh;
+
+ /*
+ * lp->pvh holds the list of PVs available for allocation or removal
+ */
+
+ if (cmd->position_argc > 1) {
+ /* First pos arg is required LV, remaining are optional PVs. */
+ if (!(use_pvh = create_pv_list(cmd->mem, lv->vg, cmd->position_argc - 1, cmd->position_argv + 1, 0)))
+ return_ECMD_FAILED;
+ lp->pv_count = cmd->position_argc - 1;
+ } else
+ use_pvh = &lv->vg->pvs;
+
+ lp->pvh = use_pvh;
+
+ /* FIXME: extract the mirrorlog functionality out of _lvconvert()? */
+ return _lvconvert(cmd, lv, lp);
+}
+
+int lvconvert_change_mirrorlog_cmd(struct cmd_context * cmd, int argc, char **argv)
+{
+ struct processing_handle *handle;
+ struct lvconvert_params lp = {
+ .conv_type = CONV_OTHER,
+ .target_attr = ~0,
+ .idls = DM_LIST_HEAD_INIT(lp.idls),
+ };
+ int ret;
+
+ if (!(handle = init_processing_handle(cmd, NULL))) {
+ log_error("Failed to initialize processing handle.");
+ return ECMD_FAILED;
+ }
+
+ handle->custom_handle = &lp;
+
+ /* FIXME: extract the relevant bits of read_params and put here. */
+ if (!_read_params(cmd, &lp)) {
+ ret = EINVALID_CMD_LINE;
+ goto_out;
+ }
+
+ ret = process_each_lv(cmd, 1, cmd->position_argv, NULL, NULL, READ_FOR_UPDATE,
+ handle, &_lvconvert_visible_check, &_lvconvert_change_mirrorlog_single);
+
+out:
+ destroy_processing_handle(cmd, handle);
+
+ return ret;
+}
+
+/*
+ * split mirror images
+ */
+
+static int _lvconvert_split_mirror_images_single(struct cmd_context *cmd, struct logical_volume *lv,
+ struct processing_handle *handle)
+{
+ struct lvconvert_params *lp = (struct lvconvert_params *) handle->custom_handle;
+ struct dm_list *use_pvh;
+
+ /*
+ * lp->pvh holds the list of PVs available for allocation or removal
+ */
+
+ if (cmd->position_argc > 1) {
+ /* First pos arg is required LV, remaining are optional PVs. */
+ if (!(use_pvh = create_pv_list(cmd->mem, lv->vg, cmd->position_argc - 1, cmd->position_argv + 1, 0)))
+ return_ECMD_FAILED;
+ lp->pv_count = cmd->position_argc - 1;
+ } else
+ use_pvh = &lv->vg->pvs;
+
+ lp->pvh = use_pvh;
+
+ /* FIXME: extract the split functionality out of _lvconvert()? */
+ return _lvconvert(cmd, lv, lp);
+}
+
+int lvconvert_split_mirror_images_cmd(struct cmd_context * cmd, int argc, char **argv)
+{
+ struct processing_handle *handle;
+ struct lvconvert_params lp = {
+ .conv_type = CONV_OTHER,
+ .target_attr = ~0,
+ .idls = DM_LIST_HEAD_INIT(lp.idls),
+ };
+ int ret;
+
+ if (!(handle = init_processing_handle(cmd, NULL))) {
+ log_error("Failed to initialize processing handle.");
+ return ECMD_FAILED;
+ }
+
+ handle->custom_handle = &lp;
+
+ /* FIXME: extract the relevant bits of read_params and put here. */
+ if (!_read_params(cmd, &lp)) {
+ ret = EINVALID_CMD_LINE;
+ goto_out;
+ }
+
+ /* FIXME: are there any hidden LVs that should be disallowed? */
+
+ ret = process_each_lv(cmd, 1, cmd->position_argv, NULL, NULL, READ_FOR_UPDATE,
+ handle, NULL, &_lvconvert_split_mirror_images_single);
+
+out:
+ destroy_processing_handle(cmd, handle);
+
+ return ret;
+}
+
+/*
+ * merge mirror images
+ *
+ * Called from both lvconvert --mergemirrors and lvconvert --merge.
+ */
+
int lvconvert_merge_mirror_images_single(struct cmd_context *cmd,
struct logical_volume *lv,
struct processing_handle *handle)
@@ -2035,9 +1943,133 @@ int lvconvert_merge_mirror_images_single(struct cmd_context *cmd,
int lvconvert_merge_mirror_images_cmd(struct cmd_context *cmd, int argc, char **argv)
{
+ /* arg can be a VG name, which is the standard option usage */
cmd->command->flags &= ~GET_VGNAME_FROM_OPTIONS;
return process_each_lv(cmd, cmd->position_argc, cmd->position_argv, NULL, NULL, READ_FOR_UPDATE,
- NULL, NULL, &lvconvert_merge_mirror_images_single);
+ NULL, &_lvconvert_visible_check, &lvconvert_merge_mirror_images_single);
+}
+
+/*
+ * repair/replace code, is called from lvconvert --repair/--replace
+ * utilities in lvconvert_other.c
+ */
+
+int lvconvert_repair_pvs_mirror(struct cmd_context *cmd, struct logical_volume *lv,
+ struct processing_handle *handle,
+ struct dm_list *use_pvh)
+{
+ struct lvconvert_result *lr = (struct lvconvert_result *) handle->custom_handle;
+ struct lvconvert_params lp = { 0 };
+ struct convert_poll_id_list *idl;
+ struct lvinfo info;
+ int ret;
+
+ /*
+ * FIXME: temporary use of lp because _lvconvert_mirrors_repair()
+ * and _aux() still use lp fields everywhere.
+ * Migrate them away from using lp (for the most part just use
+ * local variables, and check arg_values directly).
+ */
+
+ /*
+ * Fill in any lp fields here that this fn expects to be set before
+ * it's called. It's hard to tell what the old code expects in lp
+ * for repair; it doesn't take the stripes option, but it seems to
+ * expect lp.stripes to be set to 1.
+ */
+ lp.alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, ALLOC_INHERIT);
+ lp.stripes = 1;
+
+ ret = _lvconvert_mirrors_repair(cmd, lv, &lp, use_pvh);
+
+ if (lp.need_polling) {
+ if (!lv_info(cmd, lv, 0, &info, 0, 0) || !info.exists)
+ log_print_unless_silent("Conversion starts after activation.");
+ else {
+ if (!(idl = convert_poll_id_list_create(cmd, lv)))
+ return 0;
+ dm_list_add(&lr->poll_idls, &idl->list);
+ }
+ lr->need_polling = 1;
+ }
+
+ return ret;
+}
+
+static void _lvconvert_repair_pvs_raid_ask(struct cmd_context *cmd, int *do_it)
+{
+ const char *dev_policy;
+
+ *do_it = 1;
+
+ if (arg_is_set(cmd, usepolicies_ARG)) {
+ dev_policy = find_config_tree_str(cmd, activation_raid_fault_policy_CFG, NULL);
+
+ if (!strcmp(dev_policy, "allocate") ||
+ !strcmp(dev_policy, "replace"))
+ return;
+
+ /* else if (!strcmp(dev_policy, "anything_else")) -- no replace */
+ *do_it = 0;
+ return;
+ }
+
+ if (!arg_count(cmd, yes_ARG) &&
+ yes_no_prompt("Attempt to replace failed RAID images "
+ "(requires full device resync)? [y/n]: ") == 'n') {
+ *do_it = 0;
+ }
+}
+
+int lvconvert_repair_pvs_raid(struct cmd_context *cmd, struct logical_volume *lv,
+ struct processing_handle *handle,
+ struct dm_list *use_pvh)
+{
+ struct dm_list *failed_pvs;
+ int do_it;
+
+ if (!lv_is_active_exclusive_locally(lv_lock_holder(lv))) {
+ log_error("%s must be active %sto perform this operation.",
+ display_lvname(lv),
+ vg_is_clustered(lv->vg) ?
+ "exclusive locally " : "");
+ return 0;
+ }
+
+ _lvconvert_repair_pvs_raid_ask(cmd, &do_it);
+
+ if (do_it) {
+ if (!(failed_pvs = failed_pv_list(lv->vg)))
+ return_0;
+
+ if (!lv_raid_replace(lv, arg_count(cmd, force_ARG), failed_pvs, use_pvh)) {
+ log_error("Failed to replace faulty devices in %s.",
+ display_lvname(lv));
+ return 0;
+ }
+
+ log_print_unless_silent("Faulty devices in %s successfully replaced.",
+ display_lvname(lv));
+ return 1;
+ }
+
+ /* "warn" if policy not set to replace */
+ if (arg_is_set(cmd, usepolicies_ARG))
+ log_warn("Use 'lvconvert --repair %s' to replace "
+ "failed device.", display_lvname(lv));
+ return 1;
+}
+
+/*
+ * All lvconvert command defs have their own function,
+ * so the generic function name is unused.
+ */
+
+int lvconvert(struct cmd_context *cmd, int argc, char **argv)
+{
+ log_error(INTERNAL_ERROR "Missing function for command definition %s.",
+ cmd->command->command_line_id);
+ return ECMD_FAILED;
}
diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c
index 12e1a10d8..3538951f4 100644
--- a/tools/lvmcmdline.c
+++ b/tools/lvmcmdline.c
@@ -147,20 +147,17 @@ struct command_function command_functions[COMMAND_ID_COUNT] = {
{ lvconvert_split_and_keep_cachepool_CMD, lvconvert_split_cachepool_cmd },
{ lvconvert_split_and_remove_cachepool_CMD, lvconvert_split_cachepool_cmd },
+ /* lvconvert raid-related type conversions */
+ { lvconvert_raid_types_CMD, lvconvert_raid_types_cmd },
+
/* lvconvert utilities for raid/mirror */
- { lvconvert_merge_mirror_images_CMD, lvconvert_merge_mirror_images_cmd },
-#if 0
- { lvconvert_split_mirror_images_CMD, lvconvert_split_mirror_images_cmd },
+ { lvconvert_split_mirror_images_CMD, lvconvert_split_mirror_images_cmd},
{ lvconvert_change_mirrorlog_CMD, lvconvert_change_mirrorlog_cmd },
-#endif
+ { lvconvert_merge_mirror_images_CMD, lvconvert_merge_mirror_images_cmd },
/* redirected to merge_snapshot/merge_thin/merge_mirrors */
{ lvconvert_merge_CMD, lvconvert_merge_cmd },
-#if 0
- /* all raid-related type conversions */
- { lvconvert_raid_types_CMD, lvconvert_raid_types_cmd },
-#endif
};
diff --git a/tools/tools.h b/tools/tools.h
index 7342fcb08..c2a591544 100644
--- a/tools/tools.h
+++ b/tools/tools.h
@@ -271,7 +271,10 @@ int lvconvert_swap_pool_metadata_cmd(struct cmd_context *cmd, int argc, char **a
int lvconvert_merge_thin_cmd(struct cmd_context *cmd, int argc, char **argv);
int lvconvert_split_cachepool_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);
int lvconvert_merge_mirror_images_cmd(struct cmd_context *cmd, int argc, char **argv);
+int lvconvert_change_mirrorlog_cmd(struct cmd_context * cmd, int argc, char **argv);
int lvconvert_merge_cmd(struct cmd_context *cmd, int argc, char **argv);