1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-11-12 16:23:50 +03:00

Compare commits

..

34 Commits

Author SHA1 Message Date
David Teigland
5d0c7685f9 test rhel5 sysfs 2021-11-08 15:41:39 -06:00
David Teigland
024ce50f06 vgchange -aay: improve unexpected command variations
For completeness and consistency, adjust the behavior
for some variations of:

  vgchange -aay --autoactivation event [vgname]

The current standard use is with a VG name arg, and the
command is only called when all pvs_online files exist.
This is the optimal case, in which only pvs_online devs
are read.  This remains the same.

Clean up behaviors for some other unexpected uses of the
command:

. With no VG name arg, the command activates any VGs
  that are complete according to pvs_online.  If no
  pvs_online files exist, it does nothing.

. If a VG name is used but no PVs online files exist for
  the VG, or the PVs online files are incomplete, then
  consider there could be a problem with the pvs_online
  files, and fall back to a full label scan prior to
  attempting the activation.
2021-11-08 15:19:25 -06:00
David Teigland
14b68ea313 vgchange -aay: fall back to dev_cache_scan if optimization fails
Part of the optimization to avoid a full dev_cache_scan requires
translating major:minor numbers to a device name.  If this devno
translation fails, then fall back to doing a full dev_cache_scan
which is slower but certain to provide the info.  This preserves
the most important part of the label scanning optimization in the
vgchange aay (avoiding dev_cache_scan is a relatively small part
of the optimized activation compared to label scanning.)
2021-11-05 17:07:13 -05:00
David Teigland
b4067e84c7 fix device name from devno for partitions
sysfs files for partitions are different from
whole devices and will require more work to translate
to device names.
2021-11-05 16:21:23 -05:00
David Teigland
62533ae3fa vgchange -aay: optimize device list using pvs_online files
Port another optimization from pvscan -aay to vgchange -aay:
  "pvscan: only add device args to dev cache"

This optimization avoids doing a full dev_cache_scan, and
instead populates dev-cache with only the devices in the
VG being activated.

This involves shifting the use of pvs_online files from
the hints interface up to the higher level label_scan
interface.  This specialized label_scan is structured
around creating a list of devices from the pvs_online
files.  Previously, a list of all devices was created
first, and then reduced based on the pvs_online files.
The initial step of listing all devices was slow when
thousands of devices are present on the system.

This optimization extends the previous optimization that
used pvs_online files to limit the devices that were
actually scanned (i.e. reading to identify the device):
  "vgchange -aay: optimize device scan using pvs_online files"
2021-11-05 12:19:35 -05:00
David Teigland
5f7cb97743 lvm2-pvscan: include --autoactivation event
in the pvscan --cache -aay command so that the use
of the command for event activation is explicit.
2021-11-04 14:14:37 -05:00
David Teigland
f40fd88374 move code from pvscan.c to online.c
related to managing files in /run/lvm/pvs_online
and /run/lvm/vgs_online
2021-11-04 11:09:29 -05:00
David Teigland
d558b3ad7e vgchange -aay: optimize device scan using pvs_online files
Port the old pvscan -aay scanning optimization to vgchange -aay.
The optimization uses pvs_online files created by pvscan --cache
to derive a list of devices to use when activating a VG.  This
allows autoactivation of a VG to avoid scanning all devices, and
only scan the devices used by the VG itself.  The optimization is
applied internally using the device hints interface.

The new option "--autoactivation event" is given to pvscan and
vgchange commands that are called by event activation.  This
informs the command that it is being used for event activation,
so that it can apply checks and optimizations that are specific
to event activation.  Those include:

- skipping the command if lvm.conf event_activation=0
- checking that a VG is complete before activating it
- using pvs_online files to limit device scanning
2021-11-04 11:08:38 -05:00
David Teigland
594f6ca970 rename pvscan_cache_single to expect_missing_vg_device in cmd 2021-11-04 11:08:38 -05:00
David Teigland
726dd25969 add hints interface to the pvs_online file information
The information in /run/lvm/pvs_online/<pvid> files can
be used to build a list of devices for a given VG.

The pvscan -aay command has long used this information to
activate a VG while scanning only devices in that VG, which
is an important optimization for autoactivation.

This patch implements the same thing through the existing
device hints interface, so that the optimization can be
applied elsewhere.  A future patch will take advantage of
this optimization in vgchange -aay, which is now used in
place of pvscan -aay for event activation.
2021-11-04 10:58:16 -05:00
David Teigland
6ea8d975b2 lvmdevices: increase open file limit 2021-11-03 08:50:57 -05:00
David Teigland
b5b0369e4d filter-sysfs: skip when device id is set
When a device id is set for a device, using an idtype other
than devname, it means that sysfs has been used with the device
to match the device id.  So, checking for a sysfs entry for the
device in filter-sysfs is redundant.  For any other cases not
covered by this (e.g. devname ids), have filter-sysfs simply
stat /sys/dev/block/major:minor to test if the device exists
in sysfs.

The extensive processing done by filter-sysfs init is removed.
It was taking an immense amount of time with many devices, e.g.
. 1024 PVs in 520 VGs
. 520 concurrent vgchange -ay <vgname> commands
. vgchange scans only PVs in the named VG (based on pvs_online
  files from a pending patch)

A large number of the vgchange commands were taking over 1 min,
and nearly half of that time was used by filter-sysfs init.
With this patch, the vgchange commands take about half the time.
2021-11-02 16:54:53 -05:00
David Teigland
5d0964d127 hints: remove the cmd hints list
which is no longer used after commit
"toollib: remove all devices list from process_each_pv"
2021-11-01 16:01:45 -05:00
David Teigland
b65a2c3f3a vgimportdevices: skip lvmlockd locking
Help bootstrapping existing shared vgs into the devices file.
Reading the vg in vgimportdevices would require locking to be
started, but vgchange lockstart won't see the vg if it's not
in the devices file.  The lvmlockd locks are not protecting
vg modifications so skipping them here won't be a problem.
2021-10-25 12:11:17 -05:00
Christian Hesse
221e75316f The path is known anyway and should be the bullet proof option.
Signed-off-by: Christian Hesse <mail@eworm.de>
2021-10-21 16:33:23 -05:00
David Teigland
ae355ffc3f pvscan: fix messages from coverity changes 2021-10-20 16:12:55 -05:00
Marian Csontos
819a35cc91 post-release 2021-10-20 11:13:28 +02:00
Marian Csontos
ef4521831d pre-release 2021-10-20 11:12:39 +02:00
Marian Csontos
36be4d68f6 WHATS_NEW: update 2021-10-20 11:10:37 +02:00
David Teigland
33e47182f7 pvscan: only add device args to dev cache
Optimize the common pvscan --cache command by only adding
the necessary devs to dev-cache.
2021-10-19 17:13:57 -05:00
Zdenek Kabelac
60dc44b707 dev-cache: enhance dir scan also for non-udev build 2021-10-18 21:50:56 +02:00
Zdenek Kabelac
88e0d68909 dev-cache: better detection of filesystem
It appear on some systems the first found dev might not be actually for
the filesytem - so use a better way through _cache.st_dev.
2021-10-18 21:16:53 +02:00
Zdenek Kabelac
c60bac4661 configure: update 2021-10-18 19:17:27 +02:00
Zdenek Kabelac
1b104ddb55 configure.ac: remove unused part
As we are not using 'enable-compat' for anything, remove this section.
Also remove duplicated check for blkid.
Move setting of some AC_ARG_ENABLE defaults into the macro so it's always
defined.
2021-10-18 19:17:27 +02:00
Zdenek Kabelac
a172a02a9a cleanup: use const char buffer 2021-10-18 19:17:27 +02:00
Zdenek Kabelac
9cf4eac250 dev-cache: skip different filesystems on dir scan
When scanning configured  /dev dir, avoid entring
directories with different filesystem.

This minimizes risk we will block on i.e. entring
directory with mount point.
2021-10-18 19:17:26 +02:00
Zdenek Kabelac
bae1083472 cov: check device_ids_write return code
At least 'stack' failure code path as the
function device_id_update_vg_uuid() is void.
2021-10-15 23:40:56 +02:00
Zdenek Kabelac
c2be6c38d5 cov: ensure id is always initialize
Always resed sd_id128_t id and report warning in case
sd_id128_get_machine_app_specific() does not exit with 0.
2021-10-15 23:40:56 +02:00
Zdenek Kabelac
882141eb8c cov: check pointer before dereferencing
Check pv2 is non-null before trying to deref its tags.
2021-10-15 23:40:56 +02:00
Zdenek Kabelac
65ba4964df cov: do not drop already known error state
Do not try to 'discover' another error state, when ENOMEM
is already detected.
2021-10-15 23:40:56 +02:00
Zdenek Kabelac
e7b5f490c5 cov: ignore close result 2021-10-15 23:40:29 +02:00
Zdenek Kabelac
6668d6409a cov: validate subcommand existance
Before dereference of subcommand pointer, check it's not NULL
as  coverity believes there exists theoretical path for this...
2021-10-15 23:39:25 +02:00
Zdenek Kabelac
2779830a06 cov: avoid using NULL info
Check lvmcache info exists before calling lvmcache_del_save_bad_mda().
2021-10-15 23:36:22 +02:00
Zdenek Kabelac
8aefd97252 configure: fix use of withval
Newly added option --with-default-use-devices-file needs to use withval.
2021-10-15 23:35:05 +02:00
54 changed files with 1287 additions and 1387 deletions

View File

@@ -1 +1 @@
2.03.14(2)-git (2021-08-11)
2.03.15(2)-git (2021-10-20)

View File

@@ -1 +1 @@
1.02.181-git (2021-08-11)
1.02.183-git (2021-10-20)

View File

@@ -1,5 +1,9 @@
Version 2.03.14 -
==================================
Version 2.03.15 -
===================================
Version 2.03.14 - 20th October 2021
===================================
Device scanning is skipping directories on different filesystems.
Print info message with too many or too large archived files.
Reduce metadata readings during scanning phase.
Optimize computation of crc32 check sum with multiple PVs.
@@ -7,7 +11,7 @@ Version 2.03.14 -
Filter out unsupported MQ/SMQ cache policy setting.
Fix memleak in mpath filter.
Support newer location for VDO statistics.
Add support for VDO async-unsage write policy.
Add support for VDO async-unsafe write policy.
Improve lvm_import_vdo script.
Support VDO LV with lvcreate -ky.
Fix lvconvert for VDO LV bigger then 2T.

View File

@@ -1,5 +1,8 @@
Version 1.02.181 -
===================================
Version 1.02.183 -
====================================
Version 1.02.181 - 20th October 2021
====================================
Add IMA support with 'dmsetup measure' command.
Add defines DM_NAME_LIST_FLAG_HAS_UUID, DM_NAME_LIST_FLAG_DOESNT_HAVE_UUID.
Enhance tracking of activated devices when preloading dm tree.

117
configure vendored
View File

@@ -773,10 +773,10 @@ PYTHON
LVM2CMD_LIB
UDEV_LIBS
UDEV_CFLAGS
SYSTEMD_LIBS
SYSTEMD_CFLAGS
BLKID_LIBS
BLKID_CFLAGS
SYSTEMD_LIBS
SYSTEMD_CFLAGS
LOCKD_IDM_LIBS
LOCKD_IDM_CFLAGS
LOCKD_DLM_CONTROL_LIBS
@@ -964,7 +964,6 @@ enable_udev_systemd_background_jobs
enable_udev_sync
enable_udev_rules
enable_udev_rule_exec_detection
enable_compat
enable_units_compat
enable_ioctl
enable_o_direct
@@ -1029,10 +1028,10 @@ LOCKD_DLM_CONTROL_CFLAGS
LOCKD_DLM_CONTROL_LIBS
LOCKD_IDM_CFLAGS
LOCKD_IDM_LIBS
BLKID_CFLAGS
BLKID_LIBS
SYSTEMD_CFLAGS
SYSTEMD_LIBS
BLKID_CFLAGS
BLKID_LIBS
UDEV_CFLAGS
UDEV_LIBS
PYTHON
@@ -1705,7 +1704,6 @@ Optional Features:
--enable-udev_rules install rule files needed for udev synchronisation
--enable-udev-rule-exec-detection
enable executable path detection in udev rules
--enable-compat enable support for old device-mapper versions
--enable-units-compat enable output compatibility with old versions that
that do not use KiB-style unit suffixes
--disable-ioctl disable ioctl calls to device-mapper in the kernel
@@ -1853,13 +1851,13 @@ Some influential environment variables:
C compiler flags for LOCKD_IDM, overriding pkg-config
LOCKD_IDM_LIBS
linker flags for LOCKD_IDM, overriding pkg-config
BLKID_CFLAGS
C compiler flags for BLKID, overriding pkg-config
BLKID_LIBS linker flags for BLKID, overriding pkg-config
SYSTEMD_CFLAGS
C compiler flags for SYSTEMD, overriding pkg-config
SYSTEMD_LIBS
linker flags for SYSTEMD, overriding pkg-config
BLKID_CFLAGS
C compiler flags for BLKID, overriding pkg-config
BLKID_LIBS linker flags for BLKID, overriding pkg-config
UDEV_CFLAGS C compiler flags for UDEV, overriding pkg-config
UDEV_LIBS linker flags for UDEV, overriding pkg-config
PYTHON the Python interpreter
@@ -3142,10 +3140,6 @@ case "$host_os" in
LIB_SUFFIX=so
DEVMAPPER=yes
BUILD_LVMPOLLD=no
LOCKDSANLOCK=no
LOCKDDLM=no
LOCKDDLM_CONTROL=no
LOCKDIDM=no
ODIRECT=yes
DM_IOCTLS=yes
SELINUX=yes
@@ -8467,7 +8461,7 @@ $as_echo_n "checking default for use_devicesfile... " >&6; }
# Check whether --with-default-use-devices-file was given.
if test "${with_default_use_devices_file+set}" = set; then :
withval=$with_default_use_devices_file; DEFAULT_USE_DEVICES_FILE=$enableval
withval=$with_default_use_devices_file; DEFAULT_USE_DEVICES_FILE=$withval
else
DEFAULT_USE_DEVICES_FILE=0
fi
@@ -11001,6 +10995,8 @@ $as_echo_n "checking whether to build lvmpolld... " >&6; }
# Check whether --enable-lvmpolld was given.
if test "${enable_lvmpolld+set}" = set; then :
enableval=$enable_lvmpolld; LVMPOLLD=$enableval
else
LVMPOLLD=no
fi
test -n "$LVMPOLLD" && BUILD_LVMPOLLD=$LVMPOLLD
@@ -11015,6 +11011,8 @@ $as_echo_n "checking whether to build lvmlockdsanlock... " >&6; }
# Check whether --enable-lvmlockd-sanlock was given.
if test "${enable_lvmlockd_sanlock+set}" = set; then :
enableval=$enable_lvmlockd_sanlock; LOCKDSANLOCK=$enableval
else
LOCKDSANLOCK=no
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $LOCKDSANLOCK" >&5
@@ -11106,6 +11104,8 @@ $as_echo_n "checking whether to build lvmlockddlm... " >&6; }
# Check whether --enable-lvmlockd-dlm was given.
if test "${enable_lvmlockd_dlm+set}" = set; then :
enableval=$enable_lvmlockd_dlm; LOCKDDLM=$enableval
else
LOCKDDLM=no
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $LOCKDDLM" >&5
@@ -11197,6 +11197,8 @@ $as_echo_n "checking whether to build lvmlockddlmcontrol... " >&6; }
# Check whether --enable-lvmlockd-dlmcontrol was given.
if test "${enable_lvmlockd_dlmcontrol+set}" = set; then :
enableval=$enable_lvmlockd_dlmcontrol; LOCKDDLM_CONTROL=$enableval
else
LOCKDDLM_CONTROL=no
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $LOCKDDLM_CONTROL" >&5
@@ -11288,6 +11290,8 @@ $as_echo_n "checking whether to build lvmlockdidm... " >&6; }
# Check whether --enable-lvmlockd-idm was given.
if test "${enable_lvmlockd_idm+set}" = set; then :
enableval=$enable_lvmlockd_idm; LOCKDIDM=$enableval
else
LOCKDIDM=no
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $LOCKDIDM" >&5
@@ -11367,76 +11371,15 @@ else
$as_echo "yes" >&6; }
HAVE_LOCKD_IDM=yes
fi
pkg_failed=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BLKID" >&5
$as_echo_n "checking for BLKID... " >&6; }
if test -n "$BLKID_CFLAGS"; then
pkg_cv_BLKID_CFLAGS="$BLKID_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"blkid >= 2.24\""; } >&5
($PKG_CONFIG --exists --print-errors "blkid >= 2.24") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_BLKID_CFLAGS=`$PKG_CONFIG --cflags "blkid >= 2.24" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
HAVE_LOCKD_IDM=yes
else
pkg_failed=yes
fi
else
pkg_failed=untried
fi
if test -n "$BLKID_LIBS"; then
pkg_cv_BLKID_LIBS="$BLKID_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"blkid >= 2.24\""; } >&5
($PKG_CONFIG --exists --print-errors "blkid >= 2.24") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_BLKID_LIBS=`$PKG_CONFIG --libs "blkid >= 2.24" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
else
pkg_failed=untried
fi
if test $pkg_failed = yes; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
BLKID_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "blkid >= 2.24" 2>&1`
else
BLKID_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "blkid >= 2.24" 2>&1`
fi
# Put the nasty error message in config.log where it belongs
echo "$BLKID_PKG_ERRORS" >&5
$bailout
elif test $pkg_failed = untried; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
$bailout
else
BLKID_CFLAGS=$pkg_cv_BLKID_CFLAGS
BLKID_LIBS=$pkg_cv_BLKID_LIBS
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
HAVE_LOCKD_IDM=yes
$bailout
fi
$as_echo "#define LOCKDIDM_SUPPORT 1" >>confdefs.h
@@ -12086,24 +12029,6 @@ $as_echo_n "checking whether udev supports built-in blkid... " >&6; }
$as_echo "$UDEV_HAS_BUILTIN_BLKID" >&6; }
fi
################################################################################
# Check whether --enable-compat was given.
if test "${enable_compat+set}" = set; then :
enableval=$enable_compat; DM_COMPAT=$enableval
else
DM_COMPAT=no
fi
if test "$DM_COMPAT" = yes; then :
$as_echo "#define DM_COMPAT 1" >>confdefs.h
as_fn_error $? "--enable-compat is not currently supported.
Since device-mapper version 1.02.66, only one version (4) of the device-mapper
ioctl protocol is supported." "$LINENO" 5
fi
################################################################################
# Check whether --enable-units-compat was given.
if test "${enable_units_compat+set}" = set; then :

View File

@@ -38,10 +38,6 @@ case "$host_os" in
LIB_SUFFIX=so
DEVMAPPER=yes
BUILD_LVMPOLLD=no
LOCKDSANLOCK=no
LOCKDDLM=no
LOCKDDLM_CONTROL=no
LOCKDIDM=no
ODIRECT=yes
DM_IOCTLS=yes
SELINUX=yes
@@ -290,7 +286,7 @@ dnl -- Default settings for lvm.conf { devices/use_devicesfile }
AC_MSG_CHECKING(default for use_devicesfile)
AC_ARG_WITH(default-use-devices-file,
AS_HELP_STRING([--with-default-use-devices-file], [default for lvm.conf devices/use_devicesfile = [0]]),
DEFAULT_USE_DEVICES_FILE=$enableval, DEFAULT_USE_DEVICES_FILE=0)
DEFAULT_USE_DEVICES_FILE=$withval, DEFAULT_USE_DEVICES_FILE=0)
case "$DEFAULT_USE_DEVICES_FILE" in
0|1);;
*) AC_MSG_ERROR([--with-default-use-devices-file parameter invalid]);;
@@ -785,6 +781,39 @@ 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)
@@ -913,7 +942,7 @@ AC_MSG_CHECKING(whether to build lvmpolld)
AC_ARG_ENABLE(lvmpolld,
AS_HELP_STRING([--enable-lvmpolld],
[enable the LVM Polling Daemon]),
LVMPOLLD=$enableval)
LVMPOLLD=$enableval, LVMPOLLD=no)
test -n "$LVMPOLLD" && BUILD_LVMPOLLD=$LVMPOLLD
AC_MSG_RESULT($BUILD_LVMPOLLD)
@@ -925,7 +954,7 @@ AC_MSG_CHECKING(whether to build lvmlockdsanlock)
AC_ARG_ENABLE(lvmlockd-sanlock,
AS_HELP_STRING([--enable-lvmlockd-sanlock],
[enable the LVM lock daemon using sanlock]),
LOCKDSANLOCK=$enableval)
LOCKDSANLOCK=$enableval, LOCKDSANLOCK=no)
AC_MSG_RESULT($LOCKDSANLOCK)
BUILD_LOCKDSANLOCK=$LOCKDSANLOCK
@@ -943,7 +972,7 @@ AC_MSG_CHECKING(whether to build lvmlockddlm)
AC_ARG_ENABLE(lvmlockd-dlm,
AS_HELP_STRING([--enable-lvmlockd-dlm],
[enable the LVM lock daemon using dlm]),
LOCKDDLM=$enableval)
LOCKDDLM=$enableval, LOCKDDLM=no)
AC_MSG_RESULT($LOCKDDLM)
BUILD_LOCKDDLM=$LOCKDDLM
@@ -961,7 +990,7 @@ AC_MSG_CHECKING(whether to build lvmlockddlmcontrol)
AC_ARG_ENABLE(lvmlockd-dlmcontrol,
AS_HELP_STRING([--enable-lvmlockd-dlmcontrol],
[enable lvmlockd remote refresh using libdlmcontrol]),
LOCKDDLM_CONTROL=$enableval)
LOCKDDLM_CONTROL=$enableval, LOCKDDLM_CONTROL=no)
AC_MSG_RESULT($LOCKDDLM_CONTROL)
BUILD_LOCKDDLM_CONTROL=$LOCKDDLM_CONTROL
@@ -979,7 +1008,7 @@ AC_MSG_CHECKING(whether to build lvmlockdidm)
AC_ARG_ENABLE(lvmlockd-idm,
AS_HELP_STRING([--enable-lvmlockd-idm],
[enable the LVM lock daemon using idm]),
LOCKDIDM=$enableval)
LOCKDIDM=$enableval, LOCKDIDM=no)
AC_MSG_RESULT($LOCKDIDM)
BUILD_LOCKDIDM=$LOCKDIDM
@@ -987,7 +1016,7 @@ BUILD_LOCKDIDM=$LOCKDIDM
dnl -- Look for Seagate IDM libraries
if test "$BUILD_LOCKDIDM" = yes; then
PKG_CHECK_MODULES(LOCKD_IDM, libseagate_ilm >= 0.1.0, [HAVE_LOCKD_IDM=yes], $bailout)
PKG_CHECK_MODULES(BLKID, blkid >= 2.24, [HAVE_LOCKD_IDM=yes], $bailout)
PKG_CHECK_EXISTS(blkid >= 2.24, [HAVE_LOCKD_IDM=yes], $bailout)
AC_DEFINE([LOCKDIDM_SUPPORT], 1, [Define to 1 to include code that uses lvmlockd IDM option.])
BUILD_LVMLOCKD=yes
fi
@@ -1218,19 +1247,6 @@ if test "$UDEV_RULE" != no ; then
AC_MSG_RESULT($UDEV_HAS_BUILTIN_BLKID)
fi
################################################################################
dnl -- Compatibility mode
AC_ARG_ENABLE(compat,
AS_HELP_STRING([--enable-compat],
[enable support for old device-mapper versions]),
DM_COMPAT=$enableval, DM_COMPAT=no)
AS_IF([test "$DM_COMPAT" = yes],
[AC_DEFINE([DM_COMPAT], 1, [Define to enable compat protocol])
AC_MSG_ERROR([--enable-compat is not currently supported.
Since device-mapper version 1.02.66, only one version (4) of the device-mapper
ioctl protocol is supported.])])
################################################################################
dnl -- Compatible units suffix mode
AC_ARG_ENABLE(units-compat,
@@ -1639,6 +1655,10 @@ 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)
@@ -1814,6 +1834,7 @@ 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)
@@ -1946,6 +1967,7 @@ 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)
@@ -1967,6 +1989,7 @@ Makefile
make.tmpl
libdm/make.tmpl
daemons/Makefile
daemons/cmirrord/Makefile
daemons/dmeventd/Makefile
daemons/dmeventd/libdevmapper-event.pc
daemons/dmeventd/plugins/Makefile
@@ -2000,14 +2023,14 @@ libdm/libdevmapper.pc
man/Makefile
po/Makefile
scripts/lvm2-pvscan.service
scripts/lvm-activate-vgs-main.service
scripts/lvm-activate-vgs-last.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

View File

@@ -3016,9 +3016,7 @@ static int add_lockspace_thread(const char *ls_name,
!alloc_and_copy_pvs_path(&ls2->pvs, &ls->pvs)) {
log_debug("add_lockspace_thread %s fails to allocate pvs", ls->name);
rv = -ENOMEM;
}
if (ls2->thread_stop) {
} else if (ls2->thread_stop) {
log_debug("add_lockspace_thread %s exists and stopping", ls->name);
rv = -EAGAIN;
} else if (!ls2->create_fail && !ls2->create_done) {

View File

@@ -114,9 +114,6 @@
/* Define to 1 to enable the device-mapper filemap daemon. */
#undef DMFILEMAPD
/* Define to enable compat protocol */
#undef DM_COMPAT
/* Define default group for device node */
#undef DM_DEVICE_GID

View File

@@ -40,6 +40,7 @@ SOURCES =\
device/dev-luks.c \
device/dev-dasd.c \
device/dev-lvm1-pool.c \
device/online.c \
display/display.c \
error/errseg.c \
unknown/unknown.c \

10
lib/cache/lvmcache.c vendored
View File

@@ -572,6 +572,16 @@ static const char *_get_pvsummary_device_id(const char *pvid_arg, const char **d
return NULL;
}
int lvmcache_pvsummary_count(const char *vgname)
{
struct lvmcache_vginfo *vginfo;
if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, NULL)))
return_0;
return dm_list_size(&vginfo->pvsummaries);
}
/*
* Check if any PVs in vg->pvs have the same PVID as any
* entries in _unused_duplicates.

View File

@@ -229,4 +229,6 @@ void lvmcache_extra_md_component_checks(struct cmd_context *cmd);
unsigned int lvmcache_vg_info_count(void);
int lvmcache_pvsummary_count(const char *vgname);
#endif

View File

@@ -159,9 +159,11 @@ static const char *_system_id_from_source(struct cmd_context *cmd, const char *s
#ifdef APP_MACHINEID_SUPPORT
if (!strcasecmp(source, "appmachineid")) {
sd_id128_t id;
sd_id128_t id = { 0 };
sd_id128_get_machine_app_specific(LVM_APPLICATION_ID, &id);
if (sd_id128_get_machine_app_specific(LVM_APPLICATION_ID, &id) != 0)
log_warn("WARNING: sd_id128_get_machine_app_specific() failed %s (%d).",
strerror(errno), errno);
if (dm_snprintf(buf, PATH_MAX, SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(id)) < 0)
stack;
@@ -1141,19 +1143,6 @@ static struct dev_filter *_init_filter_chain(struct cmd_context *cmd)
* Update MAX_FILTERS definition above when adding new filters.
*/
/*
* sysfs filter. Only available on 2.6 kernels. Non-critical.
* Listed first because it's very efficient at eliminating
* unavailable devices.
*
* TODO: I suspect that using the lvm_type and device_id
* filters before this one may be more efficient.
*/
if (find_config_tree_bool(cmd, devices_sysfs_scan_CFG, NULL)) {
if ((filters[nr_filt] = sysfs_filter_create()))
nr_filt++;
}
/* internal filter used by command processing. */
if (!(filters[nr_filt] = internal_filter_create())) {
log_error("Failed to create internal device filter");
@@ -1193,6 +1182,17 @@ static struct dev_filter *_init_filter_chain(struct cmd_context *cmd)
}
nr_filt++;
/*
* sysfs filter. Only available on 2.6 kernels. Non-critical.
* Eliminates unavailable devices.
* TODO: this may be unnecessary now with device ids
* (currently not used for devs match to device id using syfs)
*/
if (find_config_tree_bool(cmd, devices_sysfs_scan_CFG, NULL)) {
if ((filters[nr_filt] = sysfs_filter_create()))
nr_filt++;
}
/* usable device filter. Required. */
if (!(filters[nr_filt] = usable_filter_create(cmd, cmd->dev_types, FILTER_MODE_NO_LVMETAD))) {
log_error("Failed to create usabled device filter");
@@ -1603,7 +1603,6 @@ struct cmd_context *create_config_context(void)
dm_list_init(&cmd->config_files);
dm_list_init(&cmd->tags);
dm_list_init(&cmd->hints);
if (!_init_lvm_conf(cmd))
goto_out;
@@ -1668,7 +1667,6 @@ struct cmd_context *create_toolcontext(unsigned is_clvmd,
dm_list_init(&cmd->formats);
dm_list_init(&cmd->segtypes);
dm_list_init(&cmd->tags);
dm_list_init(&cmd->hints);
dm_list_init(&cmd->config_files);
label_init();

View File

@@ -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;
@@ -183,7 +183,6 @@ struct cmd_context {
unsigned enable_hints:1; /* hints are enabled for cmds in general */
unsigned use_hints:1; /* if hints are enabled this cmd can use them */
unsigned pvscan_recreate_hints:1; /* enable special case hint handling for pvscan --cache */
unsigned hints_pvs_online:1; /* hints="pvs_online" */
unsigned scan_lvs:1;
unsigned wipe_outdated_pvs:1;
unsigned enable_devices_list:1; /* command is using --devices option */
@@ -202,12 +201,12 @@ struct cmd_context {
unsigned ignore_device_name_mismatch:1; /* skip updating devices file names */
unsigned backup_disabled:1; /* skip repeated debug message */
unsigned event_activation:1; /* whether event_activation is set */
unsigned udevoutput:1;
/*
* Devices and filtering.
*/
struct dev_filter *filter;
struct dm_list hints;
struct dm_list use_devices; /* struct dev_use for each entry in devices file */
const char *md_component_checks;
const char *search_for_devnames; /* config file setting */

View File

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

View File

@@ -328,9 +328,6 @@
#define DEFAULT_WWIDS_FILE "/etc/multipath/wwids"
#define DEFAULT_EVENT_ACTIVATION_OPTION1 "service_to_event"
#define DEFAULT_EVENT_ACTIVATION_OPTIONS "#S" DEFAULT_EVENT_ACTIVATION_OPTION1
#define PVS_ONLINE_DIR DEFAULT_RUN_DIR "/pvs_online"
#define VGS_ONLINE_DIR DEFAULT_RUN_DIR "/vgs_online"
#define PVS_LOOKUP_DIR DEFAULT_RUN_DIR "/pvs_lookup"

View File

@@ -53,6 +53,7 @@ static struct {
const char *dev_dir;
int has_scanned;
long st_dev;
struct dm_list dirs;
struct dm_list files;
@@ -1064,11 +1065,18 @@ static void _insert_dirs(struct dm_list *dirs)
struct dir_list *dl;
struct udev *udev = NULL;
int with_udev;
struct stat tinfo;
with_udev = obtain_device_list_from_udev() &&
(udev = udev_get_library_context());
dm_list_iterate_items(dl, &_cache.dirs) {
if (stat(dl->dir, &tinfo) < 0) {
log_warn("WARNING: Cannot use dir %s, %s.",
dl->dir, strerror(errno));
continue;
}
_cache.st_dev = tinfo.st_dev;
if (with_udev) {
if (!_insert_udev_dir(udev, dl->dir))
log_debug_devs("%s: Failed to insert devices from "
@@ -1091,9 +1099,17 @@ static int _device_in_udev_db(const dev_t d)
static void _insert_dirs(struct dm_list *dirs)
{
struct dir_list *dl;
struct stat tinfo;
dm_list_iterate_items(dl, &_cache.dirs)
dm_list_iterate_items(dl, &_cache.dirs) {
if (stat(dl->dir, &tinfo) < 0) {
log_warn("WARNING: Cannot use dir %s, %s.",
dl->dir, strerror(errno));
continue;
}
_cache.st_dev = tinfo.st_dev;
_insert_dir(dl->dir);
}
}
#endif /* UDEV_SYNC_SUPPORT */
@@ -1128,6 +1144,11 @@ static int _insert(const char *path, const struct stat *info,
return 1;
}
if (info->st_dev != _cache.st_dev) {
log_debug_devs("%s: Different filesystem in directory", path);
return 1;
}
if (rec && !_insert_dir(path))
return 0;
} else { /* add a device */
@@ -2035,12 +2056,12 @@ int setup_device(struct cmd_context *cmd, const char *devname)
}
/*
* pvscan --cache is specialized/optimized to look only at command args,
* autoactivation is specialized/optimized to look only at command args,
* so this just sets up the devices file, then individual devices are
* added to dev-cache and matched with device_ids later in pvscan.
* added to dev-cache and matched with device_ids.
*/
int setup_devices_for_pvscan_cache(struct cmd_context *cmd)
int setup_devices_for_online_autoactivation(struct cmd_context *cmd)
{
if (cmd->enable_devices_list) {
if (!_setup_devices_list(cmd))
@@ -2104,7 +2125,7 @@ static char *_get_devname_from_devno(struct cmd_context *cmd, dev_t devno)
}
if (!(dir = opendir(path)))
return NULL;
goto try_partition;
while ((dirent = readdir(dir))) {
if (dirent->d_name[0] == '.')
@@ -2143,7 +2164,7 @@ static char *_get_devname_from_devno(struct cmd_context *cmd, dev_t devno)
}
if (devname[0]) {
log_debug("Found %s for %d:%d from sys", devname, major, minor);
log_debug("Found %s for %d:%d from sys dm", devname, major, minor);
return _strdup(devname);
}
return NULL;
@@ -2154,6 +2175,7 @@ static char *_get_devname_from_devno(struct cmd_context *cmd, dev_t devno)
* major minor #blocks name
*/
try_partition:
if (!(fp = fopen("/proc/partitions", "r")))
return NULL;

View File

@@ -79,8 +79,7 @@ int setup_devices_file(struct cmd_context *cmd);
int setup_devices(struct cmd_context *cmd);
int setup_device(struct cmd_context *cmd, const char *devname);
/* Normal device setup functions are split up for pvscan optimization. */
int setup_devices_for_pvscan_cache(struct cmd_context *cmd);
int setup_devices_for_online_autoactivation(struct cmd_context *cmd);
int setup_devname_in_dev_cache(struct cmd_context *cmd, const char *devname);
int setup_devno_in_dev_cache(struct cmd_context *cmd, dev_t devno);

View File

@@ -778,9 +778,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;
}
@@ -1351,8 +1350,9 @@ void device_id_update_vg_uuid(struct cmd_context *cmd, struct volume_group *vg,
}
}
if (update)
device_ids_write(cmd);
if (update &&
!device_ids_write(cmd))
stack;
out:
unlock_devices_file(cmd);
}

424
lib/device/online.c Normal file
View File

@@ -0,0 +1,424 @@
/*
* Copyright (C) 2021 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "base/memory/zalloc.h"
#include "lib/misc/lib.h"
#include "lib/commands/toolcontext.h"
#include "lib/device/device.h"
#include "lib/device/device_id.h"
#include "lib/device/online.h"
#include <dirent.h>
static char *_vgname_in_pvid_file_buf(char *buf)
{
char *p, *n;
/*
* file contains:
* <major>:<minor>\n
* vg:<vgname>\n\0
*/
if (!(p = strchr(buf, '\n')))
return NULL;
p++; /* skip \n */
if (*p && !strncmp(p, "vg:", 3)) {
if ((n = strchr(p, '\n')))
*n = '\0';
return p + 3;
}
return NULL;
}
#define MAX_PVID_FILE_SIZE 512
int online_pvid_file_read(char *path, int *major, int *minor, char *vgname)
{
char buf[MAX_PVID_FILE_SIZE] = { 0 };
char *name;
int fd, rv;
fd = open(path, O_RDONLY);
if (fd < 0) {
log_warn("Failed to open %s", path);
return 0;
}
rv = read(fd, buf, sizeof(buf) - 1);
if (close(fd))
log_sys_debug("close", path);
if (!rv || rv < 0) {
log_warn("No info in %s", path);
return 0;
}
buf[rv] = 0; /* \0 terminated buffer */
if (sscanf(buf, "%d:%d", major, minor) != 2) {
log_warn("No device numbers in %s", path);
return 0;
}
/* vgname points to an offset in buf */
if ((name = _vgname_in_pvid_file_buf(buf)))
strncpy(vgname, name, NAME_LEN);
else
log_debug("No vgname in %s", path);
return 1;
}
void free_po_list(struct dm_list *list)
{
struct pv_online *po, *po2;
dm_list_iterate_items_safe(po, po2, list) {
dm_list_del(&po->list);
free(po);
}
}
int get_pvs_online(struct dm_list *pvs_online, const char *vgname)
{
char path[PATH_MAX];
char file_vgname[NAME_LEN];
DIR *dir;
struct dirent *de;
struct pv_online *po;
int file_major = 0, file_minor = 0;
if (!(dir = opendir(PVS_ONLINE_DIR)))
return 0;
while ((de = readdir(dir))) {
if (de->d_name[0] == '.')
continue;
if (strlen(de->d_name) != ID_LEN)
continue;
memset(path, 0, sizeof(path));
snprintf(path, sizeof(path), "%s/%s", PVS_ONLINE_DIR, de->d_name);
file_major = 0;
file_minor = 0;
memset(file_vgname, 0, sizeof(file_vgname));
if (!online_pvid_file_read(path, &file_major, &file_minor, file_vgname))
continue;
if (vgname && strcmp(file_vgname, vgname))
continue;
if (!(po = zalloc(sizeof(*po))))
continue;
memcpy(po->pvid, de->d_name, ID_LEN);
if (file_major || file_minor)
po->devno = MKDEV(file_major, file_minor);
if (file_vgname[0])
strncpy(po->vgname, file_vgname, NAME_LEN-1);
dm_list_add(pvs_online, &po->list);
}
if (closedir(dir))
log_sys_debug("closedir", PVS_ONLINE_DIR);
log_debug("PVs online found %d for %s", dm_list_size(pvs_online), vgname ?: "all");
return 1;
}
/*
* When a PV goes offline, remove the vg online file for that VG
* (even if other PVs for the VG are still online). This means
* that the vg will be activated again when it becomes complete.
*/
void online_vg_file_remove(const char *vgname)
{
char path[PATH_MAX];
if (dm_snprintf(path, sizeof(path), "%s/%s", VGS_ONLINE_DIR, vgname) < 0) {
log_error("Path %s/%s is too long.", VGS_ONLINE_DIR, vgname);
return;
}
log_debug("Unlink vg online: %s", path);
if (unlink(path) && (errno != ENOENT))
log_sys_debug("unlink", path);
}
int online_vg_file_create(struct cmd_context *cmd, const char *vgname)
{
char path[PATH_MAX];
int fd;
if (dm_snprintf(path, sizeof(path), "%s/%s", VGS_ONLINE_DIR, vgname) < 0) {
log_error_pvscan(cmd, "Path %s/%s is too long.", VGS_ONLINE_DIR, vgname);
return 0;
}
log_debug("Create vg online: %s", path);
fd = open(path, O_CREAT | O_EXCL | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
if (fd < 0) {
log_debug("Failed to create %s: %d", path, errno);
return 0;
}
/* We don't care about syncing, these files are not even persistent. */
if (close(fd))
log_sys_debug("close", path);
return 1;
}
int online_pvid_file_create(struct cmd_context *cmd, struct device *dev, const char *vgname)
{
char path[PATH_MAX];
char buf[MAX_PVID_FILE_SIZE] = { 0 };
char file_vgname[NAME_LEN];
int file_major = 0, file_minor = 0;
int major, minor;
int fd;
int rv;
int len;
int len1 = 0;
int len2 = 0;
major = (int)MAJOR(dev->dev);
minor = (int)MINOR(dev->dev);
if (dm_snprintf(path, sizeof(path), "%s/%s", PVS_ONLINE_DIR, dev->pvid) < 0) {
log_error_pvscan(cmd, "Path %s/%s is too long.", PVS_ONLINE_DIR, dev->pvid);
return 0;
}
if ((len1 = dm_snprintf(buf, sizeof(buf), "%d:%d\n", major, minor)) < 0) {
log_error_pvscan(cmd, "Cannot create online file path for %s %d:%d.", dev_name(dev), major, minor);
return 0;
}
if (vgname) {
if ((len2 = dm_snprintf(buf + len1, sizeof(buf) - len1, "vg:%s\n", vgname)) < 0) {
log_print_pvscan(cmd, "Incomplete online file for %s %d:%d vg %s.", dev_name(dev), major, minor, vgname);
/* can still continue without vgname */
len2 = 0;
}
}
len = len1 + len2;
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)
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;
}
while (len > 0) {
rv = write(fd, buf, len);
if (rv < 0) {
/* file exists so it still works in part */
log_warn("Cannot write online file for %s to %s error %d",
dev_name(dev), path, errno);
if (close(fd))
log_sys_debug("close", path);
return 1;
}
len -= rv;
}
/* We don't care about syncing, these files are not even persistent. */
if (close(fd))
log_sys_debug("close", path);
return 1;
check_duplicate:
/*
* If a PVID online file already exists for this PVID, check if the
* file contains a different device number, and if so we may have a
* duplicate PV.
*
* FIXME: disable autoactivation of the VG somehow?
* The VG may or may not already be activated when a dupicate appears.
* Perhaps write a new field in the pv online or vg online file?
*/
memset(file_vgname, 0, sizeof(file_vgname));
online_pvid_file_read(path, &file_major, &file_minor, file_vgname);
if ((file_major == major) && (file_minor == minor)) {
log_debug("Existing online file for %d:%d", major, minor);
return 1;
}
/* Don't know how vgname might not match, but it's not good so fail. */
if ((file_major != major) || (file_minor != minor))
log_error_pvscan(cmd, "PV %s is duplicate for PVID %s on %d:%d and %d:%d.",
dev_name(dev), dev->pvid, major, minor, file_major, file_minor);
if (file_vgname[0] && vgname && strcmp(file_vgname, vgname))
log_error_pvscan(cmd, "PV %s has unexpected VG %s vs %s.",
dev_name(dev), vgname, file_vgname);
return 0;
}
int online_pvid_file_exists(const char *pvid)
{
char path[PATH_MAX] = { 0 };
struct stat buf;
int rv;
if (dm_snprintf(path, sizeof(path), "%s/%s", PVS_ONLINE_DIR, pvid) < 0) {
log_debug(INTERNAL_ERROR "Path %s/%s is too long.", PVS_ONLINE_DIR, pvid);
return 0;
}
log_debug("Check pv online: %s", path);
rv = stat(path, &buf);
if (!rv) {
log_debug("Check pv online %s: yes", pvid);
return 1;
}
log_debug("Check pv online %s: no", pvid);
return 0;
}
int get_pvs_lookup(struct dm_list *pvs_online, const char *vgname)
{
char lookup_path[PATH_MAX] = { 0 };
char path[PATH_MAX] = { 0 };
char line[64];
char pvid[ID_LEN + 1] __attribute__((aligned(8))) = { 0 };
char file_vgname[NAME_LEN];
struct pv_online *po;
int file_major = 0, file_minor = 0;
FILE *fp;
if (dm_snprintf(lookup_path, sizeof(path), "%s/%s", PVS_LOOKUP_DIR, vgname) < 0)
return_0;
if (!(fp = fopen(lookup_path, "r")))
return_0;
while (fgets(line, sizeof(line), fp)) {
memcpy(pvid, line, ID_LEN);
if (strlen(pvid) != ID_LEN)
goto_bad;
memset(path, 0, sizeof(path));
snprintf(path, sizeof(path), "%s/%s", PVS_ONLINE_DIR, pvid);
file_major = 0;
file_minor = 0;
memset(file_vgname, 0, sizeof(file_vgname));
if (!online_pvid_file_read(path, &file_major, &file_minor, file_vgname))
goto_bad;
if (vgname && strcmp(file_vgname, vgname))
goto_bad;
if (!(po = zalloc(sizeof(*po))))
goto_bad;
memcpy(po->pvid, pvid, ID_LEN);
if (file_major || file_minor)
po->devno = MKDEV(file_major, file_minor);
if (file_vgname[0])
strncpy(po->vgname, file_vgname, NAME_LEN-1);
dm_list_add(pvs_online, &po->list);
}
log_debug("PVs online lookup found %d for %s", dm_list_size(pvs_online), vgname);
fclose(fp);
return 1;
bad:
free_po_list(pvs_online);
fclose(fp);
return 0;
}
void online_dir_setup(struct cmd_context *cmd)
{
struct stat st;
int rv;
if (!stat(DEFAULT_RUN_DIR, &st))
goto do_pvs;
log_debug("Creating run_dir.");
dm_prepare_selinux_context(DEFAULT_RUN_DIR, S_IFDIR);
rv = mkdir(DEFAULT_RUN_DIR, 0755);
dm_prepare_selinux_context(NULL, 0);
if ((rv < 0) && stat(DEFAULT_RUN_DIR, &st))
log_error_pvscan(cmd, "Failed to create %s %d", DEFAULT_RUN_DIR, errno);
do_pvs:
if (!stat(PVS_ONLINE_DIR, &st))
goto do_vgs;
log_debug("Creating pvs_online_dir.");
dm_prepare_selinux_context(PVS_ONLINE_DIR, S_IFDIR);
rv = mkdir(PVS_ONLINE_DIR, 0755);
dm_prepare_selinux_context(NULL, 0);
if ((rv < 0) && stat(PVS_ONLINE_DIR, &st))
log_error_pvscan(cmd, "Failed to create %s %d", PVS_ONLINE_DIR, errno);
do_vgs:
if (!stat(VGS_ONLINE_DIR, &st))
goto do_lookup;
log_debug("Creating vgs_online_dir.");
dm_prepare_selinux_context(VGS_ONLINE_DIR, S_IFDIR);
rv = mkdir(VGS_ONLINE_DIR, 0755);
dm_prepare_selinux_context(NULL, 0);
if ((rv < 0) && stat(VGS_ONLINE_DIR, &st))
log_error_pvscan(cmd, "Failed to create %s %d", VGS_ONLINE_DIR, errno);
do_lookup:
if (!stat(PVS_LOOKUP_DIR, &st))
return;
log_debug("Creating pvs_lookup_dir.");
dm_prepare_selinux_context(PVS_LOOKUP_DIR, S_IFDIR);
rv = mkdir(PVS_LOOKUP_DIR, 0755);
dm_prepare_selinux_context(NULL, 0);
if ((rv < 0) && stat(PVS_LOOKUP_DIR, &st))
log_error_pvscan(cmd, "Failed to create %s %d", PVS_LOOKUP_DIR, errno);
}

57
lib/device/online.h Normal file
View File

@@ -0,0 +1,57 @@
/*
* Copyright (C) 2021 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _ONLINE_H
#define _ONLINE_H
struct pv_online {
struct dm_list list;
struct device *dev;
dev_t devno;
char pvid[ID_LEN + 1];
char vgname[NAME_LEN];
};
/*
* Avoid a duplicate pvscan[%d] prefix when logging to the journal.
* FIXME: this should probably replace if (udevoutput) with
* if (log_journal & LOG_JOURNAL_OUTPUT)
*/
#define log_print_pvscan(cmd, fmt, args...) \
do \
if (cmd->udevoutput) \
log_print(fmt, ##args); \
else \
log_print("pvscan[%d] " fmt, getpid(), ##args); \
while (0)
#define log_error_pvscan(cmd, fmt, args...) \
do \
if (cmd->udevoutput) \
log_error(fmt, ##args); \
else \
log_error("pvscan[%d] " fmt, getpid(), ##args); \
while (0)
int online_pvid_file_read(char *path, int *major, int *minor, char *vgname);
int online_vg_file_create(struct cmd_context *cmd, const char *vgname);
void online_vg_file_remove(const char *vgname);
int online_pvid_file_create(struct cmd_context *cmd, struct device *dev, const char *vgname);
int online_pvid_file_exists(const char *pvid);
void online_dir_setup(struct cmd_context *cmd);
int get_pvs_online(struct dm_list *pvs_online, const char *vgname);
int get_pvs_lookup(struct dm_list *pvs_online, const char *vgname);
void free_po_list(struct dm_list *list);
#endif

View File

@@ -17,266 +17,34 @@
#ifdef __linux__
#include <sys/sysmacros.h>
#include <dirent.h>
static int _locate_sysfs_blocks(const char *sysfs_dir, char *path, size_t len,
unsigned *sysfs_depth)
{
struct stat info;
unsigned i;
static const struct dir_class {
const char path[32];
int depth;
} classes[] = {
/*
* unified classification directory for all kernel subsystems
*
* /sys/subsystem/block/devices
* |-- sda -> ../../../devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda
* |-- sda1 -> ../../../devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1
* `-- sr0 -> ../../../devices/pci0000:00/0000:00:1f.2/host1/target1:0:0/1:0:0:0/block/sr0
*
*/
{ "subsystem/block/devices", 0 },
/*
* block subsystem as a class
*
* /sys/class/block
* |-- sda -> ../../devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda
* |-- sda1 -> ../../devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1
* `-- sr0 -> ../../devices/pci0000:00/0000:00:1f.2/host1/target1:0:0/1:0:0:0/block/sr0
*
*/
{ "class/block", 0 },
/*
* old block subsystem layout with nested directories
*
* /sys/block/
* |-- sda
* | |-- capability
* | |-- dev
* ...
* | |-- sda1
* | | |-- dev
* ...
* |
* `-- sr0
* |-- capability
* |-- dev
* ...
*
*/
{ "block", 1 }
};
for (i = 0; i < DM_ARRAY_SIZE(classes); ++i)
if ((dm_snprintf(path, len, "%s%s", sysfs_dir, classes[i].path) >= 0) &&
(stat(path, &info) == 0)) {
*sysfs_depth = classes[i].depth;
return 1;
}
return 0;
}
/*----------------------------------------------------------------
* We need to store a set of dev_t.
*--------------------------------------------------------------*/
struct entry {
struct entry *next;
dev_t dev;
};
#define SET_BUCKETS 64
struct dev_set {
struct dm_pool *mem;
const char *sys_block;
unsigned sysfs_depth;
int initialised;
struct entry *slots[SET_BUCKETS];
};
static struct dev_set *_dev_set_create(struct dm_pool *mem,
const char *sys_block,
unsigned sysfs_depth)
{
struct dev_set *ds;
if (!(ds = dm_pool_zalloc(mem, sizeof(*ds))))
return NULL;
ds->mem = mem;
if (!(ds->sys_block = dm_pool_strdup(mem, sys_block)))
return NULL;
ds->sysfs_depth = sysfs_depth;
ds->initialised = 0;
return ds;
}
static unsigned _hash_dev(dev_t dev)
{
return (major(dev) ^ minor(dev)) & (SET_BUCKETS - 1);
}
/*
* Doesn't check that the set already contains dev.
*/
static int _set_insert(struct dev_set *ds, dev_t dev)
{
struct entry *e;
unsigned h = _hash_dev(dev);
if (!(e = dm_pool_alloc(ds->mem, sizeof(*e))))
return 0;
e->next = ds->slots[h];
e->dev = dev;
ds->slots[h] = e;
return 1;
}
static int _set_lookup(struct dev_set *ds, dev_t dev)
{
unsigned h = _hash_dev(dev);
struct entry *e;
for (e = ds->slots[h]; e; e = e->next)
if (e->dev == dev)
return 1;
return 0;
}
/*----------------------------------------------------------------
* filter methods
*--------------------------------------------------------------*/
static int _parse_dev(const char *file, FILE *fp, dev_t *result)
{
unsigned major, minor;
char buffer[64];
if (!fgets(buffer, sizeof(buffer), fp)) {
log_error("Empty sysfs device file: %s", file);
return 0;
}
if (sscanf(buffer, "%u:%u", &major, &minor) != 2) {
log_error("Incorrect format for sysfs device file: %s.", file);
return 0;
}
*result = makedev(major, minor);
return 1;
}
static int _read_dev(const char *file, dev_t *result)
{
int r;
FILE *fp;
if (!(fp = fopen(file, "r"))) {
log_sys_error("fopen", file);
return 0;
}
r = _parse_dev(file, fp, result);
if (fclose(fp))
log_sys_error("fclose", file);
return r;
}
/*
* Recurse through sysfs directories, inserting any devs found.
*/
static int _read_devs(struct dev_set *ds, const char *dir, unsigned sysfs_depth)
{
struct dirent *d;
DIR *dr;
struct stat info;
char path[PATH_MAX];
char file[PATH_MAX];
dev_t dev = { 0 };
int r = 1;
if (!(dr = opendir(dir))) {
log_sys_error("opendir", dir);
return 0;
}
while ((d = readdir(dr))) {
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
continue;
if (dm_snprintf(path, sizeof(path), "%s/%s", dir,
d->d_name) < 0) {
log_warn("WARNING: sysfs path name too long: %s in %s.",
d->d_name, dir);
continue;
}
/* devices have a "dev" file */
if (dm_snprintf(file, sizeof(file), "%s/dev", path) < 0) {
log_warn("WARNING: sysfs path name too long: %s in %s.",
d->d_name, dir);
continue;
}
if (!stat(file, &info)) {
/* recurse if we found a device and expect subdirs */
if (sysfs_depth)
_read_devs(ds, path, sysfs_depth - 1);
/* add the device we have found */
if (_read_dev(file, &dev))
_set_insert(ds, dev);
}
}
if (closedir(dr))
log_sys_debug("closedir", dir);
return r;
}
static int _init_devs(struct dev_set *ds)
{
if (!_read_devs(ds, ds->sys_block, ds->sysfs_depth)) {
ds->initialised = -1;
return 0;
}
ds->initialised = 1;
return 1;
}
static int _accept_p(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
{
struct dev_set *ds = (struct dev_set *) f->private;
char path[PATH_MAX];
const char *sysfs_dir;
struct stat info;
dev->filtered_flags &= ~DEV_FILTERED_SYSFS;
if (!ds->initialised)
_init_devs(ds);
/* Pass through if initialisation failed */
if (ds->initialised != 1)
/*
* Any kind of device id other than devname has been set
* using sysfs so we know that sysfs info exists for dev.
*/
if (dev->id && dev->id->idtype && (dev->id->idtype != DEV_ID_TYPE_DEVNAME))
return 1;
if (!_set_lookup(ds, dev->dev)) {
log_debug_devs("%s: Skipping (sysfs)", dev_name(dev));
dev->filtered_flags |= DEV_FILTERED_SYSFS;
return 0;
sysfs_dir = dm_sysfs_dir();
if (sysfs_dir && *sysfs_dir) {
if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d",
sysfs_dir, (int)MAJOR(dev->dev), (int)MINOR(dev->dev)) < 0) {
log_debug("failed to create sysfs path");
return 1;
}
if (lstat(path, &info)) {
log_debug_devs("%s: Skipping (sysfs)", dev_name(dev));
dev->filtered_flags |= DEV_FILTERED_SYSFS;
return 0;
}
}
return 1;
@@ -284,21 +52,14 @@ static int _accept_p(struct cmd_context *cmd, struct dev_filter *f, struct devic
static void _destroy(struct dev_filter *f)
{
struct dev_set *ds = (struct dev_set *) f->private;
if (f->use_count)
log_error(INTERNAL_ERROR "Destroying sysfs filter while in use %u times.", f->use_count);
dm_pool_destroy(ds->mem);
free(f);
}
struct dev_filter *sysfs_filter_create(void)
{
const char *sysfs_dir = dm_sysfs_dir();
char sys_block[PATH_MAX];
unsigned sysfs_depth;
struct dm_pool *mem;
struct dev_set *ds;
struct dev_filter *f;
if (!*sysfs_dir) {
@@ -306,26 +67,12 @@ struct dev_filter *sysfs_filter_create(void)
return NULL;
}
if (!_locate_sysfs_blocks(sysfs_dir, sys_block, sizeof(sys_block), &sysfs_depth))
return NULL;
if (!(mem = dm_pool_create("sysfs", 256))) {
log_error("sysfs pool creation failed");
return NULL;
}
if (!(ds = _dev_set_create(mem, sys_block, sysfs_depth))) {
log_error("sysfs dev_set creation failed");
goto bad;
}
if (!(f = dm_pool_zalloc(mem, sizeof(*f))))
if (!(f = zalloc(sizeof(*f))))
goto_bad;
f->passes_filter = _accept_p;
f->destroy = _destroy;
f->use_count = 0;
f->private = ds;
f->name = "sysfs";
log_debug_devs("Sysfs filter initialised.");
@@ -333,7 +80,6 @@ struct dev_filter *sysfs_filter_create(void)
return f;
bad:
dm_pool_destroy(mem);
return NULL;
}

View File

@@ -465,7 +465,7 @@ static struct volume_group *_vg_read_raw(struct cmd_context *cmd,
vg = _vg_read_raw_area(cmd, fid, vgname, &mdac->area, vg_fmtdata, use_previous_vg, 0, mda_is_primary(mda));
if (!vg && !*use_previous_vg) {
if (!vg && use_previous_vg && !*use_previous_vg) {
/*
* This condition (corrupt metadata text) is often seen in the
* label_scan()/_text_read() phase, where this code corresponds to
@@ -477,8 +477,12 @@ static struct volume_group *_vg_read_raw(struct cmd_context *cmd,
struct lvmcache_info *info = lvmcache_info_from_pvid(dev->pvid, dev, 0);
log_warn("WARNING: reading %s mda%d failed to read metadata.", dev_name(dev), mda_is_primary(mda)?1:2);
log_warn("WARNING: repair VG metadata on %s with vgck --updatemetadata.", dev_name(dev));
/* remove mda from lvmcache, saving it in info->bad_mdas for possible repair with updatemetadata */
lvmcache_del_save_bad_mda(info, mda->mda_num, BAD_MDA_TEXT);
if (info)
/* remove mda from lvmcache, saving it in info->bad_mdas for possible repair with updatemetadata */
lvmcache_del_save_bad_mda(info, mda->mda_num, BAD_MDA_TEXT);
else
log_warn("WARNING: No cache info for %s", dev_name(dev));
/* remove mda from fid */
fid_remove_mda(fid, mda, NULL, 0, 0);
}

View File

@@ -146,6 +146,7 @@
#include "lib/label/hints.h"
#include "lib/device/dev-type.h"
#include "lib/device/device_id.h"
#include "lib/device/online.h"
#include <sys/stat.h>
#include <fcntl.h>
@@ -156,8 +157,6 @@
#include <sys/file.h>
#include <sys/sysmacros.h>
int online_pvid_file_read(char *path, int *major, int *minor, char *vgname);
static const char *_hints_file = DEFAULT_RUN_DIR "/hints";
static const char *_nohints_file = DEFAULT_RUN_DIR "/nohints";
static const char *_newhints_file = DEFAULT_RUN_DIR "/newhints";
@@ -368,7 +367,6 @@ static void _unlock_hints(struct cmd_context *cmd)
void hints_exit(struct cmd_context *cmd)
{
free_hints(&cmd->hints);
if (_hints_fd == -1)
return;
_unlock_hints(cmd);
@@ -1216,8 +1214,8 @@ void invalidate_hints(struct cmd_context *cmd)
* probably want to exclude that command from attempting this optimization,
* because it would be difficult to know what VG that command wanted to use.
*/
static void _get_single_vgname_cmd_arg(struct cmd_context *cmd,
struct dm_list *hints, char **vgname)
void get_single_vgname_cmd_arg(struct cmd_context *cmd,
struct dm_list *hints, char **vgname)
{
struct hint *hint;
char namebuf[NAME_LEN];
@@ -1266,6 +1264,11 @@ static void _get_single_vgname_cmd_arg(struct cmd_context *cmd,
return;
check:
if (!hints) {
*vgname = name;
return;
}
/*
* Only use this vgname hint if there are hints that contain this
* vgname. This might happen if we aren't able to properly extract the
@@ -1282,109 +1285,6 @@ check:
free(name);
}
static int _get_hints_from_pvs_online(struct cmd_context *cmd, struct dm_list *hints_out,
struct dm_list *devs_in, struct dm_list *devs_out)
{
char path[PATH_MAX];
char file_vgname[NAME_LEN];
struct dm_list hints_list;
struct hint file_hint;
struct hint *alloc_hint;
struct hint *hint, *hint2;
struct device_list *devl, *devl2;
int file_major, file_minor;
int found = 0;
DIR *dir;
struct dirent *de;
char *vgname = NULL;
char *pvid;
dm_list_init(&hints_list);
if (!(dir = opendir(PVS_ONLINE_DIR)))
return 0;
while ((de = readdir(dir))) {
if (de->d_name[0] == '.')
continue;
pvid = de->d_name;
if (strlen(pvid) != ID_LEN) /* 32 */
continue;
memset(path, 0, sizeof(path));
snprintf(path, sizeof(path), "%s/%s", PVS_ONLINE_DIR, pvid);
memset(&file_hint, 0, sizeof(file_hint));
memset(file_vgname, 0, sizeof(file_vgname));
file_major = 0;
file_minor = 0;
if (!online_pvid_file_read(path, &file_major, &file_minor, file_vgname))
continue;
if (!dm_strncpy(file_hint.pvid, pvid, sizeof(file_hint.pvid)))
continue;
file_hint.devt = makedev(file_major, file_minor);
if (file_vgname[0] && validate_name(file_vgname)) {
if (!dm_strncpy(file_hint.vgname, file_vgname, sizeof(file_hint.vgname)))
continue;
}
if (!(alloc_hint = malloc(sizeof(struct hint))))
continue;
memcpy(alloc_hint, &file_hint, sizeof(struct hint));
log_debug("add hint %s %d:%d %s from pvs_online", file_hint.pvid, file_major, file_minor, file_vgname);
dm_list_add(&hints_list, &alloc_hint->list);
found++;
}
if (closedir(dir))
stack;
log_debug("accept hints found %d from pvs_online", found);
_get_single_vgname_cmd_arg(cmd, &hints_list, &vgname);
/*
* apply_hints equivalent, move devs from devs_in to devs_out if
* their devno matches the devno of a hint (and if the hint matches
* the vgname when a vgname is present.)
*/
dm_list_iterate_items_safe(devl, devl2, devs_in) {
dm_list_iterate_items_safe(hint, hint2, &hints_list) {
if ((MAJOR(devl->dev->dev) == MAJOR(hint->devt)) &&
(MINOR(devl->dev->dev) == MINOR(hint->devt))) {
if (vgname && hint->vgname[0] && strcmp(vgname, hint->vgname))
goto next_dev;
snprintf(hint->name, sizeof(hint->name), "%s", dev_name(devl->dev));
hint->chosen = 1;
dm_list_del(&devl->list);
dm_list_add(devs_out, &devl->list);
}
}
next_dev:
;
}
log_debug("applied hints using %d other %d vgname %s from pvs_online",
dm_list_size(devs_out), dm_list_size(devs_in), vgname ?: "");
dm_list_splice(hints_out, &hints_list);
free(vgname);
return 1;
}
/*
* Returns 0: no hints are used.
* . newhints is set if this command should create new hints after scan
@@ -1426,15 +1326,6 @@ int get_hints(struct cmd_context *cmd, struct dm_list *hints_out, int *newhints,
if (!cmd->use_hints)
return 0;
/* hints = "pvs_online" */
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");
return 0;
}
return 1;
}
/*
* Check if another command created the nohints file to prevent us from
* using hints.
@@ -1539,7 +1430,7 @@ int get_hints(struct cmd_context *cmd, struct dm_list *hints_out, int *newhints,
* us which devs are PVs. We might want to enable this optimization
* separately.)
*/
_get_single_vgname_cmd_arg(cmd, &hints_list, &vgname);
get_single_vgname_cmd_arg(cmd, &hints_list, &vgname);
_apply_hints(cmd, &hints_list, vgname, devs_in, devs_out);

View File

@@ -41,5 +41,8 @@ void hints_exit(struct cmd_context *cmd);
void pvscan_recreate_hints_begin(struct cmd_context *cmd);
void get_single_vgname_cmd_arg(struct cmd_context *cmd,
struct dm_list *hints, char **vgname);
#endif

View File

@@ -26,6 +26,7 @@
#include "lib/metadata/metadata.h"
#include "lib/format_text/layout.h"
#include "lib/device/device_id.h"
#include "lib/device/online.h"
#include <sys/stat.h>
#include <fcntl.h>
@@ -891,7 +892,7 @@ static int _setup_bcache(void)
#define BASE_FD_COUNT 32 /* Number of open files we want apart from devs */
static void _prepare_open_file_limit(struct cmd_context *cmd, unsigned int num_devs)
void prepare_open_file_limit(struct cmd_context *cmd, unsigned int num_devs)
{
#ifdef HAVE_PRLIMIT
struct rlimit old = { 0 }, new;
@@ -1020,6 +1021,236 @@ int label_scan_for_pvid(struct cmd_context *cmd, char *pvid, struct device **dev
return ret;
}
/*
* Use files under /run/lvm/, created by pvscan --cache autoactivation,
* to optimize device setup/scanning. autoactivation happens during
* system startup when the hints file is not useful, but he pvs_online
* files can provide a similar optimization to the hints file.
*/
int label_scan_vg_online(struct cmd_context *cmd, const char *vgname,
int *found_none, int *found_all, int *found_incomplete)
{
struct dm_list pvs_online;
struct dm_list devs;
struct pv_online *po;
struct device_list *devl, *devl2;
int relax_deviceid_filter = 0;
int metadata_pv_count;
int try_dev_scan = 0;
dm_list_init(&pvs_online);
dm_list_init(&devs);
log_debug_devs("Finding online devices to scan");
/* reads devices file, does not populate dev-cache */
if (!setup_devices_for_online_autoactivation(cmd))
return 0;
/*
* First attempt to use /run/lvm/pvs_lookup/vgname which should be
* used in cases where all PVs in a VG do not contain metadata.
* When the pvs_lookup file does not exist, then simply use all
* /run/lvm/pvs_online/pvid files that contain a matching vgname.
* The list of po structs represents the PVs in the VG, and the
* info from the online files tell us which devices those PVs are
* located on.
*/
if (vgname) {
if (!get_pvs_lookup(&pvs_online, vgname)) {
if (!get_pvs_online(&pvs_online, vgname))
goto bad;
}
} else {
if (!get_pvs_online(&pvs_online, NULL))
goto bad;
}
if (dm_list_empty(&pvs_online)) {
*found_none = 1;
return 1;
}
/*
* For each po devno add a struct dev to dev-cache. This is a faster
* alternative to the usual dev_cache_scan() which looks at all
* devices. If this optimization fails, then fall back to the usual
* dev_cache_scan().
*/
dm_list_iterate_items(po, &pvs_online) {
if (!setup_devno_in_dev_cache(cmd, po->devno)) {
log_debug("No device set up for quick mapping of %d:%d PVID %s",
(int)MAJOR(po->devno), (int)MINOR(po->devno), po->pvid);
try_dev_scan = 1;
break;
}
if (!(po->dev = dev_cache_get_by_devt(cmd, po->devno, NULL, NULL))) {
log_debug("No device found for quick mapping of %d:%d PVID %s",
(int)MAJOR(po->devno), (int)MINOR(po->devno), po->pvid);
try_dev_scan = 1;
break;
}
if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
goto_bad;
devl->dev = po->dev;
dm_list_add(&devs, &devl->list);
}
/*
* Translating a devno (major:minor) into a device name can be
* problematic for some devices that have unusual sysfs layouts, so if
* this happens, do a full dev_cache_scan, which is slower, but is
* sure to find the device.
*/
if (try_dev_scan) {
dev_cache_scan(cmd);
dm_list_iterate_items(po, &pvs_online) {
if (po->dev)
continue;
if (!(po->dev = dev_cache_get_by_devt(cmd, po->devno, NULL, NULL))) {
log_error("No device found for %d:%d PVID %s",
(int)MAJOR(po->devno), (int)MINOR(po->devno), po->pvid);
goto bad;
}
if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
goto_bad;
devl->dev = po->dev;
dm_list_add(&devs, &devl->list);
}
}
/*
* factor code common to pvscan_cache_args
*/
if (cmd->enable_devices_file) {
dm_list_iterate_items(devl, &devs)
device_ids_match_dev(cmd, devl->dev);
}
if (cmd->enable_devices_list)
device_ids_match_device_list(cmd);
if (cmd->enable_devices_file && device_ids_use_devname(cmd)) {
relax_deviceid_filter = 1;
cmd->filter_deviceid_skip = 1;
}
cmd->filter_nodata_only = 1;
dm_list_iterate_items_safe(devl, devl2, &devs) {
if (!cmd->filter->passes_filter(cmd, cmd->filter, devl->dev, NULL)) {
log_print("%s excluded by filters: %s.",
dev_name(devl->dev), dev_filtered_reason(devl->dev));
dm_list_del(&devl->list);
}
}
cmd->filter_nodata_only = 0;
/*
* Clear the results of nodata filters that were saved by the
* persistent filter so that the complete set of filters will
* be checked by passes_filter below.
*/
dm_list_iterate_items(devl, &devs)
cmd->filter->wipe(cmd, cmd->filter, devl->dev, NULL);
/*
* Read header from each dev.
* Eliminate non-lvm devs.
* Apply all filters.
*/
log_debug("label_scan_vg_online: read and filter devs");
label_scan_setup_bcache();
dm_list_iterate_items_safe(devl, devl2, &devs) {
int has_pvid;
if (!label_read_pvid(devl->dev, &has_pvid)) {
log_print("%s cannot read label.", dev_name(devl->dev));
dm_list_del(&devl->list);
continue;
}
if (!has_pvid) {
/* Not an lvm device */
log_print("%s not an lvm device.", dev_name(devl->dev));
dm_list_del(&devl->list);
continue;
}
/*
* filter-deviceid is not being used because of unstable devnames,
* so in place of that check if the pvid is in the devices file.
*/
if (relax_deviceid_filter) {
if (!get_du_for_pvid(cmd, devl->dev->pvid)) {
log_print("%s excluded by devices file (checking PVID).",
dev_name(devl->dev));
dm_list_del(&devl->list);
continue;
}
}
/* Applies all filters, including those that need data from dev. */
if (!cmd->filter->passes_filter(cmd, cmd->filter, devl->dev, NULL)) {
log_print("%s excluded by filters: %s.",
dev_name(devl->dev), dev_filtered_reason(devl->dev));
dm_list_del(&devl->list);
}
}
if (relax_deviceid_filter)
cmd->filter_deviceid_skip = 0;
free_po_list(&pvs_online);
if (dm_list_empty(&devs)) {
*found_none = 1;
return 1;
}
/*
* Scan devs to populate lvmcache info, which includes the mda info that's
* needed to read vg metadata.
* bcache data from label_read_pvid above is not invalidated so it can
* be reused (more data may need to be read depending on how much of the
* metadata was covered when reading the pvid.)
*/
_scan_list(cmd, NULL, &devs, 0, NULL);
/*
* Check if all PVs from the VG were found after scanning the devs
* produced from the online files. The online files are effectively
* hints that usually work, but are not definitive, so we need to
* be able to fall back to a standard label scan if the online hints
* gave fewer PVs than listed in VG metadata.
*/
if (vgname) {
metadata_pv_count = lvmcache_pvsummary_count(vgname);
if (metadata_pv_count > dm_list_size(&devs)) {
log_debug("Incomplete PV list from online files %d metadata %d.",
dm_list_size(&devs), metadata_pv_count);
*found_incomplete = 1;
return 1;
}
}
*found_all = 1;
return 1;
bad:
free_po_list(&pvs_online);
return 0;
}
/*
* Scan devices on the system to discover which are LVM devices.
* Info about the LVM devices (PVs) is saved in lvmcache in a
@@ -1168,7 +1399,7 @@ int label_scan(struct cmd_context *cmd)
* which we want to keep open) is higher than the current
* soft limit.
*/
_prepare_open_file_limit(cmd, dm_list_size(&scan_devs));
prepare_open_file_limit(cmd, dm_list_size(&scan_devs));
/*
* Do the main scan.
@@ -1210,8 +1441,6 @@ int label_scan(struct cmd_context *cmd)
(unsigned long long)want_size_kb);
}
dm_list_init(&cmd->hints);
/*
* If we're using hints to limit which devs we scanned, verify
* that those hints were valid, and if not we need to scan the
@@ -1223,18 +1452,16 @@ int label_scan(struct cmd_context *cmd)
_scan_list(cmd, cmd->filter, &all_devs, 0, NULL);
/* scan_devs are the devs that have been scanned */
dm_list_splice(&scan_devs, &all_devs);
free_hints(&hints_list);
using_hints = 0;
create_hints = 0;
/* invalid hints means a new dev probably appeared and
we should search for any missing pvids again. */
unlink_searched_devnames(cmd);
} else {
/* The hints may be used by another device iteration. */
dm_list_splice(&cmd->hints, &hints_list);
}
}
free_hints(&hints_list);
/*
* Check if the devices_file content is up to date and
* if not update it.

View File

@@ -118,6 +118,9 @@ int label_scan_open_excl(struct device *dev);
int label_scan_open_rw(struct device *dev);
int label_scan_reopen_rw(struct device *dev);
int label_read_pvid(struct device *dev, int *has_pvid);
int label_scan_vg_online(struct cmd_context *cmd, const char *vgname,
int *found_none, int *found_all, int *found_incomplete);
int label_scan_for_pvid(struct cmd_context *cmd, char *pvid, struct device **dev_out);
@@ -134,4 +137,6 @@ void dev_invalidate(struct device *dev);
void dev_set_last_byte(struct device *dev, uint64_t offset);
void dev_unset_last_byte(struct device *dev);
void prepare_open_file_limit(struct cmd_context *cmd, unsigned int num_devs);
#endif

View File

@@ -503,7 +503,7 @@ static int _create_sanlock_lv(struct cmd_context *cmd, struct volume_group *vg,
.read_ahead = DM_READ_AHEAD_NONE,
.stripes = 1,
.vg_name = vg->name,
.lv_name = dm_pool_strdup(cmd->mem, lock_lv_name),
.lv_name = lock_lv_name,
.zero = 1,
};

View File

@@ -2354,7 +2354,7 @@ static int _match_pv_tags(const struct dm_config_node *cling_tag_list_cn,
const struct dm_config_value *cv;
const char *str;
const char *tag_matched;
struct dm_list *tags_to_match = mem ? NULL : pv_tags ? : &pv2->tags;
struct dm_list *tags_to_match = mem ? NULL : pv_tags ? : ((pv2) ? &pv2->tags : NULL);
struct dm_str_list *sl;
unsigned first_tag = 1;
@@ -2409,7 +2409,7 @@ static int _match_pv_tags(const struct dm_config_node *cling_tag_list_cn,
continue;
}
if (!str_list_match_list(&pv1->tags, tags_to_match, &tag_matched))
if (tags_to_match && !str_list_match_list(&pv1->tags, tags_to_match, &tag_matched))
continue;
if (!pv_tags) {

View File

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

View File

@@ -5846,12 +5846,12 @@ static int _stats_report(CMD_ARGS)
if (_switches[ALL_PROGRAMS_ARG])
_program_id = "";
if (_switches[VERBOSE_ARG] && !strcmp(subcommand, "list"))
if (_switches[VERBOSE_ARG] && subcommand && !strcmp(subcommand, "list"))
_statstype |= (DM_STATS_WALK_ALL
| DM_STATS_WALK_SKIP_SINGLE_AREA);
/* suppress duplicates unless the user has requested all regions */
if (!strcmp(subcommand, "report") && !objtype_args)
if (subcommand && !objtype_args && !strcmp(subcommand, "report"))
/* suppress duplicate rows of output */
_statstype |= (DM_STATS_WALK_ALL
| DM_STATS_WALK_SKIP_SINGLE_AREA);

View File

@@ -15,6 +15,9 @@ 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")
@@ -63,7 +66,7 @@ install_initscripts:
@echo " [INSTALL] initscripts"
$(Q) $(INSTALL_DIR) $(initdir)
ifeq ("@BUILD_DMEVENTD@", "yes")
$(Q) $(INSTALL_SCRIPT) lvm2_monitoring_init_red_hat $(initdir)/lvm-monitor
$(Q) $(INSTALL_SCRIPT) lvm2_monitoring_init_red_hat $(initdir)/lvm2-monitor
endif
ifeq ("@BUILD_LVMPOLLD@", "yes")
$(Q) $(INSTALL_SCRIPT) lvm2_lvmpolld_init_red_hat $(initdir)/lvm2-lvmpolld
@@ -75,15 +78,24 @@ 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)/lvm-monitor.service
$(Q) $(INSTALL_DATA) lvm2_monitoring_systemd_red_hat.service $(systemd_unit_dir)/lvm2-monitor.service
endif
ifeq ("@BLKDEACTIVATE@", "yes")
$(Q) $(INSTALL_DATA) blk_availability_systemd_red_hat.service $(systemd_unit_dir)/blk-availability.service
@@ -143,9 +155,7 @@ DISTCLEAN_TARGETS += \
lvm2_monitoring_init_red_hat \
lvm2_monitoring_systemd_red_hat.service \
lvm2_pvscan_systemd_red_hat@.service \
lvm2_tmpfiles_red_hat.conf \
lvm-activate-vgs-main.service \
lvm-activate-vgs-last.service
lvm2_tmpfiles_red_hat.conf
# Remove ancient files
DISTCLEAN_TARGETS += \

View File

@@ -1,7 +1,7 @@
[Unit]
Description=Availability of block devices
Before=shutdown.target
After=lvm-activate-vgs-main.service lvm-activate-vgs-last.service iscsi-shutdown.service iscsi.service iscsid.service fcoe.service rbdmap.service
After=lvm2-activation.service iscsi-shutdown.service iscsi.service iscsid.service fcoe.service rbdmap.service
DefaultDependencies=no
Conflicts=shutdown.target

View File

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

View File

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

View File

@@ -10,5 +10,5 @@ Conflicts=shutdown.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=@SBINDIR@/lvm pvscan --cache --activate ay %i
ExecStart=@SBINDIR@/lvm pvscan --cache --activate ay --autoactivation event %i
ExecStop=@SBINDIR@/lvm pvscan --cache %i

View File

@@ -1,8 +1,8 @@
[Unit]
Description=Monitor LVM Logical Volumes
Description=Monitoring of LVM2 mirrors, snapshots etc. using dmeventd or progress polling
Documentation=man:dmeventd(8) man:lvcreate(8) man:lvchange(8) man:vgchange(8)
Requires=dm-event.socket
After=dm-event.socket dm-event.service lvm-activate-vgs-last.service
After=dm-event.socket dm-event.service lvm2-activation.service
Before=local-fs-pre.target shutdown.target
DefaultDependencies=no
Conflicts=shutdown.target

View File

@@ -23,10 +23,10 @@ if [ $1 = 0 ]; then
fi
%triggerun -- %{name} < 2.02.86-2
%{_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 || :
%{_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 || :
# files in the main package
%files
@@ -100,6 +100,9 @@ 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
@@ -184,17 +187,16 @@ 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/lvm-monitor
%{_sysconfdir}/rc.d/init.d/lvm2-monitor
%if %{have_service lvmpolld}
%{_sysconfdir}/rc.d/init.d/lvm2-lvmpolld
%endif

View File

@@ -15,6 +15,8 @@ SKIP_WITH_LVMPOLLD=1
. lib/inittest
find /sys
# Just skip this test if minor is already in use...
dmsetup info | tee info
grep -E "^Major, minor: *[0-9]+, 123" info && skip

View File

@@ -283,7 +283,7 @@ not ls "$RUNDIR/lvm/pvs_online/$PVID3"
# arg in devices list
_clear_online_files
pvscan --devices "$dev3" --cache -aay "$dev3"
pvscan --devices "$dev4" --cache -aay "$dev4"
pvscan --devices "$dev4","$dev3" --cache -aay "$dev4"
check lv_field $vg2/$lv2 lv_active "active"
vgchange -an $vg2

View File

@@ -219,6 +219,8 @@ udevadm trigger -c add /sys/block/$BDEV3
aux udev_wait
wait_lvm_activate $vg4
ls "$RUNDIR/lvm/pvs_lookup/"
cat "$RUNDIR/lvm/pvs_lookup/$vg4" || true
ls "$RUNDIR/lvm/pvs_online/$PVID1"
ls "$RUNDIR/lvm/pvs_online/$PVID2"
ls "$RUNDIR/lvm/pvs_online/$PVID3"
@@ -375,6 +377,7 @@ touch $DF
mdadm --create --metadata=1.0 "$mddev" --level 1 --chunk=64 --raid-devices=2 "$dev1" "$dev2"
wait_md_create "$mddev"
vgcreate $vg9 "$mddev"
lvmdevices --adddev "$mddev" || true
PVIDMD=`pvs $mddev --noheading -o uuid | tr -d - | awk '{print $1}'`
BDEVMD=$(basename "$mddev")

View File

@@ -0,0 +1,172 @@
SKIP_WITH_LVMPOLLD=1
SKIP_WITH_LVMLOCKD=1
RUNDIR="/run"
test -d "$RUNDIR" || RUNDIR="/var/run"
PVS_ONLINE_DIR="$RUNDIR/lvm/pvs_online"
VGS_ONLINE_DIR="$RUNDIR/lvm/vgs_online"
PVS_LOOKUP_DIR="$RUNDIR/lvm/pvs_lookup"
_clear_online_files() {
# wait till udev is finished
aux udev_wait
rm -f "$PVS_ONLINE_DIR"/*
rm -f "$VGS_ONLINE_DIR"/*
rm -f "$PVS_LOOKUP_DIR"/*
}
. lib/inittest
aux prepare_devs 4
# Because mapping devno to devname gets dm name from sysfs
aux lvmconf 'devices/scan = "/dev"'
base1=$(basename $dev1)
base2=$(basename $dev2)
base3=$(basename $dev3)
base4=$(basename $dev4)
aux extend_filter "a|/dev/mapper/$base1|"
aux extend_filter "a|/dev/mapper/$base2|"
aux extend_filter "a|/dev/mapper/$base3|"
aux extend_filter "a|/dev/mapper/$base4|"
vgcreate $vg1 "$dev1" "$dev2"
vgcreate $vg2 "$dev3"
pvcreate "$dev4"
lvcreate -l1 -n $lv1 -an $vg1
lvcreate -l1 -n $lv2 -an $vg1
lvcreate -l1 -n $lv1 -an $vg2
# Expected use, with vg name and all online files exist for vgchange.
_clear_online_files
pvscan --cache "$dev1"
pvscan --cache "$dev2"
vgchange -aay --autoactivation event $vg1
check lv_field $vg1/$lv1 lv_active "active"
check lv_field $vg1/$lv2 lv_active "active"
check lv_field $vg2/$lv1 lv_active ""
pvscan --cache "$dev3"
vgchange -aay --autoactivation event $vg2
check lv_field $vg2/$lv1 lv_active "active"
# Count io to check the pvs_online optimization
# is working to limit scanning.
vgchange -an
_clear_online_files
pvscan --cache "$dev1"
pvscan --cache "$dev2"
strace -e io_submit vgchange -aay --autoactivation event $vg1 2>&1|tee trace.out
test "$(grep io_submit trace.out | wc -l)" -eq 4
rm trace.out
strace -e io_submit pvscan --cache "$dev3" 2>&1|tee trace.out
test "$(grep io_submit trace.out | wc -l)" -eq 1
rm trace.out
strace -e io_submit vgchange -aay --autoactivation event $vg2 2>&1|tee trace.out
test "$(grep io_submit trace.out | wc -l)" -eq 2
rm trace.out
# non-standard usage: no VG name arg, vgchange will only used pvs_online files
vgchange -an
_clear_online_files
vgchange -aay --autoactivation event
check lv_field $vg1/$lv1 lv_active ""
check lv_field $vg1/$lv2 lv_active ""
check lv_field $vg2/$lv1 lv_active ""
pvscan --cache "$dev1"
vgchange -aay --autoactivation event
check lv_field $vg1/$lv1 lv_active ""
check lv_field $vg1/$lv2 lv_active ""
check lv_field $vg2/$lv1 lv_active ""
pvscan --cache "$dev2"
vgchange -aay --autoactivation event
check lv_field $vg1/$lv1 lv_active "active"
check lv_field $vg1/$lv2 lv_active "active"
check lv_field $vg2/$lv1 lv_active ""
pvscan --cache "$dev3"
vgchange -aay --autoactivation event
check lv_field $vg2/$lv1 lv_active "active"
# non-standard usage: include VG name arg, but missing or incomplete pvs_online files
vgchange -an
_clear_online_files
# all missing pvs_online, vgchange falls back to full label scan
vgchange -aay --autoactivation event $vg1
check lv_field $vg1/$lv1 lv_active "active"
check lv_field $vg1/$lv2 lv_active "active"
vgchange -an
_clear_online_files
# incomplete pvs_online, vgchange falls back to full label scan
pvscan --cache "$dev1"
vgchange -aay --autoactivation event $vg1
check lv_field $vg1/$lv1 lv_active "active"
check lv_field $vg1/$lv2 lv_active "active"
vgchange -an
_clear_online_files
# incomplete pvs_online, pvs_online from different vg,
# no pvs_online found for vg arg so vgchange falls back to full label scan
pvscan --cache "$dev3"
vgchange -aay --autoactivation event $vg1
check lv_field $vg1/$lv1 lv_active "active"
check lv_field $vg1/$lv2 lv_active "active"
check lv_field $vg2/$lv1 lv_active ""
vgchange -aay --autoactivation event $vg2
check lv_field $vg2/$lv1 lv_active "active"
vgchange -an
_clear_online_files
# same tests but using command options matching udev rule
pvscan --cache --listvg --checkcomplete --vgonline --autoactivation event --udevoutput --journal=output "$dev1"
pvscan --cache --listvg --checkcomplete --vgonline --autoactivation event --udevoutput --journal=output "$dev2"
vgchange -aay --autoactivation event $vg1
check lv_field $vg1/$lv1 lv_active "active"
check lv_field $vg1/$lv2 lv_active "active"
check lv_field $vg2/$lv1 lv_active ""
pvscan --cache --listvg --checkcomplete --vgonline --autoactivation event --udevoutput --journal=output "$dev3"
vgchange -aay --autoactivation event $vg2
check lv_field $vg2/$lv1 lv_active "active"
vgchange -an $vg1
vgchange -an $vg2
# with a full pvscan --cache
_clear_online_files
pvscan --cache
check lv_field $vg1/$lv1 lv_active ""
check lv_field $vg2/$lv1 lv_active ""
vgchange -aay --autoactivation event $vg1
vgchange -aay --autoactivation event $vg2
check lv_field $vg1/$lv1 lv_active "active"
check lv_field $vg2/$lv1 lv_active "active"
vgchange -an $vg1
vgchange -an $vg2
vgremove -f $vg1
vgremove -f $vg2

View File

@@ -86,7 +86,7 @@ static void *_fix_init(struct io_engine *engine)
}
if (!_runs_is_tmpfs) {
close(f->fd);
(void) close(f->fd);
// reopen with O_DIRECT
f->fd = open(f->fname, O_RDWR | O_DIRECT);
T_ASSERT(f->fd >= 0);

View File

@@ -87,6 +87,12 @@ 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 autoactivation is being used from an event.\n"
"This allows the command to apply settings that are specific\n"
"to event activation, such as device scanning optimizations\n"
"using pvs_online files created by event-based pvscans.\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"
@@ -278,11 +284,6 @@ arg(errorwhenfull_ARG, '\0', "errorwhenfull", bool_VAL, 0, 0,
"(Also see dm-thin-pool kernel module option no_space_timeout.)\n"
"See \\fBlvmthin\\fP(7) for more information.\n")
arg(eventactivation_ARG, '\0', "eventactivation", string_VAL, 0, 0,
"Specify if the command is running autoactivation from an event\n"
"or a fixed service. The lvm.conf event_activation_options setting\n"
"determines if event or service based activation commands are used.\n")
arg(force_long_ARG, '\0', "force", 0, ARG_COUNTABLE, 0,
"Force metadata restore even with thin pool LVs.\n"
"Use with extreme caution. Most changes to thin metadata\n"

View File

@@ -1642,7 +1642,7 @@ DESC: Record that a PV is online or offline.
pvscan --cache_long --activate ay
OO: --ignorelockingfailure, --reportformat ReportFmt,
--major Number, --minor Number, --noudevsync, --eventactivation String
--major Number, --minor Number, --noudevsync, --autoactivation String
OP: PV|String ...
IO: --background
ID: pvscan_cache
@@ -1650,7 +1650,7 @@ DESC: Record that a PV is online and autoactivate the VG if complete.
pvscan --cache_long --listvg PV
OO: --ignorelockingfailure, --checkcomplete, --vgonline, --udevoutput,
--eventactivation String
--autoactivation String
ID: pvscan_cache
DESC: Record that a PV is online and list the VG using the PV.
@@ -1749,7 +1749,7 @@ DESC: Start or stop processing LV conversions.
vgchange --activate Active
OO: --activationmode ActivationMode, --ignoreactivationskip, --partial, --sysinit,
--readonly, --ignorelockingfailure, --monitor Bool, --poll Bool,
--vgonline, --eventactivation String, OO_VGCHANGE
--autoactivation String, OO_VGCHANGE
OP: VG|Tag|Select ...
IO: --ignoreskippedcluster
ID: vgchange_activate

View File

@@ -2393,8 +2393,10 @@ static void _reset_current_settings_to_default(struct cmd_context *cmd)
static void _get_current_output_settings_from_args(struct cmd_context *cmd)
{
if (arg_is_set(cmd, udevoutput_ARG))
if (arg_is_set(cmd, udevoutput_ARG)) {
cmd->current_settings.suppress = 1;
cmd->udevoutput = 1;
}
if (arg_is_set(cmd, debug_ARG))
cmd->current_settings.debug = _LOG_FATAL + (arg_count(cmd, debug_ARG) - 1);
@@ -2540,8 +2542,6 @@ static int _get_current_settings(struct cmd_context *cmd)
if (!strcmp(hint_mode, "none")) {
cmd->enable_hints = 0;
cmd->use_hints = 0;
} else if (!strcmp(hint_mode, "pvs_online")) {
cmd->hints_pvs_online = 1;
}
}

View File

@@ -176,6 +176,9 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
log_error("Failed to read the devices file.");
return ECMD_FAILED;
}
prepare_open_file_limit(cmd, dm_list_size(&cmd->use_devices));
dev_cache_scan(cmd);
device_ids_match(cmd);

View File

@@ -18,11 +18,10 @@
#include "lib/cache/lvmcache.h"
#include "lib/metadata/metadata.h"
#include "lib/label/hints.h"
#include "lib/device/online.h"
#include <dirent.h>
int online_pvid_file_read(char *path, int *major, int *minor, char *vgname);
struct pvscan_params {
int new_pvs_found;
int pvs_found;
@@ -44,12 +43,6 @@ struct pvscan_aa_params {
*/
static struct volume_group *saved_vg;
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)
@@ -183,171 +176,12 @@ 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_to_event"
* . both services and events are used for activation
* . fixed services are used for activation initially,
* and last service enables event based activation
* by creating the event-activation-on file
*
* vgchange -aay --eventactivation service
* . does activation only if event-activation-on does not exist
* vgchange -aay --eventactivation event
* . does activation only if event-activation-on exists
* vgchange -aay --eventactivation service,on
* . does activation only if event-activation-on does not exist
* . creates event-activation-on to enable event-based activation
* vgchange --eventactivation on|off
* . create or remove event-activation-on to enable|disable
* event-based activation
* pvscan --eventactivation event
* . does activation only if event-activation-on exists
*
*/
int event_activation_enable(struct cmd_context *cmd)
{
FILE *fp;
if (!(fp = fopen(_event_activation_file, "w")))
return_0;
if (fclose(fp))
stack;
return 1;
}
int event_activation_is_on(struct cmd_context *cmd)
{
struct stat buf;
if (!stat(_event_activation_file, &buf))
return 1;
if (errno != ENOENT)
log_debug("event_activation_is_on errno %d", errno);
return 0;
}
/*
* Avoid a duplicate pvscan[%d] prefix when logging to the journal.
* FIXME: this should probably replace if (udevoutput) with
* if (log_journal & LOG_JOURNAL_OUTPUT)
*/
#define log_print_pvscan(cmd, fmt, args...) \
do \
if (arg_is_set(cmd, udevoutput_ARG)) \
log_print(fmt, ##args); \
else \
log_print("pvscan[%d] " fmt, getpid(), ##args); \
while (0)
#define log_error_pvscan(cmd, fmt, args...) \
do \
if (arg_is_set(cmd, udevoutput_ARG)) \
log_error(fmt, ##args); \
else \
log_error("pvscan[%d] " fmt, getpid(), ##args); \
while (0)
static char *_vgname_in_pvid_file_buf(char *buf)
{
char *p, *n;
/*
* file contains:
* <major>:<minor>\n
* vg:<vgname>\n\0
*/
if (!(p = strchr(buf, '\n')))
return NULL;
p++; /* skip \n */
if (*p && !strncmp(p, "vg:", 3)) {
if ((n = strchr(p, '\n')))
*n = '\0';
return p + 3;
}
return NULL;
}
#define MAX_PVID_FILE_SIZE 512
int online_pvid_file_read(char *path, int *major, int *minor, char *vgname)
{
char buf[MAX_PVID_FILE_SIZE] = { 0 };
char *name;
int fd, rv;
fd = open(path, O_RDONLY);
if (fd < 0) {
log_warn("Failed to open %s", path);
return 0;
}
rv = read(fd, buf, sizeof(buf) - 1);
if (close(fd))
log_sys_debug("close", path);
if (!rv || rv < 0) {
log_warn("No info in %s", path);
return 0;
}
buf[rv] = 0; /* \0 terminated buffer */
if (sscanf(buf, "%d:%d", major, minor) != 2) {
log_warn("No device numbers in %s", path);
return 0;
}
/* vgname points to an offset in buf */
if ((name = _vgname_in_pvid_file_buf(buf)))
strncpy(vgname, name, NAME_LEN);
else
log_debug("No vgname in %s", path);
return 1;
}
static void _lookup_file_remove(char *vgname)
{
char path[PATH_MAX];
if (dm_snprintf(path, sizeof(path), "%s/%s", _pvs_lookup_dir, vgname) < 0) {
log_error("Path %s/%s is too long.", _pvs_lookup_dir, vgname);
if (dm_snprintf(path, sizeof(path), "%s/%s", PVS_LOOKUP_DIR, vgname) < 0) {
log_error("Path %s/%s is too long.", PVS_LOOKUP_DIR, vgname);
return;
}
@@ -357,27 +191,6 @@ static void _lookup_file_remove(char *vgname)
log_sys_debug("unlink", path);
}
/*
* When a PV goes offline, remove the vg online file for that VG
* (even if other PVs for the VG are still online). This means
* that the vg will be activated again when it becomes complete.
*/
void online_vg_file_remove(const char *vgname)
{
char path[PATH_MAX];
if (dm_snprintf(path, sizeof(path), "%s/%s", _vgs_online_dir, vgname) < 0) {
log_error("Path %s/%s is too long.", _vgs_online_dir, vgname);
return;
}
log_debug("Unlink vg online: %s", path);
if (unlink(path) && (errno != ENOENT))
log_sys_debug("unlink", path);
}
/*
* When a device goes offline we only know its major:minor, not its PVID.
* Since the dev isn't around, we can't read it to get its PVID, so we have to
@@ -396,7 +209,7 @@ static void _online_pvid_file_remove_devno(int major, int minor)
log_debug("Remove pv online devno %d:%d", major, minor);
if (!(dir = opendir(_pvs_online_dir)))
if (!(dir = opendir(PVS_ONLINE_DIR)))
return;
while ((de = readdir(dir))) {
@@ -404,7 +217,7 @@ static void _online_pvid_file_remove_devno(int major, int minor)
continue;
memset(path, 0, sizeof(path));
snprintf(path, sizeof(path), "%s/%s", _pvs_online_dir, de->d_name);
snprintf(path, sizeof(path), "%s/%s", PVS_ONLINE_DIR, de->d_name);
file_major = 0;
file_minor = 0;
@@ -424,7 +237,7 @@ static void _online_pvid_file_remove_devno(int major, int minor)
}
}
if (closedir(dir))
log_sys_debug("closedir", _pvs_online_dir);
log_sys_debug("closedir", PVS_ONLINE_DIR);
}
static void _online_files_remove(const char *dirpath)
@@ -449,132 +262,6 @@ static void _online_files_remove(const char *dirpath)
log_sys_debug("closedir", dirpath);
}
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 };
char file_vgname[NAME_LEN];
int file_major = 0, file_minor = 0;
int major, minor;
int fd;
int rv;
int len;
int len1 = 0;
int len2 = 0;
major = (int)MAJOR(dev->dev);
minor = (int)MINOR(dev->dev);
if (dm_snprintf(path, sizeof(path), "%s/%s", _pvs_online_dir, dev->pvid) < 0) {
log_error_pvscan(cmd, "Path %s/%s is too long.", _pvs_online_dir, dev->pvid);
return 0;
}
if ((len1 = dm_snprintf(buf, sizeof(buf), "%d:%d\n", major, minor)) < 0) {
log_error_pvscan(cmd, "Cannot create online file path for %s %d:%d.", dev_name(dev), major, minor);
return 0;
}
if (vgname) {
if ((len2 = dm_snprintf(buf + len1, sizeof(buf) - len1, "vg:%s\n", vgname)) < 0) {
log_print_pvscan(cmd, "Incomplete online file for %s %d:%d vg %s.", dev_name(dev), major, minor, vgname);
/* can still continue without vgname */
len2 = 0;
}
}
len = len1 + len2;
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 (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;
}
while (len > 0) {
rv = write(fd, buf, len);
if (rv < 0) {
/* file exists so it still works in part */
log_warn("Cannot write online file for %s to %s error %d",
dev_name(dev), path, errno);
if (close(fd))
log_sys_debug("close", path);
return 1;
}
len -= rv;
}
/* We don't care about syncing, these files are not even persistent. */
if (close(fd))
log_sys_debug("close", path);
return 1;
check_duplicate:
/*
* If a PVID online file already exists for this PVID, check if the
* file contains a different device number, and if so we may have a
* duplicate PV.
*
* FIXME: disable autoactivation of the VG somehow?
* The VG may or may not already be activated when a dupicate appears.
* Perhaps write a new field in the pv online or vg online file?
*/
memset(file_vgname, 0, sizeof(file_vgname));
online_pvid_file_read(path, &file_major, &file_minor, file_vgname);
if ((file_major == major) && (file_minor == minor)) {
log_debug("Existing online file for %d:%d", major, minor);
return 1;
}
/* Don't know how vgname might not match, but it's not good so fail. */
if ((file_major != major) || (file_minor != minor))
log_error_pvscan(cmd, "PV %s is duplicate for PVID %s on %d:%d and %d:%d.",
dev_name(dev), dev->pvid, major, minor, file_major, file_minor);
if (file_vgname[0] && vgname && strcmp(file_vgname, vgname))
log_error_pvscan(cmd, "PV %s has unexpected VG %s vs %s.",
dev_name(dev), vgname, file_vgname);
return 0;
}
static int _online_pvid_file_exists(const char *pvid)
{
char path[PATH_MAX] = { 0 };
struct stat buf;
int rv;
if (dm_snprintf(path, sizeof(path), "%s/%s", _pvs_online_dir, pvid) < 0) {
log_debug(INTERNAL_ERROR "Path %s/%s is too long.", _pvs_online_dir, pvid);
return 0;
}
log_debug("Check pv online: %s", path);
rv = stat(path, &buf);
if (!rv) {
log_debug("Check pv online %s: yes", pvid);
return 1;
}
log_debug("Check pv online %s: no", pvid);
return 0;
}
static int _write_lookup_file(struct cmd_context *cmd, struct volume_group *vg)
{
char path[PATH_MAX];
@@ -582,8 +269,8 @@ static int _write_lookup_file(struct cmd_context *cmd, struct volume_group *vg)
struct pv_list *pvl;
int fd;
if (dm_snprintf(path, sizeof(path), "%s/%s", _pvs_lookup_dir, vg->name) < 0) {
log_error_pvscan(cmd, "Path %s/%s is too long.", _pvs_lookup_dir, vg->name);
if (dm_snprintf(path, sizeof(path), "%s/%s", PVS_LOOKUP_DIR, vg->name) < 0) {
log_error_pvscan(cmd, "Path %s/%s is too long.", PVS_LOOKUP_DIR, vg->name);
return 0;
}
@@ -639,7 +326,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)++;
@@ -700,8 +387,8 @@ static int _count_pvid_files_from_lookup_file(struct cmd_context *cmd, struct de
*pvs_online = 0;
*pvs_offline = 0;
if (!(dir = opendir(_pvs_lookup_dir))) {
log_sys_debug("opendir", _pvs_lookup_dir);
if (!(dir = opendir(PVS_LOOKUP_DIR))) {
log_sys_debug("opendir", PVS_LOOKUP_DIR);
return 0;
}
@@ -713,8 +400,8 @@ static int _count_pvid_files_from_lookup_file(struct cmd_context *cmd, struct de
if (de->d_name[0] == '.')
continue;
if (dm_snprintf(path, sizeof(path), "%s/%s", _pvs_lookup_dir, de->d_name) < 0) {
log_warn("WARNING: Path %s/%s is too long.", _pvs_lookup_dir, de->d_name);
if (dm_snprintf(path, sizeof(path), "%s/%s", PVS_LOOKUP_DIR, de->d_name) < 0) {
log_warn("WARNING: Path %s/%s is too long.", PVS_LOOKUP_DIR, de->d_name);
continue;
}
@@ -739,68 +426,13 @@ static int _count_pvid_files_from_lookup_file(struct cmd_context *cmd, struct de
log_sys_debug("fclose", path);
}
if (closedir(dir))
log_sys_debug("closedir", _pvs_lookup_dir);
log_sys_debug("closedir", PVS_LOOKUP_DIR);
*vgname_out = vgname;
return (vgname) ? 1 : 0;
}
void online_dir_setup(struct cmd_context *cmd)
{
struct stat st;
int rv;
if (!stat(DEFAULT_RUN_DIR, &st))
goto do_pvs;
log_debug("Creating run_dir.");
dm_prepare_selinux_context(DEFAULT_RUN_DIR, S_IFDIR);
rv = mkdir(DEFAULT_RUN_DIR, 0755);
dm_prepare_selinux_context(NULL, 0);
if ((rv < 0) && stat(DEFAULT_RUN_DIR, &st))
log_error_pvscan(cmd, "Failed to create %s %d", DEFAULT_RUN_DIR, errno);
do_pvs:
if (!stat(_pvs_online_dir, &st))
goto do_vgs;
log_debug("Creating pvs_online_dir.");
dm_prepare_selinux_context(_pvs_online_dir, S_IFDIR);
rv = mkdir(_pvs_online_dir, 0755);
dm_prepare_selinux_context(NULL, 0);
if ((rv < 0) && stat(_pvs_online_dir, &st))
log_error_pvscan(cmd, "Failed to create %s %d", _pvs_online_dir, errno);
do_vgs:
if (!stat(_vgs_online_dir, &st))
goto do_lookup;
log_debug("Creating vgs_online_dir.");
dm_prepare_selinux_context(_vgs_online_dir, S_IFDIR);
rv = mkdir(_vgs_online_dir, 0755);
dm_prepare_selinux_context(NULL, 0);
if ((rv < 0) && stat(_vgs_online_dir, &st))
log_error_pvscan(cmd, "Failed to create %s %d", _vgs_online_dir, errno);
do_lookup:
if (!stat(_pvs_lookup_dir, &st))
return;
log_debug("Creating pvs_lookup_dir.");
dm_prepare_selinux_context(_pvs_lookup_dir, S_IFDIR);
rv = mkdir(_pvs_lookup_dir, 0755);
dm_prepare_selinux_context(NULL, 0);
if ((rv < 0) && stat(_pvs_lookup_dir, &st))
log_error_pvscan(cmd, "Failed to create %s %d", _pvs_lookup_dir, errno);
}
static void _count_pvid_files(struct volume_group *vg, int *pvs_online, int *pvs_offline)
{
char pvid[ID_LEN + 1] __attribute__((aligned(8))) = { 0 };
@@ -811,7 +443,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)++;
@@ -842,32 +474,6 @@ static int _pvscan_aa_single(struct cmd_context *cmd, const char *vg_name,
return ECMD_PROCESSED;
}
int online_vg_file_create(struct cmd_context *cmd, const char *vgname)
{
char path[PATH_MAX];
int fd;
if (dm_snprintf(path, sizeof(path), "%s/%s", _vgs_online_dir, vgname) < 0) {
log_error_pvscan(cmd, "Path %s/%s is too long.", _vgs_online_dir, vgname);
return 0;
}
log_debug("Create vg online: %s", path);
fd = open(path, O_CREAT | O_EXCL | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
if (fd < 0) {
log_debug("Failed to create %s: %d", path, errno);
return 0;
}
/* We don't care about syncing, these files are not even persistent. */
if (close(fd))
log_sys_debug("close", path);
return 1;
}
/*
* This is a very unconventional way of doing things because
* we want to figure out which devices to read the VG from
@@ -927,7 +533,7 @@ static int _get_devs_from_saved_vg(struct cmd_context *cmd, const char *vgname,
memcpy(pvid, &pvl->pv->id.uuid, ID_LEN);
memset(path, 0, sizeof(path));
snprintf(path, sizeof(path), "%s/%s", _pvs_online_dir, pvid);
snprintf(path, sizeof(path), "%s/%s", PVS_ONLINE_DIR, pvid);
file_major = 0;
file_minor = 0;
@@ -1195,17 +801,11 @@ static int _pvscan_aa(struct cmd_context *cmd, struct pvscan_aa_params *pp,
* PROCESS_SKIP_SCAN: we have already done lvmcache_label_scan
* so tell process_each to skip it.
*/
if (do_all)
read_flags |= PROCESS_SKIP_SCAN;
/*
* When the command is processing specific devs (not all), it
* has done setup_devices_no_file_match() to avoid matching ids
* fo all devs unnecessarily, but now that we're falling back
* to process_each_vg() we need to complete the id matching.
*/
if (!do_all)
device_ids_match(cmd);
lvmcache_label_scan(cmd);
read_flags |= PROCESS_SKIP_SCAN;
ret = process_each_vg(cmd, 0, NULL, NULL, vgnames, read_flags, 0, handle, _pvscan_aa_single);
}
@@ -1332,7 +932,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;
@@ -1340,7 +940,7 @@ static void _set_pv_devices_online(struct cmd_context *cmd, struct volume_group
}
memset(path, 0, sizeof(path));
snprintf(path, sizeof(path), "%s/%s", _pvs_online_dir, pvid);
snprintf(path, sizeof(path), "%s/%s", PVS_ONLINE_DIR, pvid);
major = 0;
minor = 0;
@@ -1454,7 +1054,7 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
devsize = dev->size;
if (!devsize &&
!dev_get_size(dev, &devsize)) {
log_print("pvscan[%d] PV %s can get device size.", getpid(), dev_name(dev));
log_print_pvscan(cmd, "PV %s missing device size.", dev_name(dev));
release_vg(vg);
continue;
}
@@ -1512,7 +1112,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, 0, NULL)) {
if (do_cache && !online_pvid_file_create(cmd, dev, vg ? vg->name : NULL)) {
log_error_pvscan(cmd, "PV %s failed to create online file.", dev_name(dev));
release_vg(vg);
ret = 0;
@@ -1703,9 +1303,9 @@ static int _pvscan_cache_all(struct cmd_context *cmd, int argc, char **argv,
dm_list_init(&pvscan_devs);
_online_files_remove(_pvs_online_dir);
_online_files_remove(_vgs_online_dir);
_online_files_remove(_pvs_lookup_dir);
_online_files_remove(PVS_ONLINE_DIR);
_online_files_remove(VGS_ONLINE_DIR);
_online_files_remove(PVS_LOOKUP_DIR);
unlink_searched_devnames(cmd);
@@ -1769,7 +1369,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
@@ -1778,7 +1378,7 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv,
* Does not do dev_cache_scan (adds nothing to dev-cache), and
* does not do any device id matching.
*/
if (!setup_devices_for_pvscan_cache(cmd)) {
if (!setup_devices_for_online_autoactivation(cmd)) {
log_error_pvscan(cmd, "Failed to set up devices.");
return 0;
}
@@ -1892,7 +1492,7 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv,
int has_pvid;
if (!label_read_pvid(devl->dev, &has_pvid)) {
log_print("pvscan[%d] %s cannot read.", getpid(), dev_name(devl->dev));
log_print_pvscan(cmd, "%s cannot read label.", dev_name(devl->dev));
dm_list_del(&devl->list);
continue;
}
@@ -1959,13 +1559,35 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv,
return ret;
}
static int _get_autoactivation(struct cmd_context *cmd, int event_activation, int *skip_command)
{
const char *aa_str;
if (!(aa_str = arg_str_value(cmd, autoactivation_ARG, NULL)))
return 1;
if (strcmp(aa_str, "event")) {
log_print_pvscan(cmd, "Skip pvscan for unknown autoactivation value.");
*skip_command = 1;
return 1;
}
if (!event_activation) {
log_print_pvscan(cmd, "Skip pvscan for event with event_activation=0.");
*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;
const char *ea;
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;
@@ -2038,34 +1660,11 @@ int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv)
return ECMD_PROCESSED;
}
if (!_get_autoactivation(cmd, event_activation, &skip_command))
return_ECMD_FAILED;
if ((ea = arg_str_value(cmd, eventactivation_ARG, NULL))) {
int service_only = 0, event_only = 0, service_to_event = 0;
int ea_service = 0, ea_event = 0, ea_on = 0;
if (!get_event_activation_config_settings(cmd, &service_only, &event_only, &service_to_event))
return ECMD_FAILED;
if (!get_event_activation_command_options(cmd, ea, &ea_service, &ea_event, &ea_on))
return ECMD_FAILED;
if (ea_event) {
if (!event_activation) {
log_print("Skip pvscan for event and event_activation=0.");
return ECMD_PROCESSED;
}
if (service_only) {
log_print("Skip pvscan for event and event_activation_options service_only.");
return ECMD_PROCESSED;
}
if (service_to_event && !event_activation_is_on(cmd)) {
log_print("Skip pvscan for event and no event-activation-on.");
return ECMD_PROCESSED;
}
} else {
log_error("Option --eventactivation %s is not used by pvscan.", ea);
return ECMD_FAILED;
}
}
if (skip_command)
return ECMD_PROCESSED;
if (!_pvscan_cache_args(cmd, argc, argv, &complete_vgnames))
return ECMD_FAILED;

View File

@@ -17,6 +17,7 @@
#include "lib/format_text/format-text.h"
#include "lib/label/hints.h"
#include "lib/device/device_id.h"
#include "lib/device/online.h"
#include <sys/stat.h>
#include <signal.h>
@@ -5714,90 +5715,3 @@ bad:
out:
return 0;
}
int get_event_activation_config_settings(struct cmd_context *cmd,
int *service_only, int *event_only, int *service_to_event)
{
const struct dm_config_node *cn;
const struct dm_config_value *cv;
int eo = 0, so = 0, se = 0;
if (!(cn = find_config_tree_array(cmd, global_event_activation_options_CFG, NULL)))
return 1;
for (cv = cn->v; cv; cv = cv->next) {
if (cv->type != DM_CFG_STRING)
continue;
if (!strcmp(cv->v.str, "service_only"))
so = 1;
else if (!strcmp(cv->v.str, "event_only"))
eo = 1;
else if (!strcmp(cv->v.str, "service_to_event"))
se = 1;
else if (strlen(cv->v.str) > 0)
log_warn("WARNING: ignoring unrecognized event_activation_options value %s.", cv->v.str);
}
if (se && (so || eo)) {
log_warn("WARNING: ignoring incompatible event_activation_options, using service_to_event.");
*service_to_event = 1;
} else if (so && eo) {
log_warn("WARNING: ignoring incompatible event_activation_options, using event_only.");
*event_only = 1;
} else if (se) {
*service_to_event = 1;
} else if (so) {
*service_only = 1;
} else if (eo) {
*event_only = 1;
} else {
*service_to_event = 1;
}
return 1;
}
static int _ea_option_value(const char *val, int *ea_service, int *ea_event, int *ea_on)
{
if (!strcmp(val, "service"))
*ea_service = 1;
else if (!strcmp(val, "event"))
*ea_event = 1;
else if (!strcmp(val, "on"))
*ea_on = 1;
else {
log_error("Unknown --eventactivation value.");
return 0;
}
return 1;
}
int get_event_activation_command_options(struct cmd_context *cmd, const char *ea, int *ea_service, int *ea_event, int *ea_on)
{
char ea_vals[128] = {0};
char *val1, *val2;
strncpy(ea_vals, ea, 127);
/* Currently only two values can be used together. */
val1 = ea_vals;
if ((val2 = strchr(ea_vals, ','))) {
*val2 = '\0';
val2++;
}
if (val1 && !_ea_option_value(val1, ea_service, ea_event, ea_on))
return 0;
if (val2 && !_ea_option_value(val2, ea_service, ea_event, ea_on))
return 0;
if (*ea_service && *ea_event) {
log_error("Invalid --eventactivation options, service and event are incompatible.");
return 0;
}
return 1;
}

View File

@@ -237,9 +237,4 @@ int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv,
int get_lvt_enum(struct logical_volume *lv);
int get_event_activation_config_settings(struct cmd_context *cmd,
int *service_only, int *event_only, int *service_to_event);
int get_event_activation_command_options(struct cmd_context *cmd,
const char *ea, int *ea_service, int *ea_event, int *ea_on);
#endif

View File

@@ -226,8 +226,9 @@ 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, int vg_complete_to_activate);
activation_change_t activate, int vg_complete_to_activate);
int vgchange_background_polling(struct cmd_context *cmd, struct volume_group *vg);
@@ -294,11 +295,4 @@ int lvconvert_cachevol_attach_single(struct cmd_context *cmd,
struct logical_volume *lv,
struct processing_handle *handle);
int online_pvid_file_create(struct cmd_context *cmd, struct device *dev, const char *vgname, int ignore_existing, int *exists);
void online_vg_file_remove(const char *vgname);
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

View File

@@ -15,6 +15,7 @@
#include "tools.h"
#include "lib/device/device_id.h"
#include "lib/label/hints.h"
struct vgchange_params {
int lock_start_count;
@@ -195,41 +196,6 @@ 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, int vg_complete_to_activate)
{
@@ -256,11 +222,6 @@ 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) {
@@ -751,9 +712,6 @@ 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, vp->vg_complete_to_activate))
@@ -777,106 +735,28 @@ static int _vgchange_single(struct cmd_context *cmd, const char *vg_name,
return ret;
}
static int _check_event_activation(struct cmd_context *cmd, struct vgchange_params *vp, int *skip_command, int *enable_events)
static int _check_autoactivation(struct cmd_context *cmd, struct vgchange_params *vp, int *skip_command)
{
const char *ea;
int service_only = 0, event_only = 0, service_to_event = 0;
int ea_service = 0, ea_event = 0, ea_on = 0;
int on_file_exists;
int event_activation;
const char *aa;
if (!(ea = arg_str_value(cmd, eventactivation_ARG, NULL))) {
log_error("No eventactivation value.");
return 0;
if (!(aa = arg_str_value(cmd, autoactivation_ARG, NULL)))
return 1;
if (strcmp(aa, "event")) {
log_print("Skip vgchange for unknown autoactivation value.");
*skip_command = 1;
return 1;
}
/* lvm.conf event_activation_options */
if (!get_event_activation_config_settings(cmd, &service_only, &event_only, &service_to_event))
return_0;
/* --eventactivation values */
if (!get_event_activation_command_options(cmd, ea, &ea_service, &ea_event, &ea_on))
return_0;
event_activation = find_config_tree_bool(cmd, global_event_activation_CFG, NULL);
/*
* The combination of lvm.conf event_activation/event_activation_options
* and the --eventactivation service|event value determines if this
* command should do anything or be skipped, along with the existence of
* the /run/lvm/event-activation-on file in case of service_to_event.
*/
if (!event_activation) {
if (ea_event) {
log_print("Skip vgchange for event and event_activation=0.");
*skip_command = 1;
return 1;
}
} else {
if (event_only && ea_service) {
log_print("Skip vgchange for service and event_activation_options event_only.");
*skip_command = 1;
return 1;
}
if (service_only && ea_event) {
log_print("Skip vgchange for event and event_activation_options service_only.");
*skip_command = 1;
return 1;
}
on_file_exists = event_activation_is_on(cmd);
if (service_to_event && ea_service && on_file_exists) {
log_print("Skip vgchange for service and event-activation-on.");
*skip_command = 1;
return 1;
}
if (service_to_event && ea_event && !on_file_exists) {
log_print("Skip vgchange for event and no event-activation-on.");
*skip_command = 1;
return 1;
}
if (!find_config_tree_bool(cmd, global_event_activation_CFG, NULL)) {
log_print("Skip vgchange for event and event_activation=0.");
*skip_command = 1;
return 1;
}
/*
* Switch from service activation to event activation when:
* lvm.conf event_activation=1,
* event_activation_options=service_to_event,
* and --eventactivation service,on.
*
* When enabling event-based activation, first create the
* /run/lvm/event-activation-on file to tell other commands
* to begin responding to PV events and doing activation
* for newly completed VGs. It also needs to create online
* files for existing PVs because some VGs may be incomplete
* at this point, and future pvscan commands need to
* find online files for PVs that have already appeared.
* The label scan provides info to know which PVs are
* present and should have pvid online files created.
*
* process_each_vg() usually begins with lock_global() and
* lvmcache_label_scan(), and then processes each VG.
* In this case, lock_global/lvmcache_label_scan are done
* before calling process_each_vg. This allows a special
* step to be inserted between the label scan and processing
* vgs. That step creates the pvid online files, which
* requires label scan info. The lock_global and
* lvmcache_label_scan will be skipped by process_each_vg
* since they are already done here.
*/
if (event_activation && service_to_event && ea_service && ea_on) {
if (!event_activation_enable(cmd))
log_warn("WARNING: Failed to create event-activation-on.");
*enable_events = 1;
}
vp->vg_complete_to_activate = 1;
/*
* lvm.conf service_to_event, and vgchange -aay --eventactivation service,
* then only activate LVs if the VG is complete.
* A later event will complete the VG and activate it.
*/
if (event_activation && service_to_event && ea_service)
vp->vg_complete_to_activate = 1;
cmd->use_hints = 0;
return 1;
}
@@ -885,6 +765,7 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv)
{
struct vgchange_params vp = { 0 };
struct processing_handle *handle;
char *vgname = NULL;
uint32_t flags = 0;
int ret;
@@ -997,21 +878,62 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv)
cmd->lockd_vg_enforce_sh = 1;
}
if (arg_is_set(cmd, eventactivation_ARG)) {
int skip_command = 0, enable_events = 0;
if (!_check_event_activation(cmd, &vp, &skip_command, &enable_events))
if (arg_is_set(cmd, autoactivation_ARG)) {
int found_none = 0, found_all = 0, found_incomplete = 0;
int skip_command = 0;
if (!_check_autoactivation(cmd, &vp, &skip_command))
return ECMD_FAILED;
if (skip_command)
return ECMD_PROCESSED;
if (enable_events) {
if (!event_activation_enable(cmd))
log_warn("WARNING: Failed to create event-activation-on.");
/* The process_each_vg lock_global/lvmcache_label_scan will be skipped. */
if (!lock_global(cmd, "sh"))
return ECMD_FAILED;
lvmcache_label_scan(cmd);
_online_pvid_file_create_all(cmd);
flags |= PROCESS_SKIP_SCAN;
/*
* Special label scan optimized for autoactivation
* that is based on info read from /run/lvm/ files
* created by pvscan --cache during autoactivation.
* Add an option to disable this optimization? e.g.
* "online_skip" in --autoactivation / auto_activation_settings
*
* In some cases it might be useful to strictly follow
* the online files, and not fall back to a standard
* label scan when no pvs or incomplete pvs are found
* from the online files. Add option for that? e.g.
* "online_only" in --autoactivation / auto_activation_settings
*
* Generally the way that vgchange -aay --autoactivation event
* is currently used, it will not be called until pvscan --cache
* has found the VG is complete, so it will not generally be
* following the paths that fall back to standard label_scan.
*
* TODO: Like pvscan_aa_quick, this could do lock_vol(vgname)
* before label_scan_vg_online, then set cmd->can_use_one_scan=1
* to avoid rescanning in _vg_read called by process_each_vg.
*/
get_single_vgname_cmd_arg(cmd, NULL, &vgname);
if (!label_scan_vg_online(cmd, vgname, &found_none, &found_all, &found_incomplete)) {
log_print("PVs online error%s%s, using all devices.", vgname ? " for VG " : "", vgname ?: "");
} else {
if (!vgname) {
/* Not expected usage, activate any VGs that are complete based on pvs_online. */
flags |= PROCESS_SKIP_SCAN;
} else if (found_all) {
/* The expected and optimal usage, only online PVs are read. */
flags |= PROCESS_SKIP_SCAN;
/*
} else if (online_only) {
log_print("PVs online %s.", found_none ? "not found" : "incomplete");
return vgname ? ECMD_FAILED : ECMD_PROCESSED;
*/
} else if (found_none) {
/* Not expected usage, use full label_scan in process_each */
log_print("PVs online not found for VG %s, using all devices.", vgname);
} else if (found_incomplete) {
/* Not expected usage, use full label_scan in process_each */
log_print("PVs online incomplete for VG %s, using all devicess.", vgname);
} else {
/* Shouldn't happen */
log_print("PVs online unknown for VG %s, using all devices.", vgname);
}
}
}

View File

@@ -172,6 +172,17 @@ int vgimportdevices(struct cmd_context *cmd, int argc, char **argv)
cmd->filter_regex_with_devices_file = 1;
cmd->create_edit_devices_file = 1;
/*
* This helps a user bootstrap existing shared VGs into the devices
* file. Reading the vg to import devices requires locking, but
* lockstart won't find the vg before it's in the devices file.
* So, allow importing devices without an lvmlockd lock (in a
* a shared vg the vg metadata won't be updated with device ids,
* so the lvmlockd lock isn't protecting vg modification.)
*/
cmd->lockd_gl_disable = 1;
cmd->lockd_vg_disable = 1;
/*
* For each VG:
* device_id_add() each PV in the VG

View File

@@ -121,6 +121,6 @@ LABEL="direct_pvscan"
# MD | | X | X* | |
# loop | | X | X* | |
# other | X | | X | | X
RUN+="(LVM_EXEC)/lvm pvscan --cache -aay --eventactivation event --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"

View File

@@ -78,19 +78,9 @@ ENV{SYSTEMD_READY}="1"
#
# TODO: adjust the output of vgchange -aay so that
# it's better suited to appearing in the journal.
#
# "--eventactivation event" used with pvscan or vgchange
# tells the command that it is being run from an event.
# The command does nothing if lvm.conf event_activation=0.
# The command does nothing if lvm.conf event_activation=1,
# and lvm.conf event_activation_options="service_only".
# The command goes ahead if event_activation_options="event_only",
# or if event_activation_options="service_to_event" and the
# event-activation-on file exists.
#
IMPORT{program}="(LVM_EXEC)/lvm pvscan --cache --listvg --checkcomplete --vgonline --eventactivation event --udevoutput --journal=output $env{DEVNAME}"
ENV{LVM_VG_NAME_COMPLETE}=="?*", RUN+="/usr/bin/systemd-run -r --no-block --property DefaultDependencies=no --unit lvm-activate-$env{LVM_VG_NAME_COMPLETE} lvm vgchange -aay --config devices/hints=pvs_online --eventactivation event $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"