diff --git a/configure.ac b/configure.ac index 6cdf1a7e6..45183f422 100644 --- a/configure.ac +++ b/configure.ac @@ -781,39 +781,6 @@ AC_ARG_WITH(default-run-dir, AC_DEFINE_UNQUOTED(DEFAULT_RUN_DIR, ["$DEFAULT_RUN_DIR"], [Default LVM run directory.]) -################################################################################ -dnl -- Build cluster mirror log daemon -AC_MSG_CHECKING(whether to build cluster mirror log daemon) -AC_ARG_ENABLE(cmirrord, - AS_HELP_STRING([--enable-cmirrord], - [enable the cluster mirror log daemon]), - CMIRRORD=$enableval, CMIRRORD=no) -AC_MSG_RESULT($CMIRRORD) - -BUILD_CMIRRORD=$CMIRRORD - -################################################################################ -dnl -- cmirrord pidfile -if test "$BUILD_CMIRRORD" = yes; then - AC_ARG_WITH(cmirrord-pidfile, - AS_HELP_STRING([--with-cmirrord-pidfile=PATH], - [cmirrord pidfile [PID_DIR/cmirrord.pid]]), - CMIRRORD_PIDFILE=$withval, - CMIRRORD_PIDFILE="$DEFAULT_PID_DIR/cmirrord.pid") - AC_DEFINE_UNQUOTED(CMIRRORD_PIDFILE, ["$CMIRRORD_PIDFILE"], - [Path to cmirrord pidfile.]) -fi - -################################################################################ -dnl -- Look for corosync libraries if required. -if [[ "$BUILD_CMIRRORD" = yes ]]; then - pkg_config_init - - if test "$HAVE_CPG" != yes; then - PKG_CHECK_MODULES(CPG, libcpg) - fi -fi - ################################################################################ dnl -- Enable debugging AC_MSG_CHECKING(whether to enable debugging) @@ -1655,10 +1622,6 @@ fi AC_MSG_CHECKING(whether to enable editline) AC_MSG_RESULT($EDITLINE) -if test "$BUILD_CMIRRORD" = yes; then - AC_CHECK_FUNCS(atexit,,hard_bailout) -fi - if test "$BUILD_LVMLOCKD" = yes; then AS_IF([test "$HAVE_REALTIME" != yes], [AC_MSG_ERROR([Realtime clock support is mandatory for lvmlockd.])]) AC_CHECK_FUNCS(strtoull,,hard_bailout) @@ -1834,7 +1797,6 @@ AC_ARG_VAR([UDEV_LIBS], [linker flags for udev]) ################################################################################ AC_SUBST(AWK) AC_SUBST(BLKID_PC) -AC_SUBST(BUILD_CMIRRORD) AC_SUBST(BUILD_DMEVENTD) AC_SUBST(BUILD_LVMDBUSD) AC_SUBST(BUILD_LVMPOLLD) @@ -1967,7 +1929,6 @@ AC_SUBST(WRITE_INSTALL) AC_SUBST(DMEVENTD_PIDFILE) AC_SUBST(LVMPOLLD_PIDFILE) AC_SUBST(LVMLOCKD_PIDFILE) -AC_SUBST(CMIRRORD_PIDFILE) AC_SUBST(interface) AC_SUBST(kerneldir) AC_SUBST(missingkernel) @@ -1989,7 +1950,6 @@ Makefile make.tmpl libdm/make.tmpl daemons/Makefile -daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile @@ -2023,14 +1983,15 @@ libdm/libdevmapper.pc man/Makefile po/Makefile scripts/lvm2-pvscan.service +scripts/lvm-activate-vgs-main.service +scripts/lvm-activate-vgs-last.service +scripts/lvm-devices-wait.service scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service -scripts/cmirrord_init_red_hat scripts/com.redhat.lvmdbus1.service scripts/dm_event_systemd_red_hat.service scripts/dm_event_systemd_red_hat.socket -scripts/lvm2_cmirrord_systemd_red_hat.service scripts/lvm2_lvmdbusd_systemd_red_hat.service scripts/lvm2_lvmpolld_init_red_hat scripts/lvm2_lvmpolld_systemd_red_hat.service diff --git a/lib/config/config_settings.h b/lib/config/config_settings.h index d280e7adb..57597bccc 100644 --- a/lib/config/config_settings.h +++ b/lib/config/config_settings.h @@ -1121,12 +1121,8 @@ cfg(global_lvdisplay_shows_full_device_path_CFG, "lvdisplay_shows_full_device_pa cfg(global_event_activation_CFG, "event_activation", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 1, vsn(2, 3, 1), 0, 0, NULL, "Activate LVs based on system-generated device events.\n" "When a PV appears on the system, a system-generated uevent triggers\n" - "the lvm2-pvscan service which runs the pvscan --cache -aay command.\n" - "If the new PV completes a VG, pvscan autoactivates LVs in the VG.\n" - "When event_activation is disabled, the lvm2-activation services are\n" - "generated and run at fixed points during system startup. These\n" - "services run vgchange -aay to autoactivate LVs in VGs that happen\n" - "to be present at that point in time.\n" + "the pvscan command, and autoactivation when all PVs for a VG are online.\n" + "Also see auto_activation_settings.\n" "See the --setautoactivation option or the auto_activation_volume_list\n" "setting to configure autoactivation for specific VGs or LVs.\n") @@ -1409,6 +1405,21 @@ cfg_array(activation_volume_list_CFG, "volume_list", activation_CFG_SECTION, CFG "volume_list = [ \"vg1\", \"vg2/lvol1\", \"@tag1\", \"@*\" ]\n" "#\n") +cfg_array(activation_auto_activation_settings_CFG, "auto_activation_settings", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_AUTOACTIVATION_SETTINGS, vsn(2, 3, 14), NULL, 0, NULL, + "Configure autoactivation behavior.\n" + "service_and_event: use fixed activation services, then switch to event activation\n." + "(Only used when event_activation=1.)\n" + "event_only: use only event activation\n" + "(Only used when event_activation=1.)\n" + "service_only: use only fixed activation services\n" + "(Effectively the equivalent of event_activation=0.)\n" + "pvscan_hints: autoactivation commands will use PVs that\n" + "that have been processed by pvscan (from udev rule.)\n" + "Without pvscan_hints, pvscan only be used when it is needed\n" + "to perform event activation.\n" + "Autoactivation commands should set --autoactivation service|event\n" + "to indicate if they are performing service or event activation.\n") + cfg_array(activation_auto_activation_volume_list_CFG, "auto_activation_volume_list", activation_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(2, 2, 97), NULL, 0, NULL, "A list of VGs or LVs that should be autoactivated.\n" "Autoactivation is an activation command run with -aay,\n" diff --git a/lib/config/defaults.h b/lib/config/defaults.h index 3308b1ea6..bc361f7f6 100644 --- a/lib/config/defaults.h +++ b/lib/config/defaults.h @@ -332,4 +332,8 @@ #define VGS_ONLINE_DIR DEFAULT_RUN_DIR "/vgs_online" #define PVS_LOOKUP_DIR DEFAULT_RUN_DIR "/pvs_lookup" +#define DEFAULT_AUTOACTIVATION_SETTING1 "service_and_event" +#define DEFAULT_AUTOACTIVATION_SETTING2 "pvscan_hints" +#define DEFAULT_AUTOACTIVATION_SETTINGS "#S" DEFAULT_AUTOACTIVATION_SETTING1 "#S" DEFAULT_AUTOACTIVATION_SETTING2 + #endif /* _LVM_DEFAULTS_H */ diff --git a/lib/label/hints.c b/lib/label/hints.c index 4caadf774..67dcbd775 100644 --- a/lib/label/hints.c +++ b/lib/label/hints.c @@ -156,6 +156,7 @@ #include #include +/* FIXME: move online pv functions to pvs_online.c */ int online_pvid_file_read(char *path, int *major, int *minor, char *vgname); static const char *_hints_file = DEFAULT_RUN_DIR "/hints"; @@ -1406,7 +1407,7 @@ int get_hints(struct cmd_context *cmd, struct dm_list *hints_out, int *newhints, *newhints = NEWHINTS_NONE; /* No commands are using hints. */ - if (!cmd->enable_hints) + if (!cmd->enable_hints && !cmd->hints_pvs_online) return 0; /* @@ -1426,7 +1427,11 @@ int get_hints(struct cmd_context *cmd, struct dm_list *hints_out, int *newhints, if (!cmd->use_hints) return 0; - /* hints = "pvs_online" */ + /* + * enable_hints is 0 for the special hints=pvs_online + * and by lvm.conf hints="none" does not disable hints=pvs_online. + * hints=pvs_online can be disabled with --nohints. + */ if (cmd->hints_pvs_online) { if (!_get_hints_from_pvs_online(cmd, &hints_list, devs_in, devs_out)) { log_debug("get_hints: pvs_online failed"); diff --git a/lib/label/label.c b/lib/label/label.c index 3cd912270..c5e0e11ba 100644 --- a/lib/label/label.c +++ b/lib/label/label.c @@ -1130,6 +1130,9 @@ int label_scan(struct cmd_context *cmd) } } } + + log_debug_devs("Filtering devices to scan done (nodata)"); + cmd->filter_nodata_only = 0; dm_list_iterate_items(devl, &all_devs) diff --git a/scripts/Makefile.in b/scripts/Makefile.in index 0d7f45680..bc567555e 100644 --- a/scripts/Makefile.in +++ b/scripts/Makefile.in @@ -15,9 +15,6 @@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ -SOURCES = lvm2_activation_generator_systemd_red_hat.c -TARGETS = lvm2_activation_generator_systemd_red_hat - include $(top_builddir)/make.tmpl ifeq ("@BUILD_DMEVENTD@", "yes") @@ -66,7 +63,7 @@ install_initscripts: @echo " [INSTALL] initscripts" $(Q) $(INSTALL_DIR) $(initdir) ifeq ("@BUILD_DMEVENTD@", "yes") - $(Q) $(INSTALL_SCRIPT) lvm2_monitoring_init_red_hat $(initdir)/lvm2-monitor + $(Q) $(INSTALL_SCRIPT) lvm2_monitoring_init_red_hat $(initdir)/lvm-monitor endif ifeq ("@BUILD_LVMPOLLD@", "yes") $(Q) $(INSTALL_SCRIPT) lvm2_lvmpolld_init_red_hat $(initdir)/lvm2-lvmpolld @@ -78,24 +75,15 @@ ifeq ("@BLKDEACTIVATE@", "yes") $(Q) $(INSTALL_SCRIPT) blk_availability_init_red_hat $(initdir)/blk-availability endif -CFLAGS_lvm2_activation_generator_systemd_red_hat.o += $(EXTRA_EXEC_CFLAGS) - -lvm2_activation_generator_systemd_red_hat: $(OBJECTS) $(LVMINTERNAL_LIBS) - @echo " [CC] $@" - $(Q) $(CC) -o $@ $(OBJECTS) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) $(LVMINTERNAL_LIBS) $(LIBS) - -install_systemd_generators: - @echo " [INSTALL] systemd_generators" - $(Q) $(INSTALL_DIR) $(systemd_generator_dir) - $(Q) $(INSTALL_PROGRAM) lvm2_activation_generator_systemd_red_hat $(systemd_generator_dir)/lvm2-activation-generator - install_systemd_units: install_dbus_service @echo " [INSTALL] systemd_units" $(Q) $(INSTALL_DIR) $(systemd_unit_dir) + $(Q) $(INSTALL_DATA) lvm-activate-vgs-main.service $(systemd_unit_dir)/lvm-activate-vgs-main.service + $(Q) $(INSTALL_DATA) lvm-activate-vgs-last.service $(systemd_unit_dir)/lvm-activate-vgs-last.service ifeq ("@BUILD_DMEVENTD@", "yes") $(Q) $(INSTALL_DATA) dm_event_systemd_red_hat.socket $(systemd_unit_dir)/dm-event.socket $(Q) $(INSTALL_DATA) dm_event_systemd_red_hat.service $(systemd_unit_dir)/dm-event.service - $(Q) $(INSTALL_DATA) lvm2_monitoring_systemd_red_hat.service $(systemd_unit_dir)/lvm2-monitor.service + $(Q) $(INSTALL_DATA) lvm2_monitoring_systemd_red_hat.service $(systemd_unit_dir)/lvm-monitor.service endif ifeq ("@BLKDEACTIVATE@", "yes") $(Q) $(INSTALL_DATA) blk_availability_systemd_red_hat.service $(systemd_unit_dir)/blk-availability.service @@ -155,7 +143,9 @@ DISTCLEAN_TARGETS += \ lvm2_monitoring_init_red_hat \ lvm2_monitoring_systemd_red_hat.service \ lvm2_pvscan_systemd_red_hat@.service \ - lvm2_tmpfiles_red_hat.conf + lvm2_tmpfiles_red_hat.conf \ + lvm-activate-vgs-main.service \ + lvm-activate-vgs-last.service # Remove ancient files DISTCLEAN_TARGETS += \ diff --git a/scripts/blk_availability_systemd_red_hat.service.in b/scripts/blk_availability_systemd_red_hat.service.in index 82d3b82d0..e42b3ab5f 100644 --- a/scripts/blk_availability_systemd_red_hat.service.in +++ b/scripts/blk_availability_systemd_red_hat.service.in @@ -1,7 +1,7 @@ [Unit] Description=Availability of block devices Before=shutdown.target -After=lvm2-activation.service iscsi-shutdown.service iscsi.service iscsid.service fcoe.service rbdmap.service +After=lvm-activate-vgs-main.service lvm-activate-vgs-last.service iscsi-shutdown.service iscsi.service iscsid.service fcoe.service rbdmap.service DefaultDependencies=no Conflicts=shutdown.target diff --git a/scripts/lvm-activate-vgs-last.service.in b/scripts/lvm-activate-vgs-last.service.in new file mode 100644 index 000000000..8a1faf072 --- /dev/null +++ b/scripts/lvm-activate-vgs-last.service.in @@ -0,0 +1,24 @@ +[Unit] +Description=Activate LVM Volume Groups (last) +Documentation=man:vgchange(8) +After=lvm-activate-vgs-main.service multipathd.service cryptsetup.target dm-event.socket dm-event.service +Before=local-fs-pre.target shutdown.target +DefaultDependencies=no +Conflicts=shutdown.target + +# "--autoactivation service" tells vgchange it is being called +# from an activation service, so it will do nothing if +# lvm.conf autoactivation_settings has "event_only". +# "--autoactivation event_enable" tells vgchange to enable +# event-based pvscan activations by creating /run/lvm/event-activation-on. +# By default this vgchange will use device hints from pvs_online +# files, so it will only look at PVs that have finished being +# processed by udev and pvscan --cache. + +[Service] +Type=oneshot +ExecStart=@SBINDIR@/lvm vgchange -aay --vgonline --autoactivation service,event_enable +RemainAfterExit=yes + +[Install] +WantedBy=sysinit.target diff --git a/scripts/lvm-activate-vgs-main.service.in b/scripts/lvm-activate-vgs-main.service.in new file mode 100644 index 000000000..f95edfa9a --- /dev/null +++ b/scripts/lvm-activate-vgs-main.service.in @@ -0,0 +1,22 @@ +[Unit] +Description=Activate LVM Volume Groups +Documentation=man:vgchange(8) +After=dm-event.socket dm-event.service lvm-devices-wait.service +Before=local-fs-pre.target shutdown.target +DefaultDependencies=no +Conflicts=shutdown.target + +# "--autoactivation service" tells vgchange it is being called +# from an autoactivation service, so it will do nothing if +# lvm.conf autoactivation_settings has "event_only". +# By default this vgchange will use device hints from pvs_online +# files, so it will only look at PVs that have finished being +# processed by udev and pvscan --cache. + +[Service] +Type=oneshot +ExecStart=@SBINDIR@/lvm vgchange -aay --vgonline --autoactivation service +RemainAfterExit=yes + +[Install] +WantedBy=sysinit.target diff --git a/scripts/lvm-devices-wait.service.in b/scripts/lvm-devices-wait.service.in new file mode 100644 index 000000000..680f2aa40 --- /dev/null +++ b/scripts/lvm-devices-wait.service.in @@ -0,0 +1,21 @@ +[Unit] +Description=Wait for LVM devices to be ready +Documentation=man:lvmdevices(8) +After=systemd-udev-trigger.service +Before=lvm-activate-vgs-main.service lvm-activate-vgs-last.service +DefaultDependencies=no +Conflicts=shutdown.target + +# Waits for entries in /etc/lvm/devices/system.devices to be processed +# by udev and pvscan --cache. Only device entries that are found in +# sysfs are waited for. See lvm.conf devices_wait_service "timeout=N" +# to configure the number of seconds that this service will wait. + +[Service] +Type=oneshot +ExecStart=@SBINDIR@/lvmdevices --wait pvsonline +RemainAfterExit=yes + +[Install] +WantedBy=sysinit.target + diff --git a/scripts/lvm2_monitoring_systemd_red_hat.service.in b/scripts/lvm2_monitoring_systemd_red_hat.service.in index 4bf744a7f..e912c6a85 100644 --- a/scripts/lvm2_monitoring_systemd_red_hat.service.in +++ b/scripts/lvm2_monitoring_systemd_red_hat.service.in @@ -1,8 +1,8 @@ [Unit] -Description=Monitoring of LVM2 mirrors, snapshots etc. using dmeventd or progress polling +Description=Monitor LVM Logical Volumes Documentation=man:dmeventd(8) man:lvcreate(8) man:lvchange(8) man:vgchange(8) Requires=dm-event.socket -After=dm-event.socket dm-event.service lvm2-activation.service +After=dm-event.socket dm-event.service lvm-activate-vgs-last.service Before=local-fs-pre.target shutdown.target DefaultDependencies=no Conflicts=shutdown.target diff --git a/spec/packages.inc b/spec/packages.inc index 74d795520..3d6ef2de9 100644 --- a/spec/packages.inc +++ b/spec/packages.inc @@ -23,10 +23,10 @@ if [ $1 = 0 ]; then fi %triggerun -- %{name} < 2.02.86-2 -%{_bindir}/systemd-sysv-convert --save lvm2-monitor >/dev/null 2>&1 || : -/bin/systemctl --no-reload enable lvm2-monitor.service > /dev/null 2>&1 || : -/sbin/chkconfig --del lvm2-monitor > /dev/null 2>&1 || : -/bin/systemctl try-restart lvm2-monitor.service > /dev/null 2>&1 || : +%{_bindir}/systemd-sysv-convert --save lvm-monitor >/dev/null 2>&1 || : +/bin/systemctl --no-reload enable lvm-monitor.service > /dev/null 2>&1 || : +/sbin/chkconfig --del lvm-monitor > /dev/null 2>&1 || : +/bin/systemctl try-restart lvm-monitor.service > /dev/null 2>&1 || : # files in the main package %files @@ -100,9 +100,6 @@ fi %{_mandir}/man8/lvm-config.8.gz %{_mandir}/man8/lvm-dumpconfig.8.gz %{_mandir}/man8/lvm.8.gz -%if %{enable_systemd} - %{_mandir}/man8/lvm2-activation-generator.8.gz -%endif %{_mandir}/man8/lvmconfig.8.gz %{_mandir}/man8/lvmdevices.8.gz %{_mandir}/man8/lvmdiskscan.8.gz @@ -187,16 +184,17 @@ fi %dir %{_default_run_dir} %if %{enable_systemd} %{_tmpfilesdir}/%{name}.conf + %{_unitdir}/lvm-activate-vgs-main.service + %{_unitdir}/lvm-activate-vgs-last.service + %{_unitdir}/lvm-monitor.service %{_unitdir}/blk-availability.service - %{_unitdir}/lvm2-monitor.service - %attr(555, -, -) %{_prefix}/lib/systemd/system-generators/lvm2-activation-generator %if %{have_service lvmpolld} %{_unitdir}/lvm2-lvmpolld.service %{_unitdir}/lvm2-lvmpolld.socket %endif %else %{_sysconfdir}/rc.d/init.d/blk-availability - %{_sysconfdir}/rc.d/init.d/lvm2-monitor + %{_sysconfdir}/rc.d/init.d/lvm-monitor %if %{have_service lvmpolld} %{_sysconfdir}/rc.d/init.d/lvm2-lvmpolld %endif diff --git a/tools/args.h b/tools/args.h index 774ce33f4..67d7317b4 100644 --- a/tools/args.h +++ b/tools/args.h @@ -87,6 +87,11 @@ arg(atversion_ARG, '\0', "atversion", string_VAL, 0, 0, "which does not contain any newer settings for which LVM would\n" "issue a warning message when checking the configuration.\n") +arg(autoactivation_ARG, '\0', "autoactivation", string_VAL, 0, 0, + "Specify if the command is running autoactivation from an event\n" + "or a service. lvm.conf autoactivation_settings determine if\n" + "activation commands from services or events are used.\n") + arg(setautoactivation_ARG, '\0', "setautoactivation", bool_VAL, 0, 0, "Set the autoactivation property on a VG or LV.\n" "Display the property with vgs or lvs \"-o autoactivation\".\n" @@ -920,6 +925,10 @@ arg(vgonline_ARG, '\0', "vgonline", 0, 0, 0, "The first command to see a complete VG will report it uniquely.\n" "Other commands to see the complete VG will report it differently.\n") +arg(wait_ARG, '\0', "wait", string_VAL, 0, 0, + "pvsonline: wait for /run/lvm/pvs_online files to exist\n" + "for all devices file entries matched to a system device.\n") + arg(withsummary_ARG, '\0', "withsummary", 0, 0, 0, "Display a one line comment for each configuration node.\n") diff --git a/tools/command-lines.in b/tools/command-lines.in index 23ea33e6d..b5ef7e65e 100644 --- a/tools/command-lines.in +++ b/tools/command-lines.in @@ -1447,6 +1447,10 @@ lvmdevices --delpvid String ID: lvmdevices_edit DESC: Remove the devices file entry for the given PVID. +lvmdevices --wait String +ID: lvmdevices_wait +DESC: Wait for matched PV entries to be online. + --- lvreduce --size NSizeMB LV @@ -1642,14 +1646,15 @@ DESC: Record that a PV is online or offline. pvscan --cache_long --activate ay OO: --ignorelockingfailure, --reportformat ReportFmt, ---major Number, --minor Number, --noudevsync +--major Number, --minor Number, --noudevsync, --autoactivation String OP: PV|String ... IO: --background ID: pvscan_cache DESC: Record that a PV is online and autoactivate the VG if complete. pvscan --cache_long --listvg PV -OO: --ignorelockingfailure, --checkcomplete, --vgonline, --udevoutput +OO: --ignorelockingfailure, --checkcomplete, --vgonline, --udevoutput, +--autoactivation String ID: pvscan_cache DESC: Record that a PV is online and list the VG using the PV. @@ -1747,7 +1752,8 @@ DESC: Start or stop processing LV conversions. vgchange --activate Active OO: --activationmode ActivationMode, --ignoreactivationskip, --partial, --sysinit, ---readonly, --ignorelockingfailure, --monitor Bool, --poll Bool, --vgonline, OO_VGCHANGE +--readonly, --ignorelockingfailure, --monitor Bool, --poll Bool, +--vgonline, --autoactivation String, OO_VGCHANGE OP: VG|Tag|Select ... IO: --ignoreskippedcluster ID: vgchange_activate diff --git a/tools/lvmdevices.c b/tools/lvmdevices.c index 8d9634848..e359920fd 100644 --- a/tools/lvmdevices.c +++ b/tools/lvmdevices.c @@ -19,6 +19,7 @@ /* coverity[unnecessary_header] needed for MuslC */ #include +#include static void _search_devs_for_pvids(struct cmd_context *cmd, struct dm_list *search_pvids, struct dm_list *found_devs) { @@ -119,18 +120,36 @@ static void _search_devs_for_pvids(struct cmd_context *cmd, struct dm_list *sear } } +static int _all_pvids_online(struct cmd_context *cmd, struct dm_list *wait_pvids) +{ + struct device_id_list *dil, *dil2; + int notfound = 0; + + dm_list_iterate_items_safe(dil, dil2, wait_pvids) { + if (online_pvid_file_exists(dil->pvid)) + dm_list_del(&dil->list); + else + notfound++; + } + + return notfound ? 0 : 1; +} + int lvmdevices(struct cmd_context *cmd, int argc, char **argv) { struct dm_list search_pvids; + struct dm_list wait_pvids; struct dm_list found_devs; struct device_id_list *dil; struct device_list *devl; struct device *dev; struct dev_use *du, *du2; const char *deviceidtype; + time_t begin; int changes = 0; dm_list_init(&search_pvids); + dm_list_init(&wait_pvids); dm_list_init(&found_devs); if (!setup_devices_file(cmd)) @@ -141,6 +160,9 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv) return ECMD_FAILED; } + if (arg_is_set(cmd, wait_ARG)) + cmd->print_device_id_not_found = 0; + if (arg_is_set(cmd, update_ARG) || arg_is_set(cmd, adddev_ARG) || arg_is_set(cmd, deldev_ARG) || arg_is_set(cmd, addpvid_ARG) || arg_is_set(cmd, delpvid_ARG)) { @@ -454,6 +476,62 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv) goto out; } + if (arg_is_set(cmd, wait_ARG)) { + if (strcmp("pvsonline", arg_str_value(cmd, wait_ARG, ""))) { + log_error("wait option invalid."); + goto bad; + } + + /* TODO: lvm.conf lvmdevices_wait_settings "disabled" do nothing */ + + /* TODO: lvm.conf auto_activation_settings "event_only" do nothing */ + + /* TODO: if no devices file exists, what should this do? + do a udev-settle? do nothing and cause more event-based activations? */ + + /* for each du, if du->wwid matched, wait for /run/lvm/pvs_online/du->pvid */ + dm_list_iterate_items(du, &cmd->use_devices) { + if (!du->dev) + continue; + if (!(dil = dm_pool_zalloc(cmd->mem, sizeof(*dil)))) + continue; + dil->dev = du->dev; + memcpy(dil->pvid, du->pvid, ID_LEN); + dm_list_add(&wait_pvids, &dil->list); + } + + log_print("Waiting for PVs online for %u matched devices file entries.", dm_list_size(&wait_pvids)); + begin = time(NULL); + + while (1) { + if (_all_pvids_online(cmd, &wait_pvids)) { + log_print("Found all PVs online"); + goto out; + } + log_print("Waiting for PVs online for %u devices.", dm_list_size(&wait_pvids)); + + /* TODO: lvm.conf lvmdevices_wait_ids "sys_wwid=111", "sys_wwid=222" etc + waits for the specifically named devices even if the devices do not exist. */ + + /* TODO: lvm.conf lvmdevices_wait_settings "timeout=N" */ + if (time(NULL) - begin >= 10) { + log_print("Time out waiting for PVs online:"); + dm_list_iterate_items(dil, &wait_pvids) + log_print("Need PVID %s on %s", dil->pvid, dev_name(dil->dev)); + break; + } + + if (dm_list_size(&wait_pvids) > 10) { + if (interruptible_usleep(1000000)) /* 1 sec */ + break; + } else { + if (interruptible_usleep(500000)) /* .5 sec */ + break; + } + } + goto out; + } + /* If no options, print use_devices list */ dm_list_iterate_items(du, &cmd->use_devices) { 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 -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) @@ -181,6 +195,84 @@ out: return ret; } +/* + * 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 @@ -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; @@ -1438,6 +1534,20 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs continue; } + /* + * 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 @@ -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- 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- 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- 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- 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- 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- 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- 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- 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; } diff --git a/tools/toollib.c b/tools/toollib.c index d6f48aad2..b43b44f2f 100644 --- a/tools/toollib.c +++ b/tools/toollib.c @@ -5714,3 +5714,96 @@ bad: out: return 0; } + +int get_autoactivation_config_settings(struct cmd_context *cmd, + int *service_only, int *event_only, int *service_and_event, int *pvscan_hints) +{ + const struct dm_config_node *cn; + const struct dm_config_value *cv; + int eo = 0, so = 0, se = 0, ph = 0; + + if (!(cn = find_config_tree_array(cmd, activation_auto_activation_settings_CFG, NULL))) + return 1; + + for (cv = cn->v; cv; cv = cv->next) { + if (cv->type != DM_CFG_STRING) + continue; + if (!strcmp(cv->v.str, "service_only")) + so = 1; + else if (!strcmp(cv->v.str, "event_only")) + eo = 1; + else if (!strcmp(cv->v.str, "service_and_event")) + se = 1; + else if (!strcmp(cv->v.str, "pvscan_hints")) + ph = 1; + else if (strlen(cv->v.str) > 0) + log_warn("WARNING: ignoring unrecognized autoactivation_settings value %s.", cv->v.str); + } + + if (se && (so || eo)) { + log_warn("WARNING: ignoring incompatible autoactivation_settings, using service_and_event."); + *service_and_event = 1; + } else if (so && eo) { + log_warn("WARNING: ignoring incompatible autoactivation_settings, using event_only."); + *event_only = 1; + } else if (se) { + *service_and_event = 1; + } else if (so) { + *service_only = 1; + } else if (eo) { + *event_only = 1; + } else { + *service_and_event = 1; + } + + if (ph) + *pvscan_hints = 1; + + return 1; +} + +static int _aa_option_value(const char *val, int *opt_service, int *opt_event, int *opt_event_enable) +{ + if (!strcmp(val, "service")) + *opt_service = 1; + else if (!strcmp(val, "event")) + *opt_event = 1; + else if (!strcmp(val, "event_enable")) + *opt_event_enable = 1; + else { + log_error("Unknown --autoactivation value."); + return 0; + } + return 1; +} + +int get_autoactivation_command_options(struct cmd_context *cmd, const char *aa, int *opt_service, int *opt_event, int *opt_event_enable) +{ + char vals[128] = { 0 }; + char *val1, *val2; + + strncpy(vals, aa, 127); + + /* Currently only two values can be used at once. */ + + val1 = vals; + + if ((val2 = strchr(vals, ','))) { + *val2 = '\0'; + val2++; + } + + if (val1 && !_aa_option_value(val1, opt_service, opt_event, opt_event_enable)) + return 0; + + if (val2 && !_aa_option_value(val2, opt_service, opt_event, opt_event_enable)) + return 0; + + if (*opt_service && *opt_event) { + log_error("Invalid --autoactivation options, service and event are incompatible."); + return 0; + } + + return 1; +} + diff --git a/tools/toollib.h b/tools/toollib.h index f3a60fbc4..76806d4c9 100644 --- a/tools/toollib.h +++ b/tools/toollib.h @@ -237,4 +237,9 @@ int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv, int get_lvt_enum(struct logical_volume *lv); +int get_autoactivation_config_settings(struct cmd_context *cmd, int *service_only, + int *event_only, int *service_and_event, int *pvscan_hints); +int get_autoactivation_command_options(struct cmd_context *cmd, const char *aa, + int *opt_service, int *opt_event, int *opt_event_enable); + #endif diff --git a/tools/tools.h b/tools/tools.h index e2661f272..fb2542fa2 100644 --- a/tools/tools.h +++ b/tools/tools.h @@ -226,9 +226,8 @@ int lvconvert_poll(struct cmd_context *cmd, struct logical_volume *lv, unsigned int mirror_remove_missing(struct cmd_context *cmd, struct logical_volume *lv, int force); - 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 vgchange_background_polling(struct cmd_context *cmd, struct volume_group *vg); @@ -295,8 +294,13 @@ int lvconvert_cachevol_attach_single(struct cmd_context *cmd, struct logical_volume *lv, struct processing_handle *handle); +int online_pvid_file_read(char *path, int *major, int *minor, char *vgname); +int online_pvid_file_create(struct cmd_context *cmd, struct device *dev, const char *vgname, int ignore_existing, int *exists); void online_vg_file_remove(const char *vgname); +int online_pvid_file_exists(const char *pvid); int online_vg_file_create(struct cmd_context *cmd, const char *vgname); void online_dir_setup(struct cmd_context *cmd); +int event_activation_enable(struct cmd_context *cmd); +int event_activation_is_on(struct cmd_context *cmd); #endif 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); diff --git a/udev/69-dm-lvm-metad.rules.in b/udev/69-dm-lvm-metad.rules.in index 78f506520..eda58b868 100644 --- a/udev/69-dm-lvm-metad.rules.in +++ b/udev/69-dm-lvm-metad.rules.in @@ -121,6 +121,6 @@ LABEL="direct_pvscan" # MD | | X | X* | | # loop | | X | X* | | # other | X | | X | | X -RUN+="(LVM_EXEC)/lvm pvscan --background --cache --activate ay --major $major --minor $minor", ENV{LVM_SCANNED}="1" +RUN+="(LVM_EXEC)/lvm pvscan --cache -aay --autoactivation event --major $major --minor $minor", ENV{LVM_SCANNED}="1" LABEL="lvm_end" diff --git a/udev/69-dm-lvm.rules.in b/udev/69-dm-lvm.rules.in index d6bf1e0e9..8f2d4e2f9 100644 --- a/udev/69-dm-lvm.rules.in +++ b/udev/69-dm-lvm.rules.in @@ -78,9 +78,12 @@ ENV{SYSTEMD_READY}="1" # # TODO: adjust the output of vgchange -aay so that # it's better suited to appearing in the journal. +# +# "--autoactivation event" used with pvscan or vgchange +# tells the command that it is being run from an event. -IMPORT{program}="(LVM_EXEC)/lvm pvscan --cache --listvg --checkcomplete --vgonline --udevoutput --journal=output $env{DEVNAME}" -ENV{LVM_VG_NAME_COMPLETE}=="?*", RUN+="/usr/bin/systemd-run -r --no-block --property DefaultDependencies=no --unit lvm-activate-$env{LVM_VG_NAME_COMPLETE} (LVM_EXEC)/lvm vgchange -aay --nohints $env{LVM_VG_NAME_COMPLETE}" +IMPORT{program}="(LVM_EXEC)/lvm pvscan --cache --listvg --checkcomplete --vgonline --autoactivation event --udevoutput --journal=output $env{DEVNAME}" +ENV{LVM_VG_NAME_COMPLETE}=="?*", RUN+="/usr/bin/systemd-run -r --no-block --property DefaultDependencies=no --unit lvm-activate-$env{LVM_VG_NAME_COMPLETE} (LVM_EXEC)/lvm vgchange -aay --autoactivation event $env{LVM_VG_NAME_COMPLETE}" GOTO="lvm_end" LABEL="lvm_end"