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:
parent
baf834f9f6
commit
325a4ea67e
45
configure.ac
45
configure.ac
@ -781,39 +781,6 @@ AC_ARG_WITH(default-run-dir,
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_RUN_DIR, ["$DEFAULT_RUN_DIR"],
|
||||
[Default LVM run directory.])
|
||||
|
||||
################################################################################
|
||||
dnl -- Build cluster mirror log daemon
|
||||
AC_MSG_CHECKING(whether to build cluster mirror log daemon)
|
||||
AC_ARG_ENABLE(cmirrord,
|
||||
AS_HELP_STRING([--enable-cmirrord],
|
||||
[enable the cluster mirror log daemon]),
|
||||
CMIRRORD=$enableval, CMIRRORD=no)
|
||||
AC_MSG_RESULT($CMIRRORD)
|
||||
|
||||
BUILD_CMIRRORD=$CMIRRORD
|
||||
|
||||
################################################################################
|
||||
dnl -- cmirrord pidfile
|
||||
if test "$BUILD_CMIRRORD" = yes; then
|
||||
AC_ARG_WITH(cmirrord-pidfile,
|
||||
AS_HELP_STRING([--with-cmirrord-pidfile=PATH],
|
||||
[cmirrord pidfile [PID_DIR/cmirrord.pid]]),
|
||||
CMIRRORD_PIDFILE=$withval,
|
||||
CMIRRORD_PIDFILE="$DEFAULT_PID_DIR/cmirrord.pid")
|
||||
AC_DEFINE_UNQUOTED(CMIRRORD_PIDFILE, ["$CMIRRORD_PIDFILE"],
|
||||
[Path to cmirrord pidfile.])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Look for corosync libraries if required.
|
||||
if [[ "$BUILD_CMIRRORD" = yes ]]; then
|
||||
pkg_config_init
|
||||
|
||||
if test "$HAVE_CPG" != yes; then
|
||||
PKG_CHECK_MODULES(CPG, libcpg)
|
||||
fi
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Enable debugging
|
||||
AC_MSG_CHECKING(whether to enable debugging)
|
||||
@ -1655,10 +1622,6 @@ fi
|
||||
AC_MSG_CHECKING(whether to enable editline)
|
||||
AC_MSG_RESULT($EDITLINE)
|
||||
|
||||
if test "$BUILD_CMIRRORD" = yes; then
|
||||
AC_CHECK_FUNCS(atexit,,hard_bailout)
|
||||
fi
|
||||
|
||||
if test "$BUILD_LVMLOCKD" = yes; then
|
||||
AS_IF([test "$HAVE_REALTIME" != yes], [AC_MSG_ERROR([Realtime clock support is mandatory for lvmlockd.])])
|
||||
AC_CHECK_FUNCS(strtoull,,hard_bailout)
|
||||
@ -1834,7 +1797,6 @@ AC_ARG_VAR([UDEV_LIBS], [linker flags for udev])
|
||||
################################################################################
|
||||
AC_SUBST(AWK)
|
||||
AC_SUBST(BLKID_PC)
|
||||
AC_SUBST(BUILD_CMIRRORD)
|
||||
AC_SUBST(BUILD_DMEVENTD)
|
||||
AC_SUBST(BUILD_LVMDBUSD)
|
||||
AC_SUBST(BUILD_LVMPOLLD)
|
||||
@ -1967,7 +1929,6 @@ AC_SUBST(WRITE_INSTALL)
|
||||
AC_SUBST(DMEVENTD_PIDFILE)
|
||||
AC_SUBST(LVMPOLLD_PIDFILE)
|
||||
AC_SUBST(LVMLOCKD_PIDFILE)
|
||||
AC_SUBST(CMIRRORD_PIDFILE)
|
||||
AC_SUBST(interface)
|
||||
AC_SUBST(kerneldir)
|
||||
AC_SUBST(missingkernel)
|
||||
@ -1989,7 +1950,6 @@ Makefile
|
||||
make.tmpl
|
||||
libdm/make.tmpl
|
||||
daemons/Makefile
|
||||
daemons/cmirrord/Makefile
|
||||
daemons/dmeventd/Makefile
|
||||
daemons/dmeventd/libdevmapper-event.pc
|
||||
daemons/dmeventd/plugins/Makefile
|
||||
@ -2023,14 +1983,15 @@ libdm/libdevmapper.pc
|
||||
man/Makefile
|
||||
po/Makefile
|
||||
scripts/lvm2-pvscan.service
|
||||
scripts/lvm-activate-vgs-main.service
|
||||
scripts/lvm-activate-vgs-last.service
|
||||
scripts/lvm-devices-wait.service
|
||||
scripts/blkdeactivate.sh
|
||||
scripts/blk_availability_init_red_hat
|
||||
scripts/blk_availability_systemd_red_hat.service
|
||||
scripts/cmirrord_init_red_hat
|
||||
scripts/com.redhat.lvmdbus1.service
|
||||
scripts/dm_event_systemd_red_hat.service
|
||||
scripts/dm_event_systemd_red_hat.socket
|
||||
scripts/lvm2_cmirrord_systemd_red_hat.service
|
||||
scripts/lvm2_lvmdbusd_systemd_red_hat.service
|
||||
scripts/lvm2_lvmpolld_init_red_hat
|
||||
scripts/lvm2_lvmpolld_systemd_red_hat.service
|
||||
|
@ -1121,12 +1121,8 @@ cfg(global_lvdisplay_shows_full_device_path_CFG, "lvdisplay_shows_full_device_pa
|
||||
cfg(global_event_activation_CFG, "event_activation", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 1, vsn(2, 3, 1), 0, 0, NULL,
|
||||
"Activate LVs based on system-generated device events.\n"
|
||||
"When a PV appears on the system, a system-generated uevent triggers\n"
|
||||
"the lvm2-pvscan service which runs the pvscan --cache -aay command.\n"
|
||||
"If the new PV completes a VG, pvscan autoactivates LVs in the VG.\n"
|
||||
"When event_activation is disabled, the lvm2-activation services are\n"
|
||||
"generated and run at fixed points during system startup. These\n"
|
||||
"services run vgchange -aay to autoactivate LVs in VGs that happen\n"
|
||||
"to be present at that point in time.\n"
|
||||
"the pvscan command, and autoactivation when all PVs for a VG are online.\n"
|
||||
"Also see auto_activation_settings.\n"
|
||||
"See the --setautoactivation option or the auto_activation_volume_list\n"
|
||||
"setting to configure autoactivation for specific VGs or LVs.\n")
|
||||
|
||||
@ -1409,6 +1405,21 @@ cfg_array(activation_volume_list_CFG, "volume_list", activation_CFG_SECTION, CFG
|
||||
"volume_list = [ \"vg1\", \"vg2/lvol1\", \"@tag1\", \"@*\" ]\n"
|
||||
"#\n")
|
||||
|
||||
cfg_array(activation_auto_activation_settings_CFG, "auto_activation_settings", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_AUTOACTIVATION_SETTINGS, vsn(2, 3, 14), NULL, 0, NULL,
|
||||
"Configure autoactivation behavior.\n"
|
||||
"service_and_event: use fixed activation services, then switch to event activation\n."
|
||||
"(Only used when event_activation=1.)\n"
|
||||
"event_only: use only event activation\n"
|
||||
"(Only used when event_activation=1.)\n"
|
||||
"service_only: use only fixed activation services\n"
|
||||
"(Effectively the equivalent of event_activation=0.)\n"
|
||||
"pvscan_hints: autoactivation commands will use PVs that\n"
|
||||
"that have been processed by pvscan (from udev rule.)\n"
|
||||
"Without pvscan_hints, pvscan only be used when it is needed\n"
|
||||
"to perform event activation.\n"
|
||||
"Autoactivation commands should set --autoactivation service|event\n"
|
||||
"to indicate if they are performing service or event activation.\n")
|
||||
|
||||
cfg_array(activation_auto_activation_volume_list_CFG, "auto_activation_volume_list", activation_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(2, 2, 97), NULL, 0, NULL,
|
||||
"A list of VGs or LVs that should be autoactivated.\n"
|
||||
"Autoactivation is an activation command run with -aay,\n"
|
||||
|
@ -332,4 +332,8 @@
|
||||
#define VGS_ONLINE_DIR DEFAULT_RUN_DIR "/vgs_online"
|
||||
#define PVS_LOOKUP_DIR DEFAULT_RUN_DIR "/pvs_lookup"
|
||||
|
||||
#define DEFAULT_AUTOACTIVATION_SETTING1 "service_and_event"
|
||||
#define DEFAULT_AUTOACTIVATION_SETTING2 "pvscan_hints"
|
||||
#define DEFAULT_AUTOACTIVATION_SETTINGS "#S" DEFAULT_AUTOACTIVATION_SETTING1 "#S" DEFAULT_AUTOACTIVATION_SETTING2
|
||||
|
||||
#endif /* _LVM_DEFAULTS_H */
|
||||
|
@ -156,6 +156,7 @@
|
||||
#include <sys/file.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);
|
||||
|
||||
static const char *_hints_file = DEFAULT_RUN_DIR "/hints";
|
||||
@ -1406,7 +1407,7 @@ int get_hints(struct cmd_context *cmd, struct dm_list *hints_out, int *newhints,
|
||||
*newhints = NEWHINTS_NONE;
|
||||
|
||||
/* No commands are using hints. */
|
||||
if (!cmd->enable_hints)
|
||||
if (!cmd->enable_hints && !cmd->hints_pvs_online)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
@ -1426,7 +1427,11 @@ int get_hints(struct cmd_context *cmd, struct dm_list *hints_out, int *newhints,
|
||||
if (!cmd->use_hints)
|
||||
return 0;
|
||||
|
||||
/* hints = "pvs_online" */
|
||||
/*
|
||||
* enable_hints is 0 for the special hints=pvs_online
|
||||
* and by lvm.conf hints="none" does not disable hints=pvs_online.
|
||||
* hints=pvs_online can be disabled with --nohints.
|
||||
*/
|
||||
if (cmd->hints_pvs_online) {
|
||||
if (!_get_hints_from_pvs_online(cmd, &hints_list, devs_in, devs_out)) {
|
||||
log_debug("get_hints: pvs_online failed");
|
||||
|
@ -1130,6 +1130,9 @@ int label_scan(struct cmd_context *cmd)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log_debug_devs("Filtering devices to scan done (nodata)");
|
||||
|
||||
cmd->filter_nodata_only = 0;
|
||||
|
||||
dm_list_iterate_items(devl, &all_devs)
|
||||
|
@ -15,9 +15,6 @@ srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
SOURCES = lvm2_activation_generator_systemd_red_hat.c
|
||||
TARGETS = lvm2_activation_generator_systemd_red_hat
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
ifeq ("@BUILD_DMEVENTD@", "yes")
|
||||
@ -66,7 +63,7 @@ install_initscripts:
|
||||
@echo " [INSTALL] initscripts"
|
||||
$(Q) $(INSTALL_DIR) $(initdir)
|
||||
ifeq ("@BUILD_DMEVENTD@", "yes")
|
||||
$(Q) $(INSTALL_SCRIPT) lvm2_monitoring_init_red_hat $(initdir)/lvm2-monitor
|
||||
$(Q) $(INSTALL_SCRIPT) lvm2_monitoring_init_red_hat $(initdir)/lvm-monitor
|
||||
endif
|
||||
ifeq ("@BUILD_LVMPOLLD@", "yes")
|
||||
$(Q) $(INSTALL_SCRIPT) lvm2_lvmpolld_init_red_hat $(initdir)/lvm2-lvmpolld
|
||||
@ -78,24 +75,15 @@ ifeq ("@BLKDEACTIVATE@", "yes")
|
||||
$(Q) $(INSTALL_SCRIPT) blk_availability_init_red_hat $(initdir)/blk-availability
|
||||
endif
|
||||
|
||||
CFLAGS_lvm2_activation_generator_systemd_red_hat.o += $(EXTRA_EXEC_CFLAGS)
|
||||
|
||||
lvm2_activation_generator_systemd_red_hat: $(OBJECTS) $(LVMINTERNAL_LIBS)
|
||||
@echo " [CC] $@"
|
||||
$(Q) $(CC) -o $@ $(OBJECTS) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) $(LVMINTERNAL_LIBS) $(LIBS)
|
||||
|
||||
install_systemd_generators:
|
||||
@echo " [INSTALL] systemd_generators"
|
||||
$(Q) $(INSTALL_DIR) $(systemd_generator_dir)
|
||||
$(Q) $(INSTALL_PROGRAM) lvm2_activation_generator_systemd_red_hat $(systemd_generator_dir)/lvm2-activation-generator
|
||||
|
||||
install_systemd_units: install_dbus_service
|
||||
@echo " [INSTALL] systemd_units"
|
||||
$(Q) $(INSTALL_DIR) $(systemd_unit_dir)
|
||||
$(Q) $(INSTALL_DATA) lvm-activate-vgs-main.service $(systemd_unit_dir)/lvm-activate-vgs-main.service
|
||||
$(Q) $(INSTALL_DATA) lvm-activate-vgs-last.service $(systemd_unit_dir)/lvm-activate-vgs-last.service
|
||||
ifeq ("@BUILD_DMEVENTD@", "yes")
|
||||
$(Q) $(INSTALL_DATA) dm_event_systemd_red_hat.socket $(systemd_unit_dir)/dm-event.socket
|
||||
$(Q) $(INSTALL_DATA) dm_event_systemd_red_hat.service $(systemd_unit_dir)/dm-event.service
|
||||
$(Q) $(INSTALL_DATA) lvm2_monitoring_systemd_red_hat.service $(systemd_unit_dir)/lvm2-monitor.service
|
||||
$(Q) $(INSTALL_DATA) lvm2_monitoring_systemd_red_hat.service $(systemd_unit_dir)/lvm-monitor.service
|
||||
endif
|
||||
ifeq ("@BLKDEACTIVATE@", "yes")
|
||||
$(Q) $(INSTALL_DATA) blk_availability_systemd_red_hat.service $(systemd_unit_dir)/blk-availability.service
|
||||
@ -155,7 +143,9 @@ DISTCLEAN_TARGETS += \
|
||||
lvm2_monitoring_init_red_hat \
|
||||
lvm2_monitoring_systemd_red_hat.service \
|
||||
lvm2_pvscan_systemd_red_hat@.service \
|
||||
lvm2_tmpfiles_red_hat.conf
|
||||
lvm2_tmpfiles_red_hat.conf \
|
||||
lvm-activate-vgs-main.service \
|
||||
lvm-activate-vgs-last.service
|
||||
|
||||
# Remove ancient files
|
||||
DISTCLEAN_TARGETS += \
|
||||
|
@ -1,7 +1,7 @@
|
||||
[Unit]
|
||||
Description=Availability of block devices
|
||||
Before=shutdown.target
|
||||
After=lvm2-activation.service iscsi-shutdown.service iscsi.service iscsid.service fcoe.service rbdmap.service
|
||||
After=lvm-activate-vgs-main.service lvm-activate-vgs-last.service iscsi-shutdown.service iscsi.service iscsid.service fcoe.service rbdmap.service
|
||||
DefaultDependencies=no
|
||||
Conflicts=shutdown.target
|
||||
|
||||
|
24
scripts/lvm-activate-vgs-last.service.in
Normal file
24
scripts/lvm-activate-vgs-last.service.in
Normal 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
|
22
scripts/lvm-activate-vgs-main.service.in
Normal file
22
scripts/lvm-activate-vgs-main.service.in
Normal 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
|
21
scripts/lvm-devices-wait.service.in
Normal file
21
scripts/lvm-devices-wait.service.in
Normal 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
|
||||
|
@ -1,8 +1,8 @@
|
||||
[Unit]
|
||||
Description=Monitoring of LVM2 mirrors, snapshots etc. using dmeventd or progress polling
|
||||
Description=Monitor LVM Logical Volumes
|
||||
Documentation=man:dmeventd(8) man:lvcreate(8) man:lvchange(8) man:vgchange(8)
|
||||
Requires=dm-event.socket
|
||||
After=dm-event.socket dm-event.service lvm2-activation.service
|
||||
After=dm-event.socket dm-event.service lvm-activate-vgs-last.service
|
||||
Before=local-fs-pre.target shutdown.target
|
||||
DefaultDependencies=no
|
||||
Conflicts=shutdown.target
|
||||
|
@ -23,10 +23,10 @@ if [ $1 = 0 ]; then
|
||||
fi
|
||||
|
||||
%triggerun -- %{name} < 2.02.86-2
|
||||
%{_bindir}/systemd-sysv-convert --save lvm2-monitor >/dev/null 2>&1 || :
|
||||
/bin/systemctl --no-reload enable lvm2-monitor.service > /dev/null 2>&1 || :
|
||||
/sbin/chkconfig --del lvm2-monitor > /dev/null 2>&1 || :
|
||||
/bin/systemctl try-restart lvm2-monitor.service > /dev/null 2>&1 || :
|
||||
%{_bindir}/systemd-sysv-convert --save lvm-monitor >/dev/null 2>&1 || :
|
||||
/bin/systemctl --no-reload enable lvm-monitor.service > /dev/null 2>&1 || :
|
||||
/sbin/chkconfig --del lvm-monitor > /dev/null 2>&1 || :
|
||||
/bin/systemctl try-restart lvm-monitor.service > /dev/null 2>&1 || :
|
||||
# files in the main package
|
||||
|
||||
%files
|
||||
@ -100,9 +100,6 @@ fi
|
||||
%{_mandir}/man8/lvm-config.8.gz
|
||||
%{_mandir}/man8/lvm-dumpconfig.8.gz
|
||||
%{_mandir}/man8/lvm.8.gz
|
||||
%if %{enable_systemd}
|
||||
%{_mandir}/man8/lvm2-activation-generator.8.gz
|
||||
%endif
|
||||
%{_mandir}/man8/lvmconfig.8.gz
|
||||
%{_mandir}/man8/lvmdevices.8.gz
|
||||
%{_mandir}/man8/lvmdiskscan.8.gz
|
||||
@ -187,16 +184,17 @@ fi
|
||||
%dir %{_default_run_dir}
|
||||
%if %{enable_systemd}
|
||||
%{_tmpfilesdir}/%{name}.conf
|
||||
%{_unitdir}/lvm-activate-vgs-main.service
|
||||
%{_unitdir}/lvm-activate-vgs-last.service
|
||||
%{_unitdir}/lvm-monitor.service
|
||||
%{_unitdir}/blk-availability.service
|
||||
%{_unitdir}/lvm2-monitor.service
|
||||
%attr(555, -, -) %{_prefix}/lib/systemd/system-generators/lvm2-activation-generator
|
||||
%if %{have_service lvmpolld}
|
||||
%{_unitdir}/lvm2-lvmpolld.service
|
||||
%{_unitdir}/lvm2-lvmpolld.socket
|
||||
%endif
|
||||
%else
|
||||
%{_sysconfdir}/rc.d/init.d/blk-availability
|
||||
%{_sysconfdir}/rc.d/init.d/lvm2-monitor
|
||||
%{_sysconfdir}/rc.d/init.d/lvm-monitor
|
||||
%if %{have_service lvmpolld}
|
||||
%{_sysconfdir}/rc.d/init.d/lvm2-lvmpolld
|
||||
%endif
|
||||
|
@ -87,6 +87,11 @@ arg(atversion_ARG, '\0', "atversion", string_VAL, 0, 0,
|
||||
"which does not contain any newer settings for which LVM would\n"
|
||||
"issue a warning message when checking the configuration.\n")
|
||||
|
||||
arg(autoactivation_ARG, '\0', "autoactivation", string_VAL, 0, 0,
|
||||
"Specify if the command is running autoactivation from an event\n"
|
||||
"or a service. lvm.conf autoactivation_settings determine if\n"
|
||||
"activation commands from services or events are used.\n")
|
||||
|
||||
arg(setautoactivation_ARG, '\0', "setautoactivation", bool_VAL, 0, 0,
|
||||
"Set the autoactivation property on a VG or LV.\n"
|
||||
"Display the property with vgs or lvs \"-o autoactivation\".\n"
|
||||
@ -920,6 +925,10 @@ arg(vgonline_ARG, '\0', "vgonline", 0, 0, 0,
|
||||
"The first command to see a complete VG will report it uniquely.\n"
|
||||
"Other commands to see the complete VG will report it differently.\n")
|
||||
|
||||
arg(wait_ARG, '\0', "wait", string_VAL, 0, 0,
|
||||
"pvsonline: wait for /run/lvm/pvs_online files to exist\n"
|
||||
"for all devices file entries matched to a system device.\n")
|
||||
|
||||
arg(withsummary_ARG, '\0', "withsummary", 0, 0, 0,
|
||||
"Display a one line comment for each configuration node.\n")
|
||||
|
||||
|
@ -1447,6 +1447,10 @@ lvmdevices --delpvid String
|
||||
ID: lvmdevices_edit
|
||||
DESC: Remove the devices file entry for the given PVID.
|
||||
|
||||
lvmdevices --wait String
|
||||
ID: lvmdevices_wait
|
||||
DESC: Wait for matched PV entries to be online.
|
||||
|
||||
---
|
||||
|
||||
lvreduce --size NSizeMB LV
|
||||
@ -1642,14 +1646,15 @@ DESC: Record that a PV is online or offline.
|
||||
|
||||
pvscan --cache_long --activate ay
|
||||
OO: --ignorelockingfailure, --reportformat ReportFmt,
|
||||
--major Number, --minor Number, --noudevsync
|
||||
--major Number, --minor Number, --noudevsync, --autoactivation String
|
||||
OP: PV|String ...
|
||||
IO: --background
|
||||
ID: pvscan_cache
|
||||
DESC: Record that a PV is online and autoactivate the VG if complete.
|
||||
|
||||
pvscan --cache_long --listvg PV
|
||||
OO: --ignorelockingfailure, --checkcomplete, --vgonline, --udevoutput
|
||||
OO: --ignorelockingfailure, --checkcomplete, --vgonline, --udevoutput,
|
||||
--autoactivation String
|
||||
ID: pvscan_cache
|
||||
DESC: Record that a PV is online and list the VG using the PV.
|
||||
|
||||
@ -1747,7 +1752,8 @@ DESC: Start or stop processing LV conversions.
|
||||
|
||||
vgchange --activate Active
|
||||
OO: --activationmode ActivationMode, --ignoreactivationskip, --partial, --sysinit,
|
||||
--readonly, --ignorelockingfailure, --monitor Bool, --poll Bool, --vgonline, OO_VGCHANGE
|
||||
--readonly, --ignorelockingfailure, --monitor Bool, --poll Bool,
|
||||
--vgonline, --autoactivation String, OO_VGCHANGE
|
||||
OP: VG|Tag|Select ...
|
||||
IO: --ignoreskippedcluster
|
||||
ID: vgchange_activate
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
/* coverity[unnecessary_header] needed for MuslC */
|
||||
#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)
|
||||
{
|
||||
@ -119,18 +120,36 @@ static void _search_devs_for_pvids(struct cmd_context *cmd, struct dm_list *sear
|
||||
}
|
||||
}
|
||||
|
||||
static int _all_pvids_online(struct cmd_context *cmd, struct dm_list *wait_pvids)
|
||||
{
|
||||
struct device_id_list *dil, *dil2;
|
||||
int notfound = 0;
|
||||
|
||||
dm_list_iterate_items_safe(dil, dil2, wait_pvids) {
|
||||
if (online_pvid_file_exists(dil->pvid))
|
||||
dm_list_del(&dil->list);
|
||||
else
|
||||
notfound++;
|
||||
}
|
||||
|
||||
return notfound ? 0 : 1;
|
||||
}
|
||||
|
||||
int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
struct dm_list search_pvids;
|
||||
struct dm_list wait_pvids;
|
||||
struct dm_list found_devs;
|
||||
struct device_id_list *dil;
|
||||
struct device_list *devl;
|
||||
struct device *dev;
|
||||
struct dev_use *du, *du2;
|
||||
const char *deviceidtype;
|
||||
time_t begin;
|
||||
int changes = 0;
|
||||
|
||||
dm_list_init(&search_pvids);
|
||||
dm_list_init(&wait_pvids);
|
||||
dm_list_init(&found_devs);
|
||||
|
||||
if (!setup_devices_file(cmd))
|
||||
@ -141,6 +160,9 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (arg_is_set(cmd, wait_ARG))
|
||||
cmd->print_device_id_not_found = 0;
|
||||
|
||||
if (arg_is_set(cmd, update_ARG) ||
|
||||
arg_is_set(cmd, adddev_ARG) || arg_is_set(cmd, deldev_ARG) ||
|
||||
arg_is_set(cmd, addpvid_ARG) || arg_is_set(cmd, delpvid_ARG)) {
|
||||
@ -454,6 +476,62 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (arg_is_set(cmd, wait_ARG)) {
|
||||
if (strcmp("pvsonline", arg_str_value(cmd, wait_ARG, ""))) {
|
||||
log_error("wait option invalid.");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* TODO: lvm.conf lvmdevices_wait_settings "disabled" do nothing */
|
||||
|
||||
/* TODO: lvm.conf auto_activation_settings "event_only" do nothing */
|
||||
|
||||
/* TODO: if no devices file exists, what should this do?
|
||||
do a udev-settle? do nothing and cause more event-based activations? */
|
||||
|
||||
/* for each du, if du->wwid matched, wait for /run/lvm/pvs_online/du->pvid */
|
||||
dm_list_iterate_items(du, &cmd->use_devices) {
|
||||
if (!du->dev)
|
||||
continue;
|
||||
if (!(dil = dm_pool_zalloc(cmd->mem, sizeof(*dil))))
|
||||
continue;
|
||||
dil->dev = du->dev;
|
||||
memcpy(dil->pvid, du->pvid, ID_LEN);
|
||||
dm_list_add(&wait_pvids, &dil->list);
|
||||
}
|
||||
|
||||
log_print("Waiting for PVs online for %u matched devices file entries.", dm_list_size(&wait_pvids));
|
||||
begin = time(NULL);
|
||||
|
||||
while (1) {
|
||||
if (_all_pvids_online(cmd, &wait_pvids)) {
|
||||
log_print("Found all PVs online");
|
||||
goto out;
|
||||
}
|
||||
log_print("Waiting for PVs online for %u devices.", dm_list_size(&wait_pvids));
|
||||
|
||||
/* TODO: lvm.conf lvmdevices_wait_ids "sys_wwid=111", "sys_wwid=222" etc
|
||||
waits for the specifically named devices even if the devices do not exist. */
|
||||
|
||||
/* TODO: lvm.conf lvmdevices_wait_settings "timeout=N" */
|
||||
if (time(NULL) - begin >= 10) {
|
||||
log_print("Time out waiting for PVs online:");
|
||||
dm_list_iterate_items(dil, &wait_pvids)
|
||||
log_print("Need PVID %s on %s", dil->pvid, dev_name(dil->dev));
|
||||
break;
|
||||
}
|
||||
|
||||
if (dm_list_size(&wait_pvids) > 10) {
|
||||
if (interruptible_usleep(1000000)) /* 1 sec */
|
||||
break;
|
||||
} else {
|
||||
if (interruptible_usleep(500000)) /* .5 sec */
|
||||
break;
|
||||
}
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* If no options, print use_devices list */
|
||||
|
||||
dm_list_iterate_items(du, &cmd->use_devices) {
|
||||
|
265
tools/pvscan.c
265
tools/pvscan.c
@ -21,7 +21,19 @@
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
int online_pvid_file_read(char *path, int *major, int *minor, char *vgname);
|
||||
struct aa_settings {
|
||||
/* from lvm.conf */
|
||||
int event_activation;
|
||||
int service_only;
|
||||
int event_only;
|
||||
int service_and_event;
|
||||
int pvscan_hints;
|
||||
|
||||
/* from --eventactivation */
|
||||
int opt_service;
|
||||
int opt_event;
|
||||
int opt_event_enable;
|
||||
};
|
||||
|
||||
struct pvscan_params {
|
||||
int new_pvs_found;
|
||||
@ -48,6 +60,8 @@ static const char *_pvs_online_dir = DEFAULT_RUN_DIR "/pvs_online";
|
||||
static const char *_vgs_online_dir = DEFAULT_RUN_DIR "/vgs_online";
|
||||
static const char *_pvs_lookup_dir = DEFAULT_RUN_DIR "/pvs_lookup";
|
||||
|
||||
static const char *_event_activation_file = DEFAULT_RUN_DIR "/event-activation-on";
|
||||
|
||||
static int _pvscan_display_pv(struct cmd_context *cmd,
|
||||
struct physical_volume *pv,
|
||||
struct pvscan_params *params)
|
||||
@ -181,6 +195,84 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Event based activation
|
||||
* lvm.conf event_activation_options = "event_only"
|
||||
* . all events are used for activation
|
||||
* . no fixed services are used for activation
|
||||
* . lvm.conf event_activation=1 required
|
||||
*
|
||||
* vgchange -aay --eventactivation service
|
||||
* . does nothing
|
||||
* vgchange -aay --eventactivation event
|
||||
* . does activation
|
||||
* pvscan --eventactivation event
|
||||
* . does activation
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* Non-event based activation
|
||||
* lvm.conf event_activation_options = "service_only"
|
||||
* . fixed services are used for activation
|
||||
* . no events are used for activation
|
||||
* . lvm.conf event_activation=0 is equivalent to
|
||||
* event_activation=1 event_activation_options="service_only"
|
||||
*
|
||||
* vgchange -aay --eventactivation service
|
||||
* . does activation
|
||||
* vgchange -aay --eventactivation event
|
||||
* . does nothing
|
||||
* pvscan --eventactivation event
|
||||
* . does nothing
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* Mix of event and non-event based activation
|
||||
* lvm.conf event_activation_options = "service_and_event"
|
||||
* . both services and events are used for activation
|
||||
* . fixed services are used for activation initially,
|
||||
* and last service enables event based activation
|
||||
* by creating the event-activation-on file
|
||||
*
|
||||
* vgchange -aay --eventactivation service
|
||||
* . does activation only if event-activation-on does not exist
|
||||
* vgchange -aay --eventactivation event
|
||||
* . does activation only if event-activation-on exists
|
||||
* vgchange -aay --eventactivation service,on
|
||||
* . does activation only if event-activation-on does not exist
|
||||
* . creates event-activation-on to enable event-based activation
|
||||
* vgchange --eventactivation on|off
|
||||
* . create or remove event-activation-on to enable|disable
|
||||
* event-based activation
|
||||
* pvscan --eventactivation event
|
||||
* . does activation only if event-activation-on exists
|
||||
*
|
||||
*/
|
||||
|
||||
int event_activation_enable(struct cmd_context *cmd)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
if (!(fp = fopen(_event_activation_file, "w")))
|
||||
return_0;
|
||||
if (fclose(fp))
|
||||
stack;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int event_activation_is_on(struct cmd_context *cmd)
|
||||
{
|
||||
struct stat buf;
|
||||
|
||||
if (!stat(_event_activation_file, &buf))
|
||||
return 1;
|
||||
|
||||
if (errno != ENOENT)
|
||||
log_debug("event_activation_is_on errno %d", errno);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Avoid a duplicate pvscan[%d] prefix when logging to the journal.
|
||||
* FIXME: this should probably replace if (udevoutput) with
|
||||
@ -369,7 +461,7 @@ static void _online_files_remove(const char *dirpath)
|
||||
log_sys_debug("closedir", dirpath);
|
||||
}
|
||||
|
||||
static int _online_pvid_file_create(struct cmd_context *cmd, struct device *dev, const char *vgname)
|
||||
int online_pvid_file_create(struct cmd_context *cmd, struct device *dev, const char *vgname, int ignore_existing, int *exists)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
char buf[MAX_PVID_FILE_SIZE] = { 0 };
|
||||
@ -409,8 +501,13 @@ static int _online_pvid_file_create(struct cmd_context *cmd, struct device *dev,
|
||||
|
||||
fd = open(path, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
if (fd < 0) {
|
||||
if (errno == EEXIST)
|
||||
if (errno == EEXIST) {
|
||||
if (exists)
|
||||
*exists = 1;
|
||||
if (ignore_existing)
|
||||
return 1;
|
||||
goto check_duplicate;
|
||||
}
|
||||
log_error_pvscan(cmd, "Failed to create online file for %s path %s error %d", dev_name(dev), path, errno);
|
||||
return 0;
|
||||
}
|
||||
@ -429,7 +526,6 @@ static int _online_pvid_file_create(struct cmd_context *cmd, struct device *dev,
|
||||
}
|
||||
|
||||
/* We don't care about syncing, these files are not even persistent. */
|
||||
|
||||
if (close(fd))
|
||||
log_sys_debug("close", path);
|
||||
|
||||
@ -469,7 +565,7 @@ check_duplicate:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _online_pvid_file_exists(const char *pvid)
|
||||
int online_pvid_file_exists(const char *pvid)
|
||||
{
|
||||
char path[PATH_MAX] = { 0 };
|
||||
struct stat buf;
|
||||
@ -555,7 +651,7 @@ static void _lookup_file_count_pvid_files(FILE *fp, const char *vgname, int *pvs
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_online_pvid_file_exists((const char *)pvid))
|
||||
if (online_pvid_file_exists((const char *)pvid))
|
||||
(*pvs_online)++;
|
||||
else
|
||||
(*pvs_offline)++;
|
||||
@ -727,7 +823,7 @@ static void _count_pvid_files(struct volume_group *vg, int *pvs_online, int *pvs
|
||||
|
||||
dm_list_iterate_items(pvl, &vg->pvs) {
|
||||
memcpy(pvid, &pvl->pv->id.uuid, ID_LEN);
|
||||
if (_online_pvid_file_exists(pvid))
|
||||
if (online_pvid_file_exists(pvid))
|
||||
(*pvs_online)++;
|
||||
else
|
||||
(*pvs_offline)++;
|
||||
@ -750,7 +846,7 @@ static int _pvscan_aa_single(struct cmd_context *cmd, const char *vg_name,
|
||||
|
||||
log_debug("pvscan autoactivating VG %s.", vg_name);
|
||||
|
||||
if (!vgchange_activate(cmd, vg, CHANGE_AAY)) {
|
||||
if (!vgchange_activate(cmd, vg, CHANGE_AAY, 1)) {
|
||||
log_error_pvscan(cmd, "%s: autoactivation failed.", vg->name);
|
||||
pp->activate_errors++;
|
||||
}
|
||||
@ -1038,7 +1134,7 @@ static int _pvscan_aa_quick(struct cmd_context *cmd, struct pvscan_aa_params *pp
|
||||
|
||||
log_debug("pvscan autoactivating VG %s.", vgname);
|
||||
|
||||
if (!vgchange_activate(cmd, vg, CHANGE_AAY)) {
|
||||
if (!vgchange_activate(cmd, vg, CHANGE_AAY, 1)) {
|
||||
log_error_pvscan(cmd, "%s: autoactivation failed.", vg->name);
|
||||
pp->activate_errors++;
|
||||
}
|
||||
@ -1242,7 +1338,7 @@ static void _set_pv_devices_online(struct cmd_context *cmd, struct volume_group
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_online_pvid_file_exists(pvid)) {
|
||||
if (!online_pvid_file_exists(pvid)) {
|
||||
log_debug("set_pv_devices_online vg %s pv %s no online file",
|
||||
vg->name, pvid);
|
||||
pvl->pv->status |= MISSING_PV;
|
||||
@ -1282,7 +1378,7 @@ static void _set_pv_devices_online(struct cmd_context *cmd, struct volume_group
|
||||
}
|
||||
|
||||
static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvscan_devs,
|
||||
int *pv_count, struct dm_list *complete_vgnames)
|
||||
int *pv_count, struct dm_list *complete_vgnames, struct aa_settings *set)
|
||||
{
|
||||
struct device_list *devl, *devl2;
|
||||
struct device *dev;
|
||||
@ -1422,7 +1518,7 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
|
||||
* Create file named for pvid to record this PV is online.
|
||||
* The command creates/checks online files only when --cache is used.
|
||||
*/
|
||||
if (do_cache && !_online_pvid_file_create(cmd, dev, vg ? vg->name : NULL)) {
|
||||
if (do_cache && !online_pvid_file_create(cmd, dev, vg ? vg->name : NULL, 0, NULL)) {
|
||||
log_error_pvscan(cmd, "PV %s failed to create online file.", dev_name(dev));
|
||||
release_vg(vg);
|
||||
ret = 0;
|
||||
@ -1438,6 +1534,20 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* A fixed activation service will create event-activation-on
|
||||
* after which this pvscan will do the steps to trigger
|
||||
* event based activation. We get to this point because the
|
||||
* fixed activation service uses pvscan_hints which requires
|
||||
* this pvscan to create the pvs_online file. The online
|
||||
* file has now been created so the command is done.
|
||||
*/
|
||||
if (set && set->service_and_event && !event_activation_is_on(cmd)) {
|
||||
log_print_pvscan(cmd, "PV %s online before event activation.", dev_name(dev));
|
||||
release_vg(vg);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if all the PVs for this VG are online. If the arrival
|
||||
* of this dev completes the VG, then save the vgname in
|
||||
@ -1660,13 +1770,14 @@ static int _pvscan_cache_all(struct cmd_context *cmd, int argc, char **argv,
|
||||
}
|
||||
dev_iter_destroy(iter);
|
||||
|
||||
_online_devs(cmd, 1, &pvscan_devs, &pv_count, complete_vgnames);
|
||||
_online_devs(cmd, 1, &pvscan_devs, &pv_count, complete_vgnames, NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv,
|
||||
struct dm_list *complete_vgnames)
|
||||
struct dm_list *complete_vgnames,
|
||||
struct aa_settings *settings)
|
||||
{
|
||||
struct dm_list pvscan_args; /* struct pvscan_arg */
|
||||
struct dm_list pvscan_devs; /* struct device_list */
|
||||
@ -1852,7 +1963,7 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv,
|
||||
*/
|
||||
label_scan_devs_cached(cmd, NULL, &pvscan_devs);
|
||||
|
||||
ret = _online_devs(cmd, 0, &pvscan_devs, &pv_count, complete_vgnames);
|
||||
ret = _online_devs(cmd, 0, &pvscan_devs, &pv_count, complete_vgnames, settings);
|
||||
|
||||
/*
|
||||
* When a new PV appears, the system runs pvscan --cache dev.
|
||||
@ -1869,12 +1980,126 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
event_activation=1 service_and_event=1 pvscan_hints=1
|
||||
services, then events
|
||||
pvscan --cache creates pvs_online for all PVs
|
||||
lvm-activate-vgs* used first
|
||||
lvm-activate-<vgname> used later
|
||||
vgchanges use hints=pvs_online from services and events
|
||||
|
||||
event_activation=1 event_only=1 pvscan_hints=1
|
||||
only event activations
|
||||
pvscan --cache creates pvs_online for all PVs
|
||||
lvm-activate-vgs* skipped
|
||||
lvm-activate-<vgname> used
|
||||
vgchanges use hints=pvs_online from events
|
||||
|
||||
event_activation=1 service_only=1 pvscan_hints=1
|
||||
only service activations
|
||||
pvscan --cache creates pvs_online for all PVs
|
||||
lvm-activate-vgs* used first
|
||||
lvm-activate-<vgname> skipped
|
||||
vgchanges use hints=pvs_online from services
|
||||
(pvscan --cache could be skipped after services finish)
|
||||
|
||||
event_activation=1 service_and_event=1 pvscan_hints=0
|
||||
services, then events
|
||||
pvscan --cache skipped in service mode
|
||||
pvscan --cache creates pvs_online in event mode
|
||||
vgchange when enabling event mode must create pvs_online for existing PVs
|
||||
lvm-activate-vgs* used first
|
||||
lvm-activate-<vgname> used later
|
||||
vgchanges scan all PVs from services and events
|
||||
|
||||
event_activation=1 event_only=1 pvscan_hints=0
|
||||
only event activations
|
||||
pvscan --cache creates pvs_online for all PVs
|
||||
lvm-activate-vgs* skipped
|
||||
lvm-activate-<vgname> used
|
||||
vgchanges scan all PVs from events
|
||||
|
||||
event_activation=1 service_only=1 pvscan_hints=0
|
||||
only service activations
|
||||
pvscan --cache always skipped
|
||||
lvm-activate-vgs* used first
|
||||
lvm-activate-<vgname> skipped
|
||||
vgchanges scan all PVs from services
|
||||
|
||||
event_activation=0
|
||||
only service activations
|
||||
ignores service_and_events=1 or events_only=1
|
||||
. for pvscan_hints=1
|
||||
pvscan --cache creates pvs_online for all PVs
|
||||
lvm-activate-vgs* used first
|
||||
lvm-activate-<vgname> skipped
|
||||
vgchanges use hints=pvs_online from services
|
||||
(pvscan --cache could be skipped after services finish)
|
||||
. for pvscan_hints=0
|
||||
pvscan --cache always skipped
|
||||
lvm-activate-vgs* used first
|
||||
lvm-activate-<vgname> skipped
|
||||
vgchanges scan all PVs from services
|
||||
*/
|
||||
|
||||
static int _get_autoactivation(struct cmd_context *cmd,
|
||||
struct aa_settings *set,
|
||||
int *skip_command)
|
||||
{
|
||||
const char *aa_str;
|
||||
|
||||
/*
|
||||
* The lvm.conf settings only apply when the command uses --autoactivation
|
||||
* which says if the command is used for event or service activation.
|
||||
*/
|
||||
if (!(aa_str = arg_str_value(cmd, autoactivation_ARG, NULL)))
|
||||
return 1;
|
||||
|
||||
if (!get_autoactivation_config_settings(cmd, &set->service_only, &set->event_only, &set->service_and_event, &set->pvscan_hints))
|
||||
return 0;
|
||||
|
||||
if (!get_autoactivation_command_options(cmd, aa_str, &set->opt_service, &set->opt_event, &set->opt_event_enable))
|
||||
return 0;
|
||||
|
||||
if (!set->opt_event) {
|
||||
log_print_pvscan(cmd, "Skip pvscan without autoactivation=event.");
|
||||
*skip_command = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!set->event_activation && !set->pvscan_hints) {
|
||||
log_print_pvscan(cmd, "Skip pvscan with event_activation=0.");
|
||||
*skip_command = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (set->service_only && !set->pvscan_hints) {
|
||||
log_print_pvscan(cmd, "Skip pvscan with service_only.");
|
||||
*skip_command = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (set->service_and_event && !set->pvscan_hints && !event_activation_is_on(cmd)) {
|
||||
/*
|
||||
* Note that when vgchange enables events, it needs to compensate for this
|
||||
* skipped pvscan by creating pvs_online files for all existing PVs.
|
||||
*/
|
||||
log_print_pvscan(cmd, "Skip pvscan without event-activation-on.");
|
||||
*skip_command = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
struct pvscan_aa_params pp = { 0 };
|
||||
struct dm_list complete_vgnames;
|
||||
struct aa_settings settings = { 0 };
|
||||
int do_activate = arg_is_set(cmd, activate_ARG);
|
||||
int event_activation;
|
||||
int skip_command = 0;
|
||||
int devno_args = 0;
|
||||
int do_all;
|
||||
int ret;
|
||||
@ -1888,6 +2113,7 @@ int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv)
|
||||
cmd->ignore_device_name_mismatch = 1;
|
||||
|
||||
event_activation = find_config_tree_bool(cmd, global_event_activation_CFG, NULL);
|
||||
settings.event_activation = event_activation;
|
||||
|
||||
if (do_activate && !event_activation) {
|
||||
log_verbose("Ignoring pvscan --cache -aay because event_activation is disabled.");
|
||||
@ -1946,7 +2172,14 @@ int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv)
|
||||
log_verbose("Ignoring pvscan --cache because event_activation is disabled.");
|
||||
return ECMD_PROCESSED;
|
||||
}
|
||||
if (!_pvscan_cache_args(cmd, argc, argv, &complete_vgnames))
|
||||
|
||||
if (!_get_autoactivation(cmd, &settings, &skip_command))
|
||||
return_ECMD_FAILED;
|
||||
|
||||
if (skip_command)
|
||||
return ECMD_PROCESSED;
|
||||
|
||||
if (!_pvscan_cache_args(cmd, argc, argv, &complete_vgnames, &settings))
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
|
@ -5714,3 +5714,96 @@ bad:
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_autoactivation_config_settings(struct cmd_context *cmd,
|
||||
int *service_only, int *event_only, int *service_and_event, int *pvscan_hints)
|
||||
{
|
||||
const struct dm_config_node *cn;
|
||||
const struct dm_config_value *cv;
|
||||
int eo = 0, so = 0, se = 0, ph = 0;
|
||||
|
||||
if (!(cn = find_config_tree_array(cmd, activation_auto_activation_settings_CFG, NULL)))
|
||||
return 1;
|
||||
|
||||
for (cv = cn->v; cv; cv = cv->next) {
|
||||
if (cv->type != DM_CFG_STRING)
|
||||
continue;
|
||||
if (!strcmp(cv->v.str, "service_only"))
|
||||
so = 1;
|
||||
else if (!strcmp(cv->v.str, "event_only"))
|
||||
eo = 1;
|
||||
else if (!strcmp(cv->v.str, "service_and_event"))
|
||||
se = 1;
|
||||
else if (!strcmp(cv->v.str, "pvscan_hints"))
|
||||
ph = 1;
|
||||
else if (strlen(cv->v.str) > 0)
|
||||
log_warn("WARNING: ignoring unrecognized autoactivation_settings value %s.", cv->v.str);
|
||||
}
|
||||
|
||||
if (se && (so || eo)) {
|
||||
log_warn("WARNING: ignoring incompatible autoactivation_settings, using service_and_event.");
|
||||
*service_and_event = 1;
|
||||
} else if (so && eo) {
|
||||
log_warn("WARNING: ignoring incompatible autoactivation_settings, using event_only.");
|
||||
*event_only = 1;
|
||||
} else if (se) {
|
||||
*service_and_event = 1;
|
||||
} else if (so) {
|
||||
*service_only = 1;
|
||||
} else if (eo) {
|
||||
*event_only = 1;
|
||||
} else {
|
||||
*service_and_event = 1;
|
||||
}
|
||||
|
||||
if (ph)
|
||||
*pvscan_hints = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _aa_option_value(const char *val, int *opt_service, int *opt_event, int *opt_event_enable)
|
||||
{
|
||||
if (!strcmp(val, "service"))
|
||||
*opt_service = 1;
|
||||
else if (!strcmp(val, "event"))
|
||||
*opt_event = 1;
|
||||
else if (!strcmp(val, "event_enable"))
|
||||
*opt_event_enable = 1;
|
||||
else {
|
||||
log_error("Unknown --autoactivation value.");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int get_autoactivation_command_options(struct cmd_context *cmd, const char *aa, int *opt_service, int *opt_event, int *opt_event_enable)
|
||||
{
|
||||
char vals[128] = { 0 };
|
||||
char *val1, *val2;
|
||||
|
||||
strncpy(vals, aa, 127);
|
||||
|
||||
/* Currently only two values can be used at once. */
|
||||
|
||||
val1 = vals;
|
||||
|
||||
if ((val2 = strchr(vals, ','))) {
|
||||
*val2 = '\0';
|
||||
val2++;
|
||||
}
|
||||
|
||||
if (val1 && !_aa_option_value(val1, opt_service, opt_event, opt_event_enable))
|
||||
return 0;
|
||||
|
||||
if (val2 && !_aa_option_value(val2, opt_service, opt_event, opt_event_enable))
|
||||
return 0;
|
||||
|
||||
if (*opt_service && *opt_event) {
|
||||
log_error("Invalid --autoactivation options, service and event are incompatible.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -237,4 +237,9 @@ int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
|
||||
int get_lvt_enum(struct logical_volume *lv);
|
||||
|
||||
int get_autoactivation_config_settings(struct cmd_context *cmd, int *service_only,
|
||||
int *event_only, int *service_and_event, int *pvscan_hints);
|
||||
int get_autoactivation_command_options(struct cmd_context *cmd, const char *aa,
|
||||
int *opt_service, int *opt_event, int *opt_event_enable);
|
||||
|
||||
#endif
|
||||
|
@ -226,9 +226,8 @@ int lvconvert_poll(struct cmd_context *cmd, struct logical_volume *lv, unsigned
|
||||
int mirror_remove_missing(struct cmd_context *cmd,
|
||||
struct logical_volume *lv, int force);
|
||||
|
||||
|
||||
int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg,
|
||||
activation_change_t activate);
|
||||
activation_change_t activate, int vg_complete_to_activate);
|
||||
|
||||
int vgchange_background_polling(struct cmd_context *cmd, struct volume_group *vg);
|
||||
|
||||
@ -295,8 +294,13 @@ int lvconvert_cachevol_attach_single(struct cmd_context *cmd,
|
||||
struct logical_volume *lv,
|
||||
struct processing_handle *handle);
|
||||
|
||||
int online_pvid_file_read(char *path, int *major, int *minor, char *vgname);
|
||||
int online_pvid_file_create(struct cmd_context *cmd, struct device *dev, const char *vgname, int ignore_existing, int *exists);
|
||||
void online_vg_file_remove(const char *vgname);
|
||||
int online_pvid_file_exists(const char *pvid);
|
||||
int online_vg_file_create(struct cmd_context *cmd, const char *vgname);
|
||||
void online_dir_setup(struct cmd_context *cmd);
|
||||
int event_activation_enable(struct cmd_context *cmd);
|
||||
int event_activation_is_on(struct cmd_context *cmd);
|
||||
|
||||
#endif
|
||||
|
198
tools/vgchange.c
198
tools/vgchange.c
@ -19,6 +19,7 @@
|
||||
struct vgchange_params {
|
||||
int lock_start_count;
|
||||
unsigned int lock_start_sanlock : 1;
|
||||
unsigned int vg_complete_to_activate : 1;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -194,11 +195,47 @@ int vgchange_background_polling(struct cmd_context *cmd, struct volume_group *vg
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _online_pvid_file_create_all(struct cmd_context *cmd)
|
||||
{
|
||||
struct lvmcache_info *info;
|
||||
struct dev_iter *iter;
|
||||
struct device *dev;
|
||||
const char *vgname;
|
||||
int exists;
|
||||
int exist_count = 0;
|
||||
int create_count = 0;
|
||||
|
||||
if (!(iter = dev_iter_create(NULL, 0)))
|
||||
return 0;
|
||||
while ((dev = dev_iter_get(cmd, iter))) {
|
||||
if (dev->pvid[0] &&
|
||||
(info = lvmcache_info_from_pvid(dev->pvid, dev, 0))) {
|
||||
vgname = lvmcache_vgname_from_info(info);
|
||||
if (vgname && !is_orphan_vg(vgname)) {
|
||||
/*
|
||||
* Ignore exsting pvid file because a pvscan may be creating
|
||||
* the same file as the same time we are, which is expected.
|
||||
*/
|
||||
exists = 0;
|
||||
online_pvid_file_create(cmd, dev, vgname, 1, &exists);
|
||||
if (exists)
|
||||
exist_count++;
|
||||
else
|
||||
create_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
dev_iter_destroy(iter);
|
||||
log_debug("PV online files created %d exist %d", create_count, exist_count);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg,
|
||||
activation_change_t activate)
|
||||
activation_change_t activate, int vg_complete_to_activate)
|
||||
{
|
||||
int lv_open, active, monitored = 0, r = 1;
|
||||
const struct lv_list *lvl;
|
||||
struct pv_list *pvl;
|
||||
int do_activate = is_change_activating(activate);
|
||||
|
||||
/*
|
||||
@ -219,6 +256,20 @@ int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg,
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (arg_is_set(cmd, vgonline_ARG) && !online_vg_file_create(cmd, vg->name)) {
|
||||
log_print("VG %s already online", vg->name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (do_activate && vg_complete_to_activate) {
|
||||
dm_list_iterate_items(pvl, &vg->pvs) {
|
||||
if (!pvl->pv->dev) {
|
||||
log_print("VG %s is incomplete.", vg->name);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Safe, since we never write out new metadata here. Required for
|
||||
* partial activation to work.
|
||||
@ -262,11 +313,6 @@ int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg,
|
||||
}
|
||||
}
|
||||
|
||||
if (arg_is_set(cmd, vgonline_ARG) && !online_vg_file_create(cmd, vg->name)) {
|
||||
log_print("VG %s finished", vg->name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!_activate_lvs_in_vg(cmd, vg, activate)) {
|
||||
stack;
|
||||
r = 0;
|
||||
@ -652,6 +698,7 @@ static int _vgchange_single(struct cmd_context *cmd, const char *vg_name,
|
||||
struct volume_group *vg,
|
||||
struct processing_handle *handle)
|
||||
{
|
||||
struct vgchange_params *vp = (struct vgchange_params *)handle->custom_handle;
|
||||
int ret = ECMD_PROCESSED;
|
||||
unsigned i;
|
||||
activation_change_t activate;
|
||||
@ -709,7 +756,7 @@ static int _vgchange_single(struct cmd_context *cmd, const char *vg_name,
|
||||
|
||||
if (arg_is_set(cmd, activate_ARG)) {
|
||||
activate = (activation_change_t) arg_uint_value(cmd, activate_ARG, 0);
|
||||
if (!vgchange_activate(cmd, vg, activate))
|
||||
if (!vgchange_activate(cmd, vg, activate, vp->vg_complete_to_activate))
|
||||
return_ECMD_FAILED;
|
||||
} else if (arg_is_set(cmd, refresh_ARG)) {
|
||||
/* refreshes the visible LVs (which starts polling) */
|
||||
@ -730,8 +777,123 @@ static int _vgchange_single(struct cmd_context *cmd, const char *vg_name,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _check_autoactivation(struct cmd_context *cmd, struct vgchange_params *vp, int *skip_command, int *enable_events,
|
||||
int *create_pvs_online)
|
||||
{
|
||||
const char *aa;
|
||||
int service_only = 0, event_only = 0, service_and_event = 0, pvscan_hints = 0;
|
||||
int opt_service = 0, opt_event = 0, opt_event_enable = 0;
|
||||
int on_file_exists;
|
||||
int event_activation;
|
||||
|
||||
if (!(aa = arg_str_value(cmd, autoactivation_ARG, NULL))) {
|
||||
log_error("No autoactivation value.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* lvm.conf auto_activation_settings */
|
||||
if (!get_autoactivation_config_settings(cmd, &service_only, &event_only, &service_and_event, &pvscan_hints))
|
||||
return_0;
|
||||
|
||||
/* --autoactivation values */
|
||||
if (!get_autoactivation_command_options(cmd, aa, &opt_service, &opt_event, &opt_event_enable))
|
||||
return_0;
|
||||
|
||||
event_activation = find_config_tree_bool(cmd, global_event_activation_CFG, NULL);
|
||||
|
||||
/*
|
||||
* The combination of lvm.conf event_activation/auto_activation_settings
|
||||
* and the --autoactivation service|event value determines if this
|
||||
* command should do anything or be skipped, along with the existence of
|
||||
* the /run/lvm/event-activation-on file in case of service_and_event.
|
||||
*/
|
||||
if (!event_activation) {
|
||||
if (opt_event) {
|
||||
log_print("Skip vgchange for event and event_activation=0.");
|
||||
*skip_command = 1;
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if (event_only && opt_service) {
|
||||
log_print("Skip vgchange for service and autoactivation_settings event_only.");
|
||||
*skip_command = 1;
|
||||
return 1;
|
||||
}
|
||||
if (service_only && opt_event) {
|
||||
log_print("Skip vgchange for event and autoactivation_settings service_only.");
|
||||
*skip_command = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
on_file_exists = event_activation_is_on(cmd);
|
||||
|
||||
if (service_and_event && opt_service && on_file_exists) {
|
||||
log_print("Skip vgchange for service and event-activation-on.");
|
||||
*skip_command = 1;
|
||||
return 1;
|
||||
}
|
||||
if (service_and_event && opt_event && !on_file_exists) {
|
||||
log_print("Skip vgchange for event and no event-activation-on.");
|
||||
*skip_command = 1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Switch from service activation to event activation when:
|
||||
* lvm.conf event_activation=1,
|
||||
* auto_activation_settings=service_and_event,
|
||||
* and --autoactivation service,event_enable
|
||||
*
|
||||
* When enabling event-based activation, first create the
|
||||
* /run/lvm/event-activation-on file to tell other commands
|
||||
* to begin responding to PV events and doing activation
|
||||
* for newly completed VGs.
|
||||
*
|
||||
* When no pvscan_hints are used, pvscan --cache has not been
|
||||
* creating pvs_online files during service mode, so now
|
||||
* we need to create pvs_online files for all existing PVs
|
||||
* to make up for that.
|
||||
*/
|
||||
if (event_activation && service_and_event && opt_service && opt_event_enable) {
|
||||
if (!event_activation_enable(cmd))
|
||||
log_warn("WARNING: Failed to create event-activation-on.");
|
||||
*enable_events = 1;
|
||||
|
||||
if (!pvscan_hints)
|
||||
*create_pvs_online = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* lvm.conf service_and_event, and vgchange -aay --autoactivation service,
|
||||
* then only activate LVs if the VG is complete.
|
||||
* A later event will complete the VG and activate it.
|
||||
*/
|
||||
if (event_activation && service_and_event && opt_service)
|
||||
vp->vg_complete_to_activate = 1;
|
||||
|
||||
/*
|
||||
* vgchange -aay --autoactivation service, and lvm.conf
|
||||
* autoactivation_settings with pvscan_hints means the vgchange
|
||||
* should use the special hints=pvs_online.
|
||||
* Otherwise, the vgchange uses the equivalent of --nohints.
|
||||
* If --nohints is on the vgchange command line, that overrides
|
||||
* and disables autoactivation_settings pvscan_hints.
|
||||
* hints=pvs_online means the command will only use devices that
|
||||
* have been processed by pvscan --cache (which have a pvid file
|
||||
* created under /run/lvm/pvs_online.)
|
||||
*/
|
||||
if (!arg_is_set(cmd, nohints_ARG) && pvscan_hints)
|
||||
cmd->hints_pvs_online = 1;
|
||||
else
|
||||
cmd->use_hints = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vgchange(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
struct vgchange_params vp = { 0 };
|
||||
struct processing_handle *handle;
|
||||
uint32_t flags = 0;
|
||||
int ret;
|
||||
@ -845,6 +1007,26 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv)
|
||||
cmd->lockd_vg_enforce_sh = 1;
|
||||
}
|
||||
|
||||
if (arg_is_set(cmd, autoactivation_ARG)) {
|
||||
int skip_command = 0, enable_events = 0, create_pvs_online = 0;
|
||||
if (!_check_autoactivation(cmd, &vp, &skip_command, &enable_events, &create_pvs_online))
|
||||
return ECMD_FAILED;
|
||||
if (skip_command)
|
||||
return ECMD_PROCESSED;
|
||||
if (enable_events) {
|
||||
if (!event_activation_enable(cmd))
|
||||
log_warn("WARNING: Failed to create event-activation-on.");
|
||||
if (create_pvs_online) {
|
||||
/* The process_each_vg lock_global/lvmcache_label_scan will be skipped. */
|
||||
if (!lock_global(cmd, "sh"))
|
||||
return ECMD_FAILED;
|
||||
lvmcache_label_scan(cmd);
|
||||
_online_pvid_file_create_all(cmd);
|
||||
flags |= PROCESS_SKIP_SCAN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (update)
|
||||
flags |= READ_FOR_UPDATE;
|
||||
else if (arg_is_set(cmd, activate_ARG))
|
||||
@ -855,6 +1037,8 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv)
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
handle->custom_handle = &vp;
|
||||
|
||||
ret = process_each_vg(cmd, argc, argv, NULL, NULL, flags, 0, handle, &_vgchange_single);
|
||||
|
||||
destroy_processing_handle(cmd, handle);
|
||||
|
@ -121,6 +121,6 @@ LABEL="direct_pvscan"
|
||||
# MD | | X | X* | |
|
||||
# loop | | X | X* | |
|
||||
# other | X | | X | | X
|
||||
RUN+="(LVM_EXEC)/lvm pvscan --background --cache --activate ay --major $major --minor $minor", ENV{LVM_SCANNED}="1"
|
||||
RUN+="(LVM_EXEC)/lvm pvscan --cache -aay --autoactivation event --major $major --minor $minor", ENV{LVM_SCANNED}="1"
|
||||
|
||||
LABEL="lvm_end"
|
||||
|
@ -78,9 +78,12 @@ ENV{SYSTEMD_READY}="1"
|
||||
#
|
||||
# TODO: adjust the output of vgchange -aay so that
|
||||
# it's better suited to appearing in the journal.
|
||||
#
|
||||
# "--autoactivation event" used with pvscan or vgchange
|
||||
# tells the command that it is being run from an event.
|
||||
|
||||
IMPORT{program}="(LVM_EXEC)/lvm pvscan --cache --listvg --checkcomplete --vgonline --udevoutput --journal=output $env{DEVNAME}"
|
||||
ENV{LVM_VG_NAME_COMPLETE}=="?*", RUN+="/usr/bin/systemd-run -r --no-block --property DefaultDependencies=no --unit lvm-activate-$env{LVM_VG_NAME_COMPLETE} (LVM_EXEC)/lvm vgchange -aay --nohints $env{LVM_VG_NAME_COMPLETE}"
|
||||
IMPORT{program}="(LVM_EXEC)/lvm pvscan --cache --listvg --checkcomplete --vgonline --autoactivation event --udevoutput --journal=output $env{DEVNAME}"
|
||||
ENV{LVM_VG_NAME_COMPLETE}=="?*", RUN+="/usr/bin/systemd-run -r --no-block --property DefaultDependencies=no --unit lvm-activate-$env{LVM_VG_NAME_COMPLETE} (LVM_EXEC)/lvm vgchange -aay --autoactivation event $env{LVM_VG_NAME_COMPLETE}"
|
||||
GOTO="lvm_end"
|
||||
|
||||
LABEL="lvm_end"
|
||||
|
Loading…
Reference in New Issue
Block a user