1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

add activation services

New systemd services for startup:

lvm-devices-wait.service
  Used in place of systemd-udev-settle, this service waits
  for udev+pvscan to process PVs listed in system.devices.
  It runs the command "lvmdevices --wait pvsonline".
  This only waits for PVs that can be matched to a device in
  sysfs, so it only waits for devices attached to the system.
  It waits specifically for the /run/lvm/pvs_online/<pvid>
  files to be created by pvscan.  It quits waiting after a
  configurable number of seconds.  This service gives the
  first activation service a chance to activate VGs from
  PVs that are available immediately at startup.

lvm-activate-vgs-main.service
  Calls "vgchange -aay" after lvm-devices-wait to activate
  complete VGs.  It only considers PVs that have been
  processed by udev+pvscan and have pvs_online files.
  This is expected to activate VGs from basic devices
  (not virtual device types) that are present at startup.

lvm-activate-vgs-last.service
  Calls "vgchange -aay" after multipathd has started to
  activate any more VGs that became available after
  virtual device services were started, e.g. VGs on
  multipath devices.  Like -main, it only looks at PVs
  that have been processed by pvscan.
  This vgchange enables event activation by creating
  the /run/lvm/event-activation-on file.  Event-based
  activation will activate any further VGs that appear
  on the system after service (the udev rule will run
  vgchange -aay <vgname> via a transient service
  lvm-activate-<vgname>.service.)

When there are many VGs that need activation during system
startup, the two fixed services can activate them all much
faster than activating each VG individually via events.

lvm.conf auto_activation_settings can be used to configure
the behavior (default ["service_and_event", "pvscan_hints"]).

"service_and_event" - the behavior described above, where
activation services are used first, and event activation
is used afterward.

"service_only" - only lvm-activate-vgs-* are used, and
no event-based activation occurs after the services finish.
(Equivalent to setting lvm.conf event_activation=0.)

"event_only" - the lvm-activate-vgs* services are skipped,
and all VGs are activated individually with event-based
activation.

"pvscan_hints" - the vgchange autoactivation commands
use pvs_online files created by pvscan.  This optimization
limits the devices scanned by the vgchange command to only
PVs that have been processed by pvscan.
This commit is contained in:
David Teigland 2021-09-02 16:55:04 -05:00
parent baf834f9f6
commit 325a4ea67e
22 changed files with 765 additions and 111 deletions

View File

@ -781,39 +781,6 @@ AC_ARG_WITH(default-run-dir,
AC_DEFINE_UNQUOTED(DEFAULT_RUN_DIR, ["$DEFAULT_RUN_DIR"], AC_DEFINE_UNQUOTED(DEFAULT_RUN_DIR, ["$DEFAULT_RUN_DIR"],
[Default LVM run directory.]) [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 dnl -- Enable debugging
AC_MSG_CHECKING(whether to enable debugging) AC_MSG_CHECKING(whether to enable debugging)
@ -1655,10 +1622,6 @@ fi
AC_MSG_CHECKING(whether to enable editline) AC_MSG_CHECKING(whether to enable editline)
AC_MSG_RESULT($EDITLINE) AC_MSG_RESULT($EDITLINE)
if test "$BUILD_CMIRRORD" = yes; then
AC_CHECK_FUNCS(atexit,,hard_bailout)
fi
if test "$BUILD_LVMLOCKD" = yes; then if test "$BUILD_LVMLOCKD" = yes; then
AS_IF([test "$HAVE_REALTIME" != yes], [AC_MSG_ERROR([Realtime clock support is mandatory for lvmlockd.])]) AS_IF([test "$HAVE_REALTIME" != yes], [AC_MSG_ERROR([Realtime clock support is mandatory for lvmlockd.])])
AC_CHECK_FUNCS(strtoull,,hard_bailout) AC_CHECK_FUNCS(strtoull,,hard_bailout)
@ -1834,7 +1797,6 @@ AC_ARG_VAR([UDEV_LIBS], [linker flags for udev])
################################################################################ ################################################################################
AC_SUBST(AWK) AC_SUBST(AWK)
AC_SUBST(BLKID_PC) AC_SUBST(BLKID_PC)
AC_SUBST(BUILD_CMIRRORD)
AC_SUBST(BUILD_DMEVENTD) AC_SUBST(BUILD_DMEVENTD)
AC_SUBST(BUILD_LVMDBUSD) AC_SUBST(BUILD_LVMDBUSD)
AC_SUBST(BUILD_LVMPOLLD) AC_SUBST(BUILD_LVMPOLLD)
@ -1967,7 +1929,6 @@ AC_SUBST(WRITE_INSTALL)
AC_SUBST(DMEVENTD_PIDFILE) AC_SUBST(DMEVENTD_PIDFILE)
AC_SUBST(LVMPOLLD_PIDFILE) AC_SUBST(LVMPOLLD_PIDFILE)
AC_SUBST(LVMLOCKD_PIDFILE) AC_SUBST(LVMLOCKD_PIDFILE)
AC_SUBST(CMIRRORD_PIDFILE)
AC_SUBST(interface) AC_SUBST(interface)
AC_SUBST(kerneldir) AC_SUBST(kerneldir)
AC_SUBST(missingkernel) AC_SUBST(missingkernel)
@ -1989,7 +1950,6 @@ Makefile
make.tmpl make.tmpl
libdm/make.tmpl libdm/make.tmpl
daemons/Makefile daemons/Makefile
daemons/cmirrord/Makefile
daemons/dmeventd/Makefile daemons/dmeventd/Makefile
daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/libdevmapper-event.pc
daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/Makefile
@ -2023,14 +1983,15 @@ libdm/libdevmapper.pc
man/Makefile man/Makefile
po/Makefile po/Makefile
scripts/lvm2-pvscan.service 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/blkdeactivate.sh
scripts/blk_availability_init_red_hat scripts/blk_availability_init_red_hat
scripts/blk_availability_systemd_red_hat.service scripts/blk_availability_systemd_red_hat.service
scripts/cmirrord_init_red_hat
scripts/com.redhat.lvmdbus1.service scripts/com.redhat.lvmdbus1.service
scripts/dm_event_systemd_red_hat.service scripts/dm_event_systemd_red_hat.service
scripts/dm_event_systemd_red_hat.socket scripts/dm_event_systemd_red_hat.socket
scripts/lvm2_cmirrord_systemd_red_hat.service
scripts/lvm2_lvmdbusd_systemd_red_hat.service scripts/lvm2_lvmdbusd_systemd_red_hat.service
scripts/lvm2_lvmpolld_init_red_hat scripts/lvm2_lvmpolld_init_red_hat
scripts/lvm2_lvmpolld_systemd_red_hat.service scripts/lvm2_lvmpolld_systemd_red_hat.service

View File

@ -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, 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" "Activate LVs based on system-generated device events.\n"
"When a PV appears on the system, a system-generated uevent triggers\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" "the pvscan command, and autoactivation when all PVs for a VG are online.\n"
"If the new PV completes a VG, pvscan autoactivates LVs in the VG.\n" "Also see auto_activation_settings.\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"
"See the --setautoactivation option or the auto_activation_volume_list\n" "See the --setautoactivation option or the auto_activation_volume_list\n"
"setting to configure autoactivation for specific VGs or LVs.\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" "volume_list = [ \"vg1\", \"vg2/lvol1\", \"@tag1\", \"@*\" ]\n"
"#\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, 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" "A list of VGs or LVs that should be autoactivated.\n"
"Autoactivation is an activation command run with -aay,\n" "Autoactivation is an activation command run with -aay,\n"

View File

@ -332,4 +332,8 @@
#define VGS_ONLINE_DIR DEFAULT_RUN_DIR "/vgs_online" #define VGS_ONLINE_DIR DEFAULT_RUN_DIR "/vgs_online"
#define PVS_LOOKUP_DIR DEFAULT_RUN_DIR "/pvs_lookup" #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 */ #endif /* _LVM_DEFAULTS_H */

View File

@ -156,6 +156,7 @@
#include <sys/file.h> #include <sys/file.h>
#include <sys/sysmacros.h> #include <sys/sysmacros.h>
/* FIXME: move online pv functions to pvs_online.c */
int online_pvid_file_read(char *path, int *major, int *minor, char *vgname); int online_pvid_file_read(char *path, int *major, int *minor, char *vgname);
static const char *_hints_file = DEFAULT_RUN_DIR "/hints"; 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; *newhints = NEWHINTS_NONE;
/* No commands are using hints. */ /* No commands are using hints. */
if (!cmd->enable_hints) if (!cmd->enable_hints && !cmd->hints_pvs_online)
return 0; return 0;
/* /*
@ -1426,7 +1427,11 @@ int get_hints(struct cmd_context *cmd, struct dm_list *hints_out, int *newhints,
if (!cmd->use_hints) if (!cmd->use_hints)
return 0; 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 (cmd->hints_pvs_online) {
if (!_get_hints_from_pvs_online(cmd, &hints_list, devs_in, devs_out)) { if (!_get_hints_from_pvs_online(cmd, &hints_list, devs_in, devs_out)) {
log_debug("get_hints: pvs_online failed"); log_debug("get_hints: pvs_online failed");

View File

@ -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; cmd->filter_nodata_only = 0;
dm_list_iterate_items(devl, &all_devs) dm_list_iterate_items(devl, &all_devs)

View File

@ -15,9 +15,6 @@ srcdir = @srcdir@
top_srcdir = @top_srcdir@ top_srcdir = @top_srcdir@
top_builddir = @top_builddir@ top_builddir = @top_builddir@
SOURCES = lvm2_activation_generator_systemd_red_hat.c
TARGETS = lvm2_activation_generator_systemd_red_hat
include $(top_builddir)/make.tmpl include $(top_builddir)/make.tmpl
ifeq ("@BUILD_DMEVENTD@", "yes") ifeq ("@BUILD_DMEVENTD@", "yes")
@ -66,7 +63,7 @@ install_initscripts:
@echo " [INSTALL] initscripts" @echo " [INSTALL] initscripts"
$(Q) $(INSTALL_DIR) $(initdir) $(Q) $(INSTALL_DIR) $(initdir)
ifeq ("@BUILD_DMEVENTD@", "yes") 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 endif
ifeq ("@BUILD_LVMPOLLD@", "yes") ifeq ("@BUILD_LVMPOLLD@", "yes")
$(Q) $(INSTALL_SCRIPT) lvm2_lvmpolld_init_red_hat $(initdir)/lvm2-lvmpolld $(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 $(Q) $(INSTALL_SCRIPT) blk_availability_init_red_hat $(initdir)/blk-availability
endif 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 install_systemd_units: install_dbus_service
@echo " [INSTALL] systemd_units" @echo " [INSTALL] systemd_units"
$(Q) $(INSTALL_DIR) $(systemd_unit_dir) $(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") 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.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) 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 endif
ifeq ("@BLKDEACTIVATE@", "yes") ifeq ("@BLKDEACTIVATE@", "yes")
$(Q) $(INSTALL_DATA) blk_availability_systemd_red_hat.service $(systemd_unit_dir)/blk-availability.service $(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_init_red_hat \
lvm2_monitoring_systemd_red_hat.service \ lvm2_monitoring_systemd_red_hat.service \
lvm2_pvscan_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 # Remove ancient files
DISTCLEAN_TARGETS += \ DISTCLEAN_TARGETS += \

View File

@ -1,7 +1,7 @@
[Unit] [Unit]
Description=Availability of block devices Description=Availability of block devices
Before=shutdown.target 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 DefaultDependencies=no
Conflicts=shutdown.target Conflicts=shutdown.target

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,8 +1,8 @@
[Unit] [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) Documentation=man:dmeventd(8) man:lvcreate(8) man:lvchange(8) man:vgchange(8)
Requires=dm-event.socket 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 Before=local-fs-pre.target shutdown.target
DefaultDependencies=no DefaultDependencies=no
Conflicts=shutdown.target Conflicts=shutdown.target

View File

@ -23,10 +23,10 @@ if [ $1 = 0 ]; then
fi fi
%triggerun -- %{name} < 2.02.86-2 %triggerun -- %{name} < 2.02.86-2
%{_bindir}/systemd-sysv-convert --save lvm2-monitor >/dev/null 2>&1 || : %{_bindir}/systemd-sysv-convert --save lvm-monitor >/dev/null 2>&1 || :
/bin/systemctl --no-reload enable lvm2-monitor.service > /dev/null 2>&1 || : /bin/systemctl --no-reload enable lvm-monitor.service > /dev/null 2>&1 || :
/sbin/chkconfig --del lvm2-monitor > /dev/null 2>&1 || : /sbin/chkconfig --del lvm-monitor > /dev/null 2>&1 || :
/bin/systemctl try-restart lvm2-monitor.service > /dev/null 2>&1 || : /bin/systemctl try-restart lvm-monitor.service > /dev/null 2>&1 || :
# files in the main package # files in the main package
%files %files
@ -100,9 +100,6 @@ fi
%{_mandir}/man8/lvm-config.8.gz %{_mandir}/man8/lvm-config.8.gz
%{_mandir}/man8/lvm-dumpconfig.8.gz %{_mandir}/man8/lvm-dumpconfig.8.gz
%{_mandir}/man8/lvm.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/lvmconfig.8.gz
%{_mandir}/man8/lvmdevices.8.gz %{_mandir}/man8/lvmdevices.8.gz
%{_mandir}/man8/lvmdiskscan.8.gz %{_mandir}/man8/lvmdiskscan.8.gz
@ -187,16 +184,17 @@ fi
%dir %{_default_run_dir} %dir %{_default_run_dir}
%if %{enable_systemd} %if %{enable_systemd}
%{_tmpfilesdir}/%{name}.conf %{_tmpfilesdir}/%{name}.conf
%{_unitdir}/lvm-activate-vgs-main.service
%{_unitdir}/lvm-activate-vgs-last.service
%{_unitdir}/lvm-monitor.service
%{_unitdir}/blk-availability.service %{_unitdir}/blk-availability.service
%{_unitdir}/lvm2-monitor.service
%attr(555, -, -) %{_prefix}/lib/systemd/system-generators/lvm2-activation-generator
%if %{have_service lvmpolld} %if %{have_service lvmpolld}
%{_unitdir}/lvm2-lvmpolld.service %{_unitdir}/lvm2-lvmpolld.service
%{_unitdir}/lvm2-lvmpolld.socket %{_unitdir}/lvm2-lvmpolld.socket
%endif %endif
%else %else
%{_sysconfdir}/rc.d/init.d/blk-availability %{_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} %if %{have_service lvmpolld}
%{_sysconfdir}/rc.d/init.d/lvm2-lvmpolld %{_sysconfdir}/rc.d/init.d/lvm2-lvmpolld
%endif %endif

View File

@ -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" "which does not contain any newer settings for which LVM would\n"
"issue a warning message when checking the configuration.\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, arg(setautoactivation_ARG, '\0', "setautoactivation", bool_VAL, 0, 0,
"Set the autoactivation property on a VG or LV.\n" "Set the autoactivation property on a VG or LV.\n"
"Display the property with vgs or lvs \"-o autoactivation\".\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" "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") "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, arg(withsummary_ARG, '\0', "withsummary", 0, 0, 0,
"Display a one line comment for each configuration node.\n") "Display a one line comment for each configuration node.\n")

View File

@ -1447,6 +1447,10 @@ lvmdevices --delpvid String
ID: lvmdevices_edit ID: lvmdevices_edit
DESC: Remove the devices file entry for the given PVID. 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 lvreduce --size NSizeMB LV
@ -1642,14 +1646,15 @@ DESC: Record that a PV is online or offline.
pvscan --cache_long --activate ay pvscan --cache_long --activate ay
OO: --ignorelockingfailure, --reportformat ReportFmt, OO: --ignorelockingfailure, --reportformat ReportFmt,
--major Number, --minor Number, --noudevsync --major Number, --minor Number, --noudevsync, --autoactivation String
OP: PV|String ... OP: PV|String ...
IO: --background IO: --background
ID: pvscan_cache ID: pvscan_cache
DESC: Record that a PV is online and autoactivate the VG if complete. DESC: Record that a PV is online and autoactivate the VG if complete.
pvscan --cache_long --listvg PV pvscan --cache_long --listvg PV
OO: --ignorelockingfailure, --checkcomplete, --vgonline, --udevoutput OO: --ignorelockingfailure, --checkcomplete, --vgonline, --udevoutput,
--autoactivation String
ID: pvscan_cache ID: pvscan_cache
DESC: Record that a PV is online and list the VG using the PV. 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 vgchange --activate Active
OO: --activationmode ActivationMode, --ignoreactivationskip, --partial, --sysinit, 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 ... OP: VG|Tag|Select ...
IO: --ignoreskippedcluster IO: --ignoreskippedcluster
ID: vgchange_activate ID: vgchange_activate

View File

@ -19,6 +19,7 @@
/* coverity[unnecessary_header] needed for MuslC */ /* coverity[unnecessary_header] needed for MuslC */
#include <sys/file.h> #include <sys/file.h>
#include <time.h>
static void _search_devs_for_pvids(struct cmd_context *cmd, struct dm_list *search_pvids, struct dm_list *found_devs) 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) int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
{ {
struct dm_list search_pvids; struct dm_list search_pvids;
struct dm_list wait_pvids;
struct dm_list found_devs; struct dm_list found_devs;
struct device_id_list *dil; struct device_id_list *dil;
struct device_list *devl; struct device_list *devl;
struct device *dev; struct device *dev;
struct dev_use *du, *du2; struct dev_use *du, *du2;
const char *deviceidtype; const char *deviceidtype;
time_t begin;
int changes = 0; int changes = 0;
dm_list_init(&search_pvids); dm_list_init(&search_pvids);
dm_list_init(&wait_pvids);
dm_list_init(&found_devs); dm_list_init(&found_devs);
if (!setup_devices_file(cmd)) if (!setup_devices_file(cmd))
@ -141,6 +160,9 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED; return ECMD_FAILED;
} }
if (arg_is_set(cmd, wait_ARG))
cmd->print_device_id_not_found = 0;
if (arg_is_set(cmd, update_ARG) || if (arg_is_set(cmd, update_ARG) ||
arg_is_set(cmd, adddev_ARG) || arg_is_set(cmd, deldev_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)) { 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; 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 */ /* If no options, print use_devices list */
dm_list_iterate_items(du, &cmd->use_devices) { dm_list_iterate_items(du, &cmd->use_devices) {

View File

@ -21,7 +21,19 @@
#include <dirent.h> #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 { struct pvscan_params {
int new_pvs_found; 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 *_vgs_online_dir = DEFAULT_RUN_DIR "/vgs_online";
static const char *_pvs_lookup_dir = DEFAULT_RUN_DIR "/pvs_lookup"; 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, static int _pvscan_display_pv(struct cmd_context *cmd,
struct physical_volume *pv, struct physical_volume *pv,
struct pvscan_params *params) struct pvscan_params *params)
@ -181,6 +195,84 @@ out:
return ret; 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. * Avoid a duplicate pvscan[%d] prefix when logging to the journal.
* FIXME: this should probably replace if (udevoutput) with * 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); 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 path[PATH_MAX];
char buf[MAX_PVID_FILE_SIZE] = { 0 }; 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); fd = open(path, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR);
if (fd < 0) { if (fd < 0) {
if (errno == EEXIST) if (errno == EEXIST) {
if (exists)
*exists = 1;
if (ignore_existing)
return 1;
goto check_duplicate; goto check_duplicate;
}
log_error_pvscan(cmd, "Failed to create online file for %s path %s error %d", dev_name(dev), path, errno); log_error_pvscan(cmd, "Failed to create online file for %s path %s error %d", dev_name(dev), path, errno);
return 0; 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. */ /* We don't care about syncing, these files are not even persistent. */
if (close(fd)) if (close(fd))
log_sys_debug("close", path); log_sys_debug("close", path);
@ -469,7 +565,7 @@ check_duplicate:
return 0; return 0;
} }
static int _online_pvid_file_exists(const char *pvid) int online_pvid_file_exists(const char *pvid)
{ {
char path[PATH_MAX] = { 0 }; char path[PATH_MAX] = { 0 };
struct stat buf; struct stat buf;
@ -555,7 +651,7 @@ static void _lookup_file_count_pvid_files(FILE *fp, const char *vgname, int *pvs
continue; continue;
} }
if (_online_pvid_file_exists((const char *)pvid)) if (online_pvid_file_exists((const char *)pvid))
(*pvs_online)++; (*pvs_online)++;
else else
(*pvs_offline)++; (*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) { dm_list_iterate_items(pvl, &vg->pvs) {
memcpy(pvid, &pvl->pv->id.uuid, ID_LEN); memcpy(pvid, &pvl->pv->id.uuid, ID_LEN);
if (_online_pvid_file_exists(pvid)) if (online_pvid_file_exists(pvid))
(*pvs_online)++; (*pvs_online)++;
else else
(*pvs_offline)++; (*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); 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); log_error_pvscan(cmd, "%s: autoactivation failed.", vg->name);
pp->activate_errors++; 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); 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); log_error_pvscan(cmd, "%s: autoactivation failed.", vg->name);
pp->activate_errors++; pp->activate_errors++;
} }
@ -1242,7 +1338,7 @@ static void _set_pv_devices_online(struct cmd_context *cmd, struct volume_group
continue; 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", log_debug("set_pv_devices_online vg %s pv %s no online file",
vg->name, pvid); vg->name, pvid);
pvl->pv->status |= MISSING_PV; 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, 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_list *devl, *devl2;
struct device *dev; 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. * Create file named for pvid to record this PV is online.
* The command creates/checks online files only when --cache is used. * 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)); log_error_pvscan(cmd, "PV %s failed to create online file.", dev_name(dev));
release_vg(vg); release_vg(vg);
ret = 0; ret = 0;
@ -1438,6 +1534,20 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
continue; 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 * Check if all the PVs for this VG are online. If the arrival
* of this dev completes the VG, then save the vgname in * 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); 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; return 1;
} }
static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv, 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_args; /* struct pvscan_arg */
struct dm_list pvscan_devs; /* struct device_list */ 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); 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. * 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; 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) int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv)
{ {
struct pvscan_aa_params pp = { 0 }; struct pvscan_aa_params pp = { 0 };
struct dm_list complete_vgnames; struct dm_list complete_vgnames;
struct aa_settings settings = { 0 };
int do_activate = arg_is_set(cmd, activate_ARG); int do_activate = arg_is_set(cmd, activate_ARG);
int event_activation; int event_activation;
int skip_command = 0;
int devno_args = 0; int devno_args = 0;
int do_all; int do_all;
int ret; int ret;
@ -1888,6 +2113,7 @@ int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv)
cmd->ignore_device_name_mismatch = 1; cmd->ignore_device_name_mismatch = 1;
event_activation = find_config_tree_bool(cmd, global_event_activation_CFG, NULL); event_activation = find_config_tree_bool(cmd, global_event_activation_CFG, NULL);
settings.event_activation = event_activation;
if (do_activate && !event_activation) { if (do_activate && !event_activation) {
log_verbose("Ignoring pvscan --cache -aay because event_activation is disabled."); 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."); log_verbose("Ignoring pvscan --cache because event_activation is disabled.");
return ECMD_PROCESSED; 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; return ECMD_FAILED;
} }

View File

@ -5714,3 +5714,96 @@ bad:
out: out:
return 0; 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;
}

View File

@ -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_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 #endif

View File

@ -226,9 +226,8 @@ int lvconvert_poll(struct cmd_context *cmd, struct logical_volume *lv, unsigned
int mirror_remove_missing(struct cmd_context *cmd, int mirror_remove_missing(struct cmd_context *cmd,
struct logical_volume *lv, int force); struct logical_volume *lv, int force);
int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg, 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); 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 logical_volume *lv,
struct processing_handle *handle); 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); 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); int online_vg_file_create(struct cmd_context *cmd, const char *vgname);
void online_dir_setup(struct cmd_context *cmd); 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 #endif

View File

@ -19,6 +19,7 @@
struct vgchange_params { struct vgchange_params {
int lock_start_count; int lock_start_count;
unsigned int lock_start_sanlock : 1; 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; 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, 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; int lv_open, active, monitored = 0, r = 1;
const struct lv_list *lvl; const struct lv_list *lvl;
struct pv_list *pvl;
int do_activate = is_change_activating(activate); int do_activate = is_change_activating(activate);
/* /*
@ -219,6 +256,20 @@ int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg,
return 1; 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 * Safe, since we never write out new metadata here. Required for
* partial activation to work. * 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)) { if (!_activate_lvs_in_vg(cmd, vg, activate)) {
stack; stack;
r = 0; r = 0;
@ -652,6 +698,7 @@ static int _vgchange_single(struct cmd_context *cmd, const char *vg_name,
struct volume_group *vg, struct volume_group *vg,
struct processing_handle *handle) struct processing_handle *handle)
{ {
struct vgchange_params *vp = (struct vgchange_params *)handle->custom_handle;
int ret = ECMD_PROCESSED; int ret = ECMD_PROCESSED;
unsigned i; unsigned i;
activation_change_t activate; 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)) { if (arg_is_set(cmd, activate_ARG)) {
activate = (activation_change_t) arg_uint_value(cmd, activate_ARG, 0); 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; return_ECMD_FAILED;
} else if (arg_is_set(cmd, refresh_ARG)) { } else if (arg_is_set(cmd, refresh_ARG)) {
/* refreshes the visible LVs (which starts polling) */ /* 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; 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) int vgchange(struct cmd_context *cmd, int argc, char **argv)
{ {
struct vgchange_params vp = { 0 };
struct processing_handle *handle; struct processing_handle *handle;
uint32_t flags = 0; uint32_t flags = 0;
int ret; int ret;
@ -845,6 +1007,26 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv)
cmd->lockd_vg_enforce_sh = 1; 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) if (update)
flags |= READ_FOR_UPDATE; flags |= READ_FOR_UPDATE;
else if (arg_is_set(cmd, activate_ARG)) 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; return ECMD_FAILED;
} }
handle->custom_handle = &vp;
ret = process_each_vg(cmd, argc, argv, NULL, NULL, flags, 0, handle, &_vgchange_single); ret = process_each_vg(cmd, argc, argv, NULL, NULL, flags, 0, handle, &_vgchange_single);
destroy_processing_handle(cmd, handle); destroy_processing_handle(cmd, handle);

View File

@ -121,6 +121,6 @@ LABEL="direct_pvscan"
# MD | | X | X* | | # MD | | X | X* | |
# loop | | X | X* | | # loop | | X | X* | |
# other | X | | 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" LABEL="lvm_end"

View File

@ -78,9 +78,12 @@ ENV{SYSTEMD_READY}="1"
# #
# TODO: adjust the output of vgchange -aay so that # TODO: adjust the output of vgchange -aay so that
# it's better suited to appearing in the journal. # 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}" 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 --nohints $env{LVM_VG_NAME_COMPLETE}" 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" GOTO="lvm_end"
LABEL="lvm_end" LABEL="lvm_end"