summaryrefslogtreecommitdiff
path: root/tools/pvscan.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/pvscan.c')
-rw-r--r--tools/pvscan.c265
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;
}