1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-09-16 17:44:24 +03:00

Compare commits

..

4 Commits

Author SHA1 Message Date
David Teigland
5e48b04561 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-18 16:24:24 -05:00
David Teigland
3e893b9b09 hints: new pvs_online type
Use a new form of hints to reduce device scanning in
vgchange -aay run by the udev rule for event based
autoactivation.

Standard hints allow a command with a named VG arg to scan
only the PVs in the named VG, rather than scanning all
available PVs.  Standard hints are useful with a stable set
of system devices.  When new devices are arriving, as occurs
during system startup, the hints are repeatedly invalidated,
which makes standard hints unhelpful while devices are
regularly appearing.  This is the situation in which
vgchange -aay is used, so standard hints are not generally
helpful for autoactivation.

In the context of system startup, pvscan --cache is keeping
track of available PVs using the pvs_online files, similar
to what the hints file does for a running system.  Given this,
a new hint mode, hints = "pvs_online", is added which derives
an equivalent to standard hints, based on pvs_online files
that are being created by udev-run pvscans.  This hint mode
is useful while devices are appearing, e.g. during system
startup, and vgchange -aay can benefit from it.

pvscan --cache -aay autoactivation already has a similar
optimization (the "quick" activation case) that is based
on the pvs_online file, but it is not implemented as a
form of hints.

This new form of hints is mainly useful in the context of
event based autoactivation, during which standard hints are
not useful.  Once the system is in a steady state after startup
(devices are not regularly appearing), the standard hints are
most useful.  The pvs_online hint method could be used on a
running system, but would be no better than standard hints,
and may be inferior because pvs_online files are not rigidly
updated after system startup.
2021-10-15 16:27:04 -05:00
David Teigland
c06d5fe28e add fixed event activation services
Add two new fixed activation services for startup:
lvm-activate-vgs-main and lvm-activate-vgs-last.

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

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

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

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

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

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

service_to_event: the -main and -last services will
activate VGs that are complete at the time the
services run, and VGs that appear later will be
activated from per-VG event-based activation
commands.
2021-10-15 16:25:01 -05:00
David Teigland
4f1957ee50 vgchange: add vgonline option
Using --vgonline with vgchange -aay makes vgchange use
/run/lvm/vgs_online/ files in the same way as pvscan.
If the online file for the vg does not exist and the
command is able to exclusively create it, then it will
activate the VG.  If the online file exists or the create
fails, then the VG will not be activated.
2021-10-15 12:59:03 -05:00
54 changed files with 1385 additions and 1285 deletions

View File

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

View File

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

View File

@@ -1,9 +1,5 @@
Version 2.03.15 -
===================================
Version 2.03.14 - 20th October 2021
===================================
Device scanning is skipping directories on different filesystems.
Version 2.03.14 -
==================================
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.
@@ -11,7 +7,7 @@ Version 2.03.14 - 20th October 2021
Filter out unsupported MQ/SMQ cache policy setting.
Fix memleak in mpath filter.
Support newer location for VDO statistics.
Add support for VDO async-unsafe write policy.
Add support for VDO async-unsage write policy.
Improve lvm_import_vdo script.
Support VDO LV with lvcreate -ky.
Fix lvconvert for VDO LV bigger then 2T.

View File

@@ -1,8 +1,5 @@
Version 1.02.183 -
====================================
Version 1.02.181 - 20th October 2021
====================================
Version 1.02.181 -
===================================
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
BLKID_LIBS
BLKID_CFLAGS
SYSTEMD_LIBS
SYSTEMD_CFLAGS
BLKID_LIBS
BLKID_CFLAGS
LOCKD_IDM_LIBS
LOCKD_IDM_CFLAGS
LOCKD_DLM_CONTROL_LIBS
@@ -964,6 +964,7 @@ 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
@@ -1028,10 +1029,10 @@ LOCKD_DLM_CONTROL_CFLAGS
LOCKD_DLM_CONTROL_LIBS
LOCKD_IDM_CFLAGS
LOCKD_IDM_LIBS
SYSTEMD_CFLAGS
SYSTEMD_LIBS
BLKID_CFLAGS
BLKID_LIBS
SYSTEMD_CFLAGS
SYSTEMD_LIBS
UDEV_CFLAGS
UDEV_LIBS
PYTHON
@@ -1704,6 +1705,7 @@ 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
@@ -1851,13 +1853,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
@@ -3140,6 +3142,10 @@ 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
@@ -8461,7 +8467,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=$withval
withval=$with_default_use_devices_file; DEFAULT_USE_DEVICES_FILE=$enableval
else
DEFAULT_USE_DEVICES_FILE=0
fi
@@ -10995,8 +11001,6 @@ $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
@@ -11011,8 +11015,6 @@ $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
@@ -11104,8 +11106,6 @@ $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,8 +11197,6 @@ $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
@@ -11290,8 +11288,6 @@ $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
@@ -11371,15 +11367,76 @@ else
$as_echo "yes" >&6; }
HAVE_LOCKD_IDM=yes
fi
if test -n "$PKG_CONFIG" && \
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" && \
{ { $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
HAVE_LOCKD_IDM=yes
pkg_cv_BLKID_CFLAGS=`$PKG_CONFIG --cflags "blkid >= 2.24" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
$bailout
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
fi
$as_echo "#define LOCKDIDM_SUPPORT 1" >>confdefs.h
@@ -12029,6 +12086,24 @@ $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,6 +38,10 @@ 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
@@ -286,7 +290,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=$withval, DEFAULT_USE_DEVICES_FILE=0)
DEFAULT_USE_DEVICES_FILE=$enableval, DEFAULT_USE_DEVICES_FILE=0)
case "$DEFAULT_USE_DEVICES_FILE" in
0|1);;
*) AC_MSG_ERROR([--with-default-use-devices-file parameter invalid]);;
@@ -781,39 +785,6 @@ AC_ARG_WITH(default-run-dir,
AC_DEFINE_UNQUOTED(DEFAULT_RUN_DIR, ["$DEFAULT_RUN_DIR"],
[Default LVM run directory.])
################################################################################
dnl -- Build cluster mirror log daemon
AC_MSG_CHECKING(whether to build cluster mirror log daemon)
AC_ARG_ENABLE(cmirrord,
AS_HELP_STRING([--enable-cmirrord],
[enable the cluster mirror log daemon]),
CMIRRORD=$enableval, CMIRRORD=no)
AC_MSG_RESULT($CMIRRORD)
BUILD_CMIRRORD=$CMIRRORD
################################################################################
dnl -- cmirrord pidfile
if test "$BUILD_CMIRRORD" = yes; then
AC_ARG_WITH(cmirrord-pidfile,
AS_HELP_STRING([--with-cmirrord-pidfile=PATH],
[cmirrord pidfile [PID_DIR/cmirrord.pid]]),
CMIRRORD_PIDFILE=$withval,
CMIRRORD_PIDFILE="$DEFAULT_PID_DIR/cmirrord.pid")
AC_DEFINE_UNQUOTED(CMIRRORD_PIDFILE, ["$CMIRRORD_PIDFILE"],
[Path to cmirrord pidfile.])
fi
################################################################################
dnl -- Look for corosync libraries if required.
if [[ "$BUILD_CMIRRORD" = yes ]]; then
pkg_config_init
if test "$HAVE_CPG" != yes; then
PKG_CHECK_MODULES(CPG, libcpg)
fi
fi
################################################################################
dnl -- Enable debugging
AC_MSG_CHECKING(whether to enable debugging)
@@ -942,7 +913,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=no)
LVMPOLLD=$enableval)
test -n "$LVMPOLLD" && BUILD_LVMPOLLD=$LVMPOLLD
AC_MSG_RESULT($BUILD_LVMPOLLD)
@@ -954,7 +925,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=no)
LOCKDSANLOCK=$enableval)
AC_MSG_RESULT($LOCKDSANLOCK)
BUILD_LOCKDSANLOCK=$LOCKDSANLOCK
@@ -972,7 +943,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=no)
LOCKDDLM=$enableval)
AC_MSG_RESULT($LOCKDDLM)
BUILD_LOCKDDLM=$LOCKDDLM
@@ -990,7 +961,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=no)
LOCKDDLM_CONTROL=$enableval)
AC_MSG_RESULT($LOCKDDLM_CONTROL)
BUILD_LOCKDDLM_CONTROL=$LOCKDDLM_CONTROL
@@ -1008,7 +979,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=no)
LOCKDIDM=$enableval)
AC_MSG_RESULT($LOCKDIDM)
BUILD_LOCKDIDM=$LOCKDIDM
@@ -1016,7 +987,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_EXISTS(blkid >= 2.24, [HAVE_LOCKD_IDM=yes], $bailout)
PKG_CHECK_MODULES(BLKID, 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
@@ -1247,6 +1218,19 @@ 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,
@@ -1655,10 +1639,6 @@ fi
AC_MSG_CHECKING(whether to enable editline)
AC_MSG_RESULT($EDITLINE)
if test "$BUILD_CMIRRORD" = yes; then
AC_CHECK_FUNCS(atexit,,hard_bailout)
fi
if test "$BUILD_LVMLOCKD" = yes; then
AS_IF([test "$HAVE_REALTIME" != yes], [AC_MSG_ERROR([Realtime clock support is mandatory for lvmlockd.])])
AC_CHECK_FUNCS(strtoull,,hard_bailout)
@@ -1834,7 +1814,6 @@ AC_ARG_VAR([UDEV_LIBS], [linker flags for udev])
################################################################################
AC_SUBST(AWK)
AC_SUBST(BLKID_PC)
AC_SUBST(BUILD_CMIRRORD)
AC_SUBST(BUILD_DMEVENTD)
AC_SUBST(BUILD_LVMDBUSD)
AC_SUBST(BUILD_LVMPOLLD)
@@ -1967,7 +1946,6 @@ AC_SUBST(WRITE_INSTALL)
AC_SUBST(DMEVENTD_PIDFILE)
AC_SUBST(LVMPOLLD_PIDFILE)
AC_SUBST(LVMLOCKD_PIDFILE)
AC_SUBST(CMIRRORD_PIDFILE)
AC_SUBST(interface)
AC_SUBST(kerneldir)
AC_SUBST(missingkernel)
@@ -1989,7 +1967,6 @@ Makefile
make.tmpl
libdm/make.tmpl
daemons/Makefile
daemons/cmirrord/Makefile
daemons/dmeventd/Makefile
daemons/dmeventd/libdevmapper-event.pc
daemons/dmeventd/plugins/Makefile
@@ -2023,14 +2000,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,7 +3016,9 @@ 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;
} else if (ls2->thread_stop) {
}
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,6 +114,9 @@
/* 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,7 +40,6 @@ 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,16 +572,6 @@ 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,6 +229,4 @@ 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,11 +159,9 @@ 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 = { 0 };
sd_id128_t 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);
sd_id128_get_machine_app_specific(LVM_APPLICATION_ID, &id);
if (dm_snprintf(buf, PATH_MAX, SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(id)) < 0)
stack;
@@ -1143,6 +1141,19 @@ 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");
@@ -1182,17 +1193,6 @@ 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,6 +1603,7 @@ 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;
@@ -1667,6 +1668,7 @@ 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 expect_missing_vg_device:1; /* when reading a vg it's expected that a dev for a pv isn't found */
unsigned pvscan_cache_single:1;
unsigned can_use_one_scan:1;
unsigned is_clvmd:1;
unsigned md_component_detection:1;
@@ -183,6 +183,7 @@ 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 */
@@ -201,12 +202,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,6 +1130,18 @@ cfg(global_event_activation_CFG, "event_activation", global_CFG_SECTION, CFG_DEF
"See the --setautoactivation option or the auto_activation_volume_list\n"
"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,6 +328,9 @@
#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,7 +53,6 @@ static struct {
const char *dev_dir;
int has_scanned;
long st_dev;
struct dm_list dirs;
struct dm_list files;
@@ -1065,18 +1064,11 @@ 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 "
@@ -1099,17 +1091,9 @@ 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) {
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;
dm_list_iterate_items(dl, &_cache.dirs)
_insert_dir(dl->dir);
}
}
#endif /* UDEV_SYNC_SUPPORT */
@@ -1144,11 +1128,6 @@ 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 */
@@ -2056,12 +2035,12 @@ int setup_device(struct cmd_context *cmd, const char *devname)
}
/*
* autoactivation is specialized/optimized to look only at command args,
* pvscan --cache 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.
* added to dev-cache and matched with device_ids later in pvscan.
*/
int setup_devices_for_online_autoactivation(struct cmd_context *cmd)
int setup_devices_for_pvscan_cache(struct cmd_context *cmd)
{
if (cmd->enable_devices_list) {
if (!_setup_devices_list(cmd))
@@ -2125,7 +2104,7 @@ static char *_get_devname_from_devno(struct cmd_context *cmd, dev_t devno)
}
if (!(dir = opendir(path)))
goto try_partition;
return NULL;
while ((dirent = readdir(dir))) {
if (dirent->d_name[0] == '.')
@@ -2164,7 +2143,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 dm", devname, major, minor);
log_debug("Found %s for %d:%d from sys", devname, major, minor);
return _strdup(devname);
}
return NULL;
@@ -2175,7 +2154,6 @@ 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,7 +79,8 @@ 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);
int setup_devices_for_online_autoactivation(struct cmd_context *cmd);
/* Normal device setup functions are split up for pvscan optimization. */
int setup_devices_for_pvscan_cache(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,8 +778,9 @@ static void _device_ids_update_try(struct cmd_context *cmd)
{
int held = 0;
if (cmd->expect_missing_vg_device) {
log_print("skip updating devices file.");
/* Defer updates to non-pvscan-cache commands. */
if (cmd->pvscan_cache_single) {
log_print("pvscan[%d] skip updating devices file.", getpid());
return;
}
@@ -1350,9 +1351,8 @@ void device_id_update_vg_uuid(struct cmd_context *cmd, struct volume_group *vg,
}
}
if (update &&
!device_ids_write(cmd))
stack;
if (update)
device_ids_write(cmd);
out:
unlock_devices_file(cmd);
}

View File

@@ -1,424 +0,0 @@
/*
* 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);
}

View File

@@ -1,57 +0,0 @@
/*
* 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,34 +17,266 @@
#ifdef __linux__
static int _accept_p(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
#include <sys/sysmacros.h>
#include <dirent.h>
static int _locate_sysfs_blocks(const char *sysfs_dir, char *path, size_t len,
unsigned *sysfs_depth)
{
char path[PATH_MAX];
const char *sysfs_dir;
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 },
dev->filtered_flags &= ~DEV_FILTERED_SYSFS;
/*
* 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 },
/*
* 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;
/*
* old block subsystem layout with nested directories
*
* /sys/block/
* |-- sda
* | |-- capability
* | |-- dev
* ...
* | |-- sda1
* | | |-- dev
* ...
* |
* `-- sr0
* |-- capability
* |-- dev
* ...
*
*/
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");
{ "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;
}
if (lstat(path, &info)) {
log_debug_devs("%s: Skipping (sysfs)", dev_name(dev));
dev->filtered_flags |= DEV_FILTERED_SYSFS;
return 0;
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;
dev->filtered_flags &= ~DEV_FILTERED_SYSFS;
if (!ds->initialised)
_init_devs(ds);
/* Pass through if initialisation failed */
if (ds->initialised != 1)
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;
}
return 1;
@@ -52,14 +284,21 @@ 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);
free(f);
dm_pool_destroy(ds->mem);
}
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) {
@@ -67,12 +306,26 @@ struct dev_filter *sysfs_filter_create(void)
return NULL;
}
if (!(f = zalloc(sizeof(*f))))
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))))
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.");
@@ -80,6 +333,7 @@ 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 && !*use_previous_vg) {
if (!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,12 +477,8 @@ 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));
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 lvmcache, saving it in info->bad_mdas for possible repair with updatemetadata */
lvmcache_del_save_bad_mda(info, mda->mda_num, BAD_MDA_TEXT);
/* remove mda from fid */
fid_remove_mda(fid, mda, NULL, 0, 0);
}

View File

@@ -146,7 +146,6 @@
#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>
@@ -157,6 +156,8 @@
#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";
@@ -367,6 +368,7 @@ 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);
@@ -1214,8 +1216,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.
*/
void get_single_vgname_cmd_arg(struct cmd_context *cmd,
struct dm_list *hints, char **vgname)
static void _get_single_vgname_cmd_arg(struct cmd_context *cmd,
struct dm_list *hints, char **vgname)
{
struct hint *hint;
char namebuf[NAME_LEN];
@@ -1264,11 +1266,6 @@ 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
@@ -1285,6 +1282,109 @@ 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
@@ -1326,6 +1426,15 @@ 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.
@@ -1430,7 +1539,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,8 +41,5 @@ 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,7 +26,6 @@
#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>
@@ -892,7 +891,7 @@ static int _setup_bcache(void)
#define BASE_FD_COUNT 32 /* Number of open files we want apart from devs */
void prepare_open_file_limit(struct cmd_context *cmd, unsigned int num_devs)
static void _prepare_open_file_limit(struct cmd_context *cmd, unsigned int num_devs)
{
#ifdef HAVE_PRLIMIT
struct rlimit old = { 0 }, new;
@@ -1021,236 +1020,6 @@ 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
@@ -1399,7 +1168,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.
@@ -1441,6 +1210,8 @@ 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
@@ -1452,16 +1223,18 @@ 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,9 +118,6 @@ 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);
@@ -137,6 +134,4 @@ 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 = lock_lv_name,
.lv_name = dm_pool_strdup(cmd->mem, 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) ? &pv2->tags : NULL);
struct dm_list *tags_to_match = mem ? NULL : pv_tags ? : &pv2->tags;
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 (tags_to_match && !str_list_match_list(&pv1->tags, tags_to_match, &tag_matched))
if (!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->expect_missing_vg_device &&
if (cmd && !cmd->pvscan_cache_single &&
(!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) || cmd->expect_missing_vg_device)
if (vg_is_foreign(vg) && !cmd->include_foreign_vgs)
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] && subcommand && !strcmp(subcommand, "list"))
if (_switches[VERBOSE_ARG] && !strcmp(subcommand, "list"))
_statstype |= (DM_STATS_WALK_ALL
| DM_STATS_WALK_SKIP_SINGLE_AREA);
/* suppress duplicates unless the user has requested all regions */
if (subcommand && !objtype_args && !strcmp(subcommand, "report"))
if (!strcmp(subcommand, "report") && !objtype_args)
/* suppress duplicate rows of output */
_statstype |= (DM_STATS_WALK_ALL
| DM_STATS_WALK_SKIP_SINGLE_AREA);

View File

@@ -15,9 +15,6 @@ srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = @top_builddir@
SOURCES = lvm2_activation_generator_systemd_red_hat.c
TARGETS = lvm2_activation_generator_systemd_red_hat
include $(top_builddir)/make.tmpl
ifeq ("@BUILD_DMEVENTD@", "yes")
@@ -66,7 +63,7 @@ install_initscripts:
@echo " [INSTALL] initscripts"
$(Q) $(INSTALL_DIR) $(initdir)
ifeq ("@BUILD_DMEVENTD@", "yes")
$(Q) $(INSTALL_SCRIPT) lvm2_monitoring_init_red_hat $(initdir)/lvm2-monitor
$(Q) $(INSTALL_SCRIPT) lvm2_monitoring_init_red_hat $(initdir)/lvm-monitor
endif
ifeq ("@BUILD_LVMPOLLD@", "yes")
$(Q) $(INSTALL_SCRIPT) lvm2_lvmpolld_init_red_hat $(initdir)/lvm2-lvmpolld
@@ -78,24 +75,15 @@ ifeq ("@BLKDEACTIVATE@", "yes")
$(Q) $(INSTALL_SCRIPT) blk_availability_init_red_hat $(initdir)/blk-availability
endif
CFLAGS_lvm2_activation_generator_systemd_red_hat.o += $(EXTRA_EXEC_CFLAGS)
lvm2_activation_generator_systemd_red_hat: $(OBJECTS) $(LVMINTERNAL_LIBS)
@echo " [CC] $@"
$(Q) $(CC) -o $@ $(OBJECTS) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) $(LVMINTERNAL_LIBS) $(LIBS)
install_systemd_generators:
@echo " [INSTALL] systemd_generators"
$(Q) $(INSTALL_DIR) $(systemd_generator_dir)
$(Q) $(INSTALL_PROGRAM) lvm2_activation_generator_systemd_red_hat $(systemd_generator_dir)/lvm2-activation-generator
install_systemd_units: install_dbus_service
@echo " [INSTALL] systemd_units"
$(Q) $(INSTALL_DIR) $(systemd_unit_dir)
$(Q) $(INSTALL_DATA) lvm-activate-vgs-main.service $(systemd_unit_dir)/lvm-activate-vgs-main.service
$(Q) $(INSTALL_DATA) lvm-activate-vgs-last.service $(systemd_unit_dir)/lvm-activate-vgs-last.service
ifeq ("@BUILD_DMEVENTD@", "yes")
$(Q) $(INSTALL_DATA) dm_event_systemd_red_hat.socket $(systemd_unit_dir)/dm-event.socket
$(Q) $(INSTALL_DATA) dm_event_systemd_red_hat.service $(systemd_unit_dir)/dm-event.service
$(Q) $(INSTALL_DATA) lvm2_monitoring_systemd_red_hat.service $(systemd_unit_dir)/lvm2-monitor.service
$(Q) $(INSTALL_DATA) lvm2_monitoring_systemd_red_hat.service $(systemd_unit_dir)/lvm-monitor.service
endif
ifeq ("@BLKDEACTIVATE@", "yes")
$(Q) $(INSTALL_DATA) blk_availability_systemd_red_hat.service $(systemd_unit_dir)/blk-availability.service
@@ -155,7 +143,9 @@ DISTCLEAN_TARGETS += \
lvm2_monitoring_init_red_hat \
lvm2_monitoring_systemd_red_hat.service \
lvm2_pvscan_systemd_red_hat@.service \
lvm2_tmpfiles_red_hat.conf
lvm2_tmpfiles_red_hat.conf \
lvm-activate-vgs-main.service \
lvm-activate-vgs-last.service
# Remove ancient files
DISTCLEAN_TARGETS += \

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -23,10 +23,10 @@ if [ $1 = 0 ]; then
fi
%triggerun -- %{name} < 2.02.86-2
%{_bindir}/systemd-sysv-convert --save lvm2-monitor >/dev/null 2>&1 || :
/bin/systemctl --no-reload enable lvm2-monitor.service > /dev/null 2>&1 || :
/sbin/chkconfig --del lvm2-monitor > /dev/null 2>&1 || :
/bin/systemctl try-restart lvm2-monitor.service > /dev/null 2>&1 || :
%{_bindir}/systemd-sysv-convert --save lvm-monitor >/dev/null 2>&1 || :
/bin/systemctl --no-reload enable lvm-monitor.service > /dev/null 2>&1 || :
/sbin/chkconfig --del lvm-monitor > /dev/null 2>&1 || :
/bin/systemctl try-restart lvm-monitor.service > /dev/null 2>&1 || :
# files in the main package
%files
@@ -100,9 +100,6 @@ fi
%{_mandir}/man8/lvm-config.8.gz
%{_mandir}/man8/lvm-dumpconfig.8.gz
%{_mandir}/man8/lvm.8.gz
%if %{enable_systemd}
%{_mandir}/man8/lvm2-activation-generator.8.gz
%endif
%{_mandir}/man8/lvmconfig.8.gz
%{_mandir}/man8/lvmdevices.8.gz
%{_mandir}/man8/lvmdiskscan.8.gz
@@ -187,16 +184,17 @@ fi
%dir %{_default_run_dir}
%if %{enable_systemd}
%{_tmpfilesdir}/%{name}.conf
%{_unitdir}/lvm-activate-vgs-main.service
%{_unitdir}/lvm-activate-vgs-last.service
%{_unitdir}/lvm-monitor.service
%{_unitdir}/blk-availability.service
%{_unitdir}/lvm2-monitor.service
%attr(555, -, -) %{_prefix}/lib/systemd/system-generators/lvm2-activation-generator
%if %{have_service lvmpolld}
%{_unitdir}/lvm2-lvmpolld.service
%{_unitdir}/lvm2-lvmpolld.socket
%endif
%else
%{_sysconfdir}/rc.d/init.d/blk-availability
%{_sysconfdir}/rc.d/init.d/lvm2-monitor
%{_sysconfdir}/rc.d/init.d/lvm-monitor
%if %{have_service lvmpolld}
%{_sysconfdir}/rc.d/init.d/lvm2-lvmpolld
%endif

View File

@@ -15,8 +15,6 @@ 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","$dev3" --cache -aay "$dev4"
pvscan --devices "$dev4" --cache -aay "$dev4"
check lv_field $vg2/$lv2 lv_active "active"
vgchange -an $vg2

View File

@@ -219,8 +219,6 @@ 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"
@@ -377,7 +375,6 @@ 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

@@ -1,172 +0,0 @@
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) {
(void) close(f->fd);
close(f->fd);
// reopen with O_DIRECT
f->fd = open(f->fname, O_RDWR | O_DIRECT);
T_ASSERT(f->fd >= 0);

View File

@@ -87,12 +87,6 @@ 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"
@@ -284,6 +278,11 @@ 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, --autoactivation String
--major Number, --minor Number, --noudevsync, --eventactivation 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,
--autoactivation String
--eventactivation 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,
--autoactivation String, OO_VGCHANGE
--vgonline, --eventactivation String, OO_VGCHANGE
OP: VG|Tag|Select ...
IO: --ignoreskippedcluster
ID: vgchange_activate

View File

@@ -2393,10 +2393,8 @@ 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);
@@ -2542,6 +2540,8 @@ 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,9 +176,6 @@ 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,10 +18,11 @@
#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;
@@ -43,6 +44,12 @@ 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)
@@ -176,12 +183,171 @@ 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;
}
@@ -191,6 +357,27 @@ 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
@@ -209,7 +396,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))) {
@@ -217,7 +404,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;
@@ -237,7 +424,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)
@@ -262,6 +449,132 @@ 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];
@@ -269,8 +582,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;
}
@@ -326,7 +639,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)++;
@@ -387,8 +700,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;
}
@@ -400,8 +713,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;
}
@@ -426,13 +739,68 @@ 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 };
@@ -443,7 +811,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)++;
@@ -474,6 +842,32 @@ 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
@@ -533,7 +927,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;
@@ -801,11 +1195,17 @@ 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)
lvmcache_label_scan(cmd);
read_flags |= PROCESS_SKIP_SCAN;
device_ids_match(cmd);
ret = process_each_vg(cmd, 0, NULL, NULL, vgnames, read_flags, 0, handle, _pvscan_aa_single);
}
@@ -932,7 +1332,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;
@@ -940,7 +1340,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;
@@ -1054,7 +1454,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(cmd, "PV %s missing device size.", dev_name(dev));
log_print("pvscan[%d] PV %s can get device size.", getpid(), dev_name(dev));
release_vg(vg);
continue;
}
@@ -1112,7 +1512,7 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
* Create file named for pvid to record this PV is online.
* The command creates/checks online files only when --cache is used.
*/
if (do_cache && !online_pvid_file_create(cmd, dev, vg ? vg->name : NULL)) {
if (do_cache && !online_pvid_file_create(cmd, dev, vg ? vg->name : NULL, 0, NULL)) {
log_error_pvscan(cmd, "PV %s failed to create online file.", dev_name(dev));
release_vg(vg);
ret = 0;
@@ -1303,9 +1703,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);
@@ -1369,7 +1769,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->expect_missing_vg_device = 1;
cmd->pvscan_cache_single = 1;
/*
* Special pvscan-specific setup steps to avoid looking
@@ -1378,7 +1778,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_online_autoactivation(cmd)) {
if (!setup_devices_for_pvscan_cache(cmd)) {
log_error_pvscan(cmd, "Failed to set up devices.");
return 0;
}
@@ -1492,7 +1892,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(cmd, "%s cannot read label.", dev_name(devl->dev));
log_print("pvscan[%d] %s cannot read.", getpid(), dev_name(devl->dev));
dm_list_del(&devl->list);
continue;
}
@@ -1559,35 +1959,13 @@ 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;
@@ -1660,11 +2038,34 @@ 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 (skip_command)
return ECMD_PROCESSED;
if ((ea = arg_str_value(cmd, eventactivation_ARG, NULL))) {
int service_only = 0, event_only = 0, service_to_event = 0;
int ea_service = 0, ea_event = 0, ea_on = 0;
if (!get_event_activation_config_settings(cmd, &service_only, &event_only, &service_to_event))
return ECMD_FAILED;
if (!get_event_activation_command_options(cmd, ea, &ea_service, &ea_event, &ea_on))
return ECMD_FAILED;
if (ea_event) {
if (!event_activation) {
log_print("Skip pvscan for event and event_activation=0.");
return ECMD_PROCESSED;
}
if (service_only) {
log_print("Skip pvscan for event and event_activation_options service_only.");
return ECMD_PROCESSED;
}
if (service_to_event && !event_activation_is_on(cmd)) {
log_print("Skip pvscan for event and no event-activation-on.");
return ECMD_PROCESSED;
}
} else {
log_error("Option --eventactivation %s is not used by pvscan.", ea);
return ECMD_FAILED;
}
}
if (!_pvscan_cache_args(cmd, argc, argv, &complete_vgnames))
return ECMD_FAILED;

View File

@@ -17,7 +17,6 @@
#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>
@@ -5715,3 +5714,90 @@ 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,4 +237,9 @@ 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,9 +226,8 @@ int lvconvert_poll(struct cmd_context *cmd, struct logical_volume *lv, unsigned
int mirror_remove_missing(struct cmd_context *cmd,
struct logical_volume *lv, int force);
int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg,
activation_change_t activate, 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);
@@ -295,4 +294,11 @@ 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,7 +15,6 @@
#include "tools.h"
#include "lib/device/device_id.h"
#include "lib/label/hints.h"
struct vgchange_params {
int lock_start_count;
@@ -196,6 +195,41 @@ 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)
{
@@ -222,6 +256,11 @@ 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) {
@@ -712,6 +751,9 @@ 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))
@@ -735,28 +777,106 @@ static int _vgchange_single(struct cmd_context *cmd, const char *vg_name,
return ret;
}
static int _check_autoactivation(struct cmd_context *cmd, struct vgchange_params *vp, int *skip_command)
static int _check_event_activation(struct cmd_context *cmd, struct vgchange_params *vp, int *skip_command, int *enable_events)
{
const char *aa;
const char *ea;
int service_only = 0, event_only = 0, service_to_event = 0;
int ea_service = 0, ea_event = 0, ea_on = 0;
int on_file_exists;
int event_activation;
if (!(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;
if (!(ea = arg_str_value(cmd, eventactivation_ARG, NULL))) {
log_error("No eventactivation value.");
return 0;
}
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;
/* 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;
}
}
vp->vg_complete_to_activate = 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;
}
cmd->use_hints = 0;
/*
* lvm.conf service_to_event, and vgchange -aay --eventactivation service,
* then only activate LVs if the VG is complete.
* A later event will complete the VG and activate it.
*/
if (event_activation && service_to_event && ea_service)
vp->vg_complete_to_activate = 1;
return 1;
}
@@ -765,7 +885,6 @@ 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;
@@ -878,62 +997,21 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv)
cmd->lockd_vg_enforce_sh = 1;
}
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))
if (arg_is_set(cmd, eventactivation_ARG)) {
int skip_command = 0, enable_events = 0;
if (!_check_event_activation(cmd, &vp, &skip_command, &enable_events))
return ECMD_FAILED;
if (skip_command)
return ECMD_PROCESSED;
/*
* 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);
}
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;
}
}

View File

@@ -172,17 +172,6 @@ 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 --autoactivation event --major $major --minor $minor", ENV{LVM_SCANNED}="1"
RUN+="(LVM_EXEC)/lvm pvscan --cache -aay --eventactivation event --major $major --minor $minor", ENV{LVM_SCANNED}="1"
LABEL="lvm_end"

View File

@@ -78,9 +78,19 @@ 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 --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}"
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}"
GOTO="lvm_end"
LABEL="lvm_end"