mirror of
git://sourceware.org/git/lvm2.git
synced 2025-09-16 17:44:24 +03:00
Compare commits
4 Commits
dev-dct-te
...
dev-dct-pv
Author | SHA1 | Date | |
---|---|---|---|
|
5e48b04561 | ||
|
3e893b9b09 | ||
|
c06d5fe28e | ||
|
4f1957ee50 |
@@ -1 +1 @@
|
||||
1.02.183-git (2021-10-20)
|
||||
1.02.181-git (2021-08-11)
|
||||
|
10
WHATS_NEW
10
WHATS_NEW
@@ -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.
|
||||
|
@@ -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
117
configure
vendored
@@ -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 :
|
||||
|
75
configure.ac
75
configure.ac
@@ -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
|
||||
|
@@ -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) {
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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
10
lib/cache/lvmcache.c
vendored
@@ -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.
|
||||
|
2
lib/cache/lvmcache.h
vendored
2
lib/cache/lvmcache.h
vendored
@@ -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
|
||||
|
@@ -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();
|
||||
|
||||
|
@@ -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 */
|
||||
|
@@ -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)
|
||||
|
||||
|
@@ -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"
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
@@ -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
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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.
|
||||
|
@@ -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
|
||||
|
@@ -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,
|
||||
};
|
||||
|
||||
|
@@ -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) {
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -15,9 +15,6 @@ srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
SOURCES = lvm2_activation_generator_systemd_red_hat.c
|
||||
TARGETS = lvm2_activation_generator_systemd_red_hat
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
ifeq ("@BUILD_DMEVENTD@", "yes")
|
||||
@@ -66,7 +63,7 @@ install_initscripts:
|
||||
@echo " [INSTALL] initscripts"
|
||||
$(Q) $(INSTALL_DIR) $(initdir)
|
||||
ifeq ("@BUILD_DMEVENTD@", "yes")
|
||||
$(Q) $(INSTALL_SCRIPT) lvm2_monitoring_init_red_hat $(initdir)/lvm2-monitor
|
||||
$(Q) $(INSTALL_SCRIPT) lvm2_monitoring_init_red_hat $(initdir)/lvm-monitor
|
||||
endif
|
||||
ifeq ("@BUILD_LVMPOLLD@", "yes")
|
||||
$(Q) $(INSTALL_SCRIPT) lvm2_lvmpolld_init_red_hat $(initdir)/lvm2-lvmpolld
|
||||
@@ -78,24 +75,15 @@ ifeq ("@BLKDEACTIVATE@", "yes")
|
||||
$(Q) $(INSTALL_SCRIPT) blk_availability_init_red_hat $(initdir)/blk-availability
|
||||
endif
|
||||
|
||||
CFLAGS_lvm2_activation_generator_systemd_red_hat.o += $(EXTRA_EXEC_CFLAGS)
|
||||
|
||||
lvm2_activation_generator_systemd_red_hat: $(OBJECTS) $(LVMINTERNAL_LIBS)
|
||||
@echo " [CC] $@"
|
||||
$(Q) $(CC) -o $@ $(OBJECTS) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) $(LVMINTERNAL_LIBS) $(LIBS)
|
||||
|
||||
install_systemd_generators:
|
||||
@echo " [INSTALL] systemd_generators"
|
||||
$(Q) $(INSTALL_DIR) $(systemd_generator_dir)
|
||||
$(Q) $(INSTALL_PROGRAM) lvm2_activation_generator_systemd_red_hat $(systemd_generator_dir)/lvm2-activation-generator
|
||||
|
||||
install_systemd_units: install_dbus_service
|
||||
@echo " [INSTALL] systemd_units"
|
||||
$(Q) $(INSTALL_DIR) $(systemd_unit_dir)
|
||||
$(Q) $(INSTALL_DATA) lvm-activate-vgs-main.service $(systemd_unit_dir)/lvm-activate-vgs-main.service
|
||||
$(Q) $(INSTALL_DATA) lvm-activate-vgs-last.service $(systemd_unit_dir)/lvm-activate-vgs-last.service
|
||||
ifeq ("@BUILD_DMEVENTD@", "yes")
|
||||
$(Q) $(INSTALL_DATA) dm_event_systemd_red_hat.socket $(systemd_unit_dir)/dm-event.socket
|
||||
$(Q) $(INSTALL_DATA) dm_event_systemd_red_hat.service $(systemd_unit_dir)/dm-event.service
|
||||
$(Q) $(INSTALL_DATA) lvm2_monitoring_systemd_red_hat.service $(systemd_unit_dir)/lvm2-monitor.service
|
||||
$(Q) $(INSTALL_DATA) lvm2_monitoring_systemd_red_hat.service $(systemd_unit_dir)/lvm-monitor.service
|
||||
endif
|
||||
ifeq ("@BLKDEACTIVATE@", "yes")
|
||||
$(Q) $(INSTALL_DATA) blk_availability_systemd_red_hat.service $(systemd_unit_dir)/blk-availability.service
|
||||
@@ -155,7 +143,9 @@ DISTCLEAN_TARGETS += \
|
||||
lvm2_monitoring_init_red_hat \
|
||||
lvm2_monitoring_systemd_red_hat.service \
|
||||
lvm2_pvscan_systemd_red_hat@.service \
|
||||
lvm2_tmpfiles_red_hat.conf
|
||||
lvm2_tmpfiles_red_hat.conf \
|
||||
lvm-activate-vgs-main.service \
|
||||
lvm-activate-vgs-last.service
|
||||
|
||||
# Remove ancient files
|
||||
DISTCLEAN_TARGETS += \
|
||||
|
@@ -1,7 +1,7 @@
|
||||
[Unit]
|
||||
Description=Availability of block devices
|
||||
Before=shutdown.target
|
||||
After=lvm2-activation.service iscsi-shutdown.service iscsi.service iscsid.service fcoe.service rbdmap.service
|
||||
After=lvm-activate-vgs-main.service lvm-activate-vgs-last.service iscsi-shutdown.service iscsi.service iscsid.service fcoe.service rbdmap.service
|
||||
DefaultDependencies=no
|
||||
Conflicts=shutdown.target
|
||||
|
||||
|
22
scripts/lvm-activate-vgs-last.service.in
Normal file
22
scripts/lvm-activate-vgs-last.service.in
Normal 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
|
19
scripts/lvm-activate-vgs-main.service.in
Normal file
19
scripts/lvm-activate-vgs-main.service.in
Normal 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
|
@@ -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
|
||||
|
@@ -1,8 +1,8 @@
|
||||
[Unit]
|
||||
Description=Monitoring of LVM2 mirrors, snapshots etc. using dmeventd or progress polling
|
||||
Description=Monitor LVM Logical Volumes
|
||||
Documentation=man:dmeventd(8) man:lvcreate(8) man:lvchange(8) man:vgchange(8)
|
||||
Requires=dm-event.socket
|
||||
After=dm-event.socket dm-event.service lvm2-activation.service
|
||||
After=dm-event.socket dm-event.service lvm-activate-vgs-last.service
|
||||
Before=local-fs-pre.target shutdown.target
|
||||
DefaultDependencies=no
|
||||
Conflicts=shutdown.target
|
||||
|
@@ -23,10 +23,10 @@ if [ $1 = 0 ]; then
|
||||
fi
|
||||
|
||||
%triggerun -- %{name} < 2.02.86-2
|
||||
%{_bindir}/systemd-sysv-convert --save lvm2-monitor >/dev/null 2>&1 || :
|
||||
/bin/systemctl --no-reload enable lvm2-monitor.service > /dev/null 2>&1 || :
|
||||
/sbin/chkconfig --del lvm2-monitor > /dev/null 2>&1 || :
|
||||
/bin/systemctl try-restart lvm2-monitor.service > /dev/null 2>&1 || :
|
||||
%{_bindir}/systemd-sysv-convert --save lvm-monitor >/dev/null 2>&1 || :
|
||||
/bin/systemctl --no-reload enable lvm-monitor.service > /dev/null 2>&1 || :
|
||||
/sbin/chkconfig --del lvm-monitor > /dev/null 2>&1 || :
|
||||
/bin/systemctl try-restart lvm-monitor.service > /dev/null 2>&1 || :
|
||||
# files in the main package
|
||||
|
||||
%files
|
||||
@@ -100,9 +100,6 @@ fi
|
||||
%{_mandir}/man8/lvm-config.8.gz
|
||||
%{_mandir}/man8/lvm-dumpconfig.8.gz
|
||||
%{_mandir}/man8/lvm.8.gz
|
||||
%if %{enable_systemd}
|
||||
%{_mandir}/man8/lvm2-activation-generator.8.gz
|
||||
%endif
|
||||
%{_mandir}/man8/lvmconfig.8.gz
|
||||
%{_mandir}/man8/lvmdevices.8.gz
|
||||
%{_mandir}/man8/lvmdiskscan.8.gz
|
||||
@@ -187,16 +184,17 @@ fi
|
||||
%dir %{_default_run_dir}
|
||||
%if %{enable_systemd}
|
||||
%{_tmpfilesdir}/%{name}.conf
|
||||
%{_unitdir}/lvm-activate-vgs-main.service
|
||||
%{_unitdir}/lvm-activate-vgs-last.service
|
||||
%{_unitdir}/lvm-monitor.service
|
||||
%{_unitdir}/blk-availability.service
|
||||
%{_unitdir}/lvm2-monitor.service
|
||||
%attr(555, -, -) %{_prefix}/lib/systemd/system-generators/lvm2-activation-generator
|
||||
%if %{have_service lvmpolld}
|
||||
%{_unitdir}/lvm2-lvmpolld.service
|
||||
%{_unitdir}/lvm2-lvmpolld.socket
|
||||
%endif
|
||||
%else
|
||||
%{_sysconfdir}/rc.d/init.d/blk-availability
|
||||
%{_sysconfdir}/rc.d/init.d/lvm2-monitor
|
||||
%{_sysconfdir}/rc.d/init.d/lvm-monitor
|
||||
%if %{have_service lvmpolld}
|
||||
%{_sysconfdir}/rc.d/init.d/lvm2-lvmpolld
|
||||
%endif
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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")
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
11
tools/args.h
11
tools/args.h
@@ -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"
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
|
||||
|
513
tools/pvscan.c
513
tools/pvscan.c
@@ -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;
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
218
tools/vgchange.c
218
tools/vgchange.c
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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"
|
||||
|
@@ -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"
|
||||
|
Reference in New Issue
Block a user