mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-29 15:22:30 +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. If this service quits waiting before all the expected pvid files appear, then the VG associated with those PVs will most likely be activated by the -last service rather than the initial -main service. If those PVs are even slower to complete processing than the -last service, then the VG will be activated by event activation whenever they are finally complete. 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 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 in the -last service enables event activation by creating the /run/lvm/event-activation-on file. Event activation will activate any further VGs that appear on the system (or complete udev processing) after the -last service. In the case of event activation, the udev rule will run vgchange -aay <vgname> via a transient service lvm-activate-<vgname>.service. This vgchange only scans PVs in the VG being activated, also based on the pvs_online files from pvscan. 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
2b7542b40e
commit
bc17139dea
configure.ac
lib
cache
commands
config
device
label
metadata
scripts
Makefile.inblk_availability_systemd_red_hat.service.inlvm-activate-vgs-last.service.inlvm-activate-vgs-main.service.inlvm-devices-wait.service.inlvm2_monitoring_systemd_red_hat.service.in
spec
tools
udev
@ -2023,6 +2023,9 @@ 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
|
||||
|
20
lib/cache/lvmcache.c
vendored
20
lib/cache/lvmcache.c
vendored
@ -2974,3 +2974,23 @@ const char *devname_error_reason(const char *devname)
|
||||
return "device not found";
|
||||
}
|
||||
|
||||
/*
|
||||
* this shouldn't be a function, it has only one small and specific
|
||||
* purpose, but it's necessary because vginfo values can't be seen
|
||||
* outside this file.
|
||||
*/
|
||||
const char *lvmcache_ignore_pv_reason(struct cmd_context *cmd, const char *vgname)
|
||||
{
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
|
||||
if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, NULL)))
|
||||
return NULL;
|
||||
if (is_lockd_type(vginfo->lock_type))
|
||||
return "ignore_shared";
|
||||
if (vginfo->status & EXPORTED_VG)
|
||||
return "ignore_exported";
|
||||
if (!is_system_id_allowed(cmd, vginfo->system_id))
|
||||
return "ignore_foreign";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
2
lib/cache/lvmcache.h
vendored
2
lib/cache/lvmcache.h
vendored
@ -229,4 +229,6 @@ void lvmcache_extra_md_component_checks(struct cmd_context *cmd);
|
||||
|
||||
unsigned int lvmcache_vg_info_count(void);
|
||||
|
||||
const char *lvmcache_ignore_pv_reason(struct cmd_context *cmd, const char *vgname);
|
||||
|
||||
#endif
|
||||
|
@ -174,7 +174,7 @@ struct cmd_context {
|
||||
unsigned activate_component:1; /* command activates component LV */
|
||||
unsigned process_component_lvs:1; /* command processes also component LVs */
|
||||
unsigned mirror_warn_printed:1; /* command already printed warning about non-monitored mirrors */
|
||||
unsigned pvscan_cache_single:1;
|
||||
unsigned expect_missing_vg_device:1; /* when reading a vg it's expected that a dev for a pv isn't found */
|
||||
unsigned can_use_one_scan:1;
|
||||
unsigned is_clvmd:1;
|
||||
unsigned md_component_detection:1;
|
||||
|
@ -257,6 +257,12 @@ cfg(devices_hints_CFG, "hints", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_
|
||||
" Use no hints.\n"
|
||||
"#\n")
|
||||
|
||||
cfg(devices_lvmdevices_wait_seconds_CFG, "lvmdevices_wait_seconds", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_LVMDEVICES_WAIT_SECONDS, vsn(2, 3, 14), NULL, 0, NULL,
|
||||
"The max number of seconds the lvmdevices --wait command will wait.\n"
|
||||
"Set to -1 to use a variable timeout based on the number of devices.\n"
|
||||
"Set to 0 to disable waiting, in which case the command will report\n"
|
||||
"the current status and then exit.\n")
|
||||
|
||||
cfg_array(devices_preferred_names_CFG, "preferred_names", devices_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_UNDEFINED , CFG_TYPE_STRING, NULL, vsn(1, 2, 19), NULL, 0, NULL,
|
||||
"Select which path name to display for a block device.\n"
|
||||
"If multiple path names exist for a block device, and LVM needs to\n"
|
||||
@ -1121,12 +1127,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 +1411,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", activation_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,10 @@
|
||||
#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
|
||||
|
||||
#define DEFAULT_LVMDEVICES_WAIT_SECONDS -1
|
||||
|
||||
#endif /* _LVM_DEFAULTS_H */
|
||||
|
@ -779,8 +779,8 @@ static void _device_ids_update_try(struct cmd_context *cmd)
|
||||
int held = 0;
|
||||
|
||||
/* Defer updates to non-pvscan-cache commands. */
|
||||
if (cmd->pvscan_cache_single) {
|
||||
log_print("pvscan[%d] skip updating devices file.", getpid());
|
||||
if (cmd->expect_missing_vg_device) {
|
||||
log_print("skip updating devices file.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -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";
|
||||
@ -1405,7 +1406,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;
|
||||
|
||||
/*
|
||||
@ -1425,7 +1426,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)
|
||||
|
@ -3558,7 +3558,7 @@ static void _set_pv_device(struct format_instance *fid,
|
||||
if (!id_write_format(&pv->id, buffer, sizeof(buffer)))
|
||||
buffer[0] = '\0';
|
||||
|
||||
if (cmd && !cmd->pvscan_cache_single &&
|
||||
if (cmd && !cmd->expect_missing_vg_device &&
|
||||
(!vg_is_foreign(vg) && !cmd->include_foreign_vgs))
|
||||
log_warn("WARNING: Couldn't find device with uuid %s.", buffer);
|
||||
else
|
||||
@ -5084,7 +5084,7 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name, const
|
||||
if (!pvl->pv->dev) {
|
||||
/* The obvious and common case of a missing device. */
|
||||
|
||||
if (vg_is_foreign(vg) && !cmd->include_foreign_vgs)
|
||||
if ((vg_is_foreign(vg) && !cmd->include_foreign_vgs) || cmd->expect_missing_vg_device)
|
||||
log_debug("VG %s is missing PV %s (last written to %s)", vg_name, uuidstr, pvl->pv->device_hint ?: "na");
|
||||
else if (pvl->pv->device_hint)
|
||||
log_warn("WARNING: VG %s is missing PV %s (last written to %s).", vg_name, uuidstr, pvl->pv->device_hint);
|
||||
|
@ -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 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, 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,38 @@ 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 wait_pvids_count;
|
||||
int wait_sec;
|
||||
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 +162,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)) {
|
||||
@ -457,6 +481,77 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (arg_is_set(cmd, wait_ARG)) {
|
||||
int service_only = 0, event_only = 0, service_and_event = 0, pvscan_hints = 0;
|
||||
|
||||
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? */
|
||||
|
||||
get_autoactivation_config_settings(cmd, &service_only, &event_only, &service_and_event, &pvscan_hints);
|
||||
if (event_only) {
|
||||
log_print("Skip wait for auto_activation_settings event_only.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
wait_pvids_count = dm_list_size(&wait_pvids);
|
||||
wait_sec = find_config_tree_int(cmd, devices_lvmdevices_wait_seconds_CFG, NULL);
|
||||
if (wait_sec == -1) {
|
||||
if (wait_pvids_count <= 20)
|
||||
wait_sec = 1;
|
||||
else if (wait_pvids_count <= 100)
|
||||
wait_sec = 5;
|
||||
else if (wait_pvids_count <= 500)
|
||||
wait_sec = 10;
|
||||
else
|
||||
wait_sec = 20;
|
||||
}
|
||||
log_print("Waiting for PVs online for %u matched devices file entries for %u sec.", wait_pvids_count, wait_sec);
|
||||
|
||||
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. */
|
||||
|
||||
if (!wait_sec || (time(NULL) - begin >= wait_sec)) {
|
||||
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) {
|
||||
|
290
tools/pvscan.c
290
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 --autoactivation */
|
||||
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,80 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Event based activation
|
||||
* lvm.conf auto_activation_settings = "event_only"
|
||||
* . all events are used for activation
|
||||
* . no fixed services are used for activation
|
||||
* . lvm.conf event_activation=1 required
|
||||
*
|
||||
* vgchange -aay --autoactivation service
|
||||
* . does nothing
|
||||
* vgchange -aay --autoactivation event
|
||||
* . does activation
|
||||
* pvscan --autoactivation event
|
||||
* . does activation
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* Non-event based activation
|
||||
* lvm.conf event_activaion=0 or
|
||||
* lvm.conf event_activaion=1 and auto_activation_settings = "service_only"
|
||||
* . fixed services are used for activation
|
||||
* . no events are used for activation
|
||||
*
|
||||
* vgchange -aay --autoactivation service
|
||||
* . does activation
|
||||
* vgchange -aay --autoactivation event
|
||||
* . does nothing
|
||||
* pvscan --autoactivation event
|
||||
* . does not trigger activation
|
||||
* . may still create pvs_online for hints
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* Mix of event and service based activation
|
||||
* lvm.conf auto_activation_settings = "service_and_event"
|
||||
* . both services and events are used for activation
|
||||
* . fixed services are used for activation initially,
|
||||
* and the last service enables event based activation
|
||||
* by creating the event-activation-on file
|
||||
*
|
||||
* vgchange -aay --autoactivation service
|
||||
* . does activation only if event-activation-on does not exist
|
||||
* vgchange -aay --autoactivation event
|
||||
* . does activation only if event-activation-on exists
|
||||
* vgchange -aay --autoactivation service,event_enable
|
||||
* . does activation only if event-activation-on does not exist
|
||||
* . creates event-activation-on to enable event-based activation
|
||||
* pvscan --autoactivation event
|
||||
* . triggers 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 +457,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_file, int *exists, const char *ignore_pv_reason)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
char buf[MAX_PVID_FILE_SIZE] = { 0 };
|
||||
@ -381,6 +469,7 @@ static int _online_pvid_file_create(struct cmd_context *cmd, struct device *dev,
|
||||
int len;
|
||||
int len1 = 0;
|
||||
int len2 = 0;
|
||||
int len3 = 0;
|
||||
|
||||
major = (int)MAJOR(dev->dev);
|
||||
minor = (int)MINOR(dev->dev);
|
||||
@ -403,14 +492,27 @@ static int _online_pvid_file_create(struct cmd_context *cmd, struct device *dev,
|
||||
}
|
||||
}
|
||||
|
||||
len = len1 + len2;
|
||||
if (ignore_pv_reason) {
|
||||
if ((len3 = dm_snprintf(buf + len1 + len2, sizeof(buf) - len1 - len2, "%s\n", ignore_pv_reason)) < 0) {
|
||||
log_print_pvscan(cmd, "Incomplete online file for %s %d:%d %s.", dev_name(dev), major, minor, ignore_pv_reason);
|
||||
/* can still continue */
|
||||
len3 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
len = len1 + len2 + len3;
|
||||
|
||||
log_debug("Create pv online: %s %d:%d %s", path, major, minor, dev_name(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_file)
|
||||
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 +531,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 +570,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 +656,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)++;
|
||||
@ -662,7 +763,7 @@ static int _count_pvid_files_from_lookup_file(struct cmd_context *cmd, struct de
|
||||
return (vgname) ? 1 : 0;
|
||||
}
|
||||
|
||||
static void _online_dir_setup(struct cmd_context *cmd)
|
||||
void online_dir_setup(struct cmd_context *cmd)
|
||||
{
|
||||
struct stat st;
|
||||
int rv;
|
||||
@ -727,7 +828,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 +851,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++;
|
||||
}
|
||||
@ -758,7 +859,7 @@ static int _pvscan_aa_single(struct cmd_context *cmd, const char *vg_name,
|
||||
return ECMD_PROCESSED;
|
||||
}
|
||||
|
||||
static int _online_vg_file_create(struct cmd_context *cmd, const char *vgname)
|
||||
int online_vg_file_create(struct cmd_context *cmd, const char *vgname)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
int fd;
|
||||
@ -1038,7 +1139,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++;
|
||||
}
|
||||
@ -1072,7 +1173,7 @@ static int _pvscan_aa(struct cmd_context *cmd, struct pvscan_aa_params *pp,
|
||||
* to run the activation. The first to create the file will do it.
|
||||
*/
|
||||
dm_list_iterate_items_safe(sl, sl2, vgnames) {
|
||||
if (!_online_vg_file_create(cmd, sl->str)) {
|
||||
if (!online_vg_file_create(cmd, sl->str)) {
|
||||
log_print_pvscan(cmd, "VG %s skip autoactivation.", sl->str);
|
||||
str_list_del(vgnames, sl->str);
|
||||
continue;
|
||||
@ -1242,7 +1343,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 +1383,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;
|
||||
@ -1386,6 +1487,8 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
|
||||
|
||||
if (vg_is_shared(vg)) {
|
||||
log_print_pvscan(cmd, "PV %s ignore shared VG.", dev_name(dev));
|
||||
if (do_cache && !online_pvid_file_create(cmd, dev, vg ? vg->name : NULL, 1, NULL, "ignore_shared"))
|
||||
log_error_pvscan(cmd, "PV %s failed to create online file (ignore_shared).", dev_name(dev));
|
||||
release_vg(vg);
|
||||
continue;
|
||||
}
|
||||
@ -1396,12 +1499,16 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
|
||||
log_verbose("Ignore PV %s with VG system id %s with our system id %s",
|
||||
dev_name(dev), vg->system_id, cmd->system_id);
|
||||
log_print_pvscan(cmd, "PV %s ignore foreign VG.", dev_name(dev));
|
||||
if (do_cache && !online_pvid_file_create(cmd, dev, vg ? vg->name : NULL, 1, NULL, "ignore_foreign"))
|
||||
log_error_pvscan(cmd, "PV %s failed to create online file (ignore_foreign).", dev_name(dev));
|
||||
release_vg(vg);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (vg_is_exported(vg)) {
|
||||
log_print_pvscan(cmd, "PV %s ignore exported VG.", dev_name(dev));
|
||||
if (do_cache && !online_pvid_file_create(cmd, dev, vg ? vg->name : NULL, 1, NULL, "ignore_exported"))
|
||||
log_error_pvscan(cmd, "PV %s failed to create online file (ignore_exported).", dev_name(dev));
|
||||
release_vg(vg);
|
||||
continue;
|
||||
}
|
||||
@ -1422,7 +1529,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, NULL)) {
|
||||
log_error_pvscan(cmd, "PV %s failed to create online file.", dev_name(dev));
|
||||
release_vg(vg);
|
||||
ret = 0;
|
||||
@ -1438,6 +1545,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
|
||||
@ -1507,7 +1628,7 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
|
||||
} else if (!do_check_complete) {
|
||||
log_print("VG %s", vgname);
|
||||
} else if (vg_complete) {
|
||||
if (do_vgonline && !_online_vg_file_create(cmd, vgname)) {
|
||||
if (do_vgonline && !online_vg_file_create(cmd, vgname)) {
|
||||
log_print("VG %s finished", vgname);
|
||||
} else {
|
||||
/*
|
||||
@ -1660,13 +1781,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 */
|
||||
@ -1679,7 +1801,7 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv,
|
||||
dm_list_init(&pvscan_args);
|
||||
dm_list_init(&pvscan_devs);
|
||||
|
||||
cmd->pvscan_cache_single = 1;
|
||||
cmd->expect_missing_vg_device = 1;
|
||||
|
||||
/*
|
||||
* Special pvscan-specific setup steps to avoid looking
|
||||
@ -1852,7 +1974,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 +1991,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 +2124,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.");
|
||||
@ -1935,7 +2172,7 @@ int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv)
|
||||
|
||||
do_all = !argc && !devno_args;
|
||||
|
||||
_online_dir_setup(cmd);
|
||||
online_dir_setup(cmd);
|
||||
|
||||
if (do_all) {
|
||||
if (!_pvscan_cache_all(cmd, argc, argv, &complete_vgnames))
|
||||
@ -1946,7 +2183,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 auto_activation_settings value %s.", cv->v.str);
|
||||
}
|
||||
|
||||
if (se && (so || eo)) {
|
||||
log_warn("WARNING: ignoring incompatible auto_activation_settings, using service_and_event.");
|
||||
*service_and_event = 1;
|
||||
} else if (so && eo) {
|
||||
log_warn("WARNING: ignoring incompatible auto_activation_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,6 +294,14 @@ 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_file, int *exists, const char *ignore_pv_reason);
|
||||
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
|
||||
|
208
tools/vgchange.c
208
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,50 @@ 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)) {
|
||||
/* FIXME: it's dumb for vginfo values to be hidden in lvmcache.c */
|
||||
const char *ignore_pv_reason = lvmcache_ignore_pv_reason(cmd, vgname);
|
||||
|
||||
/*
|
||||
* Ignore an 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, ignore_pv_reason);
|
||||
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 +259,20 @@ int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg,
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
* partial activation to work.
|
||||
@ -647,6 +701,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;
|
||||
@ -699,9 +754,12 @@ static int _vgchange_single(struct cmd_context *cmd, const char *vg_name,
|
||||
log_print_unless_silent("Volume group \"%s\" successfully changed", vg->name);
|
||||
}
|
||||
|
||||
if (arg_is_set(cmd, vgonline_ARG))
|
||||
online_dir_setup(cmd);
|
||||
|
||||
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) */
|
||||
@ -722,8 +780,132 @@ 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 auto_activation_settings event_only.");
|
||||
*skip_command = 1;
|
||||
return 1;
|
||||
}
|
||||
if (service_only && opt_event) {
|
||||
log_print("Skip vgchange for event and auto_activation_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
|
||||
* auto_activation_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 auto_activation_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;
|
||||
|
||||
/*
|
||||
* An activation service will just run "vgchange -aay" and activate
|
||||
* whichever VGs it finds are complete. It's expected that some
|
||||
* VGs may not yet be complete and will be activated later when
|
||||
* more PVs appear, so don't print warnings.
|
||||
*/
|
||||
if (opt_service)
|
||||
cmd->expect_missing_vg_device = 1;
|
||||
|
||||
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;
|
||||
@ -837,6 +1019,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))
|
||||
@ -847,6 +1049,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