mirror of
git://sourceware.org/git/lvm2.git
synced 2025-10-19 07:33:14 +03:00
Compare commits
45 Commits
dev-dct-sc
...
dev-dct-hi
Author | SHA1 | Date | |
---|---|---|---|
|
74e404ce11 | ||
|
d13dce20df | ||
|
c229e321da | ||
|
8a0da7b4f5 | ||
|
57c0698ec4 | ||
|
f39fbebb04 | ||
|
7578a30534 | ||
|
fc726b60bc | ||
|
8f2789a37d | ||
|
f8357f5b98 | ||
|
d38fdb25e4 | ||
|
e33c2e032c | ||
|
25f0f5daac | ||
|
f8b52f2763 | ||
|
deaf43d6f0 | ||
|
9048565093 | ||
|
db22a389cf | ||
|
66daedc6d2 | ||
|
70c32d1e74 | ||
|
ed48cb26a3 | ||
|
3a92d633a5 | ||
|
d5a06f9a7d | ||
|
b876dbfc24 | ||
|
e035e32350 | ||
|
d89942d157 | ||
|
a47e20a092 | ||
|
39f497b9d8 | ||
|
580e64e93b | ||
|
2c6a2b6e86 | ||
|
5fcbc3bd7d | ||
|
6e773bb196 | ||
|
d9cb1d3983 | ||
|
73a05c8f02 | ||
|
84bd394cf9 | ||
|
1139a05939 | ||
|
c35f7722d5 | ||
|
f773040625 | ||
|
c474f174cc | ||
|
71cb54d92f | ||
|
f70d97b916 | ||
|
e8f3a63000 | ||
|
27abb03a0d | ||
|
f25df0386e | ||
|
e5740e9646 | ||
|
f8742b6df2 |
@@ -1,5 +1,9 @@
|
||||
Version 2.03.13 -
|
||||
===============================
|
||||
Fix detection of active components of external origin volume.
|
||||
Add vdoimport tool to support conversion of VDO volumes.
|
||||
Support configurable allocation/vdo_pool_header_size.
|
||||
Fix handling of lvconvert --type vdo-pool --virtualsize.
|
||||
Simplified handling of archive() and backup() internal calls.
|
||||
Fix load of kvdo target when it is not present in memory (2.03.12).
|
||||
|
||||
|
@@ -723,7 +723,7 @@ allocation {
|
||||
# vdo_write_policy = "auto"
|
||||
|
||||
# Configuration option allocation/vdo_max_discard.
|
||||
# Specified te maximum size of discard bio accepted, in 4096 byte blocks.
|
||||
# Specified the maximum size of discard bio accepted, in 4096 byte blocks.
|
||||
# I/O requests to a VDO volume are normally split into 4096-byte blocks,
|
||||
# and processed up to 2048 at a time. However, discard requests to a VDO volume
|
||||
# can be automatically split to a larger size, up to <max discard> 4096-byte blocks
|
||||
@@ -733,6 +733,11 @@ allocation {
|
||||
# The default and minimum is 1. The maximum is UINT_MAX / 4096.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_max_discard = 1
|
||||
|
||||
# Configuration option allocation/vdo_pool_header_size.
|
||||
# Specified the emptry header size in KiB at the front and end of vdo pool device.
|
||||
# This configuration option has an automatic default value.
|
||||
# vdo_pool_header_size = 512
|
||||
}
|
||||
|
||||
# Configuration section log.
|
||||
|
149
configure
vendored
149
configure
vendored
@@ -643,6 +643,8 @@ WRITE_INSTALL
|
||||
WRITECACHE
|
||||
VDO_LIB
|
||||
VDO_INCLUDE
|
||||
VDOIMPORT_PATH
|
||||
VDOIMPORT
|
||||
VDO
|
||||
VALGRIND_POOL
|
||||
USRSBINDIR
|
||||
@@ -747,7 +749,6 @@ BUILD_DMFILEMAPD
|
||||
BUILD_LOCKDDLM_CONTROL
|
||||
BUILD_LOCKDDLM
|
||||
BUILD_LOCKDSANLOCK
|
||||
BUILD_LOCKDIDM
|
||||
BUILD_LVMLOCKD
|
||||
BUILD_LVMPOLLD
|
||||
BUILD_LVMDBUSD
|
||||
@@ -775,16 +776,20 @@ SYSTEMD_LIBS
|
||||
SYSTEMD_CFLAGS
|
||||
BLKID_LIBS
|
||||
BLKID_CFLAGS
|
||||
APP_MACHINEID_LIBS
|
||||
APP_MACHINEID_CFLAGS
|
||||
NOTIFY_DBUS_LIBS
|
||||
NOTIFY_DBUS_CFLAGS
|
||||
BLKID_LIBS
|
||||
BLKID_CFLAGS
|
||||
LOCKD_IDM_LIBS
|
||||
LOCKD_IDM_CFLAGS
|
||||
LOCKD_DLM_CONTROL_LIBS
|
||||
LOCKD_DLM_CONTROL_CFLAGS
|
||||
LOCKD_DLM_LIBS
|
||||
LOCKD_DLM_CFLAGS
|
||||
LOCKD_SANLOCK_LIBS
|
||||
LOCKD_SANLOCK_CFLAGS
|
||||
LOCKD_IDM_LIBS
|
||||
LOCKD_IDM_CFLAGS
|
||||
VALGRIND_LIBS
|
||||
VALGRIND_CFLAGS
|
||||
GENPNG
|
||||
@@ -956,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
|
||||
@@ -970,6 +976,7 @@ enable_dbus_service
|
||||
enable_pkgconfig
|
||||
enable_write_install
|
||||
enable_fsadm
|
||||
enable_vdoimport
|
||||
enable_blkdeactivate
|
||||
enable_dmeventd
|
||||
enable_selinux
|
||||
@@ -1027,8 +1034,12 @@ 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
|
||||
NOTIFY_DBUS_LIBS
|
||||
SYSTEMD_CFLAGS
|
||||
SYSTEMD_LIBS
|
||||
UDEV_CFLAGS
|
||||
@@ -1689,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
|
||||
@@ -1708,6 +1720,7 @@ Optional Features:
|
||||
--enable-pkgconfig install pkgconfig support
|
||||
--enable-write_install install user writable files
|
||||
--disable-fsadm disable fsadm
|
||||
--disable-vdoimport disable vdoimport
|
||||
--disable-blkdeactivate disable blkdeactivate
|
||||
--enable-dmeventd enable the device-mapper event daemon
|
||||
--disable-selinux disable selinux support
|
||||
@@ -1843,10 +1856,17 @@ Some influential environment variables:
|
||||
C compiler flags for LOCKD_IDM, overriding pkg-config
|
||||
LOCKD_IDM_LIBS
|
||||
linker flags for LOCKD_IDM, overriding pkg-config
|
||||
BLKID_CFLAGS
|
||||
C compiler flags for BLKID, overriding pkg-config
|
||||
BLKID_LIBS linker flags for BLKID, overriding pkg-config
|
||||
NOTIFY_DBUS_CFLAGS
|
||||
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
|
||||
@@ -3140,6 +3160,7 @@ case "$host_os" in
|
||||
DM_IOCTLS=yes
|
||||
SELINUX=yes
|
||||
FSADM=yes
|
||||
VDOIMPORT=yes
|
||||
BLKDEACTIVATE=yes
|
||||
;;
|
||||
darwin*)
|
||||
@@ -3153,6 +3174,7 @@ case "$host_os" in
|
||||
DM_IOCTLS=no
|
||||
SELINUX=no
|
||||
FSADM=no
|
||||
VDOIMPORT=no
|
||||
BLKDEACTIVATE=no
|
||||
;;
|
||||
*)
|
||||
@@ -11260,7 +11282,7 @@ fi
|
||||
|
||||
|
||||
if test $pkg_failed = yes; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
|
||||
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
|
||||
@@ -11278,7 +11300,7 @@ fi
|
||||
|
||||
$bailout
|
||||
elif test $pkg_failed = untried; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
$bailout
|
||||
else
|
||||
@@ -11286,6 +11308,7 @@ else
|
||||
LOCKD_IDM_LIBS=$pkg_cv_LOCKD_IDM_LIBS
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
$as_echo "yes" >&6; }
|
||||
HAVE_LOCKD_IDM=yes
|
||||
fi
|
||||
|
||||
pkg_failed=no
|
||||
@@ -11582,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.
|
||||
@@ -12544,6 +12662,18 @@ fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $FSADM" >&5
|
||||
$as_echo "$FSADM" >&6; }
|
||||
|
||||
|
||||
################################################################################
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to install vdoimport" >&5
|
||||
$as_echo_n "checking whether to install vdoimport... " >&6; }
|
||||
# Check whether --enable-vdoimport was given.
|
||||
if test "${enable_vdoimport+set}" = set; then :
|
||||
enableval=$enable_vdoimport; VDOIMPORT=$enableval
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $VDOIMPORT" >&5
|
||||
$as_echo "$VDOIMPORT" >&6; }
|
||||
|
||||
################################################################################
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to install blkdeactivate" >&5
|
||||
$as_echo_n "checking whether to install blkdeactivate... " >&6; }
|
||||
@@ -14030,6 +14160,13 @@ cat >>confdefs.h <<_ACEOF
|
||||
_ACEOF
|
||||
|
||||
|
||||
VDOIMPORT_PATH="$SBINDIR/vdoimport"
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define VDOIMPORT_PATH "$VDOIMPORT_PATH"
|
||||
_ACEOF
|
||||
|
||||
|
||||
################################################################################
|
||||
if test "$BUILD_DMEVENTD" = yes; then
|
||||
|
||||
@@ -14350,6 +14487,8 @@ _ACEOF
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
35
configure.ac
35
configure.ac
@@ -46,6 +46,7 @@ case "$host_os" in
|
||||
DM_IOCTLS=yes
|
||||
SELINUX=yes
|
||||
FSADM=yes
|
||||
VDOIMPORT=yes
|
||||
BLKDEACTIVATE=yes
|
||||
;;
|
||||
darwin*)
|
||||
@@ -59,6 +60,7 @@ case "$host_os" in
|
||||
DM_IOCTLS=no
|
||||
SELINUX=no
|
||||
FSADM=no
|
||||
VDOIMPORT=no
|
||||
BLKDEACTIVATE=no
|
||||
;;
|
||||
*)
|
||||
@@ -1102,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
|
||||
@@ -1311,6 +1333,14 @@ AC_ARG_ENABLE(fsadm, AC_HELP_STRING([--disable-fsadm], [disable fsadm]),
|
||||
FSADM=$enableval)
|
||||
AC_MSG_RESULT($FSADM)
|
||||
|
||||
|
||||
################################################################################
|
||||
dnl -- Enable vdoimport
|
||||
AC_MSG_CHECKING(whether to install vdoimport)
|
||||
AC_ARG_ENABLE(vdoimport, AC_HELP_STRING([--disable-vdoimport], [disable vdoimport]),
|
||||
VDOIMPORT=$enableval)
|
||||
AC_MSG_RESULT($VDOIMPORT)
|
||||
|
||||
################################################################################
|
||||
dnl -- Enable blkdeactivate
|
||||
AC_MSG_CHECKING(whether to install blkdeactivate)
|
||||
@@ -1666,6 +1696,9 @@ USRSBINDIR="$(eval echo $(eval echo $usrsbindir))"
|
||||
FSADM_PATH="$SBINDIR/fsadm"
|
||||
AC_DEFINE_UNQUOTED(FSADM_PATH, ["$FSADM_PATH"], [Path to fsadm binary.])
|
||||
|
||||
VDOIMPORT_PATH="$SBINDIR/vdoimport"
|
||||
AC_DEFINE_UNQUOTED(VDOIMPORT_PATH, ["$VDOIMPORT_PATH"], [Path to vdoimport binary.])
|
||||
|
||||
################################################################################
|
||||
dnl -- dmeventd pidfile and executable path
|
||||
if test "$BUILD_DMEVENTD" = yes; then
|
||||
@@ -1902,6 +1935,8 @@ AC_SUBST(SILENT_RULES)
|
||||
AC_SUBST(USRSBINDIR)
|
||||
AC_SUBST(VALGRIND_POOL)
|
||||
AC_SUBST(VDO)
|
||||
AC_SUBST(VDOIMPORT)
|
||||
AC_SUBST(VDOIMPORT_PATH)
|
||||
AC_SUBST(VDO_FORMAT_CMD)
|
||||
AC_SUBST(VDO_INCLUDE)
|
||||
AC_SUBST(VDO_LIB)
|
||||
|
@@ -157,14 +157,15 @@ class AutomatedProperties(dbus.service.Object):
|
||||
if not self._ap_search_method:
|
||||
return 0
|
||||
|
||||
search = self.lvm_id
|
||||
if search_key:
|
||||
search = search_key
|
||||
|
||||
# Either we have the new object state or we need to go fetch it
|
||||
if object_state:
|
||||
new_state = object_state
|
||||
else:
|
||||
if search_key:
|
||||
search = search_key
|
||||
else:
|
||||
search = self.lvm_id
|
||||
|
||||
new_state = self._ap_search_method([search])[0]
|
||||
assert isinstance(new_state, State)
|
||||
|
||||
|
@@ -9,13 +9,14 @@
|
||||
|
||||
import subprocess
|
||||
from . import cfg
|
||||
from .cmdhandler import options_to_cli_args, LvmExecutionMeta
|
||||
from .cmdhandler import options_to_cli_args, LvmExecutionMeta, call_lvm
|
||||
import dbus
|
||||
from .utils import pv_range_append, pv_dest_ranges, log_error, log_debug,\
|
||||
add_no_notify
|
||||
import os
|
||||
mt_async_call
|
||||
from .request import RequestEntry
|
||||
import threading
|
||||
import time
|
||||
import traceback
|
||||
|
||||
|
||||
def pv_move_lv_cmd(move_options, lv_full_name,
|
||||
@@ -39,58 +40,50 @@ def lv_merge_cmd(merge_options, lv_full_name):
|
||||
return cmd
|
||||
|
||||
|
||||
def _load_wrapper(ignored):
|
||||
cfg.load()
|
||||
|
||||
|
||||
def _move_callback(job_state, line_str):
|
||||
try:
|
||||
if line_str.count(':') == 2:
|
||||
(device, ignore, percentage) = line_str.split(':')
|
||||
|
||||
job_state.Percent = int(round(
|
||||
float(percentage.strip()[:-1]), 1))
|
||||
|
||||
# While the move is in progress we need to periodically update
|
||||
# the state to reflect where everything is at. we will do this
|
||||
# by scheduling the load to occur in the main work queue.
|
||||
r = RequestEntry(
|
||||
-1, _load_wrapper, ("_move_callback: load",), None, None, False)
|
||||
cfg.worker_q.put(r)
|
||||
except ValueError:
|
||||
log_error("Trying to parse percentage which failed for %s" % line_str)
|
||||
|
||||
|
||||
def _move_merge(interface_name, command, job_state):
|
||||
# We need to execute these command stand alone by forking & exec'ing
|
||||
# the command always as we will be getting periodic output from them on
|
||||
# the status of the long running operation.
|
||||
command.insert(0, cfg.LVM_CMD)
|
||||
|
||||
# Instruct lvm to not register an event with us
|
||||
command = add_no_notify(command)
|
||||
|
||||
#(self, start, ended, cmd, ec, stdout_txt, stderr_txt)
|
||||
meta = LvmExecutionMeta(time.time(), 0, command, -1000, None, None)
|
||||
|
||||
cfg.blackbox.add(meta)
|
||||
|
||||
process = subprocess.Popen(command, stdout=subprocess.PIPE,
|
||||
env=os.environ,
|
||||
stderr=subprocess.PIPE, close_fds=True)
|
||||
|
||||
log_debug("Background process for %s is %d" %
|
||||
(str(command), process.pid))
|
||||
|
||||
lines_iterator = iter(process.stdout.readline, b"")
|
||||
for line in lines_iterator:
|
||||
line_str = line.decode("utf-8")
|
||||
|
||||
# Check to see if the line has the correct number of separators
|
||||
try:
|
||||
if line_str.count(':') == 2:
|
||||
(device, ignore, percentage) = line_str.split(':')
|
||||
job_state.Percent = round(
|
||||
float(percentage.strip()[:-1]), 1)
|
||||
|
||||
# While the move is in progress we need to periodically update
|
||||
# the state to reflect where everything is at.
|
||||
cfg.load()
|
||||
except ValueError:
|
||||
log_error("Trying to parse percentage which failed for %s" %
|
||||
line_str)
|
||||
|
||||
out = process.communicate()
|
||||
ec, stdout, stderr = call_lvm(command, line_cb=_move_callback,
|
||||
cb_data=job_state)
|
||||
|
||||
with meta.lock:
|
||||
meta.ended = time.time()
|
||||
meta.ec = process.returncode
|
||||
meta.stderr_txt = out[1]
|
||||
meta.ec = ec
|
||||
meta.stderr_txt = stderr
|
||||
|
||||
if process.returncode == 0:
|
||||
if ec == 0:
|
||||
job_state.Percent = 100
|
||||
else:
|
||||
raise dbus.exceptions.DBusException(
|
||||
interface_name,
|
||||
'Exit code %s, stderr = %s' % (str(process.returncode), out[1]))
|
||||
'Exit code %s, stderr = %s' % (str(ec), stderr))
|
||||
|
||||
cfg.load()
|
||||
return '/'
|
||||
|
@@ -8,6 +8,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from subprocess import Popen, PIPE
|
||||
import select
|
||||
import time
|
||||
import threading
|
||||
from itertools import chain
|
||||
@@ -16,7 +17,8 @@ import traceback
|
||||
import os
|
||||
|
||||
from lvmdbusd import cfg
|
||||
from lvmdbusd.utils import pv_dest_ranges, log_debug, log_error, add_no_notify
|
||||
from lvmdbusd.utils import pv_dest_ranges, log_debug, log_error, add_no_notify,\
|
||||
make_non_block, read_decoded
|
||||
from lvmdbusd.lvm_shell_proxy import LVMShellProxy
|
||||
|
||||
try:
|
||||
@@ -82,16 +84,23 @@ def _debug_c(cmd, exit_code, out):
|
||||
log_error(("STDERR=\n %s\n" % out[1]))
|
||||
|
||||
|
||||
def call_lvm(command, debug=False):
|
||||
def call_lvm(command, debug=False, line_cb=None,
|
||||
cb_data=None):
|
||||
"""
|
||||
Call an executable and return a tuple of exitcode, stdout, stderr
|
||||
:param command: Command to execute
|
||||
:param debug: Dump debug to stdout
|
||||
"""
|
||||
# print 'STACK:'
|
||||
# for line in traceback.format_stack():
|
||||
# print line.strip()
|
||||
:param command: Command to execute
|
||||
:param debug: Dump debug to stdout
|
||||
:param line_cb: Call the supplied function for each line read from
|
||||
stdin, CALL MUST EXECUTE QUICKLY and not *block*
|
||||
otherwise call_lvm function will fail to read
|
||||
stdin/stdout. Return value of call back is ignored
|
||||
:param cb_data: Supplied to callback to allow caller access to
|
||||
its own data
|
||||
|
||||
# Callback signature
|
||||
def my_callback(my_context, line_read_stdin)
|
||||
pass
|
||||
"""
|
||||
# Prepend the full lvm executable so that we can run different versions
|
||||
# in different locations on the same box
|
||||
command.insert(0, cfg.LVM_CMD)
|
||||
@@ -99,10 +108,44 @@ def call_lvm(command, debug=False):
|
||||
|
||||
process = Popen(command, stdout=PIPE, stderr=PIPE, close_fds=True,
|
||||
env=os.environ)
|
||||
out = process.communicate()
|
||||
|
||||
stdout_text = bytes(out[0]).decode("utf-8")
|
||||
stderr_text = bytes(out[1]).decode("utf-8")
|
||||
stdout_text = ""
|
||||
stderr_text = ""
|
||||
stdout_index = 0
|
||||
make_non_block(process.stdout)
|
||||
make_non_block(process.stderr)
|
||||
|
||||
while True:
|
||||
try:
|
||||
rd_fd = [process.stdout.fileno(), process.stderr.fileno()]
|
||||
ready = select.select(rd_fd, [], [], 2)
|
||||
|
||||
for r in ready[0]:
|
||||
if r == process.stdout.fileno():
|
||||
stdout_text += read_decoded(process.stdout)
|
||||
elif r == process.stderr.fileno():
|
||||
stderr_text += read_decoded(process.stderr)
|
||||
|
||||
if line_cb is not None:
|
||||
# Process the callback for each line read!
|
||||
while True:
|
||||
i = stdout_text.find("\n", stdout_index)
|
||||
if i != -1:
|
||||
try:
|
||||
line_cb(cb_data, stdout_text[stdout_index:i])
|
||||
except:
|
||||
st = traceback.format_exc()
|
||||
log_error("call_lvm: line_cb exception: \n %s" % st)
|
||||
stdout_index = i + 1
|
||||
else:
|
||||
break
|
||||
|
||||
# Check to see if process has terminated, None when running
|
||||
if process.poll() is not None:
|
||||
break
|
||||
except IOError as ioe:
|
||||
log_debug("call_lvm:" + str(ioe))
|
||||
pass
|
||||
|
||||
if debug or process.returncode != 0:
|
||||
_debug_c(command, process.returncode, (stdout_text, stderr_text))
|
||||
@@ -584,7 +627,13 @@ def lvm_full_report_json():
|
||||
assert(type(out) == dict)
|
||||
return out
|
||||
else:
|
||||
return json.loads(out)
|
||||
try:
|
||||
return json.loads(out)
|
||||
except json.decoder.JSONDecodeError as joe:
|
||||
log_error("JSONDecodeError %s, \n JSON=\n%s\n" %
|
||||
(str(joe), out))
|
||||
raise joe
|
||||
|
||||
return None
|
||||
|
||||
|
||||
|
@@ -20,22 +20,30 @@ import traceback
|
||||
|
||||
def _main_thread_load(refresh=True, emit_signal=True):
|
||||
num_total_changes = 0
|
||||
to_remove = []
|
||||
|
||||
num_total_changes += load_pvs(
|
||||
(changes, remove) = load_pvs(
|
||||
refresh=refresh,
|
||||
emit_signal=emit_signal,
|
||||
cache_refresh=False)[1]
|
||||
num_total_changes += load_vgs(
|
||||
refresh=refresh,
|
||||
emit_signal=emit_signal,
|
||||
cache_refresh=False)[1]
|
||||
cache_refresh=False)[1:]
|
||||
num_total_changes += changes
|
||||
to_remove.extend(remove)
|
||||
|
||||
lv_changes = load_lvs(
|
||||
(changes, remove) = load_vgs(
|
||||
refresh=refresh,
|
||||
emit_signal=emit_signal,
|
||||
cache_refresh=False)[1]
|
||||
cache_refresh=False)[1:]
|
||||
|
||||
num_total_changes += changes
|
||||
to_remove.extend(remove)
|
||||
|
||||
(lv_changes, remove) = load_lvs(
|
||||
refresh=refresh,
|
||||
emit_signal=emit_signal,
|
||||
cache_refresh=False)[1:]
|
||||
|
||||
num_total_changes += lv_changes
|
||||
to_remove.extend(remove)
|
||||
|
||||
# When the LVs change it can cause another change in the VGs which is
|
||||
# missed if we don't scan through the VGs again. We could achieve this
|
||||
@@ -44,10 +52,23 @@ def _main_thread_load(refresh=True, emit_signal=True):
|
||||
# changes causing the dbus object representing it to be removed and
|
||||
# recreated.
|
||||
if refresh and lv_changes > 0:
|
||||
num_total_changes += load_vgs(
|
||||
(changes, remove) = load_vgs(
|
||||
refresh=refresh,
|
||||
emit_signal=emit_signal,
|
||||
cache_refresh=False)[1]
|
||||
cache_refresh=False)[1:]
|
||||
|
||||
num_total_changes += changes
|
||||
to_remove.extend(remove)
|
||||
|
||||
# Remove any objects that are no longer needed. We do this after we process
|
||||
# all the objects to ensure that references still exist for objects that
|
||||
# are processed after them.
|
||||
to_remove.reverse()
|
||||
for i in to_remove:
|
||||
dbus_obj = cfg.om.get_object_by_path(i)
|
||||
if dbus_obj:
|
||||
cfg.om.remove_object(dbus_obj, True)
|
||||
num_total_changes += 1
|
||||
|
||||
return num_total_changes
|
||||
|
||||
|
@@ -75,11 +75,10 @@ def common(retrieve, o_type, search_keys,
|
||||
|
||||
object_path = None
|
||||
|
||||
to_remove = []
|
||||
if refresh:
|
||||
for k in list(existing_paths.keys()):
|
||||
cfg.om.remove_object(cfg.om.get_object_by_path(k), True)
|
||||
num_changes += 1
|
||||
to_remove = list(existing_paths.keys())
|
||||
|
||||
num_changes += len(rc)
|
||||
|
||||
return rc, num_changes
|
||||
return rc, num_changes, to_remove
|
||||
|
@@ -13,7 +13,6 @@
|
||||
|
||||
import subprocess
|
||||
import shlex
|
||||
from fcntl import fcntl, F_GETFL, F_SETFL
|
||||
import os
|
||||
import traceback
|
||||
import sys
|
||||
@@ -29,7 +28,8 @@ except ImportError:
|
||||
|
||||
|
||||
from lvmdbusd.cfg import LVM_CMD
|
||||
from lvmdbusd.utils import log_debug, log_error, add_no_notify
|
||||
from lvmdbusd.utils import log_debug, log_error, add_no_notify, make_non_block,\
|
||||
read_decoded
|
||||
|
||||
SHELL_PROMPT = "lvm> "
|
||||
|
||||
@@ -43,13 +43,6 @@ def _quote_arg(arg):
|
||||
|
||||
class LVMShellProxy(object):
|
||||
|
||||
@staticmethod
|
||||
def _read(stream):
|
||||
tmp = stream.read()
|
||||
if tmp:
|
||||
return tmp.decode("utf-8")
|
||||
return ''
|
||||
|
||||
# Read until we get prompt back and a result
|
||||
# @param: no_output Caller expects no output to report FD
|
||||
# Returns stdout, report, stderr (report is JSON!)
|
||||
@@ -75,11 +68,11 @@ class LVMShellProxy(object):
|
||||
|
||||
for r in ready[0]:
|
||||
if r == self.lvm_shell.stdout.fileno():
|
||||
stdout += LVMShellProxy._read(self.lvm_shell.stdout)
|
||||
stdout += read_decoded(self.lvm_shell.stdout)
|
||||
elif r == self.report_stream.fileno():
|
||||
report += LVMShellProxy._read(self.report_stream)
|
||||
report += read_decoded(self.report_stream)
|
||||
elif r == self.lvm_shell.stderr.fileno():
|
||||
stderr += LVMShellProxy._read(self.lvm_shell.stderr)
|
||||
stderr += read_decoded(self.lvm_shell.stderr)
|
||||
|
||||
# Check to see if the lvm process died on us
|
||||
if self.lvm_shell.poll():
|
||||
@@ -124,11 +117,6 @@ class LVMShellProxy(object):
|
||||
assert (num_written == len(cmd_bytes))
|
||||
self.lvm_shell.stdin.flush()
|
||||
|
||||
@staticmethod
|
||||
def _make_non_block(stream):
|
||||
flags = fcntl(stream, F_GETFL)
|
||||
fcntl(stream, F_SETFL, flags | os.O_NONBLOCK)
|
||||
|
||||
def __init__(self):
|
||||
|
||||
# Create a temp directory
|
||||
@@ -162,8 +150,8 @@ class LVMShellProxy(object):
|
||||
stderr=subprocess.PIPE, close_fds=True, shell=True)
|
||||
|
||||
try:
|
||||
LVMShellProxy._make_non_block(self.lvm_shell.stdout)
|
||||
LVMShellProxy._make_non_block(self.lvm_shell.stderr)
|
||||
make_non_block(self.lvm_shell.stdout)
|
||||
make_non_block(self.lvm_shell.stderr)
|
||||
|
||||
# wait for the first prompt
|
||||
errors = self._read_until_prompt(no_output=True)[2]
|
||||
|
@@ -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
|
||||
|
@@ -14,6 +14,7 @@ import ctypes
|
||||
import os
|
||||
import string
|
||||
import datetime
|
||||
from fcntl import fcntl, F_GETFL, F_SETFL
|
||||
|
||||
import dbus
|
||||
from lvmdbusd import cfg
|
||||
@@ -681,3 +682,16 @@ def _remove_objects(dbus_objects_rm):
|
||||
# Remove dbus objects from main thread
|
||||
def mt_remove_dbus_objects(objs):
|
||||
MThreadRunner(_remove_objects, objs).done()
|
||||
|
||||
|
||||
# Make stream non-blocking
|
||||
def make_non_block(stream):
|
||||
flags = fcntl(stream, F_GETFL)
|
||||
fcntl(stream, F_SETFL, flags | os.O_NONBLOCK)
|
||||
|
||||
|
||||
def read_decoded(stream):
|
||||
tmp = stream.read()
|
||||
if tmp:
|
||||
return tmp.decode("utf-8")
|
||||
return ''
|
||||
|
44
dracut/64-lvm.rules
Normal file
44
dracut/64-lvm.rules
Normal 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
112
dracut/module-setup.sh
Executable 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
18
dracut/parse-lvm.sh
Executable 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
57
dracut/pvscan-udev-initrd.sh
Executable 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 \'
|
||||
|
@@ -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
|
||||
|
||||
@@ -558,12 +561,12 @@
|
||||
/* Define to 1 to include code that uses lvmlockd dlm option. */
|
||||
#undef LOCKDDLM_SUPPORT
|
||||
|
||||
/* Define to 1 to include code that uses lvmlockd sanlock option. */
|
||||
#undef LOCKDSANLOCK_SUPPORT
|
||||
|
||||
/* Define to 1 to include code that uses lvmlockd IDM option. */
|
||||
#undef LOCKDIDM_SUPPORT
|
||||
|
||||
/* Define to 1 to include code that uses lvmlockd sanlock option. */
|
||||
#undef LOCKDSANLOCK_SUPPORT
|
||||
|
||||
/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
|
||||
slash. */
|
||||
#undef LSTAT_FOLLOWS_SLASHED_SYMLINK
|
||||
@@ -687,6 +690,9 @@
|
||||
/* Enable a valgrind aware build of pool */
|
||||
#undef VALGRIND_POOL
|
||||
|
||||
/* Path to vdoimport binary. */
|
||||
#undef VDOIMPORT_PATH
|
||||
|
||||
/* The path to 'vdoformat', if available. */
|
||||
#undef VDO_FORMAT_CMD
|
||||
|
||||
|
@@ -34,6 +34,7 @@ SOURCES =\
|
||||
device/dev-ext.c \
|
||||
device/dev-io.c \
|
||||
device/dev-md.c \
|
||||
device/dev-mpath.c \
|
||||
device/dev-swap.c \
|
||||
device/dev-type.c \
|
||||
device/dev-luks.c \
|
||||
|
@@ -2740,7 +2740,10 @@ static int _component_cb(struct logical_volume *lv, void *data)
|
||||
(lv_is_thin_pool(lv) && pool_is_active(lv)))
|
||||
return -1;
|
||||
|
||||
if (lv_is_active(lv)) {
|
||||
/* External origin is activated through thinLV and uses -real suffix.
|
||||
* Note: for old clustered logic we would need to check for all thins */
|
||||
if ((lv_is_external_origin(lv) && lv_info(lv->vg->cmd, lv, 1, NULL, 0, 0)) ||
|
||||
lv_is_active(lv)) {
|
||||
if (!lv_is_component(lv) || lv_is_visible(lv))
|
||||
return -1; /* skip whole subtree */
|
||||
|
||||
|
130
lib/cache/lvmcache.c
vendored
130
lib/cache/lvmcache.c
vendored
@@ -88,9 +88,6 @@ static int _vgs_locked = 0;
|
||||
static int _found_duplicate_vgnames = 0;
|
||||
static int _outdated_warning = 0;
|
||||
|
||||
static const char *_scan_lock_global_file = DEFAULT_RUN_DIR "/scan_lock_global";
|
||||
static int _scan_lock_global_file_exists = 0;
|
||||
|
||||
int lvmcache_init(struct cmd_context *cmd)
|
||||
{
|
||||
/*
|
||||
@@ -695,7 +692,7 @@ next:
|
||||
*/
|
||||
|
||||
info = lvmcache_info_from_pvid(pvid, NULL, 0);
|
||||
if (info && dev_is_md_component(info->dev, NULL, 1)) {
|
||||
if (info && dev_is_md_component(cmd, info->dev, NULL, 1)) {
|
||||
/* does not go in del_cache_devs which become unused_duplicates */
|
||||
log_debug_cache("PV %s drop MD component from scan selection %s", pvid, dev_name(info->dev));
|
||||
lvmcache_del(info);
|
||||
@@ -703,7 +700,7 @@ next:
|
||||
}
|
||||
|
||||
dm_list_iterate_items_safe(devl, devl_safe, &altdevs) {
|
||||
if (dev_is_md_component(devl->dev, NULL, 1)) {
|
||||
if (dev_is_md_component(cmd, devl->dev, NULL, 1)) {
|
||||
log_debug_cache("PV %s drop MD component from scan duplicates %s", pvid, dev_name(devl->dev));
|
||||
dm_list_del(&devl->list);
|
||||
}
|
||||
@@ -802,8 +799,8 @@ next:
|
||||
same_id2 = !strcmp(idname2, device_id);
|
||||
}
|
||||
|
||||
has_lv1 = (dev1->flags & DEV_USED_FOR_LV) ? 1 : 0;
|
||||
has_lv2 = (dev2->flags & DEV_USED_FOR_LV) ? 1 : 0;
|
||||
has_lv1 = dev_is_used_by_active_lv(cmd, dev1, NULL, NULL, NULL, NULL);
|
||||
has_lv2 = dev_is_used_by_active_lv(cmd, dev2, NULL, NULL, NULL, NULL);
|
||||
|
||||
in_subsys1 = dev_subsystem_part_major(dt, dev1);
|
||||
in_subsys2 = dev_subsystem_part_major(dt, dev2);
|
||||
@@ -857,6 +854,11 @@ next:
|
||||
dev_name(dev1), has_lv1 ? "is used for" : "is not used for",
|
||||
dev_name(dev2), has_lv2 ? "is used for" : "is not used for");
|
||||
|
||||
free((void *)idname1);
|
||||
free((void *)idname2);
|
||||
idname1 = NULL;
|
||||
idname2 = NULL;
|
||||
|
||||
change = 0;
|
||||
|
||||
if (prev_unchosen1 && !prev_unchosen2) {
|
||||
@@ -1202,7 +1204,7 @@ void lvmcache_extra_md_component_checks(struct cmd_context *cmd)
|
||||
(unsigned long long)pvsize, (unsigned long long)devsize,
|
||||
device_hint ?: "none", dev_name(dev));
|
||||
|
||||
if (dev_is_md_component(dev, NULL, 1)) {
|
||||
if (dev_is_md_component(cmd, dev, NULL, 1)) {
|
||||
log_debug("dropping PV from md component %s", dev_name(dev));
|
||||
dev->flags &= ~DEV_SCAN_FOUND_LABEL;
|
||||
/* lvmcache_del will also delete vginfo if info was last one */
|
||||
@@ -2745,115 +2747,19 @@ bool lvmcache_scan_mismatch(struct cmd_context *cmd, const char *vgname, const c
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* max_size_bytes and max_size_percent may come from different areas and
|
||||
* different vgs because of different area sizes.
|
||||
*/
|
||||
static uint64_t _max_metadata_size_bytes;
|
||||
static dm_percent_t _max_metadata_size_percent = DM_PERCENT_INVALID;
|
||||
static uint64_t _max_metadata_size;
|
||||
|
||||
void lvmcache_save_metadata_size_bytes(uint64_t val)
|
||||
void lvmcache_save_metadata_size(uint64_t val)
|
||||
{
|
||||
if (!_max_metadata_size_bytes)
|
||||
_max_metadata_size_bytes = val;
|
||||
else if (_max_metadata_size_bytes < val)
|
||||
_max_metadata_size_bytes = val;
|
||||
if (!_max_metadata_size)
|
||||
_max_metadata_size = val;
|
||||
else if (_max_metadata_size < val)
|
||||
_max_metadata_size = val;
|
||||
}
|
||||
|
||||
uint64_t lvmcache_max_metadata_size_bytes(void)
|
||||
uint64_t lvmcache_max_metadata_size(void)
|
||||
{
|
||||
return _max_metadata_size_bytes;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: enable/disable scan_lock_global with config setting:
|
||||
* y: always use it
|
||||
* n: never use it
|
||||
* auto (default): use based on /run/lvm/scan_lock_global
|
||||
*/
|
||||
void lvmcache_save_metadata_size_percent(uint64_t meta_size, uint64_t mdah_size)
|
||||
{
|
||||
|
||||
dm_percent_t pc = dm_make_percent(meta_size, mdah_size);
|
||||
|
||||
if (pc == DM_PERCENT_INVALID || pc == DM_PERCENT_FAILED ||
|
||||
pc == DM_PERCENT_0 || pc == DM_PERCENT_1)
|
||||
return;
|
||||
|
||||
if (_max_metadata_size_percent == DM_PERCENT_INVALID) {
|
||||
_max_metadata_size_percent = pc;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_max_metadata_size_percent < pc)
|
||||
_max_metadata_size_percent = pc;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: make the percent at which scan_lock_global is used
|
||||
* configurable?
|
||||
*/
|
||||
#define SCAN_LOCK_GLOBAL_METADATA_PERCENT (DM_PERCENT_1 * 25)
|
||||
|
||||
void set_scan_lock_global(struct cmd_context *cmd)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
if (_max_metadata_size_percent == DM_PERCENT_INVALID)
|
||||
return;
|
||||
|
||||
if (_max_metadata_size_percent >= SCAN_LOCK_GLOBAL_METADATA_PERCENT) {
|
||||
if (_scan_lock_global_file_exists)
|
||||
return;
|
||||
log_debug("Creating %s.", _scan_lock_global_file);
|
||||
if (!(fp = fopen(_scan_lock_global_file, "w")))
|
||||
return;
|
||||
if (fclose(fp))
|
||||
stack;
|
||||
} else {
|
||||
if (_scan_lock_global_file_exists) {
|
||||
log_debug("Unlinking %s.", _scan_lock_global_file);
|
||||
if (unlink(_scan_lock_global_file))
|
||||
stack;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int do_scan_lock_global(struct cmd_context *cmd, int *gl_ex)
|
||||
{
|
||||
struct stat buf;
|
||||
|
||||
if (cmd->nolocking)
|
||||
return 0;
|
||||
|
||||
/* global lock is already held */
|
||||
if (cmd->lockf_global_ex)
|
||||
return 0;
|
||||
|
||||
if (!stat(_scan_lock_global_file, &buf)) {
|
||||
_scan_lock_global_file_exists = 1;
|
||||
|
||||
/*
|
||||
* Tell the caller to use sh or ex. A command that may write
|
||||
* vg metadata should use ex, otherwise sh.
|
||||
*
|
||||
* lockd_vg_default_sh/LOCKD_VG_SH is set for commands that
|
||||
* do not modify vg metadata.
|
||||
*
|
||||
* FIXME: this variable/flag was previously used only for
|
||||
* lvmlockd locking logic, but is now more general, so
|
||||
* it should be renamed.
|
||||
*/
|
||||
if (cmd->lockd_vg_default_sh)
|
||||
*gl_ex = 0;
|
||||
else
|
||||
*gl_ex = 1;
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
return _max_metadata_size;
|
||||
}
|
||||
|
||||
int lvmcache_vginfo_has_pvid(struct lvmcache_vginfo *vginfo, char *pvid)
|
||||
|
9
lib/cache/lvmcache.h
vendored
9
lib/cache/lvmcache.h
vendored
@@ -183,9 +183,8 @@ bool lvmcache_scan_mismatch(struct cmd_context *cmd, const char *vgname, const c
|
||||
|
||||
int lvmcache_vginfo_has_pvid(struct lvmcache_vginfo *vginfo, char *pvid);
|
||||
|
||||
uint64_t lvmcache_max_metadata_size_bytes(void);
|
||||
void lvmcache_save_metadata_size_bytes(uint64_t val);
|
||||
void lvmcache_save_metadata_size_percent(uint64_t meta_size, uint64_t mdah_size);
|
||||
uint64_t lvmcache_max_metadata_size(void);
|
||||
void lvmcache_save_metadata_size(uint64_t val);
|
||||
|
||||
int dev_in_device_list(struct device *dev, struct dm_list *head);
|
||||
|
||||
@@ -227,8 +226,4 @@ void lvmcache_extra_md_component_checks(struct cmd_context *cmd);
|
||||
|
||||
unsigned int lvmcache_vg_info_count(void);
|
||||
|
||||
void set_scan_lock_global(struct cmd_context *cmd);
|
||||
int do_scan_lock_global(struct cmd_context *cmd, int *gl_ex);
|
||||
|
||||
|
||||
#endif
|
||||
|
@@ -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';
|
||||
@@ -402,15 +452,12 @@ static void _init_logging(struct cmd_context *cmd)
|
||||
reset_lvm_errno(1);
|
||||
}
|
||||
|
||||
static int _check_disable_udev(const char *msg) {
|
||||
static int _check_disable_udev(const char *msg)
|
||||
{
|
||||
if (getenv("DM_DISABLE_UDEV")) {
|
||||
log_very_verbose("DM_DISABLE_UDEV environment variable set. "
|
||||
"Overriding configuration to use "
|
||||
"udev_rules=0, udev_sync=0, verify_udev_operations=1.");
|
||||
if (udev_is_running())
|
||||
log_warn("Udev is running and DM_DISABLE_UDEV environment variable is set. "
|
||||
"Bypassing udev, LVM will %s.", msg);
|
||||
|
||||
log_very_verbose("DM_DISABLE_UDEV environment variable set.");
|
||||
log_very_verbose("Overriding configuration to use udev_rules=0, udev_sync=0, verify_udev_operations=1.");
|
||||
log_very_verbose("LVM will %s.", msg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -563,7 +610,7 @@ static int _init_system_id(struct cmd_context *cmd)
|
||||
static int _process_config(struct cmd_context *cmd)
|
||||
{
|
||||
mode_t old_umask;
|
||||
const char *dev_ext_info_src;
|
||||
const char *dev_ext_info_src = NULL;
|
||||
const char *read_ahead;
|
||||
struct stat st;
|
||||
const struct dm_config_node *cn;
|
||||
@@ -597,15 +644,26 @@ static int _process_config(struct cmd_context *cmd)
|
||||
#endif
|
||||
|
||||
dev_ext_info_src = find_config_tree_str(cmd, devices_external_device_info_source_CFG, NULL);
|
||||
if (dev_ext_info_src && !strcmp(dev_ext_info_src, "none"))
|
||||
init_external_device_info_source(DEV_EXT_NONE);
|
||||
else if (dev_ext_info_src && !strcmp(dev_ext_info_src, "udev"))
|
||||
init_external_device_info_source(DEV_EXT_UDEV);
|
||||
else {
|
||||
log_error("Invalid external device info source specification.");
|
||||
return 0;
|
||||
|
||||
if (dev_ext_info_src &&
|
||||
strcmp(dev_ext_info_src, "none") &&
|
||||
strcmp(dev_ext_info_src, "udev")) {
|
||||
log_warn("WARNING: unknown external device info source, using none.");
|
||||
dev_ext_info_src = NULL;
|
||||
}
|
||||
|
||||
if (dev_ext_info_src && !strcmp(dev_ext_info_src, "udev")) {
|
||||
if (udev_init_library_context()) {
|
||||
init_external_device_info_source(DEV_EXT_UDEV);
|
||||
} else {
|
||||
log_warn("WARNING: failed to init udev for external device info, using none.");
|
||||
dev_ext_info_src = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dev_ext_info_src || !strcmp(dev_ext_info_src, "none"))
|
||||
init_external_device_info_source(DEV_EXT_NONE);
|
||||
|
||||
/* proc dir */
|
||||
if (dm_snprintf(cmd->proc_dir, sizeof(cmd->proc_dir), "%s",
|
||||
find_config_tree_str(cmd, global_proc_CFG, NULL)) < 0) {
|
||||
@@ -966,8 +1024,13 @@ static void _destroy_config(struct cmd_context *cmd)
|
||||
/* CONFIG_FILE/CONFIG_MERGED_FILES */
|
||||
if ((cft = remove_config_tree_by_source(cmd, CONFIG_MERGED_FILES)))
|
||||
config_destroy(cft);
|
||||
else if ((cft = remove_config_tree_by_source(cmd, CONFIG_FILE)))
|
||||
else if ((cft = remove_config_tree_by_source(cmd, CONFIG_FILE))) {
|
||||
dm_list_iterate_items(cfl, &cmd->config_files) {
|
||||
if (cfl->cft == cft)
|
||||
dm_list_del(&cfl->list);
|
||||
}
|
||||
config_destroy(cft);
|
||||
}
|
||||
|
||||
dm_list_iterate_items(cfl, &cmd->config_files)
|
||||
config_destroy(cfl->cft);
|
||||
@@ -1013,16 +1076,10 @@ static int _init_dev_cache(struct cmd_context *cmd)
|
||||
if (!dev_cache_init(cmd))
|
||||
return_0;
|
||||
|
||||
/*
|
||||
* Override existing config and hardcode device_list_from_udev = 0 if:
|
||||
* - udev is not running
|
||||
* - udev is disabled using DM_DISABLE_UDEV environment variable
|
||||
*/
|
||||
if (_check_disable_udev("obtain device list by scanning device directory"))
|
||||
device_list_from_udev = 0;
|
||||
else
|
||||
device_list_from_udev = udev_is_running() ?
|
||||
find_config_tree_bool(cmd, devices_obtain_device_list_from_udev_CFG, NULL) : 0;
|
||||
if ((device_list_from_udev = find_config_tree_bool(cmd, devices_obtain_device_list_from_udev_CFG, NULL))) {
|
||||
if (!udev_init_library_context())
|
||||
device_list_from_udev = 0;
|
||||
}
|
||||
|
||||
init_obtain_device_list_from_udev(device_list_from_udev);
|
||||
|
||||
@@ -1177,7 +1234,7 @@ static struct dev_filter *_init_filter_chain(struct cmd_context *cmd)
|
||||
nr_filt++;
|
||||
}
|
||||
|
||||
if (!(composite = composite_filter_create(nr_filt, 1, filters)))
|
||||
if (!(composite = composite_filter_create(nr_filt, filters)))
|
||||
goto_bad;
|
||||
|
||||
return composite;
|
||||
@@ -1608,6 +1665,7 @@ struct cmd_context *create_toolcontext(unsigned is_clvmd,
|
||||
cmd->handles_missing_pvs = 0;
|
||||
cmd->handles_unknown_segments = 0;
|
||||
cmd->hosttags = 0;
|
||||
cmd->check_devs_used = 1;
|
||||
dm_list_init(&cmd->arg_value_groups);
|
||||
dm_list_init(&cmd->formats);
|
||||
dm_list_init(&cmd->segtypes);
|
||||
|
@@ -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 */
|
||||
@@ -192,6 +195,7 @@ struct cmd_context {
|
||||
unsigned filter_nodata_only:1; /* only use filters that do not require data from the dev */
|
||||
unsigned run_by_dmeventd:1; /* command is being run by dmeventd */
|
||||
unsigned sysinit:1; /* --sysinit is used */
|
||||
unsigned check_devs_used:1; /* check devs used by LVs */
|
||||
|
||||
/*
|
||||
* Devices and filtering.
|
||||
@@ -256,7 +260,6 @@ struct cmd_context {
|
||||
unsigned rand_seed;
|
||||
struct dm_list pending_delete; /* list of LVs for removal */
|
||||
struct dm_pool *pending_delete_mem; /* memory pool for pending deletes */
|
||||
int early_lock_vg_mode;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@@ -501,6 +501,9 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_r
|
||||
checksum_fn_t checksum_fn, uint32_t checksum,
|
||||
int checksum_only, int no_dup_node_check)
|
||||
{
|
||||
char namebuf[NAME_LEN + 1] __attribute__((aligned(8)));
|
||||
int namelen = 0;
|
||||
int bad_name = 0;
|
||||
char *fb, *fe;
|
||||
int r = 0;
|
||||
int sz, use_plain_read = 1;
|
||||
@@ -548,6 +551,23 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_r
|
||||
|
||||
fb = buf;
|
||||
|
||||
if (!(dev->flags & DEV_REGULAR)) {
|
||||
memcpy(namebuf, buf, NAME_LEN);
|
||||
|
||||
while (namebuf[namelen] && !isspace(namebuf[namelen]) && namebuf[namelen] != '{' && namelen < (NAME_LEN - 1))
|
||||
namelen++;
|
||||
namebuf[namelen] = '\0';
|
||||
|
||||
/*
|
||||
* Check that the text metadata begins with a valid name.
|
||||
*/
|
||||
if (!validate_name(namebuf)) {
|
||||
log_warn("WARNING: Metadata location on %s at offset %llu begins with invalid name.",
|
||||
dev_name(dev), (unsigned long long)offset);
|
||||
bad_name = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The checksum passed in is the checksum from the mda_header
|
||||
* preceding this metadata. They should always match.
|
||||
@@ -557,10 +577,13 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_r
|
||||
if (checksum_fn && checksum !=
|
||||
(checksum_fn(checksum_fn(INITIAL_CRC, (const uint8_t *)fb, size),
|
||||
(const uint8_t *)(fb + size), size2))) {
|
||||
log_error("%s: Checksum error at offset %" PRIu64, dev_name(dev), (uint64_t) offset);
|
||||
log_warn("WARNING: Checksum error on %s at offset %llu.", dev_name(dev), (unsigned long long)offset);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (bad_name)
|
||||
goto out;
|
||||
|
||||
if (!checksum_only) {
|
||||
fe = fb + size + size2;
|
||||
if (no_dup_node_check) {
|
||||
|
@@ -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,23 +237,11 @@ 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,
|
||||
"Select an external device information source.\n"
|
||||
"Some information may already be available in the system and LVM can\n"
|
||||
"use this information to determine the exact type or use of devices it\n"
|
||||
"processes. Using an existing external device information source can\n"
|
||||
"speed up device processing as LVM does not need to run its own native\n"
|
||||
"routines to acquire this information. For example, this information\n"
|
||||
"is used to drive LVM filtering like MD component detection, multipath\n"
|
||||
"component detection, partition detection and others.\n"
|
||||
"#\n"
|
||||
"Accepted values:\n"
|
||||
" none\n"
|
||||
" No external device information source is used.\n"
|
||||
" udev\n"
|
||||
" Reuse existing udev database records. Applicable only if LVM is\n"
|
||||
" compiled with udev support.\n"
|
||||
"#\n")
|
||||
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"
|
||||
"of MD component devices and multipath component devices.\n")
|
||||
|
||||
cfg(devices_hints_CFG, "hints", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_HINTS, vsn(2, 3, 2), NULL, 0, NULL,
|
||||
"Use a local file to remember which devices have PVs on them.\n"
|
||||
@@ -372,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"
|
||||
@@ -390,10 +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_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_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, 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"
|
||||
@@ -419,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"
|
||||
@@ -438,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"
|
||||
@@ -452,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"
|
||||
@@ -469,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"
|
||||
@@ -492,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"
|
||||
@@ -516,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"
|
||||
@@ -528,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")
|
||||
@@ -551,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"
|
||||
@@ -567,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"
|
||||
@@ -583,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")
|
||||
|
||||
@@ -807,7 +799,7 @@ cfg(allocation_vdo_write_policy_CFG, "vdo_write_policy", allocation_CFG_SECTION,
|
||||
" Data which has not been flushed is not guaranteed to persist in this mode.\n")
|
||||
|
||||
cfg(allocation_vdo_max_discard_CFG, "vdo_max_discard", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_MAX_DISCARD, VDO_1ST_VSN, NULL, 0, NULL,
|
||||
"Specified te maximum size of discard bio accepted, in 4096 byte blocks.\n"
|
||||
"Specified the maximum size of discard bio accepted, in 4096 byte blocks.\n"
|
||||
"I/O requests to a VDO volume are normally split into 4096-byte blocks,\n"
|
||||
"and processed up to 2048 at a time. However, discard requests to a VDO volume\n"
|
||||
"can be automatically split to a larger size, up to <max discard> 4096-byte blocks\n"
|
||||
@@ -816,6 +808,9 @@ cfg(allocation_vdo_max_discard_CFG, "vdo_max_discard", allocation_CFG_SECTION, C
|
||||
"increased latency for the individual discard requests.\n"
|
||||
"The default and minimum is 1. The maximum is UINT_MAX / 4096.\n")
|
||||
|
||||
cfg(allocation_vdo_pool_header_size_CFG, "vdo_pool_header_size", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_POOL_HEADER_SIZE_KB, vsn(2, 3, 12), NULL, 0, NULL,
|
||||
"Specified the emptry header size in KiB at the front and end of vdo pool device.\n")
|
||||
|
||||
cfg(log_report_command_log_CFG, "report_command_log", log_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED | CFG_DISALLOW_INTERACTIVE, CFG_TYPE_BOOL, DEFAULT_COMMAND_LOG_REPORT, vsn(2, 2, 158), NULL, 0, NULL,
|
||||
"Enable or disable LVM log reporting.\n"
|
||||
"If enabled, LVM will collect a log of operations, messages,\n"
|
||||
@@ -857,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"
|
||||
@@ -870,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")
|
||||
@@ -887,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"
|
||||
@@ -918,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"
|
||||
@@ -984,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"
|
||||
@@ -1021,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"
|
||||
@@ -1071,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"
|
||||
@@ -1089,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"
|
||||
@@ -1127,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,
|
||||
@@ -1136,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"
|
||||
@@ -1262,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"
|
||||
@@ -1278,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"
|
||||
@@ -1292,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"
|
||||
@@ -1311,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")
|
||||
@@ -1324,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"
|
||||
@@ -1334,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"
|
||||
@@ -1346,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"
|
||||
@@ -1465,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"
|
||||
@@ -1494,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"
|
||||
@@ -1515,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"
|
||||
@@ -1551,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"
|
||||
@@ -1574,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"
|
||||
@@ -1586,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"
|
||||
@@ -1600,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"
|
||||
@@ -1657,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")
|
||||
@@ -1679,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"
|
||||
@@ -2202,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)
|
||||
|
@@ -42,7 +42,7 @@
|
||||
#define DEFAULT_DEV_DIR "/dev"
|
||||
#define DEFAULT_PROC_DIR "/proc"
|
||||
#define DEFAULT_SYSTEM_ID_SOURCE "none"
|
||||
#define DEFAULT_OBTAIN_DEVICE_LIST_FROM_UDEV 1
|
||||
#define DEFAULT_OBTAIN_DEVICE_LIST_FROM_UDEV 0
|
||||
#define DEFAULT_EXTERNAL_DEVICE_INFO_SOURCE "none"
|
||||
#define DEFAULT_SYSFS_SCAN 1
|
||||
#define DEFAULT_MD_COMPONENT_DETECTION 1
|
||||
@@ -181,8 +181,7 @@
|
||||
* VDO pool will reverve some sectors in the front and the back of pool device to avoid
|
||||
* seeing same device twice in the system.
|
||||
*/
|
||||
#define DEFAULT_VDO_POOL_HEADER_SIZE (1024) // 512KiB
|
||||
|
||||
#define DEFAULT_VDO_POOL_HEADER_SIZE_KB (512)
|
||||
|
||||
|
||||
#define DEFAULT_FSADM_PATH FSADM_PATH
|
||||
@@ -323,9 +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 */
|
||||
|
@@ -412,7 +412,7 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _get_dm_uuid_from_sysfs(char *buf, size_t buf_size, int major, int minor)
|
||||
int get_dm_uuid_from_sysfs(char *buf, size_t buf_size, int major, int minor)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
|
||||
@@ -533,7 +533,7 @@ static int _get_vgid_and_lvid_for_dev(struct device *dev)
|
||||
char uuid[DM_UUID_LEN];
|
||||
size_t uuid_len;
|
||||
|
||||
if (!_get_dm_uuid_from_sysfs(uuid, sizeof(uuid), (int) MAJOR(dev->dev), (int) MINOR(dev->dev)))
|
||||
if (!get_dm_uuid_from_sysfs(uuid, sizeof(uuid), (int) MAJOR(dev->dev), (int) MINOR(dev->dev)))
|
||||
return_0;
|
||||
|
||||
uuid_len = strlen(uuid);
|
||||
@@ -1139,7 +1139,7 @@ static int _insert(const char *path, const struct stat *info,
|
||||
return 1;
|
||||
}
|
||||
|
||||
void dev_cache_scan(void)
|
||||
void dev_cache_scan(struct cmd_context *cmd)
|
||||
{
|
||||
log_debug_devs("Creating list of system devices.");
|
||||
|
||||
@@ -1147,7 +1147,8 @@ void dev_cache_scan(void)
|
||||
|
||||
_insert_dirs(&_cache.dirs);
|
||||
|
||||
(void) dev_cache_index_devs();
|
||||
if (cmd->check_devs_used)
|
||||
(void) dev_cache_index_devs();
|
||||
}
|
||||
|
||||
int dev_cache_has_scanned(void)
|
||||
@@ -1583,7 +1584,7 @@ struct device *dev_cache_get_by_devt(struct cmd_context *cmd, dev_t dev, struct
|
||||
|
||||
log_debug_devs("Device num not found in dev_cache repeat dev_cache_scan for %d:%d",
|
||||
(int)MAJOR(dev), (int)MINOR(dev));
|
||||
dev_cache_scan();
|
||||
dev_cache_scan(cmd);
|
||||
d = (struct device *) btree_lookup(_cache.devices, (uint32_t) dev);
|
||||
|
||||
if (!d)
|
||||
@@ -1953,7 +1954,7 @@ int setup_devices(struct cmd_context *cmd)
|
||||
* This will not open or read any devices, but may look at sysfs properties.
|
||||
* This list of devs comes from looking /dev entries, or from asking libudev.
|
||||
*/
|
||||
dev_cache_scan();
|
||||
dev_cache_scan(cmd);
|
||||
|
||||
/*
|
||||
* Match entries from cmd->use_devices with device structs in dev-cache.
|
||||
|
@@ -48,7 +48,7 @@ int dev_cache_exit(void);
|
||||
*/
|
||||
int dev_cache_check_for_open_devices(void);
|
||||
|
||||
void dev_cache_scan(void);
|
||||
void dev_cache_scan(struct cmd_context *cmd);
|
||||
int dev_cache_has_scanned(void);
|
||||
|
||||
int dev_cache_add_dir(const char *path);
|
||||
@@ -68,13 +68,12 @@ struct dev_iter *dev_iter_create(struct dev_filter *f, int unused);
|
||||
void dev_iter_destroy(struct dev_iter *iter);
|
||||
struct device *dev_iter_get(struct cmd_context *cmd, struct dev_iter *iter);
|
||||
|
||||
void dev_reset_error_count(struct cmd_context *cmd);
|
||||
|
||||
void dev_cache_failed_path(struct device *dev, const char *path);
|
||||
|
||||
bool dev_cache_has_md_with_end_superblock(struct dev_types *dt);
|
||||
|
||||
int get_sysfs_value(const char *path, char *buf, size_t buf_size, int error_if_no_value);
|
||||
int get_dm_uuid_from_sysfs(char *buf, size_t buf_size, int major, int minor);
|
||||
|
||||
int setup_devices_file(struct cmd_context *cmd);
|
||||
int setup_devices(struct cmd_context *cmd);
|
||||
|
@@ -18,7 +18,7 @@
|
||||
#define LUKS_SIGNATURE "LUKS\xba\xbe"
|
||||
#define LUKS_SIGNATURE_SIZE 6
|
||||
|
||||
int dev_is_luks(struct device *dev, uint64_t *offset_found, int full)
|
||||
int dev_is_luks(struct cmd_context *cmd, struct device *dev, uint64_t *offset_found, int full)
|
||||
{
|
||||
char buf[LUKS_SIGNATURE_SIZE];
|
||||
int ret = -1;
|
||||
|
@@ -17,6 +17,7 @@
|
||||
#include "lib/device/dev-type.h"
|
||||
#include "lib/mm/xlate.h"
|
||||
#include "lib/misc/crc.h"
|
||||
#include "lib/commands/toolcontext.h"
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
#include <libudev.h> /* for MD detection using udev db records */
|
||||
#include "lib/device/dev-ext-udev-constants.h"
|
||||
@@ -144,25 +145,16 @@ static int _dev_has_ddf_magic(struct device *dev, uint64_t devsize_sectors, uint
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* _udev_dev_is_md_component() only works if
|
||||
* external_device_info_source="udev"
|
||||
*
|
||||
* but
|
||||
*
|
||||
* udev_dev_is_md_component() in dev-type.c only works if
|
||||
* obtain_device_list_from_udev=1
|
||||
*
|
||||
* and neither of those config setting matches very well
|
||||
* with what we're doing here.
|
||||
*/
|
||||
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
static int _udev_dev_is_md_component(struct device *dev)
|
||||
static int _dev_is_md_component_udev(struct device *dev)
|
||||
{
|
||||
const char *value;
|
||||
struct dev_ext *ext;
|
||||
|
||||
/*
|
||||
* external_device_info_source="udev" enables these udev checks.
|
||||
* external_device_info_source="none" disables them.
|
||||
*/
|
||||
if (!(ext = dev_ext_get(dev)))
|
||||
return_0;
|
||||
|
||||
@@ -172,7 +164,7 @@ static int _udev_dev_is_md_component(struct device *dev)
|
||||
return !strcmp(value, DEV_EXT_UDEV_BLKID_TYPE_SW_RAID);
|
||||
}
|
||||
#else
|
||||
static int _udev_dev_is_md_component(struct device *dev)
|
||||
static int _dev_is_md_component_udev(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -181,13 +173,16 @@ static int _udev_dev_is_md_component(struct device *dev)
|
||||
/*
|
||||
* Returns -1 on error
|
||||
*/
|
||||
static int _native_dev_is_md_component(struct device *dev, uint64_t *offset_found, int full)
|
||||
static int _dev_is_md_component_native(struct device *dev, uint64_t *offset_found, int full)
|
||||
{
|
||||
uint64_t size, sb_offset = 0;
|
||||
int ret;
|
||||
|
||||
if (!scan_bcache)
|
||||
return -EAGAIN;
|
||||
/* i/o layer has not been set up */
|
||||
if (!scan_bcache) {
|
||||
log_error(INTERNAL_ERROR "dev_is_md_component_native requires io layer.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!dev_get_size(dev, &size)) {
|
||||
stack;
|
||||
@@ -295,41 +290,20 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dev_is_md_component(struct device *dev, uint64_t *offset_found, int full)
|
||||
int dev_is_md_component(struct cmd_context *cmd, struct device *dev, uint64_t *offset_found, int full)
|
||||
{
|
||||
int ret;
|
||||
if (_dev_is_md_component_native(dev, offset_found, full) == 1)
|
||||
goto found;
|
||||
|
||||
/*
|
||||
* If non-native device status source is selected, use it
|
||||
* only if offset_found is not requested as this
|
||||
* information is not in udev db.
|
||||
*/
|
||||
if ((dev->ext.src == DEV_EXT_NONE) || offset_found) {
|
||||
ret = _native_dev_is_md_component(dev, offset_found, full);
|
||||
|
||||
if (!full) {
|
||||
if (!ret || (ret == -EAGAIN)) {
|
||||
if (udev_dev_is_md_component(dev))
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
if (ret && (ret != -EAGAIN))
|
||||
dev->flags |= DEV_IS_MD_COMPONENT;
|
||||
return ret;
|
||||
if (external_device_info_source() == DEV_EXT_UDEV) {
|
||||
if (_dev_is_md_component_udev(dev) == 1)
|
||||
goto found;
|
||||
}
|
||||
return 0;
|
||||
|
||||
if (dev->ext.src == DEV_EXT_UDEV) {
|
||||
ret = _udev_dev_is_md_component(dev);
|
||||
if (ret && (ret != -EAGAIN))
|
||||
dev->flags |= DEV_IS_MD_COMPONENT;
|
||||
return ret;
|
||||
}
|
||||
|
||||
log_error(INTERNAL_ERROR "Missing hook for MD device recognition "
|
||||
"using external device info source %s", dev_ext_name(dev));
|
||||
|
||||
return -1;
|
||||
|
||||
found:
|
||||
dev->flags |= DEV_IS_MD_COMPONENT;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _md_sysfs_attribute_snprintf(char *path, size_t size,
|
||||
@@ -552,7 +526,8 @@ int dev_is_md_with_end_superblock(struct dev_types *dt, struct device *dev)
|
||||
|
||||
#else
|
||||
|
||||
int dev_is_md_component(struct device *dev __attribute__((unused)),
|
||||
int dev_is_md_component(struct cmd_context *cmd __attribute__((unused)),
|
||||
struct device *dev __attribute__((unused)),
|
||||
uint64_t *sb __attribute__((unused)))
|
||||
{
|
||||
return 0;
|
||||
|
483
lib/device/dev-mpath.c
Normal file
483
lib/device/dev-mpath.c
Normal file
@@ -0,0 +1,483 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "base/memory/zalloc.h"
|
||||
#include "lib/misc/lib.h"
|
||||
#include "lib/activate/activate.h"
|
||||
#include "lib/commands/toolcontext.h"
|
||||
#include "lib/device/device_id.h"
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
#include <libudev.h>
|
||||
#include "lib/device/dev-ext-udev-constants.h"
|
||||
#endif
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
#define MPATH_PREFIX "mpath-"
|
||||
|
||||
/*
|
||||
* This hash table keeps track of whether a given dm device
|
||||
* is a mpath device or not.
|
||||
*
|
||||
* If dm-3 is an mpath device, then the constant "2" is stored in
|
||||
* the hash table with the key of the dm minor number ("3" for dm-3).
|
||||
* If dm-3 is not an mpath device, then the constant "1" is stored in
|
||||
* the hash table with the key of the dm minor number.
|
||||
*/
|
||||
static struct dm_pool *_hash_mem;
|
||||
static struct dm_hash_table *_minor_hash_tab;
|
||||
static struct dm_hash_table *_wwid_hash_tab;
|
||||
|
||||
#define MAX_WWID_LINE 512
|
||||
|
||||
/*
|
||||
* do we need to check the multipath.conf blacklist?
|
||||
*/
|
||||
|
||||
static void _read_wwid_file(const char *config_wwids_file)
|
||||
{
|
||||
FILE *fp;
|
||||
char line[MAX_WWID_LINE];
|
||||
char *wwid, *p;
|
||||
int count = 0;
|
||||
|
||||
if (config_wwids_file[0] != '/') {
|
||||
log_print("Ignoring unknown multipath_wwids_file.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(fp = fopen(config_wwids_file, "r"))) {
|
||||
log_debug("multipath wwids file not found");
|
||||
return;
|
||||
}
|
||||
|
||||
while (fgets(line, sizeof(line), fp)) {
|
||||
if (line[0] == '#')
|
||||
continue;
|
||||
|
||||
wwid = line;
|
||||
|
||||
if (line[0] == '/')
|
||||
wwid++;
|
||||
|
||||
/* skip the initial '3' */
|
||||
wwid++;
|
||||
|
||||
if ((p = strchr(wwid, '/')))
|
||||
*p = '\0';
|
||||
|
||||
(void) dm_hash_insert_binary(_wwid_hash_tab, wwid, strlen(wwid), (void*)1);
|
||||
count++;
|
||||
}
|
||||
|
||||
if (fclose(fp))
|
||||
stack;
|
||||
|
||||
log_debug("multipath wwids read %d from %s", count, config_wwids_file);
|
||||
}
|
||||
|
||||
int dev_mpath_init(const char *config_wwids_file)
|
||||
{
|
||||
struct dm_pool *mem;
|
||||
struct dm_hash_table *minor_tab;
|
||||
struct dm_hash_table *wwid_tab;
|
||||
|
||||
if (!(mem = dm_pool_create("mpath", 256))) {
|
||||
log_error("mpath pool creation failed.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(minor_tab = dm_hash_create(110))) {
|
||||
log_error("mpath hash table creation failed.");
|
||||
dm_pool_destroy(mem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_hash_mem = mem;
|
||||
_minor_hash_tab = minor_tab;
|
||||
|
||||
/* multipath_wwids_file="" disables the use of the file */
|
||||
if (config_wwids_file && !strlen(config_wwids_file)) {
|
||||
log_debug("multipath wwids file disabled.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(wwid_tab = dm_hash_create(110))) {
|
||||
log_error("mpath hash table creation failed.");
|
||||
dm_hash_destroy(_minor_hash_tab);
|
||||
dm_pool_destroy(_hash_mem);
|
||||
_minor_hash_tab = NULL;
|
||||
_hash_mem = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_wwid_hash_tab = wwid_tab;
|
||||
|
||||
_read_wwid_file(config_wwids_file);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void dev_mpath_exit(void)
|
||||
{
|
||||
if (_minor_hash_tab)
|
||||
dm_hash_destroy(_minor_hash_tab);
|
||||
if (_wwid_hash_tab)
|
||||
dm_hash_destroy(_wwid_hash_tab);
|
||||
if (_hash_mem)
|
||||
dm_pool_destroy(_hash_mem);
|
||||
|
||||
_minor_hash_tab = NULL;
|
||||
_wwid_hash_tab = NULL;
|
||||
_hash_mem = NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* given "/dev/foo" return "foo"
|
||||
*/
|
||||
static const char *_get_sysfs_name(struct device *dev)
|
||||
{
|
||||
const char *name;
|
||||
|
||||
if (!(name = strrchr(dev_name(dev), '/'))) {
|
||||
log_error("Cannot find '/' in device name.");
|
||||
return NULL;
|
||||
}
|
||||
name++;
|
||||
|
||||
if (!*name) {
|
||||
log_error("Device name is not valid.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/*
|
||||
* given major:minor
|
||||
* readlink translates /sys/dev/block/major:minor to /sys/.../foo
|
||||
* from /sys/.../foo return "foo"
|
||||
*/
|
||||
static const char *_get_sysfs_name_by_devt(const char *sysfs_dir, dev_t devno,
|
||||
char *buf, size_t buf_size)
|
||||
{
|
||||
const char *name;
|
||||
char path[PATH_MAX];
|
||||
int size;
|
||||
|
||||
if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d", sysfs_dir,
|
||||
(int) MAJOR(devno), (int) MINOR(devno)) < 0) {
|
||||
log_error("Sysfs path string is too long.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((size = readlink(path, buf, buf_size - 1)) < 0) {
|
||||
log_sys_error("readlink", path);
|
||||
return NULL;
|
||||
}
|
||||
buf[size] = '\0';
|
||||
|
||||
if (!(name = strrchr(buf, '/'))) {
|
||||
log_error("Cannot find device name in sysfs path.");
|
||||
return NULL;
|
||||
}
|
||||
name++;
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
static int _get_sysfs_string(const char *path, char *buffer, int max_size)
|
||||
{
|
||||
FILE *fp;
|
||||
int r = 0;
|
||||
|
||||
if (!(fp = fopen(path, "r"))) {
|
||||
log_sys_error("fopen", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!fgets(buffer, max_size, fp))
|
||||
log_sys_error("fgets", path);
|
||||
else
|
||||
r = 1;
|
||||
|
||||
if (fclose(fp))
|
||||
log_sys_error("fclose", path);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _get_sysfs_dm_mpath(struct dev_types *dt, const char *sysfs_dir, const char *holder_name)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
char buffer[128];
|
||||
|
||||
if (dm_snprintf(path, sizeof(path), "%sblock/%s/dm/uuid", sysfs_dir, holder_name) < 0) {
|
||||
log_error("Sysfs path string is too long.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
buffer[0] = '\0';
|
||||
|
||||
if (!_get_sysfs_string(path, buffer, sizeof(buffer)))
|
||||
return_0;
|
||||
|
||||
if (!strncmp(buffer, MPATH_PREFIX, 6))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
static int _dev_is_mpath_component_udev(struct device *dev)
|
||||
{
|
||||
const char *value;
|
||||
struct dev_ext *ext;
|
||||
|
||||
/*
|
||||
* external_device_info_source="udev" enables these udev checks.
|
||||
* external_device_info_source="none" disables them.
|
||||
*/
|
||||
|
||||
if (!(ext = dev_ext_get(dev)))
|
||||
return_0;
|
||||
|
||||
value = udev_device_get_property_value((struct udev_device *)ext->handle, DEV_EXT_UDEV_BLKID_TYPE);
|
||||
if (value && !strcmp(value, DEV_EXT_UDEV_BLKID_TYPE_MPATH))
|
||||
return 1;
|
||||
|
||||
value = udev_device_get_property_value((struct udev_device *)ext->handle, DEV_EXT_UDEV_MPATH_DEVICE_PATH);
|
||||
if (value && !strcmp(value, "1"))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int _dev_is_mpath_component_udev(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int _dev_is_mpath_component_sysfs(struct cmd_context *cmd, struct device *dev)
|
||||
{
|
||||
struct dev_types *dt = cmd->dev_types;
|
||||
const char *part_name;
|
||||
const char *name; /* e.g. "sda" for "/dev/sda" */
|
||||
char link_path[PATH_MAX]; /* some obscure, unpredictable sysfs path */
|
||||
char holders_path[PATH_MAX]; /* e.g. "/sys/block/sda/holders/" */
|
||||
char dm_dev_path[PATH_MAX]; /* e.g. "/dev/dm-1" */
|
||||
char *holder_name; /* e.g. "dm-1" */
|
||||
const char *sysfs_dir = dm_sysfs_dir();
|
||||
DIR *dr;
|
||||
struct dirent *de;
|
||||
int dev_major = MAJOR(dev->dev);
|
||||
int dev_minor = MINOR(dev->dev);
|
||||
int dm_dev_major;
|
||||
int dm_dev_minor;
|
||||
struct stat info;
|
||||
dev_t primary_dev;
|
||||
int is_mpath_component = 0;
|
||||
|
||||
/* multipathing is only known to exist for SCSI or NVME devices */
|
||||
if (!major_is_scsi_device(dt, dev_major) && !dev_is_nvme(dt, dev))
|
||||
return 0;
|
||||
|
||||
switch (dev_get_primary_dev(dt, dev, &primary_dev)) {
|
||||
|
||||
case 2: /* The dev is partition. */
|
||||
part_name = dev_name(dev); /* name of original dev for log_debug msg */
|
||||
|
||||
/* gets "foo" for "/dev/foo" where "/dev/foo" comes from major:minor */
|
||||
if (!(name = _get_sysfs_name_by_devt(sysfs_dir, primary_dev, link_path, sizeof(link_path))))
|
||||
return_0;
|
||||
|
||||
log_debug_devs("%s: Device is a partition, using primary "
|
||||
"device %s for mpath component detection",
|
||||
part_name, name);
|
||||
break;
|
||||
|
||||
case 1: /* The dev is already a primary dev. Just continue with the dev. */
|
||||
|
||||
/* gets "foo" for "/dev/foo" */
|
||||
if (!(name = _get_sysfs_name(dev)))
|
||||
return_0;
|
||||
break;
|
||||
|
||||
default: /* 0, error. */
|
||||
log_warn("Failed to get primary device for %d:%d.", dev_major, dev_minor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dm_snprintf(holders_path, sizeof(holders_path), "%sblock/%s/holders", sysfs_dir, name) < 0) {
|
||||
log_warn("Sysfs path to check mpath is too long.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* also will filter out partitions */
|
||||
if (stat(holders_path, &info))
|
||||
return 0;
|
||||
|
||||
if (!S_ISDIR(info.st_mode)) {
|
||||
log_warn("Path %s is not a directory.", holders_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If any holder is a dm mpath device, then return 1;
|
||||
*/
|
||||
|
||||
if (!(dr = opendir(holders_path))) {
|
||||
log_debug("Device %s has no holders dir", dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
while ((de = readdir(dr))) {
|
||||
if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* holder_name is e.g. "dm-1"
|
||||
* dm_dev_path is then e.g. "/dev/dm-1"
|
||||
*/
|
||||
holder_name = de->d_name;
|
||||
|
||||
if (dm_snprintf(dm_dev_path, sizeof(dm_dev_path), "%s/%s", cmd->dev_dir, holder_name) < 0) {
|
||||
log_warn("dm device path to check mpath is too long.");
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* stat "/dev/dm-1" which is the holder of the dev we're checking
|
||||
* dm_dev_major:dm_dev_minor come from stat("/dev/dm-1")
|
||||
*/
|
||||
if (stat(dm_dev_path, &info)) {
|
||||
log_debug_devs("dev_is_mpath_component %s holder %s stat result %d",
|
||||
dev_name(dev), dm_dev_path, errno);
|
||||
continue;
|
||||
}
|
||||
dm_dev_major = (int)MAJOR(info.st_rdev);
|
||||
dm_dev_minor = (int)MINOR(info.st_rdev);
|
||||
|
||||
if (dm_dev_major != dt->device_mapper_major) {
|
||||
log_debug_devs("dev_is_mpath_component %s holder %s %d:%d does not have dm major",
|
||||
dev_name(dev), dm_dev_path, dm_dev_major, dm_dev_minor);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* A previous call may have checked if dm_dev_minor is mpath and saved
|
||||
* the result in the hash table. If there's a saved result just use that.
|
||||
*
|
||||
* The minor number of "/dev/dm-1" is added to the hash table with
|
||||
* const value 2 meaning that dm minor 1 (for /dev/dm-1) is a multipath dev
|
||||
* and const value 1 meaning that dm minor 1 is not a multipath dev.
|
||||
*/
|
||||
|
||||
if (_minor_hash_tab) {
|
||||
long look = (long) dm_hash_lookup_binary(_minor_hash_tab, &dm_dev_minor, sizeof(dm_dev_minor));
|
||||
if (look > 0) {
|
||||
log_debug_devs("dev_is_mpath_component %s holder %s %u:%u already checked as %sbeing mpath.",
|
||||
dev_name(dev), holder_name, dm_dev_major, dm_dev_minor, (look > 1) ? "" : "not ");
|
||||
|
||||
is_mpath_component = (look == 2);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* no saved result for dm_dev_minor, so check the uuid for it */
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 1 if /sys/block/<holder_name>/dm/uuid indicates that
|
||||
* <holder_name> is a dm device with dm uuid prefix mpath-.
|
||||
* When true, <holder_name> will be something like "dm-1".
|
||||
*/
|
||||
if (_get_sysfs_dm_mpath(dt, sysfs_dir, holder_name)) {
|
||||
log_debug_devs("dev_is_mpath_component %s holder %s %u:%u ignore mpath component",
|
||||
dev_name(dev), holder_name, dm_dev_major, dm_dev_minor);
|
||||
|
||||
/* For future checks, save that the dm minor refers to mpath ("2" == is mpath) */
|
||||
if (_minor_hash_tab)
|
||||
(void) dm_hash_insert_binary(_minor_hash_tab, &dm_dev_minor, sizeof(dm_dev_minor), (void*)2);
|
||||
|
||||
is_mpath_component = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* For future checks, save that the dm minor does not refer to mpath ("1" == is not mpath) */
|
||||
if (_minor_hash_tab)
|
||||
(void) dm_hash_insert_binary(_minor_hash_tab, &dm_dev_minor, sizeof(dm_dev_minor), (void*)1);
|
||||
}
|
||||
|
||||
out:
|
||||
if (closedir(dr))
|
||||
stack;
|
||||
|
||||
return is_mpath_component;
|
||||
}
|
||||
|
||||
static int _dev_in_wwid_file(struct cmd_context *cmd, struct device *dev)
|
||||
{
|
||||
char sysbuf[PATH_MAX] = { 0 };
|
||||
char *wwid;
|
||||
long look;
|
||||
|
||||
if (!_wwid_hash_tab)
|
||||
return 0;
|
||||
|
||||
if (!read_sys_block(cmd, dev, "device/wwid", sysbuf, sizeof(sysbuf)))
|
||||
return 0;
|
||||
|
||||
if (!sysbuf[0])
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* sysfs prints wwid as <typestr>.<value>
|
||||
* multipath wwid uses '3'<value>
|
||||
* does "<typestr>." always correspond to "3"?
|
||||
*/
|
||||
if (!(wwid = strchr(sysbuf, '.')))
|
||||
return 0;
|
||||
|
||||
/* skip the type and dot, just as '3' was skipped from wwids entry */
|
||||
wwid++;
|
||||
|
||||
look = (long) dm_hash_lookup_binary(_wwid_hash_tab, wwid, strlen(wwid));
|
||||
|
||||
if (look) {
|
||||
log_debug_devs("dev_is_mpath_component %s multipath wwid %s", dev_name(dev), wwid);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dev_is_mpath_component(struct cmd_context *cmd, struct device *dev)
|
||||
{
|
||||
if (_dev_is_mpath_component_sysfs(cmd, dev) == 1)
|
||||
goto found;
|
||||
|
||||
if (_dev_in_wwid_file(cmd, dev))
|
||||
goto found;
|
||||
|
||||
if (external_device_info_source() == DEV_EXT_UDEV) {
|
||||
if (_dev_is_mpath_component_udev(dev) == 1)
|
||||
goto found;
|
||||
}
|
||||
|
||||
return 0;
|
||||
found:
|
||||
return 1;
|
||||
}
|
||||
|
@@ -35,7 +35,7 @@ static int _swap_detect_signature(const char *buf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dev_is_swap(struct device *dev, uint64_t *offset_found, int full)
|
||||
int dev_is_swap(struct cmd_context *cmd, struct device *dev, uint64_t *offset_found, int full)
|
||||
{
|
||||
char buf[10];
|
||||
uint64_t size;
|
||||
|
@@ -22,6 +22,7 @@
|
||||
#include "lib/device/bcache.h"
|
||||
#include "lib/label/label.h"
|
||||
#include "lib/commands/toolcontext.h"
|
||||
#include "device_mapper/misc/dm-ioctl.h"
|
||||
|
||||
#ifdef BLKID_WIPING_SUPPORT
|
||||
#include <blkid.h>
|
||||
@@ -34,6 +35,7 @@
|
||||
|
||||
#include <libgen.h>
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
|
||||
/*
|
||||
* An nvme device has major number 259 (BLKEXT), minor number <minor>,
|
||||
@@ -77,6 +79,121 @@ int dev_is_lv(struct device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dev_is_used_by_active_lv(struct cmd_context *cmd, struct device *dev, int *used_by_lv_count,
|
||||
char **used_by_dm_name, char **used_by_vg_uuid, char **used_by_lv_uuid)
|
||||
{
|
||||
char holders_path[PATH_MAX];
|
||||
char dm_dev_path[PATH_MAX];
|
||||
char dm_uuid[DM_UUID_LEN];
|
||||
struct stat info;
|
||||
DIR *d;
|
||||
struct dirent *dirent;
|
||||
char *holder_name;
|
||||
int dm_dev_major, dm_dev_minor;
|
||||
size_t lvm_prefix_len = sizeof(UUID_PREFIX) - 1;
|
||||
size_t lvm_uuid_len = sizeof(UUID_PREFIX) - 1 + 2 * ID_LEN;
|
||||
size_t uuid_len;
|
||||
int used_count = 0;
|
||||
char *used_name = NULL;
|
||||
char *used_vgid = NULL;
|
||||
char *used_lvid = NULL;
|
||||
|
||||
/*
|
||||
* An LV using this device will be listed as a "holder" in the device's
|
||||
* sysfs "holders" dir.
|
||||
*/
|
||||
|
||||
if (dm_snprintf(holders_path, sizeof(holders_path), "%sdev/block/%d:%d/holders/", dm_sysfs_dir(), (int) MAJOR(dev->dev), (int) MINOR(dev->dev)) < 0) {
|
||||
log_error("%s: dm_snprintf failed for path to holders directory.", dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(d = opendir(holders_path)))
|
||||
return 0;
|
||||
|
||||
while ((dirent = readdir(d))) {
|
||||
if (!strcmp(".", dirent->d_name) || !strcmp("..", dirent->d_name))
|
||||
continue;
|
||||
|
||||
holder_name = dirent->d_name;
|
||||
|
||||
/*
|
||||
* dirent->d_name is the dev name of the holder, e.g. "dm-1"
|
||||
* from this name, create path "/dev/dm-1" to run stat on.
|
||||
*/
|
||||
|
||||
if (dm_snprintf(dm_dev_path, sizeof(dm_dev_path), "%s/%s", cmd->dev_dir, holder_name) < 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* stat "/dev/dm-1" which is the holder of the dev we're checking
|
||||
* dm_dev_major:dm_dev_minor come from stat("/dev/dm-1")
|
||||
*/
|
||||
if (stat(dm_dev_path, &info))
|
||||
continue;
|
||||
|
||||
dm_dev_major = (int)MAJOR(info.st_rdev);
|
||||
dm_dev_minor = (int)MINOR(info.st_rdev);
|
||||
|
||||
if (dm_dev_major != cmd->dev_types->device_mapper_major)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* if "dm-1" is a dm device, then check if it's an LVM LV
|
||||
* by reading /sys/block/<holder_name>/dm/uuid and seeing
|
||||
* if the uuid begins with LVM-
|
||||
* UUID_PREFIX is "LVM-"
|
||||
*/
|
||||
|
||||
dm_uuid[0] = '\0';
|
||||
|
||||
if (!get_dm_uuid_from_sysfs(dm_uuid, sizeof(dm_uuid), dm_dev_major, dm_dev_minor))
|
||||
continue;
|
||||
|
||||
if (!strncmp(dm_uuid, UUID_PREFIX, 4))
|
||||
used_count++;
|
||||
|
||||
if (used_by_dm_name && !used_name)
|
||||
used_name = dm_pool_strdup(cmd->mem, holder_name);
|
||||
|
||||
if (!used_by_vg_uuid && !used_by_lv_uuid)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* UUID for LV is either "LVM-<vg_uuid><lv_uuid>" or
|
||||
* "LVM-<vg_uuid><lv_uuid>-<suffix>", where vg_uuid and lv_uuid
|
||||
* has length of ID_LEN and suffix len is not restricted (only
|
||||
* restricted by whole DM UUID max len).
|
||||
*/
|
||||
|
||||
uuid_len = strlen(dm_uuid);
|
||||
|
||||
if (((uuid_len == lvm_uuid_len) ||
|
||||
((uuid_len > lvm_uuid_len) && (dm_uuid[lvm_uuid_len] == '-'))) &&
|
||||
!strncmp(dm_uuid, UUID_PREFIX, lvm_prefix_len)) {
|
||||
|
||||
if (used_by_vg_uuid && !used_vgid)
|
||||
used_vgid = dm_pool_strndup(cmd->mem, dm_uuid + lvm_prefix_len, ID_LEN);
|
||||
|
||||
if (used_by_lv_uuid && !used_lvid)
|
||||
used_lvid = dm_pool_strndup(cmd->mem, dm_uuid + lvm_prefix_len + ID_LEN, ID_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
if (used_by_lv_count)
|
||||
*used_by_lv_count = used_count;
|
||||
if (used_by_dm_name)
|
||||
*used_by_dm_name = used_name;
|
||||
if (used_by_vg_uuid)
|
||||
*used_by_vg_uuid = used_vgid;
|
||||
if (used_by_lv_uuid)
|
||||
*used_by_lv_uuid = used_lvid;
|
||||
|
||||
if (used_count)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dev_types *create_dev_types(const char *proc_dir,
|
||||
const struct dm_config_node *cn)
|
||||
{
|
||||
@@ -504,12 +621,16 @@ static int _has_partition_table(struct device *dev)
|
||||
}
|
||||
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
static int _udev_dev_is_partitioned(struct dev_types *dt, struct device *dev)
|
||||
static int _dev_is_partitioned_udev(struct dev_types *dt, struct device *dev)
|
||||
{
|
||||
struct dev_ext *ext;
|
||||
struct udev_device *device;
|
||||
const char *value;
|
||||
|
||||
/*
|
||||
* external_device_info_source="udev" enables these udev checks.
|
||||
* external_device_info_source="none" disables them.
|
||||
*/
|
||||
if (!(ext = dev_ext_get(dev)))
|
||||
return_0;
|
||||
|
||||
@@ -540,21 +661,20 @@ static int _udev_dev_is_partitioned(struct dev_types *dt, struct device *dev)
|
||||
return !strcmp(value, DEV_EXT_UDEV_DEVTYPE_DISK);
|
||||
}
|
||||
#else
|
||||
static int _udev_dev_is_partitioned(struct dev_types *dt, struct device *dev)
|
||||
static int _dev_is_partitioned_udev(struct dev_types *dt, struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int _native_dev_is_partitioned(struct dev_types *dt, struct device *dev)
|
||||
static int _dev_is_partitioned_native(struct dev_types *dt, struct device *dev)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!scan_bcache)
|
||||
return -EAGAIN;
|
||||
|
||||
if (!_is_partitionable(dt, dev))
|
||||
return 0;
|
||||
if (!scan_bcache) {
|
||||
log_error(INTERNAL_ERROR "dev_is_partitioned_native requires i/o.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Unpartitioned DASD devices are not supported. */
|
||||
if ((MAJOR(dev->dev) == dt->dasd_major) && dasd_is_cdl_formatted(dev))
|
||||
@@ -565,16 +685,20 @@ static int _native_dev_is_partitioned(struct dev_types *dt, struct device *dev)
|
||||
return r;
|
||||
}
|
||||
|
||||
int dev_is_partitioned(struct dev_types *dt, struct device *dev)
|
||||
int dev_is_partitioned(struct cmd_context *cmd, struct device *dev)
|
||||
{
|
||||
if (dev->ext.src == DEV_EXT_NONE)
|
||||
return _native_dev_is_partitioned(dt, dev);
|
||||
struct dev_types *dt = cmd->dev_types;
|
||||
|
||||
if (dev->ext.src == DEV_EXT_UDEV)
|
||||
return _udev_dev_is_partitioned(dt, dev);
|
||||
if (!_is_partitionable(dt, dev))
|
||||
return 0;
|
||||
|
||||
log_error(INTERNAL_ERROR "Missing hook for partition table recognition "
|
||||
"using external device info source %s", dev_ext_name(dev));
|
||||
if (_dev_is_partitioned_native(dt, dev) == 1)
|
||||
return 1;
|
||||
|
||||
if (external_device_info_source() == DEV_EXT_UDEV) {
|
||||
if (_dev_is_partitioned_udev(dt, dev) == 1)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -886,14 +1010,14 @@ out:
|
||||
|
||||
#endif /* BLKID_WIPING_SUPPORT */
|
||||
|
||||
static int _wipe_signature(struct device *dev, const char *type, const char *name,
|
||||
static int _wipe_signature(struct cmd_context *cmd, struct device *dev, const char *type, const char *name,
|
||||
int wipe_len, int yes, force_t force, int *wiped,
|
||||
int (*signature_detection_fn)(struct device *dev, uint64_t *offset_found, int full))
|
||||
int (*signature_detection_fn)(struct cmd_context *cmd, struct device *dev, uint64_t *offset_found, int full))
|
||||
{
|
||||
int wipe;
|
||||
uint64_t offset_found = 0;
|
||||
|
||||
wipe = signature_detection_fn(dev, &offset_found, 1);
|
||||
wipe = signature_detection_fn(cmd, dev, &offset_found, 1);
|
||||
if (wipe == -1) {
|
||||
log_error("Fatal error while trying to detect %s on %s.",
|
||||
type, name);
|
||||
@@ -921,7 +1045,7 @@ static int _wipe_signature(struct device *dev, const char *type, const char *nam
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _wipe_known_signatures_with_lvm(struct device *dev, const char *name,
|
||||
static int _wipe_known_signatures_with_lvm(struct cmd_context *cmd, struct device *dev, const char *name,
|
||||
uint32_t types_to_exclude __attribute__((unused)),
|
||||
uint32_t types_no_prompt __attribute__((unused)),
|
||||
int yes, force_t force, int *wiped)
|
||||
@@ -932,9 +1056,9 @@ static int _wipe_known_signatures_with_lvm(struct device *dev, const char *name,
|
||||
wiped = &wiped_tmp;
|
||||
*wiped = 0;
|
||||
|
||||
if (!_wipe_signature(dev, "software RAID md superblock", name, 4, yes, force, wiped, dev_is_md_component) ||
|
||||
!_wipe_signature(dev, "swap signature", name, 10, yes, force, wiped, dev_is_swap) ||
|
||||
!_wipe_signature(dev, "LUKS signature", name, 8, yes, force, wiped, dev_is_luks))
|
||||
if (!_wipe_signature(cmd, dev, "software RAID md superblock", name, 4, yes, force, wiped, dev_is_md_component) ||
|
||||
!_wipe_signature(cmd, dev, "swap signature", name, 10, yes, force, wiped, dev_is_swap) ||
|
||||
!_wipe_signature(cmd, dev, "LUKS signature", name, 8, yes, force, wiped, dev_is_luks))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
@@ -959,7 +1083,7 @@ int wipe_known_signatures(struct cmd_context *cmd, struct device *dev,
|
||||
"while LVM is not compiled with blkid wiping support.");
|
||||
log_warn("WARNING: Falling back to native LVM signature detection.");
|
||||
}
|
||||
return _wipe_known_signatures_with_lvm(dev, name,
|
||||
return _wipe_known_signatures_with_lvm(cmd, dev, name,
|
||||
types_to_exclude,
|
||||
types_no_prompt,
|
||||
yes, force, wiped);
|
||||
@@ -1149,147 +1273,3 @@ int dev_is_pmem(struct dev_types *dt, struct device *dev)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
|
||||
/*
|
||||
* Udev daemon usually has 30s timeout to process each event by default.
|
||||
* But still, that value can be changed in udev configuration and we
|
||||
* don't have libudev API to read the actual timeout value used.
|
||||
*/
|
||||
|
||||
/* FIXME: Is this long enough to wait for udev db to get initialized?
|
||||
*
|
||||
* Take also into consideration that this check is done for each
|
||||
* device that is scanned so we don't want to wait for a long time
|
||||
* if there's something wrong with udev, e.g. timeouts! With current
|
||||
* libudev API, we can't recognize whether the event processing has
|
||||
* not finished yet and it's still being processed or whether it has
|
||||
* failed already due to timeout in udev - in both cases the
|
||||
* udev_device_get_is_initialized returns 0.
|
||||
*/
|
||||
#define UDEV_DEV_IS_COMPONENT_ITERATION_COUNT 100
|
||||
#define UDEV_DEV_IS_COMPONENT_USLEEP 100000
|
||||
|
||||
static struct udev_device *_udev_get_dev(struct device *dev)
|
||||
{
|
||||
struct udev *udev_context = udev_get_library_context();
|
||||
struct udev_device *udev_device = NULL;
|
||||
int initialized = 0;
|
||||
unsigned i = 0;
|
||||
|
||||
if (!udev_context) {
|
||||
log_warn("WARNING: No udev context available to check if device %s is multipath component.", dev_name(dev));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (i >= UDEV_DEV_IS_COMPONENT_ITERATION_COUNT)
|
||||
break;
|
||||
|
||||
if (udev_device)
|
||||
udev_device_unref(udev_device);
|
||||
|
||||
if (!(udev_device = udev_device_new_from_devnum(udev_context, 'b', dev->dev))) {
|
||||
log_warn("WARNING: Failed to get udev device handler for device %s.", dev_name(dev));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBUDEV_UDEV_DEVICE_GET_IS_INITIALIZED
|
||||
if ((initialized = udev_device_get_is_initialized(udev_device)))
|
||||
break;
|
||||
#else
|
||||
if ((initialized = (udev_device_get_property_value(udev_device, DEV_EXT_UDEV_DEVLINKS) != NULL)))
|
||||
break;
|
||||
#endif
|
||||
|
||||
log_debug("Device %s not initialized in udev database (%u/%u, %u microseconds).", dev_name(dev),
|
||||
i + 1, UDEV_DEV_IS_COMPONENT_ITERATION_COUNT,
|
||||
i * UDEV_DEV_IS_COMPONENT_USLEEP);
|
||||
|
||||
if (!udev_sleeping())
|
||||
break;
|
||||
|
||||
usleep(UDEV_DEV_IS_COMPONENT_USLEEP);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (!initialized) {
|
||||
log_warn("WARNING: Device %s not initialized in udev database even after waiting %u microseconds.",
|
||||
dev_name(dev), i * UDEV_DEV_IS_COMPONENT_USLEEP);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return udev_device;
|
||||
}
|
||||
|
||||
int udev_dev_is_mpath_component(struct device *dev)
|
||||
{
|
||||
struct udev_device *udev_device;
|
||||
const char *value;
|
||||
int ret = 0;
|
||||
|
||||
if (!obtain_device_list_from_udev())
|
||||
return 0;
|
||||
|
||||
if (!(udev_device = _udev_get_dev(dev)))
|
||||
return 0;
|
||||
|
||||
value = udev_device_get_property_value(udev_device, DEV_EXT_UDEV_BLKID_TYPE);
|
||||
if (value && !strcmp(value, DEV_EXT_UDEV_BLKID_TYPE_MPATH)) {
|
||||
log_debug("Device %s is multipath component based on blkid variable in udev db (%s=\"%s\").",
|
||||
dev_name(dev), DEV_EXT_UDEV_BLKID_TYPE, value);
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
value = udev_device_get_property_value(udev_device, DEV_EXT_UDEV_MPATH_DEVICE_PATH);
|
||||
if (value && !strcmp(value, "1")) {
|
||||
log_debug("Device %s is multipath component based on multipath variable in udev db (%s=\"%s\").",
|
||||
dev_name(dev), DEV_EXT_UDEV_MPATH_DEVICE_PATH, value);
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
udev_device_unref(udev_device);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int udev_dev_is_md_component(struct device *dev)
|
||||
{
|
||||
struct udev_device *udev_device;
|
||||
const char *value;
|
||||
int ret = 0;
|
||||
|
||||
if (!obtain_device_list_from_udev())
|
||||
return 0;
|
||||
|
||||
if (!(udev_device = _udev_get_dev(dev)))
|
||||
return 0;
|
||||
|
||||
value = udev_device_get_property_value(udev_device, DEV_EXT_UDEV_BLKID_TYPE);
|
||||
if (value && !strcmp(value, DEV_EXT_UDEV_BLKID_TYPE_SW_RAID)) {
|
||||
log_debug("Device %s is md raid component based on blkid variable in udev db (%s=\"%s\").",
|
||||
dev_name(dev), DEV_EXT_UDEV_BLKID_TYPE, value);
|
||||
dev->flags |= DEV_IS_MD_COMPONENT;
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
udev_device_unref(udev_device);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int udev_dev_is_mpath_component(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int udev_dev_is_md_component(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -57,12 +57,11 @@ const char *dev_subsystem_name(struct dev_types *dt, struct device *dev);
|
||||
int major_is_scsi_device(struct dev_types *dt, int major);
|
||||
|
||||
/* Signature/superblock recognition with position returned where found. */
|
||||
int dev_is_md_component(struct device *dev, uint64_t *sb, int full);
|
||||
int dev_is_swap(struct device *dev, uint64_t *signature, int full);
|
||||
int dev_is_luks(struct device *dev, uint64_t *signature, int full);
|
||||
int dev_is_md_component(struct cmd_context *cmd, struct device *dev, uint64_t *sb, int full);
|
||||
int dev_is_mpath_component(struct cmd_context *cmd, struct device *dev);
|
||||
int dev_is_swap(struct cmd_context *cmd, struct device *dev, uint64_t *signature, int full);
|
||||
int dev_is_luks(struct cmd_context *cmd, struct device *dev, uint64_t *signature, int full);
|
||||
int dasd_is_cdl_formatted(struct device *dev);
|
||||
int udev_dev_is_mpath_component(struct device *dev);
|
||||
int udev_dev_is_md_component(struct device *dev);
|
||||
|
||||
int dev_is_lvm1(struct device *dev, char *buf, int buflen);
|
||||
int dev_is_pool(struct device *dev, char *buf, int buflen);
|
||||
@@ -81,7 +80,7 @@ int dev_is_md_with_end_superblock(struct dev_types *dt, struct device *dev);
|
||||
|
||||
/* Partitioning */
|
||||
int major_max_partitions(struct dev_types *dt, int major);
|
||||
int dev_is_partitioned(struct dev_types *dt, struct device *dev);
|
||||
int dev_is_partitioned(struct cmd_context *cmd, struct device *dev);
|
||||
int dev_get_primary_dev(struct dev_types *dt, struct device *dev, dev_t *result);
|
||||
int dev_get_partition_number(struct device *dev, int *num);
|
||||
|
||||
@@ -102,4 +101,7 @@ int dev_is_lv(struct device *dev);
|
||||
|
||||
int get_fs_block_size(const char *pathname, uint32_t *fs_block_size);
|
||||
|
||||
int dev_is_used_by_active_lv(struct cmd_context *cmd, struct device *dev, int *used_by_lv_count,
|
||||
char **used_by_dm_name, char **used_by_vg_uuid, char **used_by_lv_uuid);
|
||||
|
||||
#endif
|
||||
|
@@ -205,4 +205,7 @@ void dev_destroy_file(struct device *dev);
|
||||
/* Return a valid device name from the alias list; NULL otherwise */
|
||||
const char *dev_name_confirmed(struct device *dev, int quiet);
|
||||
|
||||
int dev_mpath_init(const char *config_wwids_file);
|
||||
void dev_mpath_exit(void);
|
||||
|
||||
#endif
|
||||
|
@@ -180,7 +180,7 @@ void free_dids(struct dm_list *ids)
|
||||
}
|
||||
}
|
||||
|
||||
static int _read_sys_block(struct cmd_context *cmd, struct device *dev, const char *suffix, char *sysbuf, int sysbufsize)
|
||||
int read_sys_block(struct cmd_context *cmd, struct device *dev, const char *suffix, char *sysbuf, int sysbufsize)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
dev_t devt = dev->dev;
|
||||
@@ -246,7 +246,7 @@ static int _dev_has_mpath_uuid(struct cmd_context *cmd, struct device *dev, cons
|
||||
char sysbuf[PATH_MAX] = { 0 };
|
||||
const char *idname;
|
||||
|
||||
if (!_read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf)))
|
||||
if (!read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf)))
|
||||
return 0;
|
||||
|
||||
if (!_dm_uuid_has_prefix(sysbuf, "mpath-"))
|
||||
@@ -265,7 +265,7 @@ static int _dev_has_crypt_uuid(struct cmd_context *cmd, struct device *dev, cons
|
||||
char sysbuf[PATH_MAX] = { 0 };
|
||||
const char *idname;
|
||||
|
||||
if (!_read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf)))
|
||||
if (!read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf)))
|
||||
return 0;
|
||||
|
||||
if (!_dm_uuid_has_prefix(sysbuf, "CRYPT-"))
|
||||
@@ -284,7 +284,7 @@ static int _dev_has_lvmlv_uuid(struct cmd_context *cmd, struct device *dev, cons
|
||||
char sysbuf[PATH_MAX] = { 0 };
|
||||
const char *idname;
|
||||
|
||||
if (!_read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf)))
|
||||
if (!read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf)))
|
||||
return 0;
|
||||
|
||||
if (!_dm_uuid_has_prefix(sysbuf, "LVM-"))
|
||||
@@ -304,29 +304,37 @@ const char *device_id_system_read(struct cmd_context *cmd, struct device *dev, u
|
||||
const char *idname = NULL;
|
||||
|
||||
if (idtype == DEV_ID_TYPE_SYS_WWID) {
|
||||
_read_sys_block(cmd, dev, "device/wwid", sysbuf, sizeof(sysbuf));
|
||||
read_sys_block(cmd, dev, "device/wwid", sysbuf, sizeof(sysbuf));
|
||||
|
||||
if (!sysbuf[0])
|
||||
_read_sys_block(cmd, dev, "wwid", sysbuf, sizeof(sysbuf));
|
||||
read_sys_block(cmd, dev, "wwid", sysbuf, sizeof(sysbuf));
|
||||
|
||||
/* scsi_debug wwid begins "t10.Linux scsi_debug ..." */
|
||||
if (strstr(sysbuf, "scsi_debug"))
|
||||
sysbuf[0] = '\0';
|
||||
|
||||
/* qemu wwid begins "t10.ATA QEMU HARDDISK ..." */
|
||||
if (strstr(sysbuf, "QEMU HARDDISK"))
|
||||
sysbuf[0] = '\0';
|
||||
}
|
||||
|
||||
else if (idtype == DEV_ID_TYPE_SYS_SERIAL)
|
||||
_read_sys_block(cmd, dev, "device/serial", sysbuf, sizeof(sysbuf));
|
||||
read_sys_block(cmd, dev, "device/serial", sysbuf, sizeof(sysbuf));
|
||||
|
||||
else if (idtype == DEV_ID_TYPE_MPATH_UUID)
|
||||
_read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf));
|
||||
read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf));
|
||||
|
||||
else if (idtype == DEV_ID_TYPE_CRYPT_UUID)
|
||||
_read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf));
|
||||
read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf));
|
||||
|
||||
else if (idtype == DEV_ID_TYPE_LVMLV_UUID)
|
||||
_read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf));
|
||||
read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf));
|
||||
|
||||
else if (idtype == DEV_ID_TYPE_MD_UUID)
|
||||
_read_sys_block(cmd, dev, "md/uuid", sysbuf, sizeof(sysbuf));
|
||||
read_sys_block(cmd, dev, "md/uuid", sysbuf, sizeof(sysbuf));
|
||||
|
||||
else if (idtype == DEV_ID_TYPE_LOOP_FILE) {
|
||||
_read_sys_block(cmd, dev, "loop/backing_file", sysbuf, sizeof(sysbuf));
|
||||
read_sys_block(cmd, dev, "loop/backing_file", sysbuf, sizeof(sysbuf));
|
||||
/* if backing file is deleted, fall back to devname */
|
||||
if (strstr(sysbuf, "(deleted)"))
|
||||
sysbuf[0] = '\0';
|
||||
@@ -364,17 +372,17 @@ static int _dev_has_stable_id(struct cmd_context *cmd, struct device *dev)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (_read_sys_block(cmd, dev, "device/wwid", sysbuf, sizeof(sysbuf)))
|
||||
if (read_sys_block(cmd, dev, "device/wwid", sysbuf, sizeof(sysbuf)))
|
||||
return 1;
|
||||
|
||||
if (_read_sys_block(cmd, dev, "wwid", sysbuf, sizeof(sysbuf)))
|
||||
if (read_sys_block(cmd, dev, "wwid", sysbuf, sizeof(sysbuf)))
|
||||
return 1;
|
||||
|
||||
if (_read_sys_block(cmd, dev, "device/serial", sysbuf, sizeof(sysbuf)))
|
||||
if (read_sys_block(cmd, dev, "device/serial", sysbuf, sizeof(sysbuf)))
|
||||
return 1;
|
||||
|
||||
if ((MAJOR(dev->dev) == cmd->dev_types->device_mapper_major)) {
|
||||
if (!_read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf)))
|
||||
if (!read_sys_block(cmd, dev, "dm/uuid", sysbuf, sizeof(sysbuf)))
|
||||
goto_out;
|
||||
|
||||
if (_dm_uuid_has_prefix(sysbuf, "mpath-"))
|
||||
@@ -386,11 +394,11 @@ static int _dev_has_stable_id(struct cmd_context *cmd, struct device *dev)
|
||||
}
|
||||
|
||||
if ((MAJOR(dev->dev) == cmd->dev_types->md_major) &&
|
||||
_read_sys_block(cmd, dev, "md/uuid", sysbuf, sizeof(sysbuf)))
|
||||
read_sys_block(cmd, dev, "md/uuid", sysbuf, sizeof(sysbuf)))
|
||||
return 1;
|
||||
|
||||
if ((MAJOR(dev->dev) == cmd->dev_types->loop_major) &&
|
||||
_read_sys_block(cmd, dev, "loop/backing_file", sysbuf, sizeof(sysbuf)))
|
||||
read_sys_block(cmd, dev, "loop/backing_file", sysbuf, sizeof(sysbuf)))
|
||||
return 1;
|
||||
out:
|
||||
/* DEV_ID_TYPE_DEVNAME would be used for this dev. */
|
||||
@@ -1132,6 +1140,7 @@ id_done:
|
||||
|
||||
if (yes_no_prompt("Add device with duplicate PV to devices file?") == 'n') {
|
||||
log_print("Device not added.");
|
||||
free((void *)check_idname);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -1181,7 +1190,7 @@ id_done:
|
||||
if (!label_scan_open(du_devid->dev))
|
||||
log_warn("Cannot open %s", dev_name(du_devid->dev));
|
||||
|
||||
if (dev_is_partitioned(cmd->dev_types, du_devid->dev)) {
|
||||
if (dev_is_partitioned(cmd, du_devid->dev)) {
|
||||
/* Check if existing entry is whole device and new entry is a partition of it. */
|
||||
ret1 = dev_get_primary_dev(cmd->dev_types, dev, &devt1);
|
||||
if ((ret1 == 2) && (devt1 == du_devid->dev->dev))
|
||||
|
@@ -52,4 +52,6 @@ void devices_file_exit(struct cmd_context *cmd);
|
||||
|
||||
void unlink_searched_devnames(struct cmd_context *cmd);
|
||||
|
||||
int read_sys_block(struct cmd_context *cmd, struct device *dev, const char *suffix, char *sysbuf, int sysbufsize);
|
||||
|
||||
#endif
|
||||
|
@@ -21,29 +21,24 @@
|
||||
static int _and_p(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
|
||||
{
|
||||
struct dev_filter **filters;
|
||||
int ret;
|
||||
int ret = 1;
|
||||
|
||||
dev_ext_enable(dev, external_device_info_source());
|
||||
|
||||
for (filters = (struct dev_filter **) f->private; *filters; ++filters) {
|
||||
if (use_filter_name && strcmp((*filters)->name, use_filter_name))
|
||||
continue;
|
||||
ret = (*filters)->passes_filter(cmd, *filters, dev, use_filter_name);
|
||||
|
||||
if (!ret)
|
||||
return 0; /* No 'stack': a filter, not an error. */
|
||||
if (!ret) {
|
||||
ret = 0; /* No 'stack': a filter, not an error. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _and_p_with_dev_ext_info(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
|
||||
{
|
||||
int r;
|
||||
|
||||
dev_ext_enable(dev, external_device_info_source());
|
||||
r = _and_p(cmd, f, dev, use_filter_name);
|
||||
dev_ext_disable(dev);
|
||||
|
||||
return r;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void _composite_destroy(struct dev_filter *f)
|
||||
@@ -72,7 +67,7 @@ static void _wipe(struct cmd_context *cmd, struct dev_filter *f, struct device *
|
||||
}
|
||||
}
|
||||
|
||||
struct dev_filter *composite_filter_create(int n, int use_dev_ext_info, struct dev_filter **filters)
|
||||
struct dev_filter *composite_filter_create(int n, struct dev_filter **filters)
|
||||
{
|
||||
struct dev_filter **filters_copy, *cft;
|
||||
|
||||
@@ -93,7 +88,7 @@ struct dev_filter *composite_filter_create(int n, int use_dev_ext_info, struct d
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cft->passes_filter = use_dev_ext_info ? _and_p_with_dev_ext_info : _and_p;
|
||||
cft->passes_filter = _and_p;
|
||||
cft->destroy = _composite_destroy;
|
||||
cft->wipe = _wipe;
|
||||
cft->use_count = 0;
|
||||
|
@@ -98,7 +98,7 @@ static int _passes_md_filter(struct cmd_context *cmd, struct dev_filter *f __att
|
||||
if (!md_filtering())
|
||||
return 1;
|
||||
|
||||
ret = dev_is_md_component(dev, NULL, cmd->use_full_md_check);
|
||||
ret = dev_is_md_component(cmd, dev, NULL, cmd->use_full_md_check);
|
||||
|
||||
if (ret == -EAGAIN) {
|
||||
/* let pass, call again after scan */
|
||||
|
@@ -17,333 +17,17 @@
|
||||
#include "lib/filters/filter.h"
|
||||
#include "lib/activate/activate.h"
|
||||
#include "lib/commands/toolcontext.h"
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
#include <libudev.h>
|
||||
#include "lib/device/dev-ext-udev-constants.h"
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
#define MPATH_PREFIX "mpath-"
|
||||
|
||||
struct mpath_priv {
|
||||
struct dm_pool *mem;
|
||||
struct dev_filter f;
|
||||
struct dev_types *dt;
|
||||
struct dm_hash_table *hash;
|
||||
};
|
||||
|
||||
/*
|
||||
* given "/dev/foo" return "foo"
|
||||
*/
|
||||
static const char *_get_sysfs_name(struct device *dev)
|
||||
{
|
||||
const char *name;
|
||||
|
||||
if (!(name = strrchr(dev_name(dev), '/'))) {
|
||||
log_error("Cannot find '/' in device name.");
|
||||
return NULL;
|
||||
}
|
||||
name++;
|
||||
|
||||
if (!*name) {
|
||||
log_error("Device name is not valid.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/*
|
||||
* given major:minor
|
||||
* readlink translates /sys/dev/block/major:minor to /sys/.../foo
|
||||
* from /sys/.../foo return "foo"
|
||||
*/
|
||||
static const char *_get_sysfs_name_by_devt(const char *sysfs_dir, dev_t devno,
|
||||
char *buf, size_t buf_size)
|
||||
{
|
||||
const char *name;
|
||||
char path[PATH_MAX];
|
||||
int size;
|
||||
|
||||
if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d", sysfs_dir,
|
||||
(int) MAJOR(devno), (int) MINOR(devno)) < 0) {
|
||||
log_error("Sysfs path string is too long.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((size = readlink(path, buf, buf_size - 1)) < 0) {
|
||||
log_sys_error("readlink", path);
|
||||
return NULL;
|
||||
}
|
||||
buf[size] = '\0';
|
||||
|
||||
if (!(name = strrchr(buf, '/'))) {
|
||||
log_error("Cannot find device name in sysfs path.");
|
||||
return NULL;
|
||||
}
|
||||
name++;
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
static int _get_sysfs_string(const char *path, char *buffer, int max_size)
|
||||
{
|
||||
FILE *fp;
|
||||
int r = 0;
|
||||
|
||||
if (!(fp = fopen(path, "r"))) {
|
||||
log_sys_error("fopen", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!fgets(buffer, max_size, fp))
|
||||
log_sys_error("fgets", path);
|
||||
else
|
||||
r = 1;
|
||||
|
||||
if (fclose(fp))
|
||||
log_sys_error("fclose", path);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _get_sysfs_dm_mpath(struct dev_types *dt, const char *sysfs_dir, const char *holder_name)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
char buffer[128];
|
||||
|
||||
if (dm_snprintf(path, sizeof(path), "%sblock/%s/dm/uuid", sysfs_dir, holder_name) < 0) {
|
||||
log_error("Sysfs path string is too long.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
buffer[0] = '\0';
|
||||
|
||||
if (!_get_sysfs_string(path, buffer, sizeof(buffer)))
|
||||
return_0;
|
||||
|
||||
if (!strncmp(buffer, MPATH_PREFIX, 6))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _get_holder_name(const char *dir, char *name, int max_size)
|
||||
{
|
||||
struct dirent *d;
|
||||
DIR *dr;
|
||||
int r = 0;
|
||||
|
||||
if (!(dr = opendir(dir))) {
|
||||
log_sys_error("opendir", dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*name = '\0';
|
||||
while ((d = readdir(dr))) {
|
||||
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
|
||||
continue;
|
||||
|
||||
/* There should be only one holder if it is multipath */
|
||||
if (*name) {
|
||||
r = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
strncpy(name, d->d_name, max_size);
|
||||
r = 1;
|
||||
}
|
||||
|
||||
if (closedir(dr))
|
||||
log_sys_debug("closedir", dir);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
static int _udev_dev_is_mpath_component(struct device *dev)
|
||||
{
|
||||
const char *value;
|
||||
struct dev_ext *ext;
|
||||
|
||||
if (!(ext = dev_ext_get(dev)))
|
||||
return_0;
|
||||
|
||||
value = udev_device_get_property_value((struct udev_device *)ext->handle, DEV_EXT_UDEV_BLKID_TYPE);
|
||||
if (value && !strcmp(value, DEV_EXT_UDEV_BLKID_TYPE_MPATH))
|
||||
return 1;
|
||||
|
||||
value = udev_device_get_property_value((struct udev_device *)ext->handle, DEV_EXT_UDEV_MPATH_DEVICE_PATH);
|
||||
if (value && !strcmp(value, "1"))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int _udev_dev_is_mpath_component(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int _native_dev_is_mpath_component(struct cmd_context *cmd, struct dev_filter *f, struct device *dev)
|
||||
{
|
||||
struct mpath_priv *mp = (struct mpath_priv *) f->private;
|
||||
struct dev_types *dt = mp->dt;
|
||||
const char *part_name;
|
||||
const char *name; /* e.g. "sda" for "/dev/sda" */
|
||||
char link_path[PATH_MAX]; /* some obscure, unpredictable sysfs path */
|
||||
char holders_path[PATH_MAX]; /* e.g. "/sys/block/sda/holders/" */
|
||||
char dm_dev_path[PATH_MAX]; /* e.g. "/dev/dm-1" */
|
||||
char holder_name[256]; /* e.g. "dm-1" */
|
||||
const char *sysfs_dir = dm_sysfs_dir();
|
||||
int dev_major = MAJOR(dev->dev);
|
||||
int dev_minor = MINOR(dev->dev);
|
||||
int dm_dev_major;
|
||||
int dm_dev_minor;
|
||||
struct stat info;
|
||||
dev_t primary_dev;
|
||||
long look;
|
||||
|
||||
/* Limit this filter to SCSI or NVME devices */
|
||||
if (!major_is_scsi_device(dt, dev_major) && !dev_is_nvme(dt, dev))
|
||||
return 0;
|
||||
|
||||
switch (dev_get_primary_dev(dt, dev, &primary_dev)) {
|
||||
|
||||
case 2: /* The dev is partition. */
|
||||
part_name = dev_name(dev); /* name of original dev for log_debug msg */
|
||||
|
||||
/* gets "foo" for "/dev/foo" where "/dev/foo" comes from major:minor */
|
||||
if (!(name = _get_sysfs_name_by_devt(sysfs_dir, primary_dev, link_path, sizeof(link_path))))
|
||||
return_0;
|
||||
|
||||
log_debug_devs("%s: Device is a partition, using primary "
|
||||
"device %s for mpath component detection",
|
||||
part_name, name);
|
||||
break;
|
||||
|
||||
case 1: /* The dev is already a primary dev. Just continue with the dev. */
|
||||
|
||||
/* gets "foo" for "/dev/foo" */
|
||||
if (!(name = _get_sysfs_name(dev)))
|
||||
return_0;
|
||||
break;
|
||||
|
||||
default: /* 0, error. */
|
||||
log_warn("Failed to get primary device for %d:%d.", dev_major, dev_minor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dm_snprintf(holders_path, sizeof(holders_path), "%sblock/%s/holders", sysfs_dir, name) < 0) {
|
||||
log_warn("Sysfs path to check mpath is too long.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* also will filter out partitions */
|
||||
if (stat(holders_path, &info))
|
||||
return 0;
|
||||
|
||||
if (!S_ISDIR(info.st_mode)) {
|
||||
log_warn("Path %s is not a directory.", holders_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If holders dir contains an entry such as "dm-1", then this sets
|
||||
* holder_name to "dm-1".
|
||||
*
|
||||
* If holders dir is empty, return 0 (this is generally where
|
||||
* devs that are not mpath components return.)
|
||||
*/
|
||||
if (!_get_holder_name(holders_path, holder_name, sizeof(holder_name)))
|
||||
return 0;
|
||||
|
||||
if (dm_snprintf(dm_dev_path, sizeof(dm_dev_path), "%s/%s", cmd->dev_dir, holder_name) < 0) {
|
||||
log_warn("dm device path to check mpath is too long.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* stat "/dev/dm-1" which is the holder of the dev we're checking
|
||||
* dm_dev_major:dm_dev_minor come from stat("/dev/dm-1")
|
||||
*/
|
||||
if (stat(dm_dev_path, &info)) {
|
||||
log_debug("filter-mpath %s holder %s stat result %d",
|
||||
dev_name(dev), dm_dev_path, errno);
|
||||
return 0;
|
||||
}
|
||||
dm_dev_major = (int)MAJOR(info.st_rdev);
|
||||
dm_dev_minor = (int)MINOR(info.st_rdev);
|
||||
|
||||
if (dm_dev_major != dt->device_mapper_major) {
|
||||
log_debug_devs("filter-mpath %s holder %s %d:%d does not have dm major",
|
||||
dev_name(dev), dm_dev_path, dm_dev_major, dm_dev_minor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the result of checking that "/dev/dm-1" is an mpath device
|
||||
* to avoid repeating it for each path component.
|
||||
* The minor number of "/dev/dm-1" is added to the hash table with
|
||||
* const value 2 meaning that dm minor 1 (for /dev/dm-1) is a multipath dev
|
||||
* and const value 1 meaning that dm minor 1 is not a multipath dev.
|
||||
*/
|
||||
look = (long) dm_hash_lookup_binary(mp->hash, &dm_dev_minor, sizeof(dm_dev_minor));
|
||||
if (look > 0) {
|
||||
log_debug_devs("filter-mpath %s holder %s %u:%u already checked as %sbeing mpath.",
|
||||
dev_name(dev), holder_name, dm_dev_major, dm_dev_minor, (look > 1) ? "" : "not ");
|
||||
return (look > 1) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 1 if /sys/block/<holder_name>/dm/uuid indicates that
|
||||
* <holder_name> is a dm device with dm uuid prefix mpath-.
|
||||
* When true, <holder_name> will be something like "dm-1".
|
||||
*
|
||||
* (Is a hash table worth it to avoid reading one sysfs file?)
|
||||
*/
|
||||
if (_get_sysfs_dm_mpath(dt, sysfs_dir, holder_name)) {
|
||||
log_debug_devs("filter-mpath %s holder %s %u:%u ignore mpath component",
|
||||
dev_name(dev), holder_name, dm_dev_major, dm_dev_minor);
|
||||
(void) dm_hash_insert_binary(mp->hash, &dm_dev_minor, sizeof(dm_dev_minor), (void*)2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
(void) dm_hash_insert_binary(mp->hash, &dm_dev_minor, sizeof(dm_dev_minor), (void*)1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dev_is_mpath_component(struct cmd_context *cmd, struct dev_filter *f, struct device *dev)
|
||||
{
|
||||
if (dev->ext.src == DEV_EXT_NONE)
|
||||
return _native_dev_is_mpath_component(cmd, f, dev);
|
||||
|
||||
if (dev->ext.src == DEV_EXT_UDEV)
|
||||
return _udev_dev_is_mpath_component(dev);
|
||||
|
||||
log_error(INTERNAL_ERROR "Missing hook for mpath recognition "
|
||||
"using external device info source %s", dev_ext_name(dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MSG_SKIPPING "%s: Skipping mpath component device"
|
||||
|
||||
static int _ignore_mpath_component(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
|
||||
{
|
||||
dev->filtered_flags &= ~DEV_FILTERED_MPATH_COMPONENT;
|
||||
|
||||
if (_dev_is_mpath_component(cmd, f, dev) == 1) {
|
||||
if (dev->ext.src == DEV_EXT_NONE)
|
||||
log_debug_devs(MSG_SKIPPING, dev_name(dev));
|
||||
else
|
||||
log_debug_devs(MSG_SKIPPING " [%s:%p]", dev_name(dev),
|
||||
dev_ext_name(dev), dev->ext.handle);
|
||||
if (dev_is_mpath_component(cmd, dev)) {
|
||||
log_debug_devs("%s: Skipping mpath component device", dev_name(dev));
|
||||
dev->filtered_flags |= DEV_FILTERED_MPATH_COMPONENT;
|
||||
return 0;
|
||||
}
|
||||
@@ -353,59 +37,33 @@ static int _ignore_mpath_component(struct cmd_context *cmd, struct dev_filter *f
|
||||
|
||||
static void _destroy(struct dev_filter *f)
|
||||
{
|
||||
struct mpath_priv *mp = (struct mpath_priv*) f->private;
|
||||
|
||||
if (f->use_count)
|
||||
log_error(INTERNAL_ERROR "Destroying mpath filter while in use %u times.", f->use_count);
|
||||
|
||||
dm_hash_destroy(mp->hash);
|
||||
dm_pool_destroy(mp->mem);
|
||||
}
|
||||
|
||||
struct dev_filter *mpath_filter_create(struct dev_types *dt)
|
||||
{
|
||||
struct dev_filter *f;
|
||||
const char *sysfs_dir = dm_sysfs_dir();
|
||||
struct mpath_priv *mp;
|
||||
struct dm_pool *mem;
|
||||
struct dm_hash_table *hash;
|
||||
|
||||
if (!*sysfs_dir) {
|
||||
log_verbose("No proc filesystem found: skipping multipath filter");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(hash = dm_hash_create(110))) {
|
||||
log_error("mpath hash table creation failed.");
|
||||
if (!(f = zalloc(sizeof(*f)))) {
|
||||
log_error("mpath filter allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(mem = dm_pool_create("mpath", 256))) {
|
||||
log_error("mpath pool creation failed.");
|
||||
dm_hash_destroy(hash);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(mp = dm_pool_zalloc(mem, sizeof(*mp)))) {
|
||||
log_error("mpath filter allocation failed.");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
mp->f.passes_filter = _ignore_mpath_component;
|
||||
mp->f.destroy = _destroy;
|
||||
mp->f.use_count = 0;
|
||||
mp->f.private = mp;
|
||||
mp->f.name = "mpath";
|
||||
mp->dt = dt;
|
||||
mp->mem = mem;
|
||||
mp->hash = hash;
|
||||
f->passes_filter = _ignore_mpath_component;
|
||||
f->destroy = _destroy;
|
||||
f->use_count = 0;
|
||||
f->name = "mpath";
|
||||
|
||||
log_debug_devs("mpath filter initialised.");
|
||||
|
||||
return &mp->f;
|
||||
bad:
|
||||
dm_pool_destroy(mem);
|
||||
dm_hash_destroy(hash);
|
||||
return NULL;
|
||||
return f;
|
||||
}
|
||||
|
||||
#else
|
||||
|
@@ -22,7 +22,6 @@
|
||||
|
||||
static int _passes_partitioned_filter(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
|
||||
{
|
||||
struct dev_types *dt = (struct dev_types *) f->private;
|
||||
int ret;
|
||||
|
||||
if (cmd->filter_nodata_only)
|
||||
@@ -30,7 +29,7 @@ static int _passes_partitioned_filter(struct cmd_context *cmd, struct dev_filter
|
||||
|
||||
dev->filtered_flags &= ~DEV_FILTERED_PARTITIONED;
|
||||
|
||||
ret = dev_is_partitioned(dt, dev);
|
||||
ret = dev_is_partitioned(cmd, dev);
|
||||
|
||||
if (ret == -EAGAIN) {
|
||||
/* let pass, call again after scan */
|
||||
@@ -72,7 +71,6 @@ struct dev_filter *partitioned_filter_create(struct dev_types *dt)
|
||||
f->passes_filter = _passes_partitioned_filter;
|
||||
f->destroy = _partitioned_filter_destroy;
|
||||
f->use_count = 0;
|
||||
f->private = dt;
|
||||
f->name = "partitioned";
|
||||
|
||||
log_debug_devs("Partitioned filter initialised.");
|
||||
|
@@ -16,10 +16,6 @@
|
||||
#include "lib/misc/lib.h"
|
||||
#include "lib/filters/filter.h"
|
||||
#include "lib/activate/activate.h"
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
#include <libudev.h>
|
||||
#include "lib/device/dev-ext-udev-constants.h"
|
||||
#endif
|
||||
|
||||
struct filter_data {
|
||||
filter_mode_t mode;
|
||||
@@ -28,7 +24,7 @@ struct filter_data {
|
||||
|
||||
static const char *_too_small_to_hold_pv_msg = "Too small to hold a PV";
|
||||
|
||||
static int _native_check_pv_min_size(struct device *dev)
|
||||
static int _check_pv_min_size(struct device *dev)
|
||||
{
|
||||
uint64_t size;
|
||||
int ret = 0;
|
||||
@@ -50,61 +46,6 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef UDEV_SYNC_SUPPORT
|
||||
static int _udev_check_pv_min_size(struct device *dev)
|
||||
{
|
||||
struct dev_ext *ext;
|
||||
const char *size_str;
|
||||
char *endp;
|
||||
uint64_t size;
|
||||
|
||||
if (!(ext = dev_ext_get(dev)))
|
||||
return_0;
|
||||
|
||||
if (!(size_str = udev_device_get_sysattr_value((struct udev_device *)ext->handle, DEV_EXT_UDEV_SYSFS_ATTR_SIZE))) {
|
||||
log_debug_devs("%s: Skipping: failed to get size from sysfs [%s:%p]",
|
||||
dev_name(dev), dev_ext_name(dev), dev->ext.handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
size = strtoull(size_str, &endp, 10);
|
||||
if (errno || !endp || *endp) {
|
||||
log_debug_devs("%s: Skipping: failed to parse size from sysfs [%s:%p]",
|
||||
dev_name(dev), dev_ext_name(dev), dev->ext.handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (size < pv_min_size()) {
|
||||
log_debug_devs("%s: Skipping: %s [%s:%p]", dev_name(dev),
|
||||
_too_small_to_hold_pv_msg,
|
||||
dev_ext_name(dev), dev->ext.handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
static int _udev_check_pv_min_size(struct device *dev)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int _check_pv_min_size(struct device *dev)
|
||||
{
|
||||
if (dev->ext.src == DEV_EXT_NONE)
|
||||
return _native_check_pv_min_size(dev);
|
||||
|
||||
if (dev->ext.src == DEV_EXT_UDEV)
|
||||
return _udev_check_pv_min_size(dev);
|
||||
|
||||
log_error(INTERNAL_ERROR "Missing hook for PV min size check "
|
||||
"using external device info source %s", dev_ext_name(dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _passes_usable_filter(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
|
||||
{
|
||||
struct filter_data *data = f->private;
|
||||
@@ -156,19 +97,9 @@ static int _passes_usable_filter(struct cmd_context *cmd, struct dev_filter *f,
|
||||
}
|
||||
|
||||
if (r) {
|
||||
/* check if the device is not too small to hold a PV */
|
||||
switch (mode) {
|
||||
case FILTER_MODE_NO_LVMETAD:
|
||||
/* fall through */
|
||||
case FILTER_MODE_PRE_LVMETAD:
|
||||
r = _check_pv_min_size(dev);
|
||||
if (!r)
|
||||
dev->filtered_flags |= DEV_FILTERED_MINSIZE;
|
||||
break;
|
||||
case FILTER_MODE_POST_LVMETAD:
|
||||
/* nothing to do here */
|
||||
break;
|
||||
}
|
||||
r = _check_pv_min_size(dev);
|
||||
if (!r)
|
||||
dev->filtered_flags |= DEV_FILTERED_MINSIZE;
|
||||
}
|
||||
|
||||
return r;
|
||||
|
@@ -20,7 +20,7 @@
|
||||
#include "lib/device/dev-cache.h"
|
||||
#include "lib/device/dev-type.h"
|
||||
|
||||
struct dev_filter *composite_filter_create(int n, int use_dev_ext_info, struct dev_filter **filters);
|
||||
struct dev_filter *composite_filter_create(int n, struct dev_filter **filters);
|
||||
|
||||
struct dev_filter *lvm_type_filter_create(struct dev_types *dt);
|
||||
struct dev_filter *md_filter_create(struct cmd_context *cmd, struct dev_types *dt);
|
||||
|
@@ -296,24 +296,11 @@ static struct raw_locn *_read_metadata_location_vg(struct cmd_context *cmd,
|
||||
const char *vgname,
|
||||
int *precommitted)
|
||||
{
|
||||
size_t len;
|
||||
char vgnamebuf[NAME_LEN + 2] __attribute__((aligned(8)));
|
||||
struct raw_locn *rlocn, *rlocn_precommitted;
|
||||
struct lvmcache_info *info;
|
||||
struct lvmcache_vgsummary vgsummary_orphan = {
|
||||
.vgname = FMT_TEXT_ORPHAN_VG_NAME,
|
||||
};
|
||||
int rlocn_was_ignored;
|
||||
|
||||
dm_list_init(&vgsummary_orphan.pvsummaries);
|
||||
|
||||
memcpy(&vgsummary_orphan.vgid, FMT_TEXT_ORPHAN_VG_NAME, sizeof(FMT_TEXT_ORPHAN_VG_NAME));
|
||||
|
||||
rlocn = mdah->raw_locns; /* Slot 0 */
|
||||
rlocn_precommitted = rlocn + 1; /* Slot 1 */
|
||||
|
||||
rlocn_was_ignored = rlocn_is_ignored(rlocn);
|
||||
|
||||
/* Should we use precommitted metadata? */
|
||||
if (*precommitted && rlocn_precommitted->size &&
|
||||
(rlocn_precommitted->offset != rlocn->offset)) {
|
||||
@@ -338,42 +325,7 @@ static struct raw_locn *_read_metadata_location_vg(struct cmd_context *cmd,
|
||||
if (!rlocn->offset && !rlocn->size)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Don't try to check existing metadata
|
||||
* if given vgname is an empty string.
|
||||
*/
|
||||
if (!vgname || !*vgname)
|
||||
return rlocn;
|
||||
|
||||
/*
|
||||
* If live rlocn has ignored flag, data will be out-of-date so skip further checks.
|
||||
*/
|
||||
if (rlocn_was_ignored)
|
||||
return rlocn;
|
||||
|
||||
/*
|
||||
* Verify that the VG metadata pointed to by the rlocn
|
||||
* begins with a valid vgname.
|
||||
*/
|
||||
memset(vgnamebuf, 0, sizeof(vgnamebuf));
|
||||
|
||||
if (!dev_read_bytes(dev_area->dev, dev_area->start + rlocn->offset, NAME_LEN, vgnamebuf))
|
||||
goto fail;
|
||||
|
||||
if (!strncmp(vgnamebuf, vgname, len = strlen(vgname)) &&
|
||||
(isspace(vgnamebuf[len]) || vgnamebuf[len] == '{'))
|
||||
return rlocn;
|
||||
fail:
|
||||
log_error("Metadata on %s at %llu has wrong VG name \"%s\" expected %s.",
|
||||
dev_name(dev_area->dev),
|
||||
(unsigned long long)(dev_area->start + rlocn->offset),
|
||||
vgnamebuf, vgname);
|
||||
|
||||
if ((info = lvmcache_info_from_pvid(dev_area->dev->pvid, dev_area->dev, 0)) &&
|
||||
!lvmcache_update_vgname_and_id(cmd, info, &vgsummary_orphan))
|
||||
stack;
|
||||
|
||||
return NULL;
|
||||
return rlocn;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -487,9 +439,13 @@ static struct volume_group *_vg_read_raw_area(struct cmd_context *cmd,
|
||||
rlocn->checksum,
|
||||
&when, &desc);
|
||||
|
||||
if (!vg) {
|
||||
/* FIXME: detect and handle errors, and distinguish from the optimization
|
||||
that skips parsing the metadata which also returns NULL. */
|
||||
if (!vg && !*use_previous_vg) {
|
||||
log_warn("WARNING: failed to read metadata text on %s at %llu size %llu for VG %s.",
|
||||
dev_name(area->dev),
|
||||
(unsigned long long)(area->start + rlocn->offset),
|
||||
(unsigned long long)rlocn->size,
|
||||
vgname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
log_debug_metadata("Found metadata on %s at %llu size %llu for VG %s",
|
||||
@@ -498,7 +454,7 @@ static struct volume_group *_vg_read_raw_area(struct cmd_context *cmd,
|
||||
(unsigned long long)rlocn->size,
|
||||
vgname);
|
||||
|
||||
if (vg && precommitted)
|
||||
if (precommitted)
|
||||
vg->status |= PRECOMMITTED;
|
||||
|
||||
out:
|
||||
@@ -1533,8 +1489,6 @@ int read_metadata_location_summary(const struct format_type *fmt,
|
||||
{
|
||||
struct raw_locn *rlocn;
|
||||
uint32_t wrap = 0;
|
||||
unsigned int len = 0;
|
||||
char namebuf[NAME_LEN + 1] __attribute__((aligned(8)));
|
||||
uint64_t max_size;
|
||||
|
||||
if (!mdah) {
|
||||
@@ -1563,28 +1517,6 @@ int read_metadata_location_summary(const struct format_type *fmt,
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(namebuf, 0, sizeof(namebuf));
|
||||
|
||||
if (!dev_read_bytes(dev_area->dev, dev_area->start + rlocn->offset, NAME_LEN, namebuf))
|
||||
stack;
|
||||
|
||||
while (namebuf[len] && !isspace(namebuf[len]) && namebuf[len] != '{' &&
|
||||
len < (NAME_LEN - 1))
|
||||
len++;
|
||||
|
||||
namebuf[len] = '\0';
|
||||
|
||||
/*
|
||||
* Check that the text metadata in the circular buffer begins with a
|
||||
* valid vg name.
|
||||
*/
|
||||
if (!validate_name(namebuf)) {
|
||||
log_warn("WARNING: Metadata location on %s at %llu begins with invalid VG name.",
|
||||
dev_name(dev_area->dev),
|
||||
(unsigned long long)(dev_area->start + rlocn->offset));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is used to read the vg summary during label scan.
|
||||
* Save the text start location and checksum during scan. After the VG
|
||||
@@ -1646,9 +1578,7 @@ int read_metadata_location_summary(const struct format_type *fmt,
|
||||
vgsummary->mda_size = rlocn->size;
|
||||
|
||||
/* Keep track of largest metadata size we find. */
|
||||
lvmcache_save_metadata_size_bytes(rlocn->size);
|
||||
/* Keep track of the most full metadata area. */
|
||||
lvmcache_save_metadata_size_percent(rlocn->size, mdah->size);
|
||||
lvmcache_save_metadata_size(rlocn->size);
|
||||
|
||||
lvmcache_lookup_mda(vgsummary);
|
||||
|
||||
|
@@ -327,6 +327,9 @@ static int _read_mda_header_and_metadata(const struct format_type *fmt,
|
||||
{
|
||||
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
||||
struct mda_header *mdah;
|
||||
int retries = 0;
|
||||
|
||||
retry:
|
||||
|
||||
if (!(mdah = raw_read_mda_header(fmt, &mdac->area, (mda->mda_num == 1), 0, bad_fields))) {
|
||||
log_warn("WARNING: bad metadata header on %s at %llu.",
|
||||
@@ -354,6 +357,38 @@ static int _read_mda_header_and_metadata(const struct format_type *fmt,
|
||||
if (vgsummary->zero_offset)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* This code is used by label_scan to get a summary of the
|
||||
* VG metadata that will be properly read later by vg_read.
|
||||
* The initial read of this device during label_scan
|
||||
* populates bcache with the first 128K of data from the
|
||||
* device. That block of data contains the mda_header
|
||||
* (at 4k) but will often not include the metadata text,
|
||||
* which is often located further into the metadata area
|
||||
* (beyond the 128K block saved in bcache.)
|
||||
* So read_metadata_location_summary will usually get the
|
||||
* mda_header from bcache which was read initially, and
|
||||
* then it will often need to do a new disk read to get
|
||||
* the actual metadata text that the mda_header points to.
|
||||
* Since there is no locking around label_scan, it's
|
||||
* possible (but very rare) that the entire metadata area
|
||||
* can be rewritten by other commands between the time that
|
||||
* this command read the mda_header and the time that it
|
||||
* reads the metadata text. This means the expected metadata
|
||||
* text isn't found, and an error is returned here.
|
||||
* To handle this, invalidate all data in bcache for this
|
||||
* device and reread the mda_header and metadata text back to
|
||||
* back, so inconsistency is less likely (without locking
|
||||
* there's no guarantee, e.g. if the command is blocked
|
||||
* somehow between the two reads.)
|
||||
*/
|
||||
if (!retries) {
|
||||
log_print("Retrying metadata scan.");
|
||||
retries++;
|
||||
dev_invalidate(mdac->area.dev);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
log_warn("WARNING: bad metadata text on %s in mda%d",
|
||||
dev_name(mdac->area.dev), mda->mda_num);
|
||||
*bad_fields |= BAD_MDA_TEXT;
|
||||
|
@@ -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
|
||||
@@ -1288,14 +1394,12 @@ check:
|
||||
*/
|
||||
|
||||
int get_hints(struct cmd_context *cmd, struct dm_list *hints_out, int *newhints,
|
||||
struct dm_list *devs_in, struct dm_list *devs_out, char **vgname_out)
|
||||
struct dm_list *devs_in, struct dm_list *devs_out)
|
||||
{
|
||||
struct dm_list hints_list;
|
||||
int needs_refresh = 0;
|
||||
char *vgname = NULL;
|
||||
|
||||
*vgname_out = NULL;
|
||||
|
||||
dm_list_init(&hints_list);
|
||||
|
||||
/* Decide below if the caller should create new hints. */
|
||||
@@ -1322,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.
|
||||
@@ -1435,7 +1548,7 @@ int get_hints(struct cmd_context *cmd, struct dm_list *hints_out, int *newhints,
|
||||
|
||||
dm_list_splice(hints_out, &hints_list);
|
||||
|
||||
*vgname_out = vgname;
|
||||
free(vgname);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@@ -33,7 +33,7 @@ void clear_hint_file(struct cmd_context *cmd);
|
||||
void invalidate_hints(struct cmd_context *cmd);
|
||||
|
||||
int get_hints(struct cmd_context *cmd, struct dm_list *hints, int *newhints,
|
||||
struct dm_list *devs_in, struct dm_list *devs_out, char **vgname_out);
|
||||
struct dm_list *devs_in, struct dm_list *devs_out);
|
||||
|
||||
int validate_hints(struct cmd_context *cmd, struct dm_list *hints);
|
||||
|
||||
|
@@ -264,9 +264,8 @@ static bool _in_bcache(struct device *dev)
|
||||
}
|
||||
|
||||
static struct labeller *_find_lvm_header(struct device *dev,
|
||||
char *scan_buf,
|
||||
uint32_t scan_buf_sectors,
|
||||
char *label_buf,
|
||||
char *headers_buf,
|
||||
int headers_buf_size,
|
||||
uint64_t *label_sector,
|
||||
uint64_t block_sector,
|
||||
uint64_t start_sector)
|
||||
@@ -277,24 +276,13 @@ static struct labeller *_find_lvm_header(struct device *dev,
|
||||
uint64_t sector;
|
||||
int found = 0;
|
||||
|
||||
/*
|
||||
* Find which sector in scan_buf starts with a valid label,
|
||||
* and copy it into label_buf.
|
||||
*/
|
||||
|
||||
for (sector = start_sector; sector < start_sector + LABEL_SCAN_SECTORS;
|
||||
sector += LABEL_SIZE >> SECTOR_SHIFT) {
|
||||
|
||||
/*
|
||||
* The scan_buf passed in is a bcache block, which is
|
||||
* BCACHE_BLOCK_SIZE_IN_SECTORS large. So if start_sector is
|
||||
* one of the last couple sectors in that buffer, we need to
|
||||
* break early.
|
||||
*/
|
||||
if (sector >= scan_buf_sectors)
|
||||
if ((sector * 512) >= headers_buf_size)
|
||||
break;
|
||||
|
||||
lh = (struct label_header *) (scan_buf + (sector << SECTOR_SHIFT));
|
||||
lh = (struct label_header *) (headers_buf + (sector << SECTOR_SHIFT));
|
||||
|
||||
if (!memcmp(lh->id, LABEL_ID, sizeof(lh->id))) {
|
||||
if (found) {
|
||||
@@ -332,7 +320,6 @@ static struct labeller *_find_lvm_header(struct device *dev,
|
||||
labeller_ret = li->l;
|
||||
found = 1;
|
||||
|
||||
memcpy(label_buf, lh, LABEL_SIZE);
|
||||
if (label_sector)
|
||||
*label_sector = block_sector + sector;
|
||||
break;
|
||||
@@ -354,13 +341,13 @@ static struct labeller *_find_lvm_header(struct device *dev,
|
||||
* are performed in the processing functions to get that data.
|
||||
*/
|
||||
static int _process_block(struct cmd_context *cmd, struct dev_filter *f,
|
||||
struct device *dev, struct block *bb,
|
||||
struct device *dev, char *headers_buf, int headers_buf_size,
|
||||
uint64_t block_sector, uint64_t start_sector,
|
||||
int *is_lvm_device)
|
||||
{
|
||||
char label_buf[LABEL_SIZE] __attribute__((aligned(8)));
|
||||
char *label_buf;
|
||||
struct labeller *labeller;
|
||||
uint64_t sector = 0;
|
||||
uint64_t label_sector = 0;
|
||||
int is_duplicate = 0;
|
||||
int ret = 0;
|
||||
|
||||
@@ -396,13 +383,9 @@ static int _process_block(struct cmd_context *cmd, struct dev_filter *f,
|
||||
}
|
||||
|
||||
/*
|
||||
* Finds the data sector containing the label and copies into label_buf.
|
||||
* label_buf: struct label_header + struct pv_header + struct pv_header_extension
|
||||
*
|
||||
* FIXME: we don't need to copy one sector from bb->data into label_buf,
|
||||
* we can just point label_buf at one sector in ld->buf.
|
||||
* Finds the data sector containing the label.
|
||||
*/
|
||||
if (!(labeller = _find_lvm_header(dev, bb->data, BCACHE_BLOCK_SIZE_IN_SECTORS, label_buf, §or, block_sector, start_sector))) {
|
||||
if (!(labeller = _find_lvm_header(dev, headers_buf, headers_buf_size, &label_sector, block_sector, start_sector))) {
|
||||
|
||||
/*
|
||||
* Non-PVs exit here
|
||||
@@ -427,6 +410,7 @@ static int _process_block(struct cmd_context *cmd, struct dev_filter *f,
|
||||
|
||||
dev->flags |= DEV_SCAN_FOUND_LABEL;
|
||||
*is_lvm_device = 1;
|
||||
label_buf = headers_buf + (label_sector * 512);
|
||||
|
||||
/*
|
||||
* This is the point where the scanning code dives into the rest of
|
||||
@@ -436,7 +420,7 @@ static int _process_block(struct cmd_context *cmd, struct dev_filter *f,
|
||||
* info/vginfo structs. That lvmcache info is used later when the
|
||||
* command wants to read the VG to do something to it.
|
||||
*/
|
||||
ret = labeller->ops->read(cmd, labeller, dev, label_buf, sector, &is_duplicate);
|
||||
ret = labeller->ops->read(cmd, labeller, dev, label_buf, label_sector, &is_duplicate);
|
||||
|
||||
if (!ret) {
|
||||
if (is_duplicate) {
|
||||
@@ -670,9 +654,12 @@ static void _invalidate_di(struct bcache *cache, int di)
|
||||
* its info is removed from lvmcache.
|
||||
*/
|
||||
|
||||
#define HEADERS_BUF_SIZE 4096
|
||||
|
||||
static int _scan_list(struct cmd_context *cmd, struct dev_filter *f,
|
||||
struct dm_list *devs, int want_other_devs, int *failed)
|
||||
{
|
||||
char headers_buf[HEADERS_BUF_SIZE];
|
||||
struct dm_list wait_devs;
|
||||
struct dm_list done_devs;
|
||||
struct dm_list reopen_devs;
|
||||
@@ -738,14 +725,35 @@ static int _scan_list(struct cmd_context *cmd, struct dev_filter *f,
|
||||
scan_read_errors++;
|
||||
scan_failed_count++;
|
||||
lvmcache_del_dev(devl->dev);
|
||||
if (bb)
|
||||
bcache_put(bb);
|
||||
} else {
|
||||
log_debug_devs("Processing data from device %s %d:%d di %d block %p",
|
||||
/* copy the first 4k from bb that will contain label_header */
|
||||
|
||||
memcpy(headers_buf, bb->data, HEADERS_BUF_SIZE);
|
||||
|
||||
/*
|
||||
* "put" the bcache block before process_block because
|
||||
* processing metadata may need to invalidate and reread
|
||||
* metadata that's covered by bb. invalidate/reread is
|
||||
* not allowed while bb is held. The functions for
|
||||
* filtering and scanning metadata for this device use
|
||||
* dev_read_bytes(), which will generally grab the
|
||||
* bcache block/data that we're putting here. Since
|
||||
* we're doing put, it's possible but not likely that
|
||||
* bcache could drop the block before dev_read_bytes()
|
||||
* uses it again, in which case bcache will reread it
|
||||
* from disk for dev_read_bytes().
|
||||
*/
|
||||
bcache_put(bb);
|
||||
|
||||
log_debug_devs("Processing data from device %s %d:%d di %d",
|
||||
dev_name(devl->dev),
|
||||
(int)MAJOR(devl->dev->dev),
|
||||
(int)MINOR(devl->dev->dev),
|
||||
devl->dev->bcache_di, (void *)bb);
|
||||
devl->dev->bcache_di);
|
||||
|
||||
ret = _process_block(cmd, f, devl->dev, bb, 0, 0, &is_lvm_device);
|
||||
ret = _process_block(cmd, f, devl->dev, headers_buf, sizeof(headers_buf), 0, 0, &is_lvm_device);
|
||||
|
||||
if (!ret && is_lvm_device) {
|
||||
log_debug_devs("Scan failed to process %s", dev_name(devl->dev));
|
||||
@@ -754,9 +762,6 @@ static int _scan_list(struct cmd_context *cmd, struct dev_filter *f,
|
||||
}
|
||||
}
|
||||
|
||||
if (bb)
|
||||
bcache_put(bb);
|
||||
|
||||
/*
|
||||
* Keep the bcache block of lvm devices we have processed so
|
||||
* that the vg_read phase can reuse it. If bcache failed to
|
||||
@@ -1032,7 +1037,6 @@ int label_scan(struct cmd_context *cmd)
|
||||
struct dev_iter *iter;
|
||||
struct device_list *devl, *devl2;
|
||||
struct device *dev;
|
||||
char *vgname_hint = NULL;
|
||||
uint64_t max_metadata_size_bytes;
|
||||
int device_ids_invalid = 0;
|
||||
int using_hints;
|
||||
@@ -1138,54 +1142,21 @@ int label_scan(struct cmd_context *cmd)
|
||||
* by using hints which tell us which devices are PVs, which
|
||||
* are the only devices we actually need to scan. Without
|
||||
* hints we need to scan all devs to find which are PVs.
|
||||
*/
|
||||
if (!get_hints(cmd, &hints_list, &create_hints, &all_devs, &scan_devs, &vgname_hint)) {
|
||||
dm_list_splice(&scan_devs, &all_devs);
|
||||
dm_list_init(&hints_list);
|
||||
using_hints = 0;
|
||||
} else
|
||||
using_hints = 1;
|
||||
|
||||
/*
|
||||
* If the command is using hints and a single vgname
|
||||
*
|
||||
* TODO: if the command is using hints and a single vgname
|
||||
* arg, we can also take the vg lock here, prior to scanning.
|
||||
* This means we would not need to rescan the PVs in the VG
|
||||
* in vg_read (skip lvmcache_label_rescan_vg) after the
|
||||
* vg lock is usually taken. (Some commands are already
|
||||
* able to avoid rescan in vg_read, but locking early would
|
||||
* apply to more cases.)
|
||||
*
|
||||
* TODO: we don't know exactly which vg lock mode (read or write)
|
||||
* the command will use in vg_read() for the normal lock_vol(),
|
||||
* but we could make a fairly accurate guess of READ/WRITE based
|
||||
* on looking at the command name. If we guess wrong we can
|
||||
* just unlock_vg and lock_vol again with the correct mode in
|
||||
* vg_read().
|
||||
*/
|
||||
if (vgname_hint) {
|
||||
uint32_t lck_type = LCK_VG_WRITE;
|
||||
|
||||
log_debug("Early lock vg");
|
||||
|
||||
/* FIXME: borrowing this lockd flag which should be
|
||||
quite close to what we want, based on the command name.
|
||||
Need to do proper mode selection here, and then check
|
||||
in case the later lock_vol in vg_read wants different. */
|
||||
if (cmd->lockd_vg_default_sh)
|
||||
lck_type = LCK_VG_READ;
|
||||
|
||||
if (!lock_vol(cmd, vgname_hint, lck_type, NULL)) {
|
||||
log_warn("Could not pre-lock VG %s.", vgname_hint);
|
||||
/* not an error since this is just an optimization */
|
||||
} else {
|
||||
/* Save some state indicating that the vg lock
|
||||
is already held so that the normal lock_vol()
|
||||
will know. */
|
||||
cmd->early_lock_vg_mode = lck_type;
|
||||
}
|
||||
|
||||
free(vgname_hint);
|
||||
}
|
||||
if (!get_hints(cmd, &hints_list, &create_hints, &all_devs, &scan_devs)) {
|
||||
dm_list_splice(&scan_devs, &all_devs);
|
||||
dm_list_init(&hints_list);
|
||||
using_hints = 0;
|
||||
} else
|
||||
using_hints = 1;
|
||||
|
||||
/*
|
||||
* If the total number of devices exceeds the soft open file
|
||||
@@ -1221,7 +1192,7 @@ int label_scan(struct cmd_context *cmd)
|
||||
* If the largest metadata is within 1MB of the bcache size, then start
|
||||
* warning.
|
||||
*/
|
||||
max_metadata_size_bytes = lvmcache_max_metadata_size_bytes();
|
||||
max_metadata_size_bytes = lvmcache_max_metadata_size();
|
||||
|
||||
if (max_metadata_size_bytes + (1024 * 1024) > _current_bcache_size_bytes) {
|
||||
/* we want bcache to be 1MB larger than the max metadata seen */
|
||||
@@ -1236,14 +1207,6 @@ int label_scan(struct cmd_context *cmd)
|
||||
(unsigned long long)want_size_kb);
|
||||
}
|
||||
|
||||
/*
|
||||
* If vg metadata is using a large percentage of a metadata area, then
|
||||
* create /run/lvm/scan_lock_global to tell future lvm commands to
|
||||
* begin doing lock_global() prior to scanning to avoid problems due to
|
||||
* metadata wrapping between label_scan and vg_read.
|
||||
*/
|
||||
set_scan_lock_global(cmd);
|
||||
|
||||
dm_list_init(&cmd->hints);
|
||||
|
||||
/*
|
||||
@@ -1741,6 +1704,11 @@ bool dev_invalidate_bytes(struct device *dev, uint64_t start, size_t len)
|
||||
return bcache_invalidate_bytes(scan_bcache, dev->bcache_di, start, len);
|
||||
}
|
||||
|
||||
void dev_invalidate(struct device *dev)
|
||||
{
|
||||
bcache_invalidate_di(scan_bcache, dev->bcache_di);
|
||||
}
|
||||
|
||||
bool dev_write_zeros(struct device *dev, uint64_t start, size_t len)
|
||||
{
|
||||
return dev_set_bytes(dev, start, len, 0);
|
||||
|
@@ -130,6 +130,7 @@ bool dev_write_bytes(struct device *dev, uint64_t start, size_t len, void *data)
|
||||
bool dev_write_zeros(struct device *dev, uint64_t start, size_t len);
|
||||
bool dev_set_bytes(struct device *dev, uint64_t start, size_t len, uint8_t val);
|
||||
bool dev_invalidate_bytes(struct device *dev, uint64_t start, size_t len);
|
||||
void dev_invalidate(struct device *dev);
|
||||
void dev_set_last_byte(struct device *dev, uint64_t offset);
|
||||
void dev_unset_last_byte(struct device *dev);
|
||||
|
||||
|
@@ -203,11 +203,6 @@ int lock_vol(struct cmd_context *cmd, const char *vol, uint32_t flags, const str
|
||||
if (is_orphan_vg(vol))
|
||||
return 1;
|
||||
|
||||
if (!is_global && cmd->early_lock_vg_mode && (lck_type != LCK_UNLOCK)) {
|
||||
log_debug("VG was locked early.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!_blocking_supported)
|
||||
flags |= LCK_NONBLOCK;
|
||||
|
||||
@@ -359,8 +354,10 @@ static int _lockf_global(struct cmd_context *cmd, const char *mode, int convert,
|
||||
if (!strcmp(mode, "ex")) {
|
||||
flags |= LCK_WRITE;
|
||||
|
||||
if (cmd->lockf_global_ex)
|
||||
if (cmd->lockf_global_ex) {
|
||||
log_warn("global flock already held ex");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = lock_vol(cmd, VG_GLOBAL, flags, NULL);
|
||||
if (ret)
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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.
|
||||
|
@@ -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);
|
||||
|
@@ -8739,7 +8739,8 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
}
|
||||
|
||||
if (seg_is_vdo_pool(lp)) {
|
||||
if (!convert_vdo_pool_lv(lv, &lp->vdo_params, &lp->virtual_extents, 1)) {
|
||||
if (!convert_vdo_pool_lv(lv, &lp->vdo_params, &lp->virtual_extents,
|
||||
1, lp->vdo_pool_header_size)) {
|
||||
stack;
|
||||
goto deactivate_and_revert_new_lv;
|
||||
}
|
||||
|
@@ -1034,6 +1034,7 @@ struct lvcreate_params {
|
||||
int approx_alloc; /* all */
|
||||
alloc_policy_t alloc; /* all */
|
||||
struct dm_vdo_target_params vdo_params; /* vdo */
|
||||
uint64_t vdo_pool_header_size; /* VDO */
|
||||
|
||||
int raidintegrity;
|
||||
const char *raidintegritymode;
|
||||
@@ -1368,10 +1369,12 @@ int parse_vdo_pool_status(struct dm_pool *mem, const struct logical_volume *vdo_
|
||||
struct logical_volume *convert_vdo_pool_lv(struct logical_volume *data_lv,
|
||||
const struct dm_vdo_target_params *vtp,
|
||||
uint32_t *virtual_extents,
|
||||
int format);
|
||||
int format,
|
||||
uint64_t vdo_pool_header_size);
|
||||
int set_vdo_write_policy(enum dm_vdo_write_policy *vwp, const char *policy);
|
||||
int fill_vdo_target_params(struct cmd_context *cmd,
|
||||
struct dm_vdo_target_params *vtp,
|
||||
uint64_t *vdo_pool_header_size,
|
||||
struct profile *profile);
|
||||
/* -- metadata/vdo_manip.c */
|
||||
|
||||
|
@@ -5132,7 +5132,8 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name, const
|
||||
if (!check_pv_dev_sizes(vg))
|
||||
log_warn("WARNING: One or more devices used as PVs in VG %s have changed sizes.", vg->name);
|
||||
|
||||
_check_devs_used_correspond_with_vg(vg);
|
||||
if (cmd->check_devs_used)
|
||||
_check_devs_used_correspond_with_vg(vg);
|
||||
|
||||
if (!_access_vg_lock_type(cmd, vg, lockd_state, &failure)) {
|
||||
/* Either FAILED_LOCK_TYPE or FAILED_LOCK_MODE were set. */
|
||||
@@ -5278,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;
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -356,9 +356,9 @@ static int _format_vdo_pool_data_lv(struct logical_volume *data_lv,
|
||||
struct logical_volume *convert_vdo_pool_lv(struct logical_volume *data_lv,
|
||||
const struct dm_vdo_target_params *vtp,
|
||||
uint32_t *virtual_extents,
|
||||
int format)
|
||||
int format,
|
||||
uint64_t vdo_pool_header_size)
|
||||
{
|
||||
const uint64_t header_size = DEFAULT_VDO_POOL_HEADER_SIZE;
|
||||
const uint32_t extent_size = data_lv->vg->extent_size;
|
||||
struct cmd_context *cmd = data_lv->vg->cmd;
|
||||
struct logical_volume *vdo_pool_lv = data_lv;
|
||||
@@ -379,7 +379,7 @@ struct logical_volume *convert_vdo_pool_lv(struct logical_volume *data_lv,
|
||||
|
||||
if (*virtual_extents)
|
||||
vdo_logical_size =
|
||||
_get_virtual_size(*virtual_extents, extent_size, header_size);
|
||||
_get_virtual_size(*virtual_extents, extent_size, vdo_pool_header_size);
|
||||
|
||||
if (!dm_vdo_validate_target_params(vtp, vdo_logical_size))
|
||||
return_0;
|
||||
@@ -393,7 +393,8 @@ struct logical_volume *convert_vdo_pool_lv(struct logical_volume *data_lv,
|
||||
} else {
|
||||
log_verbose("Skiping VDO formating %s.", display_lvname(data_lv));
|
||||
/* TODO: parse existing VDO data and retrieve vdo_logical_size */
|
||||
vdo_logical_size = data_lv->size;
|
||||
if (!*virtual_extents)
|
||||
vdo_logical_size = data_lv->size;
|
||||
}
|
||||
|
||||
if (!deactivate_lv(data_lv->vg->cmd, data_lv)) {
|
||||
@@ -402,7 +403,7 @@ struct logical_volume *convert_vdo_pool_lv(struct logical_volume *data_lv,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vdo_logical_size -= 2 * header_size;
|
||||
vdo_logical_size -= 2 * vdo_pool_header_size;
|
||||
|
||||
if (vdo_logical_size < extent_size) {
|
||||
if (!*virtual_extents)
|
||||
@@ -425,7 +426,7 @@ struct logical_volume *convert_vdo_pool_lv(struct logical_volume *data_lv,
|
||||
vdo_pool_seg = first_seg(vdo_pool_lv);
|
||||
vdo_pool_seg->segtype = vdo_pool_segtype;
|
||||
vdo_pool_seg->vdo_params = *vtp;
|
||||
vdo_pool_seg->vdo_pool_header_size = DEFAULT_VDO_POOL_HEADER_SIZE;
|
||||
vdo_pool_seg->vdo_pool_header_size = vdo_pool_header_size;
|
||||
vdo_pool_seg->vdo_pool_virtual_extents = *virtual_extents;
|
||||
|
||||
vdo_pool_lv->status |= LV_VDO_POOL;
|
||||
@@ -452,6 +453,7 @@ int set_vdo_write_policy(enum dm_vdo_write_policy *vwp, const char *policy)
|
||||
|
||||
int fill_vdo_target_params(struct cmd_context *cmd,
|
||||
struct dm_vdo_target_params *vtp,
|
||||
uint64_t *vdo_pool_header_size,
|
||||
struct profile *profile)
|
||||
{
|
||||
const char *policy;
|
||||
@@ -500,5 +502,7 @@ int fill_vdo_target_params(struct cmd_context *cmd,
|
||||
if (!set_vdo_write_policy(&vtp->write_policy, policy))
|
||||
return_0;
|
||||
|
||||
*vdo_pool_header_size = 2 * find_config_tree_int64(cmd, allocation_vdo_pool_header_size_CFG, profile);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@@ -25,19 +25,29 @@ struct udev *_udev;
|
||||
int udev_init_library_context(void)
|
||||
{
|
||||
if (_udev)
|
||||
udev_unref(_udev);
|
||||
return 1;
|
||||
|
||||
if (getenv("DM_DISABLE_UDEV"))
|
||||
return 0;
|
||||
|
||||
if (!(_udev = udev_new())) {
|
||||
log_error("Failed to create udev library context.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!udev_is_running()) {
|
||||
udev_unref(_udev);
|
||||
_udev = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void udev_fin_library_context(void)
|
||||
{
|
||||
udev_unref(_udev);
|
||||
if (_udev)
|
||||
udev_unref(_udev);
|
||||
_udev = NULL;
|
||||
}
|
||||
|
||||
|
@@ -23,6 +23,7 @@ else
|
||||
endif
|
||||
|
||||
FSADMMAN = fsadm.8
|
||||
VDOIMPORTMAN = vdoimport.8
|
||||
BLKDEACTIVATEMAN = blkdeactivate.8
|
||||
DMEVENTDMAN = dmeventd.8
|
||||
DMFILEMAPDMAN = dmfilemapd.8
|
||||
@@ -50,7 +51,7 @@ MAN8SYSTEMD_GENERATORS=lvm2-activation-generator.8
|
||||
|
||||
ifeq (,$(findstring $(MAKECMDGOALS), distclean all_man install_all_man))
|
||||
MAN7 += lvmcache.7 lvmthin.7 lvmvdo.7
|
||||
MAN8+=$(FSADMMAN) $(LVMPOLLDMAN) $(LVMLOCKDMAN) $(LVMDBUSDMAN)
|
||||
MAN8+=$(FSADMMAN) $(LVMPOLLDMAN) $(LVMLOCKDMAN) $(LVMDBUSDMAN) $(VDOIMPORTMAN)
|
||||
MAN8DM+=$(BLKDEACTIVATEMAN) $(DMEVENTDMAN) $(DMFILEMAPDMAN)
|
||||
MAN8CLUSTER+=$(CMIRRORDMAN)
|
||||
else
|
||||
@@ -58,6 +59,10 @@ else
|
||||
MAN8+=$(FSADMMAN)
|
||||
endif
|
||||
|
||||
ifeq ("@VDOIMPORT@", "yes")
|
||||
MAN8+=$(VDOIMPORTMAN)
|
||||
endif
|
||||
|
||||
ifeq ("@BUILD_LVMDBUSD@", "yes")
|
||||
MAN8+=$(LVMDBUSDMAN)
|
||||
endif
|
||||
|
@@ -670,7 +670,7 @@ Convert LV to type thin-pool.
|
||||
.RE
|
||||
.P
|
||||
.RS 4
|
||||
LV1 types: linear striped cache raid error zero
|
||||
LV1 types: linear striped cache raid error zero writecache
|
||||
.RE
|
||||
.P
|
||||
\(em
|
||||
|
@@ -27,6 +27,8 @@ lvmdevices \(em Manage the devices file
|
||||
\fB--deldev\fP \fIPV\fP
|
||||
.br
|
||||
\fB--delpvid\fP \fIString\fP
|
||||
.br
|
||||
\fB--deviceidtype\fP \fIString\fP
|
||||
.br
|
||||
\fB--devices\fP \fIPV\fP
|
||||
.br
|
||||
@@ -70,18 +72,18 @@ remove it from the devices file with lvmdevices --deldev. The
|
||||
vgimportdevices(8) command adds all PVs from a VG to the devices file,
|
||||
and updates the VG metadata to include device IDs of the PVs.
|
||||
.P
|
||||
Commands adding new devices to the devices file necessarily look outside
|
||||
the existing devices file to find the devices to add. pvcreate, vgcreate,
|
||||
and vgextend also look outside the devices file to create new PVs and add
|
||||
them to the devices file.
|
||||
Commands that add new devices to the devices file necessarily look outside
|
||||
the existing devices file to find the devices being added. pvcreate,
|
||||
vgcreate, and vgextend also look outside the devices file to create new
|
||||
PVs and add those PVs to the devices file.
|
||||
.P
|
||||
LVM records devices in the devices file using hardware-specific IDs, such
|
||||
as the WWID, and attempts to use subsystem-specific IDs for virtual device
|
||||
types (which also aim to be as unique and stable as possible.)
|
||||
These device IDs are also written in the VG metadata. When no hardware or
|
||||
types (which also aim to be as unique and stable as possible.) These
|
||||
device IDs are also written in the VG metadata. When no hardware or
|
||||
virtual ID is available, lvm falls back using the unstable device name as
|
||||
the device ID. When devnames are used, lvm performs extra scanning to
|
||||
find devices if their devname changes, e.g. after reboot.
|
||||
the device ID. When devnames are used as IDs, lvm performs extra scanning
|
||||
to find devices if their devname changes, e.g. after reboot.
|
||||
.P
|
||||
When proper device IDs are used, an lvm command will not look at devices
|
||||
outside the devices file, but when devnames are used as a fallback, lvm
|
||||
@@ -95,12 +97,13 @@ overriding the devices file. The listed devices act as a sort of devices
|
||||
file in terms of limiting which devices lvm will see and use. Devices
|
||||
that are not listed will appear to be missing to the lvm command.
|
||||
.P
|
||||
Multiple devices files can be kept in \fI#DEFAULT_SYS_DIR#/devices\fP, which allows lvm
|
||||
to be used with different sets of devices, e.g. system devices do not need
|
||||
to be exposed to a specific application, and the application can use lvm on
|
||||
its own devices that are not exposed to the system. The option
|
||||
--devicesfile <filename> is used to select the devices file to use with the
|
||||
command. Without the option set, the default system devices file is used.
|
||||
Multiple devices files can be kept \fI#DEFAULT_SYS_DIR#/devices\fP, which
|
||||
allows lvm to be used with different sets of devices. For example, system
|
||||
devices do not need to be exposed to a specific application, and the
|
||||
application can use lvm on its own devices that are not exposed to the
|
||||
system. The option --devicesfile <filename> is used to select the devices
|
||||
file to use with the command. Without the option set, the default system
|
||||
devices file is used.
|
||||
.P
|
||||
Setting --devicesfile "" causes lvm to not use a devices file.
|
||||
.P
|
||||
@@ -120,6 +123,45 @@ if it does not yet exist.
|
||||
.P
|
||||
It is recommended to use lvm commands to make changes to the devices file to
|
||||
ensure proper updates.
|
||||
.P
|
||||
The device ID and device ID type are included in the VG metadata and can
|
||||
be reported with pvs -o deviceid,deviceidtype. (Note that the lvmdevices
|
||||
command does not update VG metadata, but subsequent lvm commands modifying
|
||||
the metadata will include the device ID.)
|
||||
.P
|
||||
Possible device ID types are:
|
||||
.br
|
||||
.IP \[bu] 2
|
||||
.B sys_wwid
|
||||
uses the wwid reported by sysfs. This is the first choice for non-virtual
|
||||
devices.
|
||||
.IP \[bu] 2
|
||||
.B sys_serial
|
||||
uses the serial number reported by sysfs. This is the second choice for
|
||||
non-virtual devices.
|
||||
.IP \[bu] 2
|
||||
.B mpath_uuid
|
||||
is used for dm multipath devices, reported by sysfs.
|
||||
.IP \[bu] 2
|
||||
.B crypt_uuid
|
||||
is used for dm crypt devices, reported by sysfs.
|
||||
.IP \[bu] 2
|
||||
.B md_uuid
|
||||
is used for md devices, reported by sysfs.
|
||||
.B lvmlv_uuid
|
||||
is used if a PV is placed on top of an lvm LV, reported by sysfs.
|
||||
.IP \[bu] 2
|
||||
.B loop_file
|
||||
is used for loop devices, the backing file name repored by sysfs.
|
||||
.IP \[bu] 2
|
||||
.B devname
|
||||
the device name is used if no other type applies.
|
||||
.P
|
||||
|
||||
The default choice for device ID type can be overriden using lvmdevices
|
||||
--addev --deviceidtype <type>. If the specified type is available for the
|
||||
device it will be used, otherwise the device will be added using the type
|
||||
that would otherwise be chosen.
|
||||
.
|
||||
.SH USAGE
|
||||
.
|
||||
@@ -169,6 +211,8 @@ Add a device to the devices file.
|
||||
.br
|
||||
.RS 4
|
||||
.ad l
|
||||
[ \fB--deviceidtype\fP \fIString\fP ]
|
||||
.br
|
||||
[ COMMON_OPTIONS ]
|
||||
.ad b
|
||||
.RE
|
||||
@@ -214,13 +258,6 @@ Remove the devices file entry for the given PVID.
|
||||
.P
|
||||
\(em
|
||||
.P
|
||||
Common options for command:
|
||||
.
|
||||
.RS 4
|
||||
.ad l
|
||||
.ad b
|
||||
.RE
|
||||
.P
|
||||
Common options for lvm:
|
||||
.
|
||||
.RS 4
|
||||
@@ -308,6 +345,13 @@ Remove a device from the devices file.
|
||||
Remove a device with the PVID from the devices file.
|
||||
.
|
||||
.HP
|
||||
\fB--deviceidtype\fP \fIString\fP
|
||||
.br
|
||||
The type of device ID to use for the device.
|
||||
If the specified type is available for the device,
|
||||
then it will override the default type that lvm would use.
|
||||
.
|
||||
.HP
|
||||
\fB--devices\fP \fIPV\fP
|
||||
.br
|
||||
Devices that the command can use. This option can be repeated
|
||||
|
@@ -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
|
||||
|
92
man/vdoimport.8_main
Normal file
92
man/vdoimport.8_main
Normal file
@@ -0,0 +1,92 @@
|
||||
.TH "FSADM" "8" "LVM TOOLS #VERSION#" "Red Hat, Inc" "\""
|
||||
.
|
||||
.SH "NAME"
|
||||
.
|
||||
vdoimport \(em utility to import VDO volumes into a new volume group.
|
||||
.
|
||||
.SH SYNOPSIS
|
||||
.
|
||||
.PD 0
|
||||
.ad l
|
||||
.TP 10
|
||||
.B vdoimport
|
||||
.RI [ options ]
|
||||
.IR device
|
||||
.
|
||||
.PD
|
||||
.
|
||||
.SH DESCRIPTION
|
||||
.
|
||||
vdoimport utility imports VDO volumes created and managed by
|
||||
.BR vdo (8)
|
||||
manager into
|
||||
.BR lvm2 (8)
|
||||
managed VDO LV. This is realized by moving VDO superblock by 2MiB
|
||||
and creating lvm2 metadata at the front of this device. The operation is not reversible,
|
||||
thus after conversion to lvm2 the access to VDO data is only possible with
|
||||
.BR lvm2 (8)
|
||||
commands,
|
||||
.BR vdo (8)
|
||||
manager no longer control such volume.
|
||||
.
|
||||
.SH OPTIONS
|
||||
.
|
||||
.TP
|
||||
.BR -f | --force
|
||||
Bypass some sanity checks.
|
||||
.
|
||||
.TP
|
||||
.BR -h | --help
|
||||
Display the help text.
|
||||
.
|
||||
.TP
|
||||
.BR -n | --name
|
||||
Specifies the name of converted VDO LV. When the name is not specified,
|
||||
some automatic name is selected. In case the converted VDO volume is
|
||||
already using LV a backend device, the name of this LV is used for VDO LV.
|
||||
In this case also the of volume group must stay same.
|
||||
.
|
||||
.TP
|
||||
.BR -v | --verbose
|
||||
Be more verbose.
|
||||
.
|
||||
.TP
|
||||
.BR -y | --yes
|
||||
Answer "yes" at any prompts.
|
||||
.
|
||||
.TP
|
||||
.BR --dry-run
|
||||
Print commands without running them.
|
||||
.
|
||||
.
|
||||
.SH DIAGNOSTICS
|
||||
.
|
||||
On successful completion, the status code is 0.
|
||||
A status code of 1 is used for failure.
|
||||
.
|
||||
.SH EXAMPLES
|
||||
.
|
||||
Convert VDO volume created by vdo manager into logical volume LV1 with within volume group VG1.
|
||||
.P
|
||||
#
|
||||
.B vdoimport --name VG1/LV1 /dev/mapper/vdo-volume
|
||||
.
|
||||
.SH ENVIRONMENT VARIABLES
|
||||
.
|
||||
.TP
|
||||
.B TMPDIR
|
||||
The temporary directory name for mount points. Defaults to "\fI/tmp\fP".
|
||||
.TP
|
||||
.B DM_DEV_DIR
|
||||
The device directory name.
|
||||
Defaults to "\fI/dev\fP" and must be an absolute path.
|
||||
.
|
||||
.SH SEE ALSO
|
||||
.
|
||||
.nh
|
||||
.ad l
|
||||
.BR lvm (8),
|
||||
.BR lvm.conf (5),
|
||||
.P
|
||||
.BR vdo (8),
|
||||
.BR vdo2lvm (8),
|
@@ -393,13 +393,6 @@ Change the lock type for a shared VG.
|
||||
.P
|
||||
\(em
|
||||
.P
|
||||
Common options for command:
|
||||
.
|
||||
.RS 4
|
||||
.ad l
|
||||
.ad b
|
||||
.RE
|
||||
.P
|
||||
Common options for lvm:
|
||||
.
|
||||
.RS 4
|
||||
|
@@ -46,13 +46,6 @@ Rewrite VG metadata to correct problems.
|
||||
.ad b
|
||||
.RE
|
||||
.P
|
||||
Common options for command:
|
||||
.
|
||||
.RS 4
|
||||
.ad l
|
||||
.ad b
|
||||
.RE
|
||||
.P
|
||||
Common options for lvm:
|
||||
.
|
||||
.RS 4
|
||||
|
@@ -31,6 +31,10 @@ ifeq ("@FSADM@", "yes")
|
||||
LVM_SCRIPTS += fsadm.sh
|
||||
endif
|
||||
|
||||
ifeq ("@VDOIMPORT@", "yes")
|
||||
LVM_SCRIPTS += vdoimport.sh
|
||||
endif
|
||||
|
||||
ifeq ("@BLKDEACTIVATE@", "yes")
|
||||
DM_SCRIPTS += blkdeactivate.sh
|
||||
endif
|
||||
@@ -88,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
|
||||
|
376
scripts/vdoimport.sh
Executable file
376
scripts/vdoimport.sh
Executable file
@@ -0,0 +1,376 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright (C) 2021 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This file is part of LVM2.
|
||||
#
|
||||
# This copyrighted material is made available to anyone wishing to use,
|
||||
# modify, copy, or redistribute it subject to the terms and conditions
|
||||
# of the GNU 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
|
||||
#
|
||||
# Author: Zdenek Kabelac <zkabelac at redhat.com>
|
||||
#
|
||||
# Script for converting VDO volumes to lvm2 VDO LVs
|
||||
#
|
||||
# Needed utilities:
|
||||
# lvm, dmsetup,
|
||||
# vdo, vdo2lvm,
|
||||
# grep, awk, sed, blockdev, readlink, mkdir
|
||||
#
|
||||
# Conversion is using 'vdo convert' support from VDO manager to move
|
||||
# existing VDO header by 2M which makes space to place in PV header
|
||||
# and VG metadata area, and then create VDOPOOL LV and VDO LV in such VG.
|
||||
#
|
||||
|
||||
set -euE -o pipefail
|
||||
|
||||
TOOL=vdoimport
|
||||
|
||||
_SAVEPATH=$PATH
|
||||
PATH="/sbin:/usr/sbin:/bin:/usr/sbin:$PATH"
|
||||
|
||||
# user may override lvm location by setting LVM_BINARY
|
||||
LVM=${LVM_BINARY:-lvm}
|
||||
VDO=${VDO_BINARY:-vdo}
|
||||
VDOCONF=${VDOCONF:-}
|
||||
BLOCKDEV="blockdev"
|
||||
READLINK="readlink"
|
||||
READLINK_E="-e"
|
||||
MKDIR="mkdir"
|
||||
|
||||
TEMPDIR="${TMPDIR:-/tmp}/${TOOL}_${RANDOM}$$"
|
||||
DM_DEV_DIR="${DM_DEV_DIR:-/dev}"
|
||||
|
||||
DRY=0
|
||||
VERB=""
|
||||
FORCE=""
|
||||
YES=""
|
||||
|
||||
# default name for converted VG and its VDO LV
|
||||
NAME="vdovg/vdolvol"
|
||||
|
||||
# help message
|
||||
tool_usage() {
|
||||
echo "${TOOL}: Utility to convert VDO volume to VDO LV."
|
||||
echo
|
||||
echo " ${TOOL} [options] <vdo_device_path>"
|
||||
echo
|
||||
echo " Options:"
|
||||
echo " -f | --force Bypass sanity checks"
|
||||
echo " -h | --help Show this help message"
|
||||
echo " -n | --name Specifies VG/LV name for converted VDO volume"
|
||||
echo " -v | --verbose Be verbose"
|
||||
echo " -y | --yes Answer \"yes\" at any prompts"
|
||||
echo " --dry-run Print commands without running them"
|
||||
|
||||
exit
|
||||
}
|
||||
|
||||
verbose() {
|
||||
test -z "$VERB" || echo "$TOOL:" "$@"
|
||||
}
|
||||
|
||||
# Support multi-line error messages
|
||||
error() {
|
||||
for i in "$@" ; do
|
||||
echo "$TOOL: $i" >&2
|
||||
done
|
||||
cleanup 1
|
||||
}
|
||||
|
||||
dry() {
|
||||
if [ "$DRY" -ne 0 ]; then
|
||||
verbose "Dry execution" "$@"
|
||||
return 0
|
||||
fi
|
||||
verbose "Executing" "$@"
|
||||
"$@"
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
trap '' 2
|
||||
|
||||
rm -rf "$TEMPDIR"
|
||||
# error exit status for break
|
||||
exit "${1:-1}"
|
||||
}
|
||||
|
||||
get_enabled_value_() {
|
||||
case "$1" in
|
||||
enabled) echo "1" ;;
|
||||
*) echo "0" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
get_kb_size_with_unit_() {
|
||||
case "$1" in
|
||||
*[kK]) echo $(( ${1%[kK]} )) ;;
|
||||
*[mM]) echo $(( ${1%[mM]} * 1024 )) ;;
|
||||
*[gG]) echo $(( ${1%[gG]} * 1024 * 1024 )) ;;
|
||||
*[tT]) echo $(( ${1%[tT]} * 1024 * 1024 * 1024 )) ;;
|
||||
*[pP]) echo $(( ${1%[pP]} * 1024 * 1024 * 1024 * 1024 )) ;;
|
||||
esac
|
||||
}
|
||||
|
||||
get_mb_size_with_unit_() {
|
||||
case "$1" in
|
||||
*[mM]) echo $(( ${1%[mM]} )) ;;
|
||||
*[gG]) echo $(( ${1%[gG]} * 1024 )) ;;
|
||||
*[tT]) echo $(( ${1%[tT]} * 1024 * 1024 )) ;;
|
||||
*[pP]) echo $(( ${1%[pP]} * 1024 * 1024 * 1024 )) ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Figure out largest possible extent size usable for VG
|
||||
# $1 physical size
|
||||
# $2 logical size
|
||||
get_largest_extent_size_() {
|
||||
local max=4
|
||||
local i
|
||||
local d
|
||||
|
||||
for i in 8 16 32 64 128 256 512 1024 2048 4096 ; do
|
||||
d=$(( $1 / i ))
|
||||
test $(( d * i )) -eq "$1" || break
|
||||
d=$(( $2 / i ))
|
||||
test $(( d * i )) -eq "$2" || break
|
||||
max=$i
|
||||
done
|
||||
echo "$max"
|
||||
}
|
||||
|
||||
# detect LV on the given device
|
||||
# dereference device name if it is symbolic link
|
||||
detect_lv_() {
|
||||
local DEVICE=$1
|
||||
local MAJOR
|
||||
local MINOR
|
||||
local SYSVOLUME
|
||||
local MAJORMINOR
|
||||
|
||||
DEVICE=${1/#"${DM_DEV_DIR}/"/}
|
||||
DEVICE=$("$READLINK" $READLINK_E "$DM_DEV_DIR/$DEVICE")
|
||||
test -n "$DEVICE" || error "Cannot get readlink \"$1\"."
|
||||
RDEVICE=$DEVICE
|
||||
case "$RDEVICE" in
|
||||
# hardcoded /dev since udev does not create these entries elsewhere
|
||||
/dev/dm-[0-9]*)
|
||||
read -r <"/sys/block/${RDEVICE#/dev/}/dm/name" SYSVOLUME 2>&1 && DEVICE="$DM_DEV_DIR/mapper/$SYSVOLUME"
|
||||
read -r <"/sys/block/${RDEVICE#/dev/}/dev" MAJORMINOR 2>&1 || error "Cannot get major:minor for \"$DEVICE\"."
|
||||
MAJOR=${MAJORMINOR%%:*}
|
||||
MINOR=${MAJORMINOR##*:}
|
||||
;;
|
||||
*)
|
||||
STAT=$(stat --format "MAJOR=\$((0x%t)) MINOR=\$((0x%T))" "$RDEVICE")
|
||||
test -n "$STAT" || error "Cannot get major:minor for \"$DEVICE\"."
|
||||
eval "$STAT"
|
||||
;;
|
||||
esac
|
||||
|
||||
eval "$(dmsetup info -c -j "$MAJOR" -m "$MINOR" -o uuid,name --noheadings --nameprefixes --separator ' ')"
|
||||
}
|
||||
|
||||
# parse yaml config files into 'prefix_yaml_part_names=("value")' strings
|
||||
parse_yaml_() {
|
||||
local yaml_file=$1
|
||||
local prefix=$2
|
||||
local s
|
||||
local w
|
||||
local fs
|
||||
|
||||
s='[[:space:]]*'
|
||||
w='[a-zA-Z0-9_.-]*'
|
||||
fs="$(echo @|tr @ '\034')"
|
||||
|
||||
(
|
||||
sed -ne '/^--/s|--||g; s|\"|\\\"|g; s/[[:space:]]*$//g;' \
|
||||
-e 's/\$/\\\$/g' \
|
||||
-e "/#.*[\"\']/!s| #.*||g; /^#/s|#.*||g;" \
|
||||
-e "s|^\($s\)\($w\)$s:$s\"\(.*\)\"$s\$|\1$fs\2$fs\3|p" \
|
||||
-e "s|^\($s\)\($w\)${s}[:-]$s\(.*\)$s\$|\1$fs\2$fs\3|p" |
|
||||
|
||||
awk -F"$fs" '{
|
||||
indent = length($1)/2;
|
||||
if (length($2) == 0) { conj[indent]="+";} else {conj[indent]="";}
|
||||
vname[indent] = $2;
|
||||
for (i in vname) {if (i > indent) {delete vname[i]}}
|
||||
if (length($3) > 0) {
|
||||
vn=""; for (i=0; i<indent; i++) {vn=(vn)(vname[i])("_")}
|
||||
printf("%s%s%s%s=(\"%s\")\n", "'"$prefix"'",vn, $2, conj[indent-1], $3);
|
||||
}
|
||||
}' |
|
||||
|
||||
sed -e 's/_=/+=/g' |
|
||||
|
||||
awk 'BEGIN {
|
||||
FS="=";
|
||||
OFS="="
|
||||
}
|
||||
/(-|\.).*=/ {
|
||||
gsub("-|\\.", "_", $1)
|
||||
}
|
||||
{ print }'
|
||||
) < "$yaml_file"
|
||||
}
|
||||
|
||||
# convert existing VDO volume into lvm2 volume
|
||||
convert2lvm_() {
|
||||
local DEVICE=$1
|
||||
local VGNAME=${NAME%/*}
|
||||
local LVNAME=${NAME#*/}
|
||||
local VDONAME
|
||||
local TRVDONAME
|
||||
local EXTENTSZ
|
||||
local IS_LV=1
|
||||
|
||||
DM_UUID=""
|
||||
detect_lv_ "$DEVICE"
|
||||
case "$DM_UUID" in
|
||||
LVM-*) eval "$(dmsetup splitname --nameprefixes --noheadings --separator ' ' "$DM_NAME")"
|
||||
if [ -z "$VGNAME" ] || [ "$VGNAME" = "$LVNAME" ] ; then
|
||||
VGNAME=$DM_VG_NAME
|
||||
elif test "$VGNAME" != "$DM_VG_NAME" ; then
|
||||
error "Volume group name \"$VGNAME\" does not match name \"$DM_VG_NAME\" for device \"$DEVICE\"."
|
||||
fi
|
||||
;;
|
||||
*) IS_LV=0
|
||||
# Check $VGNANE does not already exists
|
||||
"$LVM" vgs "$VGNAME" && error "Cannot use already existing volume group name \"$VGNAME\"."
|
||||
;;
|
||||
esac
|
||||
|
||||
verbose "Checked whether device $1 is already LV ($IS_LV)."
|
||||
|
||||
"$MKDIR" -p -m 0000 "$TEMPDIR" || error "Failed to create $TEMPDIR."
|
||||
|
||||
verbose "Getting YAML VDO configuration."
|
||||
"$VDO" printConfigFile $VDOCONF >"$TEMPDIR/vdoconf.yml"
|
||||
|
||||
VDONAME=$(awk -v DNAME="$DEVICE" '/.*VDOService$/ {VNAME=substr($1, 0, length($1) - 1)} /[[:space:]]*device:/ { if ($2 ~ DNAME) {print VNAME}}' "$TEMPDIR/vdoconf.yml")
|
||||
TRVDONAME=$(echo "$VDONAME" | tr '-' '_')
|
||||
|
||||
# When VDO volume is 'active', check it's not mounted/being used
|
||||
eval "$(dmsetup info -c -o open "$VDONAME" --noheadings --nameprefixes || true)"
|
||||
test "${DM_OPEN:-0}" -eq 0 || error "Cannot converted VDO volume \"$VDONAME\" which is in use!"
|
||||
|
||||
#parse_yaml_ "$TEMPDIR/vdoconf.yml" _
|
||||
eval "$(parse_yaml_ "$TEMPDIR/vdoconf.yml" _ | grep "$TRVDONAME" | sed -e "s/_config_vdos_$TRVDONAME/vdo/g")"
|
||||
|
||||
vdo_logicalSize=$(get_kb_size_with_unit_ "$vdo_logicalSize")
|
||||
vdo_physicalSize=$(get_kb_size_with_unit_ "$vdo_physicalSize")
|
||||
|
||||
verbose "Going to convert physical sized VDO device $vdo_physicalSize KiB."
|
||||
verbose "With logical volume of size $vdo_logicalSize KiB."
|
||||
|
||||
PARAMS=$(cat <<EOF
|
||||
allocation {
|
||||
vdo_use_compression = $(get_enabled_value_ "$vdo_compression")
|
||||
vdo_use_deduplication = $(get_enabled_value_ "$vdo_deduplication")
|
||||
vdo_use_metadata_hints=1
|
||||
vdo_minimum_io_size = $vdo_logicalBlockSize
|
||||
vdo_block_map_cache_size_mb = $(get_mb_size_with_unit_ "$vdo_blockMapCacheSize")
|
||||
vdo_block_map_period = $vdo_blockMapPeriod
|
||||
vdo_check_point_frequency = $vdo_indexCfreq
|
||||
vdo_use_sparse_index = $(get_enabled_value_ "$vdo_indexSparse")
|
||||
vdo_index_memory_size_mb = $(awk "BEGIN {print $vdo_indexMemory * 1024}")
|
||||
vdo_slab_size_mb = $(get_mb_size_with_unit_ "$vdo_blockMapCacheSize")
|
||||
vdo_ack_threads = $vdo_ackThreads
|
||||
vdo_bio_threads = $vdo_bioThreads
|
||||
vdo_bio_rotation = $vdo_bioRotationInterval
|
||||
vdo_cpu_threads = $vdo_cpuThreads
|
||||
vdo_hash_zone_threads = $vdo_hashZoneThreads
|
||||
vdo_logical_threads = $vdo_logicalThreads
|
||||
vdo_physical_threads = $vdo_physicalThreads
|
||||
vdo_write_policy = $vdo_writePolicy
|
||||
vdo_max_discard = $(( $(get_kb_size_with_unit_ "$vdo_maxDiscardSize") * 1024 ))
|
||||
vdo_pool_header_size = 0
|
||||
}
|
||||
EOF
|
||||
)
|
||||
verbose "VDO conversion paramaters: $PARAMS"
|
||||
|
||||
verbose "Stopping VDO volume."
|
||||
dry "$VDO" stop $VDOCONF --name "$VDONAME"
|
||||
|
||||
if [ "$IS_LV" = "0" ]; then
|
||||
verbose "Moving VDO header by 2MiB."
|
||||
dry "$VDO" convert $VDOCONF --force --name "$VDONAME"
|
||||
|
||||
dry "$LVM" pvcreate $YES --dataalignment 2M "$DEVICE" || {
|
||||
error "Creation of PV on \"$DEVICE\" failed, while VDO header has been already moved!"
|
||||
}
|
||||
|
||||
# Obtain free space in this new PV
|
||||
# after 'vdo convert/vdo2lvm' call there is +2M free space at the front of the device
|
||||
case "$DRY" in
|
||||
0) pvfree=$("$LVM" pvs -o devsize --units b --nosuffix --noheadings "$DEVICE") ;;
|
||||
*) pvfree=$("$BLOCKDEV" --getsize64 "$DEVICE") ;;
|
||||
esac
|
||||
|
||||
pvfree=$(( pvfree / 1024 - 2048 )) # to KiB
|
||||
else
|
||||
pvfree=$("$LVM" lvs -o size --units b --nosuffix --noheadings "$VGNAME/$LVNAME")
|
||||
pvfree=$(( pvfree / 1024 )) # to KiB
|
||||
fi
|
||||
|
||||
# select largest possible extent size that can exactly express both sizes
|
||||
EXTENTSZ=$(get_largest_extent_size_ "$pvfree" "$vdo_logicalSize")
|
||||
|
||||
if [ "$IS_LV" = "0" ]; then
|
||||
verbose "Creating VG \"${NAME%/*}\" with extent size $EXTENTSZ KiB."
|
||||
dry "$LVM" vgcreate $YES $VERB -s "${EXTENTSZ}k" "$VGNAME" "$DEVICE" || {
|
||||
error "Creation of VG \"$VGNAME\" failed, while VDO header has been already moved!"
|
||||
}
|
||||
|
||||
verbose "Creating VDO pool data LV from all extents in volume group $VGNAME."
|
||||
dry "$LVM" lvcreate -Zn -Wn $YES $VERB -l100%VG -n "${LVNAME}_vpool" "$VGNAME"
|
||||
else
|
||||
# validate existing VG extent_size can express virtual VDO size
|
||||
vg_extent_size=$("$LVM" vgs -o vg_extent_size --units b --nosuffix --noheadings "$VGNAME" || true)
|
||||
vg_extent_size=$(( vg_extent_size / 1024 ))
|
||||
|
||||
test "$vg_extent_size" -le "$EXTENTSZ" || {
|
||||
error "Please vgchange extent_size to at most $EXTENTSZ KiB or extend and align virtual size on $vg_extent_size KiB."
|
||||
}
|
||||
verbose "Renaming existing LV to be used as _vdata volume for VDO pool LV."
|
||||
dry "$LVM" lvrename $YES $VERB "$VGNAME/$LVNAME" "$VGNAME/${LVNAME}_vpool" || {
|
||||
error "Rename of LV \"$VGNAME/$LVNAME\" failed, while VDO header has been already moved!"
|
||||
}
|
||||
fi
|
||||
|
||||
verbose "Converting to VDO pool."
|
||||
dry "$LVM" lvconvert $YES $VERB $FORCE --config "$PARAMS" -Zn -V "${vdo_logicalSize}k" -n "$LVNAME" --type vdo-pool "$VGNAME/${LVNAME}_vpool"
|
||||
|
||||
rm -fr "$TEMPDIR"
|
||||
}
|
||||
|
||||
#############################
|
||||
# start point of this script
|
||||
# - parsing parameters
|
||||
#############################
|
||||
trap "cleanup 2" 2
|
||||
|
||||
test "$#" -eq 0 && tool_usage
|
||||
|
||||
while [ "$#" -ne 0 ]
|
||||
do
|
||||
case "$1" in
|
||||
"") ;;
|
||||
"-f"|"--force" ) FORCE="-f" ;;
|
||||
"-h"|"--help" ) tool_usage ;;
|
||||
"-n"|"--name" ) shift; NAME=$1 ;;
|
||||
"-v"|"--verbose") VERB="-v" ;;
|
||||
"-y"|"--yes" ) YES="-y" ;;
|
||||
"--dry-run" ) DRY="1" ;;
|
||||
"-*") error "Wrong argument \"$1\". (see: $TOOL --help)" ;;
|
||||
*) DEVICENAME=$1 ;; # device name does not start with '-'
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# do conversion
|
||||
convert2lvm_ "$DEVICENAME"
|
@@ -70,6 +70,7 @@ fi
|
||||
%{_sbindir}/vgdisplay
|
||||
%{_sbindir}/vgexport
|
||||
%{_sbindir}/vgextend
|
||||
%{_sbindir}/vdoimport
|
||||
%{_sbindir}/vgimport
|
||||
%{_sbindir}/vgimportclone
|
||||
%{_sbindir}/vgimportdevices
|
||||
@@ -157,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
|
||||
@@ -183,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
|
||||
|
@@ -171,7 +171,7 @@ check_lvmlockd_dlm: .tests-stamp
|
||||
endif
|
||||
|
||||
ifeq ("@BUILD_LVMLOCKD@", "yes")
|
||||
check_lvmlockd_idm: .tests-stamp
|
||||
check_lvmlockd_idm: .tests-stamp lib/idm_inject_failure
|
||||
$(INSTALL_PROGRAM) lib/idm_inject_failure $(EXECDIR)
|
||||
VERBOSE=$(VERBOSE) ./lib/runner \
|
||||
--testdir . --outdir $(LVM_TEST_RESULTS) \
|
||||
@@ -368,6 +368,7 @@ LIB = $(addprefix lib/, $(LIB_SECURETEST) $(LIB_DMSECURETEST) $(LIB_SHARED) $(LI
|
||||
$(Q) $(LN_S) -f $(abs_top_srcdir)/conf/lvmdbusd.profile lib/
|
||||
$(Q) $(LN_S) -f $(abs_top_srcdir)/conf/thin-performance.profile lib/
|
||||
$(Q) $(LN_S) -f $(abs_top_srcdir)/scripts/fsadm.sh lib/fsadm
|
||||
$(Q) $(LN_S) -f $(abs_top_srcdir)/scripts/vdoimport.sh lib/vdoimport
|
||||
@test "$(srcdir)" = . || \
|
||||
for i in $(LIB_LVMLOCKD_CONF) $(LIB_MKE2FS_CONF); do \
|
||||
test -n "$(Q)" || echo "$(LN_S) -f $(abs_top_srcdir)/test/lib/$$i lib/"; \
|
||||
|
@@ -67,4 +67,26 @@ fail lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $vg/$lv
|
||||
# Thin-pool CAN use cached data LV
|
||||
lvconvert --yes --thinpool $vg/$lv
|
||||
|
||||
lvremove -f $vg
|
||||
|
||||
# Check we can active snapshot of cached external origin (BZ: 1967744)
|
||||
lvcreate -T -L10M $vg/pool "$dev1"
|
||||
|
||||
lvcreate -L10M -n origin $vg "$dev1"
|
||||
lvcreate -H -L4M -n CPOOL $vg/origin "$dev2"
|
||||
|
||||
# Use cached origin as external origin
|
||||
lvconvert -y -T --thinpool $vg/pool --originname extorig origin
|
||||
|
||||
# Check we can easily create snapshot of such LV
|
||||
lvcreate -y -kn -n snap -s $vg/origin
|
||||
|
||||
# Deactivate everything and do a component activation of _cmeta volume
|
||||
lvchange -an $vg
|
||||
lvchange -ay -y $vg/CPOOL_cpool_cmeta
|
||||
|
||||
# Now this must fail since component volume is active
|
||||
not lvcreate -y -kn -n snap2 -s $vg/origin |& tee err
|
||||
grep "cmeta is active" err
|
||||
|
||||
vgremove -f $vg
|
||||
|
@@ -118,6 +118,14 @@ mkdir -p "$mount_dir"
|
||||
|
||||
aux prepare_devs 6 70 # want 64M of usable space from each dev
|
||||
|
||||
# Tests with fs block sizes require a libblkid version that shows BLOCK_SIZE
|
||||
vgcreate $vg "$dev1"
|
||||
lvcreate -n $lv1 -L50 $vg
|
||||
mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
|
||||
blkid -c /dev/null "$DM_DEV_DIR/$vg/$lv1" | grep BLOCK_SIZE || skip
|
||||
lvchange -an $vg
|
||||
vgremove -ff $vg
|
||||
|
||||
# generate random data
|
||||
dd if=/dev/urandom of=pattern bs=512K count=1
|
||||
|
||||
|
@@ -15,13 +15,15 @@ SKIP_WITH_LVMPOLLD=1
|
||||
|
||||
. lib/inittest
|
||||
|
||||
[ -z "$LVM_TEST_LOCK_TYPE_IDM" ] && skip;
|
||||
|
||||
aux prepare_devs 6
|
||||
get_devs
|
||||
|
||||
pvcreate -M2 "${DEVICES[@]}"
|
||||
|
||||
vgcreate --shared -M2 "$vg1" "$dev1" "$dev2" "$dev3"
|
||||
vgcreate --shared -M2 "$vg2" "$dev4" "$dev5" "$dev6"
|
||||
vgcreate $SHARED -M2 "$vg1" "$dev1" "$dev2" "$dev3"
|
||||
vgcreate $SHARED -M2 "$vg2" "$dev4" "$dev5" "$dev6"
|
||||
|
||||
test_vg_thread1()
|
||||
{
|
||||
|
@@ -15,6 +15,8 @@ SKIP_WITH_LVMPOLLD=1
|
||||
|
||||
. lib/inittest
|
||||
|
||||
[ -z "$LVM_TEST_LOCK_TYPE_IDM" ] && skip;
|
||||
|
||||
aux prepare_devs 8
|
||||
get_devs
|
||||
|
||||
@@ -24,14 +26,14 @@ test_vg_thread1()
|
||||
{
|
||||
for i in {1..1000}
|
||||
do
|
||||
vgcreate --shared -M2 "$vg1" "$dev1" "$dev2" "$dev3"
|
||||
vgcreate $SHARED -M2 "$vg1" "$dev1" "$dev2" "$dev3"
|
||||
vgremove -ff $vg1
|
||||
done
|
||||
}
|
||||
|
||||
test_vg_thread2()
|
||||
{
|
||||
vgcreate --shared -M2 "$vg2" "$dev4" "$dev5" "$dev6"
|
||||
vgcreate $SHARED -M2 "$vg2" "$dev4" "$dev5" "$dev6"
|
||||
|
||||
for i in {1..1000}
|
||||
do
|
||||
|
@@ -15,6 +15,8 @@ SKIP_WITH_LVMPOLLD=1
|
||||
|
||||
. lib/inittest
|
||||
|
||||
[ -z "$LVM_TEST_LOCK_TYPE_IDM" ] && skip;
|
||||
|
||||
aux prepare_vg 3
|
||||
|
||||
for i in {1..1000}
|
||||
|
@@ -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)
|
||||
|
403
test/shell/udev-pvscan-vgchange.sh
Normal file
403
test/shell/udev-pvscan-vgchange.sh
Normal 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
|
||||
|
110
test/shell/vdo-convert.sh
Normal file
110
test/shell/vdo-convert.sh
Normal file
@@ -0,0 +1,110 @@
|
||||
#!/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 conversion of VDO volumes made by vdo manager into VDO LV.
|
||||
|
||||
|
||||
SKIP_WITH_LVMPOLLD=1
|
||||
|
||||
. lib/inittest
|
||||
|
||||
# Use local for this test vdo configuratoin
|
||||
VDOCONF="-f vdotestconf.yml"
|
||||
#VDOCONF=""
|
||||
export VDOCONF
|
||||
VDONAME="${PREFIX}-TESTVDO"
|
||||
|
||||
# VDO automatically starts dmeventd
|
||||
aux prepare_dmeventd
|
||||
|
||||
#
|
||||
# Main
|
||||
#
|
||||
which vdo || skip
|
||||
which mkfs.ext4 || skip
|
||||
export MKE2FS_CONFIG="$TESTDIR/lib/mke2fs.conf"
|
||||
|
||||
aux have_vdo 6 2 0 || skip
|
||||
|
||||
aux prepare_devs 2 10000
|
||||
|
||||
aux extend_filter_LVMTEST
|
||||
|
||||
|
||||
#
|
||||
# Check conversion of VDO volume made on some LV
|
||||
#
|
||||
# In this case we do not need to move any VDO headers.
|
||||
#
|
||||
vgcreate $vg "$dev1"
|
||||
|
||||
lvcreate -L5G -n $lv1 $vg
|
||||
|
||||
vdo create $VDOCONF --name "$VDONAME" --device="$DM_DEV_DIR/$vg/$lv1" --vdoLogicalSize=10G
|
||||
|
||||
mkfs -E nodiscard "$DM_DEV_DIR/mapper/$VDONAME"
|
||||
|
||||
# Different VG name fails
|
||||
not vdoimport -y -v --name $vg1/$lv1 "$DM_DEV_DIR/$vg/$lv1"
|
||||
|
||||
# Try just dry run and observe logging
|
||||
vdoimport --dry-run -y -v --name $lv1 "$DM_DEV_DIR/$vg/$lv1"
|
||||
|
||||
vdoimport -y --name $lv1 "$DM_DEV_DIR/$vg/$lv1"
|
||||
|
||||
# ATM needed - since we do not call 'vdo convert' in this case
|
||||
vdo remove $VDOCONF --force --name "$VDONAME" || true
|
||||
|
||||
vgremove -f $vg
|
||||
|
||||
aux wipefs_a "$dev1"
|
||||
|
||||
# prepare 'unused' $vg2
|
||||
vgcreate $vg2 "$dev2"
|
||||
|
||||
#
|
||||
# Check conversion of VDO volume on non-LV device
|
||||
#
|
||||
vdo create $VDOCONF --name "$VDONAME" --device="$dev1" --vdoLogicalSize=31G
|
||||
|
||||
mkfs -E nodiscard "$DM_DEV_DIR/mapper/$VDONAME"
|
||||
|
||||
# Fail with an already existing volume group $vg2
|
||||
not vdoimport --dry-run -y -v --name $vg2/$lv1 "$dev1" |& tee err
|
||||
grep "already existing volume group" err
|
||||
|
||||
# User can also convert already stopped VDO volume
|
||||
vdo stop $VDOCONF --name "$VDONAME"
|
||||
|
||||
vdoimport -y -v --name $vg/$lv1 "$dev1"
|
||||
|
||||
fsck -n "$DM_DEV_DIR/$vg/$lv1"
|
||||
|
||||
vgremove -f $vg
|
||||
|
||||
|
||||
#
|
||||
# Try once again with different vgname/lvname and sizes
|
||||
#
|
||||
aux teardown_devs
|
||||
aux prepare_devs 1 23456
|
||||
|
||||
vdo create $VDOCONF --name "$VDONAME" --device="$dev1" --vdoLogicalSize=23G
|
||||
|
||||
mkfs -E nodiscard "$DM_DEV_DIR/mapper/$VDONAME"
|
||||
|
||||
vdoimport -y -v --name $vg1/$lv2 "$dev1"
|
||||
|
||||
fsck -n "$DM_DEV_DIR/$vg1/$lv2"
|
||||
|
||||
vgremove -f $vg1
|
||||
|
@@ -159,6 +159,14 @@ _run_test() {
|
||||
aux prepare_scsi_debug_dev 256 sector_size=512 physblk_exp=3
|
||||
aux prepare_devs 2 64
|
||||
|
||||
# Tests with fs block sizes require a libblkid version that shows BLOCK_SIZE
|
||||
vgcreate $vg "$dev1"
|
||||
lvcreate -n $lv1 -L50 $vg
|
||||
mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
|
||||
blkid -c /dev/null "$DM_DEV_DIR/$vg/$lv1" | grep BLOCK_SIZE || skip
|
||||
lvchange -an $vg
|
||||
vgremove -ff $vg
|
||||
|
||||
# loopa/loopb have LBS 512 PBS 512
|
||||
which fallocate || skip
|
||||
fallocate -l 64M loopa
|
||||
|
@@ -25,6 +25,14 @@ check sysfs "$(< SCSI_DEBUG_DEV)" queue/logical_block_size "512"
|
||||
check sysfs "$(< SCSI_DEBUG_DEV)" queue/physical_block_size "512"
|
||||
aux prepare_devs 2 64
|
||||
|
||||
# Tests with fs block sizes require a libblkid version that shows BLOCK_SIZE
|
||||
vgcreate $vg "$dev1"
|
||||
lvcreate -n $lv1 -L50 $vg
|
||||
mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
|
||||
blkid -c /dev/null "$DM_DEV_DIR/$vg/$lv1" | grep BLOCK_SIZE || skip
|
||||
lvchange -an $vg
|
||||
vgremove -ff $vg
|
||||
|
||||
# scsi_debug devices with 512 LBS and 4K PBS
|
||||
#aux prepare_scsi_debug_dev 256 sector_size=512 physblk_exp=3
|
||||
#check sysfs "$(< SCSI_DEBUG_DEV)" queue/logical_block_size "512"
|
||||
|
28
tools/args.h
28
tools/args.h
@@ -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")
|
||||
|
||||
|
@@ -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.
|
||||
|
||||
---
|
||||
|
||||
|
@@ -141,7 +141,7 @@ static inline int dumptype_arg(struct cmd_context *cmd __attribute__((unused)),
|
||||
#define CAN_USE_ONE_SCAN 0x00002000
|
||||
#define ALLOW_HINTS 0x00004000
|
||||
#define ALLOW_EXPORTED 0x00008000
|
||||
|
||||
#define CHECK_DEVS_USED 0x00010000
|
||||
|
||||
/* create foo_CMD enums for command def ID's in command-lines.in */
|
||||
|
||||
|
@@ -31,7 +31,7 @@ xx(formats,
|
||||
|
||||
xx(fullreport,
|
||||
"Display full report",
|
||||
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | ALLOW_HINTS | ALLOW_EXPORTED)
|
||||
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | ALLOW_HINTS | ALLOW_EXPORTED | CHECK_DEVS_USED)
|
||||
|
||||
xx(help,
|
||||
"Display help for commands",
|
||||
@@ -55,7 +55,7 @@ xx(lvcreate,
|
||||
|
||||
xx(lvdisplay,
|
||||
"Display information about a logical volume",
|
||||
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS)
|
||||
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS | CHECK_DEVS_USED)
|
||||
|
||||
xx(lvextend,
|
||||
"Add space to a logical volume",
|
||||
@@ -75,7 +75,7 @@ xx(lvmdevices,
|
||||
|
||||
xx(lvmdiskscan,
|
||||
"List devices that may be used as physical volumes",
|
||||
PERMITTED_READ_ONLY | ENABLE_ALL_DEVS | ALLOW_EXPORTED)
|
||||
PERMITTED_READ_ONLY | ENABLE_ALL_DEVS | ALLOW_EXPORTED | CHECK_DEVS_USED)
|
||||
|
||||
xx(lvmsadc,
|
||||
"Collect activity data",
|
||||
@@ -107,11 +107,11 @@ xx(lvresize,
|
||||
|
||||
xx(lvs,
|
||||
"Display information about logical volumes",
|
||||
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS)
|
||||
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS | CHECK_DEVS_USED)
|
||||
|
||||
xx(lvscan,
|
||||
"List all logical volumes in all volume groups",
|
||||
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH)
|
||||
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CHECK_DEVS_USED)
|
||||
|
||||
xx(pvchange,
|
||||
"Change attributes of physical volume(s)",
|
||||
@@ -131,7 +131,7 @@ xx(pvdata,
|
||||
|
||||
xx(pvdisplay,
|
||||
"Display various attributes of physical volume(s)",
|
||||
PERMITTED_READ_ONLY | ENABLE_ALL_DEVS | ENABLE_DUPLICATE_DEVS | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS | ALLOW_EXPORTED)
|
||||
PERMITTED_READ_ONLY | ENABLE_ALL_DEVS | ENABLE_DUPLICATE_DEVS | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS | ALLOW_EXPORTED | CHECK_DEVS_USED)
|
||||
|
||||
/* ALL_VGS_IS_DEFAULT is for polldaemon to find pvmoves in-progress using process_each_vg. */
|
||||
|
||||
@@ -149,11 +149,11 @@ xx(pvresize,
|
||||
|
||||
xx(pvs,
|
||||
"Display information about physical volumes",
|
||||
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | ENABLE_ALL_DEVS | ENABLE_DUPLICATE_DEVS | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS | ALLOW_EXPORTED)
|
||||
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | ENABLE_ALL_DEVS | ENABLE_DUPLICATE_DEVS | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS | ALLOW_EXPORTED | CHECK_DEVS_USED)
|
||||
|
||||
xx(pvscan,
|
||||
"List all physical volumes",
|
||||
PERMITTED_READ_ONLY | LOCKD_VG_SH | ALLOW_EXPORTED)
|
||||
PERMITTED_READ_ONLY | LOCKD_VG_SH | ALLOW_EXPORTED | CHECK_DEVS_USED)
|
||||
|
||||
xx(segtypes,
|
||||
"List available segment types",
|
||||
@@ -197,7 +197,7 @@ xx(vgcreate,
|
||||
|
||||
xx(vgdisplay,
|
||||
"Display volume group information",
|
||||
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS | ALLOW_EXPORTED)
|
||||
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS | ALLOW_EXPORTED | CHECK_DEVS_USED)
|
||||
|
||||
xx(vgexport,
|
||||
"Unregister volume group(s) from the system",
|
||||
@@ -241,11 +241,11 @@ xx(vgrename,
|
||||
|
||||
xx(vgs,
|
||||
"Display information about volume groups",
|
||||
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS | ALLOW_EXPORTED)
|
||||
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS | ALLOW_EXPORTED | CHECK_DEVS_USED)
|
||||
|
||||
xx(vgscan,
|
||||
"Search for all volume groups",
|
||||
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | ALLOW_EXPORTED)
|
||||
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | ALLOW_EXPORTED | CHECK_DEVS_USED)
|
||||
|
||||
xx(vgsplit,
|
||||
"Move physical volumes into a new or existing volume group",
|
||||
|
@@ -4769,7 +4769,7 @@ static int _lvconvert_to_pool_or_swap_metadata_single(struct cmd_context *cmd,
|
||||
|
||||
switch (cmd->command->command_enum) {
|
||||
case lvconvert_to_thinpool_or_swap_metadata_CMD:
|
||||
if (lv_is_cache(lv))
|
||||
if (lv_is_cache(lv) || lv_is_writecache(lv))
|
||||
/* For cached LV check the cache origin LV type */
|
||||
lvt_enum = get_lvt_enum(seg_lv(first_seg(lv), 0));
|
||||
to_thinpool = 1;
|
||||
@@ -5404,7 +5404,8 @@ static int _lvconvert_to_vdopool_single(struct cmd_context *cmd,
|
||||
struct processing_handle *handle)
|
||||
{
|
||||
const char *vg_name = NULL;
|
||||
unsigned int zero_vdopool;
|
||||
unsigned int vdo_pool_zero;
|
||||
uint64_t vdo_pool_header_size;
|
||||
struct volume_group *vg = lv->vg;
|
||||
struct logical_volume *vdo_lv;
|
||||
struct dm_vdo_target_params vdo_params; /* vdo */
|
||||
@@ -5447,7 +5448,7 @@ static int _lvconvert_to_vdopool_single(struct cmd_context *cmd,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!fill_vdo_target_params(cmd, &vdo_params, vg->profile))
|
||||
if (!fill_vdo_target_params(cmd, &vdo_params, &vdo_pool_header_size, vg->profile))
|
||||
goto_out;
|
||||
|
||||
if (arg_is_set(cmd, compression_ARG))
|
||||
@@ -5463,12 +5464,12 @@ static int _lvconvert_to_vdopool_single(struct cmd_context *cmd,
|
||||
goto out;
|
||||
}
|
||||
|
||||
zero_vdopool = arg_int_value(cmd, zero_ARG, 1);
|
||||
vdo_pool_zero = arg_int_value(cmd, zero_ARG, 1);
|
||||
|
||||
log_warn("WARNING: Converting logical volume %s to VDO pool volume %s formating.",
|
||||
display_lvname(lv), zero_vdopool ? "with" : "WITHOUT");
|
||||
display_lvname(lv), vdo_pool_zero ? "with" : "WITHOUT");
|
||||
|
||||
if (zero_vdopool)
|
||||
if (vdo_pool_zero)
|
||||
log_warn("THIS WILL DESTROY CONTENT OF LOGICAL VOLUME (filesystem etc.)");
|
||||
else
|
||||
log_warn("WARNING: Using invalid VDO pool data MAY DESTROY YOUR DATA!");
|
||||
@@ -5480,7 +5481,7 @@ static int _lvconvert_to_vdopool_single(struct cmd_context *cmd,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (zero_vdopool) {
|
||||
if (vdo_pool_zero) {
|
||||
if (!wipe_lv(lv, (struct wipe_params) { .do_zero = 1, .do_wipe_signatures = 1,
|
||||
.yes = arg_count(cmd, yes_ARG),
|
||||
.force = arg_count(cmd, force_ARG)})) {
|
||||
@@ -5489,7 +5490,8 @@ static int _lvconvert_to_vdopool_single(struct cmd_context *cmd,
|
||||
}
|
||||
}
|
||||
|
||||
if (!convert_vdo_pool_lv(lv, &vdo_params, &lvc.virtual_extents, zero_vdopool))
|
||||
if (!convert_vdo_pool_lv(lv, &vdo_params, &lvc.virtual_extents,
|
||||
vdo_pool_zero, vdo_pool_header_size))
|
||||
goto_out;
|
||||
|
||||
dm_list_init(&lvc.tags);
|
||||
@@ -5992,24 +5994,13 @@ static int _set_writecache_block_size(struct cmd_context *cmd,
|
||||
rv = get_fs_block_size(pathname, &fs_block_size);
|
||||
skip_fs:
|
||||
if (!rv || !fs_block_size) {
|
||||
if (lbs_4k && pbs_4k && !pbs_512) {
|
||||
block_size = 4096;
|
||||
} else if (lbs_512 && pbs_512 && !pbs_4k) {
|
||||
block_size = 512;
|
||||
} else if (lbs_512 && pbs_4k) {
|
||||
if (block_size_setting == 4096)
|
||||
block_size = 4096;
|
||||
else
|
||||
block_size = 512;
|
||||
} else {
|
||||
block_size = 512;
|
||||
}
|
||||
|
||||
if (block_size_setting && (block_size_setting != block_size)) {
|
||||
log_warn("WARNING: writecache block size %u does not match device block sizes, logical %u physical %u",
|
||||
block_size_setting, lbs_4k ? 4096 : 512, pbs_4k ? 4096 : 512);
|
||||
if (block_size_setting)
|
||||
block_size = block_size_setting;
|
||||
}
|
||||
else
|
||||
block_size = 4096;
|
||||
|
||||
log_print("Using writecache block size %u for unknown file system block size, logical block size %u, physical block size %u.",
|
||||
block_size, lbs_4k ? 4096 : 512, pbs_4k ? 4096 : 512);
|
||||
|
||||
if (block_size != 512) {
|
||||
log_warn("WARNING: unable to detect a file system block size on %s", display_lvname(lv));
|
||||
@@ -6021,8 +6012,6 @@ skip_fs:
|
||||
}
|
||||
}
|
||||
|
||||
log_print("Using writecache block size %u for unknown file system block size, logical block size %u, physical block size %u.",
|
||||
block_size, lbs_4k ? 4096 : 512, pbs_4k ? 4096 : 512);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@@ -1097,7 +1097,7 @@ static int _lvcreate_params(struct cmd_context *cmd,
|
||||
|
||||
// FIXME: prefiling here - this is wrong place
|
||||
// but will work for this moment
|
||||
if (!fill_vdo_target_params(cmd, &lp->vdo_params, NULL))
|
||||
if (!fill_vdo_target_params(cmd, &lp->vdo_params, &lp->vdo_pool_header_size, NULL))
|
||||
return_0;
|
||||
|
||||
if (arg_is_set(cmd, compression_ARG))
|
||||
|
@@ -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)
|
||||
@@ -2473,6 +2489,8 @@ static int _get_current_settings(struct cmd_context *cmd)
|
||||
|
||||
cmd->allow_mixed_block_sizes = find_config_tree_bool(cmd, devices_allow_mixed_block_sizes_CFG, NULL);
|
||||
|
||||
cmd->check_devs_used = (cmd->cname->flags & CHECK_DEVS_USED) ? 1 : 0;
|
||||
|
||||
/*
|
||||
* enable_hints is set to 1 if any commands are using hints.
|
||||
* use_hints is set to 1 if this command should use the hints.
|
||||
@@ -2509,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3226,6 +3246,11 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
|
||||
|
||||
_init_md_checks(cmd);
|
||||
|
||||
if (!dev_mpath_init(find_config_tree_str_allow_empty(cmd, devices_multipath_wwids_file_CFG, NULL))) {
|
||||
ret = ECMD_FAILED;
|
||||
goto_out;
|
||||
}
|
||||
|
||||
if (!_cmd_no_meta_proc(cmd) && !_init_lvmlockd(cmd)) {
|
||||
ret = ECMD_FAILED;
|
||||
goto_out;
|
||||
@@ -3246,6 +3271,7 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
|
||||
|
||||
out:
|
||||
|
||||
dev_mpath_exit();
|
||||
hints_exit(cmd);
|
||||
lvmcache_destroy(cmd, 1, 1);
|
||||
label_scan_destroy(cmd);
|
||||
@@ -3539,9 +3565,6 @@ struct cmd_context *init_lvm(unsigned set_connections,
|
||||
{
|
||||
struct cmd_context *cmd;
|
||||
|
||||
if (!udev_init_library_context())
|
||||
stack;
|
||||
|
||||
/*
|
||||
* It's not necessary to use name mangling for LVM:
|
||||
* - the character set used for LV names is subset of udev character set
|
||||
@@ -3549,9 +3572,7 @@ struct cmd_context *init_lvm(unsigned set_connections,
|
||||
*/
|
||||
dm_set_name_mangling_mode(DM_STRING_MANGLING_NONE);
|
||||
|
||||
if (!(cmd = create_toolcontext(0, NULL, 1, threaded,
|
||||
set_connections, set_filters))) {
|
||||
udev_fin_library_context();
|
||||
if (!(cmd = create_toolcontext(0, NULL, 1, threaded, set_connections, set_filters))) {
|
||||
return_NULL;
|
||||
}
|
||||
|
||||
@@ -3559,7 +3580,6 @@ struct cmd_context *init_lvm(unsigned set_connections,
|
||||
|
||||
if (stored_errno()) {
|
||||
destroy_toolcontext(cmd);
|
||||
udev_fin_library_context();
|
||||
return_NULL;
|
||||
}
|
||||
|
||||
|
@@ -15,6 +15,7 @@
|
||||
#include "tools.h"
|
||||
#include "lib/cache/lvmcache.h"
|
||||
#include "lib/device/device_id.h"
|
||||
#include "lib/device/dev-type.h"
|
||||
|
||||
static void _search_devs_for_pvids(struct cmd_context *cmd, struct dm_list *search_pvids, struct dm_list *found_devs)
|
||||
{
|
||||
@@ -171,7 +172,7 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
|
||||
log_error("Failed to read the devices file.");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
dev_cache_scan();
|
||||
dev_cache_scan(cmd);
|
||||
device_ids_match(cmd);
|
||||
|
||||
if (arg_is_set(cmd, check_ARG) || arg_is_set(cmd, update_ARG)) {
|
||||
@@ -389,7 +390,7 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
|
||||
* dev_cache_scan uses sysfs to check if an LV is using each dev
|
||||
* and sets this flag is so.
|
||||
*/
|
||||
if (dev->flags & DEV_USED_FOR_LV) {
|
||||
if (dev_is_used_by_active_lv(cmd, dev, NULL, NULL, NULL, NULL)) {
|
||||
if (!arg_count(cmd, yes_ARG) &&
|
||||
yes_no_prompt("Device %s is used by an active LV, continue to remove? ", devname) == 'n') {
|
||||
log_error("Device not removed.");
|
||||
@@ -435,7 +436,7 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
|
||||
|
||||
if (du->devname && (du->devname[0] != '.')) {
|
||||
if ((dev = dev_cache_get(cmd, du->devname, NULL)) &&
|
||||
(dev->flags & DEV_USED_FOR_LV)) {
|
||||
dev_is_used_by_active_lv(cmd, dev, NULL, NULL, NULL, NULL)) {
|
||||
if (!arg_count(cmd, yes_ARG) &&
|
||||
yes_no_prompt("Device %s is used by an active LV, continue to remove? ", du->devname) == 'n') {
|
||||
log_error("Device not removed.");
|
||||
|
@@ -3053,7 +3053,7 @@ int pvck(struct cmd_context *cmd, int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (arg_is_set(cmd, dump_ARG)) {
|
||||
if ((dump = arg_str_value(cmd, dump_ARG, NULL))) {
|
||||
struct stat sb;
|
||||
|
||||
pv_name = argv[0];
|
||||
@@ -3121,7 +3121,7 @@ int pvck(struct cmd_context *cmd, int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if ((dump = arg_str_value(cmd, dump_ARG, NULL))) {
|
||||
if (dump) {
|
||||
cmd->use_hints = 0;
|
||||
|
||||
if (!strcmp(dump, "metadata"))
|
||||
@@ -3145,6 +3145,7 @@ int pvck(struct cmd_context *cmd, int argc, char **argv)
|
||||
} else
|
||||
log_error("Unknown dump value.");
|
||||
|
||||
free(def);
|
||||
if (!ret)
|
||||
return ECMD_FAILED;
|
||||
return ECMD_PROCESSED;
|
||||
|
453
tools/pvscan.c
453
tools/pvscan.c
@@ -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) {
|
||||
@@ -1193,26 +1279,16 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
|
||||
|
||||
log_debug("online_devs %s %s", dev_name(dev), dev->pvid);
|
||||
|
||||
/*
|
||||
* This should already have been done by the filter, but make
|
||||
* another check directly with udev in case the filter was not
|
||||
* using udev and the native version didn't catch it.
|
||||
*/
|
||||
if (udev_dev_is_mpath_component(dev)) {
|
||||
log_print("pvscan[%d] ignore multipath component %s.", getpid(), dev_name(dev));
|
||||
continue;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -1231,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;
|
||||
@@ -1240,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;
|
||||
}
|
||||
@@ -1257,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(dev, NULL, 1)) {
|
||||
log_print("pvscan[%d] ignore md component %s.", getpid(), dev_name(dev));
|
||||
|
||||
if (do_full_check && dev_is_md_component(cmd, dev, NULL, 1)) {
|
||||
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;
|
||||
}
|
||||
@@ -1274,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;
|
||||
}
|
||||
@@ -1293,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;
|
||||
}
|
||||
@@ -1313,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);
|
||||
@@ -1453,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;
|
||||
}
|
||||
|
||||
@@ -1519,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);
|
||||
}
|
||||
}
|
||||
@@ -1556,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;
|
||||
}
|
||||
@@ -1567,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;
|
||||
}
|
||||
@@ -1576,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);
|
||||
}
|
||||
}
|
||||
@@ -1621,18 +1806,53 @@ int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv)
|
||||
struct pvscan_aa_params pp = { 0 };
|
||||
struct dm_list complete_vgnames;
|
||||
int do_activate = arg_is_set(cmd, activate_ARG);
|
||||
int event_activation;
|
||||
int devno_args = 0;
|
||||
int do_all;
|
||||
int ret;
|
||||
|
||||
dm_list_init(&complete_vgnames);
|
||||
|
||||
if (do_activate &&
|
||||
!find_config_tree_bool(cmd, global_event_activation_CFG, NULL)) {
|
||||
cmd->check_devs_used = 0;
|
||||
|
||||
event_activation = find_config_tree_bool(cmd, global_event_activation_CFG, NULL);
|
||||
|
||||
if (do_activate && !event_activation) {
|
||||
log_verbose("Ignoring pvscan --cache -aay because event_activation is disabled.");
|
||||
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;
|
||||
|
||||
@@ -1643,12 +1863,17 @@ 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 (!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;
|
||||
}
|
||||
if (!_pvscan_cache_args(cmd, argc, argv, &complete_vgnames))
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
@@ -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;
|
||||
@@ -2140,7 +2158,6 @@ int process_each_vg(struct cmd_context *cmd,
|
||||
struct dm_list vgnameids_to_process; /* vgnameid_list */
|
||||
int enable_all_vgs = (cmd->cname->flags & ALL_VGS_IS_DEFAULT);
|
||||
int process_all_vgs_on_system = 0;
|
||||
int gl_ex = 0;
|
||||
int ret_max = ECMD_PROCESSED;
|
||||
int ret;
|
||||
|
||||
@@ -2174,25 +2191,11 @@ int process_each_vg(struct cmd_context *cmd,
|
||||
process_all_vgs_on_system = 1;
|
||||
|
||||
/*
|
||||
* The global lock will be taken prior to scanning if the
|
||||
* /run/lvm/scan_lock_global file has been created by a prior command,
|
||||
* indicating that vg metadata sizes are large enough to possibly wrap
|
||||
* around the metadata area during label_scan or between label_scan and
|
||||
* vg_read, which can invalidate the scan results (normally unlocked)
|
||||
* and prevent a valid vg_read (which uses metadata locations saved by
|
||||
* label_scan).
|
||||
* Needed for a current listing of the global VG namespace.
|
||||
*/
|
||||
if (do_scan_lock_global(cmd, &gl_ex)) {
|
||||
if (!lock_global(cmd, gl_ex ? "ex" : "sh")) {
|
||||
ret_max = ECMD_FAILED;
|
||||
goto_out;
|
||||
}
|
||||
} else if (process_all_vgs_on_system) {
|
||||
/* Needed for a current listing of the global VG namespace. */
|
||||
if (!lock_global(cmd, "sh")) {
|
||||
ret_max = ECMD_FAILED;
|
||||
goto_out;
|
||||
}
|
||||
if (process_all_vgs_on_system && !lock_global(cmd, "sh")) {
|
||||
ret_max = ECMD_FAILED;
|
||||
goto_out;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3683,7 +3686,6 @@ int process_each_lv(struct cmd_context *cmd,
|
||||
struct dm_list vgnameids_to_process; /* vgnameid_list */
|
||||
int enable_all_vgs = (cmd->cname->flags & ALL_VGS_IS_DEFAULT);
|
||||
int process_all_vgs_on_system = 0;
|
||||
int gl_ex = 0;
|
||||
int ret_max = ECMD_PROCESSED;
|
||||
int ret;
|
||||
|
||||
@@ -3738,17 +3740,12 @@ int process_each_lv(struct cmd_context *cmd,
|
||||
else if (dm_list_empty(&arg_vgnames) && handle->internal_report_for_select)
|
||||
process_all_vgs_on_system = 1;
|
||||
|
||||
if (do_scan_lock_global(cmd, &gl_ex)) {
|
||||
if (!lock_global(cmd, gl_ex ? "ex" : "sh")) {
|
||||
ret_max = ECMD_FAILED;
|
||||
goto_out;
|
||||
}
|
||||
} else if (process_all_vgs_on_system) {
|
||||
/* Needed for a current listing of the global VG namespace. */
|
||||
if (!lock_global(cmd, "sh")) {
|
||||
ret_max = ECMD_FAILED;
|
||||
goto_out;
|
||||
}
|
||||
/*
|
||||
* Needed for a current listing of the global VG namespace.
|
||||
*/
|
||||
if (process_all_vgs_on_system && !lock_global(cmd, "sh")) {
|
||||
ret_max = ECMD_FAILED;
|
||||
goto_out;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4405,7 +4402,6 @@ int process_each_pv(struct cmd_context *cmd,
|
||||
struct device_id_list *dil;
|
||||
int process_all_pvs;
|
||||
int process_all_devices;
|
||||
int gl_ex = 0;
|
||||
int ret_max = ECMD_PROCESSED;
|
||||
int ret;
|
||||
|
||||
@@ -4456,17 +4452,10 @@ int process_each_pv(struct cmd_context *cmd,
|
||||
|
||||
process_all_devices = process_all_pvs && (cmd->cname->flags & ENABLE_ALL_DEVS) && all_is_set;
|
||||
|
||||
if (do_scan_lock_global(cmd, &gl_ex)) {
|
||||
if (!lock_global(cmd, gl_ex ? "ex" : "sh")) {
|
||||
ret_max = ECMD_FAILED;
|
||||
goto_out;
|
||||
}
|
||||
} else if (!only_this_vgname) {
|
||||
/* Needed for a current listing of the global VG namespace. */
|
||||
if (!lock_global(cmd, "sh")) {
|
||||
ret_max = ECMD_FAILED;
|
||||
goto_out;
|
||||
}
|
||||
/* Needed for a current listing of the global VG namespace. */
|
||||
if (!only_this_vgname && !lock_global(cmd, "sh")) {
|
||||
ret_max = ECMD_FAILED;
|
||||
goto_out;
|
||||
}
|
||||
|
||||
if (!(read_flags & PROCESS_SKIP_SCAN))
|
||||
|
@@ -139,6 +139,8 @@ struct arg_value_group_list {
|
||||
#define ALLOW_HINTS 0x00004000
|
||||
/* Command can access exported vg. */
|
||||
#define ALLOW_EXPORTED 0x00008000
|
||||
/* Command checks and reports warning if devs used by LV are incorrect. */
|
||||
#define CHECK_DEVS_USED 0x00010000
|
||||
|
||||
|
||||
void usage(const char *name);
|
||||
@@ -291,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
|
||||
|
@@ -61,14 +61,14 @@ static int _update_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
/*
|
||||
* N.B. lvs_in_vg_activated() is not smart enough to distinguish
|
||||
* between LVs that are active in the original VG vs the cloned VG
|
||||
* that's being imported, so check DEV_USED_FOR_LV.
|
||||
* that's being imported, so check dev_is_used_by_active_lv.
|
||||
*/
|
||||
dm_list_iterate_items(pvl, &vg->pvs) {
|
||||
if (is_missing_pv(pvl->pv) || !pvl->pv->dev) {
|
||||
log_error("VG is missing a device.");
|
||||
goto bad;
|
||||
}
|
||||
if (pvl->pv->dev->flags & DEV_USED_FOR_LV) {
|
||||
if (dev_is_used_by_active_lv(cmd, pvl->pv->dev, NULL, NULL, NULL, NULL)) {
|
||||
log_error("Device %s has active LVs, deactivate first.", dev_name(pvl->pv->dev));
|
||||
devs_used_for_lv++;
|
||||
}
|
||||
|
87
udev/69-dm-lvm.rules.in
Normal file
87
udev/69-dm-lvm.rules.in
Normal 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"
|
||||
|
@@ -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}')
|
||||
|
||||
|
Reference in New Issue
Block a user