1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-01-06 17:18:29 +03:00

add fixed event activation services

Add two new fixed activation services for startup:
lvm-activate-vgs-main and lvm-activate-vgs-last.

The -main service runs early, without service dependencies.
The -last service runs later, after other services have
started (other services that may set up devices for PVs,
like mulitpathd.)

The lvm-activate-vgs services both run "vgchange -aay"
to activate all VGs that are preset and complete at the
time of system startup.  When there are many VGs, these
two vgchange commands will replace many per-VG vgchange
commands.

The last service enables event activation by creating
the file /run/lvm/event-activation-on.  After that,
new devices that appear will be processed by event based
autoactivation commands.  Prior to the existence of the
event-activation-on file, event-based commands do nothing.

lvm.conf event_activation_options can be used to
configure service-based activation only, or event-based
activation only, or the approach described above which
begins with service based activation and then switches
to event-based.

service_only: only the -main and -last services will
activate VGs.  VGs on devices that appear later will
not be autoactivated.

event_only: the -main and -last services will not
activate any VGs, and all VGs will be activated
from per-VG event-based activation commands.

service_to_event: the -main and -last services will
activate VGs that are complete at the time the
services run, and VGs that appear later will be
activated from per-VG event-based activation
commands.
This commit is contained in:
David Teigland 2021-09-02 16:55:04 -05:00
parent 566d576c09
commit f3c1ce4d35
19 changed files with 498 additions and 93 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,14 @@ 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/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

@ -1130,6 +1130,18 @@ cfg(global_event_activation_CFG, "event_activation", global_CFG_SECTION, CFG_DEF
"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")
cfg_array(global_event_activation_options_CFG, "event_activation_options", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_EVENT_ACTIVATION_OPTIONS, vsn(2, 3, 14), NULL, 0, NULL,
"Set event activation options.\n"
"service_to_event: begin with fixed activation services,\n"
"then switch to event based activation.\n"
"event_only: only use event based activation.\n"
"service_only: only use fixed activation services.\n"
"(This is equivalent to event_activation=0.)\n"
"Autoactivation commands should set --eventactivation service|event\n"
"to indicate if they are performing service or event activation.\n"
"An autoactivation command may then be skipped according to the\n"
"value of this setting.\n")
cfg(global_use_lvmetad_CFG, "use_lvmetad", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 0, vsn(2, 2, 93), 0, vsn(2, 3, 0), NULL, cfg(global_use_lvmetad_CFG, "use_lvmetad", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 0, vsn(2, 2, 93), 0, vsn(2, 3, 0), NULL,
NULL) NULL)

View File

@ -328,4 +328,7 @@
#define DEFAULT_WWIDS_FILE "/etc/multipath/wwids" #define DEFAULT_WWIDS_FILE "/etc/multipath/wwids"
#define DEFAULT_EVENT_ACTIVATION_OPTION1 "service_to_event"
#define DEFAULT_EVENT_ACTIVATION_OPTIONS "#S" DEFAULT_EVENT_ACTIVATION_OPTION1
#endif /* _LVM_DEFAULTS_H */ #endif /* _LVM_DEFAULTS_H */

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,22 @@
[Unit]
Description=Activate LVM Volume Groups (last)
Documentation=man:vgchange(8)
Wants=systemd-udev-settle.service
After=lvm-activate-vgs-main.service systemd-udev-settle.service multipathd.service cryptsetup.target
Before=local-fs-pre.target shutdown.target
DefaultDependencies=no
Conflicts=shutdown.target
# "--eventactivation service" tells vgchange it is being called
# from an activation service, so it will do nothing if
# lvm.conf event_activation_options = "event_only".
# "--eventactivation on" tells vgchange to enable event-based
# pvscan activations by creating /run/lvm/event-activation-on.
[Service]
Type=oneshot
ExecStart=@SBINDIR@/lvm vgchange -aay --nohints --vgonline --eventactivation service,on
RemainAfterExit=yes
[Install]
WantedBy=sysinit.target

View File

@ -0,0 +1,19 @@
[Unit]
Description=Activate LVM Volume Groups
Documentation=man:vgchange(8)
After=dm-event.socket dm-event.service
Before=local-fs-pre.target shutdown.target
DefaultDependencies=no
Conflicts=shutdown.target
# "--eventactivation service" tells vgchange it is being called
# from an activation service, so it will do nothing if
# lvm.conf event_activation_options = "event_only".
[Service]
Type=oneshot
ExecStart=@SBINDIR@/lvm vgchange -aay --nohints --vgonline --eventactivation service
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

@ -278,6 +278,11 @@ arg(errorwhenfull_ARG, '\0', "errorwhenfull", bool_VAL, 0, 0,
"(Also see dm-thin-pool kernel module option no_space_timeout.)\n" "(Also see dm-thin-pool kernel module option no_space_timeout.)\n"
"See \\fBlvmthin\\fP(7) for more information.\n") "See \\fBlvmthin\\fP(7) for more information.\n")
arg(eventactivation_ARG, '\0', "eventactivation", string_VAL, 0, 0,
"Specify if the command is running autoactivation from an event\n"
"or a fixed service. The lvm.conf event_activation_options setting\n"
"determines if event or service based activation commands are used.\n")
arg(force_long_ARG, '\0', "force", 0, ARG_COUNTABLE, 0, arg(force_long_ARG, '\0', "force", 0, ARG_COUNTABLE, 0,
"Force metadata restore even with thin pool LVs.\n" "Force metadata restore even with thin pool LVs.\n"
"Use with extreme caution. Most changes to thin metadata\n" "Use with extreme caution. Most changes to thin metadata\n"

View File

@ -1642,14 +1642,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, --eventactivation 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,
--eventactivation 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 +1748,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, --eventactivation String, OO_VGCHANGE
OP: VG|Tag|Select ... OP: VG|Tag|Select ...
IO: --ignoreskippedcluster IO: --ignoreskippedcluster
ID: vgchange_activate ID: vgchange_activate

View File

@ -46,6 +46,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)
@ -179,6 +181,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_to_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
@ -367,7 +447,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 };
@ -407,8 +487,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;
} }
@ -427,7 +512,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);
@ -748,7 +832,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++;
} }
@ -1036,7 +1120,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++;
} }
@ -1420,7 +1504,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;
@ -1871,6 +1955,7 @@ 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;
const char *ea;
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 devno_args = 0; int devno_args = 0;
@ -1944,6 +2029,36 @@ 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 ((ea = arg_str_value(cmd, eventactivation_ARG, NULL))) {
int service_only = 0, event_only = 0, service_to_event = 0;
int ea_service = 0, ea_event = 0, ea_on = 0;
if (!get_event_activation_config_settings(cmd, &service_only, &event_only, &service_to_event))
return ECMD_FAILED;
if (!get_event_activation_command_options(cmd, ea, &ea_service, &ea_event, &ea_on))
return ECMD_FAILED;
if (ea_event) {
if (!event_activation) {
log_print_pvscan(cmd, "Skip pvscan for event and event_activation=0.");
return ECMD_PROCESSED;
}
if (service_only) {
log_print_pvscan(cmd, "Skip pvscan for event and event_activation_options service_only.");
return ECMD_PROCESSED;
}
if (service_to_event && !event_activation_is_on(cmd)) {
log_print_pvscan(cmd, "Skip pvscan for event and no event-activation-on.");
return ECMD_PROCESSED;
}
} else {
log_error("Option --eventactivation %s is not used by pvscan.", ea);
return ECMD_FAILED;
}
}
if (!_pvscan_cache_args(cmd, argc, argv, &complete_vgnames)) if (!_pvscan_cache_args(cmd, argc, argv, &complete_vgnames))
return ECMD_FAILED; return ECMD_FAILED;
} }

View File

@ -5714,3 +5714,90 @@ bad:
out: out:
return 0; return 0;
} }
int get_event_activation_config_settings(struct cmd_context *cmd,
int *service_only, int *event_only, int *service_to_event)
{
const struct dm_config_node *cn;
const struct dm_config_value *cv;
int eo = 0, so = 0, se = 0;
if (!(cn = find_config_tree_array(cmd, global_event_activation_options_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_to_event"))
se = 1;
else if (strlen(cv->v.str) > 0)
log_warn("WARNING: ignoring unrecognized event_activation_options value %s.", cv->v.str);
}
if (se && (so || eo)) {
log_warn("WARNING: ignoring incompatible event_activation_options, using service_to_event.");
*service_to_event = 1;
} else if (so && eo) {
log_warn("WARNING: ignoring incompatible event_activation_options, using event_only.");
*event_only = 1;
} else if (se) {
*service_to_event = 1;
} else if (so) {
*service_only = 1;
} else if (eo) {
*event_only = 1;
} else {
*service_to_event = 1;
}
return 1;
}
static int _ea_option_value(const char *val, int *ea_service, int *ea_event, int *ea_on)
{
if (!strcmp(val, "service"))
*ea_service = 1;
else if (!strcmp(val, "event"))
*ea_event = 1;
else if (!strcmp(val, "on"))
*ea_on = 1;
else {
log_error("Unknown --eventactivation value.");
return 0;
}
return 1;
}
int get_event_activation_command_options(struct cmd_context *cmd, const char *ea, int *ea_service, int *ea_event, int *ea_on)
{
char ea_vals[128] = {0};
char *val1, *val2;
strncpy(ea_vals, ea, 127);
/* Currently only two values can be used together. */
val1 = ea_vals;
if ((val2 = strchr(ea_vals, ','))) {
*val2 = '\0';
val2++;
}
if (val1 && !_ea_option_value(val1, ea_service, ea_event, ea_on))
return 0;
if (val2 && !_ea_option_value(val2, ea_service, ea_event, ea_on))
return 0;
if (*ea_service && *ea_event) {
log_error("Invalid --eventactivation 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_event_activation_config_settings(struct cmd_context *cmd,
int *service_only, int *event_only, int *service_to_event);
int get_event_activation_command_options(struct cmd_context *cmd,
const char *ea, int *ea_service, int *ea_event, int *ea_on);
#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,11 @@ 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_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_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,113 @@ static int _vgchange_single(struct cmd_context *cmd, const char *vg_name,
return ret; return ret;
} }
static int _check_event_activation(struct cmd_context *cmd, struct vgchange_params *vp, int *skip_command, int *enable_events)
{
const char *ea;
int service_only = 0, event_only = 0, service_to_event = 0;
int ea_service = 0, ea_event = 0, ea_on = 0;
int on_file_exists;
int event_activation;
if (!(ea = arg_str_value(cmd, eventactivation_ARG, NULL))) {
log_error("No eventactivation value.");
return 0;
}
/* lvm.conf event_activation_options */
if (!get_event_activation_config_settings(cmd, &service_only, &event_only, &service_to_event))
return_0;
/* --eventactivation values */
if (!get_event_activation_command_options(cmd, ea, &ea_service, &ea_event, &ea_on))
return_0;
event_activation = find_config_tree_bool(cmd, global_event_activation_CFG, NULL);
/*
* The combination of lvm.conf event_activation/event_activation_options
* and the --eventactivation 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_to_event.
*/
if (!event_activation) {
if (ea_event) {
log_print("Skip vgchange for event and event_activation=0.");
*skip_command = 1;
return 1;
}
} else {
if (event_only && ea_service) {
log_print("Skip vgchange for service and event_activation_options event_only.");
*skip_command = 1;
return 1;
}
if (service_only && ea_event) {
log_print("Skip vgchange for event and event_activation_options service_only.");
*skip_command = 1;
return 1;
}
on_file_exists = event_activation_is_on(cmd);
if (service_to_event && ea_service && on_file_exists) {
log_print("Skip vgchange for service and event-activation-on.");
*skip_command = 1;
return 1;
}
if (service_to_event && ea_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,
* event_activation_options=service_to_event,
* and --eventactivation service,on.
*
* 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. It also needs to create online
* files for existing PVs because some VGs may be incomplete
* at this point, and future pvscan commands need to
* find online files for PVs that have already appeared.
* The label scan provides info to know which PVs are
* present and should have pvid online files created.
*
* process_each_vg() usually begins with lock_global() and
* lvmcache_label_scan(), and then processes each VG.
* In this case, lock_global/lvmcache_label_scan are done
* before calling process_each_vg. This allows a special
* step to be inserted between the label scan and processing
* vgs. That step creates the pvid online files, which
* requires label scan info. The lock_global and
* lvmcache_label_scan will be skipped by process_each_vg
* since they are already done here.
*/
if (event_activation && service_to_event && ea_service && ea_on) {
if (!event_activation_enable(cmd))
log_warn("WARNING: Failed to create event-activation-on.");
*enable_events = 1;
}
/*
* lvm.conf service_to_event, and vgchange -aay --eventactivation service,
* then only activate LVs if the VG is complete.
* A later event will complete the VG and activate it.
*/
if (event_activation && service_to_event && ea_service)
vp->vg_complete_to_activate = 1;
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 +997,24 @@ 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, eventactivation_ARG)) {
int skip_command = 0, enable_events = 0;
if (!_check_event_activation(cmd, &vp, &skip_command, &enable_events))
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.");
/* 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 +1025,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 --eventactivation event --major $major --minor $minor", ENV{LVM_SCANNED}="1"
LABEL="lvm_end" LABEL="lvm_end"

View File

@ -78,9 +78,19 @@ 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.
#
# "--eventactivation event" used with pvscan or vgchange
# tells the command that it is being run from an event.
# The command does nothing if lvm.conf event_activation=0.
# The command does nothing if lvm.conf event_activation=1,
# and lvm.conf event_activation_options="service_only".
# The command goes ahead if event_activation_options="event_only",
# or if event_activation_options="service_to_event" and the
# event-activation-on file exists.
#
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 --eventactivation 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 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 vgchange -aay --nohints --eventactivation event $env{LVM_VG_NAME_COMPLETE}"
GOTO="lvm_end" GOTO="lvm_end"
LABEL="lvm_end" LABEL="lvm_end"