diff --git a/WHATS_NEW b/WHATS_NEW index 9656da722..69345c6ec 100644 --- a/WHATS_NEW +++ b/WHATS_NEW @@ -1,5 +1,6 @@ Version 2.02.178 - ===================================== + Support activation of component LVs in read-only mode. Extend internal library to recognize and work with component LV. Skip duplicate check for active LV when prompting for its removal. Activate correct lock holding LV when it is cached. diff --git a/lib/activate/activate.c b/lib/activate/activate.c index aa230fe88..6333ba9a0 100644 --- a/lib/activate/activate.c +++ b/lib/activate/activate.c @@ -2673,7 +2673,11 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s, goto out; } - if (filter) + /* Component LV activation is enforced to be 'read-only' */ + /* TODO: should not apply for LVs in maintenance mode */ + if (!lv_is_visible(lv) && lv_is_component(lv)) { + laopts->read_only = 1; + } else if (filter) laopts->read_only = _passes_readonly_filter(cmd, lv); log_debug_activation("Activating %s%s%s%s%s.", display_lvname(lv), diff --git a/lib/commands/toolcontext.h b/lib/commands/toolcontext.h index 392116725..4225c57ff 100644 --- a/lib/commands/toolcontext.h +++ b/lib/commands/toolcontext.h @@ -166,6 +166,8 @@ struct cmd_context { unsigned lv_notify:1; unsigned pv_notify:1; unsigned use_aio:1; + unsigned activate_component:1; /* command activates component LV */ + unsigned process_component_lvs:1; /* command processes also component LVs */ /* * Filtering. diff --git a/lib/locking/locking.c b/lib/locking/locking.c index 1e1be56d5..f90bd2d78 100644 --- a/lib/locking/locking.c +++ b/lib/locking/locking.c @@ -252,6 +252,7 @@ static int _lock_vol(struct cmd_context *cmd, const char *resource, uint32_t lck_type = flags & LCK_TYPE_MASK; uint32_t lck_scope = flags & LCK_SCOPE_MASK; int ret = 0; + const struct logical_volume *active_lv; block_signals(flags); _lock_memory(cmd, lv_op); @@ -268,6 +269,16 @@ static int _lock_vol(struct cmd_context *cmd, const char *resource, goto out; } + /* When trying activating component LV, make sure none of + * sub component LV or LVs that are using it are active */ + if (lv && ((lck_type == LCK_READ) || (lck_type == LCK_EXCL)) && + ((!lv_is_visible(lv) && (active_lv = lv_holder_is_active(lv))) || + (active_lv = lv_component_is_active(lv)))) { + log_error("Activation of logical volume %s is prohibited while logical volume %s is active.", + display_lvname(lv), display_lvname(active_lv)); + goto out; + } + if (cmd->metadata_read_only && lck_type == LCK_WRITE && strcmp(resource, VG_GLOBAL)) { log_error("Operation prohibited while global/metadata_read_only is set."); diff --git a/tools/lvchange.c b/tools/lvchange.c index 288b04cf9..0aac5ac19 100644 --- a/tools/lvchange.c +++ b/tools/lvchange.c @@ -1266,6 +1266,11 @@ int lvchange_properties_cmd(struct cmd_context *cmd, int argc, char **argv) { int ret; + if (cmd->activate_component) { + log_error("Cannot change LV properties when activating component LVs."); + return 0; + } + /* * A command def rule allows only some options when LV is partial, * so handles_missing_pvs will only affect those. @@ -1362,7 +1367,10 @@ static int _lvchange_activate_check(struct cmd_context *cmd, struct processing_handle *handle, int lv_is_named_arg) { - if (!lv_is_visible(lv)) { + if (!lv_is_visible(lv) && + !cmd->activate_component && /* activation of named component LV */ + ((first_seg(lv)->status & MERGING) || /* merging already started */ + !cmd->process_component_lvs)) { /* deactivation of a component LV */ if (lv_is_named_arg) log_error("Operation not permitted on hidden LV %s.", display_lvname(lv)); return 0; @@ -1391,6 +1399,23 @@ int lvchange_activate_cmd(struct cmd_context *cmd, int argc, char **argv) if (do_activate) cmd->lockd_vg_enforce_sh = 1; + /* When activating, check if given LV is a component LV */ + if (do_activate) { + if ((argc == 1) && is_component_lvname(argv[0])) { + /* With single arg with reserved name prompt for component activation */ + if (arg_is_set(cmd, yes_ARG) || + (yes_no_prompt("Do you want to activate component LV " + "in read-only mode? [y/n]: ") == 'y')) { + log_print_unless_silent("Allowing activation of component LV."); + cmd->activate_component = 1; + } + + if (sigint_caught()) + return_ECMD_FAILED; + } + } else /* Component LVs might be active, support easy deactivation */ + cmd->process_component_lvs = 1; + ret = process_each_lv(cmd, argc, argv, NULL, NULL, 0, NULL, &_lvchange_activate_check, &_lvchange_activate_single); diff --git a/tools/toollib.c b/tools/toollib.c index 0958f2f05..eab622346 100644 --- a/tools/toollib.c +++ b/tools/toollib.c @@ -3058,7 +3058,8 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg, * Only let hidden LVs through if --all was used or the LVs * were specifically named on the command line. */ - if (!lvargs_supplied && !lv_is_visible(lvl->lv) && !arg_is_set(cmd, all_ARG)) + if (!lvargs_supplied && !lv_is_visible(lvl->lv) && !arg_is_set(cmd, all_ARG) && + (!cmd->process_component_lvs || !lv_is_component(lvl->lv))) continue; /* diff --git a/tools/vgchange.c b/tools/vgchange.c index 616a9d3f3..6d739fe9b 100644 --- a/tools/vgchange.c +++ b/tools/vgchange.c @@ -92,7 +92,7 @@ static int _activate_lvs_in_vg(struct cmd_context *cmd, struct volume_group *vg, lv = lvl->lv; - if (!lv_is_visible(lv)) + if (!lv_is_visible(lv) && (!cmd->process_component_lvs || !lv_is_component(lv))) continue; /* If LV is sparse, activate origin instead */ @@ -222,6 +222,8 @@ int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg, /* FIXME Move into library where clvmd can use it */ if (do_activate) check_current_backup(vg); + else /* Component LVs might be active, support easy deactivation */ + cmd->process_component_lvs = 1; if (do_activate && (active = lvs_in_vg_activated(vg))) { log_verbose("%d logical volume(s) in volume group \"%s\" "