diff options
Diffstat (limited to 'tools/pvscan.c')
-rw-r--r-- | tools/pvscan.c | 265 |
1 files changed, 249 insertions, 16 deletions
diff --git a/tools/pvscan.c b/tools/pvscan.c index d68daa62b..e4f90a759 100644 --- a/tools/pvscan.c +++ b/tools/pvscan.c @@ -21,7 +21,19 @@ #include <dirent.h> -int online_pvid_file_read(char *path, int *major, int *minor, char *vgname); +struct aa_settings { + /* from lvm.conf */ + int event_activation; + int service_only; + int event_only; + int service_and_event; + int pvscan_hints; + + /* from --eventactivation */ + int opt_service; + int opt_event; + int opt_event_enable; +}; struct pvscan_params { int new_pvs_found; @@ -48,6 +60,8 @@ static const char *_pvs_online_dir = DEFAULT_RUN_DIR "/pvs_online"; static const char *_vgs_online_dir = DEFAULT_RUN_DIR "/vgs_online"; static const char *_pvs_lookup_dir = DEFAULT_RUN_DIR "/pvs_lookup"; +static const char *_event_activation_file = DEFAULT_RUN_DIR "/event-activation-on"; + static int _pvscan_display_pv(struct cmd_context *cmd, struct physical_volume *pv, struct pvscan_params *params) @@ -182,6 +196,84 @@ out: } /* + * Event based activation + * lvm.conf event_activation_options = "event_only" + * . all events are used for activation + * . no fixed services are used for activation + * . lvm.conf event_activation=1 required + * + * vgchange -aay --eventactivation service + * . does nothing + * vgchange -aay --eventactivation event + * . does activation + * pvscan --eventactivation event + * . does activation + * + * --- + * + * Non-event based activation + * lvm.conf event_activation_options = "service_only" + * . fixed services are used for activation + * . no events are used for activation + * . lvm.conf event_activation=0 is equivalent to + * event_activation=1 event_activation_options="service_only" + * + * vgchange -aay --eventactivation service + * . does activation + * vgchange -aay --eventactivation event + * . does nothing + * pvscan --eventactivation event + * . does nothing + * + * --- + * + * Mix of event and non-event based activation + * lvm.conf event_activation_options = "service_and_event" + * . both services and events are used for activation + * . fixed services are used for activation initially, + * and last service enables event based activation + * by creating the event-activation-on file + * + * vgchange -aay --eventactivation service + * . does activation only if event-activation-on does not exist + * vgchange -aay --eventactivation event + * . does activation only if event-activation-on exists + * vgchange -aay --eventactivation service,on + * . does activation only if event-activation-on does not exist + * . creates event-activation-on to enable event-based activation + * vgchange --eventactivation on|off + * . create or remove event-activation-on to enable|disable + * event-based activation + * pvscan --eventactivation event + * . does activation only if event-activation-on exists + * + */ + +int event_activation_enable(struct cmd_context *cmd) +{ + FILE *fp; + + if (!(fp = fopen(_event_activation_file, "w"))) + return_0; + if (fclose(fp)) + stack; + return 1; +} + +int event_activation_is_on(struct cmd_context *cmd) +{ + struct stat buf; + + if (!stat(_event_activation_file, &buf)) + return 1; + + if (errno != ENOENT) + log_debug("event_activation_is_on errno %d", errno); + + return 0; +} + +/* * Avoid a duplicate pvscan[%d] prefix when logging to the journal. * FIXME: this should probably replace if (udevoutput) with * if (log_journal & LOG_JOURNAL_OUTPUT) @@ -369,7 +461,7 @@ static void _online_files_remove(const char *dirpath) log_sys_debug("closedir", dirpath); } -static int _online_pvid_file_create(struct cmd_context *cmd, struct device *dev, const char *vgname) +int online_pvid_file_create(struct cmd_context *cmd, struct device *dev, const char *vgname, int ignore_existing, int *exists) { char path[PATH_MAX]; char buf[MAX_PVID_FILE_SIZE] = { 0 }; @@ -409,8 +501,13 @@ static int _online_pvid_file_create(struct cmd_context *cmd, struct device *dev, fd = open(path, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR); if (fd < 0) { - if (errno == EEXIST) + if (errno == EEXIST) { + if (exists) + *exists = 1; + if (ignore_existing) + return 1; goto check_duplicate; + } log_error_pvscan(cmd, "Failed to create online file for %s path %s error %d", dev_name(dev), path, errno); return 0; } @@ -429,7 +526,6 @@ static int _online_pvid_file_create(struct cmd_context *cmd, struct device *dev, } /* We don't care about syncing, these files are not even persistent. */ - if (close(fd)) log_sys_debug("close", path); @@ -469,7 +565,7 @@ check_duplicate: return 0; } -static int _online_pvid_file_exists(const char *pvid) +int online_pvid_file_exists(const char *pvid) { char path[PATH_MAX] = { 0 }; struct stat buf; @@ -555,7 +651,7 @@ static void _lookup_file_count_pvid_files(FILE *fp, const char *vgname, int *pvs continue; } - if (_online_pvid_file_exists((const char *)pvid)) + if (online_pvid_file_exists((const char *)pvid)) (*pvs_online)++; else (*pvs_offline)++; @@ -727,7 +823,7 @@ static void _count_pvid_files(struct volume_group *vg, int *pvs_online, int *pvs dm_list_iterate_items(pvl, &vg->pvs) { memcpy(pvid, &pvl->pv->id.uuid, ID_LEN); - if (_online_pvid_file_exists(pvid)) + if (online_pvid_file_exists(pvid)) (*pvs_online)++; else (*pvs_offline)++; @@ -750,7 +846,7 @@ static int _pvscan_aa_single(struct cmd_context *cmd, const char *vg_name, log_debug("pvscan autoactivating VG %s.", vg_name); - if (!vgchange_activate(cmd, vg, CHANGE_AAY)) { + if (!vgchange_activate(cmd, vg, CHANGE_AAY, 1)) { log_error_pvscan(cmd, "%s: autoactivation failed.", vg->name); pp->activate_errors++; } @@ -1038,7 +1134,7 @@ static int _pvscan_aa_quick(struct cmd_context *cmd, struct pvscan_aa_params *pp log_debug("pvscan autoactivating VG %s.", vgname); - if (!vgchange_activate(cmd, vg, CHANGE_AAY)) { + if (!vgchange_activate(cmd, vg, CHANGE_AAY, 1)) { log_error_pvscan(cmd, "%s: autoactivation failed.", vg->name); pp->activate_errors++; } @@ -1242,7 +1338,7 @@ static void _set_pv_devices_online(struct cmd_context *cmd, struct volume_group continue; } - if (!_online_pvid_file_exists(pvid)) { + if (!online_pvid_file_exists(pvid)) { log_debug("set_pv_devices_online vg %s pv %s no online file", vg->name, pvid); pvl->pv->status |= MISSING_PV; @@ -1282,7 +1378,7 @@ static void _set_pv_devices_online(struct cmd_context *cmd, struct volume_group } static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvscan_devs, - int *pv_count, struct dm_list *complete_vgnames) + int *pv_count, struct dm_list *complete_vgnames, struct aa_settings *set) { struct device_list *devl, *devl2; struct device *dev; @@ -1422,7 +1518,7 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs * Create file named for pvid to record this PV is online. * The command creates/checks online files only when --cache is used. */ - if (do_cache && !_online_pvid_file_create(cmd, dev, vg ? vg->name : NULL)) { + if (do_cache && !online_pvid_file_create(cmd, dev, vg ? vg->name : NULL, 0, NULL)) { log_error_pvscan(cmd, "PV %s failed to create online file.", dev_name(dev)); release_vg(vg); ret = 0; @@ -1439,6 +1535,20 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs } /* + * A fixed activation service will create event-activation-on + * after which this pvscan will do the steps to trigger + * event based activation. We get to this point because the + * fixed activation service uses pvscan_hints which requires + * this pvscan to create the pvs_online file. The online + * file has now been created so the command is done. + */ + if (set && set->service_and_event && !event_activation_is_on(cmd)) { + log_print_pvscan(cmd, "PV %s online before event activation.", dev_name(dev)); + release_vg(vg); + continue; + } + + /* * Check if all the PVs for this VG are online. If the arrival * of this dev completes the VG, then save the vgname in * complete_vgnames (activation phase will want to know which @@ -1660,13 +1770,14 @@ static int _pvscan_cache_all(struct cmd_context *cmd, int argc, char **argv, } dev_iter_destroy(iter); - _online_devs(cmd, 1, &pvscan_devs, &pv_count, complete_vgnames); + _online_devs(cmd, 1, &pvscan_devs, &pv_count, complete_vgnames, NULL); return 1; } static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv, - struct dm_list *complete_vgnames) + struct dm_list *complete_vgnames, + struct aa_settings *settings) { struct dm_list pvscan_args; /* struct pvscan_arg */ struct dm_list pvscan_devs; /* struct device_list */ @@ -1852,7 +1963,7 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv, */ label_scan_devs_cached(cmd, NULL, &pvscan_devs); - ret = _online_devs(cmd, 0, &pvscan_devs, &pv_count, complete_vgnames); + ret = _online_devs(cmd, 0, &pvscan_devs, &pv_count, complete_vgnames, settings); /* * When a new PV appears, the system runs pvscan --cache dev. @@ -1869,12 +1980,126 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv, return ret; } +/* +event_activation=1 service_and_event=1 pvscan_hints=1 +services, then events +pvscan --cache creates pvs_online for all PVs +lvm-activate-vgs* used first +lvm-activate-<vgname> used later +vgchanges use hints=pvs_online from services and events + +event_activation=1 event_only=1 pvscan_hints=1 +only event activations +pvscan --cache creates pvs_online for all PVs +lvm-activate-vgs* skipped +lvm-activate-<vgname> used +vgchanges use hints=pvs_online from events + +event_activation=1 service_only=1 pvscan_hints=1 +only service activations +pvscan --cache creates pvs_online for all PVs +lvm-activate-vgs* used first +lvm-activate-<vgname> skipped +vgchanges use hints=pvs_online from services +(pvscan --cache could be skipped after services finish) + +event_activation=1 service_and_event=1 pvscan_hints=0 +services, then events +pvscan --cache skipped in service mode +pvscan --cache creates pvs_online in event mode +vgchange when enabling event mode must create pvs_online for existing PVs +lvm-activate-vgs* used first +lvm-activate-<vgname> used later +vgchanges scan all PVs from services and events + +event_activation=1 event_only=1 pvscan_hints=0 +only event activations +pvscan --cache creates pvs_online for all PVs +lvm-activate-vgs* skipped +lvm-activate-<vgname> used +vgchanges scan all PVs from events + +event_activation=1 service_only=1 pvscan_hints=0 +only service activations +pvscan --cache always skipped +lvm-activate-vgs* used first +lvm-activate-<vgname> skipped +vgchanges scan all PVs from services + +event_activation=0 +only service activations +ignores service_and_events=1 or events_only=1 +. for pvscan_hints=1 + pvscan --cache creates pvs_online for all PVs + lvm-activate-vgs* used first + lvm-activate-<vgname> skipped + vgchanges use hints=pvs_online from services + (pvscan --cache could be skipped after services finish) +. for pvscan_hints=0 + pvscan --cache always skipped + lvm-activate-vgs* used first + lvm-activate-<vgname> skipped + vgchanges scan all PVs from services +*/ + +static int _get_autoactivation(struct cmd_context *cmd, + struct aa_settings *set, + int *skip_command) +{ + const char *aa_str; + + /* + * The lvm.conf settings only apply when the command uses --autoactivation + * which says if the command is used for event or service activation. + */ + if (!(aa_str = arg_str_value(cmd, autoactivation_ARG, NULL))) + return 1; + + if (!get_autoactivation_config_settings(cmd, &set->service_only, &set->event_only, &set->service_and_event, &set->pvscan_hints)) + return 0; + + if (!get_autoactivation_command_options(cmd, aa_str, &set->opt_service, &set->opt_event, &set->opt_event_enable)) + return 0; + + if (!set->opt_event) { + log_print_pvscan(cmd, "Skip pvscan without autoactivation=event."); + *skip_command = 1; + return 1; + } + + if (!set->event_activation && !set->pvscan_hints) { + log_print_pvscan(cmd, "Skip pvscan with event_activation=0."); + *skip_command = 1; + return 1; + } + + if (set->service_only && !set->pvscan_hints) { + log_print_pvscan(cmd, "Skip pvscan with service_only."); + *skip_command = 1; + return 1; + } + + if (set->service_and_event && !set->pvscan_hints && !event_activation_is_on(cmd)) { + /* + * Note that when vgchange enables events, it needs to compensate for this + * skipped pvscan by creating pvs_online files for all existing PVs. + */ + log_print_pvscan(cmd, "Skip pvscan without event-activation-on."); + *skip_command = 1; + return 1; + } + + return 1; +} + int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv) { struct pvscan_aa_params pp = { 0 }; struct dm_list complete_vgnames; + struct aa_settings settings = { 0 }; int do_activate = arg_is_set(cmd, activate_ARG); int event_activation; + int skip_command = 0; int devno_args = 0; int do_all; int ret; @@ -1888,6 +2113,7 @@ int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv) cmd->ignore_device_name_mismatch = 1; event_activation = find_config_tree_bool(cmd, global_event_activation_CFG, NULL); + settings.event_activation = event_activation; if (do_activate && !event_activation) { log_verbose("Ignoring pvscan --cache -aay because event_activation is disabled."); @@ -1946,7 +2172,14 @@ int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv) log_verbose("Ignoring pvscan --cache because event_activation is disabled."); return ECMD_PROCESSED; } - if (!_pvscan_cache_args(cmd, argc, argv, &complete_vgnames)) + + if (!_get_autoactivation(cmd, &settings, &skip_command)) + return_ECMD_FAILED; + + if (skip_command) + return ECMD_PROCESSED; + + if (!_pvscan_cache_args(cmd, argc, argv, &complete_vgnames, &settings)) return ECMD_FAILED; } |