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

Compare commits

...

10 Commits

Author SHA1 Message Date
David Teigland
74e404ce11 hints: new pvs_online type
Use a new form of hints to reduce device scanning in
vgchange -aay run by the udev rule for event based
autoactivation.

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

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

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

This new form of hints is mainly useful in the context of
event based autoactivation, during which standard hints are
not useful.  Once the system is in a steady state after startup
(devices are not regularly appearing), the standard hints are
most useful.  The pvs_online hint method could be used on a
running system, but would be no better than standard hints,
and may be inferior because pvs_online files are not rigidly
updated after system startup.
2021-07-19 13:29:54 -05:00
Vojtech Trefny
d13dce20df lvmdbusd: Use ID_FS_TYPE UDev property in udevwatch
'.ID_FS_TYPE_NEW' is a custom property added by an LVM UDev rule
which is now being removed and 'ID_FS_TYPE' has the same value.

Signed-off-by: Vojtech Trefny <vtrefny@redhat.com>
2021-07-14 12:52:22 -05:00
David Teigland
c229e321da add dracut files
pvscan-udev-initrd.sh is shell wrapper around the
pvscan command for use in the initrd lvm udev rule.
It finds the intersection of complete VG/LVs reported
by pvscan, and the VG/LVs specified on boot cmdline.
The resulting VG or LVs are printed as env-vars that
the udev rule can IMPORT, and pass to vgchange/lvchange.

64-lvm.rules calls pvscan-udev-initrd.sh/pvscan to scan
the PV to check if any VG or LVs are complete given the
new device.  The pvscan will only ever read the single
device triggering the uevent.  If any VG or LVs are
complete, the udev rule uses systemd-run to run a
vgchange or lvchange command to activate the complete
VG or LVs.  (Running vgchange or lvchange directly may
take longer than udev likes, so systemd-run --no-block
is used.)
2021-07-14 12:52:22 -05:00
Marian Csontos
8a0da7b4f5 configure: update 2021-07-14 12:52:22 -05:00
David Teigland
57c0698ec4 new udev autoactivation
new udev rule 69-dm-lvm.rules replaces
69-dm-lvm-meta.rules and lvm2-pvscan.service

udev rule calls pvscan directly on the added device

pvscan output indicates if a complete VG can be activated

udev env var LVM_VG_NAME_COMPLETE is used to pass complete
VG name from pvscan to the udev rule

udev rule uses systemd-run to run vgchange -aay <vgname>
2021-07-14 12:52:22 -05:00
David Teigland
f39fbebb04 logging: to the systemd journal
Configure via lvm.conf log/journal or command line --journal.

Possible values:
"command" records command information.
"output" records default command output.
"debug" records full command debugging.

Multiple values can be set in lvm.conf as an array.
One value can be set in --journal which is added to
values set in lvm.conf
2021-07-14 12:52:22 -05:00
David Teigland
7578a30534 pvscan: add options listlvs listvg checkcomplete
pvscan --cache <dev>
    . read only dev
    . create online file for dev

pvscan --listvg <dev>
    . read only dev
    . list VG using dev

pvscan --listlvs <dev>
    . read only dev
    . list VG using dev
    . list LVs using dev

pvscan --cache --listvg [--checkcomplete] <dev>
    . read only dev
    . create online file for dev
    . list VG using dev
    . [check online files and report if VG is complete]

pvscan --cache --listlvs [--checkcomplete] <dev>
    . read only dev
    . create online file for dev
    . list VG using dev
    . list LVs using dev
    . [check online files and report if VG is complete]
    . [check online files and report if LVs are complete]

[--vgonline]
can be used with --checkcomplete, to enable use of a vg online
file.  This results in only the first pvscan command to see
the complete VG to report 'VG complete', and others will report
'VG finished'.  This allows the caller to easily run a single
activation of the VG.

[--udevoutput]
can be used with --cache --listvg --checkcomplete, to enable
an output mode that prints LVM_VG_NAME_COMPLETE='vgname' that
a udev rule can import, and prevents other output from the
command (other output causes udev to ignore the command.)

The list of complete LVs is meant to be passed to lvchange -aay,
or the complete VG used with vgchange -aay.

When --checkcomplete is used, lvm assumes that that the output
will be used to trigger event-based autoactivation, so the pvscan
does nothing if event_activation=0 and --checkcomplete is used.

Example of listlvs
------------------

$ lvs -a vg -olvname,devices
  LV     Devices
  lv_a   /dev/loop0(0)
  lv_ab  /dev/loop0(1),/dev/loop1(1)
  lv_abc /dev/loop0(3),/dev/loop1(3),/dev/loop2(1)
  lv_b   /dev/loop1(0)
  lv_c   /dev/loop2(0)

$ pvscan --cache --listlvs --checkcomplete /dev/loop0
  pvscan[35680] PV /dev/loop0 online, VG vg incomplete (need 2).
  VG vg incomplete
  LV vg/lv_a complete
  LV vg/lv_ab incomplete
  LV vg/lv_abc incomplete

$ pvscan --cache --listlvs --checkcomplete /dev/loop1
  pvscan[35681] PV /dev/loop1 online, VG vg incomplete (need 1).
  VG vg incomplete
  LV vg/lv_b complete
  LV vg/lv_ab complete
  LV vg/lv_abc incomplete

$ pvscan --cache --listlvs --checkcomplete /dev/loop2
  pvscan[35682] PV /dev/loop2 online, VG vg is complete.
  VG vg complete
  LV vg/lv_c complete
  LV vg/lv_abc complete

Example of listvg
-----------------

$ pvscan --cache --listvg --checkcomplete /dev/loop0
  pvscan[35684] PV /dev/loop0 online, VG vg incomplete (need 2).
  VG vg incomplete

$ pvscan --cache --listvg --checkcomplete /dev/loop1
  pvscan[35685] PV /dev/loop1 online, VG vg incomplete (need 1).
  VG vg incomplete

$ pvscan --cache --listvg --checkcomplete /dev/loop2
  pvscan[35686] PV /dev/loop2 online, VG vg is complete.
  VG vg complete
2021-07-14 12:51:59 -05:00
David Teigland
fc726b60bc system_id: new appmachineid option
The new system_id_source="appmachineid" will cause
lvm to use an lvm-specific derivation of the machine-id,
instead of the machine-id directly.  This is now
recommended in place of using machineid.
2021-07-14 11:28:11 -05:00
David Teigland
8f2789a37d config: change default use_devicesfile to 1 2021-07-14 11:28:11 -05:00
David Teigland
f8357f5b98 config: comment all default settings 2021-07-14 11:28:11 -05:00
31 changed files with 1723 additions and 205 deletions

112
configure vendored
View File

@@ -774,6 +774,10 @@ UDEV_LIBS
UDEV_CFLAGS
SYSTEMD_LIBS
SYSTEMD_CFLAGS
BLKID_LIBS
BLKID_CFLAGS
APP_MACHINEID_LIBS
APP_MACHINEID_CFLAGS
NOTIFY_DBUS_LIBS
NOTIFY_DBUS_CFLAGS
BLKID_LIBS
@@ -957,6 +961,7 @@ enable_use_lvmpolld
with_lvmpolld_pidfile
enable_dmfilemapd
enable_notify_dbus
enable_app_machineid
enable_blkid_wiping
enable_udev_systemd_background_jobs
enable_udev_sync
@@ -1027,6 +1032,10 @@ LOCKD_DLM_CONTROL_CFLAGS
LOCKD_DLM_CONTROL_LIBS
LOCKD_IDM_CFLAGS
LOCKD_IDM_LIBS
NOTIFY_DBUS_CFLAGS
NOTIFY_DBUS_LIBS
APP_MACHINEID_CFLAGS
APP_MACHINEID_LIBS
BLKID_CFLAGS
BLKID_LIBS
NOTIFY_DBUS_CFLAGS
@@ -1691,6 +1700,7 @@ Optional Features:
--disable-use-lvmpolld disable usage of LVM Poll Daemon
--enable-dmfilemapd enable the dmstats filemap daemon
--enable-notify-dbus enable LVM notification using dbus
--enable-app-machineid enable LVM system ID using app-specific machine-id
--disable-blkid_wiping disable libblkid detection of signatures when wiping
and use native code instead
--disable-udev-systemd-background-jobs
@@ -1853,6 +1863,13 @@ Some influential environment variables:
C compiler flags for NOTIFY_DBUS, overriding pkg-config
NOTIFY_DBUS_LIBS
linker flags for NOTIFY_DBUS, overriding pkg-config
APP_MACHINEID_CFLAGS
C compiler flags for APP_MACHINEID, overriding pkg-config
APP_MACHINEID_LIBS
linker flags for APP_MACHINEID, 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
@@ -11588,6 +11605,101 @@ $as_echo "yes" >&6; }
fi
fi
################################################################################
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build appmachineid" >&5
$as_echo_n "checking whether to build appmachineid... " >&6; }
# Check whether --enable-app-machineid was given.
if test "${enable_app_machineid+set}" = set; then :
enableval=$enable_app_machineid; APP_MACHINEID_SUPPORT=$enableval
else
APP_MACHINEID_SUPPORT=no
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $APP_MACHINEID_SUPPORT" >&5
$as_echo "$APP_MACHINEID_SUPPORT" >&6; }
if test "$APP_MACHINEID_SUPPORT" = yes; then
$as_echo "#define APP_MACHINEID_SUPPORT 1" >>confdefs.h
SYSTEMD_LIBS="-lsystemd"
fi
################################################################################
if test "$APP_MACHINEID_SUPPORT" = yes; then
pkg_failed=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for APP_MACHINEID" >&5
$as_echo_n "checking for APP_MACHINEID... " >&6; }
if test -n "$APP_MACHINEID_CFLAGS"; then
pkg_cv_APP_MACHINEID_CFLAGS="$APP_MACHINEID_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"systemd >= 234\""; } >&5
($PKG_CONFIG --exists --print-errors "systemd >= 234") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_APP_MACHINEID_CFLAGS=`$PKG_CONFIG --cflags "systemd >= 234" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
else
pkg_failed=untried
fi
if test -n "$APP_MACHINEID_LIBS"; then
pkg_cv_APP_MACHINEID_LIBS="$APP_MACHINEID_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"systemd >= 234\""; } >&5
($PKG_CONFIG --exists --print-errors "systemd >= 234") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_APP_MACHINEID_LIBS=`$PKG_CONFIG --libs "systemd >= 234" 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
APP_MACHINEID_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "systemd >= 234" 2>&1`
else
APP_MACHINEID_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "systemd >= 234" 2>&1`
fi
# Put the nasty error message in config.log where it belongs
echo "$APP_MACHINEID_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
APP_MACHINEID_CFLAGS=$pkg_cv_APP_MACHINEID_CFLAGS
APP_MACHINEID_LIBS=$pkg_cv_APP_MACHINEID_LIBS
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
HAVE_APP_MACHINEID=yes
fi
fi
################################################################################
# Check whether --enable-blkid_wiping was given.

View File

@@ -1104,6 +1104,26 @@ if test "$NOTIFYDBUS_SUPPORT" = yes; then
PKG_CHECK_MODULES(NOTIFY_DBUS, systemd >= 221, [HAVE_NOTIFY_DBUS=yes], $bailout)
fi
################################################################################
dnl -- Build appmachineid
AC_MSG_CHECKING(whether to build appmachineid)
AC_ARG_ENABLE(app-machineid,
AC_HELP_STRING([--enable-app-machineid],
[enable LVM system ID using app-specific machine-id]),
APP_MACHINEID_SUPPORT=$enableval, APP_MACHINEID_SUPPORT=no)
AC_MSG_RESULT($APP_MACHINEID_SUPPORT)
if test "$APP_MACHINEID_SUPPORT" = yes; then
AC_DEFINE([APP_MACHINEID_SUPPORT], 1, [Define to 1 to include code that uses libsystemd machine-id apis.])
SYSTEMD_LIBS="-lsystemd"
fi
################################################################################
dnl -- Look for libsystemd libraries
if test "$APP_MACHINEID_SUPPORT" = yes; then
PKG_CHECK_MODULES(APP_MACHINEID, systemd >= 234, [HAVE_APP_MACHINEID=yes], $bailout)
fi
################################################################################
dnl -- Enable blkid wiping functionality

View File

@@ -52,8 +52,8 @@ def filter_event(action, device):
# when appropriate.
refresh = False
if '.ID_FS_TYPE_NEW' in device:
fs_type_new = device['.ID_FS_TYPE_NEW']
if 'ID_FS_TYPE' in device:
fs_type_new = device['ID_FS_TYPE']
if 'LVM' in fs_type_new:
refresh = True

44
dracut/64-lvm.rules Normal file
View File

@@ -0,0 +1,44 @@
# Copyright 2008,2021 Red Hat, Inc.
#
# Jeremy Katz <katzj@redhat.com>
SUBSYSTEM!="block", GOTO="lvm_end"
ACTION!="add|change", GOTO="lvm_end"
# Also don't process disks that are slated to be a multipath device
ENV{DM_MULTIPATH_DEVICE_PATH}=="1", GOTO="lvm_end"
KERNEL=="dm-[0-9]*", ACTION=="add", GOTO="lvm_end"
ENV{ID_FS_TYPE}!="LVM2_member", GOTO="lvm_end"
PROGRAM=="/bin/sh -c 'for i in $sys/$devpath/holders/dm-[0-9]*; do [ -e $$i ] && exit 0; done; exit 1;' ", \
GOTO="lvm_end"
# pvscan-udev-initrd.sh is a wrapper that calls pvscan and prints
# LVM_VG_NAME_COMPLETE='...'
# LVM_LV_NAMES_COMPLETE='...'
# if the given device completes a VG or LVs listed in
# rd.lvm.vg or rd.lvm.lv
#
# If a VG or LVs are completed by the device, but are not
# listed in rd.lvm.vg/lv, then they are not printed
# (we don't want to activate VGs/LVs that are not specified.)
#
# If no VG or LVs are completed by the device, then
# nothing is printed.
#
# LVs may be complete and activated before the VG is complete,
# i.e. the entire VG is not necessary to activate LVs in it.
#
# If multiple LV names are completed from one device,
# e.g. LVM_LV_NAMES_COMPLETE='vg/lv1 vg/lv2 vg/lv3'
# they will be activated by one lvchange command.
IMPORT{program}="pvscan-udev-initrd.sh $env{DEVNAME}"
# systemd services are used to run vgchange/lvchange
# because the lvm activation commands can run for longer
# than udev will tolerate.
ENV{LVM_VG_NAME_COMPLETE}=="?*", RUN+="/usr/bin/systemd-run --no-block --property DefaultDependencies=no /sbin/lvm vgchange -ay --yes --ignoremonitoring --poll n --sysinit $env{LVM_VG_NAME_COMPLETE}"
ENV{LVM_LV_NAMES_COMPLETE}=="?*", RUN+="/usr/bin/systemd-run --no-block --property DefaultDependencies=no /sbin/lvm lvchange -ay --yes -K --ignoremonitoring --poll n --sysinit $env{LVM_LV_NAMES_COMPLETE}"
LABEL="lvm_end"

112
dracut/module-setup.sh Executable file
View File

@@ -0,0 +1,112 @@
#!/bin/bash
# called by dracut
check() {
# No point trying to support lvm if the binaries are missing
require_binaries lvm || return 1
[[ $hostonly ]] || [[ $mount_needs ]] && {
for fs in "${host_fs_types[@]}"; do
[[ $fs = LVM*_member ]] && return 0
done
return 255
}
return 0
}
# called by dracut
depends() {
# We depend on dm_mod being loaded
echo rootfs-block dm
return 0
}
# called by dracut
cmdline() {
local _activated
declare -A _activated
for dev in "${!host_fs_types[@]}"; do
[ -e /sys/block/${dev#/dev/}/dm/name ] || continue
[ -e /sys/block/${dev#/dev/}/dm/uuid ] || continue
uuid=$(</sys/block/${dev#/dev/}/dm/uuid)
[[ "${uuid#LVM-}" == "$uuid" ]] && continue
dev=$(</sys/block/${dev#/dev/}/dm/name)
eval $(dmsetup splitname --nameprefixes --noheadings --rows "$dev" 2>/dev/null)
[[ ${DM_VG_NAME} ]] && [[ ${DM_LV_NAME} ]] || return 1
if ! [[ ${_activated[${DM_VG_NAME}/${DM_LV_NAME}]} ]]; then
printf " rd.lvm.lv=%s " "${DM_VG_NAME}/${DM_LV_NAME} "
_activated["${DM_VG_NAME}/${DM_LV_NAME}"]=1
fi
done
}
installkernel() {
hostonly='' instmods dm-snapshot
}
# called by dracut
install() {
local _i
inst lvm
if [[ $hostonly_cmdline == "yes" ]]; then
local _lvmconf=$(cmdline)
[[ $_lvmconf ]] && printf "%s\n" "$_lvmconf" >> "${initdir}/etc/cmdline.d/90lvm.conf"
fi
inst_rules "$moddir/64-lvm.rules"
if [[ $hostonly ]] || [[ $lvmconf = "yes" ]]; then
if [ -f $dracutsysrootdir/etc/lvm/lvm.conf ]; then
inst_simple -H /etc/lvm/lvm.conf
fi
export LVM_SUPPRESS_FD_WARNINGS=1
# Also install any files needed for LVM system id support.
if [ -f $dracutsysrootdir/etc/lvm/lvmlocal.conf ]; then
inst_simple -H /etc/lvm/lvmlocal.conf
fi
eval $(lvm dumpconfig global/system_id_source &>/dev/null)
if [ "$system_id_source" == "file" ]; then
eval $(lvm dumpconfig global/system_id_file)
if [ -f "$system_id_file" ]; then
inst_simple -H $system_id_file
fi
fi
unset LVM_SUPPRESS_FD_WARNINGS
fi
inst_rules 11-dm-lvm.rules
inst_script "$moddir/pvscan-udev-initrd.sh" /usr/lib/udev/pvscan-udev-initrd.sh
inst_hook cmdline 30 "$moddir/parse-lvm.sh"
inst_libdir_file "libdevmapper-event-lvm*.so"
if [[ $hostonly ]] && type -P lvs &>/dev/null; then
for dev in "${!host_fs_types[@]}"; do
[ -e /sys/block/${dev#/dev/}/dm/name ] || continue
dev=$(</sys/block/${dev#/dev/}/dm/name)
eval $(dmsetup splitname --nameprefixes --noheadings --rows "$dev" 2>/dev/null)
[[ ${DM_VG_NAME} ]] && [[ ${DM_LV_NAME} ]] || continue
case "$(lvs --noheadings -o segtype ${DM_VG_NAME} 2>/dev/null)" in
*thin*|*cache*|*era*)
inst_multiple -o thin_dump thin_restore thin_check thin_repair \
cache_dump cache_restore cache_check cache_repair \
era_check era_dump era_invalidate era_restore
break;;
esac
done
fi
if ! [[ $hostonly ]]; then
inst_multiple -o thin_dump thin_restore thin_check thin_repair \
cache_dump cache_restore cache_check cache_repair \
era_check era_dump era_invalidate era_restore
fi
dracut_need_initqueue
}

18
dracut/parse-lvm.sh Executable file
View File

@@ -0,0 +1,18 @@
#!/bin/sh
if [ -e /etc/lvm/lvm.conf ] && ! getargbool 1 rd.lvm.conf -d -n rd_NO_LVMCONF; then
rm -f -- /etc/lvm/lvm.conf
fi
LV_DEVS="$(getargs rd.lvm.vg -d rd_LVM_VG=) $(getargs rd.lvm.lv -d rd_LVM_LV=)"
if ! getargbool 1 rd.lvm -d -n rd_NO_LVM \
|| ( [ -z "$LV_DEVS" ] && ! getargbool 0 rd.auto ); then
info "rd.lvm=0: removing LVM activation"
rm -f -- /etc/udev/rules.d/64-lvm*.rules
else
for dev in $LV_DEVS; do
wait_for_dev -n "/dev/$dev"
done
fi

57
dracut/pvscan-udev-initrd.sh Executable file
View File

@@ -0,0 +1,57 @@
#!/bin/sh
# pvscan wrapper called by initrd lvm udev rule to find the
# intersection of complete VGs/LVs found by pvscan and the
# requested VGs/LVs from the cmdline.
#
# Used in 64-lvm.rules as:
# IMPORT{program}="pvscan-udev-initrd.sh $env{DEVNAME}"
#
# See /usr/lib/dracut/modules.d/90lvm/64-lvm.rules
dev=$1
type getarg >/dev/null 2>&1 || . /lib/dracut-lib.sh
VGS=$(getargs rd.lvm.vg -d rd_LVM_VG=)
LVS=$(getargs rd.lvm.lv -d rd_LVM_LV=)
IFS=' '
# pvscan will produce a single VG line, and one or more LV lines.
# VG <name> complete
# VG <name> incomplete
# LV <name> complete
# LV <name> incomplete
#
# LV names are printed as vgname/lvname.
# We only care about the complete items.
# Each pvscan will produce a single VG line,
# and may produce zero, one or more LV lines.
PVSCAN=$(/sbin/lvm pvscan --cache --listlvs --checkcomplete --journal output --config 'global/event_activation=1' $dev)
read -r -a VGSARRAY <<< "$VGS"
for VG in "${VGSARRAY[@]}"
do
if strstr "$PVSCAN" "VG $VG complete" ; then
echo LVM_VG_NAME_COMPLETE=\'"$VG"\'
fi
done
# Combine all matching LVs into a single print containing them all,
# e.g. LVM_LV_NAMES_COMPLETE='vg/lv1 vg/lv2'
read -r -a LVSARRAY <<< "$LVS"
echo -n LVM_LV_NAMES_COMPLETE=\'
for LV in "${LVSARRAY[@]}"
do
if strstr "$PVSCAN" "LV $LV complete" ; then
echo -n "$LV "
fi
done
echo \'

View File

@@ -1,5 +1,8 @@
/* include/configure.h.in. Generated from configure.ac by autoheader. */
/* Define to 1 to include code that uses libsystemd machine-id apis. */
#undef APP_MACHINEID_SUPPORT
/* Define to 1 to use libblkid detection of signatures when wiping. */
#undef BLKID_WIPING_SUPPORT

View File

@@ -41,6 +41,10 @@
#include <syslog.h>
#include <time.h>
#ifdef APP_MACHINEID_SUPPORT
#include <systemd/sd-id128.h>
#endif
#ifdef __linux__
# include <malloc.h>
#endif
@@ -129,9 +133,12 @@ static const char *_read_system_id_from_file(struct cmd_context *cmd, const char
return system_id;
}
/* systemd-id128 new produced: f64406832c2140e8ac5422d1089aae03 */
#define LVM_APPLICATION_ID SD_ID128_MAKE(f6,44,06,83,2c,21,40,e8,ac,54,22,d1,08,9a,ae,03)
static const char *_system_id_from_source(struct cmd_context *cmd, const char *source)
{
char filebuf[PATH_MAX];
char buf[PATH_MAX];
const char *file;
const char *etc_str;
const char *str;
@@ -150,10 +157,23 @@ static const char *_system_id_from_source(struct cmd_context *cmd, const char *s
goto out;
}
#ifdef APP_MACHINEID_SUPPORT
if (!strcasecmp(source, "appmachineid")) {
sd_id128_t id;
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;
system_id = system_id_from_string(cmd, buf);
goto out;
}
#endif
if (!strcasecmp(source, "machineid") || !strcasecmp(source, "machine-id")) {
etc_str = find_config_tree_str(cmd, global_etc_CFG, NULL);
if (dm_snprintf(filebuf, sizeof(filebuf), "%s/machine-id", etc_str) != -1)
system_id = _read_system_id_from_file(cmd, filebuf);
if (dm_snprintf(buf, sizeof(buf), "%s/machine-id", etc_str) != -1)
system_id = _read_system_id_from_file(cmd, buf);
goto out;
}
@@ -320,6 +340,33 @@ static int _parse_debug_classes(struct cmd_context *cmd)
return debug_classes;
}
static uint32_t _parse_log_journal(struct cmd_context *cmd, int cfg, const char *cfgname)
{
const struct dm_config_node *cn;
const struct dm_config_value *cv;
uint32_t fields = 0;
uint32_t val;
if (!(cn = find_config_tree_array(cmd, cfg, NULL))) {
log_debug("Unable to find configuration for log/%s.", cfgname);
return 0;
}
for (cv = cn->v; cv; cv = cv->next) {
if (cv->type != DM_CFG_STRING) {
log_verbose("log/%s contains a value which is not a string. Ignoring.", cfgname);
continue;
}
if ((val = log_journal_str_to_val(cv->v.str)))
fields |= val;
else
log_verbose("Unrecognised value for log/%s: %s", cfgname, cv->v.str);
}
return fields;
}
static void _init_logging(struct cmd_context *cmd)
{
int append = 1;
@@ -388,6 +435,9 @@ static void _init_logging(struct cmd_context *cmd)
init_debug_file_fields(_parse_debug_fields(cmd, log_debug_file_fields_CFG, "debug_file_fields"));
init_debug_output_fields(_parse_debug_fields(cmd, log_debug_output_fields_CFG, "debug_output_fields"));
cmd->default_settings.journal = _parse_log_journal(cmd, log_journal_CFG, "journal");
init_log_journal(cmd->default_settings.journal);
t = time(NULL);
ctime_r(&t, &timebuf[0]);
timebuf[24] = '\0';

View File

@@ -29,6 +29,7 @@ struct config_info {
int debug_classes;
int verbose;
int silent;
int suppress;
int test;
int syslog;
int activation;
@@ -40,6 +41,7 @@ struct config_info {
int udev_sync;
int udev_fallback;
int issue_discards;
uint32_t journal;
const char *msg_prefix;
const char *fmt_name;
const char *dmeventd_executable;
@@ -180,6 +182,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 */

View File

@@ -205,7 +205,7 @@ cfg_section(local_CFG_SECTION, "local", root_CFG_SECTION, 0, vsn(2, 2, 117), 0,
"# Please take care that each setting only appears once if uncommenting\n" \
"# example settings in this file and never copy this file between hosts.\n\n"
cfg(config_checks_CFG, "checks", config_CFG_SECTION, 0, CFG_TYPE_BOOL, 1, vsn(2, 2, 99), NULL, 0, NULL,
cfg(config_checks_CFG, "checks", config_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 1, vsn(2, 2, 99), NULL, 0, NULL,
"If enabled, any LVM configuration mismatch is reported.\n"
"This implies checking that the configuration key is understood by\n"
"LVM and that the value of the key is the proper type. If disabled,\n"
@@ -213,22 +213,22 @@ cfg(config_checks_CFG, "checks", config_CFG_SECTION, 0, CFG_TYPE_BOOL, 1, vsn(2,
"without any warning (a message about the configuration key not being\n"
"found is issued in verbose mode only).\n")
cfg(config_abort_on_errors_CFG, "abort_on_errors", config_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(2,2,99), NULL, 0, NULL,
cfg(config_abort_on_errors_CFG, "abort_on_errors", config_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 0, vsn(2,2,99), NULL, 0, NULL,
"Abort the LVM process if a configuration mismatch is found.\n")
cfg_runtime(config_profile_dir_CFG, "profile_dir", config_CFG_SECTION, CFG_DISALLOW_INTERACTIVE, CFG_TYPE_STRING, vsn(2, 2, 99), 0, NULL,
cfg_runtime(config_profile_dir_CFG, "profile_dir", config_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_DISALLOW_INTERACTIVE, CFG_TYPE_STRING, vsn(2, 2, 99), 0, NULL,
"Directory where LVM looks for configuration profiles.\n")
cfg(devices_dir_CFG, "dir", devices_CFG_SECTION, CFG_ADVANCED, CFG_TYPE_STRING, DEFAULT_DEV_DIR, vsn(1, 0, 0), NULL, 0, NULL,
cfg(devices_dir_CFG, "dir", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_ADVANCED, CFG_TYPE_STRING, DEFAULT_DEV_DIR, vsn(1, 0, 0), NULL, 0, NULL,
"Directory in which to create volume group device nodes.\n"
"Commands also accept this as a prefix on volume group names.\n")
cfg_array(devices_scan_CFG, "scan", devices_CFG_SECTION, CFG_ADVANCED, CFG_TYPE_STRING, "#S/dev", vsn(1, 0, 0), NULL, 0, NULL,
cfg_array(devices_scan_CFG, "scan", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_ADVANCED, CFG_TYPE_STRING, "#S/dev", vsn(1, 0, 0), NULL, 0, NULL,
"Directories containing device nodes to use with LVM.\n")
cfg_array(devices_loopfiles_CFG, "loopfiles", devices_CFG_SECTION, CFG_DEFAULT_UNDEFINED | CFG_UNSUPPORTED, CFG_TYPE_STRING, NULL, vsn(1, 2, 0), NULL, vsn(2, 3, 0), NULL, NULL)
cfg(devices_obtain_device_list_from_udev_CFG, "obtain_device_list_from_udev", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_OBTAIN_DEVICE_LIST_FROM_UDEV, vsn(2, 2, 85), NULL, 0, NULL,
cfg(devices_obtain_device_list_from_udev_CFG, "obtain_device_list_from_udev", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_OBTAIN_DEVICE_LIST_FROM_UDEV, vsn(2, 2, 85), NULL, 0, NULL,
"Obtain the list of available devices from udev.\n"
"This avoids opening or using any inapplicable non-block devices or\n"
"subdirectories found in the udev directory. Any device node or\n"
@@ -237,7 +237,7 @@ cfg(devices_obtain_device_list_from_udev_CFG, "obtain_device_list_from_udev", de
"directories will be scanned fully. LVM needs to be compiled with\n"
"udev support for this setting to apply.\n")
cfg(devices_external_device_info_source_CFG, "external_device_info_source", devices_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_EXTERNAL_DEVICE_INFO_SOURCE, vsn(2, 2, 116), NULL, 0, NULL,
cfg(devices_external_device_info_source_CFG, "external_device_info_source", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_EXTERNAL_DEVICE_INFO_SOURCE, vsn(2, 2, 116), NULL, 0, NULL,
"Enable device information from udev.\n"
"If set to \"udev\", lvm will supplement its own native device information\n"
"with information from libudev. This can potentially improve the detection\n"
@@ -360,12 +360,12 @@ cfg_array(devices_types_CFG, "types", devices_CFG_SECTION, CFG_DEFAULT_UNDEFINED
"types = [ \"fd\", 16 ]\n"
"#\n")
cfg(devices_sysfs_scan_CFG, "sysfs_scan", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_SYSFS_SCAN, vsn(1, 0, 8), NULL, 0, NULL,
cfg(devices_sysfs_scan_CFG, "sysfs_scan", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_SYSFS_SCAN, vsn(1, 0, 8), NULL, 0, NULL,
"Restrict device scanning to block devices appearing in sysfs.\n"
"This is a quick way of filtering out block devices that are not\n"
"present on the system. sysfs must be part of the kernel and mounted.)\n")
cfg(devices_scan_lvs_CFG, "scan_lvs", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_SCAN_LVS, vsn(2, 2, 182), NULL, 0, NULL,
cfg(devices_scan_lvs_CFG, "scan_lvs", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_SCAN_LVS, vsn(2, 2, 182), NULL, 0, NULL,
"Scan LVM LVs for layered PVs, allowing LVs to be used as PVs.\n"
"When 1, LVM will detect PVs layered on LVs, and caution must be\n"
"taken to avoid a host accessing a layered VG that may not belong\n"
@@ -378,14 +378,14 @@ cfg(devices_scan_lvs_CFG, "scan_lvs", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEF
"an LV. The LVs are ignored using a built in device filter that\n"
"identifies and excludes LVs.\n")
cfg(devices_multipath_component_detection_CFG, "multipath_component_detection", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_MULTIPATH_COMPONENT_DETECTION, vsn(2, 2, 89), NULL, 0, NULL,
cfg(devices_multipath_component_detection_CFG, "multipath_component_detection", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_MULTIPATH_COMPONENT_DETECTION, vsn(2, 2, 89), NULL, 0, NULL,
"Ignore devices that are components of DM multipath devices.\n")
cfg(devices_multipath_wwids_file_CFG, "multipath_wwids_file", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_ALLOW_EMPTY, CFG_TYPE_STRING, DEFAULT_WWIDS_FILE, vsn(2, 3, 13), NULL, 0, NULL,
"The path to the multipath wwids file used for multipath component detection.\n"
"Set this to an empty string to disable the use of the multipath wwids file.\n")
cfg(devices_md_component_detection_CFG, "md_component_detection", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_MD_COMPONENT_DETECTION, vsn(1, 0, 18), NULL, 0, NULL,
cfg(devices_md_component_detection_CFG, "md_component_detection", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_MD_COMPONENT_DETECTION, vsn(1, 0, 18), NULL, 0, NULL,
"Enable detection and exclusion of MD component devices.\n"
"An MD component device is a block device that MD uses as part\n"
"of a software RAID virtual device. When an LVM PV is created\n"
@@ -411,12 +411,12 @@ cfg(devices_md_component_checks_CFG, "md_component_checks", devices_CFG_SECTION,
" This requires an extra read at the end of devices.\n"
"#\n")
cfg(devices_fw_raid_component_detection_CFG, "fw_raid_component_detection", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_FW_RAID_COMPONENT_DETECTION, vsn(2, 2, 112), NULL, 0, NULL,
cfg(devices_fw_raid_component_detection_CFG, "fw_raid_component_detection", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_FW_RAID_COMPONENT_DETECTION, vsn(2, 2, 112), NULL, 0, NULL,
"Ignore devices that are components of firmware RAID devices.\n"
"LVM must use an external_device_info_source other than none for this\n"
"detection to execute.\n")
cfg(devices_md_chunk_alignment_CFG, "md_chunk_alignment", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_MD_CHUNK_ALIGNMENT, vsn(2, 2, 48), NULL, 0, NULL,
cfg(devices_md_chunk_alignment_CFG, "md_chunk_alignment", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_MD_CHUNK_ALIGNMENT, vsn(2, 2, 48), NULL, 0, NULL,
"Align the start of a PV data area with md device's stripe-width.\n"
"This applies if a PV is placed directly on an md device.\n"
"default_data_alignment will be overridden if it is not aligned\n"
@@ -430,7 +430,7 @@ cfg(devices_default_data_alignment_CFG, "default_data_alignment", devices_CFG_SE
"This setting is overridden by data_alignment and the --dataalignment\n"
"option.\n")
cfg(devices_data_alignment_detection_CFG, "data_alignment_detection", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_DATA_ALIGNMENT_DETECTION, vsn(2, 2, 51), NULL, 0, NULL,
cfg(devices_data_alignment_detection_CFG, "data_alignment_detection", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_DATA_ALIGNMENT_DETECTION, vsn(2, 2, 51), NULL, 0, NULL,
"Align the start of a PV data area with sysfs io properties.\n"
"The start of a PV data area will be a multiple of minimum_io_size or\n"
"optimal_io_size exposed in sysfs. minimum_io_size is the smallest\n"
@@ -444,14 +444,14 @@ cfg(devices_data_alignment_detection_CFG, "data_alignment_detection", devices_CF
"This setting is overridden by data_alignment and the --dataalignment\n"
"option.\n")
cfg(devices_data_alignment_CFG, "data_alignment", devices_CFG_SECTION, 0, CFG_TYPE_INT, 0, vsn(2, 2, 45), NULL, 0, NULL,
cfg(devices_data_alignment_CFG, "data_alignment", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, 0, vsn(2, 2, 45), NULL, 0, NULL,
"Align the start of a PV data area with this number of KiB.\n"
"When non-zero, this setting overrides default_data_alignment.\n"
"Set to 0 to disable, in which case default_data_alignment\n"
"is used to align the first PE in units of MiB.\n"
"This setting is overridden by the --dataalignment option.\n")
cfg(devices_data_alignment_offset_detection_CFG, "data_alignment_offset_detection", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_DATA_ALIGNMENT_OFFSET_DETECTION, vsn(2, 2, 50), NULL, 0, NULL,
cfg(devices_data_alignment_offset_detection_CFG, "data_alignment_offset_detection", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_DATA_ALIGNMENT_OFFSET_DETECTION, vsn(2, 2, 50), NULL, 0, NULL,
"Shift the start of an aligned PV data area based on sysfs information.\n"
"After a PV data area is aligned, it will be shifted by the\n"
"alignment_offset exposed in sysfs. This offset is often 0, but may\n"
@@ -461,12 +461,12 @@ cfg(devices_data_alignment_offset_detection_CFG, "data_alignment_offset_detectio
"LBA -1, and consequently sector 63 is aligned on a 4KiB boundary).\n"
"This setting is overridden by the --dataalignmentoffset option.\n")
cfg(devices_ignore_suspended_devices_CFG, "ignore_suspended_devices", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_IGNORE_SUSPENDED_DEVICES, vsn(1, 2, 19), NULL, 0, NULL,
cfg(devices_ignore_suspended_devices_CFG, "ignore_suspended_devices", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_IGNORE_SUSPENDED_DEVICES, vsn(1, 2, 19), NULL, 0, NULL,
"Ignore DM devices that have I/O suspended while scanning devices.\n"
"Otherwise, LVM waits for a suspended device to become accessible.\n"
"This should only be needed in recovery situations.\n")
cfg(devices_ignore_lvm_mirrors_CFG, "ignore_lvm_mirrors", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_IGNORE_LVM_MIRRORS, vsn(2, 2, 104), NULL, 0, NULL,
cfg(devices_ignore_lvm_mirrors_CFG, "ignore_lvm_mirrors", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_IGNORE_LVM_MIRRORS, vsn(2, 2, 104), NULL, 0, NULL,
"Do not scan 'mirror' LVs to avoid possible deadlocks.\n"
"This avoids possible deadlocks when using the 'mirror' segment type.\n"
"This setting determines whether LVs using the 'mirror' segment type\n"
@@ -484,19 +484,19 @@ cfg(devices_ignore_lvm_mirrors_CFG, "ignore_lvm_mirrors", devices_CFG_SECTION, 0
"apply to LVM RAID types like 'raid1' which handle failures in a\n"
"different way, making them a better choice for VG stacking.\n")
cfg(devices_disable_after_error_count_CFG, "disable_after_error_count", devices_CFG_SECTION, 0, CFG_TYPE_INT, 0, vsn(2, 2, 75), NULL, vsn(2, 3, 0), NULL,
cfg(devices_disable_after_error_count_CFG, "disable_after_error_count", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, 0, vsn(2, 2, 75), NULL, vsn(2, 3, 0), NULL,
NULL)
cfg(devices_require_restorefile_with_uuid_CFG, "require_restorefile_with_uuid", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_REQUIRE_RESTOREFILE_WITH_UUID, vsn(2, 2, 73), NULL, 0, NULL,
cfg(devices_require_restorefile_with_uuid_CFG, "require_restorefile_with_uuid", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_REQUIRE_RESTOREFILE_WITH_UUID, vsn(2, 2, 73), NULL, 0, NULL,
"Allow use of pvcreate --uuid without requiring --restorefile.\n")
cfg(devices_pv_min_size_CFG, "pv_min_size", devices_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_PV_MIN_SIZE_KB, vsn(2, 2, 85), NULL, 0, NULL,
cfg(devices_pv_min_size_CFG, "pv_min_size", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_PV_MIN_SIZE_KB, vsn(2, 2, 85), NULL, 0, NULL,
"Minimum size in KiB of block devices which can be used as PVs.\n"
"In a clustered environment all nodes must use the same value.\n"
"Any value smaller than 512KiB is ignored. The previous built-in\n"
"value was 512.\n")
cfg(devices_issue_discards_CFG, "issue_discards", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_ISSUE_DISCARDS, vsn(2, 2, 85), NULL, 0, NULL,
cfg(devices_issue_discards_CFG, "issue_discards", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_ISSUE_DISCARDS, vsn(2, 2, 85), NULL, 0, NULL,
"Issue discards to PVs that are no longer used by an LV.\n"
"Discards are sent to an LV's underlying physical volumes when the LV\n"
"is no longer using the physical volumes' space, e.g. lvremove,\n"
@@ -508,7 +508,7 @@ cfg(devices_issue_discards_CFG, "issue_discards", devices_CFG_SECTION, 0, CFG_TY
"generally do. If enabled, discards will only be issued if both the\n"
"storage and kernel provide support.\n")
cfg(devices_allow_changes_with_duplicate_pvs_CFG, "allow_changes_with_duplicate_pvs", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_ALLOW_CHANGES_WITH_DUPLICATE_PVS, vsn(2, 2, 153), NULL, 0, NULL,
cfg(devices_allow_changes_with_duplicate_pvs_CFG, "allow_changes_with_duplicate_pvs", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_ALLOW_CHANGES_WITH_DUPLICATE_PVS, vsn(2, 2, 153), NULL, 0, NULL,
"Allow VG modification while a PV appears on multiple devices.\n"
"When a PV appears on multiple devices, LVM attempts to choose the\n"
"best device to use for the PV. If the devices represent the same\n"
@@ -520,7 +520,7 @@ cfg(devices_allow_changes_with_duplicate_pvs_CFG, "allow_changes_with_duplicate_
"Enabling this setting allows the VG to be used as usual even with\n"
"uncertain devices.\n")
cfg(devices_allow_mixed_block_sizes_CFG, "allow_mixed_block_sizes", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(2, 3, 6), NULL, 0, NULL,
cfg(devices_allow_mixed_block_sizes_CFG, "allow_mixed_block_sizes", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 0, vsn(2, 3, 6), NULL, 0, NULL,
"Allow PVs in the same VG with different logical block sizes.\n"
"When allowed, the user is responsible to ensure that an LV is\n"
"using PVs with matching block sizes when necessary.\n")
@@ -543,14 +543,14 @@ cfg_array(allocation_cling_tag_list_CFG, "cling_tag_list", allocation_CFG_SECTIO
"cling_tag_list = [ \"@site1\", \"@site2\" ]\n"
"#\n")
cfg(allocation_maximise_cling_CFG, "maximise_cling", allocation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_MAXIMISE_CLING, vsn(2, 2, 85), NULL, 0, NULL,
cfg(allocation_maximise_cling_CFG, "maximise_cling", allocation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_MAXIMISE_CLING, vsn(2, 2, 85), NULL, 0, NULL,
"Use a previous allocation algorithm.\n"
"Changes made in version 2.02.85 extended the reach of the 'cling'\n"
"policies to detect more situations where data can be grouped onto\n"
"the same disks. This setting can be used to disable the changes\n"
"and revert to the previous algorithm.\n")
cfg(allocation_use_blkid_wiping_CFG, "use_blkid_wiping", allocation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_USE_BLKID_WIPING, vsn(2, 2, 105), "@DEFAULT_USE_BLKID_WIPING@", 0, NULL,
cfg(allocation_use_blkid_wiping_CFG, "use_blkid_wiping", allocation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_USE_BLKID_WIPING, vsn(2, 2, 105), "@DEFAULT_USE_BLKID_WIPING@", 0, NULL,
"Use blkid to detect and erase existing signatures on new PVs and LVs.\n"
"The blkid library can detect more signatures than the native LVM\n"
"detection code, but may take longer. LVM needs to be compiled with\n"
@@ -559,7 +559,7 @@ cfg(allocation_use_blkid_wiping_CFG, "use_blkid_wiping", allocation_CFG_SECTION,
"swap signature, and LUKS signatures. To see the list of signatures\n"
"recognized by blkid, check the output of the 'blkid -k' command.\n")
cfg(allocation_wipe_signatures_when_zeroing_new_lvs_CFG, "wipe_signatures_when_zeroing_new_lvs", allocation_CFG_SECTION, 0, CFG_TYPE_BOOL, 1, vsn(2, 2, 105), NULL, 0, NULL,
cfg(allocation_wipe_signatures_when_zeroing_new_lvs_CFG, "wipe_signatures_when_zeroing_new_lvs", allocation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 1, vsn(2, 2, 105), NULL, 0, NULL,
"Look for and erase any signatures while zeroing a new LV.\n"
"The --wipesignatures option overrides this setting.\n"
"Zeroing is controlled by the -Z/--zero option, and if not specified,\n"
@@ -575,7 +575,7 @@ cfg(allocation_wipe_signatures_when_zeroing_new_lvs_CFG, "wipe_signatures_when_z
"When this setting is disabled, signatures on new LVs are not detected\n"
"or erased unless the --wipesignatures option is used directly.\n")
cfg(allocation_mirror_logs_require_separate_pvs_CFG, "mirror_logs_require_separate_pvs", allocation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_MIRROR_LOGS_REQUIRE_SEPARATE_PVS, vsn(2, 2, 85), NULL, 0, NULL,
cfg(allocation_mirror_logs_require_separate_pvs_CFG, "mirror_logs_require_separate_pvs", allocation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_MIRROR_LOGS_REQUIRE_SEPARATE_PVS, vsn(2, 2, 85), NULL, 0, NULL,
"Mirror logs and images will always use different PVs.\n"
"The default setting changed in version 2.02.85.\n")
@@ -852,10 +852,10 @@ cfg(log_command_log_selection_CFG, "command_log_selection", log_CFG_SECTION, CFG
"For more information about selection criteria in general, see\n"
"lvm(8) man page.\n")
cfg(log_verbose_CFG, "verbose", log_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_VERBOSE, vsn(1, 0, 0), NULL, 0, NULL,
cfg(log_verbose_CFG, "verbose", log_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VERBOSE, vsn(1, 0, 0), NULL, 0, NULL,
"Controls the messages sent to stdout or stderr.\n")
cfg(log_silent_CFG, "silent", log_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_SILENT, vsn(2, 2, 98), NULL, 0, NULL,
cfg(log_silent_CFG, "silent", log_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_SILENT, vsn(2, 2, 98), NULL, 0, NULL,
"Suppress all non-essential messages from stdout.\n"
"This has the same effect as -qq. When enabled, the following commands\n"
"still produce output: dumpconfig, lvdisplay, lvmdiskscan, lvs, pvck,\n"
@@ -865,16 +865,22 @@ cfg(log_silent_CFG, "silent", log_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_SILENT,
"Any 'yes' or 'no' questions not overridden by other arguments are\n"
"suppressed and default to 'no'.\n")
cfg(log_syslog_CFG, "syslog", log_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_SYSLOG, vsn(1, 0, 0), NULL, 0, NULL,
cfg(log_syslog_CFG, "syslog", log_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_SYSLOG, vsn(1, 0, 0), NULL, 0, NULL,
"Send log messages through syslog.\n")
cfg(log_file_CFG, "file", log_CFG_SECTION, CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL, 0, NULL,
"Write error and debug log messages to a file specified here.\n")
cfg(log_overwrite_CFG, "overwrite", log_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_OVERWRITE, vsn(1, 0, 0), NULL, 0, NULL,
cfg_array(log_journal_CFG, "journal", log_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, NULL, vsn(2, 3, 12), NULL, 0, NULL,
"Record lvm information in the systemd journal.\n"
"command: record commands that are run.\n"
"output: record default output from commands.\n"
"debug: record debug messages from commands.\n")
cfg(log_overwrite_CFG, "overwrite", log_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_OVERWRITE, vsn(1, 0, 0), NULL, 0, NULL,
"Overwrite the log file each time the program is run.\n")
cfg(log_level_CFG, "level", log_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_LOGLEVEL, vsn(1, 0, 0), NULL, 0, NULL,
cfg(log_level_CFG, "level", log_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_LOGLEVEL, vsn(1, 0, 0), NULL, 0, NULL,
"The level of log messages that are sent to the log file or syslog.\n"
"There are 6 syslog-like log levels currently in use: 2 to 7 inclusive.\n"
"7 is the most verbose (LOG_DEBUG).\n")
@@ -882,23 +888,23 @@ cfg(log_level_CFG, "level", log_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_LOGLEVEL,
cfg(log_indent_CFG, "indent", log_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_INDENT, vsn(1, 0, 0), NULL, 0, NULL,
"Indent messages according to their severity.\n")
cfg(log_command_names_CFG, "command_names", log_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_CMD_NAME, vsn(1, 0, 0), NULL, 0, NULL,
cfg(log_command_names_CFG, "command_names", log_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_CMD_NAME, vsn(1, 0, 0), NULL, 0, NULL,
"Display the command name on each line of output.\n")
cfg(log_prefix_CFG, "prefix", log_CFG_SECTION, CFG_ALLOW_EMPTY, CFG_TYPE_STRING, DEFAULT_MSG_PREFIX, vsn(1, 0, 0), NULL, 0, NULL,
cfg(log_prefix_CFG, "prefix", log_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_ALLOW_EMPTY, CFG_TYPE_STRING, DEFAULT_MSG_PREFIX, vsn(1, 0, 0), NULL, 0, NULL,
"A prefix to use before the log message text.\n"
"(After the command name, if selected).\n"
"Two spaces allows you to see/grep the severity of each message.\n"
"To make the messages look similar to the original LVM tools use:\n"
"indent = 0, command_names = 1, prefix = \" -- \"\n")
cfg(log_activation_CFG, "activation", log_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(1, 0, 0), NULL, 0, NULL,
cfg(log_activation_CFG, "activation", log_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 0, vsn(1, 0, 0), NULL, 0, NULL,
"Log messages during activation.\n"
"Don't use this in low memory situations (can deadlock).\n")
cfg(log_activate_file_CFG, "activate_file", log_CFG_SECTION, CFG_DEFAULT_UNDEFINED | CFG_UNSUPPORTED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL, 0, NULL, NULL)
cfg_array(log_debug_classes_CFG, "debug_classes", log_CFG_SECTION, CFG_ALLOW_EMPTY, CFG_TYPE_STRING, "#Smemory#Sdevices#Sio#Sactivation#Sallocation#Smetadata#Scache#Slocking#Slvmpolld#Sdbus", vsn(2, 2, 99), NULL, 0, NULL,
cfg_array(log_debug_classes_CFG, "debug_classes", log_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_ALLOW_EMPTY, CFG_TYPE_STRING, "#Smemory#Sdevices#Sio#Sactivation#Sallocation#Smetadata#Scache#Slocking#Slvmpolld#Sdbus", vsn(2, 2, 99), NULL, 0, NULL,
"Select log messages by class.\n"
"Some debugging messages are assigned to a class and only appear in\n"
"debug output if the class is listed here. Classes currently\n"
@@ -913,55 +919,55 @@ cfg_array(log_debug_output_fields_CFG, "debug_output_fields", log_CFG_SECTION, C
"The fields included in debug output written to stderr.\n"
"Use \"all\" to include everything (the default).\n")
cfg(backup_backup_CFG, "backup", backup_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_BACKUP_ENABLED, vsn(1, 0, 0), NULL, 0, NULL,
cfg(backup_backup_CFG, "backup", backup_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_BACKUP_ENABLED, vsn(1, 0, 0), NULL, 0, NULL,
"Maintain a backup of the current metadata configuration.\n"
"Think very hard before turning this off!\n")
cfg_runtime(backup_backup_dir_CFG, "backup_dir", backup_CFG_SECTION, 0, CFG_TYPE_STRING, vsn(1, 0, 0), 0, NULL,
cfg_runtime(backup_backup_dir_CFG, "backup_dir", backup_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, vsn(1, 0, 0), 0, NULL,
"Location of the metadata backup files.\n"
"Remember to back up this directory regularly!\n")
cfg(backup_archive_CFG, "archive", backup_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_ARCHIVE_ENABLED, vsn(1, 0, 0), NULL, 0, NULL,
cfg(backup_archive_CFG, "archive", backup_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_ARCHIVE_ENABLED, vsn(1, 0, 0), NULL, 0, NULL,
"Maintain an archive of old metadata configurations.\n"
"Think very hard before turning this off.\n")
cfg_runtime(backup_archive_dir_CFG, "archive_dir", backup_CFG_SECTION, 0, CFG_TYPE_STRING, vsn(1, 0, 0), 0, NULL,
cfg_runtime(backup_archive_dir_CFG, "archive_dir", backup_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, vsn(1, 0, 0), 0, NULL,
"Location of the metdata archive files.\n"
"Remember to back up this directory regularly!\n")
cfg(backup_retain_min_CFG, "retain_min", backup_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_ARCHIVE_NUMBER, vsn(1, 0, 0), NULL, 0, NULL,
cfg(backup_retain_min_CFG, "retain_min", backup_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_ARCHIVE_NUMBER, vsn(1, 0, 0), NULL, 0, NULL,
"Minimum number of archives to keep.\n")
cfg(backup_retain_days_CFG, "retain_days", backup_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_ARCHIVE_DAYS, vsn(1, 0, 0), NULL, 0, NULL,
cfg(backup_retain_days_CFG, "retain_days", backup_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_ARCHIVE_DAYS, vsn(1, 0, 0), NULL, 0, NULL,
"Minimum number of days to keep archive files.\n")
cfg(shell_history_size_CFG, "history_size", shell_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_MAX_HISTORY, vsn(1, 0, 0), NULL, 0, NULL,
cfg(shell_history_size_CFG, "history_size", shell_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_MAX_HISTORY, vsn(1, 0, 0), NULL, 0, NULL,
"Number of lines of history to store in ~/.lvm_history.\n")
cfg(global_umask_CFG, "umask", global_CFG_SECTION, CFG_FORMAT_INT_OCTAL, CFG_TYPE_INT, DEFAULT_UMASK, vsn(1, 0, 0), NULL, 0, NULL,
cfg(global_umask_CFG, "umask", global_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_FORMAT_INT_OCTAL, CFG_TYPE_INT, DEFAULT_UMASK, vsn(1, 0, 0), NULL, 0, NULL,
"The file creation mask for any files and directories created.\n"
"Interpreted as octal if the first digit is zero.\n")
cfg(global_test_CFG, "test", global_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(1, 0, 0), NULL, 0, NULL,
cfg(global_test_CFG, "test", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 0, vsn(1, 0, 0), NULL, 0, NULL,
"No on-disk metadata changes will be made in test mode.\n"
"Equivalent to having the -t option on every command.\n")
cfg(global_units_CFG, "units", global_CFG_SECTION, CFG_PROFILABLE, CFG_TYPE_STRING, DEFAULT_UNITS, vsn(1, 0, 0), NULL, 0, NULL,
cfg(global_units_CFG, "units", global_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_PROFILABLE, CFG_TYPE_STRING, DEFAULT_UNITS, vsn(1, 0, 0), NULL, 0, NULL,
"Default value for --units argument.\n")
cfg(global_si_unit_consistency_CFG, "si_unit_consistency", global_CFG_SECTION, CFG_PROFILABLE, CFG_TYPE_BOOL, DEFAULT_SI_UNIT_CONSISTENCY, vsn(2, 2, 54), NULL, 0, NULL,
cfg(global_si_unit_consistency_CFG, "si_unit_consistency", global_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_PROFILABLE, CFG_TYPE_BOOL, DEFAULT_SI_UNIT_CONSISTENCY, vsn(2, 2, 54), NULL, 0, NULL,
"Distinguish between powers of 1024 and 1000 bytes.\n"
"The LVM commands distinguish between powers of 1024 bytes,\n"
"e.g. KiB, MiB, GiB, and powers of 1000 bytes, e.g. KB, MB, GB.\n"
"If scripts depend on the old behaviour, disable this setting\n"
"temporarily until they are updated.\n")
cfg(global_suffix_CFG, "suffix", global_CFG_SECTION, CFG_PROFILABLE, CFG_TYPE_BOOL, DEFAULT_SUFFIX, vsn(1, 0, 0), NULL, 0, NULL,
cfg(global_suffix_CFG, "suffix", global_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_PROFILABLE, CFG_TYPE_BOOL, DEFAULT_SUFFIX, vsn(1, 0, 0), NULL, 0, NULL,
"Display unit suffix for sizes.\n"
"This setting has no effect if the units are in human-readable form\n"
"(global/units = \"h\") in which case the suffix is always displayed.\n")
cfg(global_activation_CFG, "activation", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_ACTIVATION, vsn(1, 0, 0), NULL, 0, NULL,
cfg(global_activation_CFG, "activation", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_ACTIVATION, vsn(1, 0, 0), NULL, 0, NULL,
"Enable/disable communication with the kernel device-mapper.\n"
"Disable to use the tools to manipulate LVM metadata without\n"
"activating any logical volumes. If the device-mapper driver\n"
@@ -979,30 +985,30 @@ cfg_array(global_format_libraries_CFG, "format_libraries", global_CFG_SECTION, C
cfg_array(global_segment_libraries_CFG, "segment_libraries", global_CFG_SECTION, CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(1, 0, 18), NULL, vsn(2, 3, 3), NULL, NULL)
cfg(global_proc_CFG, "proc", global_CFG_SECTION, CFG_ADVANCED, CFG_TYPE_STRING, DEFAULT_PROC_DIR, vsn(1, 0, 0), NULL, 0, NULL,
cfg(global_proc_CFG, "proc", global_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_ADVANCED, CFG_TYPE_STRING, DEFAULT_PROC_DIR, vsn(1, 0, 0), NULL, 0, NULL,
"Location of proc filesystem.\n")
cfg(global_etc_CFG, "etc", global_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_ETC_DIR, vsn(2, 2, 117), "@CONFDIR@", 0, NULL,
cfg(global_etc_CFG, "etc", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_ETC_DIR, vsn(2, 2, 117), "@CONFDIR@", 0, NULL,
"Location of /etc system configuration directory.\n")
cfg(global_locking_type_CFG, "locking_type", global_CFG_SECTION, 0, CFG_TYPE_INT, 1, vsn(1, 0, 0), NULL, vsn(2, 3, 0), NULL,
cfg(global_locking_type_CFG, "locking_type", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, 1, vsn(1, 0, 0), NULL, vsn(2, 3, 0), NULL,
NULL)
cfg(global_wait_for_locks_CFG, "wait_for_locks", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_WAIT_FOR_LOCKS, vsn(2, 2, 50), NULL, 0, NULL,
cfg(global_wait_for_locks_CFG, "wait_for_locks", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_WAIT_FOR_LOCKS, vsn(2, 2, 50), NULL, 0, NULL,
"When disabled, fail if a lock request would block.\n")
cfg(global_fallback_to_clustered_locking_CFG, "fallback_to_clustered_locking", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_FALLBACK_TO_CLUSTERED_LOCKING, vsn(2, 2, 42), NULL, vsn(2, 3, 0), NULL,
cfg(global_fallback_to_clustered_locking_CFG, "fallback_to_clustered_locking", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_FALLBACK_TO_CLUSTERED_LOCKING, vsn(2, 2, 42), NULL, vsn(2, 3, 0), NULL,
NULL)
cfg(global_fallback_to_local_locking_CFG, "fallback_to_local_locking", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_FALLBACK_TO_LOCAL_LOCKING, vsn(2, 2, 42), NULL, vsn(2, 3, 0), NULL,
cfg(global_fallback_to_local_locking_CFG, "fallback_to_local_locking", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_FALLBACK_TO_LOCAL_LOCKING, vsn(2, 2, 42), NULL, vsn(2, 3, 0), NULL,
NULL)
cfg(global_locking_dir_CFG, "locking_dir", global_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_LOCK_DIR, vsn(1, 0, 0), "@DEFAULT_LOCK_DIR@", 0, NULL,
cfg(global_locking_dir_CFG, "locking_dir", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_LOCK_DIR, vsn(1, 0, 0), "@DEFAULT_LOCK_DIR@", 0, NULL,
"Directory to use for LVM command file locks.\n"
"Local non-LV directory that holds file-based locks while commands are\n"
"in progress. A directory like /tmp that may get wiped on reboot is OK.\n")
cfg(global_prioritise_write_locks_CFG, "prioritise_write_locks", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_PRIORITISE_WRITE_LOCKS, vsn(2, 2, 52), NULL, 0, NULL,
cfg(global_prioritise_write_locks_CFG, "prioritise_write_locks", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_PRIORITISE_WRITE_LOCKS, vsn(2, 2, 52), NULL, 0, NULL,
"Allow quicker VG write access during high volume read access.\n"
"When there are competing read-only and read-write access requests for\n"
"a volume group's metadata, instead of always granting the read-only\n"
@@ -1016,22 +1022,22 @@ cfg(global_library_dir_CFG, "library_dir", global_CFG_SECTION, CFG_DEFAULT_UNDEF
cfg(global_locking_library_CFG, "locking_library", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_LOCKING_LIB, vsn(1, 0, 0), NULL, vsn(2, 3, 0), NULL,
NULL)
cfg(global_abort_on_internal_errors_CFG, "abort_on_internal_errors", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_ABORT_ON_INTERNAL_ERRORS, vsn(2, 2, 57), NULL, 0, NULL,
cfg(global_abort_on_internal_errors_CFG, "abort_on_internal_errors", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_ABORT_ON_INTERNAL_ERRORS, vsn(2, 2, 57), NULL, 0, NULL,
"Abort a command that encounters an internal error.\n"
"Treat any internal errors as fatal errors, aborting the process that\n"
"encountered the internal error. Please only enable for debugging.\n")
cfg(global_detect_internal_vg_cache_corruption_CFG, "detect_internal_vg_cache_corruption", global_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(2, 2, 96), NULL, vsn(2, 2, 174), NULL,
cfg(global_detect_internal_vg_cache_corruption_CFG, "detect_internal_vg_cache_corruption", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 0, vsn(2, 2, 96), NULL, vsn(2, 2, 174), NULL,
NULL)
cfg(global_metadata_read_only_CFG, "metadata_read_only", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_METADATA_READ_ONLY, vsn(2, 2, 75), NULL, 0, NULL,
cfg(global_metadata_read_only_CFG, "metadata_read_only", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_METADATA_READ_ONLY, vsn(2, 2, 75), NULL, 0, NULL,
"No operations that change on-disk metadata are permitted.\n"
"Additionally, read-only commands that encounter metadata in need of\n"
"repair will still be allowed to proceed exactly as if the repair had\n"
"been performed (except for the unchanged vg_seqno). Inappropriate\n"
"use could mess up your system, so seek advice first!\n")
cfg(global_mirror_segtype_default_CFG, "mirror_segtype_default", global_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_MIRROR_SEGTYPE, vsn(2, 2, 87), "@DEFAULT_MIRROR_SEGTYPE@", 0, NULL,
cfg(global_mirror_segtype_default_CFG, "mirror_segtype_default", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_MIRROR_SEGTYPE, vsn(2, 2, 87), "@DEFAULT_MIRROR_SEGTYPE@", 0, NULL,
"The segment type used by the short mirroring option -m.\n"
"The --type mirror|raid1 option overrides this setting.\n"
"#\n"
@@ -1066,7 +1072,7 @@ cfg(global_support_mirrored_mirror_log_CFG, "support_mirrored_mirror_log", globa
"Not supported for regular operation!\n"
"\n")
cfg(global_raid10_segtype_default_CFG, "raid10_segtype_default", global_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_RAID10_SEGTYPE, vsn(2, 2, 99), "@DEFAULT_RAID10_SEGTYPE@", 0, NULL,
cfg(global_raid10_segtype_default_CFG, "raid10_segtype_default", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_RAID10_SEGTYPE, vsn(2, 2, 99), "@DEFAULT_RAID10_SEGTYPE@", 0, NULL,
"The segment type used by the -i -m combination.\n"
"The --type raid10|mirror option overrides this setting.\n"
"The --stripes/-i and --mirrors/-m options can both be specified\n"
@@ -1084,7 +1090,7 @@ cfg(global_raid10_segtype_default_CFG, "raid10_segtype_default", global_CFG_SECT
" in terms of providing redundancy and performance.\n"
"#\n")
cfg(global_sparse_segtype_default_CFG, "sparse_segtype_default", global_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_SPARSE_SEGTYPE, vsn(2, 2, 112), "@DEFAULT_SPARSE_SEGTYPE@", 0, NULL,
cfg(global_sparse_segtype_default_CFG, "sparse_segtype_default", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_SPARSE_SEGTYPE, vsn(2, 2, 112), "@DEFAULT_SPARSE_SEGTYPE@", 0, NULL,
"The segment type used by the -V -L combination.\n"
"The --type snapshot|thin option overrides this setting.\n"
"The combination of -V and -L options creates a sparse LV. There are\n"
@@ -1122,7 +1128,7 @@ 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(global_use_lvmetad_CFG, "use_lvmetad", global_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(2, 2, 93), 0, vsn(2, 3, 0), NULL,
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)
cfg(global_lvmetad_update_wait_time_CFG, "lvmetad_update_wait_time", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, 0, vsn(2, 2, 151), NULL, vsn(2, 3, 0), NULL,
@@ -1131,7 +1137,7 @@ cfg(global_lvmetad_update_wait_time_CFG, "lvmetad_update_wait_time", global_CFG_
cfg(global_use_aio_CFG, "use_aio", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_USE_AIO, vsn(2, 2, 183), NULL, 0, NULL,
"Use async I/O when reading and writing devices.\n")
cfg(global_use_lvmlockd_CFG, "use_lvmlockd", global_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(2, 2, 124), NULL, 0, NULL,
cfg(global_use_lvmlockd_CFG, "use_lvmlockd", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, 0, vsn(2, 2, 124), NULL, 0, NULL,
"Use lvmlockd for locking among hosts using LVM on shared storage.\n"
"Applicable only if LVM is compiled with lockd support in which\n"
"case there is also lvmlockd(8) man page available for more\n"
@@ -1257,7 +1263,7 @@ cfg(global_fsadm_executable_CFG, "fsadm_executable", global_CFG_SECTION, CFG_DEF
"The full path to the fsadm command.\n"
"LVM uses this command to help with lvresize -r operations.\n")
cfg(global_system_id_source_CFG, "system_id_source", global_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_SYSTEM_ID_SOURCE, vsn(2, 2, 117), NULL, 0, NULL,
cfg(global_system_id_source_CFG, "system_id_source", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_SYSTEM_ID_SOURCE, vsn(2, 2, 117), NULL, 0, NULL,
"The method LVM uses to set the local system ID.\n"
"Volume Groups can also be given a system ID (by vgcreate, vgchange,\n"
"or vgimport.) A VG on shared storage devices is accessible only to\n"
@@ -1273,10 +1279,12 @@ cfg(global_system_id_source_CFG, "system_id_source", global_CFG_SECTION, 0, CFG_
" uname\n"
" Set the system ID from the hostname (uname) of the system.\n"
" System IDs beginning localhost are not permitted.\n"
" appmachineid\n"
" Use an LVM-specific derivation of the local machine-id as the\n"
" system ID. See 'man machine-id'.\n"
" machineid\n"
" Use the contents of the machine-id file to set the system ID.\n"
" Some systems create this file at installation time.\n"
" See 'man machine-id' and global/etc.\n"
" Use the contents of the machine-id file to set the system ID\n"
" (appmachineid is recommended.)\n"
" file\n"
" Use the contents of another file (system_id_file) to set the\n"
" system ID.\n"
@@ -1287,13 +1295,13 @@ cfg(global_system_id_file_CFG, "system_id_file", global_CFG_SECTION, CFG_DEFAULT
"This is used when system_id_source is set to 'file'.\n"
"Comments starting with the character # are ignored.\n")
cfg(activation_checks_CFG, "checks", activation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_ACTIVATION_CHECKS, vsn(2, 2, 86), NULL, 0, NULL,
cfg(activation_checks_CFG, "checks", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_ACTIVATION_CHECKS, vsn(2, 2, 86), NULL, 0, NULL,
"Perform internal checks of libdevmapper operations.\n"
"Useful for debugging problems with activation. Some of the checks may\n"
"be expensive, so it's best to use this only when there seems to be a\n"
"problem.\n")
cfg(global_use_lvmpolld_CFG, "use_lvmpolld", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_USE_LVMPOLLD, vsn(2, 2, 120), "@DEFAULT_USE_LVMPOLLD@", 0, NULL,
cfg(global_use_lvmpolld_CFG, "use_lvmpolld", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_USE_LVMPOLLD, vsn(2, 2, 120), "@DEFAULT_USE_LVMPOLLD@", 0, NULL,
"Use lvmpolld to supervise long running LVM commands.\n"
"When enabled, control of long running LVM commands is transferred\n"
"from the original LVM command to the lvmpolld daemon. This allows\n"
@@ -1306,7 +1314,7 @@ cfg(global_use_lvmpolld_CFG, "use_lvmpolld", global_CFG_SECTION, 0, CFG_TYPE_BOO
"commands will supervise long running operations by forking themselves.\n"
"Applicable only if LVM is compiled with lvmpolld support.\n")
cfg(global_notify_dbus_CFG, "notify_dbus", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_NOTIFY_DBUS, vsn(2, 2, 145), NULL, 0, NULL,
cfg(global_notify_dbus_CFG, "notify_dbus", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_NOTIFY_DBUS, vsn(2, 2, 145), NULL, 0, NULL,
"Enable D-Bus notification from LVM commands.\n"
"When enabled, an LVM command that changes PVs, changes VG metadata,\n"
"or changes the activation state of an LV will send a notification.\n")
@@ -1319,7 +1327,7 @@ cfg(global_io_memory_size_CFG, "io_memory_size", global_CFG_SECTION, CFG_DEFAULT
"This value should usually not be decreased from the default; setting\n"
"it too low can result in lvm failing to read VGs.\n")
cfg(activation_udev_sync_CFG, "udev_sync", activation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_UDEV_SYNC, vsn(2, 2, 51), NULL, 0, NULL,
cfg(activation_udev_sync_CFG, "udev_sync", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_UDEV_SYNC, vsn(2, 2, 51), NULL, 0, NULL,
"Use udev notifications to synchronize udev and LVM.\n"
"The --noudevsync option overrides this setting.\n"
"When disabled, LVM commands will not wait for notifications from\n"
@@ -1329,7 +1337,7 @@ cfg(activation_udev_sync_CFG, "udev_sync", activation_CFG_SECTION, 0, CFG_TYPE_B
"running, and LVM processes are waiting for udev, run the command\n"
"'dmsetup udevcomplete_all' to wake them up.\n")
cfg(activation_udev_rules_CFG, "udev_rules", activation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_UDEV_RULES, vsn(2, 2, 57), NULL, 0, NULL,
cfg(activation_udev_rules_CFG, "udev_rules", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_UDEV_RULES, vsn(2, 2, 57), NULL, 0, NULL,
"Use udev rules to manage LV device nodes and symlinks.\n"
"When disabled, LVM will manage the device nodes and symlinks for\n"
"active LVs itself. Manual intervention may be required if this\n"
@@ -1341,13 +1349,13 @@ cfg(activation_verify_udev_operations_CFG, "verify_udev_operations", activation_
"in the device directory after udev has completed processing its\n"
"events. Useful for diagnosing problems with LVM/udev interactions.\n")
cfg(activation_retry_deactivation_CFG, "retry_deactivation", activation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_RETRY_DEACTIVATION, vsn(2, 2, 89), NULL, 0, NULL,
cfg(activation_retry_deactivation_CFG, "retry_deactivation", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_RETRY_DEACTIVATION, vsn(2, 2, 89), NULL, 0, NULL,
"Retry failed LV deactivation.\n"
"If LV deactivation fails, LVM will retry for a few seconds before\n"
"failing. This may happen because a process run from a quick udev rule\n"
"temporarily opened the device.\n")
cfg(activation_missing_stripe_filler_CFG, "missing_stripe_filler", activation_CFG_SECTION, CFG_ADVANCED, CFG_TYPE_STRING, DEFAULT_STRIPE_FILLER, vsn(1, 0, 0), NULL, 0, NULL,
cfg(activation_missing_stripe_filler_CFG, "missing_stripe_filler", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_ADVANCED, CFG_TYPE_STRING, DEFAULT_STRIPE_FILLER, vsn(1, 0, 0), NULL, 0, NULL,
"Method to fill missing stripes when activating an incomplete LV.\n"
"Using 'error' will make inaccessible parts of the device return I/O\n"
"errors on access. Using 'zero' will return success (and zero) on I/O\n"
@@ -1460,11 +1468,11 @@ cfg_array(activation_read_only_volume_list_CFG, "read_only_volume_list", activat
"read_only_volume_list = [ \"vg1\", \"vg2/lvol1\", \"@tag1\", \"@*\" ]\n"
"#\n")
cfg(activation_mirror_region_size_CFG, "mirror_region_size", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_RAID_REGION_SIZE, vsn(1, 0, 0), NULL, vsn(2, 2, 99),
cfg(activation_mirror_region_size_CFG, "mirror_region_size", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_RAID_REGION_SIZE, vsn(1, 0, 0), NULL, vsn(2, 2, 99),
"This has been replaced by the activation/raid_region_size setting.\n",
"Size in KiB of each raid or mirror synchronization region.\n")
cfg(activation_raid_region_size_CFG, "raid_region_size", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_RAID_REGION_SIZE, vsn(2, 2, 99), NULL, 0, NULL,
cfg(activation_raid_region_size_CFG, "raid_region_size", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_RAID_REGION_SIZE, vsn(2, 2, 99), NULL, 0, NULL,
"Size in KiB of each raid or mirror synchronization region.\n"
"The clean/dirty state of data is tracked for each region.\n"
"The value is rounded down to a power of two if necessary, and\n"
@@ -1489,7 +1497,7 @@ cfg(activation_readahead_CFG, "readahead", activation_CFG_SECTION, CFG_DEFAULT_C
" Use default value chosen by kernel.\n"
"#\n")
cfg(activation_raid_fault_policy_CFG, "raid_fault_policy", activation_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_RAID_FAULT_POLICY, vsn(2, 2, 89), NULL, 0, NULL,
cfg(activation_raid_fault_policy_CFG, "raid_fault_policy", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_RAID_FAULT_POLICY, vsn(2, 2, 89), NULL, 0, NULL,
"Defines how a device failure in a RAID LV is handled.\n"
"This includes LVs that have the following segment types:\n"
"raid1, raid4, raid5*, and raid6*.\n"
@@ -1510,7 +1518,7 @@ cfg(activation_raid_fault_policy_CFG, "raid_fault_policy", activation_CFG_SECTIO
" replace faulty devices.\n"
"#\n")
cfg_runtime(activation_mirror_image_fault_policy_CFG, "mirror_image_fault_policy", activation_CFG_SECTION, 0, CFG_TYPE_STRING, vsn(2, 2, 57), 0, NULL,
cfg_runtime(activation_mirror_image_fault_policy_CFG, "mirror_image_fault_policy", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, vsn(2, 2, 57), 0, NULL,
"Defines how a device failure in a 'mirror' LV is handled.\n"
"An LV with the 'mirror' segment type is composed of mirror images\n"
"(copies) and a mirror log. A disk log ensures that a mirror LV does\n"
@@ -1546,16 +1554,16 @@ cfg_runtime(activation_mirror_image_fault_policy_CFG, "mirror_image_fault_policy
" replacement.\n"
"#\n")
cfg(activation_mirror_log_fault_policy_CFG, "mirror_log_fault_policy", activation_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_MIRROR_LOG_FAULT_POLICY, vsn(1, 2, 18), NULL, 0, NULL,
cfg(activation_mirror_log_fault_policy_CFG, "mirror_log_fault_policy", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_MIRROR_LOG_FAULT_POLICY, vsn(1, 2, 18), NULL, 0, NULL,
"Defines how a device failure in a 'mirror' log LV is handled.\n"
"The mirror_image_fault_policy description for mirrored LVs also\n"
"applies to mirrored log LVs.\n")
cfg(activation_mirror_device_fault_policy_CFG, "mirror_device_fault_policy", activation_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_MIRROR_DEVICE_FAULT_POLICY, vsn(1, 2, 10), NULL, vsn(2, 2, 57),
cfg(activation_mirror_device_fault_policy_CFG, "mirror_device_fault_policy", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_MIRROR_DEVICE_FAULT_POLICY, vsn(1, 2, 10), NULL, vsn(2, 2, 57),
"This has been replaced by the activation/mirror_image_fault_policy setting.\n",
"Define how a device failure affecting a mirror is handled.\n")
cfg(activation_snapshot_autoextend_threshold_CFG, "snapshot_autoextend_threshold", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_SNAPSHOT_AUTOEXTEND_THRESHOLD, vsn(2, 2, 75), NULL, 0, NULL,
cfg(activation_snapshot_autoextend_threshold_CFG, "snapshot_autoextend_threshold", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_SNAPSHOT_AUTOEXTEND_THRESHOLD, vsn(2, 2, 75), NULL, 0, NULL,
"Auto-extend a snapshot when its usage exceeds this percent.\n"
"Setting this to 100 disables automatic extension.\n"
"The minimum value is 50 (a smaller value is treated as 50.)\n"
@@ -1569,7 +1577,7 @@ cfg(activation_snapshot_autoextend_threshold_CFG, "snapshot_autoextend_threshold
"snapshot_autoextend_threshold = 70\n"
"#\n")
cfg(activation_snapshot_autoextend_percent_CFG, "snapshot_autoextend_percent", activation_CFG_SECTION, 0, CFG_TYPE_INT, DEFAULT_SNAPSHOT_AUTOEXTEND_PERCENT, vsn(2, 2, 75), NULL, 0, NULL,
cfg(activation_snapshot_autoextend_percent_CFG, "snapshot_autoextend_percent", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_SNAPSHOT_AUTOEXTEND_PERCENT, vsn(2, 2, 75), NULL, 0, NULL,
"Auto-extending a snapshot adds this percent extra space.\n"
"The amount of additional space added to a snapshot is this\n"
"percent of its current size.\n"
@@ -1581,7 +1589,7 @@ cfg(activation_snapshot_autoextend_percent_CFG, "snapshot_autoextend_percent", a
"snapshot_autoextend_percent = 20\n"
"#\n")
cfg(activation_thin_pool_autoextend_threshold_CFG, "thin_pool_autoextend_threshold", activation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA, CFG_TYPE_INT, DEFAULT_THIN_POOL_AUTOEXTEND_THRESHOLD, vsn(2, 2, 89), NULL, 0, NULL,
cfg(activation_thin_pool_autoextend_threshold_CFG, "thin_pool_autoextend_threshold", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_PROFILABLE | CFG_PROFILABLE_METADATA, CFG_TYPE_INT, DEFAULT_THIN_POOL_AUTOEXTEND_THRESHOLD, vsn(2, 2, 89), NULL, 0, NULL,
"Auto-extend a thin pool when its usage exceeds this percent.\n"
"Setting this to 100 disables automatic extension.\n"
"The minimum value is 50 (a smaller value is treated as 50.)\n"
@@ -1595,7 +1603,7 @@ cfg(activation_thin_pool_autoextend_threshold_CFG, "thin_pool_autoextend_thresho
"thin_pool_autoextend_threshold = 70\n"
"#\n")
cfg(activation_thin_pool_autoextend_percent_CFG, "thin_pool_autoextend_percent", activation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA, CFG_TYPE_INT, DEFAULT_THIN_POOL_AUTOEXTEND_PERCENT, vsn(2, 2, 89), NULL, 0, NULL,
cfg(activation_thin_pool_autoextend_percent_CFG, "thin_pool_autoextend_percent", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_PROFILABLE | CFG_PROFILABLE_METADATA, CFG_TYPE_INT, DEFAULT_THIN_POOL_AUTOEXTEND_PERCENT, vsn(2, 2, 89), NULL, 0, NULL,
"Auto-extending a thin pool adds this percent extra space.\n"
"The amount of additional space added to a thin pool is this\n"
"percent of its current size.\n"
@@ -1652,7 +1660,7 @@ cfg(activation_use_mlockall_CFG, "use_mlockall", activation_CFG_SECTION, CFG_DEF
"Prior to version 2.02.62, LVM used mlockall() to pin the whole\n"
"process's memory while activating devices.\n")
cfg(activation_monitoring_CFG, "monitoring", activation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_DMEVENTD_MONITOR, vsn(2, 2, 63), NULL, 0, NULL,
cfg(activation_monitoring_CFG, "monitoring", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_DMEVENTD_MONITOR, vsn(2, 2, 63), NULL, 0, NULL,
"Monitor LVs that are activated.\n"
"The --ignoremonitoring option overrides this setting.\n"
"When enabled, LVM will ask dmeventd to monitor activated LVs.\n")
@@ -1674,7 +1682,7 @@ cfg(activation_auto_set_activation_skip_CFG, "auto_set_activation_skip", activat
"flag set. When this setting is enabled, the activation skip flag is\n"
"set on new thin snapshot LVs.\n")
cfg(activation_mode_CFG, "activation_mode", activation_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_ACTIVATION_MODE, vsn(2,2,108), NULL, 0, NULL,
cfg(activation_mode_CFG, "activation_mode", activation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_ACTIVATION_MODE, vsn(2,2,108), NULL, 0, NULL,
"How LVs with missing devices are activated.\n"
"The --activationmode option overrides this setting.\n"
"#\n"
@@ -2197,4 +2205,4 @@ cfg(local_host_id_CFG, "host_id", local_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_
"This must be unique among all hosts, and must be between 1 and 2000.\n"
"Applicable only if LVM is compiled with lockd support\n")
cfg(CFG_COUNT, NULL, root_CFG_SECTION, 0, CFG_TYPE_INT, 0, vsn(0, 0, 0), NULL, 0, NULL, NULL)
cfg(CFG_COUNT, NULL, root_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, 0, vsn(0, 0, 0), NULL, 0, NULL, NULL)

View File

@@ -322,11 +322,15 @@
#define DEFAULT_MD_COMPONENT_CHECKS "auto"
#define DEFAULT_USE_DEVICES_FILE 0
#define DEFAULT_USE_DEVICES_FILE 1
#define DEFAULT_DEVICES_FILE "system.devices"
#define DEFAULT_SEARCH_FOR_DEVNAMES "auto"
#define DEFAULT_WWIDS_FILE "/etc/multipath/wwids"
#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"
#endif /* _LVM_DEFAULTS_H */

View File

@@ -150,11 +150,14 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
#include <time.h>
#include <sys/types.h>
#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";
@@ -1279,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
@@ -1320,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.

View File

@@ -25,6 +25,7 @@
#include <syslog.h>
#include <ctype.h>
#include <time.h>
#include <systemd/sd-journal.h>
static FILE *_log_file;
static char _log_file_path[PATH_MAX];
@@ -40,6 +41,7 @@ static char _msg_prefix[30] = " ";
static int _abort_on_internal_errors_config = 0;
static uint32_t _debug_file_fields;
static uint32_t _debug_output_fields;
static uint32_t _log_journal = 0;
static lvm2_log_fn_t _lvm2_log_fn = NULL;
@@ -455,6 +457,11 @@ void init_debug_output_fields(uint32_t debug_fields)
_debug_output_fields = debug_fields;
}
void init_log_journal(uint32_t fields)
{
_log_journal = fields;
}
static void _set_time_prefix(char *prefix, int buflen)
{
@@ -609,6 +616,33 @@ static void _vprint_log(int level, const char *file, int line, int dm_errno_or_c
}
log_it:
if (_log_journal) {
int to_journal = 0;
/* By default the visible command output is _LOG_WARN or less. */
if (_log_journal & LOG_JOURNAL_DEBUG)
to_journal = 1;
if ((_log_journal & LOG_JOURNAL_OUTPUT) && (log_level(level) <= _LOG_WARN))
to_journal = 1;
if (to_journal) {
int prio;
switch (log_level(level)) {
case _LOG_ERR: prio = LOG_ERR; break;
case _LOG_WARN: prio = LOG_WARNING; break;
case _LOG_INFO: prio = LOG_INFO; break;
case _LOG_NOTICE: prio = LOG_NOTICE; break;
case _LOG_DEBUG: prio = LOG_DEBUG; break;
default: prio = LOG_INFO;
}
va_copy(ap, orig_ap);
sd_journal_printv(prio, trformat, ap);
va_end(ap);
}
}
if (!logged_via_report && ((verbose_level() >= level) && !_log_suppress)) {
if (verbose_level() > _LOG_DEBUG) {
memset(buf, 0, sizeof(buf));
@@ -792,3 +826,60 @@ void log_set_report_object_name_and_id(const char *name, const char *id)
_log_report.object_name = name;
_log_report.object_id = id;
}
/*
* TODO: log/journal=["daemon_command"]
* daemon_command: record commands that are run by an lvm daemon.
* (i.e. not commands run directly by a user.)
* For this we need to be able to clearly identify when a command is
* being run by dmeventd/lvmpolld/lvmdbusd.
*
* TODO: log/journal_commmand_names=["lvcreate","lvconvert"]
* This would restrict log/journal=["command"] to the listed command names.
* Also allow "!command" to exclude a command, e.g. ["!pvs"]
*
* TODO: log/journal_daemon_command_names=["lvcreate","lvconvert"]
* This would restrict log/journal=["dameon_command"] to the listed command names.
*
* TODO: log/journal_daemon_names=["dmeventd"]
* This would restrict log/journal=["daemon_command"] to commands run by
* the named daemon.
*
* TODO: log/command_to_file=<path> would write this info to the file.
*
* TODO: log/debug_to_file=<path> would write full debugging to the file.
* (the same effect as log/file=<path> log/level=7)
*/
void log_command(const char *cmd_line, const char *cmd_name, const char *cmd_id)
{
if (_log_journal & LOG_JOURNAL_COMMAND) {
/*
* TODO: DAEMON=dmeventd|lvmpolld|lvmdbusd,
* Could we include caller info such as libblkid, udev rule, etc?
* Does systemd already record the caller for us?
*/
/* The command line, pid, and other things are automatically included. */
sd_journal_send("MESSAGE=lvm command %s", cmd_name,
"MESSAGE_ID=3ca432788c374e4ba684b834188eca36",
"LVM_CMD_NAME=%s", cmd_name,
"LVM_CMD_ID=%s", cmd_id,
"PRIORITY=%i", LOG_INFO,
NULL);
}
}
uint32_t log_journal_str_to_val(const char *str)
{
if (!strcasecmp(str, "command"))
return LOG_JOURNAL_COMMAND;
if (!strcasecmp(str, "output"))
return LOG_JOURNAL_OUTPUT;
if (!strcasecmp(str, "debug"))
return LOG_JOURNAL_DEBUG;
return 0;
}

View File

@@ -63,6 +63,10 @@
#define LOG_DEBUG_FIELD_FILELINE 0x0004
#define LOG_DEBUG_FIELD_MESSAGE 0x0008
#define LOG_JOURNAL_COMMAND 0x0001
#define LOG_JOURNAL_OUTPUT 0x0002
#define LOG_JOURNAL_DEBUG 0x0004
/*
* Classes available for debug log messages.

View File

@@ -62,6 +62,12 @@ void reset_log_duplicated(void);
void init_syslog(int facility);
void fin_syslog(void);
void init_log_journal(uint32_t fields);
uint32_t log_journal_str_to_val(const char *str);
void log_command(const char *cmd_line, const char *cmd_name, const char *cmd_id);
int error_message_produced(void);
void reset_lvm_errno(int store_errmsg);
int stored_errno(void);

View File

@@ -5279,3 +5279,36 @@ struct volume_group *vg_read_for_update(struct cmd_context *cmd, const char *vg_
return vg;
}
int get_visible_lvs_using_pv(struct cmd_context *cmd, struct volume_group *vg, struct device *dev,
struct dm_list *lvs_list)
{
struct pv_list *pvl;
struct lv_list *lvl, *lvl2;
struct physical_volume *pv = NULL;
dm_list_iterate_items(pvl, &vg->pvs) {
if (pvl->pv->dev == dev) {
pv = pvl->pv;
break;
}
}
if (!pv)
return_0;
dm_list_iterate_items(lvl, &vg->lvs) {
if (!lv_is_visible(lvl->lv))
continue;
if (!lv_is_on_pv(lvl->lv, pv))
continue;
if (!(lvl2 = dm_pool_zalloc(cmd->mem, sizeof(*lvl2))))
return_0;
lvl2->lv = lvl->lv;
dm_list_add(lvs_list, &lvl2->list);
}
return 1;
}

View File

@@ -538,4 +538,8 @@ char *tags_format_and_copy(struct dm_pool *mem, const struct dm_list *tagsl);
void set_pv_devices(struct format_instance *fid, struct volume_group *vg);
int get_visible_lvs_using_pv(struct cmd_context *cmd, struct volume_group *vg, struct device *dev,
struct dm_list *lvs_list);
#endif

View File

@@ -172,6 +172,22 @@ global {
}
.fi
.
.TP
.B appmachineid
.br
An LVM-specific derivation of /etc/machine-id is used as the system ID.
See
.BR machine-id (5)
to check if machine-id is available on the host.
.I lvm.conf
.nf
global {
system_id_source = "appmachineid"
}
.fi
.TP
.B machineid
.br
@@ -181,6 +197,7 @@ See
and
.BR systemd-machine-id-setup (1)
to check if machine-id is available on the host.
(appmachineid is recommended in place of machineid.)
.sp
.I lvm.conf
.nf

View File

@@ -92,7 +92,6 @@ install_systemd_generators:
install_systemd_units: install_dbus_service
@echo " [INSTALL] systemd_units"
$(Q) $(INSTALL_DIR) $(systemd_unit_dir)
$(Q) $(INSTALL_DATA) lvm2-pvscan.service $(systemd_unit_dir)/lvm2-pvscan@.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

View File

@@ -158,7 +158,7 @@ fi
%endif
%if %{enable_udev}
%{_udevdir}/11-dm-lvm.rules
%{_udevdir}/69-dm-lvm-metad.rules
%{_udevdir}/69-dm-lvm.rules
%endif
%dir %{_sysconfdir}/lvm
%ghost %{_sysconfdir}/lvm/cache/.cache
@@ -184,7 +184,6 @@ fi
%{_tmpfilesdir}/%{name}.conf
%{_unitdir}/blk-availability.service
%{_unitdir}/lvm2-monitor.service
%{_unitdir}/lvm2-pvscan@.service
%attr(555, -, -) %{_prefix}/lib/systemd/system-generators/lvm2-activation-generator
%if %{have_service lvmpolld}
%{_unitdir}/lvm2-lvmpolld.service

View File

@@ -50,6 +50,17 @@ check vg_field $vg1 systemid "$SID"
vgremove $vg1
fi
## appmachineid
lvm version > lvmver
if grep app-machineid lvmver; then
aux lvmconf "global/system_id_source = appmachineid"
lvm systemid | awk '{ print $3 }' > sid_lvm
vgcreate $vg1 "$dev1"
vgs -o systemid --noheadings $vg1 | awk '{print $1}' > sid_vg
diff sid_lvm sid_vg
vgremove $vg1
fi
## uname
SID1=$(uname -n)

View File

@@ -0,0 +1,403 @@
#!/usr/bin/env bash
# Copyright (C) 2021 Red Hat, Inc. All rights reserved.
#
# 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 General Public License v.2.
#
# You should have received a copy of the GNU 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
test_description='udev rule and systemd unit run vgchange'
SKIP_WITH_LVMPOLLD=1
SKIP_WITH_LVMLOCKD=1
. lib/inittest
#
# $ cat /tmp/devs
# /dev/sdb
# /dev/sdc
# /dev/sdd
#
# Specify this file as LVM_TEST_DEVICE_LIST=/tmp/devs
# when running the test.
#
# This test will wipe these devices.
#
if [ -z ${LVM_TEST_DEVICE_LIST+x} ]; then echo "LVM_TEST_DEVICE_LIST is unset" && skip; else echo "LVM_TEST_DEVICE_LIST is set to '$LVM_TEST_DEVICE_LIST'"; fi
test -e "$LVM_TEST_DEVICE_LIST" || skip
num_devs=$(cat $LVM_TEST_DEVICE_LIST | wc -l)
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"/*
}
test -d "$PVS_ONLINE_DIR" || mkdir -p "$PVS_ONLINE_DIR"
test -d "$VGS_ONLINE_DIR" || mkdir -p "$VGS_ONLINE_DIR"
test -d "$PVS_LOOKUP_DIR" || mkdir -p "$PVS_LOOKUP_DIR"
_clear_online_files
aux prepare_real_devs
aux lvmconf 'devices/dir = "/dev"'
aux lvmconf 'devices/use_devicesfile = 1'
DFDIR="$LVM_SYSTEM_DIR/devices"
DF="$DFDIR/system.devices"
mkdir $DFDIR || true
not ls $DF
get_real_devs
wipe_all() {
for dev in "${REAL_DEVICES[@]}"; do
wipefs -a $dev
done
}
# udevadm trigger runs udev rule which runs systemd-run --no-wait vgchange -aay
# Because of --no-wait, we need to wait for the transient systemd
# service to be gone before checking the effects of the vgchange.
wait_lvm_activate() {
local vgw=$1
local wait=0
while systemctl status lvm-activate-$vgw > /dev/null && test "$wait" -le 30; do
sleep .2
wait=$(( wait + 1 ))
done
}
# Test requires 3 devs
test $num_devs -gt 2 || skip
BDEV1=$(basename "$dev1")
BDEV2=$(basename "$dev2")
BDEV3=$(basename "$dev3")
wipe_all
touch $DF
for dev in "${REAL_DEVICES[@]}"; do
pvcreate $dev
done
# 1 dev, 1 vg, 1 lv
vgcreate $vg1 "$dev1"
lvcreate -l1 -an -n $lv1 $vg1 "$dev1"
PVID1=$(pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}')
_clear_online_files
udevadm trigger --settle -c add /sys/block/$BDEV1
wait_lvm_activate $vg1
ls "$RUNDIR/lvm/pvs_online/$PVID1"
ls "$RUNDIR/lvm/vgs_online/$vg1"
journalctl -u lvm-activate-$vg1 | tee out || true
grep "now active" out
check lv_field $vg1/$lv1 lv_active "active"
vgchange -an $vg1
vgremove -y $vg1
# 2 devs, 1 vg, 2 lvs
vgcreate $vg2 "$dev1" "$dev2"
lvcreate -l1 -an -n $lv1 $vg2 "$dev1"
lvcreate -l1 -an -n $lv2 $vg2 "$dev2"
PVID1=$(pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}')
PVID2=$(pvs "$dev2" --noheading -o uuid | tr -d - | awk '{print $1}')
_clear_online_files
udevadm trigger --settle -c add /sys/block/$BDEV1
ls "$RUNDIR/lvm/pvs_online/$PVID1"
not ls "$RUNDIR/lvm/vgs_online/$vg2"
journalctl -u lvm-activate-$vg2 | tee out || true
not grep "now active" out
check lv_field $vg2/$lv1 lv_active ""
check lv_field $vg2/$lv2 lv_active ""
udevadm trigger --settle -c add /sys/block/$BDEV2
ls "$RUNDIR/lvm/pvs_online/$PVID2"
ls "$RUNDIR/lvm/vgs_online/$vg2"
wait_lvm_activate $vg2
journalctl -u lvm-activate-$vg2 | tee out || true
grep "now active" out
check lv_field $vg2/$lv1 lv_active "active"
check lv_field $vg2/$lv2 lv_active "active"
vgchange -an $vg2
vgremove -y $vg2
# 3 devs, 1 vg, 4 lvs, concurrent pvscans
# (attempting to have the pvscans run concurrently and race
# to activate the VG)
vgcreate $vg3 "$dev1" "$dev2" "$dev3"
lvcreate -l1 -an -n $lv1 $vg3 "$dev1"
lvcreate -l1 -an -n $lv2 $vg3 "$dev2"
lvcreate -l1 -an -n $lv3 $vg3 "$dev3"
lvcreate -l8 -an -n $lv4 -i 2 $vg3 "$dev1" "$dev2"
PVID1=$(pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}')
PVID2=$(pvs "$dev2" --noheading -o uuid | tr -d - | awk '{print $1}')
PVID3=$(pvs "$dev3" --noheading -o uuid | tr -d - | awk '{print $1}')
_clear_online_files
udevadm trigger -c add /sys/block/$BDEV1 &
udevadm trigger -c add /sys/block/$BDEV2 &
udevadm trigger -c add /sys/block/$BDEV3
aux udev_wait
wait_lvm_activate $vg3
ls "$RUNDIR/lvm/pvs_online/$PVID1"
ls "$RUNDIR/lvm/pvs_online/$PVID2"
ls "$RUNDIR/lvm/pvs_online/$PVID3"
ls "$RUNDIR/lvm/vgs_online/$vg3"
journalctl -u lvm-activate-$vg3 | tee out || true
grep "now active" out
check lv_field $vg3/$lv1 lv_active "active"
check lv_field $vg3/$lv2 lv_active "active"
check lv_field $vg3/$lv3 lv_active "active"
check lv_field $vg3/$lv4 lv_active "active"
vgchange -an $vg3
vgremove -y $vg3
# 3 devs, 1 vg, 4 lvs, concurrent pvscans, metadata on only 1 PV
wipe_all
rm $DF
touch $DF
pvcreate --metadatacopies 0 "$dev1"
pvcreate --metadatacopies 0 "$dev2"
pvcreate "$dev3"
vgcreate $vg4 "$dev1" "$dev2" "$dev3"
lvcreate -l1 -an -n $lv1 $vg4 "$dev1"
lvcreate -l1 -an -n $lv2 $vg4 "$dev2"
lvcreate -l1 -an -n $lv3 $vg4 "$dev3"
lvcreate -l8 -an -n $lv4 -i 2 $vg4 "$dev1" "$dev2"
PVID1=$(pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}')
PVID2=$(pvs "$dev2" --noheading -o uuid | tr -d - | awk '{print $1}')
PVID3=$(pvs "$dev3" --noheading -o uuid | tr -d - | awk '{print $1}')
_clear_online_files
udevadm trigger -c add /sys/block/$BDEV1 &
udevadm trigger -c add /sys/block/$BDEV2 &
udevadm trigger -c add /sys/block/$BDEV3
aux udev_wait
wait_lvm_activate $vg4
ls "$RUNDIR/lvm/pvs_online/$PVID1"
ls "$RUNDIR/lvm/pvs_online/$PVID2"
ls "$RUNDIR/lvm/pvs_online/$PVID3"
ls "$RUNDIR/lvm/vgs_online/$vg4"
journalctl -u lvm-activate-$vg4 | tee out || true
grep "now active" out
check lv_field $vg4/$lv1 lv_active "active"
check lv_field $vg4/$lv2 lv_active "active"
check lv_field $vg4/$lv3 lv_active "active"
check lv_field $vg4/$lv4 lv_active "active"
vgchange -an $vg4
vgremove -y $vg4
# 3 devs, 3 vgs, 2 lvs in each vg, concurrent pvscans
wipe_all
rm $DF
touch $DF
vgcreate $vg5 "$dev1"
vgcreate $vg6 "$dev2"
vgcreate $vg7 "$dev3"
lvcreate -l1 -an -n $lv1 $vg5
lvcreate -l1 -an -n $lv2 $vg5
lvcreate -l1 -an -n $lv1 $vg6
lvcreate -l1 -an -n $lv2 $vg6
lvcreate -l1 -an -n $lv1 $vg7
lvcreate -l1 -an -n $lv2 $vg7
_clear_online_files
udevadm trigger -c add /sys/block/$BDEV1 &
udevadm trigger -c add /sys/block/$BDEV2 &
udevadm trigger -c add /sys/block/$BDEV3
aux udev_wait
wait_lvm_activate $vg5
wait_lvm_activate $vg6
wait_lvm_activate $vg7
ls "$RUNDIR/lvm/vgs_online/$vg5"
ls "$RUNDIR/lvm/vgs_online/$vg6"
ls "$RUNDIR/lvm/vgs_online/$vg7"
journalctl -u lvm-activate-$vg5 | tee out || true
grep "now active" out
journalctl -u lvm-activate-$vg6 | tee out || true
grep "now active" out
journalctl -u lvm-activate-$vg7 | tee out || true
grep "now active" out
check lv_field $vg5/$lv1 lv_active "active"
check lv_field $vg5/$lv2 lv_active "active"
check lv_field $vg6/$lv1 lv_active "active"
check lv_field $vg6/$lv2 lv_active "active"
check lv_field $vg7/$lv1 lv_active "active"
check lv_field $vg7/$lv2 lv_active "active"
vgchange -an $vg5
vgremove -y $vg5
vgchange -an $vg6
vgremove -y $vg6
vgchange -an $vg7
vgremove -y $vg7
# 3 devs, 1 vg, 1000 LVs
wipe_all
rm $DF
touch $DF
pvcreate --metadatacopies 0 "$dev1"
pvcreate "$dev2"
pvcreate "$dev3"
vgcreate -s 128K $vg8 "$dev1" "$dev2" "$dev3"
# Number of LVs to create
TEST_DEVS=1000
# On low-memory boxes let's not stress too much
test "$(aux total_mem)" -gt 524288 || TEST_DEVS=256
vgcfgbackup -f data $vg8
# Generate a lot of devices (size of 1 extent)
awk -v TEST_DEVS=$TEST_DEVS '/^\t\}/ {
printf("\t}\n\tlogical_volumes {\n");
cnt=0;
for (i = 0; i < TEST_DEVS; i++) {
printf("\t\tlvol%06d {\n", i);
printf("\t\t\tid = \"%06d-1111-2222-3333-2222-1111-%06d\"\n", i, i);
print "\t\t\tstatus = [\"READ\", \"WRITE\", \"VISIBLE\"]";
print "\t\t\tsegment_count = 1";
print "\t\t\tsegment1 {";
print "\t\t\t\tstart_extent = 0";
print "\t\t\t\textent_count = 1";
print "\t\t\t\ttype = \"striped\"";
print "\t\t\t\tstripe_count = 1";
print "\t\t\t\tstripes = [";
print "\t\t\t\t\t\"pv0\", " cnt++;
printf("\t\t\t\t]\n\t\t\t}\n\t\t}\n");
}
}
{print}
' data >data_new
vgcfgrestore -f data_new $vg8
_clear_online_files
udevadm trigger -c add /sys/block/$BDEV1 &
udevadm trigger -c add /sys/block/$BDEV2 &
udevadm trigger -c add /sys/block/$BDEV3
aux udev_wait
wait_lvm_activate $vg8
ls "$RUNDIR/lvm/vgs_online/$vg8"
journalctl -u lvm-activate-$vg8 | tee out || true
grep "now active" out
num_active=$(lvs $vg8 --noheading -o active | grep active | wc -l)
test $num_active -eq $TEST_DEVS
vgchange -an $vg8
vgremove -y $vg8
# 1 pv on an md dev, 1 vg
wait_md_create() {
local md=$1
while :; do
if ! grep "$(basename $md)" /proc/mdstat; then
echo "$md not ready"
cat /proc/mdstat
sleep 2
else
break
fi
done
echo "$md" > WAIT_MD_DEV
}
test -f /proc/mdstat && grep -q raid1 /proc/mdstat || \
modprobe raid1 || skip
mddev="/dev/md33"
not grep $mddev /proc/mdstat || skip
wipe_all
rm $DF
touch $DF
mdadm --create --metadata=1.0 "$mddev" --level 1 --chunk=64 --raid-devices=2 "$dev1" "$dev2"
wait_md_create "$mddev"
vgcreate $vg9 "$mddev"
PVIDMD=`pvs $mddev --noheading -o uuid | tr -d - | awk '{print $1}'`
BDEVMD=$(basename "$mddev")
lvcreate -l1 -an -n $lv1 $vg9
lvcreate -l1 -an -n $lv2 $vg9
_clear_online_files
udevadm trigger --settle -c add /sys/block/$BDEVMD
wait_lvm_activate $vg9
ls "$RUNDIR/lvm/vgs_online/$vg9"
journalctl -u lvm-activate-$vg9 | tee out || true
grep "now active" out
check lv_field $vg9/$lv1 lv_active "active"
check lv_field $vg9/$lv2 lv_active "active"
vgchange -an $vg9
vgremove -y $vg9
mdadm --stop "$mddev"
aux udev_wait
wipe_all

View File

@@ -323,12 +323,33 @@ arg(ignoreunsupported_ARG, '\0', "ignoreunsupported", 0, 0, 0,
arg(importdevices_ARG, '\0', "importdevices", 0, 0, 0,
"Add devices to the devices file.\n")
arg(journal_ARG, '\0', "journal", string_VAL, 0, 0,
"Record information in the systemd journal.\n"
"This information is in addition to information\n"
"enabled by the lvm.conf log/journal setting.\n"
"command: record information about the command.\n"
"output: record the default command output.\n"
"debug: record full command debugging.\n")
arg(labelsector_ARG, '\0', "labelsector", number_VAL, 0, 0,
"By default the PV is labelled with an LVM2 identifier in its second\n"
"sector (sector 1). This lets you use a different sector near the\n"
"start of the disk (between 0 and 3 inclusive - see LABEL_SCAN_SECTORS\n"
"in the source). Use with care.\n")
arg(listlvs_ARG, '\0', "listlvs", 0, 0, 0,
"Print a list of LVs that use the device.\n")
arg(listvg_ARG, '\0', "listvg", 0, 0, 0,
"Print the VG that uses the device.\n")
arg(checkcomplete_ARG, '\0', "checkcomplete", 0, 0, 0,
"Check if all the devices used by a VG or LV are present,\n"
"and print \"complete\" or \"incomplete\" for each listed\n"
"VG or LV. This option is used as a part of event-based\n"
"autoactivation, so pvscan will do nothing if this option\n"
"is set and event_activation=0 in the config settings.\n")
arg(lockopt_ARG, '\0', "lockopt", string_VAL, 0, 0,
"Used to pass options for special cases to lvmlockd.\n"
"See \\fBlvmlockd\\fP(8) for more information.\n")
@@ -811,6 +832,9 @@ arg(type_ARG, '\0', "type", segtype_VAL, 0, 0,
"(e.g. --stripes, --mirrors, --snapshot, --virtualsize, --thin, --cache, --vdo).\n"
"Use inferred types with care because it can lead to unexpected results.\n")
arg(udevoutput_ARG, '\0', "udevoutput", 0, 0, 0,
"Command output is modified to be imported from a udev rule.\n")
arg(unbuffered_ARG, '\0', "unbuffered", 0, 0, 0,
"Produce output immediately without sorting or aligning the columns properly.\n")
@@ -887,6 +911,10 @@ arg(vgmetadatacopies_ARG, '\0', "vgmetadatacopies", vgmetadatacopies_VAL, 0, 0,
"\\fBall\\fP causes LVM to first clear the metadataignore flags on\n"
"all PVs, and then to become unmanaged.\n")
arg(vgonline_ARG, '\0', "vgonline", 0, 0, 0,
"The first command to see a complete VG will report it uniquely.\n"
"Other commands to see the complete VG will report it differently.\n")
arg(withsummary_ARG, '\0', "withsummary", 0, 0, 0,
"Display a one line comment for each configuration node.\n")

View File

@@ -204,7 +204,7 @@
#
OO_ALL: --commandprofile String, --config String, --debug,
--driverloaded Bool, --help, --nolocking, --lockopt String, --longhelp, --profile String, --quiet,
--verbose, --version, --yes, --test, --devicesfile String, --devices PV
--verbose, --version, --yes, --test, --devicesfile String, --devices PV, --journal String
#
# options for pvs, lvs, vgs, fullreport
@@ -1633,11 +1633,37 @@ DESC: Display PV information.
pvscan --cache_long
OO: --ignorelockingfailure, --reportformat ReportFmt,
--activate ay, --major Number, --minor Number, --noudevsync
--major Number, --minor Number, --noudevsync
OP: PV|String ...
IO: --background
ID: pvscan_cache
DESC: Autoactivate a VG when all PVs are online.
DESC: Record that a PV is online or offline.
pvscan --cache_long --activate ay
OO: --ignorelockingfailure, --reportformat ReportFmt,
--major Number, --minor Number, --noudevsync
OP: PV|String ...
IO: --background
ID: pvscan_cache
DESC: Record that a PV is online and autoactivate the VG if complete.
pvscan --cache_long --listvg PV
OO: --ignorelockingfailure, --checkcomplete, --vgonline, --udevoutput
ID: pvscan_cache
DESC: Record that a PV is online and list the VG using the PV.
pvscan --cache_long --listlvs PV
OO: --ignorelockingfailure, --checkcomplete, --vgonline
ID: pvscan_cache
DESC: Record that a PV is online and list LVs using the PV.
pvscan --listlvs PV
ID: pvscan_cache
DESC: List LVs using the PV.
pvscan --listvg PV
ID: pvscan_cache
DESC: List the VG using the PV.
---

View File

@@ -2016,6 +2016,8 @@ out:
log_debug("Recognised command %s (id %d / enum %d).",
commands[best_i].command_id, best_i, commands[best_i].command_enum);
log_command(cmd->cmd_line, commands[best_i].name, commands[best_i].command_id);
return &commands[best_i];
}
@@ -2390,6 +2392,9 @@ 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))
cmd->current_settings.suppress = 1;
if (arg_is_set(cmd, debug_ARG))
cmd->current_settings.debug = _LOG_FATAL + (arg_count(cmd, debug_ARG) - 1);
@@ -2401,14 +2406,25 @@ static void _get_current_output_settings_from_args(struct cmd_context *cmd)
cmd->current_settings.verbose = 0;
cmd->current_settings.silent = (arg_count(cmd, quiet_ARG) > 1) ? 1 : 0;
}
/*
* default_settings.journal is already set from config and has already been
* applied using init_log_journal().
* current_settings have been set to default_settings.
* now --journal value adds to current_settings.
*/
if (arg_is_set(cmd, journal_ARG))
cmd->current_settings.journal |= log_journal_str_to_val(arg_str_value(cmd, journal_ARG, ""));
}
static void _apply_current_output_settings(struct cmd_context *cmd)
{
log_suppress(cmd->current_settings.suppress);
init_debug(cmd->current_settings.debug);
init_debug_classes_logged(cmd->default_settings.debug_classes);
init_verbose(cmd->current_settings.verbose + VERBOSE_BASE_LEVEL);
init_silent(cmd->current_settings.silent);
init_log_journal(cmd->current_settings.journal);
}
static int _read_devices_list(struct cmd_context *cmd)
@@ -2511,6 +2527,8 @@ static int _get_current_settings(struct cmd_context *cmd)
if (!strcmp(hint_mode, "none")) {
cmd->enable_hints = 0;
cmd->use_hints = 0;
} else if (!strcmp(hint_mode, "pvs_online")) {
cmd->hints_pvs_online = 1;
}
}

View File

@@ -21,6 +21,8 @@
#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;
@@ -179,6 +181,27 @@ out:
return ret;
}
/*
* 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;
@@ -204,7 +227,7 @@ static char *_vgname_in_pvid_file_buf(char *buf)
#define MAX_PVID_FILE_SIZE 512
static int _online_pvid_file_read(char *path, int *major, int *minor, char *vgname)
int online_pvid_file_read(char *path, int *major, int *minor, char *vgname)
{
char buf[MAX_PVID_FILE_SIZE] = { 0 };
char *name;
@@ -259,7 +282,7 @@ static void _lookup_file_remove(char *vgname)
* that the vg will be activated again when it becomes complete.
*/
static void _online_vg_file_remove(const char *vgname)
void online_vg_file_remove(const char *vgname)
{
char path[PATH_MAX];
@@ -306,7 +329,7 @@ static void _online_pvid_file_remove_devno(int major, int minor)
file_minor = 0;
memset(file_vgname, 0, sizeof(file_vgname));
_online_pvid_file_read(path, &file_major, &file_minor, file_vgname);
online_pvid_file_read(path, &file_major, &file_minor, file_vgname);
if ((file_major == major) && (file_minor == minor)) {
log_debug("Unlink pv online %s", path);
@@ -314,7 +337,7 @@ static void _online_pvid_file_remove_devno(int major, int minor)
log_sys_debug("unlink", path);
if (file_vgname[0]) {
_online_vg_file_remove(file_vgname);
online_vg_file_remove(file_vgname);
_lookup_file_remove(file_vgname);
}
}
@@ -345,7 +368,7 @@ static void _online_files_remove(const char *dirpath)
log_sys_debug("closedir", dirpath);
}
static int _online_pvid_file_create(struct device *dev, const char *vgname)
static 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 };
@@ -362,18 +385,18 @@ static int _online_pvid_file_create(struct device *dev, const char *vgname)
minor = (int)MINOR(dev->dev);
if (dm_snprintf(path, sizeof(path), "%s/%s", _pvs_online_dir, dev->pvid) < 0) {
log_error("Path %s/%s is too long.", _pvs_online_dir, dev->pvid);
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("Cannot create online file path for %s %d:%d.", dev_name(dev), major, minor);
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_warn("Incomplete online file for %s %d:%d vg %s.", dev_name(dev), major, minor, vgname);
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;
}
@@ -387,7 +410,7 @@ static int _online_pvid_file_create(struct device *dev, const char *vgname)
if (fd < 0) {
if (errno == EEXIST)
goto check_duplicate;
log_error("Failed to create online file for %s path %s error %d", dev_name(dev), path, errno);
log_error_pvscan(cmd, "Failed to create online file for %s path %s error %d", dev_name(dev), path, errno);
return 0;
}
@@ -425,7 +448,7 @@ check_duplicate:
memset(file_vgname, 0, sizeof(file_vgname));
_online_pvid_file_read(path, &file_major, &file_minor, 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);
@@ -435,12 +458,12 @@ check_duplicate:
/* 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[%d] PV %s is duplicate for PVID %s on %d:%d and %d:%d.",
getpid(), dev_name(dev), dev->pvid, major, minor, file_major, file_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[%d] PV %s has unexpected VG %s vs %s.",
getpid(), dev_name(dev), vgname, file_vgname);
log_error_pvscan(cmd, "PV %s has unexpected VG %s vs %s.",
dev_name(dev), vgname, file_vgname);
return 0;
}
@@ -475,7 +498,7 @@ static int _write_lookup_file(struct cmd_context *cmd, struct volume_group *vg)
int fd;
if (dm_snprintf(path, sizeof(path), "%s/%s", _pvs_lookup_dir, vg->name) < 0) {
log_error("Path %s/%s is too long.", _pvs_lookup_dir, vg->name);
log_error_pvscan(cmd, "Path %s/%s is too long.", _pvs_lookup_dir, vg->name);
return 0;
}
@@ -638,7 +661,7 @@ static int _count_pvid_files_from_lookup_file(struct cmd_context *cmd, struct de
return (vgname) ? 1 : 0;
}
static void _online_dir_setup(void)
static void _online_dir_setup(struct cmd_context *cmd)
{
struct stat st;
int rv;
@@ -652,7 +675,7 @@ static void _online_dir_setup(void)
dm_prepare_selinux_context(NULL, 0);
if ((rv < 0) && stat(DEFAULT_RUN_DIR, &st))
log_error("Failed to create %s %d", DEFAULT_RUN_DIR, errno);
log_error_pvscan(cmd, "Failed to create %s %d", DEFAULT_RUN_DIR, errno);
do_pvs:
if (!stat(_pvs_online_dir, &st))
@@ -664,7 +687,7 @@ do_pvs:
dm_prepare_selinux_context(NULL, 0);
if ((rv < 0) && stat(_pvs_online_dir, &st))
log_error("Failed to create %s %d", _pvs_online_dir, errno);
log_error_pvscan(cmd, "Failed to create %s %d", _pvs_online_dir, errno);
do_vgs:
if (!stat(_vgs_online_dir, &st))
@@ -676,7 +699,7 @@ do_vgs:
dm_prepare_selinux_context(NULL, 0);
if ((rv < 0) && stat(_vgs_online_dir, &st))
log_error("Failed to create %s %d", _vgs_online_dir, errno);
log_error_pvscan(cmd, "Failed to create %s %d", _vgs_online_dir, errno);
do_lookup:
if (!stat(_pvs_lookup_dir, &st))
@@ -688,7 +711,7 @@ do_lookup:
dm_prepare_selinux_context(NULL, 0);
if ((rv < 0) && stat(_pvs_lookup_dir, &st))
log_error("Failed to create %s %d", _pvs_lookup_dir, errno);
log_error_pvscan(cmd, "Failed to create %s %d", _pvs_lookup_dir, errno);
}
@@ -725,7 +748,7 @@ static int _pvscan_aa_single(struct cmd_context *cmd, const char *vg_name,
log_debug("pvscan autoactivating VG %s.", vg_name);
if (!vgchange_activate(cmd, vg, CHANGE_AAY)) {
log_error("%s: autoactivation failed.", vg->name);
log_error_pvscan(cmd, "%s: autoactivation failed.", vg->name);
pp->activate_errors++;
}
@@ -738,7 +761,7 @@ static int _online_vg_file_create(struct cmd_context *cmd, const char *vgname)
int fd;
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);
log_error_pvscan(cmd, "Path %s/%s is too long.", _vgs_online_dir, vgname);
return 0;
}
@@ -823,18 +846,18 @@ static int _get_devs_from_saved_vg(struct cmd_context *cmd, const char *vgname,
file_minor = 0;
memset(file_vgname, 0, sizeof(file_vgname));
_online_pvid_file_read(path, &file_major, &file_minor, file_vgname);
online_pvid_file_read(path, &file_major, &file_minor, file_vgname);
if (file_vgname[0] && strcmp(vgname, file_vgname)) {
log_error("Wrong VG found for %d:%d PVID %s: %s vs %s",
file_major, file_minor, pvid, vgname, file_vgname);
log_error_pvscan(cmd, "Wrong VG found for %d:%d PVID %s: %s vs %s",
file_major, file_minor, pvid, vgname, file_vgname);
goto bad;
}
devno = MKDEV(file_major, file_minor);
if (!(dev = dev_cache_get_by_devt(cmd, devno, NULL, NULL))) {
log_error("No device found for %d:%d PVID %s", file_major, file_minor, pvid);
log_error_pvscan(cmd, "No device found for %d:%d PVID %s", file_major, file_minor, pvid);
goto bad;
}
@@ -844,7 +867,7 @@ static int _get_devs_from_saved_vg(struct cmd_context *cmd, const char *vgname,
if (strcmp(name1, name2)) {
if (!id_write_format((const struct id *)pvid, uuidstr, sizeof(uuidstr)))
uuidstr[0] = '\0';
log_print("PVID %s read from %s last written to %s.", uuidstr, name1, name2);
log_print_pvscan(cmd, "PVID %s read from %s last written to %s.", uuidstr, name1, name2);
goto bad;
}
@@ -921,7 +944,7 @@ static int _pvscan_aa_quick(struct cmd_context *cmd, struct pvscan_aa_params *pp
* The dev_cache gives us struct devices from the devnums.
*/
if (!_get_devs_from_saved_vg(cmd, vgname, &devs)) {
log_print("pvscan[%d] VG %s not using quick activation.", getpid(), vgname);
log_print_pvscan(cmd, "VG %s not using quick activation.", vgname);
*no_quick = 1;
return ECMD_FAILED;
}
@@ -932,7 +955,7 @@ static int _pvscan_aa_quick(struct cmd_context *cmd, struct pvscan_aa_params *pp
* label rescan are then disabled in vg_read.)
*/
if (!lock_vol(cmd, vgname, LCK_VG_WRITE, NULL)) {
log_error("pvscan activation for VG %s failed to lock VG.", vgname);
log_error_pvscan(cmd, "activation for VG %s failed to lock VG.", vgname);
return ECMD_FAILED;
}
@@ -945,7 +968,7 @@ static int _pvscan_aa_quick(struct cmd_context *cmd, struct pvscan_aa_params *pp
label_scan_devs(cmd, NULL, &devs);
if (!(vgid = lvmcache_vgid_from_vgname(cmd, vgname))) {
log_error("pvscan activation for VG %s failed to find vgid.", vgname);
log_error_pvscan(cmd, "activation for VG %s failed to find vgid.", vgname);
return ECMD_FAILED;
}
@@ -965,7 +988,7 @@ static int _pvscan_aa_quick(struct cmd_context *cmd, struct pvscan_aa_params *pp
* original device arg scan. There will be very few and unusual
* cases that would be caught here.
*/
log_error("pvscan activation for VG %s cannot read (%x).", vgname, error_flags);
log_error_pvscan(cmd, "activation for VG %s cannot read (%x).", vgname, error_flags);
return ECMD_FAILED;
}
@@ -987,7 +1010,7 @@ static int _pvscan_aa_quick(struct cmd_context *cmd, struct pvscan_aa_params *pp
dm_list_iterate_items(pvl, &vg->pvs) {
if (dev_in_device_list(pvl->pv->dev, &devs))
continue;
log_error("pvscan activation for VG %s found different devices.", vgname);
log_error_pvscan(cmd, "activation for VG %s found different devices.", vgname);
ret = ECMD_FAILED;
goto out;
}
@@ -995,7 +1018,7 @@ static int _pvscan_aa_quick(struct cmd_context *cmd, struct pvscan_aa_params *pp
log_debug("pvscan autoactivating VG %s.", vgname);
if (!vgchange_activate(cmd, vg, CHANGE_AAY)) {
log_error("%s: autoactivation failed.", vg->name);
log_error_pvscan(cmd, "%s: autoactivation failed.", vg->name);
pp->activate_errors++;
}
@@ -1014,7 +1037,7 @@ static int _pvscan_aa(struct cmd_context *cmd, struct pvscan_aa_params *pp,
int ret = ECMD_FAILED;
if (!(handle = init_processing_handle(cmd, NULL))) {
log_error("Failed to initialize processing handle.");
log_error_pvscan(cmd, "Failed to initialize processing handle.");
goto out;
}
@@ -1029,11 +1052,11 @@ static int _pvscan_aa(struct cmd_context *cmd, struct pvscan_aa_params *pp,
*/
dm_list_iterate_items_safe(sl, sl2, vgnames) {
if (!_online_vg_file_create(cmd, sl->str)) {
log_print("pvscan[%d] VG %s skip autoactivation.", getpid(), sl->str);
log_print_pvscan(cmd, "VG %s skip autoactivation.", sl->str);
str_list_del(vgnames, sl->str);
continue;
}
log_print("pvscan[%d] VG %s run autoactivation.", getpid(), sl->str);
log_print_pvscan(cmd, "VG %s run autoactivation.", sl->str);
}
if (dm_list_empty(vgnames)) {
@@ -1165,6 +1188,64 @@ static int _get_args_devs(struct cmd_context *cmd, struct dm_list *pvscan_args,
return 1;
}
static void _set_pv_devices_online(struct cmd_context *cmd, struct volume_group *vg)
{
char path[PATH_MAX];
char file_vgname[NAME_LEN];
char pvid[ID_LEN+1] = { 0 };
struct pv_list *pvl;
struct device *dev;
int major, minor;
dev_t devno;
dm_list_iterate_items(pvl, &vg->pvs) {
memcpy(&pvid, &pvl->pv->id.uuid, ID_LEN);
if (pvl->pv->status & MISSING_PV) {
log_debug("set_pv_devices_online vg %s pv %s missing flag already set",
vg->name, pvid);
continue;
}
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;
continue;
}
memset(path, 0, sizeof(path));
snprintf(path, sizeof(path), "%s/%s", _pvs_online_dir, pvid);
major = 0;
minor = 0;
file_vgname[0] = '\0';
online_pvid_file_read(path, &major, &minor, file_vgname);
if (file_vgname[0] && strcmp(vg->name, file_vgname)) {
log_warn("WARNING: VG %s PV %s wrong vgname in online file %s",
vg->name, pvid, file_vgname);
pvl->pv->status |= MISSING_PV;
continue;
}
devno = MKDEV(major, minor);
if (!(dev = dev_cache_get_by_devt(cmd, devno, NULL, NULL))) {
log_print_pvscan(cmd, "VG %s PV %s no device found for %d:%d",
vg->name, pvid, major, minor);
pvl->pv->status |= MISSING_PV;
continue;
}
log_debug("set_pv_devices_online vg %s pv %s is online %s",
vg->name, pvid, dev_name(dev));
pvl->pv->dev = dev;
}
}
static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvscan_devs,
int *pv_count, struct dm_list *complete_vgnames)
{
@@ -1177,15 +1258,20 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
struct metadata_area *mda1, *mda2;
struct volume_group *vg;
struct physical_volume *pv;
const char *vgname;
uint32_t ext_version, ext_flags;
const char *vgname = NULL;
uint64_t devsize;
uint32_t ext_version, ext_flags;
int do_cache = arg_is_set(cmd, cache_long_ARG);
int do_activate = arg_is_set(cmd, activate_ARG);
int do_full_check;
int do_list_lvs = arg_is_set(cmd, listlvs_ARG);
int do_list_vg = arg_is_set(cmd, listvg_ARG);
int do_check_complete = arg_is_set(cmd, checkcomplete_ARG);
int do_vgonline = arg_is_set(cmd, vgonline_ARG);
int pvs_online;
int pvs_offline;
int pvs_unknown;
int vg_complete;
int do_full_check;
int ret = 1;
dm_list_iterate_items_safe(devl, devl2, pvscan_devs) {
@@ -1195,14 +1281,14 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
if (!(info = lvmcache_info_from_pvid(dev->pvid, dev, 0))) {
if (!do_all)
log_print("pvscan[%d] ignore %s with no lvm info.", getpid(), dev_name(dev));
log_print_pvscan(cmd, "ignore %s with no lvm info.", dev_name(dev));
continue;
}
ext_version = lvmcache_ext_version(info);
ext_flags = lvmcache_ext_flags(info);
if ((ext_version >= 2) && !(ext_flags & PV_EXT_USED)) {
log_print("pvscan[%d] PV %s not used.", getpid(), dev_name(dev));
log_print_pvscan(cmd, "PV %s not used.", dev_name(dev));
(*pv_count)++;
continue;
}
@@ -1221,7 +1307,7 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
vg = mda2->ops->vg_read(cmd, fid, "", mda2, NULL, NULL);
if (!vg) {
log_print("pvscan[%d] PV %s has no VG metadata.", getpid(), dev_name(dev));
log_print_pvscan(cmd, "PV %s has no VG metadata.", dev_name(dev));
if (fid)
fmt->ops->destroy_instance(fid);
goto online;
@@ -1230,7 +1316,7 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
set_pv_devices(fid, vg);
if (!(pv = find_pv(vg, dev))) {
log_print("pvscan[%d] PV %s not found in VG %s.", getpid(), dev_name(dev), vg->name);
log_print_pvscan(cmd, "PV %s not found in VG %s.", dev_name(dev), vg->name);
release_vg(vg);
continue;
}
@@ -1247,14 +1333,15 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
if (pv->device_hint && !strncmp(pv->device_hint, "/dev/md", 7))
do_full_check = 1;
}
if (do_full_check && dev_is_md_component(cmd, dev, NULL, 1)) {
log_print("pvscan[%d] ignore md component %s.", getpid(), dev_name(dev));
log_print_pvscan(cmd, "ignore md component %s.", dev_name(dev));
release_vg(vg);
continue;
}
if (vg_is_shared(vg)) {
log_print("pvscan[%d] PV %s ignore shared VG.", getpid(), dev_name(dev));
log_print_pvscan(cmd, "PV %s ignore shared VG.", dev_name(dev));
release_vg(vg);
continue;
}
@@ -1264,7 +1351,13 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
vg_is_foreign(vg)) {
log_verbose("Ignore PV %s with VG system id %s with our system id %s",
dev_name(dev), vg->system_id, cmd->system_id);
log_print("pvscan[%d] PV %s ignore foreign VG.", getpid(), dev_name(dev));
log_print_pvscan(cmd, "PV %s ignore foreign VG.", dev_name(dev));
release_vg(vg);
continue;
}
if (vg_is_exported(vg)) {
log_print_pvscan(cmd, "PV %s ignore exported VG.", dev_name(dev));
release_vg(vg);
continue;
}
@@ -1283,19 +1376,20 @@ 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 (!_online_pvid_file_create(dev, vg ? vg->name : NULL)) {
log_error("pvscan[%d] PV %s failed to create online file.", getpid(), dev_name(dev));
if (do_cache && !_online_pvid_file_create(cmd, dev, vg ? vg->name : NULL)) {
log_error_pvscan(cmd, "PV %s failed to create online file.", dev_name(dev));
release_vg(vg);
ret = 0;
continue;
}
/*
* When not activating we don't need to know about vg completeness.
* A plain pvscan --cache <dev> just creates the online file.
*/
if (!do_activate) {
log_print("pvscan[%d] PV %s online.", getpid(), dev_name(dev));
if (!do_activate && !do_list_lvs && !do_list_vg) {
log_print_pvscan(cmd, "PV %s online.", dev_name(dev));
release_vg(vg);
continue;
}
@@ -1303,58 +1397,159 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
/*
* Check if all the PVs for this VG are online. If the arrival
* of this dev completes the VG, then save the vgname in
* complete_vgnames so it will be activated.
* complete_vgnames (activation phase will want to know which
* VGs to activate.)
*/
pvs_online = 0;
pvs_offline = 0;
pvs_unknown = 0;
vg_complete = 0;
if (do_activate || do_check_complete) {
pvs_online = 0;
pvs_offline = 0;
pvs_unknown = 0;
vg_complete = 0;
if (vg) {
/*
* Use the VG metadata from this PV for a list of all
* PVIDs. Write a lookup file of PVIDs in case another
* pvscan needs it. After writing lookup file, recheck
* pvid files to resolve a possible race with another
* pvscan reading the lookup file that missed it.
*/
log_debug("checking all pvid files from vg %s", vg->name);
_count_pvid_files(vg, &pvs_online, &pvs_offline);
if (pvs_offline && _write_lookup_file(cmd, vg)) {
log_debug("rechecking all pvid files from vg %s", vg->name);
if (vg) {
/*
* Use the VG metadata from this PV for a list of all
* PVIDs. Write a lookup file of PVIDs in case another
* pvscan needs it. After writing lookup file, recheck
* pvid files to resolve a possible race with another
* pvscan reading the lookup file that missed it.
*/
log_debug("checking all pvid files from vg %s", vg->name);
_count_pvid_files(vg, &pvs_online, &pvs_offline);
if (!pvs_offline)
log_print("pvscan[%d] VG %s complete after recheck.", getpid(), vg->name);
if (pvs_offline && _write_lookup_file(cmd, vg)) {
log_debug("rechecking all pvid files from vg %s", vg->name);
_count_pvid_files(vg, &pvs_online, &pvs_offline);
if (!pvs_offline)
log_print_pvscan(cmd, "VG %s complete after recheck.", vg->name);
}
vgname = vg->name;
} else {
/*
* No VG metadata on this PV, so try to use a lookup
* file written by a prior pvscan for a list of all
* PVIDs. A lookup file may not exist for this PV if
* it's the first to appear from the VG.
*/
log_debug("checking all pvid files from lookup file");
if (!_count_pvid_files_from_lookup_file(cmd, dev, &pvs_online, &pvs_offline, &vgname))
pvs_unknown = 1;
}
if (pvs_unknown) {
log_print_pvscan(cmd, "PV %s online, VG unknown.", dev_name(dev));
vg_complete = 0;
} else if (pvs_offline) {
log_print_pvscan(cmd, "PV %s online, VG %s incomplete (need %d).",
dev_name(dev), vgname, pvs_offline);
vg_complete = 0;
} else {
log_print_pvscan(cmd, "PV %s online, VG %s is complete.", dev_name(dev), vgname);
if (!str_list_add(cmd->mem, complete_vgnames, dm_pool_strdup(cmd->mem, vgname)))
stack;
vg_complete = 1;
}
}
if (!vgname && vg)
vgname = vg->name;
if (do_list_vg || do_list_lvs) {
if (!vgname) {
log_print("VG unknown");
} else if (!do_check_complete) {
log_print("VG %s", vgname);
} else if (vg_complete) {
if (do_vgonline && !_online_vg_file_create(cmd, vgname)) {
log_print("VG %s finished", vgname);
} else {
/*
* A udev rule imports KEY=val from a program's stdout.
* Other output causes udev to ignore everything.
* Run pvscan from udev rule using --udevoutput to
* enable this printf, and suppress all log output
*/
if (arg_is_set(cmd, udevoutput_ARG))
printf("LVM_VG_NAME_COMPLETE='%s'\n", vgname);
else
log_print("VG %s complete", vgname);
}
} else {
if (arg_is_set(cmd, udevoutput_ARG))
printf("LVM_VG_NAME_INCOMPLETE='%s'\n", vgname);
else
log_print("VG %s incomplete", vgname);
}
vgname = vg->name;
} else {
/*
* No VG metadata on this PV, so try to use a lookup
* file written by a prior pvscan for a list of all
* PVIDs. A lookup file may not exist for this PV if
* it's the first to appear from the VG.
* When the VG is complete|finished, we could print
* a list of devices in the VG, by reading the pvid files
* that were counted, which provides major:minor of each
* device and using that to get the struct dev and dev_name.
* The user could pass this list of devices to --devices
* to optimize a subsequent command (activation) on the VG.
* Just call set_pv_devices_online (if not done othewise)
* since that finds the devs.
*/
log_debug("checking all pvid files from lookup file");
if (!_count_pvid_files_from_lookup_file(cmd, dev, &pvs_online, &pvs_offline, &vgname))
pvs_unknown = 1;
}
if (pvs_unknown) {
log_print("pvscan[%d] PV %s online, VG unknown.",
getpid(), dev_name(dev));
} else if (pvs_offline) {
log_print("pvscan[%d] PV %s online, VG %s incomplete (need %d).",
getpid(), dev_name(dev), vgname, pvs_offline);
} else {
log_print("pvscan[%d] PV %s online, VG %s is complete.", getpid(), dev_name(dev), vgname);
if (!str_list_add(cmd->mem, complete_vgnames, dm_pool_strdup(cmd->mem, vgname)))
stack;
vg_complete = 1;
if (do_list_lvs && !vg) {
/* require all PVs used for booting have metadata */
log_print_pvscan(cmd, "Cannot list LVs from device without metadata.");
}
if (!saved_vg && vg && vg_complete && !do_all && (dm_list_size(pvscan_devs) == 1))
if (do_list_lvs && vg) {
struct dm_list lvs_list;
struct lv_list *lvl;
dm_list_init(&lvs_list);
/*
* For each vg->pvs entry, get the dev based on the online file
* for the pvid and set pv->dev or pv->status MISSING_PV.
*/
_set_pv_devices_online(cmd, vg);
/*
* lvs_list are LVs that use dev.
*/
if (!get_visible_lvs_using_pv(cmd, vg, dev, &lvs_list))
log_print_pvscan(cmd, "Failed to find LVs using %s.", dev_name(dev));
if (!do_check_complete) {
dm_list_iterate_items(lvl, &lvs_list)
log_print("LV %s", display_lvname(lvl->lv));
} else if (vg_complete) {
/*
* A shortcut; the vg complete implies all lvs are complete.
*/
dm_list_iterate_items(lvl, &lvs_list)
log_print("LV %s complete", display_lvname(lvl->lv));
} else {
/*
* For each LV in VG, check if all devs are present.
* Sets the PARTIAL flag on LVs that are not complete.
*/
if (!vg_mark_partial_lvs(vg, 1))
log_print_pvscan(cmd, "Failed to check partial lvs.");
dm_list_iterate_items(lvl, &lvs_list) {
if (!lv_is_partial(lvl->lv))
log_print("LV %s complete", display_lvname(lvl->lv));
else
log_print("LV %s incomplete", display_lvname(lvl->lv));
}
}
}
/*
* When "pvscan --cache -aay <dev>" completes the vg, save the
* struct vg to use for quick activation function.
*/
if (do_activate && !saved_vg && vg && vg_complete && !do_all && (dm_list_size(pvscan_devs) == 1))
saved_vg = vg;
else
release_vg(vg);
@@ -1443,7 +1638,7 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv,
cmd->pvscan_cache_single = 1;
if (!setup_devices(cmd)) {
log_error("Failed to set up devices.");
log_error_pvscan(cmd, "Failed to set up devices.");
return 0;
}
@@ -1509,8 +1704,8 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv,
dm_list_iterate_items_safe(devl, devl2, &pvscan_devs) {
if (!cmd->filter->passes_filter(cmd, cmd->filter, devl->dev, NULL)) {
log_print("pvscan[%d] %s excluded by filters: %s.", getpid(),
dev_name(devl->dev), dev_filtered_reason(devl->dev));
log_print_pvscan(cmd, "%s excluded by filters: %s.",
dev_name(devl->dev), dev_filtered_reason(devl->dev));
dm_list_del(&devl->list);
}
}
@@ -1546,7 +1741,7 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv,
if (!has_pvid) {
/* Not an lvm device */
log_print("pvscan[%d] %s not an lvm device.", getpid(), dev_name(devl->dev));
log_print_pvscan(cmd, "%s not an lvm device.", dev_name(devl->dev));
dm_list_del(&devl->list);
continue;
}
@@ -1557,8 +1752,8 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv,
*/
if (relax_deviceid_filter) {
if (!get_du_for_pvid(cmd, devl->dev->pvid)) {
log_print("pvscan[%d] %s excluded by devices file (checking PVID).",
getpid(), dev_name(devl->dev));
log_print_pvscan(cmd, "%s excluded by devices file (checking PVID).",
dev_name(devl->dev));
dm_list_del(&devl->list);
continue;
}
@@ -1566,8 +1761,8 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv,
/* Applies all filters, including those that need data from dev. */
if (!cmd->filter->passes_filter(cmd, cmd->filter, devl->dev, NULL)) {
log_print("pvscan[%d] %s excluded by filters: %s.", getpid(),
dev_name(devl->dev), dev_filtered_reason(devl->dev));
log_print_pvscan(cmd, "%s excluded by filters: %s.",
dev_name(devl->dev), dev_filtered_reason(devl->dev));
dm_list_del(&devl->list);
}
}
@@ -1627,6 +1822,37 @@ int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv)
return ECMD_PROCESSED;
}
/*
* lvm udev rules call:
* pvscan --cache --listvg|--listlvs --checkcomplete PV
* when PVs appear, even if event_activation=0 in lvm.conf.
*
* The udev rules will do autoactivation if they see complete
* VGs/LVs reported from the pvscan.
*
* When event_activation=0 we do not want to do autoactivation
* from udev events, so we need the pvscan to not report any
* complete VGs/LVs when event_activation=0 so that the udev
* rules do not attempt to autoactivate.
*/
if (arg_is_set(cmd, checkcomplete_ARG) && !event_activation) {
if (arg_is_set(cmd, udevoutput_ARG))
printf("LVM_EVENT_ACTIVATION=0\n");
else
log_print_pvscan(cmd, "Ignoring pvscan with --checkcomplete because event_activation is disabled.");
return ECMD_PROCESSED;
}
/*
* If obtain_device_list_from_udev was set to 1, force it to 0.
* Don't ask udev for info since pvscan is running from udev.
* If a pvscan attempts to get dev info from udev, udev can
* repeatedly return errors about the dev not being initialized
* which will stall the pvscan.
*/
init_obtain_device_list_from_udev(0);
if (arg_is_set(cmd, major_ARG) + arg_is_set(cmd, minor_ARG))
devno_args = 1;
@@ -1637,13 +1863,13 @@ int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv)
do_all = !argc && !devno_args;
_online_dir_setup();
_online_dir_setup(cmd);
if (do_all) {
if (!_pvscan_cache_all(cmd, argc, argv, &complete_vgnames))
return ECMD_FAILED;
} else {
if (!event_activation) {
if (!arg_is_set(cmd, checkcomplete_ARG) && !event_activation) {
/* Avoid doing anything for device removal: pvscan --cache <devno> */
log_verbose("Ignoring pvscan --cache because event_activation is disabled.");
return ECMD_PROCESSED;

View File

@@ -811,6 +811,24 @@ int lv_change_activate(struct cmd_context *cmd, struct logical_volume *lv,
lv_clear_integrity_recalculate_metadata(lv);
}
/*
* When LVs are deactivated, then autoactivation of the VG is
* "re-armed" by removing the vg online file. So, after deactivation
* of LVs, if PVs are disconnected and reconnected again, event
* activation will trigger autoactivation again. This secondary
* autoactivation is somewhat different from, and not as important as
* the initial autoactivation during system startup. The secondary
* autoactivation will happen to a VG on a running system and may be
* mixing with user commands, so the end result is unpredictable.
*
* It's possible that we might want a config setting for usersto
* disable secondary autoactivations. Once a system is up, the
* user may want to take charge of activation changes to the VG
* and not have the system autoactivation interfere.
*/
if (!is_change_activating(activate) && find_config_tree_bool(cmd, global_event_activation_CFG, NULL))
online_vg_file_remove(lv->vg->name);
set_lv_notify(lv->vg->cmd);
return r;

View File

@@ -293,4 +293,6 @@ int lvconvert_cachevol_attach_single(struct cmd_context *cmd,
struct logical_volume *lv,
struct processing_handle *handle);
void online_vg_file_remove(const char *vgname);
#endif

87
udev/69-dm-lvm.rules.in Normal file
View File

@@ -0,0 +1,87 @@
# Copyright (C) 2012,2021 Red Hat, Inc. All rights reserved.
#
# This file is part of LVM.
#
# This rule requires blkid to be called on block devices before so only devices
# used as LVM PVs are processed (ID_FS_TYPE="LVM2_member").
SUBSYSTEM!="block", GOTO="lvm_end"
(LVM_EXEC_RULE)
ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", GOTO="lvm_end"
# Only process devices already marked as a PV - this requires blkid to be called before.
ENV{ID_FS_TYPE}!="LVM2_member", GOTO="lvm_end"
ENV{DM_MULTIPATH_DEVICE_PATH}=="1", GOTO="lvm_end"
ACTION=="remove", GOTO="lvm_end"
# Create /dev/disk/by-id/lvm-pv-uuid-<PV_UUID> symlink for each PV
ENV{ID_FS_UUID_ENC}=="?*", SYMLINK+="disk/by-id/lvm-pv-uuid-$env{ID_FS_UUID_ENC}"
# If the PV is a special device listed below, scan only if the device is
# properly activated. These devices are not usable after an ADD event,
# but they require an extra setup and they are ready after a CHANGE event.
# Also support coldplugging with ADD event but only if the device is already
# properly activated.
# This logic should be eventually moved to rules where those particular
# devices are processed primarily (MD and loop).
# DM device:
KERNEL!="dm-[0-9]*", GOTO="next"
ENV{DM_UDEV_PRIMARY_SOURCE_FLAG}=="1", ENV{DM_ACTIVATION}=="1", GOTO="lvm_scan"
GOTO="lvm_end"
# MD device:
LABEL="next"
KERNEL!="md[0-9]*", GOTO="next"
IMPORT{db}="LVM_MD_PV_ACTIVATED"
ACTION=="add", ENV{LVM_MD_PV_ACTIVATED}=="1", GOTO="lvm_scan"
ACTION=="change", ENV{LVM_MD_PV_ACTIVATED}!="1", TEST=="md/array_state", ENV{LVM_MD_PV_ACTIVATED}="1", GOTO="lvm_scan"
ACTION=="add", KERNEL=="md[0-9]*p[0-9]*", GOTO="lvm_scan"
ENV{LVM_MD_PV_ACTIVATED}!="1", ENV{SYSTEMD_READY}="0"
GOTO="lvm_end"
# Loop device:
LABEL="next"
KERNEL!="loop[0-9]*", GOTO="next"
ACTION=="add", ENV{LVM_LOOP_PV_ACTIVATED}=="1", GOTO="lvm_scan"
ACTION=="change", ENV{LVM_LOOP_PV_ACTIVATED}!="1", TEST=="loop/backing_file", ENV{LVM_LOOP_PV_ACTIVATED}="1", GOTO="lvm_scan"
ENV{LVM_LOOP_PV_ACTIVATED}!="1", ENV{SYSTEMD_READY}="0"
GOTO="lvm_end"
LABEL="next"
ACTION!="add", GOTO="lvm_end"
LABEL="lvm_scan"
ENV{SYSTEMD_READY}="1"
# pvscan will check if this device completes a VG,
# i.e. all PVs in the VG are now present with the
# arrival of this PV. If so, it prints to stdout:
# LVM_VG_NAME_COMPLETE='foo'
#
# When the VG is complete it can be activated, so
# vgchange -aay <vgname> is run. It is run via
# systemd since it can take longer to run than
# udev wants to block when processing rules.
# (if there are hundreds of LVs to activate,
# the vgchange can take many seconds.)
#
# pvscan only reads the single device specified,
# and uses temp files under /run/lvm to check if
# other PVs in the VG are present.
#
# If event_activation=0 in lvm.conf, this pvscan
# (using checkcomplete) will do nothing, so that
# no event-based autoactivation will be happen.
#
# TODO: adjust the output of vgchange -aay so that
# it's better suited to appearing in the journal.
IMPORT{program}="(LVM_EXEC)/lvm pvscan --cache --listvg --checkcomplete --vgonline --udevoutput --journal=output $env{DEVNAME}"
ENV{LVM_VG_NAME_COMPLETE}=="?*", RUN+="/usr/bin/systemd-run -r --no-block --property DefaultDependencies=no --unit lvm-activate-$env{LVM_VG_NAME_COMPLETE} lvm vgchange -aay --config devices/hints=pvs_online $env{LVM_VG_NAME_COMPLETE}"
GOTO="lvm_end"
LABEL="lvm_end"

View File

@@ -18,7 +18,7 @@ top_builddir = @top_builddir@
include $(top_builddir)/make.tmpl
DM_RULES=10-dm.rules 13-dm-disk.rules 95-dm-notify.rules
LVM_RULES=11-dm-lvm.rules 69-dm-lvm-metad.rules
LVM_RULES=11-dm-lvm.rules 69-dm-lvm.rules
DM_DIR=$(shell $(GREP) "\#define DM_DIR" $(top_srcdir)/libdm/misc/dm-ioctl.h | $(AWK) '{print $$3}')