diff options
Diffstat (limited to 'tools/vgchange.c')
-rw-r--r-- | tools/vgchange.c | 198 |
1 files changed, 191 insertions, 7 deletions
diff --git a/tools/vgchange.c b/tools/vgchange.c index 985907a02..b6dc5a2fc 100644 --- a/tools/vgchange.c +++ b/tools/vgchange.c @@ -19,6 +19,7 @@ struct vgchange_params { int lock_start_count; unsigned int lock_start_sanlock : 1; + unsigned int vg_complete_to_activate : 1; }; /* @@ -194,11 +195,47 @@ int vgchange_background_polling(struct cmd_context *cmd, struct volume_group *vg return 1; } +static int _online_pvid_file_create_all(struct cmd_context *cmd) +{ + struct lvmcache_info *info; + struct dev_iter *iter; + struct device *dev; + const char *vgname; + int exists; + int exist_count = 0; + int create_count = 0; + + if (!(iter = dev_iter_create(NULL, 0))) + return 0; + while ((dev = dev_iter_get(cmd, iter))) { + if (dev->pvid[0] && + (info = lvmcache_info_from_pvid(dev->pvid, dev, 0))) { + vgname = lvmcache_vgname_from_info(info); + if (vgname && !is_orphan_vg(vgname)) { + /* + * Ignore exsting pvid file because a pvscan may be creating + * the same file as the same time we are, which is expected. + */ + exists = 0; + online_pvid_file_create(cmd, dev, vgname, 1, &exists); + if (exists) + exist_count++; + else + create_count++; + } + } + } + dev_iter_destroy(iter); + log_debug("PV online files created %d exist %d", create_count, exist_count); + return 1; +} + int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg, - activation_change_t activate) + activation_change_t activate, int vg_complete_to_activate) { int lv_open, active, monitored = 0, r = 1; const struct lv_list *lvl; + struct pv_list *pvl; int do_activate = is_change_activating(activate); /* @@ -219,6 +256,20 @@ int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg, return 1; } + if (arg_is_set(cmd, vgonline_ARG) && !online_vg_file_create(cmd, vg->name)) { + log_print("VG %s already online", vg->name); + return 1; + } + + if (do_activate && vg_complete_to_activate) { + dm_list_iterate_items(pvl, &vg->pvs) { + if (!pvl->pv->dev) { + log_print("VG %s is incomplete.", vg->name); + return 1; + } + } + } + /* * Safe, since we never write out new metadata here. Required for * partial activation to work. @@ -262,11 +313,6 @@ int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg, } } - if (arg_is_set(cmd, vgonline_ARG) && !online_vg_file_create(cmd, vg->name)) { - log_print("VG %s finished", vg->name); - return 1; - } - if (!_activate_lvs_in_vg(cmd, vg, activate)) { stack; r = 0; @@ -652,6 +698,7 @@ static int _vgchange_single(struct cmd_context *cmd, const char *vg_name, struct volume_group *vg, struct processing_handle *handle) { + struct vgchange_params *vp = (struct vgchange_params *)handle->custom_handle; int ret = ECMD_PROCESSED; unsigned i; activation_change_t activate; @@ -709,7 +756,7 @@ static int _vgchange_single(struct cmd_context *cmd, const char *vg_name, if (arg_is_set(cmd, activate_ARG)) { activate = (activation_change_t) arg_uint_value(cmd, activate_ARG, 0); - if (!vgchange_activate(cmd, vg, activate)) + if (!vgchange_activate(cmd, vg, activate, vp->vg_complete_to_activate)) return_ECMD_FAILED; } else if (arg_is_set(cmd, refresh_ARG)) { /* refreshes the visible LVs (which starts polling) */ @@ -730,8 +777,123 @@ static int _vgchange_single(struct cmd_context *cmd, const char *vg_name, return ret; } +static int _check_autoactivation(struct cmd_context *cmd, struct vgchange_params *vp, int *skip_command, int *enable_events, + int *create_pvs_online) +{ + const char *aa; + int service_only = 0, event_only = 0, service_and_event = 0, pvscan_hints = 0; + int opt_service = 0, opt_event = 0, opt_event_enable = 0; + int on_file_exists; + int event_activation; + + if (!(aa = arg_str_value(cmd, autoactivation_ARG, NULL))) { + log_error("No autoactivation value."); + return 0; + } + + /* lvm.conf auto_activation_settings */ + if (!get_autoactivation_config_settings(cmd, &service_only, &event_only, &service_and_event, &pvscan_hints)) + return_0; + + /* --autoactivation values */ + if (!get_autoactivation_command_options(cmd, aa, &opt_service, &opt_event, &opt_event_enable)) + return_0; + + event_activation = find_config_tree_bool(cmd, global_event_activation_CFG, NULL); + + /* + * The combination of lvm.conf event_activation/auto_activation_settings + * and the --autoactivation service|event value determines if this + * command should do anything or be skipped, along with the existence of + * the /run/lvm/event-activation-on file in case of service_and_event. + */ + if (!event_activation) { + if (opt_event) { + log_print("Skip vgchange for event and event_activation=0."); + *skip_command = 1; + return 1; + } + } else { + if (event_only && opt_service) { + log_print("Skip vgchange for service and autoactivation_settings event_only."); + *skip_command = 1; + return 1; + } + if (service_only && opt_event) { + log_print("Skip vgchange for event and autoactivation_settings service_only."); + *skip_command = 1; + return 1; + } + + on_file_exists = event_activation_is_on(cmd); + + if (service_and_event && opt_service && on_file_exists) { + log_print("Skip vgchange for service and event-activation-on."); + *skip_command = 1; + return 1; + } + if (service_and_event && opt_event && !on_file_exists) { + log_print("Skip vgchange for event and no event-activation-on."); + *skip_command = 1; + return 1; + } + } + + /* + * Switch from service activation to event activation when: + * lvm.conf event_activation=1, + * auto_activation_settings=service_and_event, + * and --autoactivation service,event_enable + * + * When enabling event-based activation, first create the + * /run/lvm/event-activation-on file to tell other commands + * to begin responding to PV events and doing activation + * for newly completed VGs. + * + * When no pvscan_hints are used, pvscan --cache has not been + * creating pvs_online files during service mode, so now + * we need to create pvs_online files for all existing PVs + * to make up for that. + */ + if (event_activation && service_and_event && opt_service && opt_event_enable) { + if (!event_activation_enable(cmd)) + log_warn("WARNING: Failed to create event-activation-on."); + *enable_events = 1; + + if (!pvscan_hints) + *create_pvs_online = 1; + } + + /* + * lvm.conf service_and_event, and vgchange -aay --autoactivation service, + * then only activate LVs if the VG is complete. + * A later event will complete the VG and activate it. + */ + if (event_activation && service_and_event && opt_service) + vp->vg_complete_to_activate = 1; + + /* + * vgchange -aay --autoactivation service, and lvm.conf + * autoactivation_settings with pvscan_hints means the vgchange + * should use the special hints=pvs_online. + * Otherwise, the vgchange uses the equivalent of --nohints. + * If --nohints is on the vgchange command line, that overrides + * and disables autoactivation_settings pvscan_hints. + * hints=pvs_online means the command will only use devices that + * have been processed by pvscan --cache (which have a pvid file + * created under /run/lvm/pvs_online.) + */ + if (!arg_is_set(cmd, nohints_ARG) && pvscan_hints) + cmd->hints_pvs_online = 1; + else + cmd->use_hints = 0; + + return 1; +} + int vgchange(struct cmd_context *cmd, int argc, char **argv) { + struct vgchange_params vp = { 0 }; struct processing_handle *handle; uint32_t flags = 0; int ret; @@ -845,6 +1007,26 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv) cmd->lockd_vg_enforce_sh = 1; } + if (arg_is_set(cmd, autoactivation_ARG)) { + int skip_command = 0, enable_events = 0, create_pvs_online = 0; + if (!_check_autoactivation(cmd, &vp, &skip_command, &enable_events, &create_pvs_online)) + return ECMD_FAILED; + if (skip_command) + return ECMD_PROCESSED; + if (enable_events) { + if (!event_activation_enable(cmd)) + log_warn("WARNING: Failed to create event-activation-on."); + if (create_pvs_online) { + /* The process_each_vg lock_global/lvmcache_label_scan will be skipped. */ + if (!lock_global(cmd, "sh")) + return ECMD_FAILED; + lvmcache_label_scan(cmd); + _online_pvid_file_create_all(cmd); + flags |= PROCESS_SKIP_SCAN; + } + } + } + if (update) flags |= READ_FOR_UPDATE; else if (arg_is_set(cmd, activate_ARG)) @@ -855,6 +1037,8 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv) return ECMD_FAILED; } + handle->custom_handle = &vp; + ret = process_each_vg(cmd, argc, argv, NULL, NULL, flags, 0, handle, &_vgchange_single); destroy_processing_handle(cmd, handle); |