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

add fixed event activation services

System startup runs two new fixed activation services:
lvm-activate-vgs-main and lvm-activate-vgs-last

These activate VGs that are present and complete at the
time of system startup.

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
activation.

lvm.conf event_activation_options can be used to
configure service-based activation only, or event-based
activation only, or the default hybrid approach.
This commit is contained in:
David Teigland 2021-09-02 16:55:04 -05:00
parent 240db28214
commit ff0eb5823a
19 changed files with 411 additions and 87 deletions

View File

@ -772,39 +772,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)
@ -1642,10 +1609,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)
@ -1808,7 +1771,6 @@ AC_DEFINE_UNQUOTED(LVM_CONFIGURE_LINE, "$CONFIGURE_LINE", [configure command lin
################################################################################ ################################################################################
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)
@ -1946,7 +1908,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)
@ -1968,7 +1929,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
@ -2002,14 +1962,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

@ -329,4 +329,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

@ -1129,6 +1129,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);
@ -1412,7 +1496,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;
@ -1857,6 +1941,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;
@ -1930,6 +2015,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("Skip pvscan for event and event_activation=0.");
return ECMD_PROCESSED;
}
if (service_only) {
log_print("Skip pvscan for event and event_activation_options service_only.");
return ECMD_PROCESSED;
}
if (service_to_event && !event_activation_is_on(cmd)) {
log_print("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

@ -5829,3 +5829,61 @@ 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;
}
int get_event_activation_command_options(struct cmd_context *cmd, const char *ea, int *ea_service, int *ea_event, int *ea_on)
{
if (strstr(ea, "service"))
*ea_service = 1;
if (strstr(ea, "event"))
*ea_event = 1;
if (strstr(ea, "on"))
*ea_on = 1;
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

@ -295,8 +295,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

@ -194,6 +194,41 @@ 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)
{ {
@ -219,6 +254,11 @@ 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;
}
/* /*
* 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 +302,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;
@ -733,6 +768,7 @@ static int _vgchange_single(struct cmd_context *cmd, const char *vg_name,
int vgchange(struct cmd_context *cmd, int argc, char **argv) int vgchange(struct cmd_context *cmd, int argc, char **argv)
{ {
struct processing_handle *handle; struct processing_handle *handle;
const char *ea;
uint32_t flags = 0; uint32_t flags = 0;
int ret; int ret;
@ -845,6 +881,89 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv)
cmd->lockd_vg_enforce_sh = 1; cmd->lockd_vg_enforce_sh = 1;
} }
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;
int on_file_exists;
int event_activation;
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;
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.");
return ECMD_PROCESSED;
}
} else {
if (event_only && ea_service) {
log_print("Skip vgchange for service and event_activation_options event_only.");
return ECMD_PROCESSED;
}
if (service_only && ea_event) {
log_print("Skip vgchange for event and event_activation_options service_only.");
return ECMD_PROCESSED;
}
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.");
return ECMD_PROCESSED;
}
if (service_to_event && ea_event && !on_file_exists) {
log_print("Skip vgchange for event and no event-activation-on.");
return ECMD_PROCESSED;
}
}
/*
* 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.");
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))

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"