summaryrefslogtreecommitdiff
path: root/tools/lvchange.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/lvchange.c')
-rw-r--r--tools/lvchange.c283
1 files changed, 283 insertions, 0 deletions
diff --git a/tools/lvchange.c b/tools/lvchange.c
index 250d7209b..462e0a71f 100644
--- a/tools/lvchange.c
+++ b/tools/lvchange.c
@@ -1436,3 +1436,286 @@ int lvchange(struct cmd_context *cmd, int argc, char **argv)
update ? READ_FOR_UPDATE : 0, NULL,
&_lvchange_single);
}
+
+#if 0
+/*
+ * Check if the status of the LV allows running lvchange.
+ *
+ * FIXME: check for invalid VG/LV properties in a way that is not prone
+ * to missing some. Currently, there are some checks here, some in the
+ * functions above, some in process_each, and some may be missing.
+ */
+static int _lvchange_status_is_valid(struct cmd_context *cmd, struct logical_volume *lv)
+{
+ if (!(lv->vg->status & LVM_WRITE)) {
+ log_error("Operation not permitted on LV %s: writable VG required.",
+ display_lvname(lv));
+ return 0;
+ }
+
+ if (lv_is_pvmove(lv)) {
+ log_error("Operation not permitted on LV %s: used for pvmove.",
+ display_lvname(lv));
+ if (arg_is_set(cmd, activate_ARG))
+ log_error("Use 'pvmove --abort' to abandon a pvmove");
+ return 0;
+ }
+
+ if (lv_is_mirror_log(lv)) {
+ log_error("Operation not permitted on LV %s: is mirror log.",
+ display_lvname(lv));
+ return 0;
+ }
+
+ if (lv_is_mirror_image(lv)) {
+ log_error("Operation not permitted on LV %s: is mirror image.",
+ display_lvname(lv));
+ return 0;
+ }
+
+ if (lv_is_origin(lv) && !lv_is_thin_volume(lv)) {
+ log_error("Operation not permitted on LV %s: is under snapshot.",
+ display_lvname(lv));
+ return 0;
+ }
+
+ return 1;
+}
+
+static int _lvchange_properties_single(struct cmd_context *cmd,
+ struct logical_volume *lv,
+ struct processing_handle *handle)
+{
+ int doit = 0, docmds = 0;
+
+ /* FIXME: sort out hidden/internal LVs, e.g. _lvchange_hidden_is_valid() */
+
+ if (!_lvchange_status_is_valid(cmd, lv))
+ return_ECMD_FAILED;
+
+ if (arg_is_set(cmd, persistent_ARG) && lv_is_pool(lv)) {
+ log_error("Operation not permitted on LV %s: persistent device numbers are not supported with pools.",
+ display_lvname(lv));
+ return ECMD_FAILED;
+ }
+
+ /*
+ * If a persistent lv lock already exists from activation
+ * (with the needed mode or higher), this will be a no-op.
+ * Otherwise, the lv lock will be taken as non-persistent
+ * and released when this command exits.
+ */
+ if (!lockd_lv(cmd, lv, "ex", 0)) {
+ stack;
+ return ECMD_FAILED;
+ }
+
+ for (i = 0; i < cmd->command->ro_count; i++) {
+ opt_enum = cmd->command->required_opt_args[i].opt;
+
+ if (!arg_is_set(cmd, opt_enum))
+ continue;
+
+ if (!archive(lv->vg))
+ return_ECMD_FAILED;
+
+ docmds++;
+
+ switch (opt_enum) {
+ case permission_ARG:
+ doit += _lvchange_permission(cmd, lv);
+ break;
+
+ case alloc_ARG:
+ case contiguous_ARG:
+ doit += _lvchange_alloc(cmd, lv);
+ break;
+
+ case errorwhenfull_ARG:
+ doit += _lvchange_errorwhenfull(cmd, lv);
+ break;
+
+ case readahead_ARG:
+ doit += _lvchange_readahead(cmd, lv);
+ break;
+
+ case persistent_ARG:
+ doit += _lvchange_persistent(cmd, lv);
+ break;
+
+ case discards_ARG:
+ case zero_ARG:
+ doit += _lvchange_pool_update(cmd, lv);
+ break;
+
+ case addtag_ARG:
+ case deltag_ARG:
+ doit += _lvchange_tag(cmd, lv, opt_enum);
+ break;
+
+ case writemostly_ARG:
+ case writebehind_ARG:
+ doit += _lvchange_writemostly(lv);
+ break;
+
+ case minrecoveryrate_ARG:
+ case maxrecoveryrate_ARG:
+ doit += _lvchange_recovery_rate(lv);
+ break;
+
+ case profile_ARG:
+ case metadataprofile_ARG:
+ case detachprofile_ARG:
+ doit += _lvchange_profile(lv);
+ break;
+
+ case setactivationskip_ARG:
+ doit += _lvchange_activation_skip(lv);
+ break;
+
+ case cachemode_ARG:
+ case cachepolicy_ARG:
+ case cachesettings_ARG:
+ doit += _lvchange_cache(cmd, lv);
+ break;
+
+ default:
+ log_error(INTERNAL_ERROR "Failed to check for option %s",
+ arg_long_option_name(i));
+ }
+
+ if (doit)
+ log_print_unless_silent("Logical volume %s changed.", display_lvname(lv));
+
+ if (doit != docmds)
+ return_ECMD_FAILED;
+
+ return ECMD_PROCESSED;
+}
+
+int lvchange_properties_cmd(struct cmd_context *cmd, int argc, char **argv)
+{
+ struct processing_handle *handle = init_processing_handle(cmd, NULL);
+ int ret;
+
+ ret = process_each_lv(cmd, argc, argv, NULL, NULL, READ_FOR_UPDATE, handle, _lvchange_properties_single);
+
+ destroy_processing_handle(cmd, handle);
+ return ret;
+}
+
+static int _lvchange_activate_single(struct cmd_context *cmd,
+ struct logical_volume *lv,
+ struct processing_handle *handle)
+{
+ struct logical_volume *origin;
+ char snaps_msg[128];
+
+ /* FIXME: sort out hidden/internal LVs, e.g. _lvchange_hidden_is_valid() */
+
+ if (!_lvchange_status_is_valid(cmd, lv))
+ return_ECMD_FAILED;
+
+ /* FIXME: untangle the proper logic for cow / sparse / virtual origin */
+
+ /* If LV is sparse, activate origin instead */
+ if (lv_is_cow(lv) && lv_is_virtual_origin(origin = origin_from_cow(lv)))
+ lv = origin;
+
+ if (lv_is_cow(lv)) {
+ origin = origin_from_cow(lv);
+ if (origin->origin_count < 2)
+ snaps_msg[0] = '\0';
+ else if (dm_snprintf(snaps_msg, sizeof(snaps_msg),
+ " and %u other snapshot(s)",
+ origin->origin_count - 1) < 0) {
+ log_error("Failed to prepare message.");
+ return ECMD_FAILED;
+ }
+
+ if (!arg_is_set(cmd, yes_ARG) &&
+ (yes_no_prompt("Change of snapshot %s will also change its "
+ "origin %s%s. Proceed? [y/n]: ",
+ display_lvname(lv), display_lvname(origin),
+ snaps_msg) == 'n')) {
+ log_error("Logical volume %s not changed.", display_lvname(lv));
+ return ECMD_FAILED;
+ }
+ }
+
+ /*
+ * If --sysinit -aay is used and at the same time lvmetad is used,
+ * we want to rely on autoactivation to take place. Also, we
+ * need to take special care here as lvmetad service does
+ * not neet to be running at this moment yet - it could be
+ * just too early during system initialization time.
+ */
+ if (arg_is_set(cmd, sysinit_ARG) && (arg_uint_value(cmd, activate_ARG, 0) == CHANGE_AAY)) {
+ if (lvmetad_used()) {
+ log_warn("WARNING: lvmetad is active, skipping direct activation during sysinit.");
+ return ECMD_PROCESSED;
+ }
+ }
+
+ if (!_lvchange_activate(cmd, lv))
+ return_ECMD_FAILED;
+
+ return ECMD_PROCESSED;
+}
+
+int lvchange_activate_cmd(struct cmd_context *cmd, int argc, char **argv)
+{
+ struct processing_handle *handle = init_processing_handle(cmd, NULL);
+
+ cmd->handles_missing_pvs = 1;
+ cmd->lockd_vg_default_sh = 1;
+
+ /*
+ * Include foreign VGs that contain active LVs.
+ * That shouldn't happen in general, but if it does by some
+ * mistake, then we want to allow those LVs to be deactivated.
+ */
+ cmd->include_active_foreign_vgs = 1;
+
+ /* Allow deactivating if locks fail. */
+ if (is_change_activating((activation_change_t)arg_uint_value(cmd, activate_ARG, CHANGE_AY)))
+ cmd->lockd_vg_enforce_sh = 1;
+
+ ret = process_each_lv(cmd, argc, argv, NULL, NULL, 0, handle, _lvchange_activate_single);
+
+ destroy_processing_handle(cmd, handle);
+ return ret;
+}
+
+static int _lvchange_refresh_single(struct cmd_context *cmd,
+ struct logical_volume *lv,
+ struct processing_handle *handle)
+{
+ /* FIXME: sort out hidden/internal LVs, e.g. _lvchange_hidden_is_valid() */
+
+ if (!_lvchange_status_is_valid(cmd, lv))
+ return_ECMD_FAILED;
+
+ log_verbose("Refreshing logical volume %s (if active).", display_lvname(lv));
+
+ if (!_lv_refresh(cmd, lv))
+ return_ECMD_FAILED;
+
+ return ECMD_PROCESSED;
+}
+
+int lvchange_refresh_cmd(struct cmd_context *cmd, int argc, char **argv)
+{
+ struct processing_handle *handle = init_processing_handle(cmd, NULL);
+ int ret;
+
+ cmd->handles_missing_pvs = 1;
+ cmd->lockd_vg_default_sh = 1;
+
+ ret = process_each_lv(cmd, argc, argv, NULL, NULL, 0, handle, _lvchange_refresh_single);
+
+ destroy_processing_handle(cmd, handle);
+ return ret;
+}
+#endif
+