1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-09-20 05:44:20 +03:00

Compare commits

..

1 Commits

Author SHA1 Message Date
David Teigland
07338325e5 devices: fix name handling
- Fix cases where incorrect device paths were left
  on the dev->aliases list.  Leaving incorrect paths
  on dev->aliases could result in using the wrong device.

- Fix a widespread incorrect assumption that dev_name()
  always returns a valid path (or NULL).  dev_name()
  returns "[unknown]" when there are no paths to a
  device, and is mainly meant to be used in messages.

- Check for valid dev paths in cases that want to use
  the from dev_name() for things other than a message.
2022-02-24 15:37:53 -06:00
297 changed files with 10714 additions and 24522 deletions

21
.gitignore vendored
View File

@@ -16,10 +16,6 @@
*.sw*
*~
# gcov files:
*.gcda
*.gcno
.export.sym
.exported_symbols_generated
.gdb_history
@@ -43,11 +39,9 @@ make.tmpl
coverity/coverity_model.xml
/libdm/.symver_check
daemons/clvmd
daemons/dmfilemapd
daemons/lvmetad/
# gcov files:
*.gcda
*.gcno
tools/man-generator
tools/man-generator.c
@@ -108,8 +102,6 @@ test/api/thin_percent.t
test/api/vglist.t
test/api/vgtest.t
test/lib/aux
test/lib/cache-mq.profile
test/lib/cache-smq.profile
test/lib/check
test/lib/clvmd
test/lib/dm-version-expected
@@ -119,7 +111,6 @@ test/lib/dmstats
test/lib/fail
test/lib/flavour-ndev-cluster
test/lib/flavour-ndev-cluster-lvmpolld
test/lib/flavour-ndev-devicesfile
test/lib/flavour-ndev-lvmetad
test/lib/flavour-ndev-lvmetad-lvmpolld
test/lib/flavour-ndev-lvmpolld
@@ -129,7 +120,6 @@ test/lib/flavour-udev-cluster-lvmpolld
test/lib/flavour-udev-lvmetad
test/lib/flavour-udev-lvmetad-lvmpolld
test/lib/flavour-udev-lvmlockd-dlm
test/lib/flavour-udev-lvmlockd-idm
test/lib/flavour-udev-lvmlockd-sanlock
test/lib/flavour-udev-lvmlockd-test
test/lib/flavour-udev-lvmpolld
@@ -142,11 +132,8 @@ test/lib/lvm
test/lib/lvm-wrapper
test/lib/lvmchange
test/lib/lvmdbusd.profile
test/lib/lvmdevices
test/lib/lvmetad
test/lib/lvmpolld
test/lib/lvm_import_vdo
test/lib/lvm_vdo_wrapper
test/lib/not
test/lib/paths
test/lib/paths-common
@@ -156,7 +143,5 @@ test/lib/test
test/lib/thin-performance.profile
test/lib/utils
test/lib/version-expected
test/lib/vgimportdevices
test/unit/dmraid_t.c
test/unit/unit-test

View File

@@ -47,7 +47,7 @@ include $(top_srcdir)/base/Makefile
include $(top_srcdir)/device_mapper/Makefile
include $(top_srcdir)/test/unit/Makefile
lib: include libdaemon $(BASE_TARGET) $(DEVICE_MAPPER_TARGET)
lib: libdaemon $(BASE_TARGET) $(DEVICE_MAPPER_TARGET)
daemons: lib libdaemon tools
scripts: lib
tools: lib libdaemon

View File

@@ -24,7 +24,7 @@ You MUST disable (or mask) any LVM daemons:
For running cluster tests, we are using singlenode locking. Pass
`--with-clvmd=singlenode` to configure.
NOTE: This is useful only for testing, and should not be used in production
NOTE: This is useful only for testing, and should not be used in produciton
code.
To run D-Bus daemon tests, existing D-Bus session is required.

View File

@@ -1 +1 @@
2.03.19(2)-git (2022-12-22)
2.03.16(2)-git (2022-02-07)

View File

@@ -1 +1 @@
1.02.191-git (2022-12-22)
1.02.185-git (2022-02-07)

View File

@@ -1,44 +1,5 @@
version 2.03.19 -
Version 2.03.16 -
====================================
Do not reset SYSTEMD_READY variable in udev for PVs on MD and loop devices.
Ensure udev is processing origin LV before its thick snapshots LVs.
Fix and improve runtime memory size detection for VDO volumes.
version 2.03.18 - 22nd december 2022
====================================
Fix issues reported by coverity scan.
Fix warning for thin pool overprovisioning on lvextend (2.03.17).
Add support for writecache metadata_only and pause_writeback settings.
Fix missing error messages in lvmdbusd.
Version 2.03.17 - 10th November 2022
====================================
Add new options (--fs, --fsmode) for FS handling when resizing LVs.
Fix 'lvremove -S|--select LV' to not also remove its historical LV right away.
Fix lv_active field type to binary so --select and --binary applies properly.
Switch to use mallinfo2 and use it only with glibc.
Error out in lvm shell if using a cmd argument not supported in the shell.
Fix lvm shell's lastlog command to report previous pre-command failures.
Extend VDO and VDOPOOL without flushing and locking fs.
Add --valuesonly option to lvmconfig to print only values without keys.
Updates configure with recent autoconf tooling.
Fix lvconvert --test --type vdo-pool execution.
Add json_std output format for more JSON standard compliant version of output.
Fix vdo_slab_size_mb value for converted VDO volume.
Fix many corner cases in device_id, including handling of S/N duplicates.
Fix various issues in lvmdbusd.
Version 2.03.16 - 18th May 2022
===============================
Fix segfault when handling selection with historical LVs.
Add support --vdosettings with lvcreate, lvconvert, lvchange.
Filtering multipath devices respects blacklist setting from multipath
configuration.
lvmdevices support for removing by device id using --deviceidtype and
--deldev.
Display writecache block size with lvs -o writecache_block_size.
Improve cachesettings description in man lvmcache.
Fix lossing of delete message on thin-pool extension.
Version 2.03.15 - 07th February 2022
====================================
@@ -199,7 +160,7 @@ Version 2.03.10 - 09th August 2020
Version 2.03.09 - 26th March 2020
=================================
Fix formatting of vdopool (vdo_slab_size_mb was smaller by 2 bits).
Fix formating of vdopool (vdo_slab_size_mb was smaller by 2 bits).
Fix showing of a dm kernel error when uncaching a volume with cachevol.
Version 2.03.08 - 11th February 2020

View File

@@ -1,17 +1,5 @@
Version 1.02.191 -
Version 1.02.185 -
=====================================
Remove NAME="mapper/control" rule from 10-dm.rules to avoid udev warnings.
Version 1.02.189 - 22nd December 2022
=====================================
Improve 'dmsetup create' without given table line with new kernels.
Version 1.02.187 - 10th November 2022
=====================================
Add DM_REPORT_GROUP_JSON_STD for more JSON standard compliant output format.
Version 1.02.185 - 18th May 2022
================================
Version 1.02.183 - 07th February 2022
=====================================

272
aclocal.m4 vendored
View File

@@ -1,6 +1,6 @@
# generated automatically by aclocal 1.16.5 -*- Autoconf -*-
# generated automatically by aclocal 1.16.2 -*- Autoconf -*-
# Copyright (C) 1996-2021 Free Software Foundation, Inc.
# Copyright (C) 1996-2020 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -413,7 +413,7 @@ AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"],
[AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])])
])dnl PKG_HAVE_DEFINE_WITH_MODULES
# Copyright (C) 1999-2021 Free Software Foundation, Inc.
# Copyright (C) 1999-2020 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -492,7 +492,7 @@ AC_DEFUN([AM_PATH_PYTHON],
])
if test "$PYTHON" = :; then
dnl Run any user-specified action, or abort.
dnl Run any user-specified action, or abort.
m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])])
else
@@ -501,132 +501,27 @@ AC_DEFUN([AM_PATH_PYTHON],
dnl trailing zero was eliminated. So now we output just the major
dnl and minor version numbers, as numbers. Apparently the tertiary
dnl version is not of interest.
dnl
AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version],
[am_cv_python_version=`$PYTHON -c "import sys; print ('%u.%u' % sys.version_info[[:2]])"`])
[am_cv_python_version=`$PYTHON -c "import sys; print('%u.%u' % sys.version_info[[:2]])"`])
AC_SUBST([PYTHON_VERSION], [$am_cv_python_version])
dnl At times, e.g., when building shared libraries, you may want
dnl Use the values of $prefix and $exec_prefix for the corresponding
dnl values of PYTHON_PREFIX and PYTHON_EXEC_PREFIX. These are made
dnl distinct variables so they can be overridden if need be. However,
dnl general consensus is that you shouldn't need this ability.
AC_SUBST([PYTHON_PREFIX], ['${prefix}'])
AC_SUBST([PYTHON_EXEC_PREFIX], ['${exec_prefix}'])
dnl At times (like when building shared libraries) you may want
dnl to know which OS platform Python thinks this is.
dnl
AC_CACHE_CHECK([for $am_display_PYTHON platform], [am_cv_python_platform],
[am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"`])
AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform])
dnl emacs-page
dnl If --with-python-sys-prefix is given, use the values of sys.prefix
dnl and sys.exec_prefix for the corresponding values of PYTHON_PREFIX
dnl and PYTHON_EXEC_PREFIX. Otherwise, use the GNU ${prefix} and
dnl ${exec_prefix} variables.
dnl
dnl The two are made distinct variables so they can be overridden if
dnl need be, although general consensus is that you shouldn't need
dnl this separation.
dnl
dnl Also allow directly setting the prefixes via configure options,
dnl overriding any default.
dnl
if test "x$prefix" = xNONE; then
am__usable_prefix=$ac_default_prefix
else
am__usable_prefix=$prefix
fi
# Allow user to request using sys.* values from Python,
# instead of the GNU $prefix values.
AC_ARG_WITH([python-sys-prefix],
[AS_HELP_STRING([--with-python-sys-prefix],
[use Python's sys.prefix and sys.exec_prefix values])],
[am_use_python_sys=:],
[am_use_python_sys=false])
# Allow user to override whatever the default Python prefix is.
AC_ARG_WITH([python_prefix],
[AS_HELP_STRING([--with-python_prefix],
[override the default PYTHON_PREFIX])],
[am_python_prefix_subst=$withval
am_cv_python_prefix=$withval
AC_MSG_CHECKING([for explicit $am_display_PYTHON prefix])
AC_MSG_RESULT([$am_cv_python_prefix])],
[
if $am_use_python_sys; then
# using python sys.prefix value, not GNU
AC_CACHE_CHECK([for python default $am_display_PYTHON prefix],
[am_cv_python_prefix],
[am_cv_python_prefix=`$PYTHON -c "import sys; sys.stdout.write(sys.prefix)"`])
dnl If sys.prefix is a subdir of $prefix, replace the literal value of
dnl $prefix with a variable reference so it can be overridden.
case $am_cv_python_prefix in
$am__usable_prefix*)
am__strip_prefix=`echo "$am__usable_prefix" | sed 's|.|.|g'`
am_python_prefix_subst=`echo "$am_cv_python_prefix" | sed "s,^$am__strip_prefix,\\${prefix},"`
;;
*)
am_python_prefix_subst=$am_cv_python_prefix
;;
esac
else # using GNU prefix value, not python sys.prefix
am_python_prefix_subst='${prefix}'
am_python_prefix=$am_python_prefix_subst
AC_MSG_CHECKING([for GNU default $am_display_PYTHON prefix])
AC_MSG_RESULT([$am_python_prefix])
fi])
# Substituting python_prefix_subst value.
AC_SUBST([PYTHON_PREFIX], [$am_python_prefix_subst])
# emacs-page Now do it all over again for Python exec_prefix, but with yet
# another conditional: fall back to regular prefix if that was specified.
AC_ARG_WITH([python_exec_prefix],
[AS_HELP_STRING([--with-python_exec_prefix],
[override the default PYTHON_EXEC_PREFIX])],
[am_python_exec_prefix_subst=$withval
am_cv_python_exec_prefix=$withval
AC_MSG_CHECKING([for explicit $am_display_PYTHON exec_prefix])
AC_MSG_RESULT([$am_cv_python_exec_prefix])],
[
# no explicit --with-python_exec_prefix, but if
# --with-python_prefix was given, use its value for python_exec_prefix too.
AS_IF([test -n "$with_python_prefix"],
[am_python_exec_prefix_subst=$with_python_prefix
am_cv_python_exec_prefix=$with_python_prefix
AC_MSG_CHECKING([for python_prefix-given $am_display_PYTHON exec_prefix])
AC_MSG_RESULT([$am_cv_python_exec_prefix])],
[
# Set am__usable_exec_prefix whether using GNU or Python values,
# since we use that variable for pyexecdir.
if test "x$exec_prefix" = xNONE; then
am__usable_exec_prefix=$am__usable_prefix
else
am__usable_exec_prefix=$exec_prefix
fi
#
if $am_use_python_sys; then # using python sys.exec_prefix, not GNU
AC_CACHE_CHECK([for python default $am_display_PYTHON exec_prefix],
[am_cv_python_exec_prefix],
[am_cv_python_exec_prefix=`$PYTHON -c "import sys; sys.stdout.write(sys.exec_prefix)"`])
dnl If sys.exec_prefix is a subdir of $exec_prefix, replace the
dnl literal value of $exec_prefix with a variable reference so it can
dnl be overridden.
case $am_cv_python_exec_prefix in
$am__usable_exec_prefix*)
am__strip_prefix=`echo "$am__usable_exec_prefix" | sed 's|.|.|g'`
am_python_exec_prefix_subst=`echo "$am_cv_python_exec_prefix" | sed "s,^$am__strip_prefix,\\${exec_prefix},"`
;;
*)
am_python_exec_prefix_subst=$am_cv_python_exec_prefix
;;
esac
else # using GNU $exec_prefix, not python sys.exec_prefix
am_python_exec_prefix_subst='${exec_prefix}'
am_python_exec_prefix=$am_python_exec_prefix_subst
AC_MSG_CHECKING([for GNU default $am_display_PYTHON exec_prefix])
AC_MSG_RESULT([$am_python_exec_prefix])
fi])])
# Substituting python_exec_prefix_subst.
AC_SUBST([PYTHON_EXEC_PREFIX], [$am_python_exec_prefix_subst])
# Factor out some code duplication into this shell variable.
# Just factor out some code duplication.
am_python_setup_sysconfig="\
import sys
# Prefer sysconfig over distutils.sysconfig, for better compatibility
@@ -646,95 +541,96 @@ try:
except ImportError:
pass"
dnl emacs-page Set up 4 directories:
dnl Set up 4 directories:
dnl 1. pythondir: where to install python scripts. This is the
dnl site-packages directory, not the python standard library
dnl directory like in previous automake betas. This behavior
dnl is more consistent with lispdir.m4 for example.
dnl pythondir -- where to install python scripts. This is the
dnl site-packages directory, not the python standard library
dnl directory like in previous automake betas. This behavior
dnl is more consistent with lispdir.m4 for example.
dnl Query distutils for this directory.
dnl
AC_CACHE_CHECK([for $am_display_PYTHON script directory (pythondir)],
[am_cv_python_pythondir],
[if test "x$am_cv_python_prefix" = x; then
am_py_prefix=$am__usable_prefix
else
am_py_prefix=$am_cv_python_prefix
fi
am_cv_python_pythondir=`$PYTHON -c "
AC_CACHE_CHECK([for $am_display_PYTHON script directory],
[am_cv_python_pythondir],
[if test "x$prefix" = xNONE
then
am_py_prefix=$ac_default_prefix
else
am_py_prefix=$prefix
fi
am_cv_python_pythondir=`$PYTHON -c "
$am_python_setup_sysconfig
if can_use_sysconfig:
sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'})
sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'})
else:
from distutils import sysconfig
sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix')
from distutils import sysconfig
sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix')
sys.stdout.write(sitedir)"`
#
case $am_cv_python_pythondir in
$am_py_prefix*)
am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'`
am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,\\${PYTHON_PREFIX},"`
;;
*)
case $am_py_prefix in
/usr|/System*) ;;
*) am_cv_python_pythondir="\${PYTHON_PREFIX}/lib/python$PYTHON_VERSION/site-packages"
;;
case $am_cv_python_pythondir in
$am_py_prefix*)
am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'`
am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,$PYTHON_PREFIX,"`
;;
*)
case $am_py_prefix in
/usr|/System*) ;;
*)
am_cv_python_pythondir=$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages
;;
esac
;;
esac
;;
esac
])
])
AC_SUBST([pythondir], [$am_cv_python_pythondir])
dnl 2. pkgpythondir: $PACKAGE directory under pythondir. Was
dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is
dnl more consistent with the rest of automake.
dnl
dnl pkgpythondir -- $PACKAGE directory under pythondir. Was
dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is
dnl more consistent with the rest of automake.
AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE])
dnl 3. pyexecdir: directory for installing python extension modules
dnl (shared libraries).
dnl pyexecdir -- directory for installing python extension modules
dnl (shared libraries)
dnl Query distutils for this directory.
dnl
AC_CACHE_CHECK([for $am_display_PYTHON extension module directory (pyexecdir)],
[am_cv_python_pyexecdir],
[if test "x$am_cv_python_exec_prefix" = x; then
am_py_exec_prefix=$am__usable_exec_prefix
else
am_py_exec_prefix=$am_cv_python_exec_prefix
fi
am_cv_python_pyexecdir=`$PYTHON -c "
AC_CACHE_CHECK([for $am_display_PYTHON extension module directory],
[am_cv_python_pyexecdir],
[if test "x$exec_prefix" = xNONE
then
am_py_exec_prefix=$am_py_prefix
else
am_py_exec_prefix=$exec_prefix
fi
am_cv_python_pyexecdir=`$PYTHON -c "
$am_python_setup_sysconfig
if can_use_sysconfig:
sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_exec_prefix'})
sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_prefix'})
else:
from distutils import sysconfig
sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_exec_prefix')
from distutils import sysconfig
sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_prefix')
sys.stdout.write(sitedir)"`
#
case $am_cv_python_pyexecdir in
$am_py_exec_prefix*)
am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'`
am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,\\${PYTHON_EXEC_PREFIX},"`
;;
*)
case $am_py_exec_prefix in
/usr|/System*) ;;
*) am_cv_python_pyexecdir="\${PYTHON_EXEC_PREFIX}/lib/python$PYTHON_VERSION/site-packages"
;;
case $am_cv_python_pyexecdir in
$am_py_exec_prefix*)
am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'`
am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,$PYTHON_EXEC_PREFIX,"`
;;
*)
case $am_py_exec_prefix in
/usr|/System*) ;;
*)
am_cv_python_pyexecdir=$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages
;;
esac
;;
esac
;;
esac
])
])
AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir])
dnl 4. pkgpyexecdir: $(pyexecdir)/$(PACKAGE)
dnl
dnl pkgpyexecdir -- $(pyexecdir)/$(PACKAGE)
AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE])
dnl Run any user-specified action.
$2
fi
])
@@ -757,7 +653,7 @@ for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[[i]]
sys.exit(sys.hexversion < minverhex)"
AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])])
# Copyright (C) 2001-2021 Free Software Foundation, Inc.
# Copyright (C) 2001-2020 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,

1712
autoconf/config.guess vendored

File diff suppressed because it is too large Load Diff

2881
autoconf/config.sub vendored

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
#!/usr/bin/sh
#!/bin/sh
# install - install a program, script, or datafile
scriptversion=2020-11-14.01; # UTC
scriptversion=2006-10-14.15
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
@@ -35,62 +35,57 @@ scriptversion=2020-11-14.01; # UTC
# FSF changes to this file are in the public domain.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# 'make' implicit rules from creating a file called install from it
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch.
tab=' '
nl='
'
IFS=" $tab$nl"
IFS=" "" $nl"
# Set DOITPROG to "echo" to test this script.
# set DOITPROG to echo to test this script
doit=${DOITPROG-}
doit_exec=${doit:-exec}
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"
if test -z "$doit"; then
doit_exec=exec
else
doit_exec=$doit
fi
# Put in absolute file names if you don't have them in your path;
# or use environment vars.
chgrpprog=${CHGRPPROG-chgrp}
chmodprog=${CHMODPROG-chmod}
chownprog=${CHOWNPROG-chown}
cmpprog=${CMPPROG-cmp}
cpprog=${CPPROG-cp}
mkdirprog=${MKDIRPROG-mkdir}
mvprog=${MVPROG-mv}
rmprog=${RMPROG-rm}
stripprog=${STRIPPROG-strip}
mvprog="${MVPROG-mv}"
cpprog="${CPPROG-cp}"
chmodprog="${CHMODPROG-chmod}"
chownprog="${CHOWNPROG-chown}"
chgrpprog="${CHGRPPROG-chgrp}"
stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"
posix_glob=
posix_mkdir=
# Desired mode of installed file.
mode=0755
# Create dirs (including intermediate dirs) using mode 755.
# This is like GNU 'install' as of coreutils 8.32 (2020).
mkdir_umask=22
backupsuffix=
chgrpcmd=
chmodcmd=$chmodprog
chowncmd=
mvcmd=$mvprog
rmcmd="$rmprog -f"
chgrpcmd=
stripcmd=
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src=
dst=
dir_arg=
dst_arg=
dstarg=
no_target_directory=
copy_on_change=false
is_target_a_directory=possibly
usage="\
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
or: $0 [OPTION]... SRCFILES... DIRECTORY
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
or: $0 [OPTION]... -d DIRECTORIES...
@@ -100,116 +95,91 @@ In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
In the 4th, create DIRECTORIES.
Options:
--help display this help and exit.
--version display version info and exit.
-c (ignored)
-C install only if different (preserve data modification time)
-d create directories instead of installing files.
-g GROUP $chgrpprog installed files to GROUP.
-m MODE $chmodprog installed files to MODE.
-o USER $chownprog installed files to USER.
-p pass -p to $cpprog.
-s $stripprog installed files.
-S SUFFIX attempt to back up existing files, with suffix SUFFIX.
-t DIRECTORY install into DIRECTORY.
-T report an error if DSTFILE is a directory.
-c (ignored)
-d create directories instead of installing files.
-g GROUP $chgrpprog installed files to GROUP.
-m MODE $chmodprog installed files to MODE.
-o USER $chownprog installed files to USER.
-s $stripprog installed files.
-t DIRECTORY install into DIRECTORY.
-T report an error if DSTFILE is a directory.
--help display this help and exit.
--version display version info and exit.
Environment variables override the default commands:
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
RMPROG STRIPPROG
By default, rm is invoked with -f; when overridden with RMPROG,
it's up to you to specify -f if you want it.
If -S is not specified, no backups are attempted.
Email bug reports to bug-automake@gnu.org.
Automake home page: https://www.gnu.org/software/automake/
CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
"
while test $# -ne 0; do
case $1 in
-c) ;;
-c) shift
continue;;
-C) copy_on_change=true;;
-d) dir_arg=true;;
-d) dir_arg=true
shift
continue;;
-g) chgrpcmd="$chgrpprog $2"
shift;;
shift
shift
continue;;
--help) echo "$usage"; exit $?;;
-m) mode=$2
case $mode in
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
shift;;
shift
shift
case $mode in
*' '* | *' '* | *'
'* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
continue;;
-o) chowncmd="$chownprog $2"
shift;;
shift
shift
continue;;
-p) cpprog="$cpprog -p";;
-s) stripcmd=$stripprog
shift
continue;;
-s) stripcmd=$stripprog;;
-t) dstarg=$2
shift
shift
continue;;
-S) backupsuffix="$2"
shift;;
-t)
is_target_a_directory=always
dst_arg=$2
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
shift;;
-T) is_target_a_directory=never;;
-T) no_target_directory=true
shift
continue;;
--version) echo "$0 $scriptversion"; exit $?;;
--) shift
break;;
--) shift
break;;
-*) echo "$0: invalid option: $1" >&2
exit 1;;
-*) echo "$0: invalid option: $1" >&2
exit 1;;
*) break;;
esac
shift
done
# We allow the use of options -d and -T together, by making -d
# take the precedence; this is for compatibility with GNU install.
if test -n "$dir_arg"; then
if test -n "$dst_arg"; then
echo "$0: target directory not allowed when installing a directory." >&2
exit 1
fi
fi
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
if test $# -ne 0 && test -z "$dir_arg$dstarg"; then
# When -d is used, all remaining arguments are directories to create.
# When -t is used, the destination is already specified.
# Otherwise, the last argument is the destination. Remove it from $@.
for arg
do
if test -n "$dst_arg"; then
if test -n "$dstarg"; then
# $@ is not empty: it contains at least $arg.
set fnord "$@" "$dst_arg"
set fnord "$@" "$dstarg"
shift # fnord
fi
shift # arg
dst_arg=$arg
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
dstarg=$arg
done
fi
@@ -218,26 +188,13 @@ if test $# -eq 0; then
echo "$0: no input file specified." >&2
exit 1
fi
# It's OK to call 'install-sh -d' without argument.
# It's OK to call `install-sh -d' without argument.
# This can happen when creating conditional directories.
exit 0
fi
if test -z "$dir_arg"; then
if test $# -gt 1 || test "$is_target_a_directory" = always; then
if test ! -d "$dst_arg"; then
echo "$0: $dst_arg: Is not a directory." >&2
exit 1
fi
fi
fi
if test -z "$dir_arg"; then
do_exit='(exit $ret); exit $ret'
trap "ret=129; $do_exit" 1
trap "ret=130; $do_exit" 2
trap "ret=141; $do_exit" 13
trap "ret=143; $do_exit" 15
trap '(exit $?); exit' 1 2 13 15
# Set umask so as not to create temps with too-generous modes.
# However, 'strip' requires both read and write access to temps.
@@ -248,16 +205,16 @@ if test -z "$dir_arg"; then
*[0-7])
if test -z "$stripcmd"; then
u_plus_rw=
u_plus_rw=
else
u_plus_rw='% 200'
u_plus_rw='% 200'
fi
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
*)
if test -z "$stripcmd"; then
u_plus_rw=
u_plus_rw=
else
u_plus_rw=,u+rw
u_plus_rw=,u+rw
fi
cp_umask=$mode$u_plus_rw;;
esac
@@ -265,9 +222,9 @@ fi
for src
do
# Protect names problematic for 'test' and other utilities.
# Protect names starting with `-'.
case $src in
-* | [=\(\)!]) src=./$src;;
-*) src=./$src ;;
esac
if test -n "$dir_arg"; then
@@ -275,10 +232,6 @@ do
dstdir=$dst
test -d "$dstdir"
dstdir_status=$?
# Don't chown directories that already exist.
if test $dstdir_status = 0; then
chowncmd=""
fi
else
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
@@ -289,154 +242,196 @@ do
exit 1
fi
if test -z "$dst_arg"; then
if test -z "$dstarg"; then
echo "$0: no destination specified." >&2
exit 1
fi
dst=$dst_arg
# If destination is a directory, append the input filename.
dst=$dstarg
# Protect names starting with `-'.
case $dst in
-*) dst=./$dst ;;
esac
# If destination is a directory, append the input filename; won't work
# if double slashes aren't ignored.
if test -d "$dst"; then
if test "$is_target_a_directory" = never; then
echo "$0: $dst_arg: Is a directory" >&2
exit 1
if test -n "$no_target_directory"; then
echo "$0: $dstarg: Is a directory" >&2
exit 1
fi
dstdir=$dst
dstbase=`basename "$src"`
case $dst in
*/) dst=$dst$dstbase;;
*) dst=$dst/$dstbase;;
esac
dst=$dstdir/`basename "$src"`
dstdir_status=0
else
dstdir=`dirname "$dst"`
# Prefer dirname, but fall back on a substitute if dirname fails.
dstdir=`
(dirname "$dst") 2>/dev/null ||
expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$dst" : 'X\(//\)[^/]' \| \
X"$dst" : 'X\(//\)$' \| \
X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
echo X"$dst" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
}
/^X\(\/\/\)[^/].*/{
s//\1/
q
}
/^X\(\/\/\)$/{
s//\1/
q
}
/^X\(\/\).*/{
s//\1/
q
}
s/.*/./; q'
`
test -d "$dstdir"
dstdir_status=$?
fi
fi
case $dstdir in
*/) dstdirslash=$dstdir;;
*) dstdirslash=$dstdir/;;
esac
obsolete_mkdir_used=false
if test $dstdir_status != 0; then
case $posix_mkdir in
'')
# With -d, create the new directory with the user-specified mode.
# Otherwise, rely on $mkdir_umask.
if test -n "$dir_arg"; then
mkdir_mode=-m$mode
else
mkdir_mode=
fi
# Create intermediate dirs using mode 755 as modified by the umask.
# This is like FreeBSD 'install' as of 1997-10-28.
umask=`umask`
case $stripcmd.$umask in
# Optimize common cases.
*[2367][2367]) mkdir_umask=$umask;;
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
posix_mkdir=false
# The $RANDOM variable is not portable (e.g., dash). Use it
# here however when possible just to lower collision chance.
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
*[0-7])
mkdir_umask=`expr $umask + 22 \
- $umask % 100 % 40 + $umask % 20 \
- $umask % 10 % 4 + $umask % 2
`;;
*) mkdir_umask=$umask,go-w;;
esac
trap '
ret=$?
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null
exit $ret
' 0
# Because "mkdir -p" follows existing symlinks and we likely work
# directly in world-writeable /tmp, make sure that the '$tmpdir'
# directory is successfully created first before we actually test
# 'mkdir -p'.
if (umask $mkdir_umask &&
$mkdirprog $mkdir_mode "$tmpdir" &&
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
then
if test -z "$dir_arg" || {
# Check for POSIX incompatibilities with -m.
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
# other-writable bit of parent directory when it shouldn't.
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
test_tmpdir="$tmpdir/a"
ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
case $ls_ld_tmpdir in
d????-?r-*) different_mode=700;;
d????-?--*) different_mode=755;;
*) false;;
esac &&
$mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
}
}
then posix_mkdir=:
fi
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
# With -d, create the new directory with the user-specified mode.
# Otherwise, rely on $mkdir_umask.
if test -n "$dir_arg"; then
mkdir_mode=-m$mode
else
# Remove any dirs left behind by ancient mkdir implementations.
rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
mkdir_mode=
fi
trap '' 0;;
posix_mkdir=false
case $umask in
*[123567][0-7][0-7])
# POSIX mkdir -p sets u+wx bits regardless of umask, which
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
;;
*)
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
if (umask $mkdir_umask &&
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
then
if test -z "$dir_arg" || {
# Check for POSIX incompatibilities with -m.
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
# other-writeable bit of parent directory when it shouldn't.
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
ls_ld_tmpdir=`ls -ld "$tmpdir"`
case $ls_ld_tmpdir in
d????-?r-*) different_mode=700;;
d????-?--*) different_mode=755;;
*) false;;
esac &&
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
}
}
then posix_mkdir=:
fi
rmdir "$tmpdir/d" "$tmpdir"
else
# Remove any dirs left behind by ancient mkdir implementations.
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
fi
trap '' 0;;
esac;;
esac
if
$posix_mkdir && (
umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
)
then :
else
# mkdir does not conform to POSIX,
# The umask is ridiculous, or mkdir does not conform to POSIX,
# or it failed possibly due to a race condition. Create the
# directory the slow way, step by step, checking for races as we go.
case $dstdir in
/*) prefix='/';;
[-=\(\)!]*) prefix='./';;
*) prefix='';;
/*) prefix=/ ;;
-*) prefix=./ ;;
*) prefix= ;;
esac
case $posix_glob in
'')
if (set -f) 2>/dev/null; then
posix_glob=true
else
posix_glob=false
fi ;;
esac
oIFS=$IFS
IFS=/
set -f
$posix_glob && set -f
set fnord $dstdir
shift
set +f
$posix_glob && set +f
IFS=$oIFS
prefixes=
for d
do
test X"$d" = X && continue
test -z "$d" && continue
prefix=$prefix$d
if test -d "$prefix"; then
prefixes=
else
if $posix_mkdir; then
(umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
# Don't fail if two instances are running concurrently.
test -d "$prefix" || exit 1
else
case $prefix in
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
*) qprefix=$prefix;;
esac
prefixes="$prefixes '$qprefix'"
fi
fi
prefix=$prefix/
prefix=$prefix$d
if test -d "$prefix"; then
prefixes=
else
if $posix_mkdir; then
(umask=$mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
# Don't fail if two instances are running concurrently.
test -d "$prefix" || exit 1
else
case $prefix in
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
*) qprefix=$prefix;;
esac
prefixes="$prefixes '$qprefix'"
fi
fi
prefix=$prefix/
done
if test -n "$prefixes"; then
# Don't fail if two instances are running concurrently.
(umask $mkdir_umask &&
eval "\$doit_exec \$mkdirprog $prefixes") ||
test -d "$dstdir" || exit 1
obsolete_mkdir_used=true
# Don't fail if two instances are running concurrently.
(umask $mkdir_umask &&
eval "\$doit_exec \$mkdirprog $prefixes") ||
test -d "$dstdir" || exit 1
obsolete_mkdir_used=true
fi
fi
fi
@@ -449,25 +444,14 @@ do
else
# Make a couple of temp file names in the proper directory.
dsttmp=${dstdirslash}_inst.$$_
rmtmp=${dstdirslash}_rm.$$_
dsttmp=$dstdir/_inst.$$_
rmtmp=$dstdir/_rm.$$_
# Trap to clean up those temp files at exit.
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
# Copy the file name to the temp name.
(umask $cp_umask &&
{ test -z "$stripcmd" || {
# Create $dsttmp read-write so that cp doesn't create it read-only,
# which would cause strip to fail.
if test -z "$doit"; then
: >"$dsttmp" # No need to fork-exec 'touch'.
else
$doit touch "$dsttmp"
fi
}
} &&
$doit_exec $cpprog "$src" "$dsttmp") &&
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
# and set any options; do chmod last to preserve setuid bits.
#
@@ -475,67 +459,49 @@ do
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $cpprog $src $dsttmp" command.
#
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \
&& { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \
&& { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \
&& { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
# If -C, don't bother to copy if it wouldn't change the file.
if $copy_on_change &&
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
set -f &&
set X $old && old=:$2:$4:$5:$6 &&
set X $new && new=:$2:$4:$5:$6 &&
set +f &&
test "$old" = "$new" &&
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
then
rm -f "$dsttmp"
else
# If $backupsuffix is set, and the file being installed
# already exists, attempt a backup. Don't worry if it fails,
# e.g., if mv doesn't support -f.
if test -n "$backupsuffix" && test -f "$dst"; then
$doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null
fi
# Now rename the file to the real destination.
{ $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null \
|| {
# The rename failed, perhaps because mv can't rename something else
# to itself, or perhaps because mv is so ancient that it does not
# support -f.
# Rename the file to the real destination.
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
# Now remove or move aside any old file at destination location.
# We try this two ways since rm can't unlink itself on some
# systems and the destination file might be busy for other
# reasons. In this case, the final cleanup might fail but the new
# file should still install successfully.
{
if test -f "$dst"; then
$doit $rmcmd -f "$dst" 2>/dev/null \
|| { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null \
&& { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }; }\
|| {
echo "$0: cannot unlink or rename $dst" >&2
(exit 1); exit 1
}
else
:
fi
} &&
# The rename failed, perhaps because mv can't rename something else
# to itself, or perhaps because mv is so ancient that it does not
# support -f.
{
# Now remove or move aside any old file at destination location.
# We try this two ways since rm can't unlink itself on some
# systems and the destination file might be busy for other
# reasons. In this case, the final cleanup might fail but the new
# file should still install successfully.
{
test ! -f "$dst" ||
$doit $rmcmd "$dst" 2>/dev/null ||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
{ $doit $rmcmd "$rmtmp" 2>/dev/null; :; }
} ||
{ echo "$0: cannot unlink or rename $dst" >&2
(exit 1); exit 1
}
} &&
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dst"
}
fi || exit 1
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dst"
}
} || exit 1
trap '' 0
fi
done
# Local variables:
# eval: (add-hook 'before-save-hook 'time-stamp)
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# time-stamp-end: "$"
# End:

View File

@@ -126,7 +126,7 @@ devices {
# be used, regardless of this setting, when the --devicesfile
# option is set to a specific file name.
# This configuration option has an automatic default value.
# use_devicesfile = @DEFAULT_USE_DEVICES_FILE@
# use_devicesfile = 0
# Configuration option devices/devicesfile.
# The name of the system devices file, listing devices that LVM should use.
@@ -625,12 +625,13 @@ allocation {
# Enables or disables whether VDO volume should tag its latency-critical
# writes with the REQ_SYNC flag. Some device mapper targets such as dm-raid5
# process writes with this flag at a higher priority.
# Default is enabled.
# This configuration option has an automatic default value.
# vdo_use_metadata_hints = 1
# Configuration option allocation/vdo_minimum_io_size.
# The minimum IO size for VDO volume to accept, in bytes.
# Valid values are 512 or 4096. The recommended value is 4096.
# Valid values are 512 or 4096. The recommended and default value is 4096.
# This configuration option has an automatic default value.
# vdo_minimum_io_size = 4096
@@ -683,7 +684,7 @@ allocation {
# Configuration option allocation/vdo_bio_threads.
# Specifies the number of threads to use for submitting I/O
# operations to the storage device of VDO volume.
# The value must be in range [1..100].
# The value must be in range [1..100]
# Each additional thread after the first will use an additional 18MiB of RAM,
# plus 1.12 MiB of RAM per megabyte of configured read cache size.
# This configuration option has an automatic default value.
@@ -697,7 +698,7 @@ allocation {
# Configuration option allocation/vdo_cpu_threads.
# Specifies the number of threads to use for CPU-intensive work such as
# hashing or compression for VDO volume. The value must be in range [1..100].
# hashing or compression for VDO volume. The value must be in range [1..100]
# This configuration option has an automatic default value.
# vdo_cpu_threads = 2
@@ -715,7 +716,7 @@ allocation {
# processing based on the hash value computed from the block data.
# A logical thread count of 9 or more will require explicitly specifying
# a sufficiently large block map cache size, as well.
# The value must be in range [0..60].
# The value must be in range [0..100].
# vdo_hash_zone_threads, vdo_logical_threads and vdo_physical_threads must be
# either all zero or all non-zero.
# This configuration option has an automatic default value.
@@ -757,7 +758,7 @@ allocation {
# vdo_max_discard = 1
# Configuration option allocation/vdo_pool_header_size.
# Specified the empty header size in KiB at the front and end of vdo pool device.
# 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
}
@@ -936,7 +937,7 @@ backup {
# archive = 1
# Configuration option backup/archive_dir.
# Location of the metadata archive files.
# Location of the metdata archive files.
# Remember to back up this directory regularly!
# This configuration option has an automatic default value.
# archive_dir = "@DEFAULT_SYS_DIR@/@DEFAULT_ARCHIVE_SUBDIR@"
@@ -1463,13 +1464,13 @@ activation {
# Configuration option activation/reserved_stack.
# Stack size in KiB to reserve for use while devices are suspended.
# Insufficient reserve risks I/O deadlock during device suspension.
# Insufficent reserve risks I/O deadlock during device suspension.
# This configuration option has an automatic default value.
# reserved_stack = 64
# Configuration option activation/reserved_memory.
# Memory size in KiB to reserve for use while devices are suspended.
# Insufficient reserve risks I/O deadlock during device suspension.
# Insufficent reserve risks I/O deadlock during device suspension.
# This configuration option has an automatic default value.
# reserved_memory = 8192
@@ -1604,7 +1605,7 @@ activation {
# This includes LVs that have the following segment types:
# raid1, raid4, raid5*, and raid6*.
# If a device in the LV fails, the policy determines the steps
# performed by dmeventd automatically, and the steps performed by the
# performed by dmeventd automatically, and the steps perfomed by the
# manual command lvconvert --repair --use-policies.
# Automatic handling requires dmeventd to be monitoring the LV.
#
@@ -1628,7 +1629,7 @@ activation {
# (copies) and a mirror log. A disk log ensures that a mirror LV does
# not need to be re-synced (all copies made the same) every time a
# machine reboots or crashes. If a device in the LV fails, this policy
# determines the steps performed by dmeventd automatically, and the steps
# determines the steps perfomed by dmeventd automatically, and the steps
# performed by the manual command lvconvert --repair --use-policies.
# Automatic handling requires dmeventd to be monitoring the LV.
#
@@ -1951,12 +1952,6 @@ activation {
# name for identification.
# json
# JSON format.
# json_std
# JSON format that is more compliant with JSON standard.
# Compared to original "json" format:
# - it does not use double quotes around numeric values,
# - it uses 'null' for undefined numeric values,
# - it prints string list as proper JSON array of strings instead of a single string.
# This configuration option has an automatic default value.
# output_format = "basic"

9984
configure vendored

File diff suppressed because it is too large Load Diff

View File

@@ -83,7 +83,6 @@ AC_PROG_LN_S
AC_PROG_MAKE_SET
AC_PROG_MKDIR_P
AC_PROG_RANLIB
AC_CHECK_TOOL([READELF], [readelf])
AC_CHECK_TOOL(AR, ar)
AC_PATH_TOOL(CFLOW_CMD, cflow)
AC_PATH_TOOL(CSCOPE_CMD, cscope)
@@ -96,6 +95,9 @@ dnl -- Check for header files.
AC_HEADER_DIRENT
AC_HEADER_MAJOR
AC_HEADER_STDBOOL
AC_HEADER_STDC
AC_HEADER_SYS_WAIT
AC_HEADER_TIME
AC_CHECK_HEADERS([assert.h ctype.h dirent.h errno.h fcntl.h float.h \
getopt.h inttypes.h langinfo.h libgen.h limits.h locale.h paths.h \
@@ -123,6 +125,7 @@ AC_STRUCT_ST_BLOCKS
AC_STRUCT_TM
AC_TYPE_OFF_T
AC_TYPE_PID_T
AC_TYPE_SIGNAL
AC_TYPE_SIZE_T
AC_TYPE_MODE_T
AC_TYPE_INT8_T
@@ -150,7 +153,7 @@ AC_CHECK_FUNCS([ftruncate gethostname getpagesize gettimeofday localtime_r \
memchr memset mkdir mkfifo munmap nl_langinfo pselect realpath rmdir setenv \
setlocale strcasecmp strchr strcspn strdup strerror strncasecmp strndup \
strrchr strspn strstr strtol strtoul uname], , [AC_MSG_ERROR(bailing out)])
AC_CHECK_FUNCS([ffs mallinfo2 prlimit versionsort])
AC_CHECK_FUNCS([ffs prlimit versionsort])
AC_FUNC_ALLOCA
AC_FUNC_CLOSEDIR_VOID
AC_FUNC_CHOWN
@@ -290,7 +293,7 @@ case "$DEFAULT_USE_DEVICES_FILE" in
esac
AC_MSG_RESULT($DEFAULT_USE_DEVICES_FILE)
AC_DEFINE_UNQUOTED(DEFAULT_USE_DEVICES_FILE, [$DEFAULT_USE_DEVICES_FILE],
[Default for lvm.conf use_devicesfile.])
[Default for lvm.conf use_devicefile.])
AC_MSG_CHECKING(default name mangling)
AC_ARG_WITH(default-name-mangling,
@@ -1136,7 +1139,7 @@ AC_CHECK_HEADER([systemd/sd-id128.h],
[APP_MACHINEID_SUPPORT=no])
AC_MSG_CHECKING(whether to support systemd appmachineid)
AC_ARG_ENABLE(app-machineid,
AS_HELP_STRING([--disable-app-machineid],
AC_HELP_STRING([--disable-app-machineid],
[disable LVM system ID using app-specific machine-id]),
AS_IF([test "$enableval" = yes && test "$APP_MACHINEID_SUPPORT" = no],
AC_MSG_ERROR([Enabling app machineid requires systemd/sd-id128.h and systemd >= 234.]))
@@ -1320,8 +1323,8 @@ if test "$BUILD_LVMDBUSD" = yes; then
test "$PYTHON3_BINDINGS" = yes && PYTHON_BINDINGS=yes
# To get this macro, install autoconf-archive package then run autoreconf
AX_PYTHON_MODULE([pyudev], [Required], python3)
AX_PYTHON_MODULE([dbus], [Required], python3)
AC_PYTHON_MODULE([pyudev], [Required], python3)
AC_PYTHON_MODULE([dbus], [Required], python3)
fi
################################################################################
@@ -1606,11 +1609,6 @@ AC_ARG_WITH(usrsbindir,
[usrsbin executables in DIR [PREFIX/sbin]]),
usrsbindir=$withval, usrsbindir='${prefix}/sbin')
AC_ARG_WITH(libexecdir,
AS_HELP_STRING([--with-libexecdir=DIR],
[libexec executables in DIR [PREFIX/libexec]]),
libexecdir=$withval, libexecdir='${prefix}/libexec')
################################################################################
AC_ARG_WITH(udev_prefix,
AS_HELP_STRING([--with-udev-prefix=UPREFIX],
@@ -1715,11 +1713,6 @@ AC_DEFINE_UNQUOTED(FSADM_PATH, ["$FSADM_PATH"], [Path to fsadm binary.])
LVMIMPORTVDO_PATH="$SBINDIR/lvm_import_vdo"
AC_DEFINE_UNQUOTED(LVMIMPORTVDO_PATH, ["$LVMIMPORTVDO_PATH"], [Path to lvm_import_vdo script.])
LIBEXECDIR="$(eval echo $(eval echo $libexecdir))"
LVRESIZE_FS_HELPER_PATH="$LIBEXECDIR/lvresize_fs_helper"
AC_DEFINE_UNQUOTED(LVRESIZE_FS_HELPER_PATH, ["$LVRESIZE_FS_HELPER_PATH"], [Path to lvresize_fs_helper script.])
################################################################################
dnl -- dmeventd pidfile and executable path
if test "$BUILD_DMEVENTD" = yes; then
@@ -1878,7 +1871,6 @@ AC_SUBST(DEFAULT_SPARSE_SEGTYPE)
AC_SUBST(DEFAULT_SYS_DIR)
AC_SUBST(DEFAULT_SYS_LOCK_DIR)
AC_SUBST(DEFAULT_USE_BLKID_WIPING)
AC_SUBST(DEFAULT_USE_DEVICES_FILE)
AC_SUBST(DEFAULT_USE_LVMPOLLD)
AC_SUBST(DEFAULT_USE_LVMLOCKD)
AC_SUBST(DEVMAPPER)
@@ -1890,7 +1882,6 @@ AC_SUBST(DM_LIB_PATCHLEVEL)
AC_SUBST(ELDFLAGS)
AC_SUBST(FSADM)
AC_SUBST(FSADM_PATH)
AC_SUBST(LVRESIZE_FS_HELPER_PATH)
AC_SUBST(BLKDEACTIVATE)
AC_SUBST(HAVE_LIBDL)
AC_SUBST(HAVE_REALTIME)
@@ -1989,7 +1980,6 @@ AC_SUBST(systemdutildir)
AC_SUBST(tmpfilesdir)
AC_SUBST(usrlibdir)
AC_SUBST(usrsbindir)
AC_SUBST(libexecdir)
################################################################################
dnl -- First and last lines should not contain files to generate in order to

View File

@@ -928,8 +928,8 @@ void dm_event_log(const char *subsys, int level, const char *file,
start = now;
now -= start;
if (_debug_level)
fprintf(stream, "[%2lld:%02lld] %8x:%-6s%s",
(long long)now / 60, (long long)now % 60,
fprintf(stream, "[%2d:%02d] %8x:%-6s%s",
(int)now / 60, (int)now % 60,
// TODO: Maybe use shorter ID
// ((int)(pthread_self()) >> 6) & 0xffff,
(int)pthread_self(), subsys,

View File

@@ -88,6 +88,7 @@ class AutomatedProperties(dbus.service.Object):
cb, cbe, False)
cfg.worker_q.put(r)
@staticmethod
def _get_all_prop(obj, interface_name):
if interface_name in obj.interface(True):

View File

@@ -7,13 +7,16 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import subprocess
from . import cfg
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
from .utils import pv_range_append, pv_dest_ranges, log_error, log_debug,\
mt_async_call
from .request import RequestEntry
import threading
import time
import traceback
def pv_move_lv_cmd(move_options, lv_full_name,
@@ -64,13 +67,16 @@ def _move_merge(interface_name, command, job_state):
# the command always as we will be getting periodic output from them on
# the status of the long running operation.
meta = LvmExecutionMeta(time.time(), 0, command)
cfg.flightrecorder.add(meta)
meta = LvmExecutionMeta(time.time(), 0, command, -1000, None, None)
cfg.blackbox.add(meta)
ec, stdout, stderr = call_lvm(command, line_cb=_move_callback,
cb_data=job_state)
ended = time.time()
meta.completed(ended, ec, stdout, stderr)
with meta.lock:
meta.ended = time.time()
meta.ec = ec
meta.stderr_txt = stderr
if ec == 0:
job_state.Percent = 100

View File

@@ -16,8 +16,6 @@ from lvmdbusd import path
LVM_CMD = os.getenv('LVM_BINARY', path.LVM_BINARY)
LOCK_FILE = os.getenv("LVM_DBUSD_LOCKFILE", "/var/lock/lvm/lvmdbusd")
# This is the global object manager
om = None
@@ -45,9 +43,6 @@ worker_q = queue.Queue()
# Main event loop
loop = None
# Used to instruct the daemon if we should ignore SIGTERM
ignore_sigterm = False
BUS_NAME = os.getenv('LVM_DBUS_NAME', 'com.redhat.lvmdbus1')
BASE_INTERFACE = 'com.redhat.lvmdbus1'
PV_INTERFACE = BASE_INTERFACE + '.Pv'
@@ -95,14 +90,11 @@ vdo_support = False
db = None
# lvm flight recorder
flightrecorder = None
blackbox = None
# RequestEntry ctor
create_request_entry = None
# Circular debug log
debug = None
def exit_daemon():
"""
@@ -112,9 +104,3 @@ def exit_daemon():
if run and loop:
run.value = 0
loop.quit()
# Debug data for lvm
lvmdebug = None
systemd = False

View File

@@ -6,18 +6,19 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import errno
from subprocess import Popen, PIPE
import select
import time
import threading
from itertools import chain
import collections
import traceback
import os
from lvmdbusd import cfg
from lvmdbusd.utils import pv_dest_ranges, log_debug, log_error, add_no_notify,\
make_non_block, read_decoded, extract_stack_trace, LvmBug, add_config_option, get_error_msg
make_non_block, read_decoded
from lvmdbusd.lvm_shell_proxy import LVMShellProxy
try:
@@ -25,6 +26,7 @@ try:
except ImportError:
import json
SEP = '{|}'
total_time = 0.0
total_count = 0
@@ -36,7 +38,7 @@ cmd_lock = threading.RLock()
class LvmExecutionMeta(object):
def __init__(self, start, ended, cmd, ec=-1000, stdout_txt=None, stderr_txt=None):
def __init__(self, start, ended, cmd, ec, stdout_txt, stderr_txt):
self.lock = threading.RLock()
self.start = start
self.ended = ended
@@ -47,49 +49,32 @@ class LvmExecutionMeta(object):
def __str__(self):
with self.lock:
if self.ended == 0:
ended_txt = "still running"
self.ended = time.time()
else:
ended_txt = str(time.ctime(self.ended))
return 'EC= %d for "%s"\n' \
"STARTED: %s, ENDED: %s, DURATION: %f\n" \
return "EC= %d for %s\n" \
"STARTED: %f, ENDED: %f\n" \
"STDOUT=%s\n" \
"STDERR=%s\n" % \
(self.ec, " ".join(self.cmd), time.ctime(self.start), ended_txt, float(self.ended) - self.start,
self.stdout_txt,
self.stderr_txt)
def completed(self, end_time, ec, stdout_txt, stderr_txt):
with self.lock:
self.ended = end_time
self.ec = ec
self.stdout_txt = stdout_txt
self.stderr_txt = stderr_txt
(self.ec, str(self.cmd), self.start, self.ended, self.stdout_txt,
self.stderr_txt)
class LvmFlightRecorder(object):
def __init__(self, size=16):
self.queue = collections.deque(maxlen=size)
self.lock = threading.RLock()
def add(self, lvm_exec_meta):
with self.lock:
self.queue.append(lvm_exec_meta)
self.queue.append(lvm_exec_meta)
def dump(self):
with self.lock:
with cmd_lock:
if len(self.queue):
log_error("LVM dbus flight recorder START (in order of newest to oldest)")
log_error("LVM dbus flight recorder START")
for c in reversed(self.queue):
log_error(str(c))
log_error("LVM dbus flight recorder END")
self.queue.clear()
cfg.flightrecorder = LvmFlightRecorder()
cfg.blackbox = LvmFlightRecorder()
def _debug_c(cmd, exit_code, out):
@@ -121,9 +106,6 @@ def call_lvm(command, debug=False, line_cb=None,
command.insert(0, cfg.LVM_CMD)
command = add_no_notify(command)
# Ensure we get an error message when we fork & exec the lvm command line
command = add_config_option(command, "--config", 'log/command_log_selection="log_context!=''"')
process = Popen(command, stdout=PIPE, stderr=PIPE, close_fds=True,
env=os.environ)
@@ -133,7 +115,7 @@ def call_lvm(command, debug=False, line_cb=None,
make_non_block(process.stdout)
make_non_block(process.stderr)
while True and cfg.run.value != 0:
while True:
try:
rd_fd = [process.stdout.fileno(), process.stderr.fileno()]
ready = select.select(rd_fd, [], [], 2)
@@ -151,8 +133,8 @@ def call_lvm(command, debug=False, line_cb=None,
if i != -1:
try:
line_cb(cb_data, stdout_text[stdout_index:i])
except BaseException as be:
st = extract_stack_trace(be)
except:
st = traceback.format_exc()
log_error("call_lvm: line_cb exception: \n %s" % st)
stdout_index = i + 1
else:
@@ -163,31 +145,12 @@ def call_lvm(command, debug=False, line_cb=None,
break
except IOError as ioe:
log_debug("call_lvm:" + str(ioe))
break
pass
if process.returncode is not None:
cfg.lvmdebug.lvm_complete()
if debug or (process.returncode != 0 and (process.returncode != 5 and "fullreport" in command)):
_debug_c(command, process.returncode, (stdout_text, stderr_text))
try:
report_json = json.loads(stdout_text)
except json.decoder.JSONDecodeError:
# Some lvm commands don't return json even though we are asking for it to do so.
return process.returncode, stdout_text, stderr_text
error_msg = get_error_msg(report_json)
if error_msg:
stderr_text += error_msg
return process.returncode, report_json, stderr_text
else:
if cfg.run.value == 0:
raise SystemExit
# We can bail out before the lvm command finished when we get a signal
# which is requesting we exit
return -errno.EINTR, "", "operation interrupted"
if debug or process.returncode != 0:
_debug_c(command, process.returncode, (stdout_text, stderr_text))
return process.returncode, stdout_text, stderr_text
# The actual method which gets called to invoke the lvm command, can vary
# from forking a new process to using lvm shell
@@ -202,11 +165,11 @@ def _shell_cfg():
_t_call = lvm_shell.call_lvm
cfg.SHELL_IN_USE = lvm_shell
return True
except Exception as e:
except Exception:
_t_call = call_lvm
cfg.SHELL_IN_USE = None
log_error("Unable to utilize lvm shell, dropping "
"back to fork & exec\n%s" % extract_stack_trace(e))
log_error(traceback.format_exc())
log_error("Unable to utilize lvm shell, dropping back to fork & exec")
return False
@@ -237,15 +200,11 @@ def time_wrapper(command, debug=False):
with cmd_lock:
start = time.time()
meta = LvmExecutionMeta(start, 0, command)
# Add the partial metadata to flight recorder, so if the command hangs
# we will see what it was.
cfg.flightrecorder.add(meta)
results = _t_call(command, debug)
ended = time.time()
total_time += (ended - start)
total_count += 1
meta.completed(ended, *results)
cfg.blackbox.add(LvmExecutionMeta(start, ended, command, *results))
return results
@@ -255,11 +214,44 @@ call = time_wrapper
# Default cmd
# Place default arguments for every command here.
def _dc(cmd, args):
c = [cmd, '--nosuffix', '--unbuffered', '--units', 'b']
c = [cmd, '--noheading', '--separator', '%s' % SEP, '--nosuffix',
'--unbuffered', '--units', 'b']
c.extend(args)
return c
def parse(out):
rc = []
for line in out.split('\n'):
# This line includes separators, so process them
if SEP in line:
elem = line.split(SEP)
cleaned_elem = []
for e in elem:
e = e.strip()
cleaned_elem.append(e)
if len(cleaned_elem) > 1:
rc.append(cleaned_elem)
else:
t = line.strip()
if len(t) > 0:
rc.append(t)
return rc
def parse_column_names(out, column_names):
lines = parse(out)
rc = []
for i in range(0, len(lines)):
d = dict(list(zip(column_names, lines[i])))
rc.append(d)
return rc
def options_to_cli_args(options):
rc = []
for k, v in list(dict(options).items()):
@@ -621,20 +613,68 @@ def lvm_full_report_json():
'--configreport', 'vg', '-o', ','.join(vg_columns),
'--configreport', 'lv', '-o', ','.join(lv_columns),
'--configreport', 'seg', '-o', ','.join(lv_seg_columns),
'--configreport', 'pvseg', '-o', ','.join(pv_seg_columns)
'--configreport', 'pvseg', '-o', ','.join(pv_seg_columns),
'--reportformat', 'json'
])
# We are running the fullreport command, we will ask lvm to output the debug
# data, so we can have the required information for lvm to debug the fullreport failures.
fn = cfg.lvmdebug.setup()
add_config_option(cmd, "--config", "log {level=7 file=%s syslog=0}" % fn)
rc, out, err = call(cmd)
# When we have an exported vg the exit code of lvs or fullreport will be 5
if rc == 0 or rc == 5:
assert(type(out) == dict)
return out
raise LvmBug("'fullreport' exited with code '%d'" % rc)
# With the current implementation, if we are using the shell then we
# are using JSON and JSON is returned back to us as it was parsed to
# figure out if we completed OK or not
if cfg.SHELL_IN_USE:
assert(type(out) == dict)
return out
else:
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
def pv_retrieve_with_segs(device=None):
d = []
err = ""
out = ""
rc = 0
columns = ['pv_name', 'pv_uuid', 'pv_fmt', 'pv_size', 'pv_free',
'pv_used', 'dev_size', 'pv_mda_size', 'pv_mda_free',
'pv_ba_start', 'pv_ba_size', 'pe_start', 'pv_pe_count',
'pv_pe_alloc_count', 'pv_attr', 'pv_tags', 'vg_name',
'vg_uuid', 'pvseg_start', 'pvseg_size', 'segtype', 'pv_missing']
# Lvm has some issues where it returns failure when querying pvs when other
# operations are in process, see:
# https://bugzilla.redhat.com/show_bug.cgi?id=1274085
for i in range(0, 10):
cmd = _dc('pvs', ['-o', ','.join(columns)])
if device:
cmd.extend(device)
rc, out, err = call(cmd)
if rc == 0:
d = parse_column_names(out, columns)
break
else:
time.sleep(0.2)
log_debug("LVM Bug workaround, retrying pvs command...")
if rc != 0:
msg = "We were unable to get pvs to return without error after " \
"trying 10 times, RC=%d, STDERR=(%s), STDOUT=(%s)" % \
(rc, err, out)
log_error(msg)
raise RuntimeError(msg)
return d
def pv_resize(device, size_bytes, create_options):
@@ -791,6 +831,53 @@ def activate_deactivate(op, name, activate, control_flags, options):
return call(cmd)
def vg_retrieve(vg_specific):
if vg_specific:
assert isinstance(vg_specific, list)
columns = ['vg_name', 'vg_uuid', 'vg_fmt', 'vg_size', 'vg_free',
'vg_sysid', 'vg_extent_size', 'vg_extent_count',
'vg_free_count', 'vg_profile', 'max_lv', 'max_pv',
'pv_count', 'lv_count', 'snap_count', 'vg_seqno',
'vg_mda_count', 'vg_mda_free', 'vg_mda_size',
'vg_mda_used_count', 'vg_attr', 'vg_tags']
cmd = _dc('vgs', ['-o', ','.join(columns)])
if vg_specific:
cmd.extend(vg_specific)
d = []
rc, out, err = call(cmd)
if rc == 0:
d = parse_column_names(out, columns)
return d
def lv_retrieve_with_segments():
columns = ['lv_uuid', 'lv_name', 'lv_path', 'lv_size',
'vg_name', 'pool_lv_uuid', 'pool_lv', 'origin_uuid',
'origin', 'data_percent',
'lv_attr', 'lv_tags', 'vg_uuid', 'lv_active', 'data_lv',
'metadata_lv', 'seg_pe_ranges', 'segtype', 'lv_parent',
'lv_role', 'lv_layout',
'snap_percent', 'metadata_percent', 'copy_percent',
'sync_percent', 'lv_metadata_size', 'move_pv', 'move_pv_uuid']
cmd = _dc('lvs', ['-a', '-o', ','.join(columns)])
rc, out, err = call(cmd)
d = []
if rc == 0:
d = parse_column_names(out, columns)
return d
if __name__ == '__main__':
# Leave this for future debug as needed
pass
pv_data = pv_retrieve_with_segs()
for p in pv_data:
print(str(p))

View File

@@ -6,16 +6,16 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import errno
from .pv import load_pvs
from .vg import load_vgs
from .lv import load_lvs
from . import cfg
from .utils import MThreadRunner, log_debug, log_error, LvmBug, extract_stack_trace
from .utils import MThreadRunner, log_debug, log_error
import threading
import queue
import time
import traceback
def _main_thread_load(refresh=True, emit_signal=True):
@@ -120,108 +120,81 @@ class StateUpdate(object):
@staticmethod
def update_thread(obj):
exception_count = 0
queued_requests = []
def set_results(val):
nonlocal queued_requests
for idx in queued_requests:
idx.set_result(val)
# Only clear out the requests after we have given them a result
# otherwise we can orphan the waiting threads, and they never
# wake up if we get an exception
queued_requests = []
def bailing(rv):
set_results(rv)
try:
while True:
item = obj.queue.get(False)
item.set_result(rv)
except queue.Empty:
pass
def _load_args(requests):
"""
If we have multiple requests in the queue, they might not all have the same options. If any of the requests
have an option set we need to honor it.
"""
refresh = any([r.refresh for r in requests])
emit_signal = any([r.emit_signal for r in requests])
cache_refresh = any([r.cache_refresh for r in requests])
log = any([r.log for r in requests])
need_main_thread = any([r.need_main_thread for r in requests])
return refresh, emit_signal, cache_refresh, log, need_main_thread
def _drain_queue(queued, incoming):
try:
while True:
queued.append(incoming.get(block=False))
except queue.Empty:
pass
def _handle_error():
nonlocal exception_count
exception_count += 1
if exception_count >= 5:
log_error("Too many errors in update_thread, exiting daemon")
cfg.debug.dump()
cfg.flightrecorder.dump()
bailing(errno.EFAULT)
cfg.exit_daemon()
else:
# Slow things down when encountering errors
cfg.lvmdebug.complete()
time.sleep(1)
while cfg.run.value != 0:
# noinspection PyBroadException
try:
refresh = True
emit_signal = True
cache_refresh = True
log = True
need_main_thread = True
with obj.lock:
wait = not obj.deferred
obj.deferred = False
if len(queued_requests) == 0 and wait:
# Note: If we don't have anything for 2 seconds we will
# get a queue.Empty exception raised here
queued_requests.append(obj.queue.get(block=True, timeout=2))
queued_requests.append(obj.queue.get(True, 2))
# Ok we have one or the deferred queue has some,
# check if any others and grab them too
_drain_queue(queued_requests, obj.queue)
# check if any others
try:
while True:
queued_requests.append(obj.queue.get(False))
except queue.Empty:
pass
if len(queued_requests) > 1:
log_debug("Processing %d updates!" % len(queued_requests),
'bg_black', 'fg_light_green')
num_changes = load(*_load_args(queued_requests))
# We have what we can, run the update with the needed options
for i in queued_requests:
if not i.refresh:
refresh = False
if not i.emit_signal:
emit_signal = False
if not i.cache_refresh:
cache_refresh = False
if not i.log:
log = False
if not i.need_main_thread:
need_main_thread = False
num_changes = load(refresh, emit_signal, cache_refresh, log,
need_main_thread)
# Update is done, let everyone know!
set_results(num_changes)
for i in queued_requests:
i.set_result(num_changes)
# Only clear out the requests after we have given them a result
# otherwise we can orphan the waiting threads and they never
# wake up if we get an exception
queued_requests = []
# We retrieved OK, clear exception count
exception_count = 0
except queue.Empty:
pass
except SystemExit:
break
except LvmBug as bug:
# If a lvm bug occurred, we will dump the lvm debug data if
# we have it.
cfg.lvmdebug.dump()
log_error(str(bug))
_handle_error()
except Exception as e:
log_error("update_thread: \n%s" % extract_stack_trace(e))
_handle_error()
finally:
cfg.lvmdebug.complete()
st = traceback.format_exc()
log_error("update_thread exception: \n%s" % st)
cfg.blackbox.dump()
exception_count += 1
if exception_count >= 5:
for i in queued_requests:
i.set_result(e)
# Make sure to unblock any that may be waiting before we exit this thread
# otherwise they hang forever ...
bailing(Exception("update thread exiting"))
log_debug("update thread exiting!")
log_error("Too many errors in update_thread, exiting daemon")
cfg.exit_daemon()
else:
# Slow things down when encountering errors
time.sleep(1)
def __init__(self):
self.lock = threading.RLock()

View File

@@ -226,21 +226,3 @@ class Job(AutomatedProperties):
def Uuid(self):
import uuid
return uuid.uuid1()
# Override the property "getters" implementation for the job interface, so a user can query a job while the queue
# is processing items. Originally all the property get methods were this way, but we changed this in
# e53454d6de07de56736303dd2157c3859f6fa848
# Properties
# noinspection PyUnusedLocal
@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
in_signature='ss', out_signature='v')
def Get(self, interface_name, property_name):
# Note: If we get an exception in this handler we won't know about it,
# only the side effect of no returned value!
return AutomatedProperties._get_prop(self, interface_name, property_name)
@dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE,
in_signature='s', out_signature='a{sv}')
def GetAll(self, interface_name):
return AutomatedProperties._get_all_prop(self, interface_name)

View File

@@ -10,7 +10,7 @@
from .automatedproperties import AutomatedProperties
from . import utils
from .utils import vg_obj_path_generate, log_error, _handle_execute, LvmBug
from .utils import vg_obj_path_generate, log_error, _handle_execute
import dbus
from . import cmdhandler
from . import cfg
@@ -21,9 +21,11 @@ from .utils import n, n32, d
from .loader import common
from .state import State
from . import background
from .utils import round_size, mt_remove_dbus_objects, lvm_column_key
from .utils import round_size, mt_remove_dbus_objects
from .job import JobState
import traceback
# Try and build a key for a LV, so that we sort the LVs with least dependencies
# first. This may be error prone because of the flexibility LVM
@@ -71,74 +73,67 @@ def lvs_state_retrieve(selection, cache_refresh=True):
# don't have information available yet.
lvs = sorted(cfg.db.fetch_lvs(selection), key=get_key)
try:
for l in lvs:
if cfg.vdo_support:
rc.append(LvStateVdo(
l['lv_uuid'], l['lv_name'],
l['lv_path'], n(l['lv_size']),
l['vg_name'],
l['vg_uuid'], l['pool_lv_uuid'],
l['pool_lv'], l['origin_uuid'], l['origin'],
n32(l['data_percent']), l['lv_attr'],
l['lv_tags'], l['lv_active'], l['data_lv'],
l['metadata_lv'], l['segtype'], l['lv_role'],
l['lv_layout'],
n32(l['snap_percent']),
n32(l['metadata_percent']),
n32(l['copy_percent']),
n32(l['sync_percent']),
n(l['lv_metadata_size']),
l['move_pv'],
l['move_pv_uuid'],
l['vdo_operating_mode'],
l['vdo_compression_state'],
l['vdo_index_state'],
n(l['vdo_used_size']),
d(l['vdo_saving_percent']),
l['vdo_compression'],
l['vdo_deduplication'],
l['vdo_use_metadata_hints'],
n32(l['vdo_minimum_io_size']),
n(l['vdo_block_map_cache_size']),
n32(l['vdo_block_map_era_length']),
l['vdo_use_sparse_index'],
n(l['vdo_index_memory_size']),
n(l['vdo_slab_size']),
n32(l['vdo_ack_threads']),
n32(l['vdo_bio_threads']),
n32(l['vdo_bio_rotation']),
n32(l['vdo_cpu_threads']),
n32(l['vdo_hash_zone_threads']),
n32(l['vdo_logical_threads']),
n32(l['vdo_physical_threads']),
n32(l['vdo_max_discard']),
l['vdo_write_policy'],
n32(l['vdo_header_size'])))
else:
rc.append(LvState(
l['lv_uuid'], l['lv_name'],
l['lv_path'], n(l['lv_size']),
l['vg_name'],
l['vg_uuid'], l['pool_lv_uuid'],
l['pool_lv'], l['origin_uuid'], l['origin'],
n32(l['data_percent']), l['lv_attr'],
l['lv_tags'], l['lv_active'], l['data_lv'],
l['metadata_lv'], l['segtype'], l['lv_role'],
l['lv_layout'],
n32(l['snap_percent']),
n32(l['metadata_percent']),
n32(l['copy_percent']),
n32(l['sync_percent']),
n(l['lv_metadata_size']),
l['move_pv'],
l['move_pv_uuid']))
except KeyError as ke:
# Sometimes lvm omits returning one of the keys we requested.
key = ke.args[0]
if lvm_column_key(key):
raise LvmBug("missing JSON key: '%s'" % key)
raise ke
for l in lvs:
if cfg.vdo_support:
rc.append(LvStateVdo(
l['lv_uuid'], l['lv_name'],
l['lv_path'], n(l['lv_size']),
l['vg_name'],
l['vg_uuid'], l['pool_lv_uuid'],
l['pool_lv'], l['origin_uuid'], l['origin'],
n32(l['data_percent']), l['lv_attr'],
l['lv_tags'], l['lv_active'], l['data_lv'],
l['metadata_lv'], l['segtype'], l['lv_role'],
l['lv_layout'],
n32(l['snap_percent']),
n32(l['metadata_percent']),
n32(l['copy_percent']),
n32(l['sync_percent']),
n(l['lv_metadata_size']),
l['move_pv'],
l['move_pv_uuid'],
l['vdo_operating_mode'],
l['vdo_compression_state'],
l['vdo_index_state'],
n(l['vdo_used_size']),
d(l['vdo_saving_percent']),
l['vdo_compression'],
l['vdo_deduplication'],
l['vdo_use_metadata_hints'],
n32(l['vdo_minimum_io_size']),
n(l['vdo_block_map_cache_size']),
n32(l['vdo_block_map_era_length']),
l['vdo_use_sparse_index'],
n(l['vdo_index_memory_size']),
n(l['vdo_slab_size']),
n32(l['vdo_ack_threads']),
n32(l['vdo_bio_threads']),
n32(l['vdo_bio_rotation']),
n32(l['vdo_cpu_threads']),
n32(l['vdo_hash_zone_threads']),
n32(l['vdo_logical_threads']),
n32(l['vdo_physical_threads']),
n32(l['vdo_max_discard']),
l['vdo_write_policy'],
n32(l['vdo_header_size'])))
else:
rc.append(LvState(
l['lv_uuid'], l['lv_name'],
l['lv_path'], n(l['lv_size']),
l['vg_name'],
l['vg_uuid'], l['pool_lv_uuid'],
l['pool_lv'], l['origin_uuid'], l['origin'],
n32(l['data_percent']), l['lv_attr'],
l['lv_tags'], l['lv_active'], l['data_lv'],
l['metadata_lv'], l['segtype'], l['lv_role'],
l['lv_layout'],
n32(l['snap_percent']),
n32(l['metadata_percent']),
n32(l['copy_percent']),
n32(l['sync_percent']),
n(l['lv_metadata_size']),
l['move_pv'],
l['move_pv_uuid']))
return rc
@@ -279,15 +274,15 @@ class LvStateVdo(LvState):
MetaDataPercent, CopyPercent, SyncPercent,
MetaDataSizeBytes, move_pv, move_pv_uuid,
vdo_operating_mode, vdo_compression_state, vdo_index_state,
vdo_used_size, vdo_saving_percent, vdo_compression,
vdo_deduplication, vdo_use_metadata_hints,
vdo_minimum_io_size, vdo_block_map_cache_size,
vdo_block_map_era_length, vdo_use_sparse_index,
vdo_index_memory_size, vdo_slab_size, vdo_ack_threads,
vdo_bio_threads, vdo_bio_rotation, vdo_cpu_threads,
vdo_hash_zone_threads, vdo_logical_threads,
vdo_physical_threads, vdo_max_discard,
vdo_write_policy, vdo_header_size):
vdo_used_size,vdo_saving_percent,vdo_compression,
vdo_deduplication,vdo_use_metadata_hints,
vdo_minimum_io_size,vdo_block_map_cache_size,
vdo_block_map_era_length,vdo_use_sparse_index,
vdo_index_memory_size,vdo_slab_size,vdo_ack_threads,
vdo_bio_threads,vdo_bio_rotation,vdo_cpu_threads,
vdo_hash_zone_threads,vdo_logical_threads,
vdo_physical_threads,vdo_max_discard,
vdo_write_policy,vdo_header_size):
super(LvStateVdo, self).__init__(Uuid, Name, Path, SizeBytes,
vg_name, vg_uuid, pool_lv_uuid, PoolLv,
origin_uuid, OriginLv, DataPercent, Attr, Tags, active,
@@ -376,8 +371,8 @@ class LvCommon(AutomatedProperties):
return dbus.Struct((self.state.Attr[index],
type_map.get(self.state.Attr[index], default)),
signature="(ss)")
except BaseException as b:
st = utils.extract_stack_trace(b)
except BaseException:
st = traceback.format_exc()
log_error("attr_struct: \n%s" % st)
return dbus.Struct(('?', 'Unavailable'), signature="(ss)")
@@ -600,7 +595,7 @@ class Lv(LvCommon):
optional_size = space + 512 - remainder
LvCommon.handle_execute(*cmdhandler.vg_lv_snapshot(
lv_name, snapshot_options, name, optional_size))
lv_name, snapshot_options,name, optional_size))
full_name = "%s/%s" % (dbo.vg_name_lookup(), name)
return cfg.om.get_object_path_by_lvm_id(full_name)
@@ -640,7 +635,7 @@ class Lv(LvCommon):
size_change = new_size_bytes - dbo.SizeBytes
LvCommon.handle_execute(*cmdhandler.lv_resize(
dbo.lvm_id, size_change, pv_dests, resize_options))
dbo.lvm_id, size_change,pv_dests, resize_options))
return "/"
@dbus.service.method(
@@ -749,7 +744,7 @@ class Lv(LvCommon):
cfg.worker_q.put(r)
@staticmethod
def _caching_common(method, lv_uuid, lv_name, lv_object_path, cache_options):
def _writecache_lv(lv_uuid, lv_name, lv_object_path, cache_options):
# Make sure we have a dbus object representing it
dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
@@ -758,7 +753,7 @@ class Lv(LvCommon):
if lv_to_cache:
fcn = lv_to_cache.lv_full_name()
rc, out, err = method(
rc, out, err = cmdhandler.lv_writecache_lv(
dbo.lv_full_name(), fcn, cache_options)
if rc == 0:
# When we cache an LV, the cache pool and the lv that is getting
@@ -775,14 +770,9 @@ class Lv(LvCommon):
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE, 'LV to cache with object path %s not present!' %
lv_object_path)
lv_object_path)
return lv_converted
@staticmethod
def _writecache_lv(lv_uuid, lv_name, lv_object_path, cache_options):
return Lv._caching_common(cmdhandler.lv_writecache_lv, lv_uuid,
lv_name, lv_object_path, cache_options)
@dbus.service.method(
dbus_interface=LV_INTERFACE,
in_signature='oia{sv}',
@@ -855,10 +845,10 @@ class LvVdoPool(Lv):
cfg.worker_q.put(r)
@dbus.service.method(
dbus_interface=VDO_POOL_INTERFACE,
in_signature='ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
dbus_interface=VDO_POOL_INTERFACE,
in_signature='ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def DisableCompression(self, tmo, comp_options, cb, cbe):
r = RequestEntry(
tmo, LvVdoPool._enable_disable_compression,
@@ -888,10 +878,10 @@ class LvVdoPool(Lv):
cfg.worker_q.put(r)
@dbus.service.method(
dbus_interface=VDO_POOL_INTERFACE,
in_signature='ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
dbus_interface=VDO_POOL_INTERFACE,
in_signature='ia{sv}',
out_signature='o',
async_callbacks=('cb', 'cbe'))
def DisableDeduplication(self, tmo, dedup_options, cb, cbe):
r = RequestEntry(
tmo, LvVdoPool._enable_disable_deduplication,
@@ -962,8 +952,33 @@ class LvCachePool(Lv):
@staticmethod
def _cache_lv(lv_uuid, lv_name, lv_object_path, cache_options):
return Lv._caching_common(cmdhandler.lv_cache_lv, lv_uuid, lv_name,
lv_object_path, cache_options)
# Make sure we have a dbus object representing cache pool
dbo = LvCommon.validate_dbus_object(lv_uuid, lv_name)
# Make sure we have dbus object representing lv to cache
lv_to_cache = cfg.om.get_object_by_path(lv_object_path)
if lv_to_cache:
fcn = lv_to_cache.lv_full_name()
rc, out, err = cmdhandler.lv_cache_lv(
dbo.lv_full_name(), fcn, cache_options)
if rc == 0:
# When we cache an LV, the cache pool and the lv that is getting
# cached need to be removed from the object manager and
# re-created as their interfaces have changed!
mt_remove_dbus_objects((dbo, lv_to_cache))
cfg.load()
lv_converted = cfg.om.get_object_path_by_lvm_id(fcn)
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE,
'Exit code %s, stderr = %s' % (str(rc), err))
else:
raise dbus.exceptions.DBusException(
LV_INTERFACE, 'LV to cache with object path %s not present!' %
lv_object_path)
return lv_converted
@dbus.service.method(
dbus_interface=CACHE_POOL_INTERFACE,

223
daemons/lvmdbusd/lvm_shell_proxy.py.in Executable file → Normal file
View File

@@ -14,11 +14,12 @@
import subprocess
import shlex
import os
import pty
import traceback
import sys
import tempfile
import time
import select
import copy
try:
import simplejson as json
@@ -26,9 +27,9 @@ except ImportError:
import json
import lvmdbusd.cfg as cfg
from lvmdbusd.cfg import LVM_CMD
from lvmdbusd.utils import log_debug, log_error, add_no_notify, make_non_block,\
read_decoded, extract_stack_trace, LvmBug, get_error_msg
read_decoded
SHELL_PROMPT = "lvm> "
@@ -42,11 +43,10 @@ def _quote_arg(arg):
class LVMShellProxy(object):
# Read REPORT FD until we have a complete and valid JSON record or give
# up trying to get one.
#
# Returns stdout, report (JSON), stderr
def _read_response(self, no_output=False):
# 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!)
def _read_until_prompt(self, no_output=False):
stdout = ""
report = ""
stderr = ""
@@ -58,27 +58,24 @@ class LVMShellProxy(object):
# Try reading from all FDs to prevent one from filling up and causing
# a hang. Keep reading until we get the prompt back and the report
# FD does not contain valid JSON
while keep_reading and cfg.run.value != 0:
while keep_reading:
try:
rd_fd = [
self.parent_stdout_fd,
self.lvm_shell.stdout.fileno(),
self.report_stream.fileno(),
self.parent_stderr_fd]
self.lvm_shell.stderr.fileno()]
ready = select.select(rd_fd, [], [], 2)
for r in ready[0]:
if r == self.parent_stdout_fd:
for line in self.parent_stdout.readlines():
stdout += line
if r == self.lvm_shell.stdout.fileno():
stdout += read_decoded(self.lvm_shell.stdout)
elif r == self.report_stream.fileno():
report += read_decoded(self.report_stream)
elif r == self.parent_stderr_fd:
for line in self.parent_stderr.readlines():
stderr += line
elif r == self.lvm_shell.stderr.fileno():
stderr += read_decoded(self.lvm_shell.stderr)
# Check to see if the lvm process died on us
if self.lvm_shell.poll() is not None:
if self.lvm_shell.poll():
raise Exception(self.lvm_shell.returncode, "%s" % stderr)
if stdout.endswith(SHELL_PROMPT):
@@ -102,96 +99,91 @@ class LVMShellProxy(object):
extra_passes -= 1
if extra_passes <= 0:
if len(report):
raise LvmBug("Invalid json: %s" %
raise ValueError("Invalid json: %s" %
report)
else:
raise LvmBug(
raise ValueError(
"lvm returned no JSON output!")
except IOError as ioe:
log_debug(str(ioe))
self.exit_shell()
raise ioe
if keep_reading and cfg.run.value == 0:
# We didn't complete as we are shutting down
# Try to clean up lvm shell process
log_debug("exiting lvm shell as we are shutting down")
self.exit_shell()
raise SystemExit
pass
return stdout, report_json, stderr
def _write_cmd(self, cmd):
self.parent_stdin.write(cmd)
self.parent_stdin.flush()
cmd_bytes = bytes(cmd, "utf-8")
num_written = self.lvm_shell.stdin.write(cmd_bytes)
assert (num_written == len(cmd_bytes))
self.lvm_shell.stdin.flush()
def __init__(self):
# Create a temp directory
tmp_dir = tempfile.mkdtemp(prefix="lvmdbus_")
tmp_file = "%s/lvmdbus_report" % (tmp_dir)
# Create a fifo for the report output
os.mkfifo(tmp_file, 0o600)
try:
# Lets create fifo for the report output
os.mkfifo(tmp_file, 0o600)
except FileExistsError:
pass
# Open the fifo for use to read and for lvm child process to write to.
# We have to open non-blocking as the other side isn't open until
# we actually fork the process.
self.report_fd = os.open(tmp_file, os.O_NONBLOCK)
self.report_stream = os.fdopen(self.report_fd, 'rb', 0)
lvm_fd = os.open(tmp_file, os.O_WRONLY)
# Set up the environment for using our own socket for reporting and disable the abort
# logic if lvm logs too much, which easily happens when utilizing the lvm shell.
local_env = {"LC_ALL": "C", "LVM_REPORT_FD": "%s" % lvm_fd, "LVM_COMMAND_PROFILE": "lvmdbusd",
"LVM_LOG_FILE_MAX_LINES": "0"}
# Setup the environment for using our own socket for reporting
local_env = copy.deepcopy(os.environ)
local_env["LVM_REPORT_FD"] = "32"
local_env["LVM_COMMAND_PROFILE"] = "lvmdbusd"
# If any env variables contain LVM we will propagate them too
for k, v in os.environ.items():
if "LVM" in k:
local_env[k] = v
self.parent_stdin_fd, child_stdin_fd = pty.openpty()
self.parent_stdout_fd, child_stdout_fd = pty.openpty()
self.parent_stderr_fd, child_stderr_fd = pty.openpty()
self.parent_stdin = os.fdopen(self.parent_stdin_fd, "w")
self.parent_stdout = os.fdopen(self.parent_stdout_fd, "r")
self.parent_stderr = os.fdopen(self.parent_stderr_fd, "r")
# Disable the abort logic if lvm logs too much, which easily happens
# when utilizing the lvm shell.
local_env["LVM_LOG_FILE_MAX_LINES"] = "0"
# run the lvm shell
self.lvm_shell = subprocess.Popen(
[cfg.LVM_CMD],
stdin=child_stdin_fd,
stdout=child_stdout_fd, env=local_env,
stderr=child_stderr_fd, close_fds=True,
pass_fds=(lvm_fd,), shell=False)
[LVM_CMD + " 32>%s" % tmp_file],
stdin=subprocess.PIPE, stdout=subprocess.PIPE, env=local_env,
stderr=subprocess.PIPE, close_fds=True, shell=True)
try:
make_non_block(self.parent_stdout_fd)
make_non_block(self.parent_stderr_fd)
# Close our copies of the child FDs there were created with the fork, we don't need them open.
os.close(lvm_fd)
os.close(child_stdin_fd)
os.close(child_stdout_fd)
os.close(child_stderr_fd)
make_non_block(self.lvm_shell.stdout)
make_non_block(self.lvm_shell.stderr)
# wait for the first prompt
log_debug("waiting for first prompt...")
errors = self._read_response(no_output=True)[2]
errors = self._read_until_prompt(no_output=True)[2]
if errors and len(errors):
raise LvmBug(errors)
log_debug("lvm prompt read!!!")
raise RuntimeError(errors)
except:
raise
finally:
# These will get deleted when the FD count goes to zero, so we
# These will get deleted when the FD count goes to zero so we
# can be sure to clean up correctly no matter how we finish
os.unlink(tmp_file)
os.rmdir(tmp_dir)
def get_last_log(self):
def get_error_msg(self):
# We got an error, lets go fetch the error message
self._write_cmd('lastlog\n')
report_json = self._read_response()[1]
return get_error_msg(report_json)
# read everything from the STDOUT to the next prompt
stdout, report_json, stderr = self._read_until_prompt()
if 'log' in report_json:
error_msg = ""
# Walk the entire log array and build an error string
for log_entry in report_json['log']:
if log_entry['log_type'] == "error":
if error_msg:
error_msg += ', ' + log_entry['log_message']
else:
error_msg = log_entry['log_message']
return error_msg
return 'No error reason provided! (missing "log" section)'
def call_lvm(self, argv, debug=False):
rc = 1
@@ -212,29 +204,21 @@ class LVMShellProxy(object):
self._write_cmd(cmd)
# read everything from the STDOUT to the next prompt
stdout, report_json, stderr = self._read_response()
stdout, report_json, stderr = self._read_until_prompt()
# Parse the report to see what happened
if 'log' in report_json:
ret_code = int(report_json['log'][-1:][0]['log_ret_code'])
# If we have an exported vg we get a log_ret_code == 5 when
# we do a 'fullreport'
# Note: 0 == error
if (ret_code == 1) or (ret_code == 5 and argv[0] == 'fullreport'):
rc = 0
else:
# Depending on where lvm fails the command, it may not have anything
# to report for "lastlog", so we need to check for a message in the
# report json too.
error_msg = self.get_last_log()
if error_msg is None:
error_msg = get_error_msg(report_json)
if error_msg is None:
error_msg = 'No error reason provided! (missing "log" section)'
error_msg = self.get_error_msg()
if debug or rc != 0:
log_error(("CMD= %s" % cmd))
log_error(("EC= %d" % rc))
log_error(('CMD: %s' % cmd))
log_error(("EC = %d" % rc))
log_error(("ERROR_MSG=\n %s\n" % error_msg))
return rc, report_json, error_msg
@@ -242,58 +226,35 @@ class LVMShellProxy(object):
def exit_shell(self):
try:
self._write_cmd('exit\n')
self.lvm_shell.wait(1)
self.lvm_shell = None
except Exception as _e:
log_error(str(_e))
except Exception as e:
log_error(str(e))
def __del__(self):
# Note: When we are shutting down the daemon and the main process has already exited
# and this gets called we have a limited set of things we can do, like we cannot call
# log_error as _common_log is None!!!
if self.lvm_shell is not None:
try:
self.lvm_shell.wait(1)
except subprocess.TimeoutExpired:
print("lvm shell child process did not exit as instructed, sending SIGTERM")
cfg.ignore_sigterm = True
self.lvm_shell.terminate()
child_exit_code = self.lvm_shell.wait(1)
print("lvm shell process exited with %d" % child_exit_code)
try:
self.lvm_shell.terminate()
except:
pass
if __name__ == "__main__":
print("USING LVM BINARY: %s " % cfg.LVM_CMD)
shell = LVMShellProxy()
in_line = "start"
try:
if len(sys.argv) > 1 and sys.argv[1] == "bisect":
shell = LVMShellProxy()
shell.exit_shell()
else:
shell = LVMShellProxy()
in_line = "start"
try:
while in_line:
in_line = input("lvm> ")
if in_line:
if in_line == "exit":
shell.exit_shell()
sys.exit(0)
start = time.time()
ret, out, err = shell.call_lvm(in_line.split())
end = time.time()
while in_line:
in_line = input("lvm> ")
if in_line:
start = time.time()
ret, out, err = shell.call_lvm(in_line.split())
end = time.time()
print(("RC: %d" % ret))
print(("OUT:\n%s" % out))
print(("ERR:\n%s" % err))
print(("RC: %d" % ret))
print(("OUT:\n%s" % out))
print(("ERR:\n%s" % err))
print("Command = %f seconds" % (end - start))
except KeyboardInterrupt:
pass
except EOFError:
pass
except Exception as e:
log_error("main process exiting on exception!\n%s" % extract_stack_trace(e))
sys.exit(1)
sys.exit(0)
print("Command = %f seconds" % (end - start))
except KeyboardInterrupt:
pass
except EOFError:
pass
except Exception:
traceback.print_exc(file=sys.stdout)

View File

@@ -13,13 +13,14 @@ from collections import OrderedDict
import pprint as prettyprint
import os
import sys
from lvmdbusd import cmdhandler
from lvmdbusd.utils import log_debug, log_error, lvm_column_key, LvmBug
from lvmdbusd.utils import log_debug, log_error
class DataStore(object):
def __init__(self, vdo_support=False):
def __init__(self, usejson=True, vdo_support=False):
self.pvs = {}
self.vgs = {}
self.lvs = {}
@@ -34,9 +35,41 @@ class DataStore(object):
self.lvs_in_vgs = {}
self.pvs_in_vgs = {}
# self.refresh()
self.num_refreshes = 0
if usejson:
self.json = cmdhandler.supports_json()
else:
self.json = usejson
self.vdo_support = vdo_support
@staticmethod
def _insert_record(table, key, record, allowed_multiple):
if key in table:
existing = table[key]
for rec_k, rec_v in record.items():
if rec_k in allowed_multiple:
# This column name allows us to store multiple value for
# each type
if not isinstance(existing[rec_k], list):
existing_value = existing[rec_k]
existing[rec_k] = [existing_value, rec_v]
else:
existing[rec_k].append(rec_v)
else:
# If something is not expected to have changing values
# lets ensure that
if existing[rec_k] != rec_v:
raise RuntimeError(
"existing[%s]=%s != %s" %
(rec_k, str(existing[rec_k]),
str(rec_v)))
else:
table[key] = record
@staticmethod
def _pvs_parse_common(c_pvs, c_pvs_in_vgs, c_lookup):
for p in c_pvs.values():
@@ -51,6 +84,22 @@ class DataStore(object):
# Lookup for translating between /dev/<name> and pv uuid
c_lookup[p['pv_name']] = p['pv_uuid']
@staticmethod
def _parse_pvs(_pvs):
pvs = sorted(_pvs, key=lambda pk: pk['pv_name'])
c_pvs = OrderedDict()
c_lookup = {}
c_pvs_in_vgs = {}
for p in pvs:
DataStore._insert_record(
c_pvs, p['pv_uuid'], p,
['pvseg_start', 'pvseg_size', 'segtype'])
DataStore._pvs_parse_common(c_pvs, c_pvs_in_vgs, c_lookup)
return c_pvs, c_lookup, c_pvs_in_vgs
@staticmethod
def _parse_pvs_json(_all):
@@ -58,7 +107,7 @@ class DataStore(object):
c_lookup = {}
c_pvs_in_vgs = {}
# Each item in the report is a collection of information pertaining
# Each item item in the report is a collection of information pertaining
# to the vg
for r in _all['report']:
tmp_pv = []
@@ -92,6 +141,28 @@ class DataStore(object):
return c_pvs, c_lookup, c_pvs_in_vgs
@staticmethod
def _parse_vgs(_vgs):
vgs = sorted(_vgs, key=lambda vk: vk['vg_uuid'])
c_vgs = OrderedDict()
c_lookup = {}
for i in vgs:
vg_name = i['vg_name']
# Lvm allows duplicate vg names. When this occurs, each subsequent
# matching VG name will be called vg_name:vg_uuid. Note: ':' is an
# invalid character for lvm VG names
if vg_name in c_lookup:
vg_name = "%s:%s" % (vg_name, i['vg_uuid'])
i['vg_name'] = vg_name
c_lookup[vg_name] = i['vg_uuid']
DataStore._insert_record(c_vgs, i['vg_uuid'], i, [])
return c_vgs, c_lookup
@staticmethod
def _parse_vgs_json(_all):
@@ -156,12 +227,28 @@ class DataStore(object):
return c_lvs, c_lvs_in_vgs, c_lvs_hidden, c_lv_full_lookup
@staticmethod
def _parse_lvs(_lvs):
lvs = sorted(_lvs, key=lambda vk: vk['lv_name'])
c_lvs = OrderedDict()
c_lv_full_lookup = OrderedDict()
for i in lvs:
full_name = "%s/%s" % (i['vg_name'], i['lv_name'])
c_lv_full_lookup[full_name] = i['lv_uuid']
DataStore._insert_record(
c_lvs, i['lv_uuid'], i,
['seg_pe_ranges', 'segtype'])
return DataStore._parse_lvs_common(c_lvs, c_lv_full_lookup)
def _parse_lvs_json(self, _all):
c_lvs = OrderedDict()
c_lv_full_lookup = {}
# Each item in the report is a collection of information pertaining
# Each item item in the report is a collection of information pertaining
# to the vg
for r in _all['report']:
# Get the lv data for this VG.
@@ -309,12 +396,12 @@ class DataStore(object):
:param log Add debug log entry/exit messages
:return: None
"""
try:
self.num_refreshes += 1
if log:
log_debug("lvmdb - refresh entry")
self.num_refreshes += 1
if log:
log_debug("lvmdb - refresh entry")
# Grab everything first then parse it
# Grab everything first then parse it
if self.json:
# Do a single lvm retrieve for everything in json
a = cmdhandler.lvm_full_report_json()
@@ -322,25 +409,29 @@ class DataStore(object):
_vgs, _vgs_lookup = self._parse_vgs_json(a)
_lvs, _lvs_in_vgs, _lvs_hidden, _lvs_lookup = self._parse_lvs_json(a)
# Set all
self.pvs = _pvs
self.pv_path_to_uuid = _pvs_lookup
self.vg_name_to_uuid = _vgs_lookup
self.lv_full_name_to_uuid = _lvs_lookup
else:
_raw_pvs = cmdhandler.pv_retrieve_with_segs()
_raw_vgs = cmdhandler.vg_retrieve(None)
_raw_lvs = cmdhandler.lv_retrieve_with_segments()
self.vgs = _vgs
self.lvs = _lvs
self.lvs_in_vgs = _lvs_in_vgs
self.pvs_in_vgs = _pvs_in_vgs
self.lvs_hidden = _lvs_hidden
_pvs, _pvs_lookup, _pvs_in_vgs = self._parse_pvs(_raw_pvs)
_vgs, _vgs_lookup = self._parse_vgs(_raw_vgs)
_lvs, _lvs_in_vgs, _lvs_hidden, _lvs_lookup = self._parse_lvs(_raw_lvs)
# Create lookup table for which LV and segments are on each PV
self.pv_lvs, self.lv_pvs = self._parse_pv_in_lvs()
except KeyError as ke:
key = ke.args[0]
if lvm_column_key(key):
raise LvmBug("missing JSON key: '%s'" % key)
raise ke
# Set all
self.pvs = _pvs
self.pv_path_to_uuid = _pvs_lookup
self.vg_name_to_uuid = _vgs_lookup
self.lv_full_name_to_uuid = _lvs_lookup
self.vgs = _vgs
self.lvs = _lvs
self.lvs_in_vgs = _lvs_in_vgs
self.pvs_in_vgs = _pvs_in_vgs
self.lvs_hidden = _lvs_hidden
# Create lookup table for which LV and segments are on each PV
self.pv_lvs, self.lv_pvs = self._parse_pv_in_lvs()
if log:
log_debug("lvmdb - refresh exit")
@@ -360,13 +451,10 @@ class DataStore(object):
return rc
def pv_missing(self, pv_uuid):
# The uuid might not be a PV, default to false
if pv_uuid in self.pvs:
if self.pvs[pv_uuid]['pv_missing'] == '':
return False
else:
return True
return False
return True
def fetch_vgs(self, vg_name):
if not vg_name:
@@ -439,7 +527,13 @@ class DataStore(object):
if __name__ == "__main__":
pp = prettyprint.PrettyPrinter(indent=4)
ds = DataStore()
use_json = False
if len(sys.argv) != 1:
print(len(sys.argv))
use_json = True
ds = DataStore(use_json)
ds.refresh()
print("PVS")

View File

@@ -22,13 +22,14 @@ from . import lvmdb
from gi.repository import GLib
from .fetch import StateUpdate
from .manager import Manager
import traceback
import queue
from . import udevwatch
from .utils import log_debug, log_error, log_msg, DebugMessages
from .utils import log_debug, log_error
import argparse
import os
import sys
from .cmdhandler import LvmFlightRecorder, supports_vdo, supports_json
from .cmdhandler import LvmFlightRecorder, supports_vdo
from .request import RequestEntry
@@ -49,15 +50,12 @@ def process_request():
log_debug("Method complete: %s" % str(req.method))
except queue.Empty:
pass
except SystemExit:
break
except Exception as e:
st = utils.extract_stack_trace(e)
except Exception:
st = traceback.format_exc()
utils.log_error("process_request exception: \n%s" % st)
log_debug("process_request thread exiting!")
def check_fr_size(value):
def check_bb_size(value):
v = int(value)
if v < 0:
raise argparse.ArgumentTypeError(
@@ -79,13 +77,13 @@ def install_signal_handlers():
signal_add(GLib.PRIORITY_HIGH, signal.SIGHUP, utils.handler, signal.SIGHUP)
signal_add(GLib.PRIORITY_HIGH, signal.SIGINT, utils.handler, signal.SIGINT)
signal_add(GLib.PRIORITY_HIGH, signal.SIGUSR1, utils.handler, signal.SIGUSR1)
signal_add(GLib.PRIORITY_HIGH, signal.SIGUSR2, utils.handler, signal.SIGUSR2)
signal_add(GLib.PRIORITY_HIGH, signal.SIGTERM, utils.handler, signal.SIGTERM)
else:
log_error("GLib.unix_signal_[add|add_full] are NOT available!")
def process_args():
def main():
start = time.time()
# Add simple command line handling
parser = argparse.ArgumentParser()
parser.add_argument(
"--udev", action='store_true',
@@ -106,141 +104,101 @@ def process_args():
default=False,
dest='use_lvm_shell')
parser.add_argument(
"--frsize",
help="Size of the flight recorder (num. entries), 0 to disable (signal 12 to dump)",
"--blackboxsize",
help="Size of the black box flight recorder, 0 to disable",
default=10,
type=check_fr_size,
dest='fr_size')
type=check_bb_size,
dest='bb_size')
args = parser.parse_args()
use_session = os.getenv('LVMDBUSD_USE_SESSION', False)
if not args.use_json:
log_error("Daemon no longer supports lvm without JSON support, exiting!")
sys.exit(1)
else:
if not supports_json():
log_error("Un-supported version of LVM, daemon requires JSON output, exiting!")
sys.exit(1)
# Add udev watching
if args.use_udev:
# Make sure this msg ends up in the journal, so we know
log_msg('The --udev option is no longer supported,'
'the daemon always uses a combination of dbus notify from lvm tools and udev')
return args
def running_under_systemd():
""""
Checks to see if we are running under systemd, by checking damon fd 0, 1
systemd sets stdin to /dev/null and 1 & 2 are a socket
"""
base = "/proc/self/fd"
stdout = os.readlink("%s/0" % base)
if stdout == "/dev/null":
stdout = os.readlink("%s/1" % base)
if "socket" in stdout:
return True
return False
def main():
start = time.time()
use_session = os.getenv('LVM_DBUSD_USE_SESSION', False)
# Ensure that we get consistent output for parsing stdout/stderr and that we
# are using the lvmdbusd profile.
# Ensure that we get consistent output for parsing stdout/stderr
os.environ["LC_ALL"] = "C"
os.environ["LVM_COMMAND_PROFILE"] = "lvmdbusd"
# Save off the debug data needed for lvm team to debug issues
# only used for 'fullreport' at this time.
cfg.lvmdebug = utils.LvmDebugData()
# Indicator if we are running under systemd
cfg.systemd = running_under_systemd()
# Add simple command line handling
cfg.args = process_args()
cfg.args = parser.parse_args()
cfg.create_request_entry = RequestEntry
# We create a flight recorder in cmdhandler too, but we replace it here
# as the user may be specifying a different size. The default one in
# cmdhandler is for when we are running other code with a different main.
cfg.flightrecorder = LvmFlightRecorder(cfg.args.fr_size)
cfg.blackbox = LvmFlightRecorder(cfg.args.bb_size)
# Create a circular buffer for debug logs
cfg.debug = DebugMessages()
log_debug("Using lvm binary: %s" % cfg.LVM_CMD)
if cfg.args.use_lvm_shell and not cfg.args.use_json:
log_error("You cannot specify --lvmshell and --nojson")
sys.exit(1)
# We will dynamically add interfaces which support vdo if it
# exists.
cfg.vdo_support = supports_vdo()
if cfg.vdo_support and not cfg.args.use_json:
log_error("You cannot specify --nojson when lvm has VDO support")
sys.exit(1)
# List of threads that we start up
thread_list = []
install_signal_handlers()
with utils.LockFile(cfg.LOCK_FILE):
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
dbus.mainloop.glib.threads_init()
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
dbus.mainloop.glib.threads_init()
cmdhandler.set_execution(cfg.args.use_lvm_shell)
cmdhandler.set_execution(cfg.args.use_lvm_shell)
if use_session:
cfg.bus = dbus.SessionBus()
else:
cfg.bus = dbus.SystemBus()
# The base name variable needs to exist for things to work.
# noinspection PyUnusedLocal
base_name = dbus.service.BusName(BUS_NAME, cfg.bus)
cfg.om = Lvm(BASE_OBJ_PATH)
cfg.om.register_object(Manager(MANAGER_OBJ_PATH))
if use_session:
cfg.bus = dbus.SessionBus()
else:
cfg.bus = dbus.SystemBus()
# The base name variable needs to exist for things to work.
# noinspection PyUnusedLocal
base_name = dbus.service.BusName(BUS_NAME, cfg.bus)
cfg.om = Lvm(BASE_OBJ_PATH)
cfg.om.register_object(Manager(MANAGER_OBJ_PATH))
cfg.db = lvmdb.DataStore(vdo_support=cfg.vdo_support)
cfg.db = lvmdb.DataStore(cfg.args.use_json, cfg.vdo_support)
# Using a thread to process requests, we cannot hang the dbus library
# thread that is handling the dbus interface
thread_list.append(
threading.Thread(target=process_request, name='process_request'))
# Using a thread to process requests, we cannot hang the dbus library
# thread that is handling the dbus interface
thread_list.append(
threading.Thread(target=process_request, name='process_request'))
# Have a single thread handling updating lvm and the dbus model so we
# don't have multiple threads doing this as the same time
updater = StateUpdate()
thread_list.append(updater.thread)
# Have a single thread handling updating lvm and the dbus model so we
# don't have multiple threads doing this as the same time
updater = StateUpdate()
thread_list.append(updater.thread)
cfg.load = updater.load
cfg.load = updater.load
cfg.loop = GLib.MainLoop()
cfg.loop = GLib.MainLoop()
for thread in thread_list:
thread.damon = True
thread.start()
for thread in thread_list:
thread.damon = True
thread.start()
# In all cases we are going to monitor for udev until we get an
# ExternalEvent. In the case where we get an external event and the user
# didn't specify --udev we will stop monitoring udev
udevwatch.add()
# Add udev watching
if cfg.args.use_udev:
log_debug('Utilizing udev to trigger updates')
end = time.time()
log_debug(
'Service ready! total time= %.4f, lvm time= %.4f count= %d' %
(end - start, cmdhandler.total_time, cmdhandler.total_count),
'bg_black', 'fg_light_green')
# In all cases we are going to monitor for udev until we get an
# ExternalEvent. In the case where we get an external event and the user
# didn't specify --udev we will stop monitoring udev
udevwatch.add()
try:
if cfg.run.value != 0:
cfg.loop.run()
udevwatch.remove()
end = time.time()
log_debug(
'Service ready! total time= %.4f, lvm time= %.4f count= %d' %
(end - start, cmdhandler.total_time, cmdhandler.total_count),
'bg_black', 'fg_light_green')
for thread in thread_list:
thread.join()
except KeyboardInterrupt:
# If we are unable to register signal handler, we will end up here when
# the service gets a ^C or a kill -2 <parent pid>
utils.handler(signal.SIGINT)
try:
if cfg.run.value != 0:
cfg.loop.run()
udevwatch.remove()
for thread in thread_list:
thread.join()
except KeyboardInterrupt:
# If we are unable to register signal handler, we will end up here when
# the service gets a ^C or a kill -2 <parent pid>
utils.handler(signal.SIGINT)
return 0

View File

@@ -137,8 +137,7 @@ class Manager(AutomatedProperties):
"""
Dump the flight recorder to syslog
"""
cfg.debug.dump()
cfg.flightrecorder.dump()
cfg.blackbox.dump()
@staticmethod
def _lookup_by_lvm_id(key):
@@ -195,7 +194,6 @@ class Manager(AutomatedProperties):
def _external_event(command):
utils.log_debug("Processing _external_event= %s" % command,
'bg_black', 'fg_orange')
cfg.got_external_event = True
cfg.load()
@dbus.service.method(
@@ -203,6 +201,14 @@ class Manager(AutomatedProperties):
in_signature='s', out_signature='i')
def ExternalEvent(self, command):
utils.log_debug("ExternalEvent %s" % command)
# If a user didn't explicitly specify udev, we will turn it off now.
if not cfg.args.use_udev:
if udevwatch.remove():
utils.log_debug("ExternalEvent received, disabling "
"udev monitoring")
# We are dependent on external events now to stay current!
cfg.got_external_event = True
r = RequestEntry(
-1, Manager._external_event, (command,), None, None, False)
cfg.worker_q.put(r)

View File

@@ -9,11 +9,12 @@
import sys
import threading
import traceback
import dbus
import os
import copy
from . import cfg
from .utils import log_debug, pv_obj_path_generate, log_error, extract_stack_trace
from .utils import log_debug, pv_obj_path_generate, log_error
from .automatedproperties import AutomatedProperties
@@ -39,8 +40,8 @@ class ObjectManager(AutomatedProperties):
for k, v in list(obj._objects.items()):
path, props = v[0].emit_data()
rc[path] = props
except Exception as e:
log_error("_get_managed_objects exception, bailing: \n%s" % extract_stack_trace(e))
except Exception:
traceback.print_exc(file=sys.stdout)
sys.exit(1)
return rc
@@ -52,6 +53,15 @@ class ObjectManager(AutomatedProperties):
(self, ), cb, cbe, False)
cfg.worker_q.put(r)
def locked(self):
"""
If some external code need to run across a number of different
calls into ObjectManager while blocking others they can use this method
to lock others out.
:return:
"""
return ObjectManagerLock(self.rlock)
@dbus.service.signal(
dbus_interface="org.freedesktop.DBus.ObjectManager",
signature='oa{sa{sv}}')
@@ -277,7 +287,7 @@ class ObjectManager(AutomatedProperties):
register it with the object manager for the specified uuid & lvm_id.
Note: If path create is not None, uuid and lvm_id cannot be equal
:param uuid: The uuid for the lvm object we are searching for
:param lvm_id: The lvm name (e.g. pv device path, vg name, lv full name)
:param lvm_id: The lvm name (eg. pv device path, vg name, lv full name)
:param path_create: If not None, create the path using this function if
we fail to find the object by uuid or lvm_id.
:returns None if lvm asset not found and path_create == None otherwise
@@ -298,11 +308,12 @@ class ObjectManager(AutomatedProperties):
# We have a uuid and a lvm_id we can do sanity checks to ensure
# that they are consistent
# If a PV is missing its device path is '[unknown]' or some
# If a PV is missing it's device path is '[unknown]' or some
# other text derivation of unknown. When we find that a PV is
# missing we will clear out the lvm_id as it's not unique
# and thus not useful and harmful for lookups.
if cfg.db.pv_missing(uuid):
# missing we will clear out the lvm_id as it's likely not unique
# and thus not useful and potentially harmful for lookups.
if path_create == pv_obj_path_generate and \
cfg.db.pv_missing(uuid):
lvm_id = None
# Lets check for the uuid first
@@ -326,3 +337,29 @@ class ObjectManager(AutomatedProperties):
# (uuid, lvm_id, str(path_create), path))
return path
class ObjectManagerLock(object):
"""
The sole purpose of this class is to allow other code the ability to
lock the object manager using a `with` statement, eg.
with cfg.om.locked():
# Do stuff with object manager
This will ensure that the lock is always released (assuming this is done
correctly)
"""
def __init__(self, recursive_lock):
self._lock = recursive_lock
def __enter__(self):
# Acquire lock
self._lock.acquire()
# noinspection PyUnusedLocal
def __exit__(self, e_type, e_value, e_traceback):
# Release lock
self._lock.release()
self._lock = None

View File

@@ -14,11 +14,11 @@ import dbus
from .cfg import PV_INTERFACE
from . import cmdhandler
from .utils import vg_obj_path_generate, n, pv_obj_path_generate, \
lv_object_path_method, _handle_execute, lvm_column_key
lv_object_path_method, _handle_execute
from .loader import common
from .request import RequestEntry
from .state import State
from .utils import round_size, LvmBug
from .utils import round_size
# noinspection PyUnusedLocal
@@ -28,23 +28,16 @@ def pvs_state_retrieve(selection, cache_refresh=True):
if cache_refresh:
cfg.db.refresh()
try:
for p in cfg.db.fetch_pvs(selection):
rc.append(
PvState(
p["pv_name"], p["pv_uuid"], p["pv_name"],
p["pv_fmt"], n(p["pv_size"]), n(p["pv_free"]),
n(p["pv_used"]), n(p["dev_size"]), n(p["pv_mda_size"]),
n(p["pv_mda_free"]), int(p["pv_ba_start"]),
n(p["pv_ba_size"]), n(p["pe_start"]),
int(p["pv_pe_count"]), int(p["pv_pe_alloc_count"]),
p["pv_attr"], p["pv_tags"], p["vg_name"], p["vg_uuid"]))
except KeyError as ke:
# Sometimes lvm omits returning one of the keys we requested.
key = ke.args[0]
if lvm_column_key(key):
raise LvmBug("missing JSON key: '%s'" % key)
raise ke
for p in cfg.db.fetch_pvs(selection):
rc.append(
PvState(
p["pv_name"], p["pv_uuid"], p["pv_name"],
p["pv_fmt"], n(p["pv_size"]), n(p["pv_free"]),
n(p["pv_used"]), n(p["dev_size"]), n(p["pv_mda_size"]),
n(p["pv_mda_free"]), int(p["pv_ba_start"]),
n(p["pv_ba_size"]), n(p["pe_start"]),
int(p["pv_pe_count"]), int(p["pv_pe_alloc_count"]),
p["pv_attr"], p["pv_tags"], p["vg_name"], p["vg_uuid"]))
return rc

View File

@@ -7,13 +7,13 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import dbus
import threading
# noinspection PyUnresolvedReferences
from gi.repository import GLib
from .job import Job
from . import cfg
from .utils import log_error, mt_async_call, extract_stack_trace
import traceback
from .utils import log_error, mt_async_call
class RequestEntry(object):
@@ -71,23 +71,13 @@ class RequestEntry(object):
try:
result = self.method(*self.arguments)
self.register_result(result)
except SystemExit as se:
self.register_error(-1, str(se), se)
raise se
except dbus.exceptions.DBusException as dbe:
# This is an expected error path when something goes awry that
# we handled
self.register_error(-1, str(dbe), dbe)
except Exception as e:
# Use the request entry to return the result as the client may
# have gotten a job by the time we hit an error
# Lets set the exception text as the error message and log the
# exception in the journal for figuring out what went wrong.
cfg.debug.dump()
cfg.flightrecorder.dump()
tb = extract_stack_trace(e)
log_error("While processing %s: we encountered\n%s" % (str(self.method), tb))
log_error("Error returned to client: %s" % str(e))
# Lets get the stacktrace and set that to the error message
st = traceback.format_exc()
cfg.blackbox.dump()
log_error("Exception returned to client: \n%s" % st)
self.register_error(-1, str(e), e)
def is_done(self):

View File

@@ -52,30 +52,20 @@ def filter_event(action, device):
# when appropriate.
refresh = False
# Ignore everything but change
if action != 'change':
return
if 'ID_FS_TYPE' in device:
fs_type_new = device['ID_FS_TYPE']
if 'LVM' in fs_type_new:
# If we get a lvm related udev event for a block device
# we don't know about, it's either a pvcreate which we
# would handle with the dbus notification or something
# copied a pv signature onto a block device, this is
# required to catch the latter.
if not cfg.om.get_object_by_lvm_id(device['DEVNAME']):
refresh = True
refresh = True
elif fs_type_new == '':
# Check to see if the device was one we knew about
if 'DEVNAME' in device:
if cfg.om.get_object_by_lvm_id(device['DEVNAME']):
found = cfg.om.get_object_by_lvm_id(device['DEVNAME'])
if found:
refresh = True
else:
# This handles the wipefs -a path
if not refresh and 'DEVNAME' in device:
if cfg.om.get_object_by_lvm_id(device['DEVNAME']):
refresh = True
if 'DM_LV_NAME' in device:
refresh = True
if refresh:
udev_add()

View File

@@ -10,15 +10,11 @@
import xml.etree.ElementTree as Et
import sys
import inspect
import collections
import ctypes
import errno
import fcntl
import os
import stat
import string
import datetime
import tempfile
from fcntl import fcntl, F_GETFL, F_SETFL
import dbus
from lvmdbusd import cfg
@@ -284,47 +280,17 @@ def parse_tags(tags):
return dbus.Array([], signature='s')
class DebugMessages(object):
def __init__(self, size=5000):
self.queue = collections.deque(maxlen=size)
self.lock = threading.RLock()
def add(self, message):
with self.lock:
self.queue.append(message)
def dump(self):
if cfg.args and not cfg.args.debug:
with self.lock:
if len(self.queue):
log_error("LVM dbus debug messages START last (%d max) messages" % self.queue.maxlen)
for m in self.queue:
print(m)
log_error("LVM dbus debug messages END")
self.queue.clear()
def _format_log_entry(msg):
def _common_log(msg, *attributes):
cfg.stdout_lock.acquire()
tid = ctypes.CDLL('libc.so.6').syscall(186)
if not cfg.systemd and STDOUT_TTY:
if STDOUT_TTY:
msg = "%s: %d:%d - %s" % \
(datetime.datetime.now().strftime("%b %d %H:%M:%S.%f"),
os.getpid(), tid, msg)
else:
if cfg.systemd:
# Systemd already puts the daemon pid in the log, we'll just add the tid
msg = "[%d]: %s" % (tid, msg)
else:
msg = "[%d:%d]: %s" % (os.getpid(), tid, msg)
return msg
def _common_log(msg, *attributes):
cfg.stdout_lock.acquire()
msg = _format_log_entry(msg)
msg = "%d:%d - %s" % (os.getpid(), tid, msg)
if STDOUT_TTY and attributes:
print(color(msg, *attributes))
@@ -341,19 +307,12 @@ def _common_log(msg, *attributes):
def log_debug(msg, *attributes):
if cfg.args and cfg.args.debug:
_common_log(msg, *attributes)
else:
if cfg.debug:
cfg.debug.add(_format_log_entry(msg))
def log_error(msg, *attributes):
_common_log(msg, *attributes)
def log_msg(msg, *attributes):
_common_log(msg, *attributes)
def dump_threads_stackframe():
ident_to_name = {}
@@ -381,32 +340,15 @@ def dump_threads_stackframe():
# noinspection PyUnusedLocal
def handler(signum):
try:
# signal 10
if signum == signal.SIGUSR1:
cfg.debug.dump()
dump_threads_stackframe()
# signal 12
elif signum == signal.SIGUSR2:
cfg.debug.dump()
cfg.flightrecorder.dump()
else:
# If we are getting a SIGTERM, and we sent one to the lvm shell we
# will ignore this and keep running.
if signum == signal.SIGTERM and cfg.ignore_sigterm:
# Clear the flag, so we will exit on SIGTERM if we didn't
# send it.
cfg.ignore_sigterm = False
return True
# If lvm shell is in use, tell it to exit
if cfg.SHELL_IN_USE is not None:
cfg.SHELL_IN_USE.exit_shell()
cfg.run.value = 0
log_error('Exiting daemon with signal %d' % signum)
log_debug('Exiting daemon with signal %d' % signum)
if cfg.loop is not None:
cfg.loop.quit()
except BaseException as be:
st = extract_stack_trace(be)
except:
st = traceback.format_exc()
log_error("signal handler: exception (logged, not reported!) \n %s" % st)
# It's important we report that we handled the exception for the exception
@@ -630,23 +572,6 @@ def validate_tag(interface, tag):
% (tag, _ALLOWABLE_TAG_CH))
def add_config_option(cmdline, key, value):
if 'help' in cmdline:
return cmdline
if key in cmdline:
for i, arg in enumerate(cmdline):
if arg == key:
if len(cmdline) <= i + 1:
raise dbus.exceptions.DBusException("Missing value for --config option.")
cmdline[i + 1] += " %s" % value
break
else:
cmdline.extend([key, value])
return cmdline
def add_no_notify(cmdline):
"""
Given a command line to execute we will see if `--config` is present, if it
@@ -658,18 +583,27 @@ def add_no_notify(cmdline):
:rtype: list
"""
# Only after we have seen an external event will we disable lvm from sending
# Only after we have seen an external event will be disable lvm from sending
# us one when we call lvm
rv = cmdline
if cfg.got_external_event:
rv = add_config_option(rv, "--config", "global/notify_dbus=0")
if 'help' in cmdline:
return cmdline
return rv
if '--config' in cmdline:
for i, arg in enumerate(cmdline):
if arg == '--config':
if len(cmdline) <= i+1:
raise dbus.exceptions.DBusException("Missing value for --config option.")
cmdline[i+1] += " global/notify_dbus=0"
break
else:
cmdline.extend(['--config', 'global/notify_dbus=0'])
return cmdline
# The methods below which start with mt_* are used to execute the desired code
# on the main thread of execution to alleviate any issues the dbus-python
# library with regard to multithreaded access. Essentially, we are trying to
# on the the main thread of execution to alleviate any issues the dbus-python
# library with regards to multi-threaded access. Essentially, we are trying to
# ensure all dbus library interaction is done from the same thread!
@@ -683,8 +617,9 @@ def _async_handler(call_back, parameters):
call_back(*parameters)
else:
call_back()
except BaseException as be:
log_error("mt_async_call: exception (logged, not reported!) \n %s" % extract_stack_trace(be))
except:
st = traceback.format_exc()
log_error("mt_async_call: exception (logged, not reported!) \n %s" % st)
# Execute the function on the main thread with the provided parameters, do
@@ -734,6 +669,9 @@ class MThreadRunner(object):
self.rc = self.f()
except BaseException as be:
self.exception = be
st = traceback.format_exc()
log_error("MThreadRunner: exception \n %s" % st)
log_error("Exception will be raised in calling thread!")
def _remove_objects(dbus_objects_rm):
@@ -748,8 +686,8 @@ def mt_remove_dbus_objects(objs):
# Make stream non-blocking
def make_non_block(stream):
flags = fcntl.fcntl(stream, fcntl.F_GETFL)
fcntl.fcntl(stream, fcntl.F_SETFL, flags | os.O_NONBLOCK)
flags = fcntl(stream, F_GETFL)
fcntl(stream, F_SETFL, flags | os.O_NONBLOCK)
def read_decoded(stream):
@@ -757,122 +695,3 @@ def read_decoded(stream):
if tmp:
return tmp.decode("utf-8")
return ''
class LockFile(object):
"""
Simple lock file class
Based on Pg.1144 "The Linux Programming Interface" by Michael Kerrisk
"""
def __init__(self, lock_file):
self.fd = 0
self.lock_file = lock_file
def __enter__(self):
try:
self.fd = os.open(self.lock_file, os.O_CREAT | os.O_RDWR, stat.S_IRUSR | stat.S_IWUSR)
# Get and set the close on exec and lock the file
flags = fcntl.fcntl(self.fd, fcntl.F_GETFD)
flags |= fcntl.FD_CLOEXEC
fcntl.fcntl(self.fd, fcntl.F_SETFL, flags)
fcntl.lockf(self.fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
except OSError as e:
if e.errno == errno.EAGAIN:
log_error("Daemon already running, exiting!")
else:
log_error("Error during creation of lock file(%s): errno(%d), exiting!" % (self.lock_file, e.errno))
sys.exit(114)
def __exit__(self, _type, _value, _traceback):
os.close(self.fd)
def extract_stack_trace(exception):
return ''.join(traceback.format_exception(None, exception, exception.__traceback__))
def lvm_column_key(key):
# Check LV
if key.startswith("lv_") or key.startswith("vg_") or key.startswith("pool_") or \
key.endswith("_percent") or key.startswith("move_") or key.startswith("vdo_") or \
key in ["origin_uuid", "segtype", "origin", "data_lv", "metadata_lv"]:
return True
# Check VG
if key.startswith("vg_") or key.startswith("lv_") or key.startswith("pv_") or \
key in ["max_lv", "max_pv", "snap_count"]:
return True
# Check PV
if key.startswith("pv") or key.startswith("vg") or (key in ['dev_size', 'pe_start']):
return True
return False
class LvmBug(RuntimeError):
"""
Things that are clearly a bug with lvm itself.
"""
def __init__(self, msg):
super().__init__(msg)
def __str__(self):
return "lvm bug encountered: %s" % ' '.join(self.args)
class LvmDebugData:
def __init__(self):
self.fd = -1
self.fn = None
def _remove_file(self):
if self.fn is not None:
os.unlink(self.fn)
self.fn = None
def _close_fd(self):
if self.fd != -1:
os.close(self.fd)
self.fd = -1
def setup(self):
# Create a secure filename
self.fd, self.fn = tempfile.mkstemp(suffix=".log", prefix="lvmdbusd.lvm.debug.")
return self.fn
def lvm_complete(self):
# Remove the file ASAP, so we decrease our odds of leaving it
# around if the daemon gets killed by a signal -9
self._remove_file()
def dump(self):
# Read the file and log it to log_err
if self.fd != -1:
# How big could the verbose debug get?
debug = os.read(self.fd, 1024*1024*5)
debug_txt = debug.decode("utf-8")
for line in debug_txt.split("\n"):
log_error("lvm debug >>> %s" % line)
self._close_fd()
# In case lvm_complete doesn't get called.
self._remove_file()
def complete(self):
self._close_fd()
# In case lvm_complete doesn't get called.
self._remove_file()
def get_error_msg(report_json):
# Get the error message from the returned JSON
if 'log' in report_json:
error_msg = ""
# Walk the entire log array and build an error string
for log_entry in report_json['log']:
if log_entry['log_type'] == "error":
if error_msg:
error_msg += ', ' + log_entry['log_message']
else:
error_msg = log_entry['log_message']
return error_msg
return None

View File

@@ -20,7 +20,7 @@ from .request import RequestEntry
from .loader import common
from .state import State
from . import background
from .utils import round_size, mt_remove_dbus_objects, LvmBug, lvm_column_key
from .utils import round_size, mt_remove_dbus_objects
from .job import JobState
@@ -31,24 +31,17 @@ def vgs_state_retrieve(selection, cache_refresh=True):
if cache_refresh:
cfg.db.refresh()
try:
for v in cfg.db.fetch_vgs(selection):
rc.append(
VgState(
v['vg_uuid'], v['vg_name'], v['vg_fmt'], n(v['vg_size']),
n(v['vg_free']), v['vg_sysid'], n(v['vg_extent_size']),
n(v['vg_extent_count']), n(v['vg_free_count']),
v['vg_profile'], n(v['max_lv']), n(v['max_pv']),
n(v['pv_count']), n(v['lv_count']), n(v['snap_count']),
n(v['vg_seqno']), n(v['vg_mda_count']),
n(v['vg_mda_free']), n(v['vg_mda_size']),
n(v['vg_mda_used_count']), v['vg_attr'], v['vg_tags']))
except KeyError as ke:
# Sometimes lvm omits returning one of the keys we requested.
key = ke.args[0]
if lvm_column_key(key):
raise LvmBug("missing JSON key: '%s'" % key)
raise ke
for v in cfg.db.fetch_vgs(selection):
rc.append(
VgState(
v['vg_uuid'], v['vg_name'], v['vg_fmt'], n(v['vg_size']),
n(v['vg_free']), v['vg_sysid'], n(v['vg_extent_size']),
n(v['vg_extent_count']), n(v['vg_free_count']),
v['vg_profile'], n(v['max_lv']), n(v['max_pv']),
n(v['pv_count']), n(v['lv_count']), n(v['snap_count']),
n(v['vg_seqno']), n(v['vg_mda_count']),
n(v['vg_mda_free']), n(v['vg_mda_size']),
n(v['vg_mda_used_count']), v['vg_attr'], v['vg_tags']))
return rc

View File

@@ -5954,18 +5954,7 @@ static void adopt_locks(void)
}
/* Try to purge the orphan locks when lock manager is dlm */
if (lm_support_dlm() && lm_is_running_dlm()) {
list_for_each_entry(ls, &ls_found, list) {
pthread_mutex_lock(&lockspaces_mutex);
ls1 = find_lockspace_name(ls->name);
if (ls1) {
log_debug("ls: %s purge locks", ls->name);
lm_purge_locks_dlm(ls1);
}
pthread_mutex_unlock(&lockspaces_mutex);
}
}
/* FIXME: purge any remaining orphan locks in each rejoined ls? */
if (count_start_fail || count_adopt_fail)
goto fail;

View File

@@ -220,86 +220,6 @@ int lm_prepare_lockspace_dlm(struct lockspace *ls)
return 0;
}
#define DLM_COMMS_PATH "/sys/kernel/config/dlm/cluster/comms"
#define LOCK_LINE_MAX 1024
static int get_local_nodeid(void)
{
struct dirent *de;
DIR *ls_dir;
char ls_comms_path[PATH_MAX];
FILE *file = NULL;
char line[LOCK_LINE_MAX];
int rv = -1, val;
memset(ls_comms_path, 0, sizeof(ls_comms_path));
snprintf(ls_comms_path, PATH_MAX, "%s",DLM_COMMS_PATH);
if (!(ls_dir = opendir(ls_comms_path)))
return -ECONNREFUSED;
while ((de = readdir(ls_dir))) {
if (de->d_name[0] == '.')
continue;
memset(ls_comms_path, 0, sizeof(ls_comms_path));
snprintf(ls_comms_path, PATH_MAX, "%s/%s/local",
DLM_COMMS_PATH, de->d_name);
file = fopen(ls_comms_path, "r");
if (!file)
continue;
if (fgets(line, LOCK_LINE_MAX, file)) {
fclose(file);
rv = sscanf(line, "%d", &val);
if ((rv == 1) && (val == 1 )) {
memset(ls_comms_path, 0, sizeof(ls_comms_path));
snprintf(ls_comms_path, PATH_MAX, "%s/%s/nodeid",
DLM_COMMS_PATH, de->d_name);
file = fopen(ls_comms_path, "r");
if (!file)
continue;
if (fgets(line, LOCK_LINE_MAX, file)) {
rv = sscanf(line, "%d", &val);
if (rv == 1) {
fclose(file);
closedir(ls_dir);
return val;
}
}
}
}
fclose(file);
}
if (closedir(ls_dir))
log_error("get_local_nodeid closedir error");
return rv;
}
int lm_purge_locks_dlm(struct lockspace *ls)
{
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;
int nodeid;
int rv = -1;
if (!lmd || !lmd->dh) {
log_error("purge_locks_dlm %s no dlm_handle_t error", ls->name);
goto fail;
}
nodeid = get_local_nodeid();
if (nodeid < 0) {
log_error("failed to get local nodeid");
goto fail;
}
if (dlm_ls_purge(lmd->dh, nodeid, 0)) {
log_error("purge_locks_dlm %s error", ls->name);
goto fail;
}
rv = 0;
fail:
return rv;
}
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt)
{
struct lm_dlm *lmd = (struct lm_dlm *)ls->lm_data;

View File

@@ -392,7 +392,6 @@ static inline const char *mode_str(int x)
int lm_init_vg_dlm(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
int lm_prepare_lockspace_dlm(struct lockspace *ls);
int lm_add_lockspace_dlm(struct lockspace *ls, int adopt);
int lm_purge_locks_dlm(struct lockspace *ls);
int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg);
int lm_lock_dlm(struct lockspace *ls, struct resource *r, int ld_mode,
struct val_blk *vb_out, int adopt);
@@ -430,11 +429,6 @@ static inline int lm_add_lockspace_dlm(struct lockspace *ls, int adopt)
return -1;
}
static inline int lm_purge_locks_dlm(struct lockspace *ls)
{
return -1;
}
static inline int lm_rem_lockspace_dlm(struct lockspace *ls, int free_vg)
{
return -1;

View File

@@ -684,10 +684,10 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
break;
}
if (rv < 0) {
if (rv) {
log_error("clear lv resource area %llu error %d",
(unsigned long long)offset, rv);
return rv;
break;
}
offset += align_size;
}

View File

@@ -52,7 +52,7 @@ static pthread_key_t key;
static const char *_strerror_r(int errnum, struct lvmpolld_thread_data *data)
{
#if defined(_GNU_SOURCE) && defined(STRERROR_R_CHAR_P)
#ifdef _GNU_SOURCE
return strerror_r(errnum, data->buf, sizeof(data->buf)); /* never returns NULL */
#elif (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600)
return strerror_r(errnum, data->buf, sizeof(data->buf)) ? "" : data->buf;

View File

@@ -1,4 +1,4 @@
# Copyright (C) 2018 - 2022 Red Hat, Inc. All rights reserved.
# Copyright (C) 2018 Red Hat, Inc. All rights reserved.
#
# This file is part of the device-mapper userspace tools.
#
@@ -29,7 +29,6 @@ DEVICE_MAPPER_SOURCE=\
device_mapper/regex/parse_rx.c \
device_mapper/regex/ttree.c \
device_mapper/vdo/status.c \
device_mapper/vdo/vdo_reader.c \
device_mapper/vdo/vdo_target.c
DEVICE_MAPPER_TARGET = device_mapper/libdevice-mapper.a

View File

@@ -982,9 +982,7 @@ struct writecache_settings {
uint32_t fua;
uint32_t nofua;
uint32_t cleaner;
uint32_t max_age; /* in milliseconds */
uint32_t metadata_only;
uint32_t pause_writeback; /* in milliseconds */
uint32_t max_age;
/*
* Allow an unrecognized key and its val to be passed to the kernel for
@@ -1006,8 +1004,6 @@ struct writecache_settings {
unsigned nofua_set:1;
unsigned cleaner_set:1;
unsigned max_age_set:1;
unsigned metadata_only_set:1;
unsigned pause_writeback_set:1;
};
int dm_tree_node_add_writecache_target(struct dm_tree_node *node,
@@ -1053,7 +1049,6 @@ int dm_tree_node_add_integrity_target(struct dm_tree_node *node,
*/
int dm_tree_node_add_vdo_target(struct dm_tree_node *node,
uint64_t size,
uint32_t vdo_version,
const char *vdo_pool_name,
const char *data_uuid,
uint64_t data_size,
@@ -1987,8 +1982,7 @@ struct dm_report_group;
typedef enum {
DM_REPORT_GROUP_SINGLE,
DM_REPORT_GROUP_BASIC,
DM_REPORT_GROUP_JSON,
DM_REPORT_GROUP_JSON_STD
DM_REPORT_GROUP_JSON
} dm_report_group_type_t;
struct dm_report_group *dm_report_group_create(dm_report_group_type_t type, void *data);

View File

@@ -139,6 +139,7 @@ static char *_align(char *ptr, unsigned int a)
return (char *) (((unsigned long) ptr + agn) & ~agn);
}
#ifdef DM_IOCTLS
static unsigned _kernel_major = 0;
static unsigned _kernel_minor = 0;
static unsigned _kernel_release = 0;
@@ -181,9 +182,6 @@ int get_uname_version(unsigned *major, unsigned *minor, unsigned *release)
return 1;
}
#ifdef DM_IOCTLS
/*
* Set number to NULL to populate _dm_bitset - otherwise first
* match is returned.

View File

@@ -214,7 +214,6 @@ struct load_segment {
uint32_t device_id; /* Thin */
// VDO params
uint32_t vdo_version; /* VDO - version of target table line */
struct dm_tree_node *vdo_data; /* VDO */
struct dm_vdo_target_params vdo_params; /* VDO */
const char *vdo_name; /* VDO - device name is ALSO passed as table arg */
@@ -294,10 +293,6 @@ struct load_properties {
unsigned send_messages;
/* Skip suspending node's children, used when sending messages to thin-pool */
int skip_suspend;
/* Suspend and Resume siblings after node activation with udev flags*/
unsigned reactivate_siblings;
uint16_t reactivate_udev_flags;
};
/* Two of these used to join two nodes with uses and used_by. */
@@ -2034,68 +2029,6 @@ static int _rename_conflict_exists(struct dm_tree_node *parent,
return 0;
}
/*
* Reactivation of sibling nodes
*
* Function is used when activating origin and its thick snapshots
* to ensure udev is processing first the origin LV and all the
* snapshot LVs are processed afterwards.
*/
static int _reactivate_siblings(struct dm_tree_node *dnode,
const char *uuid_prefix,
size_t uuid_prefix_len)
{
struct dm_tree_node *child;
const char *uuid;
void *handle = NULL;
int r = 1;
/* Wait for udev before reactivating siblings */
if (!dm_udev_wait(dm_tree_get_cookie(dnode)))
stack;
dm_tree_set_cookie(dnode, 0);
while ((child = dm_tree_next_child(&handle, dnode, 0))) {
if (child->props.reactivate_siblings) {
/* Skip 'leading' device in this group, marked with flag */
child->props.reactivate_siblings = 0;
continue;
}
if (!(uuid = dm_tree_node_get_uuid(child))) {
stack;
continue;
}
if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
continue;
if (!_suspend_node(child->name, child->info.major, child->info.minor,
child->dtree->skip_lockfs,
child->dtree->no_flush, &child->info)) {
log_error("Unable to suspend %s (" FMTu32
":" FMTu32 ")", child->name,
child->info.major, child->info.minor);
r = 0;
continue;
}
if (!_resume_node(child->name, child->info.major, child->info.minor,
child->props.read_ahead, child->props.read_ahead_flags,
&child->info, &child->dtree->cookie,
child->props.reactivate_udev_flags, // use these flags
child->info.suspended)) {
log_error("Failed to suspend %s (" FMTu32
":" FMTu32 ")", child->name,
child->info.major, child->info.minor);
r = 0;
continue;
}
}
return r;
}
int dm_tree_activate_children(struct dm_tree_node *dnode,
const char *uuid_prefix,
size_t uuid_prefix_len)
@@ -2106,7 +2039,7 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
struct dm_tree_node *child = dnode;
const char *name;
const char *uuid;
int priority, next_priority;
int priority;
/* Activate children first */
while ((child = dm_tree_next_child(&handle, dnode, 0))) {
@@ -2124,16 +2057,12 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
}
handle = NULL;
for (priority = 0; priority < 3; priority++) {
awaiting_peer_rename = 0;
next_priority = 0;
while ((child = dm_tree_next_child(&handle, dnode, 0))) {
if (priority != child->activation_priority) {
if ((next_priority < child->activation_priority) &&
(child->activation_priority > priority))
next_priority = child->activation_priority;
if (priority != child->activation_priority)
continue;
}
if (!(uuid = dm_tree_node_get_uuid(child))) {
stack;
@@ -2188,16 +2117,9 @@ int dm_tree_activate_children(struct dm_tree_node *dnode,
if (r && (child->props.send_messages > 1) &&
!(r = _node_send_messages(child, uuid_prefix, uuid_prefix_len, 1)))
stack;
/* Reactivate only for fresh activated origin */
if (r && child->props.reactivate_siblings &&
(!(r = _reactivate_siblings(dnode, uuid_prefix, uuid_prefix_len))))
stack;
}
if (awaiting_peer_rename)
priority--; /* redo priority level */
else if (!next_priority)
break; /* no more work, higher priority was not found in the chain */
}
return r;
@@ -2756,10 +2678,6 @@ static int _writecache_emit_segment_line(struct dm_task *dmt,
count += 1;
if (seg->writecache_settings.max_age_set)
count += 2;
if (seg->writecache_settings.metadata_only_set)
count += 1;
if (seg->writecache_settings.pause_writeback_set)
count += 2;
if (seg->writecache_settings.new_key)
count += 2;
@@ -2811,14 +2729,6 @@ static int _writecache_emit_segment_line(struct dm_task *dmt,
EMIT_PARAMS(pos, " max_age %u", seg->writecache_settings.max_age);
}
if (seg->writecache_settings.metadata_only_set) {
EMIT_PARAMS(pos, " metadata_only");
}
if (seg->writecache_settings.pause_writeback_set) {
EMIT_PARAMS(pos, " pause_writeback %u", seg->writecache_settings.pause_writeback);
}
if (seg->writecache_settings.new_key) {
EMIT_PARAMS(pos, " %s %s",
seg->writecache_settings.new_key,
@@ -2939,18 +2849,13 @@ static int _thin_pool_emit_segment_line(struct dm_task *dmt,
return 1;
}
static int _vdo_emit_segment_line(struct dm_task *dmt, uint32_t major, uint32_t minor,
static int _vdo_emit_segment_line(struct dm_task *dmt,
struct load_segment *seg,
char *params, size_t paramsize)
{
int pos = 0;
char data[DM_FORMAT_DEV_BUFSIZE];
char data_dev[128]; // for /dev/dm-XXXX
uint64_t logical_blocks;
struct dm_task *vdo_dmt;
uint64_t start, length = 0;
char *type = NULL;
char *vdo_params = NULL;
if (!_build_dev_string(data, sizeof(data), seg->vdo_data))
return_0;
@@ -2960,59 +2865,18 @@ static int _vdo_emit_segment_line(struct dm_task *dmt, uint32_t major, uint32_t
return 0;
}
/*
* If there is already running VDO target, read 'existing' virtual size out of table line
* and avoid reading it them from VDO metadata device
*
* NOTE: ATM VDO virtual size can be ONLY extended thus it's simple to recongnize 'right' size.
* However if there would be supported also reduction, this check would need to check range.
*/
if ((vdo_dmt = dm_task_create(DM_DEVICE_TABLE))) {
if (dm_task_set_major(vdo_dmt, major) &&
dm_task_set_minor(vdo_dmt, minor) &&
dm_task_run(vdo_dmt)) {
(void) dm_get_next_target(vdo_dmt, NULL, &start, &length, &type, &vdo_params);
if (!type || strcmp(type, "vdo"))
length = 0;
}
dm_task_destroy(vdo_dmt);
}
if (!length && dm_vdo_parse_logical_size(data_dev, &logical_blocks))
length = logical_blocks * 8;
if (seg->size < length) {
log_debug_activation("Correcting VDO virtual volume size from " FMTu64 " to " FMTu64 ".",
seg->size, length);
seg->size = length;
}
if (seg->vdo_version < 4) {
EMIT_PARAMS(pos, "V2 %s " FMTu64 " %u " FMTu64 " %u %s %s %s ",
data_dev,
seg->vdo_data_size / 8, // this parameter is in 4K units
seg->vdo_params.minimum_io_size * UINT32_C(512), // sector to byte units
seg->vdo_params.block_map_cache_size_mb * UINT64_C(256), // 1MiB -> 4KiB units
seg->vdo_params.block_map_era_length,
seg->vdo_params.use_metadata_hints ? "on" : "off" ,
(seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_SYNC) ? "sync" :
(seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_ASYNC) ? "async" :
(seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_ASYNC_UNSAFE) ? "async-unsafe" : "auto", // policy
seg->vdo_name);
} else {
EMIT_PARAMS(pos, "V4 %s " FMTu64 " %u " FMTu64 " %u "
"deduplication %s compression %s ",
data_dev,
seg->vdo_data_size / 8, // this parameter is in 4K units
seg->vdo_params.minimum_io_size * UINT32_C(512), // sector to byte units
seg->vdo_params.block_map_cache_size_mb * UINT64_C(256), // 1MiB -> 4KiB units
seg->vdo_params.block_map_era_length,
seg->vdo_params.use_deduplication ? "on" : "off",
seg->vdo_params.use_compression ? "on" : "off");
}
EMIT_PARAMS(pos, "maxDiscard %u ack %u bio %u bioRotationInterval %u cpu %u hash %u logical %u physical %u",
EMIT_PARAMS(pos, "V2 %s " FMTu64 " %u " FMTu64 " %u %s %s %s "
"maxDiscard %u ack %u bio %u bioRotationInterval %u cpu %u hash %u logical %u physical %u",
data_dev,
seg->vdo_data_size / 8, // this parameter is in 4K units
seg->vdo_params.minimum_io_size * UINT32_C(512), // sector to byte units
seg->vdo_params.block_map_cache_size_mb * UINT64_C(256), // 1MiB -> 4KiB units
seg->vdo_params.block_map_era_length,
seg->vdo_params.use_metadata_hints ? "on" : "off" ,
(seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_SYNC) ? "sync" :
(seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_ASYNC) ? "async" :
(seg->vdo_params.write_policy == DM_VDO_WRITE_POLICY_ASYNC_UNSAFE) ? "async-unsafe" : "auto", // policy
seg->vdo_name,
seg->vdo_params.max_discard,
seg->vdo_params.ack_threads,
seg->vdo_params.bio_threads,
@@ -3087,7 +2951,7 @@ static int _emit_segment_line(struct dm_task *dmt, uint32_t major,
EMIT_PARAMS(pos, "%u %u ", seg->area_count, seg->stripe_size);
break;
case SEG_VDO:
if (!_vdo_emit_segment_line(dmt, major, minor, seg, params, paramsize))
if (!_vdo_emit_segment_line(dmt, seg, params, paramsize))
return_0;
break;
case SEG_CRYPT:
@@ -3526,10 +3390,6 @@ int dm_tree_node_add_snapshot_origin_target(struct dm_tree_node *dnode,
/* Resume snapshot origins after new snapshots */
dnode->activation_priority = 1;
if (!dnode->info.exists)
/* Reactivate siblings for this origin after being resumed */
dnode->props.reactivate_siblings = 1;
/*
* Don't resume the origin immediately in case it is a non-trivial
* target that must not be active more than once concurrently!
@@ -3592,20 +3452,6 @@ static int _add_snapshot_target(struct dm_tree_node *node,
/* Resume merging snapshot after snapshot-merge */
seg->merge->activation_priority = 2;
}
} else if (!origin_node->info.exists) {
/* Keep original udev_flags for reactivation. */
node->props.reactivate_udev_flags = node->udev_flags;
/* Reactivation is needed if the origin's -real device is not in DM table.
* For this case after the resume of its origin LV we resume its snapshots
* with updated udev_flags to completely avoid udev scanning for the first resume.
* Reactivation then resumes snapshots with original udev_flags.
*/
node->udev_flags |= DM_SUBSYSTEM_UDEV_FLAG0 |
DM_UDEV_DISABLE_DISK_RULES_FLAG |
DM_UDEV_DISABLE_OTHER_RULES_FLAG;
log_debug_activation("Using udev_flags 0x%x for activation of %s.",
node->udev_flags, node->name);
}
return 1;
@@ -4477,7 +4323,6 @@ void dm_tree_node_set_callback(struct dm_tree_node *dnode,
int dm_tree_node_add_vdo_target(struct dm_tree_node *node,
uint64_t size,
uint32_t vdo_version,
const char *vdo_pool_name,
const char *data_uuid,
uint64_t data_size,
@@ -4499,13 +4344,11 @@ int dm_tree_node_add_vdo_target(struct dm_tree_node *node,
if (!_link_tree_nodes(node, seg->vdo_data))
return_0;
seg->vdo_version = vdo_version;
seg->vdo_params = *vtp;
seg->vdo_name = vdo_pool_name;
seg->vdo_data_size = data_size;
if (seg->vdo_version < 4)
node->props.send_messages = 2;
node->props.send_messages = 2;
return 1;
}

View File

@@ -384,246 +384,172 @@ int dm_report_field_percent(struct dm_report *rh,
return 1;
}
struct pos_len {
struct str_list_sort_value_item {
unsigned pos;
size_t len;
};
struct str_pos_len {
const char *str;
struct pos_len item;
};
struct str_list_sort_value {
const char *value;
struct pos_len *items;
struct str_list_sort_value_item *items;
};
static int _str_sort_cmp(const void *a, const void *b)
{
return strcmp(((const struct str_pos_len *) a)->str, ((const struct str_pos_len *) b)->str);
}
struct str_list_sort_item {
const char *str;
struct str_list_sort_value_item item;
};
#define FIELD_STRING_LIST_DEFAULT_DELIMITER ","
static int _str_list_sort_item_cmp(const void *a, const void *b)
{
const struct str_list_sort_item *slsi_a = (const struct str_list_sort_item *) a;
const struct str_list_sort_item *slsi_b = (const struct str_list_sort_item *) b;
return strcmp(slsi_a->str, slsi_b->str);
}
static int _report_field_string_list(struct dm_report *rh,
struct dm_report_field *field,
const struct dm_list *data,
const char *delimiter,
int sort_repstr)
int sort)
{
static const char _error_msg_prefix[] = "_report_field_string_list: ";
unsigned int list_size, i, pos;
struct str_pos_len *arr = NULL;
static const char _string_list_grow_object_failed_msg[] = "dm_report_field_string_list: dm_pool_grow_object_failed";
struct str_list_sort_value *sort_value = NULL;
unsigned int list_size, pos, i;
struct str_list_sort_item *arr = NULL;
struct dm_str_list *sl;
size_t delimiter_len, repstr_str_len, repstr_size;
char *repstr = NULL;
struct pos_len *repstr_extra;
struct str_list_sort_value *sortval = NULL;
size_t delimiter_len, len;
void *object;
int r = 0;
/*
* The 'field->report_string' has 2 parts:
*
* - string representing the whole string list
* (terminated by '\0' at its end as usual)
*
* - extra info beyond the end of the string representing
* position and length of each list item within the
* field->report_string (array of 'struct pos_len')
*
* We can use the extra info to unambiguously identify list items,
* the delimiter is not enough here as it's not assured it won't appear
* in list item itself. We will make use of this extra info in case
* we need to apply further formatting to the list in dm_report_output
* where the pure field->report_string is not enough for printout.
*
*
* The 'field->sort_value' contains a value of type 'struct
* str_list_sort_value' ('sortval'). This one has a pointer to the
* 'field->report_string' string ('sortval->value') and info
* about position and length of each list item within the string
* (array of 'struct pos_len').
*
*
* The 'field->report_string' is either in sorted or unsorted form,
* depending on 'sort_repstr' arg.
*
* The 'field->sort_value.items' is always in sorted form because
* we need that for effective sorting and selection.
*
* If 'field->report_string' is sorted, then field->report_string
* and field->sort_value.items share the same array of
* 'struct pos_len' (because they're both sorted the same way),
* otherwise, each one has its own array.
*
* The very first item in the array of 'struct pos_len' is always
* a pair denoting '[list_size,strlen(field->report_string)]'. The
* rest of items denote start and lenght of each item in the list.
*
*
* For example, if we have a list with "abc", "xy", "defgh"
* as input and delimiter is ",", we end up with either:
*
* A) if we don't want the report string sorted ('sort_repstr == 0'):
*
* - field->report_string = repstr
*
* repstr repstr_extra
* | |
* V V
* abc,xy,defgh\0{[3,12],[0,3],[4,2],[7,5]}
* |____________||________________________|
* string array of struct pos_len
* |____||________________|
* #items items
*
* - field->sort_value = sortval
*
* sortval->value = repstr
* sortval->items = {[3,12],[0,3],[7,5],[4,2]}
* (that is 'abc,defgh,xy')
*
*
* B) if we want the report string sorted ('sort_repstr == 1'):
*
* - field->report_string = repstr
*
* repstr repstr_extra
* | |
* V V
* abc,defgh,xy\0{[3,12],[0,3],[4,5],[10,2]}
* |____________||________________________|
* string array of struct pos_len
* |____||________________|
* #items items
*
* - field->sort_value = sortval
*
* sortval->value = repstr
* sortval->items = repstr_extra
* (that is 'abc,defgh,xy')
*/
if (!delimiter)
delimiter = FIELD_STRING_LIST_DEFAULT_DELIMITER;
delimiter_len = strlen(delimiter);
list_size = dm_list_size(data);
if (!(sortval = dm_pool_alloc(rh->mem, sizeof(struct str_list_sort_value)))) {
log_error("%s failed to allocate sort value structure", _error_msg_prefix);
goto out;
if (!(sort_value = dm_pool_zalloc(rh->mem, sizeof(struct str_list_sort_value)))) {
log_error("dm_report_field_string_list: dm_pool_zalloc failed for sort_value");
return 0;
}
list_size = dm_list_size(data);
/*
* Sort value stores the pointer to the report_string and then
* position and length for each list element withing the report_string.
* The first element stores number of elements in 'len' (therefore
* list_size + 1 is used below for the extra element).
* For example, with this input:
* sort = 0; (we don't want to report sorted)
* report_string = "abc,xy,defgh"; (this is reported)
*
* ...we end up with:
* sort_value->value = report_string; (we'll use the original report_string for indices)
* sort_value->items[0] = {0,3}; (we have 3 items)
* sort_value->items[1] = {0,3}; ("abc")
* sort_value->items[2] = {7,5}; ("defgh")
* sort_value->items[3] = {4,2}; ("xy")
*
* The items alone are always sorted while in report_string they can be
* sorted or not (based on "sort" arg) - it depends on how we prefer to
* display the list. Having items sorted internally helps with searching
* through them.
*/
if (!(sort_value->items = dm_pool_zalloc(rh->mem, (list_size + 1) * sizeof(struct str_list_sort_value_item)))) {
log_error("dm_report_fiel_string_list: dm_pool_zalloc failed for sort value items");
goto out;
}
sort_value->items[0].len = list_size;
/* zero items */
if (list_size == 0) {
field->report_string = sortval->value = "";
sortval->items = NULL;
field->sort_value = sortval;
if (!list_size) {
sort_value->value = field->report_string = "";
field->sort_value = sort_value;
return 1;
}
/* one item */
if (list_size == 1) {
sl = (struct dm_str_list *) dm_list_first(data);
repstr_str_len = strlen(sl->str);
repstr_size = repstr_str_len + 1 + (2 * sizeof(struct pos_len));
if (!(repstr = dm_pool_alloc(rh->mem, repstr_size))) {
log_error("%s failed to allocate report string structure", _error_msg_prefix);
if (!sl ||
!(sort_value->value = field->report_string = dm_pool_strdup(rh->mem, sl->str))) {
log_error("dm_report_field_string_list: dm_pool_strdup failed");
goto out;
}
repstr_extra = (struct pos_len *) (repstr + repstr_str_len + 1);
memcpy(repstr, sl->str, repstr_str_len + 1);
memcpy(repstr_extra, &((struct pos_len) {.pos = 1, .len = repstr_str_len}), sizeof(struct pos_len));
memcpy(repstr_extra + 1, &((struct pos_len) {.pos = 0, .len = repstr_str_len}), sizeof(struct pos_len));
sortval->value = field->report_string = repstr;
sortval->items = repstr_extra;
field->sort_value = sortval;
sort_value->items[1].pos = 0;
sort_value->items[1].len = strlen(sl->str);
field->sort_value = sort_value;
return 1;
}
/* more than one item - allocate temporary array for string list items for further processing */
if (!(arr = malloc(list_size * sizeof(struct str_pos_len)))) {
log_error("%s failed to allocate temporary array for processing", _error_msg_prefix);
/* more than one item - sort the list */
if (!(arr = malloc(sizeof(struct str_list_sort_item) * list_size))) {
log_error("dm_report_field_string_list: malloc failed");
goto out;
}
i = 0;
repstr_size = 0;
if (!(dm_pool_begin_object(rh->mem, 256))) {
log_error(_string_list_grow_object_failed_msg);
goto out;
}
if (!delimiter)
delimiter = ",";
delimiter_len = strlen(delimiter);
i = pos = 0;
dm_list_iterate_items(sl, data) {
arr[i].str = sl->str;
repstr_size += (arr[i].item.len = strlen(sl->str));
if (!sort) {
/* sorted outpud not required - report the list as it is */
len = strlen(sl->str);
if (!dm_pool_grow_object(rh->mem, arr[i].str, len) ||
(i+1 != list_size && !dm_pool_grow_object(rh->mem, delimiter, delimiter_len))) {
log_error(_string_list_grow_object_failed_msg);
goto out;
}
arr[i].item.pos = pos;
arr[i].item.len = len;
pos = i+1 == list_size ? pos+len : pos+len+delimiter_len;
}
i++;
}
/*
* At this point, repstr_size contains sum of lengths of all string list items.
* Now, add these to the repstr_size:
*
* --> sum of character count used by all delimiters: + ((list_size - 1) * delimiter_len)
*
* --> '\0' used at the end of the string list: + 1
*
* --> sum of structures used to keep info about pos and length of each string list item:
* [0, <list_size>] [<pos1>,<size1>] [<pos2>,<size2>] ...
* That is: + ((list_size + 1) * sizeof(struct pos_len))
*/
repstr_size += ((list_size - 1) * delimiter_len);
repstr_str_len = repstr_size;
repstr_size += 1 + ((list_size + 1) * sizeof(struct pos_len));
qsort(arr, i, sizeof(struct str_list_sort_item), _str_list_sort_item_cmp);
if (sort_repstr)
qsort(arr, list_size, sizeof(struct str_pos_len), _str_sort_cmp);
for (i = 0, pos = 0; i < list_size; i++) {
if (sort) {
/* sorted output required - report the list as sorted */
len = strlen(arr[i].str);
if (!dm_pool_grow_object(rh->mem, arr[i].str, len) ||
(i+1 != list_size && !dm_pool_grow_object(rh->mem, delimiter, delimiter_len))) {
log_error(_string_list_grow_object_failed_msg);
goto out;
}
/*
* Save position and length of the string
* element in report_string for sort_value.
* Use i+1 here since items[0] stores list size!!!
*/
sort_value->items[i+1].pos = pos;
sort_value->items[i+1].len = len;
pos = i+1 == list_size ? pos+len : pos+len+delimiter_len;
} else {
sort_value->items[i+1].pos = arr[i].item.pos;
sort_value->items[i+1].len = arr[i].item.len;
}
}
if (!(repstr = dm_pool_alloc(rh->mem, repstr_size))) {
log_error("%s failed to allocate report string structure", _error_msg_prefix);
if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
log_error(_string_list_grow_object_failed_msg);
goto out;
}
repstr_extra = (struct pos_len *) (repstr + repstr_str_len + 1);
memcpy(repstr_extra, &(struct pos_len) {.pos = list_size, .len = repstr_str_len}, sizeof(struct pos_len));
for (i = 0, pos = 0; i < list_size; i++) {
arr[i].item.pos = pos;
memcpy(repstr + pos, arr[i].str, arr[i].item.len);
memcpy(repstr_extra + i + 1, &arr[i].item, sizeof(struct pos_len));
pos += arr[i].item.len;
if (i + 1 < list_size) {
memcpy(repstr + pos, delimiter, delimiter_len);
pos += delimiter_len;
}
}
*(repstr + pos) = '\0';
sortval->value = repstr;
if (sort_repstr)
sortval->items = repstr_extra;
else {
if (!(sortval->items = dm_pool_alloc(rh->mem, (list_size + 1) * sizeof(struct pos_len)))) {
log_error("%s failed to allocate array of items inside sort value structure",
_error_msg_prefix);
goto out;
}
qsort(arr, list_size, sizeof(struct str_pos_len), _str_sort_cmp);
sortval->items[0] = (struct pos_len) {.pos = list_size, .len = repstr_str_len};
for (i = 0; i < list_size; i++)
sortval->items[i+1] = arr[i].item;
}
field->report_string = repstr;
field->sort_value = sortval;
object = dm_pool_end_object(rh->mem);
sort_value->value = object;
field->sort_value = sort_value;
field->report_string = object;
r = 1;
out:
if (!r && sortval)
dm_pool_free(rh->mem, sortval);
if (!r && sort_value)
dm_pool_free(rh->mem, sort_value);
free(arr);
return r;
}
@@ -1762,7 +1688,7 @@ static int _cmp_field_string_list_strict_all(const struct str_list_sort_value *v
struct dm_str_list *sel_item;
unsigned int i = 1;
if (!val->items) {
if (!val->items[0].len) {
if (sel_list_size == 1) {
/* match blank string list with selection defined as blank string only */
sel_item = dm_list_item(dm_list_first(&sel->str_list.list), struct dm_str_list);
@@ -1772,7 +1698,7 @@ static int _cmp_field_string_list_strict_all(const struct str_list_sort_value *v
}
/* if item count differs, it's clear the lists do not match */
if (val->items[0].pos != sel_list_size)
if (val->items[0].len != sel_list_size)
return 0;
/* both lists are sorted so they either match 1:1 or not */
@@ -1795,7 +1721,7 @@ static int _cmp_field_string_list_subset_all(const struct str_list_sort_value *v
unsigned int i, last_found = 1;
int r = 0;
if (!val->items) {
if (!val->items[0].len) {
if (sel_list_size == 1) {
/* match blank string list with selection defined as blank string only */
sel_item = dm_list_item(dm_list_first(&sel->str_list.list), struct dm_str_list);
@@ -1807,7 +1733,7 @@ static int _cmp_field_string_list_subset_all(const struct str_list_sort_value *v
/* check selection is a subset of the value */
dm_list_iterate_items(sel_item, &sel->str_list.list) {
r = 0;
for (i = last_found; i <= val->items[0].pos; i++) {
for (i = last_found; i <= val->items[0].len; i++) {
if ((strlen(sel_item->str) == val->items[i].len) &&
!strncmp(sel_item->str, val->value + val->items[i].pos, val->items[i].len)) {
last_found = i;
@@ -1829,7 +1755,7 @@ static int _cmp_field_string_list_any(const struct str_list_sort_value *val,
unsigned int i;
/* match blank string list with selection that contains blank string */
if (!val->items) {
if (!val->items[0].len) {
dm_list_iterate_items(sel_item, &sel->str_list.list) {
if (!strcmp(sel_item->str, ""))
return 1;
@@ -1842,7 +1768,7 @@ static int _cmp_field_string_list_any(const struct str_list_sort_value *val,
* TODO: Optimize this so we don't need to compare the whole lists' content.
* Make use of the fact that the lists are sorted!
*/
for (i = 1; i <= val->items[0].pos; i++) {
for (i = 1; i <= val->items[0].len; i++) {
if ((strlen(sel_item->str) == val->items[i].len) &&
!strncmp(sel_item->str, val->value + val->items[i].pos, val->items[i].len))
return 1;
@@ -4434,7 +4360,6 @@ static int _sort_rows(struct dm_report *rh)
#define JSON_ARRAY_START "["
#define JSON_ARRAY_END "]"
#define JSON_ESCAPE_CHAR "\\"
#define JSON_NULL "null"
#define UNABLE_TO_EXTEND_OUTPUT_LINE_MSG "dm_report: Unable to extend output line"
@@ -4444,42 +4369,38 @@ static int _is_basic_report(struct dm_report *rh)
(rh->group_item->group->type == DM_REPORT_GROUP_BASIC);
}
static int _is_json_std_report(struct dm_report *rh)
{
return rh->group_item &&
rh->group_item->group->type == DM_REPORT_GROUP_JSON_STD;
}
static int _is_json_report(struct dm_report *rh)
{
return rh->group_item &&
(rh->group_item->group->type == DM_REPORT_GROUP_JSON ||
rh->group_item->group->type == DM_REPORT_GROUP_JSON_STD);
(rh->group_item->group->type == DM_REPORT_GROUP_JSON);
}
static int _is_pure_numeric_field(struct dm_report_field *field)
{
return field->props->flags & (DM_REPORT_FIELD_TYPE_NUMBER | DM_REPORT_FIELD_TYPE_PERCENT);
}
static const char *_get_field_id(struct dm_report *rh, struct dm_report_field *field)
/*
* Produce report output
*/
static int _output_field(struct dm_report *rh, struct dm_report_field *field)
{
const struct dm_report_field_type *fields = field->props->implicit ? _implicit_report_fields
: rh->fields;
return fields[field->props->field_num].id;
}
static int _output_field_basic_fmt(struct dm_report *rh, struct dm_report_field *field)
{
char *field_id;
int32_t width;
uint32_t align;
const char *repstr;
const char *p1_repstr, *p2_repstr;
char *buf = NULL;
size_t buf_size = 0;
if (rh->flags & DM_REPORT_OUTPUT_FIELD_NAME_PREFIX) {
if (!(field_id = strdup(_get_field_id(rh, field)))) {
if (_is_json_report(rh)) {
if (!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1) ||
!dm_pool_grow_object(rh->mem, fields[field->props->field_num].id, 0) ||
!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1) ||
!dm_pool_grow_object(rh->mem, JSON_PAIR, 1) ||
!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1)) {
log_error("dm_report: Unable to extend output line");
return 0;
}
} else if (rh->flags & DM_REPORT_OUTPUT_FIELD_NAME_PREFIX) {
if (!(field_id = strdup(fields[field->props->field_num].id))) {
log_error("dm_report: Failed to copy field name");
return 0;
}
@@ -4510,14 +4431,43 @@ static int _output_field_basic_fmt(struct dm_report *rh, struct dm_report_field
}
}
if (rh->flags & DM_REPORT_OUTPUT_ALIGNED) {
repstr = field->report_string;
width = field->props->width;
if (!(rh->flags & DM_REPORT_OUTPUT_ALIGNED)) {
if (_is_json_report(rh)) {
/* Escape any JSON_QUOTE that may appear in reported string. */
p1_repstr = repstr;
while ((p2_repstr = strstr(p1_repstr, JSON_QUOTE))) {
if (p2_repstr > p1_repstr) {
if (!dm_pool_grow_object(rh->mem, p1_repstr, p2_repstr - p1_repstr)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
}
if (!dm_pool_grow_object(rh->mem, JSON_ESCAPE_CHAR, 1) ||
!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
p1_repstr = p2_repstr + 1;
}
if (!dm_pool_grow_object(rh->mem, p1_repstr, 0)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
} else {
if (!dm_pool_grow_object(rh->mem, repstr, 0)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
}
} else {
if (!(align = field->props->flags & DM_REPORT_FIELD_ALIGN_MASK))
align = ((field->props->flags & DM_REPORT_FIELD_TYPE_NUMBER) ||
(field->props->flags & DM_REPORT_FIELD_TYPE_SIZE)) ?
(field->props->flags & DM_REPORT_FIELD_TYPE_SIZE)) ?
DM_REPORT_FIELD_ALIGN_RIGHT : DM_REPORT_FIELD_ALIGN_LEFT;
width = field->props->width;
/* Including trailing '\0'! */
buf_size = width + 1;
if (!(buf = malloc(buf_size))) {
@@ -4527,7 +4477,7 @@ static int _output_field_basic_fmt(struct dm_report *rh, struct dm_report_field
if (align & DM_REPORT_FIELD_ALIGN_LEFT) {
if (dm_snprintf(buf, buf_size, "%-*.*s",
width, width, field->report_string) < 0) {
width, width, repstr) < 0) {
log_error("dm_report: left-aligned snprintf() failed");
goto bad;
}
@@ -4537,7 +4487,7 @@ static int _output_field_basic_fmt(struct dm_report *rh, struct dm_report_field
}
} else if (align & DM_REPORT_FIELD_ALIGN_RIGHT) {
if (dm_snprintf(buf, buf_size, "%*.*s",
width, width, field->report_string) < 0) {
width, width, repstr) < 0) {
log_error("dm_report: right-aligned snprintf() failed");
goto bad;
}
@@ -4546,11 +4496,6 @@ static int _output_field_basic_fmt(struct dm_report *rh, struct dm_report_field
goto bad;
}
}
} else {
if (!dm_pool_grow_object(rh->mem, field->report_string, 0)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
}
if (rh->flags & DM_REPORT_OUTPUT_FIELD_NAME_PREFIX) {
@@ -4560,164 +4505,21 @@ static int _output_field_basic_fmt(struct dm_report *rh, struct dm_report_field
goto bad;
}
}
} else if (_is_json_report(rh)) {
if (!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
goto bad;
}
}
free(buf);
return 1;
bad:
free(buf);
return 0;
}
static int _safe_repstr_output(struct dm_report *rh, const char *repstr, size_t len)
{
const char *p_repstr;
const char *repstr_end = len ? repstr + len : repstr + strlen(repstr);
/* Escape any JSON_QUOTE that may appear in reported string. */
while (1) {
if (!(p_repstr = memchr(repstr, JSON_QUOTE[0], repstr_end - repstr)))
break;
if (p_repstr > repstr) {
if (!dm_pool_grow_object(rh->mem, repstr, p_repstr - repstr)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
}
if (!dm_pool_grow_object(rh->mem, JSON_ESCAPE_CHAR, 1) ||
!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
repstr = p_repstr + 1;
}
if (!dm_pool_grow_object(rh->mem, repstr, repstr_end - repstr)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
return 1;
}
static int _output_field_json_fmt(struct dm_report *rh, struct dm_report_field *field)
{
const char *repstr;
size_t list_size, i;
struct pos_len *pos_len;
if (!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1) ||
!dm_pool_grow_object(rh->mem, _get_field_id(rh, field), 0) ||
!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1) ||
!dm_pool_grow_object(rh->mem, JSON_PAIR, 1)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
if (field->props->flags & DM_REPORT_FIELD_TYPE_STRING_LIST) {
if (!_is_json_std_report(rh)) {
/* string list in JSON - report whole list as simple string in quotes */
if (!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
if (!_safe_repstr_output(rh, field->report_string, 0))
return_0;
if (!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
return 1;
}
/* string list in JSON_STD - report list as proper JSON array */
if (!dm_pool_grow_object(rh->mem, JSON_ARRAY_START, 1)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
if (*field->report_string != 0) {
pos_len = (struct pos_len *) (field->report_string +
((struct str_list_sort_value *) field->sort_value)->items[0].len + 1);
list_size = pos_len->pos;
} else
list_size = 0;
for (i = 0; i < list_size; i++) {
pos_len++;
if (i != 0) {
if (!dm_pool_grow_object(rh->mem, JSON_SEPARATOR, 1)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
}
if (!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
if (!_safe_repstr_output(rh, field->report_string + pos_len->pos, pos_len->len))
return_0;
if (!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
}
if (!dm_pool_grow_object(rh->mem, JSON_ARRAY_END, 1)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
return 1;
}
/* all other types than string list - handle both JSON and JSON_STD */
if (!(_is_json_std_report(rh) && _is_pure_numeric_field(field))) {
if (!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
}
if (_is_json_std_report(rh) && _is_pure_numeric_field(field) && !*field->report_string)
repstr = JSON_NULL;
else
repstr = field->report_string;
if (!_safe_repstr_output(rh, repstr, 0))
return_0;
if (!(_is_json_std_report(rh) && _is_pure_numeric_field(field))) {
if (!dm_pool_grow_object(rh->mem, JSON_QUOTE, 1)) {
log_error(UNABLE_TO_EXTEND_OUTPUT_LINE_MSG);
return 0;
}
}
return 1;
}
/*
* Produce report output
*/
static int _output_field(struct dm_report *rh, struct dm_report_field *field)
{
return _is_json_report(rh) ? _output_field_json_fmt(rh, field)
: _output_field_basic_fmt(rh, field);
}
static void _destroy_rows(struct dm_report *rh)
{
/*
@@ -5181,7 +4983,6 @@ int dm_report_group_push(struct dm_report_group *group, struct dm_report *report
goto_bad;
break;
case DM_REPORT_GROUP_JSON:
case DM_REPORT_GROUP_JSON_STD:
if (!_report_group_push_json(item, data))
goto_bad;
break;
@@ -5245,7 +5046,6 @@ int dm_report_group_pop(struct dm_report_group *group)
return_0;
break;
case DM_REPORT_GROUP_JSON:
case DM_REPORT_GROUP_JSON_STD:
if (!_report_group_pop_json(item))
return_0;
break;
@@ -5282,7 +5082,7 @@ int dm_report_group_output_and_pop_all(struct dm_report_group *group)
return_0;
}
if (group->type == DM_REPORT_GROUP_JSON || group->type == DM_REPORT_GROUP_JSON_STD) {
if (group->type == DM_REPORT_GROUP_JSON) {
_json_output_start(group);
log_print(JSON_OBJECT_END);
group->indent -= JSON_INDENT_UNIT;

View File

@@ -77,10 +77,8 @@ enum dm_vdo_write_policy {
struct dm_vdo_target_params {
uint32_t minimum_io_size; // in sectors
uint32_t block_map_cache_size_mb;
union {
uint32_t block_map_era_length; // format period
uint32_t block_map_period; // supported alias
};
uint32_t block_map_era_length; // format period
uint32_t check_point_frequency;
uint32_t index_memory_size_mb; // format
@@ -108,8 +106,6 @@ struct dm_vdo_target_params {
bool dm_vdo_validate_target_params(const struct dm_vdo_target_params *vtp,
uint64_t vdo_size);
bool dm_vdo_parse_logical_size(const char *vdo_path, uint64_t *logical_blocks);
//----------------------------------------------------------------
#endif

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018 Red Hat, Inc. All rights reserved.
*
* This file is part of the device-mapper userspace tools.
*
@@ -15,52 +15,49 @@
#ifndef DEVICE_MAPPER_VDO_LIMITS_H
#define DEVICE_MAPPER_VDO_LIMITS_H
#ifndef SECTOR_SHIFT
#define SECTOR_SHIFT 9L
#endif
#define DM_VDO_BLOCK_SIZE UINT64_C(8) // 4KiB in sectors
#define DM_VDO_BLOCK_SIZE_KB (DM_VDO_BLOCK_SIZE << SECTOR_SHIFT)
#define DM_VDO_BLOCK_MAP_CACHE_SIZE_MINIMUM_MB (128) // 128MiB
#define DM_VDO_BLOCK_MAP_CACHE_SIZE_MAXIMUM_MB (16 * 1024 * 1024 - 1) // 16TiB - 1
#define DM_VDO_BLOCK_MAP_CACHE_SIZE_MINIMUM_PER_LOGICAL_THREAD (4096 * DM_VDO_BLOCK_SIZE_KB)
#define DM_VDO_BLOCK_MAP_ERA_LENGTH_MINIMUM 1
#define DM_VDO_BLOCK_MAP_ERA_LENGTH_MAXIMUM 16380
#define DM_VDO_BLOCK_MAP_ERA_LENGTH_MINIMUM (1)
#define DM_VDO_BLOCK_MAP_ERA_LENGTH_MAXIMUM (16380)
#define DM_VDO_INDEX_MEMORY_SIZE_MINIMUM_MB 256 // 0.25 GiB
#define DM_VDO_INDEX_MEMORY_SIZE_MINIMUM_MB (256) // 0.25 GiB
#define DM_VDO_INDEX_MEMORY_SIZE_MAXIMUM_MB (1024 * 1024 * 1024) // 1TiB
#define DM_VDO_SLAB_SIZE_MINIMUM_MB 128 // 128MiB
//#define DM_VDO_READ_CACHE_SIZE_MINIMUM_MB (0)
#define DM_VDO_READ_CACHE_SIZE_MAXIMUM_MB (16 * 1024 * 1024 - 1) // 16TiB - 1
#define DM_VDO_SLAB_SIZE_MINIMUM_MB (128) // 128MiB
#define DM_VDO_SLAB_SIZE_MAXIMUM_MB (32 * 1024) // 32GiB
#define DM_VDO_SLABS_MAXIMUM 8192
#define DM_VDO_LOGICAL_SIZE_MAXIMUM (UINT64_C(4) * 1024 * 1024 * 1024 * 1024 * 1024 >> SECTOR_SHIFT) // 4PiB
#define DM_VDO_PHYSICAL_SIZE_MAXIMUM (UINT64_C(64) * DM_VDO_BLOCK_SIZE_KB * 1024 * 1024 * 1024 >> SECTOR_SHIFT) // 256TiB
//#define DM_VDO_LOGICAL_SIZE_MINIMUM_MB (0)
#define DM_VDO_LOGICAL_SIZE_MAXIMUM_MB (UINT64_C(4) * 1024 * 1024 * 1024) // 4PiB
#define DM_VDO_ACK_THREADS_MINIMUM 0
#define DM_VDO_ACK_THREADS_MAXIMUM 100
//#define DM_VDO_ACK_THREADS_MINIMUM (0)
#define DM_VDO_ACK_THREADS_MAXIMUM (100)
#define DM_VDO_BIO_THREADS_MINIMUM 1
#define DM_VDO_BIO_THREADS_MAXIMUM 100
#define DM_VDO_BIO_THREADS_MINIMUM (1)
#define DM_VDO_BIO_THREADS_MAXIMUM (100)
#define DM_VDO_BIO_ROTATION_MINIMUM 1
#define DM_VDO_BIO_ROTATION_MAXIMUM 1024
#define DM_VDO_BIO_ROTATION_MINIMUM (1)
#define DM_VDO_BIO_ROTATION_MAXIMUM (1024)
#define DM_VDO_CPU_THREADS_MINIMUM 1
#define DM_VDO_CPU_THREADS_MAXIMUM 100
#define DM_VDO_CPU_THREADS_MINIMUM (1)
#define DM_VDO_CPU_THREADS_MAXIMUM (100)
#define DM_VDO_HASH_ZONE_THREADS_MINIMUM 0
#define DM_VDO_HASH_ZONE_THREADS_MAXIMUM 100
//#define DM_VDO_HASH_ZONE_THREADS_MINIMUM (0)
#define DM_VDO_HASH_ZONE_THREADS_MAXIMUM (100)
#define DM_VDO_LOGICAL_THREADS_MINIMUM 0
#define DM_VDO_LOGICAL_THREADS_MAXIMUM 60
//#define DM_VDO_LOGICAL_THREADS_MINIMUM (0)
#define DM_VDO_LOGICAL_THREADS_MAXIMUM (100)
#define DM_VDO_PHYSICAL_THREADS_MINIMUM 0
#define DM_VDO_PHYSICAL_THREADS_MAXIMUM 16
//#define DM_VDO_PHYSICAL_THREADS_MINIMUM (0)
#define DM_VDO_PHYSICAL_THREADS_MAXIMUM (16)
#define DM_VDO_MAX_DISCARD_MINIMUM 1
#define DM_VDO_MAX_DISCARD_MAXIMUM (UINT32_MAX / (uint32_t)(DM_VDO_BLOCK_SIZE_KB))
#define DM_VDO_MAX_DISCARD_MINIMUM (1)
#define DM_VDO_MAX_DISCARD_MAXIMUM (UINT32_MAX / 4096)
#endif // DEVICE_MAPPER_VDO_LIMITS_H

View File

@@ -1,279 +0,0 @@
/*
* Copyright (C) 2022 Red Hat, Inc. All rights reserved.
*
* This file is part of the device-mapper userspace tools.
*
* 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
*/
/*
* Based on VDO sources: https://github.com/dm-vdo/vdo
*
* Simplified parser of VDO superblock to obtain basic VDO parameteers
*
* TODO: maybe switch to some library in the future
*/
//#define _GNU_SOURCE 1
//#define _LARGEFILE64_SOURCE 1
#include "device_mapper/misc/dmlib.h"
#include "target.h"
#include "lib/mm/xlate.h"
//#include "linux/byteorder/big_endian.h"
//#include "linux/byteorder/little_endian.h"
//#define le32_to_cpu __le32_to_cpu
//#define le64_to_cpu __le64_to_cpu
#include <errno.h>
#include <fcntl.h>
#include <linux/fs.h> /* For block ioctl definitions */
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <unistd.h>
typedef unsigned char uuid_t[16];
#define __packed __attribute__((packed))
static const char _MAGIC_NUMBER[] = "dmvdo001";
#define MAGIC_NUMBER_SIZE (sizeof(_MAGIC_NUMBER) - 1)
struct vdo_version_number {
uint32_t major_version;
uint32_t minor_version;
} __packed;
/*
* The registry of component ids for use in headers
*/
enum {
SUPER_BLOCK = 0,
FIXED_LAYOUT = 1,
RECOVERY_JOURNAL = 2,
SLAB_DEPOT = 3,
BLOCK_MAP = 4,
GEOMETRY_BLOCK = 5,
}; /* ComponentID */
struct vdo_header {
uint32_t id; /* The component this is a header for */
struct vdo_version_number version; /* The version of the data format */
size_t size; /* The size of the data following this header */
} __packed;
struct vdo_geometry_block {
char magic_number[MAGIC_NUMBER_SIZE];
struct vdo_header header;
uint32_t checksum;
} __packed;
struct vdo_config {
uint64_t logical_blocks; /* number of logical blocks */
uint64_t physical_blocks; /* number of physical blocks */
uint64_t slab_size; /* number of blocks in a slab */
uint64_t recovery_journal_size; /* number of recovery journal blocks */
uint64_t slab_journal_blocks; /* number of slab journal blocks */
} __packed;
struct vdo_component_41_0 {
uint32_t state;
uint64_t complete_recoveries;
uint64_t read_only_recoveries;
struct vdo_config config; /* packed */
uint64_t nonce;
} __packed;
enum vdo_volume_region_id {
VDO_INDEX_REGION = 0,
VDO_DATA_REGION = 1,
VDO_VOLUME_REGION_COUNT,
};
struct vdo_volume_region {
/* The ID of the region */
enum vdo_volume_region_id id;
/*
* The absolute starting offset on the device. The region continues
* until the next region begins.
*/
uint64_t start_block;
} __packed;
struct vdo_index_config {
uint32_t mem;
uint32_t unused;
uint8_t sparse;
} __packed;
struct vdo_volume_geometry {
uint32_t release_version;
uint64_t nonce;
uuid_t uuid;
uint64_t bio_offset;
struct vdo_volume_region regions[VDO_VOLUME_REGION_COUNT];
struct vdo_index_config index_config;
} __packed;
/* Decoding mostly only some used stucture members */
static void _vdo_decode_version(struct vdo_version_number *v)
{
v->major_version = le32_to_cpu(v->major_version);
v->minor_version = le32_to_cpu(v->minor_version);
}
static void _vdo_decode_header(struct vdo_header *h)
{
h->id = le32_to_cpu(h->id);
_vdo_decode_version(&h->version);
h->size = le64_to_cpu(h->size);
}
static void _vdo_decode_geometry_region(struct vdo_volume_region *vr)
{
vr->id = le32_to_cpu(vr->id);
vr->start_block = le32_to_cpu(vr->start_block);
}
static void _vdo_decode_volume_geometry(struct vdo_volume_geometry *vg)
{
vg->release_version = le64_to_cpu(vg->release_version);
vg->nonce = le64_to_cpu(vg->nonce);
_vdo_decode_geometry_region(&vg->regions[VDO_DATA_REGION]);
}
static void _vdo_decode_config(struct vdo_config *vc)
{
vc->logical_blocks = le64_to_cpu(vc->logical_blocks);
vc->physical_blocks = le64_to_cpu(vc->physical_blocks);
vc->slab_size = le64_to_cpu(vc->slab_size);
vc->recovery_journal_size = le64_to_cpu(vc->recovery_journal_size);
vc->slab_journal_blocks = le64_to_cpu(vc->slab_journal_blocks);
}
static void _vdo_decode_pvc(struct vdo_component_41_0 *pvc)
{
_vdo_decode_config(&pvc->config);
pvc->nonce = le64_to_cpu(pvc->nonce);
}
bool dm_vdo_parse_logical_size(const char *vdo_path, uint64_t *logical_blocks)
{
char buffer[4096];
int fh, n;
bool r = false;
off_t l;
struct stat st;
uint64_t size;
uint64_t regpos;
struct vdo_header h;
struct vdo_version_number vn;
struct vdo_volume_geometry vg;
struct vdo_component_41_0 pvc;
*logical_blocks = 0;
if ((fh = open(vdo_path, O_RDONLY)) == -1) {
log_sys_debug("Failed to open VDO backend %s.", vdo_path);
return false;
}
if (ioctl(fh, BLKGETSIZE64, &size) == -1) {
if (errno != ENOTTY) {
log_sys_debug("ioctl", vdo_path);
goto err;
}
/* lets retry for file sizes */
if (fstat(fh, &st) < 0) {
log_sys_debug("fstat", vdo_path);
goto err;
}
size = st.st_size;
}
if ((n = read(fh, buffer, sizeof(buffer))) < 0) {
log_sys_debug("read", vdo_path);
goto err;
}
if (strncmp(buffer, _MAGIC_NUMBER, MAGIC_NUMBER_SIZE)) {
log_debug_activation("Found mismatching VDO magic header in %s.", vdo_path);
goto err;
}
memcpy(&h, buffer + MAGIC_NUMBER_SIZE, sizeof(h));
_vdo_decode_header(&h);
if (h.version.major_version != 5) {
log_debug_activation("Unsupported VDO version %u.%u.", h.version.major_version, h.version.minor_version);
goto err;
}
memcpy(&vg, buffer + MAGIC_NUMBER_SIZE + sizeof(h), sizeof(vg));
_vdo_decode_volume_geometry(&vg);
regpos = vg.regions[VDO_DATA_REGION].start_block * 4096;
if ((regpos + sizeof(buffer)) > size) {
log_debug_activation("File/Device is shorter and can't provide requested VDO volume region at " FMTu64 " > " FMTu64 ".", regpos, size);
goto err;
}
if ((l = lseek(fh, regpos, SEEK_SET)) < 0) {
log_sys_debug("lseek", vdo_path);
goto err;
}
if ((n = read(fh, buffer, sizeof(buffer))) < 0) {
log_sys_debug("read", vdo_path);
goto err;
}
memcpy(&vn, buffer + sizeof(struct vdo_geometry_block), sizeof(vn));
_vdo_decode_version(&vn);
if (vn.major_version > 41) {
log_debug_activation("Unknown VDO component version %u.", vn.major_version); // should be 41!
goto err;
}
memcpy(&pvc, buffer + sizeof(struct vdo_geometry_block) + sizeof(vn), sizeof(pvc));
_vdo_decode_pvc(&pvc);
if (pvc.nonce != vg.nonce) {
log_debug_activation("VDO metadata has mismatching VDO nonces " FMTu64 " != " FMTu64 ".", pvc.nonce, vg.nonce);
goto err;
}
#if 0
log_debug_activation("LogBlocks " FMTu64 ".", pvc.config.logical_blocks);
log_debug_activation("PhyBlocks " FMTu64 ".", pvc.config.physical_blocks);
log_debug_activation("SlabSize " FMTu64 ".", pvc.config.slab_size);
log_debug_activation("RecJourSize " FMTu64 ".", pvc.config.recovery_journal_size);
log_debug_activation("SlabJouSize " FMTu64 ".", pvc.config.slab_journal_blocks);
#endif
*logical_blocks = pvc.config.logical_blocks;
r = true;
err:
(void) close(fh);
return r;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2022 Red Hat, Inc. All rights reserved.
* Copyright (C) 2018 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -18,117 +18,82 @@
#include "vdo_limits.h"
#include "target.h"
/* validate vdo target parameters and 'vdo_size' in sectors */
bool dm_vdo_validate_target_params(const struct dm_vdo_target_params *vtp,
uint64_t vdo_size)
{
bool valid = true;
/* 512 or 4096 bytes only ATM */
if ((vtp->minimum_io_size != (512 >> SECTOR_SHIFT)) &&
(vtp->minimum_io_size != (4096 >> SECTOR_SHIFT))) {
log_error("VDO minimum io size %u is unsupported [512, 4096].",
if ((vtp->minimum_io_size != 1) &&
(vtp->minimum_io_size != 8)) {
log_error("VDO minimum io size %u is unsupported.",
vtp->minimum_io_size);
valid = false;
}
if ((vtp->block_map_cache_size_mb < DM_VDO_BLOCK_MAP_CACHE_SIZE_MINIMUM_MB) ||
(vtp->block_map_cache_size_mb > DM_VDO_BLOCK_MAP_CACHE_SIZE_MAXIMUM_MB)) {
log_error("VDO block map cache size %u MiB is out of range [%u..%u].",
vtp->block_map_cache_size_mb,
DM_VDO_BLOCK_MAP_CACHE_SIZE_MINIMUM_MB,
DM_VDO_BLOCK_MAP_CACHE_SIZE_MAXIMUM_MB);
valid = false;
}
if ((vtp->block_map_era_length < DM_VDO_BLOCK_MAP_ERA_LENGTH_MINIMUM) ||
(vtp->block_map_era_length > DM_VDO_BLOCK_MAP_ERA_LENGTH_MAXIMUM)) {
log_error("VDO block map era length %u is out of range [%u..%u].",
vtp->block_map_era_length,
DM_VDO_BLOCK_MAP_ERA_LENGTH_MINIMUM,
DM_VDO_BLOCK_MAP_ERA_LENGTH_MAXIMUM);
log_error("VDO block map cache size %u out of range.",
vtp->block_map_cache_size_mb);
valid = false;
}
if ((vtp->index_memory_size_mb < DM_VDO_INDEX_MEMORY_SIZE_MINIMUM_MB) ||
(vtp->index_memory_size_mb > DM_VDO_INDEX_MEMORY_SIZE_MAXIMUM_MB)) {
log_error("VDO index memory size %u MiB is out of range [%u..%u].",
vtp->index_memory_size_mb,
DM_VDO_INDEX_MEMORY_SIZE_MINIMUM_MB,
DM_VDO_INDEX_MEMORY_SIZE_MAXIMUM_MB);
log_error("VDO index memory size %u out of range.",
vtp->index_memory_size_mb);
valid = false;
}
if ((vtp->slab_size_mb < DM_VDO_SLAB_SIZE_MINIMUM_MB) ||
(vtp->slab_size_mb > DM_VDO_SLAB_SIZE_MAXIMUM_MB)) {
log_error("VDO slab size %u MiB is out of range [%u..%u].",
vtp->slab_size_mb,
DM_VDO_SLAB_SIZE_MINIMUM_MB,
DM_VDO_SLAB_SIZE_MAXIMUM_MB);
log_error("VDO slab size %u out of range.",
vtp->slab_size_mb);
valid = false;
}
if ((vtp->max_discard < DM_VDO_MAX_DISCARD_MINIMUM) ||
(vtp->max_discard > DM_VDO_MAX_DISCARD_MAXIMUM)) {
log_error("VDO max discard %u is out of range [%u..%u].",
vtp->max_discard,
DM_VDO_MAX_DISCARD_MINIMUM,
DM_VDO_MAX_DISCARD_MAXIMUM);
log_error("VDO max discard %u out of range.",
vtp->max_discard);
valid = false;
}
if (vtp->ack_threads > DM_VDO_ACK_THREADS_MAXIMUM) {
log_error("VDO ack threads %u is out of range [0..%u].",
vtp->ack_threads,
DM_VDO_ACK_THREADS_MAXIMUM);
log_error("VDO ack threads %u out of range.", vtp->ack_threads);
valid = false;
}
if ((vtp->bio_threads < DM_VDO_BIO_THREADS_MINIMUM) ||
(vtp->bio_threads > DM_VDO_BIO_THREADS_MAXIMUM)) {
log_error("VDO bio threads %u is out of range [%u..%u].",
vtp->bio_threads,
DM_VDO_BIO_THREADS_MINIMUM,
DM_VDO_BIO_THREADS_MAXIMUM);
log_error("VDO bio threads %u out of range.", vtp->bio_threads);
valid = false;
}
if ((vtp->bio_rotation < DM_VDO_BIO_ROTATION_MINIMUM) ||
(vtp->bio_rotation > DM_VDO_BIO_ROTATION_MAXIMUM)) {
log_error("VDO bio rotation %u is out of range [%u..%u].",
vtp->bio_rotation,
DM_VDO_BIO_ROTATION_MINIMUM,
DM_VDO_BIO_ROTATION_MAXIMUM);
log_error("VDO bio rotation %u out of range.", vtp->bio_rotation);
valid = false;
}
if ((vtp->cpu_threads < DM_VDO_CPU_THREADS_MINIMUM) ||
(vtp->cpu_threads > DM_VDO_CPU_THREADS_MAXIMUM)) {
log_error("VDO cpu threads %u is out of range [%u..%u].",
vtp->cpu_threads,
DM_VDO_CPU_THREADS_MINIMUM,
DM_VDO_CPU_THREADS_MAXIMUM);
log_error("VDO cpu threads %u out of range.", vtp->cpu_threads);
valid = false;
}
if (vtp->hash_zone_threads > DM_VDO_HASH_ZONE_THREADS_MAXIMUM) {
log_error("VDO hash zone threads %u is out of range [0..%u].",
vtp->hash_zone_threads,
DM_VDO_HASH_ZONE_THREADS_MAXIMUM);
log_error("VDO hash zone threads %u out of range.", vtp->hash_zone_threads);
valid = false;
}
if (vtp->logical_threads > DM_VDO_LOGICAL_THREADS_MAXIMUM) {
log_error("VDO logical threads %u is out of range [0..%u].",
vtp->logical_threads,
DM_VDO_LOGICAL_THREADS_MAXIMUM);
log_error("VDO logical threads %u out of range.", vtp->logical_threads);
valid = false;
}
if (vtp->physical_threads > DM_VDO_PHYSICAL_THREADS_MAXIMUM) {
log_error("VDO physical threads %u is out of range [0..%u].",
vtp->physical_threads,
DM_VDO_PHYSICAL_THREADS_MAXIMUM);
log_error("VDO physical threads %u out of range.", vtp->physical_threads);
valid = false;
}
@@ -155,10 +120,10 @@ bool dm_vdo_validate_target_params(const struct dm_vdo_target_params *vtp,
valid = false;
}
if (vdo_size > DM_VDO_LOGICAL_SIZE_MAXIMUM) {
log_error("VDO logical size is larger than limit " FMTu64 " TiB by " FMTu64 " KiB.",
DM_VDO_LOGICAL_SIZE_MAXIMUM / (UINT64_C(1024) * 1024 * 1024 * 1024 >> SECTOR_SHIFT),
(vdo_size - DM_VDO_LOGICAL_SIZE_MAXIMUM) / 2);
if (vdo_size >= (DM_VDO_LOGICAL_SIZE_MAXIMUM_MB * UINT64_C(1024 * 2))) {
log_error("VDO logical size is by " FMTu64 "KiB bigger then limit " FMTu64 "TiB.",
(vdo_size - (DM_VDO_LOGICAL_SIZE_MAXIMUM_MB * UINT64_C(1024 * 2))) / 2,
DM_VDO_LOGICAL_SIZE_MAXIMUM_MB / UINT64_C(1024) / UINT64_C(1024));
valid = false;
}

View File

@@ -67,7 +67,7 @@ the entries (each hotspot block covers a larger area than a single
cache block).
All this means smq uses ~25bytes per cache block. Still a lot of
memory, but a substantial improvement nonetheless.
memory, but a substantial improvement nontheless.
Level balancing:
mq placed entries in different levels of the multiqueue structures

View File

@@ -35,7 +35,7 @@ Parameters: <cipher> <key> <iv_offset> <device path> \
capi:authenc(hmac(sha256),xts(aes))-random
capi:rfc7539(chacha20,poly1305)-random
The /proc/crypto contains a list of currently loaded crypto modes.
The /proc/crypto contains a list of curently loaded crypto modes.
<key>
Key used for encryption. It is encoded either as a hexadecimal number
@@ -81,7 +81,7 @@ Parameters: <cipher> <key> <iv_offset> <device path> \
<#opt_params>
Number of optional parameters. If there are no optional parameters,
the optional parameters section can be skipped or #opt_params can be zero.
the optional paramaters section can be skipped or #opt_params can be zero.
Otherwise #opt_params is the number of following arguments.
Example of optional parameters section:

View File

@@ -120,7 +120,7 @@ journal_crypt:algorithm(:key) (the key is optional)
"salsa20", "ctr(aes)" or "ecb(arc4)").
The journal contains history of last writes to the block device,
an attacker reading the journal could see the last sector numbers
an attacker reading the journal could see the last sector nubmers
that were written. From the sector numbers, the attacker can infer
the size of files that were written. To protect against this
situation, you can encrypt the journal.

View File

@@ -65,7 +65,7 @@ Construction Parameters
<#opt_params>
Number of optional parameters. If there are no optional parameters,
the optional parameters section can be skipped or #opt_params can be zero.
the optional paramaters section can be skipped or #opt_params can be zero.
Otherwise #opt_params is the number of following arguments.
Example of optional parameters section:

View File

@@ -37,7 +37,7 @@ segment type. The available RAID types are:
"raid6_nr" - RAID6 Rotating parity N with data restart
"raid6_nc" - RAID6 Rotating parity N with data continuation
The exception to 'no shorthand options' will be where the RAID implementations
can displace traditional targets. This is the case with 'mirror' and 'raid1'.
can displace traditional tagets. This is the case with 'mirror' and 'raid1'.
In this case, "mirror_segtype_default" - found under the "global" section in
lvm.conf - can be set to "mirror" or "raid1". The segment type inferred when
the '-m' option is used will be taken from this setting. The default segment
@@ -104,7 +104,7 @@ and 4 devices for RAID 6/10.
lvconvert should work exactly as it does now when dealing with mirrors -
even if(when) we switch to MD RAID1. Of course, there are no plans to
allow the presence of the metadata area to be configurable (e.g. --corelog).
allow the presense of the metadata area to be configurable (e.g. --corelog).
It will be simple enough to detect if the LV being up/down-converted is
new or old-style mirroring.
@@ -120,7 +120,7 @@ RAID4 to RAID5 or RAID5 to RAID6.
Line 02/03/04:
These are familiar options - all of which would now be available as options
for change. (However, it'd be nice if we didn't have regionsize in there.
It's simple on the kernel side, but is just an extra - often unnecessary -
It's simple on the kernel side, but is just an extra - often unecessary -
parameter to many functions in the LVM codebase.)
Line 05:
@@ -375,8 +375,8 @@ the slot. Even the names of the images will be renamed to properly reflect
their index in the array. Unlike the "mirror" segment type, you will never have
an image named "*_rimage_1" occupying the index position 0.
As with adding images, removing images holds off on committing LVM metadata
until all possible changes have been made. This reduces the likelihood of bad
As with adding images, removing images holds off on commiting LVM metadata
until all possible changes have been made. This reduces the likelyhood of bad
intermediate stages being left due to a failure of operation or machine crash.
RAID1 '--splitmirrors', '--trackchanges', and '--merge' operations

View File

@@ -87,7 +87,7 @@ are as follows:
/etc/lvm/lvm.conf. Once this operation is complete, the logical volumes
will be consistent. However, the volume group will still be inconsistent -
due to the refernced-but-missing device/PV - and operations will still be
restricted to the aforementioned actions until either the device is
restricted to the aformentioned actions until either the device is
restored or 'vgreduce --removemissing' is run.
Device Revival (transient failures):
@@ -135,9 +135,9 @@ If a mirror is not 'in-sync', a read failure will produce an I/O error.
This error will propagate all the way up to the applications above the
logical volume (e.g. the file system). No automatic intervention will
take place in this case either. It is up to the user to decide what
can be done/salvaged in this scenario. If the user is confident that the
can be done/salvaged in this senario. If the user is confident that the
images of the mirror are the same (or they are willing to simply attempt
to retrieve whatever data they can), 'lvconvert' can be used to eliminate
to retreive whatever data they can), 'lvconvert' can be used to eliminate
the failed image and proceed.
Mirror resynchronization errors:
@@ -191,11 +191,11 @@ command are set in the LVM configuration file. They are:
3-way mirror fails, the mirror will be converted to a 2-way mirror.
The "allocate" policy takes the further action of trying to replace
the failed image using space that is available in the volume group.
Replacing a failed mirror image will incur the cost of
Replacing a failed mirror image will incure the cost of
resynchronizing - degrading the performance of the mirror. The
default policy for handling an image failure is "remove". This
allows the mirror to still function, but gives the administrator the
choice of when to incur the extra performance costs of replacing
choice of when to incure the extra performance costs of replacing
the failed image.
RAID logical volume device failures are handled differently from the "mirror"

View File

@@ -63,7 +63,7 @@ classical snapshot merge, thin snapshot merge.
The second store is suited only for pvmove --abort operations in-progress. Both
stores are independent and identical LVs (pvmove /dev/sda3 and pvmove --abort /dev/sda3)
can be run concurrently from lvmpolld point of view (on lvm2 side the consistency is
can be run concurently from lvmpolld point of view (on lvm2 side the consistency is
guaranteed by lvm2 locking mechanism).
Locking order

View File

@@ -126,7 +126,7 @@ Usage Examples
followed by 'vgchange -ay vg2'
Option (ii) - localised admin & configuration
Option (ii) - localised admin & configuation
(i.e. each host holds *locally* which classes of volumes to activate)
# Add @database tag to vg1's metadata
vgchange --addtag @database vg1

View File

@@ -35,7 +35,7 @@ VGs from PVs as they appear, and at the same time collect information on what is
already available. A command, pvscan --cache is expected to be used to
implement udev rules. It is relatively easy to make this command print out a
list of VGs (and possibly LVs) that have been made available by adding any
particular device to the set of visible devices. In other words, udev says "hey,
particular device to the set of visible devices. In othe words, udev says "hey,
/dev/sdb just appeared", calls pvscan --cache, which talks to lvmetad, which
says "cool, that makes vg0 complete". Pvscan takes this info and prints it out,
and the udev rule can then somehow decide whether anything needs to be done

View File

@@ -18,21 +18,6 @@ top_builddir = @top_builddir@
include $(top_builddir)/make.tmpl
cmds.h:
@echo " [GEN] $@"
$(Q) set -o pipefail && \
( cat $(top_srcdir)/tools/license.inc && \
echo "/* Do not edit. This file is generated by the Makefile. */" && \
echo "cmd(CMD_NONE, none)" && \
$(GREP) '^ID:' $(top_srcdir)/tools/command-lines.in | LC_ALL=C $(SORT) -u | $(AWK) '{print "cmd(" $$2 "_CMD, " $$2 ")"}' && \
echo "cmd(CMD_COUNT, count)" \
) > $@
all: cmds.h
clean:
rm -f cmds.h
DISTCLEAN_TARGETS += configure.h lvm-version.h
CLEAN_TARGETS += \
.symlinks \
@@ -114,5 +99,4 @@ CLEAN_TARGETS += \
util.h \
uuid.h \
vg.h \
xlate.h \
cmds.h
xlate.h

View File

@@ -25,13 +25,18 @@
/* The path to 'cache_restore', if available. */
#undef CACHE_RESTORE_CMD
/* Define to 1 if the `closedir' function returns void instead of int. */
/* Define to 1 if the `closedir' function returns void instead of `int'. */
#undef CLOSEDIR_VOID
/* Path to cmirrord pidfile. */
#undef CMIRRORD_PIDFILE
/* Define to 1 if using 'alloca.c'. */
/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
systems. This function is required for `alloca.c' support on those systems.
*/
#undef CRAY_STACKSEG_END
/* Define to 1 if using `alloca.c'. */
#undef C_ALLOCA
/* Name of default metadata archive subdirectory. */
@@ -85,7 +90,7 @@
/* Use blkid wiping by default. */
#undef DEFAULT_USE_BLKID_WIPING
/* Default for lvm.conf use_devicesfile. */
/* Default for lvm.conf use_devicefile. */
#undef DEFAULT_USE_DEVICES_FILE
/* Use lvmlockd by default. */
@@ -136,10 +141,11 @@
/* Define to 1 if you have the `alarm' function. */
#undef HAVE_ALARM
/* Define to 1 if you have 'alloca', as a function or macro. */
/* Define to 1 if you have `alloca', as a function or macro. */
#undef HAVE_ALLOCA
/* Define to 1 if <alloca.h> works. */
/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
*/
#undef HAVE_ALLOCA_H
/* Define to 1 if you have the <arpa/inet.h> header file. */
@@ -267,9 +273,6 @@
/* Define to 1 if you have the <machine/endian.h> header file. */
#undef HAVE_MACHINE_ENDIAN_H
/* Define to 1 if you have the `mallinfo2' function. */
#undef HAVE_MALLINFO2
/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
to 0 otherwise. */
#undef HAVE_MALLOC
@@ -280,6 +283,9 @@
/* Define to 1 if you have the `memchr' function. */
#undef HAVE_MEMCHR
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the `memset' function. */
#undef HAVE_MEMSET
@@ -396,7 +402,7 @@
/* Define to 1 if you have the `strerror' function. */
#undef HAVE_STRERROR
/* Define if you have `strerror_r'. */
/* Define to 1 if you have the `strerror_r' function. */
#undef HAVE_STRERROR_R
/* Define to 1 if you have the <strings.h> header file. */
@@ -598,9 +604,6 @@
/* Path to lvm binary. */
#undef LVM_PATH
/* Path to lvresize_fs_helper script. */
#undef LVRESIZE_FS_HELPER_PATH
/* Define to 1 if `major', `minor', and `makedev' are declared in <mkdev.h>.
*/
#undef MAJOR_IN_MKDEV
@@ -645,6 +648,9 @@
/* Define to 1 to include the LVM readline shell. */
#undef READLINE_SUPPORT
/* Define as the return type of signal handlers (`int' or `void'). */
#undef RETSIGTYPE
/* Define to 1 to include built-in support for snapshots. */
#undef SNAPSHOT_INTERNAL
@@ -656,9 +662,7 @@
STACK_DIRECTION = 0 => direction of growth unknown */
#undef STACK_DIRECTION
/* Define to 1 if all of the C90 standard headers exist (not just the ones
required in a freestanding environment). This macro is provided for
backward compatibility; new code need not use it. */
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Define to 1 if strerror_r returns char *. */
@@ -689,6 +693,9 @@
/* The path to 'thin_restore', if available. */
#undef THIN_RESTORE_CMD
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
#undef TIME_WITH_SYS_TIME
/* Define to 1 if your <sys/time.h> declares `struct tm'. */
#undef TM_IN_SYS_TIME
@@ -765,7 +772,7 @@
/* Define to `long int' if <sys/types.h> does not define. */
#undef off_t
/* Define as a signed integer type capable of holding a process identifier. */
/* Define to `int' if <sys/types.h> does not define. */
#undef pid_t
/* Define to rpl_realloc if the replacement function should be used. */

View File

@@ -40,10 +40,7 @@ SOURCES =\
device/dev-luks.c \
device/dev-dasd.c \
device/dev-lvm1-pool.c \
device/filesystem.c \
device/online.c \
device/parse_vpd.c \
device/dev_util.c \
display/display.c \
error/errseg.c \
unknown/unknown.c \
@@ -57,6 +54,7 @@ SOURCES =\
filters/filter-partitioned.c \
filters/filter-type.c \
filters/filter-usable.c \
filters/filter-internal.c \
filters/filter-signature.c \
filters/filter-deviceid.c \
format_text/archive.c \

View File

@@ -322,11 +322,6 @@ int lv_vdo_pool_percent(const struct logical_volume *lv, dm_percent_t *percent)
{
return 0;
}
int lv_vdo_pool_size_config(const struct logical_volume *lv,
struct vdo_pool_size_config *cfg)
{
return 0;
}
int lvs_in_vg_activated(const struct volume_group *vg)
{
return 0;
@@ -1368,32 +1363,6 @@ int lv_vdo_pool_percent(const struct logical_volume *lv, dm_percent_t *percent)
return 1;
}
/*
* lv_vdo_pool_size_config obtains size configuration from active VDO table line
*
* If the 'params' string has been already retrieved, use it.
* If the mempool already exists, use it.
*
*/
int lv_vdo_pool_size_config(const struct logical_volume *lv,
struct vdo_pool_size_config *cfg)
{
struct dev_manager *dm;
int r;
if (!lv_info(lv->vg->cmd, lv, 1, NULL, 0, 0))
return 1; /* Inactive VDO pool -> no runtime config */
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name, !lv_is_pvmove(lv))))
return_0;
r = dev_manager_vdo_pool_size_config(dm, lv, cfg);
dev_manager_destroy(dm);
return r;
}
static int _lv_active(struct cmd_context *cmd, const struct logical_volume *lv)
{
struct lvinfo info;
@@ -2172,11 +2141,7 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
* TODO: Relax this limiting condition further */
if (!flush_required &&
(lv_is_pvmove(lv) || pvmove_lv ||
(!lv_is_mirror(lv) &&
!lv_is_thin_volume(lv) &&
!lv_is_thin_pool(lv) &&
!lv_is_vdo(lv) &&
!lv_is_vdo_pool(lv)))) {
(!lv_is_mirror(lv) && !lv_is_thin_pool(lv) && !lv_is_thin_volume(lv)))) {
log_debug("Requiring flush for LV %s.", display_lvname(lv));
flush_required = 1;
}
@@ -2795,7 +2760,7 @@ static int _component_cb(struct logical_volume *lv, void *data)
if (lv_is_locked(lv) || lv_is_pvmove(lv) ||/* ignoring */
/* thin-pool is special and it's using layered device */
(lv_is_thin_pool(lv) && thin_pool_is_active(lv)))
(lv_is_thin_pool(lv) && pool_is_active(lv)))
return -1;
/* External origin is activated through thinLV and uses -real suffix.

View File

@@ -204,8 +204,6 @@ int lv_thin_pool_status(const struct logical_volume *lv, int flush,
int lv_vdo_pool_status(const struct logical_volume *lv, int flush,
struct lv_status_vdo **status);
int lv_vdo_pool_percent(const struct logical_volume *lv, dm_percent_t *percent);
int lv_vdo_pool_size_config(const struct logical_volume *lv,
struct vdo_pool_size_config *cfg);
/*
* Return number of LVs in the VG that are active.

View File

@@ -277,7 +277,7 @@ static int _info_run(const char *dlid, struct dm_info *dminfo,
int dmtask;
int with_flush; /* TODO: arg for _info_run */
void *target = NULL;
uint64_t target_start, target_length, start, extent_size, length, length_crop = 0;
uint64_t target_start, target_length, start, length, length_crop = 0;
char *target_name, *target_params;
const char *devname;
@@ -306,8 +306,8 @@ static int _info_run(const char *dlid, struct dm_info *dminfo,
/* Query status only for active device */
if (seg_status && dminfo->exists) {
extent_size = length = seg_status->seg->lv->vg->extent_size;
start = extent_size * seg_status->seg->le;
start = length = seg_status->seg->lv->vg->extent_size;
start *= seg_status->seg->le;
length *= _seg_len(seg_status->seg);
/* Uses max DM_THIN_MAX_METADATA_SIZE sectors for metadata device */
@@ -328,8 +328,6 @@ static int _info_run(const char *dlid, struct dm_info *dminfo,
if ((start == target_start) &&
((length == target_length) ||
((lv_is_vdo_pool(seg_status->seg->lv)) && /* should fit within extent size */
(length < target_length) && ((length + extent_size) > target_length)) ||
(length_crop && (length_crop == target_length))))
break; /* Keep target_params when matching segment is found */
@@ -1957,71 +1955,6 @@ out:
return r;
}
int dev_manager_vdo_pool_size_config(struct dev_manager *dm,
const struct logical_volume *lv,
struct vdo_pool_size_config *cfg)
{
const char *dlid;
struct dm_info info;
uint64_t start, length;
struct dm_task *dmt = NULL;
char *type = NULL;
char *params = NULL;
int r = 0;
unsigned version = 0;
memset(cfg, 0, sizeof(*cfg));
if (!(dlid = build_dm_uuid(dm->mem, lv, lv_layer(lv))))
return_0;
if (!(dmt = _setup_task_run(DM_DEVICE_TABLE, &info, NULL, dlid, 0, 0, 0, 0, 0, 0)))
return_0;
if (!info.exists)
goto inactive; /* VDO device is not active, should not happen here... */
log_debug_activation("Checking VDO pool table line for LV %s.",
display_lvname(lv));
if (dm_get_next_target(dmt, NULL, &start, &length, &type, &params)) {
log_error("More then one table line found for %s.",
display_lvname(lv));
goto out;
}
if (!type || strcmp(type, TARGET_NAME_VDO)) {
log_error("Expected %s segment type but got %s instead.",
TARGET_NAME_VDO, type ? type : "NULL");
goto out;
}
if (sscanf(params, "V%u %*s " FMTu64 " %*u " FMTu32,
&version, &cfg->physical_size, &cfg->block_map_cache_size_mb) != 3) {
log_error("Failed to parse VDO parameters %s for LV %s.",
params, display_lvname(lv));
goto out;
}
switch (version) {
case 2: break;
case 4: break;
default: log_warn("WARNING: Unknown VDO table line version %u.", version);
}
cfg->virtual_size = length;
cfg->physical_size *= 8; // From 4K unit to 512B
cfg->block_map_cache_size_mb /= 256; // From 4K unit to MiB
cfg->index_memory_size_mb = first_seg(lv)->vdo_params.index_memory_size_mb; // Preserved
inactive:
r = 1;
out:
dm_task_destroy(dmt);
return r;
}
/*************************/
/* NEW CODE STARTS HERE */
@@ -3909,12 +3842,11 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
if (!seg_is_striped_target(first_seg(lv)) || (action == CLEAN))
dm->cmd->disable_dm_devs = 1;
dtree = _create_partial_dtree(dm, lv, laopts->origin_only);
dm->cmd->disable_dm_devs = tmp_state;
if (!dtree)
if (!(dtree = _create_partial_dtree(dm, lv, laopts->origin_only)))
return_0;
dm->cmd->disable_dm_devs = tmp_state;
if (!(root = dm_tree_find_node(dtree, 0, 0))) {
log_error("Lost dependency tree root node.");
goto out_no_root;
@@ -3975,8 +3907,6 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
* non 'thin pool/volume' and size increase */
else if (!lv_is_thin_volume(lv) &&
!lv_is_thin_pool(lv) &&
!lv_is_vdo(lv) &&
!lv_is_vdo_pool(lv) &&
dm_tree_node_size_changed(root))
dm->flush_required = 1;
@@ -4095,78 +4025,3 @@ out:
return r;
}
/*
* crypt offset is usually the LUKS header size but can be larger.
* The LUKS header is usually 2MB for LUKS1 and 16MB for LUKS2.
* The offset needs to be subtracted from the LV size to get the
* size used to resize the crypt device.
*/
int get_crypt_table_offset(dev_t crypt_devt, uint32_t *offset_bytes)
{
struct dm_task *dmt = dm_task_create(DM_DEVICE_TABLE);
uint64_t start, length;
char *target_type = NULL;
void *next = NULL;
char *params = NULL;
char offset_str[32] = { 0 };
int copy_offset = 0;
int spaces = 0;
int i, i_off = 0;
if (!dmt)
return_0;
if (!dm_task_set_major_minor(dmt, (int)MAJOR(crypt_devt), (int)MINOR(crypt_devt), 0)) {
dm_task_destroy(dmt);
return_0;
}
/* Non-blocking status read */
if (!dm_task_no_flush(dmt))
log_warn("WARNING: Can't set no_flush for dm status.");
if (!dm_task_run(dmt)) {
dm_task_destroy(dmt);
return_0;
}
next = dm_get_next_target(dmt, next, &start, &length, &target_type, &params);
if (!target_type || !params || strcmp(target_type, "crypt")) {
dm_task_destroy(dmt);
return_0;
}
/*
* get offset from params string:
* <cipher> <key> <iv_offset> <device> <offset> [<#opt_params> <opt_params>]
* <offset> is reported in 512 byte sectors.
*/
for (i = 0; i < strlen(params); i++) {
if (params[i] == ' ') {
spaces++;
if (spaces == 4)
copy_offset = 1;
if (spaces == 5)
break;
continue;
}
if (!copy_offset)
continue;
offset_str[i_off++] = params[i];
if (i_off == sizeof(offset_str)) {
offset_str[0] = '\0';
break;
}
}
dm_task_destroy(dmt);
if (!offset_str[0])
return_0;
*offset_bytes = ((uint32_t)strtoul(offset_str, NULL, 0) * 512);
return 1;
}

View File

@@ -29,8 +29,6 @@ struct lv_seg_status;
int read_only_lv(const struct logical_volume *lv, const struct lv_activate_opts *laopts, const char *layer);
int get_crypt_table_offset(dev_t crypt_devt, uint32_t *offset_bytes);
/*
* Constructor and destructor.
*/
@@ -83,9 +81,6 @@ int dev_manager_thin_pool_status(struct dev_manager *dm,
int dev_manager_vdo_pool_status(struct dev_manager *dm,
const struct logical_volume *lv, int flush,
struct lv_status_vdo **status, int *exists);
int dev_manager_vdo_pool_size_config(struct dev_manager *dm,
const struct logical_volume *lv,
struct vdo_pool_size_config *cfg);
int dev_manager_suspend(struct dev_manager *dm, const struct logical_volume *lv,
struct lv_activate_opts *laopts, int lockfs, int flush_required);
int dev_manager_activate(struct dev_manager *dm, const struct logical_volume *lv,

116
lib/cache/lvmcache.c vendored
View File

@@ -144,6 +144,28 @@ int lvmcache_found_duplicate_vgnames(void)
return _found_duplicate_vgnames;
}
static struct device_list *_get_devl_in_device_list(struct device *dev, struct dm_list *head)
{
struct device_list *devl;
dm_list_iterate_items(devl, head) {
if (devl->dev == dev)
return devl;
}
return NULL;
}
int dev_in_device_list(struct device *dev, struct dm_list *head)
{
struct device_list *devl;
dm_list_iterate_items(devl, head) {
if (devl->dev == dev)
return 1;
}
return 0;
}
bool lvmcache_has_duplicate_devs(void)
{
if (dm_list_empty(&_unused_duplicates) && dm_list_empty(&_initial_duplicates))
@@ -170,11 +192,11 @@ void lvmcache_del_dev_from_duplicates(struct device *dev)
{
struct device_list *devl;
if ((devl = device_list_find_dev(&_initial_duplicates, dev))) {
if ((devl = _get_devl_in_device_list(dev, &_initial_duplicates))) {
log_debug_cache("delete dev from initial duplicates %s", dev_name(dev));
dm_list_del(&devl->list);
}
if ((devl = device_list_find_dev(&_unused_duplicates, dev))) {
if ((devl = _get_devl_in_device_list(dev, &_unused_duplicates))) {
log_debug_cache("delete dev from unused duplicates %s", dev_name(dev));
dm_list_del(&devl->list);
}
@@ -583,7 +605,7 @@ int vg_has_duplicate_pvs(struct volume_group *vg)
bool lvmcache_dev_is_unused_duplicate(struct device *dev)
{
return device_list_find_dev(&_unused_duplicates, dev) ? true : false;
return dev_in_device_list(dev, &_unused_duplicates) ? true : false;
}
static void _warn_unused_duplicates(struct cmd_context *cmd)
@@ -622,19 +644,14 @@ static int _all_multipath_components(struct cmd_context *cmd, struct lvmcache_in
struct device *dev_mp = NULL;
struct device *dev1 = NULL;
struct device *dev;
char wwid1_buf[DEV_WWID_SIZE] = { 0 };
char wwid_buf[DEV_WWID_SIZE] = { 0 };
const char *wwid1 = NULL;
const char *wwid = NULL;
const char *wwid;
int diff_wwid = 0;
int same_wwid = 0;
int dev_is_mp;
*dev_mpath = NULL;
if (!find_config_tree_bool(cmd, devices_multipath_component_detection_CFG, NULL))
return 0;
/* This function only makes sense with more than one dev. */
if ((info && dm_list_empty(altdevs)) || (!info && (dm_list_size(altdevs) == 1))) {
log_debug("Skip multipath component checks with single device for PVID %s", pvid);
@@ -647,23 +664,14 @@ static int _all_multipath_components(struct cmd_context *cmd, struct lvmcache_in
dev = info->dev;
dev_is_mp = (cmd->dev_types->device_mapper_major == MAJOR(dev->dev)) && dev_has_mpath_uuid(cmd, dev, NULL);
/*
* dev_mpath_component_wwid allocates wwid from dm_pool,
* device_id_system_read does not and needs free.
*/
if (dev_is_mp) {
if ((wwid1 = dev_mpath_component_wwid(cmd, dev))) {
strncpy(wwid1_buf, wwid1, DEV_WWID_SIZE-1);
dev_mp = dev;
dev1 = dev;
}
} else {
if ((wwid1 = device_id_system_read(cmd, dev, DEV_ID_TYPE_SYS_WWID))) {
strncpy(wwid1_buf, wwid1, DEV_WWID_SIZE-1);
free((char *)wwid1);
if ((wwid1 = device_id_system_read(cmd, dev, DEV_ID_TYPE_SYS_WWID)))
dev1 = dev;
}
}
}
@@ -671,36 +679,31 @@ static int _all_multipath_components(struct cmd_context *cmd, struct lvmcache_in
dev = devl->dev;
dev_is_mp = (cmd->dev_types->device_mapper_major == MAJOR(dev->dev)) && dev_has_mpath_uuid(cmd, dev, NULL);
if (dev_is_mp) {
if ((wwid = dev_mpath_component_wwid(cmd, dev)))
strncpy(wwid_buf, wwid, DEV_WWID_SIZE-1);
} else {
if ((wwid = device_id_system_read(cmd, dev, DEV_ID_TYPE_SYS_WWID))) {
strncpy(wwid_buf, wwid, DEV_WWID_SIZE-1);
free((char *)wwid);
}
}
if (dev_is_mp)
wwid = dev_mpath_component_wwid(cmd, dev);
else
wwid = device_id_system_read(cmd, dev, DEV_ID_TYPE_SYS_WWID);
if (!wwid_buf[0] && wwid1_buf[0]) {
if (!wwid && wwid1) {
log_debug("Different wwids for duplicate PVs %s %s %s none",
dev_name(dev1), wwid1_buf, dev_name(dev));
dev_name(dev1), wwid1, dev_name(dev));
diff_wwid++;
continue;
}
if (!wwid_buf[0])
if (!wwid)
continue;
if (!wwid1_buf[0]) {
memcpy(wwid1_buf, wwid_buf, DEV_WWID_SIZE-1);
if (!wwid1) {
wwid1 = wwid;
dev1 = dev;
continue;
}
/* Different wwids indicates these are not multipath components. */
if (strcmp(wwid1_buf, wwid_buf)) {
if (strcmp(wwid1, wwid)) {
log_debug("Different wwids for duplicate PVs %s %s %s %s",
dev_name(dev1), wwid1_buf, dev_name(dev), wwid_buf);
dev_name(dev1), wwid1, dev_name(dev), wwid);
diff_wwid++;
continue;
}
@@ -708,7 +711,7 @@ static int _all_multipath_components(struct cmd_context *cmd, struct lvmcache_in
/* Different mpath devs with the same wwid shouldn't happen. */
if (dev_is_mp && dev_mp) {
log_print("Found multiple multipath devices for PVID %s WWID %s: %s %s",
pvid, wwid1_buf, dev_name(dev_mp), dev_name(dev));
pvid, wwid1, dev_name(dev_mp), dev_name(dev));
continue;
}
@@ -724,7 +727,7 @@ static int _all_multipath_components(struct cmd_context *cmd, struct lvmcache_in
return 0;
if (dev_mp)
log_debug("Found multipath device %s for PVID %s WWID %s.", dev_name(dev_mp), pvid, wwid1_buf);
log_debug("Found multipath device %s for PVID %s WWID %s.", dev_name(dev_mp), pvid, wwid1);
*dev_mpath = dev_mp;
return 1;
@@ -912,7 +915,7 @@ next:
}
/* Remove dev_mpath from altdevs. */
if ((devl = device_list_find_dev(&altdevs, dev_mpath)))
if ((devl = _get_devl_in_device_list(dev_mpath, &altdevs)))
dm_list_del(&devl->list);
/* Remove info from lvmcache that came from the component dev. */
@@ -979,7 +982,7 @@ next:
}
/* Remove dev_md from altdevs. */
if ((devl = device_list_find_dev(&altdevs, dev_md)))
if ((devl = _get_devl_in_device_list(dev_md, &altdevs)))
dm_list_del(&devl->list);
/* Remove info from lvmcache that came from the component dev. */
@@ -1007,7 +1010,7 @@ next:
}
/* Remove dev_md from altdevs. */
if ((devl = device_list_find_dev(&altdevs, dev_md)))
if ((devl = _get_devl_in_device_list(dev_md, &altdevs)))
dm_list_del(&devl->list);
}
@@ -1085,8 +1088,8 @@ next:
if (dev1 == dev2)
continue;
prev_unchosen1 = device_list_find_dev(&_unused_duplicates, dev1) ? 1 :0;
prev_unchosen2 = device_list_find_dev(&_unused_duplicates, dev2) ? 1 :0;
prev_unchosen1 = dev_in_device_list(dev1, &_unused_duplicates);
prev_unchosen2 = dev_in_device_list(dev2, &_unused_duplicates);
if (!prev_unchosen1 && !prev_unchosen2) {
/*
@@ -1096,8 +1099,8 @@ next:
* want the same duplicate preference to be preserved
* in each instance of lvmcache for a single command.
*/
prev_unchosen1 = device_list_find_dev(&_prev_unused_duplicate_devs, dev1) ? 1 :0;
prev_unchosen2 = device_list_find_dev(&_prev_unused_duplicate_devs, dev2) ? 1 : 0;
prev_unchosen1 = dev_in_device_list(dev1, &_prev_unused_duplicate_devs);
prev_unchosen2 = dev_in_device_list(dev2, &_prev_unused_duplicate_devs);
}
dev1_major = MAJOR(dev1->dev);
@@ -1274,7 +1277,7 @@ next:
if (!info) {
log_debug_cache("PV %s with duplicates will use %s.", pvid, dev_name(dev1));
if (!(devl_add = device_list_find_dev(&altdevs, dev1))) {
if (!(devl_add = _get_devl_in_device_list(dev1, &altdevs))) {
/* shouldn't happen */
log_error(INTERNAL_ERROR "PV %s with duplicates no alternate list entry for %s", pvid, dev_name(dev1));
dm_list_splice(&new_unused, &altdevs);
@@ -1293,7 +1296,7 @@ next:
* for the current lvmcache device to drop.
*/
if (!(devl_add = device_list_find_dev(&altdevs, dev1))) {
if (!(devl_add = _get_devl_in_device_list(dev1, &altdevs))) {
/* shouldn't happen */
log_error(INTERNAL_ERROR "PV %s with duplicates no alternate list entry for %s", pvid, dev_name(dev1));
dm_list_splice(&new_unused, &altdevs);
@@ -1609,24 +1612,7 @@ int lvmcache_label_scan(struct cmd_context *cmd)
* with infos/vginfos based on reading headers from
* each device, and a vg summary from each mda.
*/
if (!label_scan(cmd))
return_0;
/*
* device_ids_validate() found devices using a sys_serial device id
* which had a PVID on disk that did not match the PVID in the devices
* file. Serial numbers may not always be unique, so any device with
* the same serial number is found and searched for the correct PVID.
* If the PVID is found on a device that has not been scanned, then
* it needs to be scanned so it can be used.
*/
if (!dm_list_empty(&cmd->device_ids_check_serial)) {
struct dm_list scan_devs;
dm_list_init(&scan_devs);
device_ids_check_serial(cmd, &scan_devs, NULL, 0);
if (!dm_list_empty(&scan_devs))
label_scan_devs(cmd, cmd->filter, &scan_devs);
}
label_scan(cmd);
/*
* When devnames are used as device ids (which is dispreferred),
@@ -2508,7 +2494,7 @@ struct lvmcache_info *lvmcache_add(struct cmd_context *cmd, struct labeller *lab
memcpy(dev->pvid, pvid, ID_LEN);
/* shouldn't happen */
if (device_list_find_dev(&_initial_duplicates, dev))
if (dev_in_device_list(dev, &_initial_duplicates))
log_debug_cache("Initial duplicate already in list %s", dev_name(dev));
else {
/*

View File

@@ -186,6 +186,8 @@ int lvmcache_vginfo_has_pvid(struct lvmcache_vginfo *vginfo, const char *pvid_ar
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);
bool lvmcache_has_bad_metadata(struct device *dev);
bool lvmcache_has_old_metadata(struct cmd_context *cmd, const char *vgname, const char *vgid, struct device *dev);

View File

@@ -1,19 +0,0 @@
#ifndef _CMD_ENUM_H
#define _CMD_ENUM_H
/*
* include/cmds.h is generated by the Makefile. For each command definition
* in command-lines.in, cmds.h contains:
* cmd(foo_CMD, foo)
*
* This header adds each of the foo_CMD's into an enum, so there's
* a unique integer identifier for each command definition.
*/
enum {
#define cmd(a, b) a ,
#include "../../include/cmds.h"
#undef cmd
};
#endif

View File

@@ -643,7 +643,6 @@ static int _process_config(struct cmd_context *cmd)
if (!dm_set_uuid_prefix(UUID_PREFIX))
return_0;
#endif
cmd->device_id_sysfs_dir = find_config_tree_str(cmd, devices_device_id_sysfs_dir_CFG, NULL);
dev_ext_info_src = find_config_tree_str(cmd, devices_external_device_info_source_CFG, NULL);
@@ -1129,7 +1128,7 @@ static int _init_dev_cache(struct cmd_context *cmd)
return 1;
}
#define MAX_FILTERS 10
#define MAX_FILTERS 11
static struct dev_filter *_init_filter_chain(struct cmd_context *cmd)
{
@@ -1144,6 +1143,13 @@ static struct dev_filter *_init_filter_chain(struct cmd_context *cmd)
* Update MAX_FILTERS definition above when adding new filters.
*/
/* internal filter used by command processing. */
if (!(filters[nr_filt] = internal_filter_create())) {
log_error("Failed to create internal device filter");
goto bad;
}
nr_filt++;
/* global regex filter. Optional. */
if ((cn = find_config_tree_node(cmd, devices_global_filter_CFG, NULL))) {
if (!(filters[nr_filt] = regex_filter_create(cn->v, 0, 1))) {
@@ -1906,6 +1912,7 @@ int refresh_toolcontext(struct cmd_context *cmd)
_destroy_segtypes(&cmd->segtypes);
_destroy_formats(cmd, &cmd->formats);
devices_file_exit(cmd);
if (!dev_cache_exit())
stack;
_destroy_dev_types(cmd);
@@ -2034,6 +2041,7 @@ void destroy_toolcontext(struct cmd_context *cmd)
_destroy_segtypes(&cmd->segtypes);
_destroy_formats(cmd, &cmd->formats);
_destroy_filters(cmd);
devices_file_exit(cmd);
dev_cache_exit();
_destroy_dev_types(cmd);
_destroy_tags(cmd);

View File

@@ -18,7 +18,6 @@
#include "lib/device/dev-cache.h"
#include "lib/device/dev-type.h"
#include "lib/commands/cmd_enum.h"
#include <limits.h>
@@ -95,7 +94,6 @@ struct cmd_context {
const char *name; /* needed before cmd->command is set */
struct command_name *cname;
struct command *command;
int command_enum; /* duplicate from command->command_enum for lib code */
char **argv;
struct arg_values *opt_arg_values;
struct dm_list arg_value_groups;
@@ -146,7 +144,6 @@ struct cmd_context {
unsigned degraded_activation:1;
unsigned auto_set_activation_skip:1;
unsigned si_unit_consistency:1;
unsigned report_strict_type_mode:1;
unsigned report_binary_values_as_numeric:1;
unsigned report_mark_hidden_devices:1;
unsigned metadata_read_only:1;
@@ -194,7 +191,6 @@ struct cmd_context {
unsigned create_edit_devices_file:1; /* command expects to create and/or edit devices file */
unsigned edit_devices_file:1; /* command expects to edit devices file */
unsigned filter_deviceid_skip:1; /* don't use filter-deviceid */
unsigned filter_regex_skip:1; /* don't use filter-regex */
unsigned filter_regex_with_devices_file:1; /* use filter-regex even when devices file is enabled */
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 */
@@ -208,7 +204,6 @@ struct cmd_context {
unsigned udevoutput:1;
unsigned online_vg_file_removed:1;
unsigned disable_dm_devs:1; /* temporarily disable use of dm devs cache */
unsigned filter_regex_set_preferred_name_disable:1; /* prevent dev_set_preferred_name */
/*
* Devices and filtering.
@@ -217,7 +212,6 @@ struct cmd_context {
struct dm_list use_devices; /* struct dev_use for each entry in devices file */
const char *md_component_checks;
const char *search_for_devnames; /* config file setting */
struct dm_list device_ids_check_serial;
const char *devicesfile; /* from --devicesfile option */
struct dm_list deviceslist; /* from --devices option, struct dm_str_list */
@@ -250,7 +244,6 @@ struct cmd_context {
* Paths.
*/
const char *lib_dir; /* cache value global/library_dir */
const char *device_id_sysfs_dir;
char system_dir[PATH_MAX];
char dev_dir[PATH_MAX];
char proc_dir[PATH_MAX];

View File

@@ -1830,9 +1830,8 @@ static int _out_line_fn(const struct dm_config_node *cn, const char *line, void
char summary[MAX_COMMENT_LINE+1];
char version[9];
int pos = 0;
int space_prefix_len = 0;
const char *p;
size_t len;
char *space_prefix;
if ((out->tree_spec->type == CFG_DEF_TREE_DIFF) &&
(!(out->tree_spec->check_status[cn->id] & CFG_DIFF)))
@@ -1866,36 +1865,16 @@ static int _out_line_fn(const struct dm_config_node *cn, const char *line, void
/* Usual tree view with nodes and their values. */
if (out->tree_spec->valuesonly && !(cfg_def->type & CFG_TYPE_SECTION)) {
if ((space_prefix_len = strspn(line, "\t "))) {
len = strlen(line);
p = line + space_prefix_len;
/* copy space_prefix, skip key and '=', copy value */
if (!dm_pool_begin_object(out->mem, len))
return_0;
if (!dm_pool_grow_object(out->mem, line, space_prefix_len) ||
!dm_pool_grow_object(out->mem, p + strcspn(p, "=") + 1, len + 1)) {
dm_pool_abandon_object(out->mem);
return_0;
}
line = dm_pool_end_object(out->mem);
} else
line = strchr(line, '=') + 1;
}
if ((out->tree_spec->type != CFG_DEF_TREE_CURRENT) &&
(out->tree_spec->type != CFG_DEF_TREE_DIFF) &&
(out->tree_spec->type != CFG_DEF_TREE_FULL) &&
!out->tree_spec->valuesonly &&
(cfg_def->flags & (CFG_DEFAULT_UNDEFINED | CFG_DEFAULT_COMMENTED))) {
/* print with # at the front to comment out the line */
if (_should_print_cfg_with_undef_def_val(out, cfg_def, cn)) {
space_prefix_len = strspn(line, "\t ");
fprintf(out->fp, "%.*s%s%s\n", space_prefix_len, line, "# ",
line + space_prefix_len);
space_prefix = ((len = strspn(line, "\t "))) ? dm_pool_strndup(out->mem, line, len) : NULL;
fprintf(out->fp, "%s%s%s\n", space_prefix ? : "", "# ", line + len);
if (space_prefix)
dm_pool_free(out->mem, space_prefix);
}
return 1;
}
@@ -1904,9 +1883,6 @@ static int _out_line_fn(const struct dm_config_node *cn, const char *line, void
if (_should_print_cfg_with_undef_def_val(out, cfg_def, cn))
fprintf(out->fp, "%s\n", line);
if (out->tree_spec->valuesonly && !(cfg_def->type & CFG_TYPE_SECTION) && space_prefix_len)
dm_pool_free(out->mem, (char *) line);
return 1;
}

View File

@@ -176,7 +176,6 @@ struct config_def_tree_spec {
unsigned unconfigured:1; /* use unconfigured path strings */
unsigned withgeneralpreamble:1; /* include preamble for a general config file */
unsigned withlocalpreamble:1; /* include preamble for a local config file */
unsigned valuesonly:1; /* print only values without keys */
uint8_t *check_status; /* status of last tree check (currently needed for CFG_DEF_TREE_MISSING only) */
};

View File

@@ -118,7 +118,6 @@
* the previous default value was set (uncommented) in lvm.conf.
*/
#include "lib/config/defaults.h"
#include "device_mapper/vdo/vdo_limits.h"
cfg_section(root_CFG_SECTION, "(root)", root_CFG_SECTION, 0, vsn(0, 0, 0), 0, NULL, NULL)
@@ -224,9 +223,6 @@ cfg(devices_dir_CFG, "dir", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_ADV
"Directory in which to create volume group device nodes.\n"
"Commands also accept this as a prefix on volume group names.\n")
cfg(devices_device_id_sysfs_dir_CFG, "device_id_sysfs_dir", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED | CFG_UNSUPPORTED, CFG_TYPE_STRING, DEFAULT_DEVICE_ID_SYSFS_DIR, vsn(2, 3, 17), NULL, 0, NULL,
"Location of sysfs for finding device ids (for testing.)\n")
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")
@@ -280,7 +276,7 @@ cfg_array(devices_preferred_names_CFG, "preferred_names", devices_CFG_SECTION, C
"preferred_names = [ \"^/dev/mpath/\", \"^/dev/mapper/mpath\", \"^/dev/[hs]d\" ]\n"
"#\n")
cfg(devices_use_devicesfile_CFG, "use_devicesfile", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_USE_DEVICES_FILE, vsn(2, 3, 12), "@DEFAULT_USE_DEVICES_FILE@", 0, NULL,
cfg(devices_use_devicesfile_CFG, "use_devicesfile", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_USE_DEVICES_FILE, vsn(2, 3, 12), NULL, 0, NULL,
"Enable or disable the use of a devices file.\n"
"When enabled, lvm will only use devices that\n"
"are lised in the devices file. A devices file will\n"
@@ -712,11 +708,12 @@ cfg(allocation_vdo_use_deduplication_CFG, "vdo_use_deduplication", allocation_CF
cfg(allocation_vdo_use_metadata_hints_CFG, "vdo_use_metadata_hints", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_USE_METADATA_HINTS, VDO_1ST_VSN, NULL, 0, NULL,
"Enables or disables whether VDO volume should tag its latency-critical\n"
"writes with the REQ_SYNC flag. Some device mapper targets such as dm-raid5\n"
"process writes with this flag at a higher priority.\n")
"process writes with this flag at a higher priority.\n"
"Default is enabled.\n")
cfg(allocation_vdo_minimum_io_size_CFG, "vdo_minimum_io_size", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_MINIMUM_IO_SIZE, VDO_1ST_VSN, NULL, 0, NULL,
"The minimum IO size for VDO volume to accept, in bytes.\n"
"Valid values are 512 or 4096. The recommended value is 4096.\n")
"Valid values are 512 or 4096. The recommended and default value is 4096.\n")
cfg(allocation_vdo_block_map_cache_size_mb_CFG, "vdo_block_map_cache_size_mb", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_BLOCK_MAP_CACHE_SIZE_MB, VDO_1ST_VSN, NULL, 0, NULL,
"Specifies the amount of memory in MiB allocated for caching block map\n"
@@ -729,8 +726,7 @@ cfg(allocation_vdo_block_map_era_length_CFG, "vdo_block_map_period", allocation_
"The speed with which the block map cache writes out modified block map pages.\n"
"A smaller era length is likely to reduce the amount time spent rebuilding,\n"
"at the cost of increased block map writes during normal operation.\n"
"The maximum and recommended value is " DM_TO_STRING(DM_VDO_BLOCK_MAP_ERA_LENGTH_MAXIMUM)
"; the minimum value is " DM_TO_STRING(DM_VDO_BLOCK_MAP_ERA_LENGTH_MINIMUM) ".\n")
"The maximum and recommended value is 16380; the minimum value is 1.\n")
cfg(allocation_vdo_check_point_frequency_CFG, "vdo_check_point_frequency", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_CHECK_POINT_FREQUENCY, VDO_1ST_VSN, NULL, 0, NULL,
"The default check point frequency for VDO volume.\n")
@@ -752,34 +748,27 @@ cfg(allocation_vdo_slab_size_mb_CFG, "vdo_slab_size_mb", allocation_CFG_SECTION,
cfg(allocation_vdo_ack_threads_CFG, "vdo_ack_threads", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_ACK_THREADS, VDO_1ST_VSN, NULL, 0, NULL,
"Specifies the number of threads to use for acknowledging\n"
"completion of requested VDO I/O operations.\n"
"The value must be at in range [" DM_TO_STRING(DM_VDO_ACK_THREADS_MINIMUM) ".."
DM_TO_STRING(DM_VDO_ACK_THREADS_MAXIMUM) "].\n")
"The value must be at in range [0..100].\n")
cfg(allocation_vdo_bio_threads_CFG, "vdo_bio_threads", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_BIO_THREADS, VDO_1ST_VSN, NULL, 0, NULL,
"Specifies the number of threads to use for submitting I/O\n"
"operations to the storage device of VDO volume.\n"
"The value must be in range [" DM_TO_STRING(DM_VDO_BIO_THREADS_MINIMUM) ".."
DM_TO_STRING(DM_VDO_BIO_THREADS_MAXIMUM) "].\n"
"The value must be in range [1..100]\n"
"Each additional thread after the first will use an additional 18MiB of RAM,\n"
"plus 1.12 MiB of RAM per megabyte of configured read cache size.\n")
cfg(allocation_vdo_bio_rotation_CFG, "vdo_bio_rotation", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_BIO_ROTATION, VDO_1ST_VSN, NULL, 0, NULL,
"Specifies the number of I/O operations to enqueue for each bio-submission\n"
"thread before directing work to the next. The value must be in range ["
DM_TO_STRING(DM_VDO_BIO_ROTATION_MINIMUM) ".."
DM_TO_STRING(DM_VDO_BIO_ROTATION_MAXIMUM) "].\n")
"thread before directing work to the next. The value must be in range [1..1024].\n")
cfg(allocation_vdo_cpu_threads_CFG, "vdo_cpu_threads", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_CPU_THREADS, VDO_1ST_VSN, NULL, 0, NULL,
"Specifies the number of threads to use for CPU-intensive work such as\n"
"hashing or compression for VDO volume. The value must be in range ["
DM_TO_STRING(DM_VDO_CPU_THREADS_MINIMUM) ".."
DM_TO_STRING(DM_VDO_CPU_THREADS_MAXIMUM) "].\n")
"hashing or compression for VDO volume. The value must be in range [1..100]\n")
cfg(allocation_vdo_hash_zone_threads_CFG, "vdo_hash_zone_threads", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_PROFILABLE_METADATA | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_VDO_HASH_ZONE_THREADS, VDO_1ST_VSN, NULL, 0, NULL,
"Specifies the number of threads across which to subdivide parts of the VDO\n"
"processing based on the hash value computed from the block data.\n"
"The value must be at in range [" DM_TO_STRING(DM_VDO_HASH_ZONE_THREADS_MINIMUM) ".."
DM_TO_STRING(DM_VDO_HASH_ZONE_THREADS_MAXIMUM) "].\n"
"The value must be at in range [0..100].\n"
"vdo_hash_zone_threads, vdo_logical_threads and vdo_physical_threads must be\n"
"either all zero or all non-zero.\n")
@@ -788,8 +777,7 @@ cfg(allocation_vdo_logical_threads_CFG, "vdo_logical_threads", allocation_CFG_SE
"processing based on the hash value computed from the block data.\n"
"A logical thread count of 9 or more will require explicitly specifying\n"
"a sufficiently large block map cache size, as well.\n"
"The value must be in range [" DM_TO_STRING(DM_VDO_LOGICAL_THREADS_MINIMUM) ".."
DM_TO_STRING(DM_VDO_LOGICAL_THREADS_MAXIMUM) "].\n"
"The value must be in range [0..100].\n"
"vdo_hash_zone_threads, vdo_logical_threads and vdo_physical_threads must be\n"
"either all zero or all non-zero.\n")
@@ -797,8 +785,7 @@ cfg(allocation_vdo_physical_threads_CFG, "vdo_physical_threads", allocation_CFG_
"Specifies the number of threads across which to subdivide parts of the VDO\n"
"processing based on physical block addresses.\n"
"Each additional thread after the first will use an additional 10MiB of RAM.\n"
"The value must be in range [" DM_TO_STRING(DM_VDO_PHYSICAL_THREADS_MINIMUM) ".."
DM_TO_STRING(DM_VDO_PHYSICAL_THREADS_MAXIMUM) "].\n"
"The value must be in range [0..16].\n"
"vdo_hash_zone_threads, vdo_logical_threads and vdo_physical_threads must be\n"
"either all zero or all non-zero.\n")
@@ -1809,14 +1796,7 @@ cfg(report_output_format_CFG, "output_format", report_CFG_SECTION, CFG_PROFILABL
" one report per command, each report is prefixed with report's\n"
" name for identification.\n"
" json\n"
" JSON format.\n"
" json_std\n"
" JSON format that is more compliant with JSON standard.\n"
" Compared to original \"json\" format:\n"
" - it does not use double quotes around numeric values,\n"
" - it uses 'null' for undefined numeric values,\n"
" - it prints string list as proper JSON array of strings instead of a single string."
"\n")
" JSON format.\n")
cfg(report_compact_output_CFG, "compact_output", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_REP_COMPACT_OUTPUT, vsn(2, 2, 115), NULL, 0, NULL,
"Do not print empty values for all report fields.\n"

View File

@@ -332,6 +332,4 @@
#define VGS_ONLINE_DIR DEFAULT_RUN_DIR "/vgs_online"
#define PVS_LOOKUP_DIR DEFAULT_RUN_DIR "/pvs_lookup"
#define DEFAULT_DEVICE_ID_SYSFS_DIR "/sys/" /* trailing / to match dm_sysfs_dir() */
#endif /* _LVM_DEFAULTS_H */

View File

@@ -80,7 +80,6 @@ static void _dev_init(struct device *dev)
dm_list_init(&dev->aliases);
dm_list_init(&dev->ids);
dm_list_init(&dev->wwids);
}
void dev_destroy_file(struct device *dev)
@@ -384,22 +383,6 @@ out:
return 1;
}
int get_sysfs_binary(const char *path, char *buf, size_t buf_size, int *retlen)
{
int ret;
int fd;
fd = open(path, O_RDONLY);
if (fd < 0)
return 0;
ret = read(fd, buf, buf_size);
close(fd);
if (ret <= 0)
return 0;
*retlen = ret;
return 1;
}
int get_sysfs_value(const char *path, char *buf, size_t buf_size, int error_if_no_value)
{
FILE *fp;
@@ -1353,7 +1336,6 @@ int dev_cache_exit(void)
dm_hash_iterate(n, _cache.names) {
dev = (struct device *) dm_hash_get_data(_cache.names, n);
free_dids(&dev->ids);
free_wwids(&dev->wwids);
}
}
@@ -1428,7 +1410,7 @@ static void _remove_alias(struct device *dev, const char *name)
* deactivated LV. Those old paths are all invalid and are dropped here.
*/
void dev_cache_verify_aliases(struct device *dev)
static void _verify_aliases(struct device *dev)
{
struct dm_str_list *strl, *strl2;
struct stat st;
@@ -1477,7 +1459,7 @@ static struct device *_dev_cache_get(struct cmd_context *cmd, const char *name,
_remove_alias(dev, name);
/* Remove any other names in dev->aliases that are incorrect. */
dev_cache_verify_aliases(dev);
_verify_aliases(dev);
}
return NULL;
}
@@ -1624,6 +1606,18 @@ static struct device *_dev_cache_get(struct cmd_context *cmd, const char *name,
return dev;
ret = f->passes_filter(cmd, f, dev, NULL);
/*
* This might happen if this function is called before
* filters can do i/o. I don't think this will happen
* any longer and this EAGAIN case can be removed.
*/
if (ret == -EAGAIN) {
log_debug_devs("dev_cache_get filter deferred %s", dev_name(dev));
dev->flags |= DEV_FILTER_AFTER_SCAN;
ret = 1;
}
if (!ret) {
log_debug_devs("dev_cache_get filter excludes %s", dev_name(dev));
return NULL;
@@ -1694,9 +1688,16 @@ struct device *dev_iter_get(struct cmd_context *cmd, struct dev_iter *iter)
f = iter->filter;
if (f && !(d->flags & DEV_REGULAR))
if (f && !(d->flags & DEV_REGULAR)) {
ret = f->passes_filter(cmd, f, d, NULL);
if (ret == -EAGAIN) {
log_debug_devs("get device by iter defer filter %s", dev_name(d));
d->flags |= DEV_FILTER_AFTER_SCAN;
ret = 1;
}
}
if (!f || (d->flags & DEV_REGULAR) || ret)
return d;
}
@@ -1881,15 +1882,6 @@ int setup_devices(struct cmd_context *cmd)
file_exists = devices_file_exists(cmd);
/*
* Fail if user specifies a file name that doesn't exist and
* the command is not creating a new devices file.
*/
if (!file_exists && !cmd->create_edit_devices_file && cmd->devicesfile && strlen(cmd->devicesfile)) {
log_error("Devices file not found: %s", cmd->devices_file_path);
return 0;
}
/*
* Removing the devices file is another way of disabling the use of
* a devices file, unless the command creates the devices file.
@@ -1937,9 +1929,10 @@ int setup_devices(struct cmd_context *cmd)
if (!file_exists) {
/*
* pvcreate/vgcreate create a new devices file here if it
* doesn't exist. They have create_edit_devices_file=1.
* First create/lock-ex the devices file lockfile.
* pvcreate/vgcreate/vgimportdevices/lvmdevices-add create
* a new devices file here if it doesn't exist.
* They have the create_edit_devices_file flag set.
* First they create/lock-ex the devices file lockfile.
* Other commands will not use a devices file if none exists.
*/
lock_mode = LOCK_EX;

View File

@@ -55,7 +55,6 @@ int dev_cache_add_dir(const char *path);
struct device *dev_cache_get(struct cmd_context *cmd, const char *name, struct dev_filter *f);
struct device *dev_cache_get_existing(struct cmd_context *cmd, const char *name, struct dev_filter *f);
struct device *dev_cache_get_by_devt(struct cmd_context *cmd, dev_t devt);
void dev_cache_verify_aliases(struct device *dev);
struct device *dev_hash_get(const char *name);
@@ -74,7 +73,6 @@ 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_sysfs_binary(const char *path, char *buf, size_t buf_size, int *retlen);
int get_dm_uuid_from_sysfs(char *buf, size_t buf_size, int major, int minor);
int setup_devices_file(struct cmd_context *cmd);

View File

@@ -23,6 +23,9 @@ int dev_is_luks(struct cmd_context *cmd, struct device *dev, uint64_t *offset_fo
char buf[LUKS_SIGNATURE_SIZE];
int ret = -1;
if (!scan_bcache)
return -EAGAIN;
if (offset_found)
*offset_found = 0;

View File

@@ -178,6 +178,12 @@ static int _dev_is_md_component_native(struct device *dev, uint64_t *offset_foun
uint64_t size, sb_offset = 0;
int ret;
/* 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;
return -1;

View File

@@ -17,14 +17,12 @@
#include "lib/activate/activate.h"
#include "lib/commands/toolcontext.h"
#include "lib/device/device_id.h"
#include "lib/datastruct/str_list.h"
#ifdef UDEV_SYNC_SUPPORT
#include <libudev.h>
#include "lib/device/dev-ext-udev-constants.h"
#endif
#include <dirent.h>
#include <ctype.h>
#define MPATH_PREFIX "mpath-"
@@ -37,175 +35,21 @@
* 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 *_wwid_mem;
static struct dm_pool *_hash_mem;
static struct dm_hash_table *_minor_hash_tab;
static struct dm_hash_table *_wwid_hash_tab;
static struct dm_list _ignored;
static struct dm_list _ignored_exceptions;
#define MAX_WWID_LINE 512
static void _read_blacklist_file(const char *path)
{
FILE *fp;
char line[MAX_WWID_LINE];
char wwid[MAX_WWID_LINE];
char *word, *p;
int section_black = 0;
int section_exceptions = 0;
int found_quote;
int found_type;
int i, j;
/*
* do we need to check the multipath.conf blacklist?
*/
if (!(fp = fopen(path, "r")))
return;
while (fgets(line, sizeof(line), fp)) {
word = NULL;
/* skip initial white space on the line */
for (i = 0; i < MAX_WWID_LINE; i++) {
if ((line[i] == '\n') || (line[i] == '\0'))
break;
if (isspace(line[i]))
continue;
word = &line[i];
break;
}
if (!word || word[0] == '#')
continue;
/* identify the start of the section we want to read */
if (strchr(word, '{')) {
if (!strncmp(word, "blacklist_exceptions", 20))
section_exceptions = 1;
else if (!strncmp(word, "blacklist", 9))
section_black = 1;
continue;
}
/* identify the end of the section we've been reading */
if (strchr(word, '}')) {
section_exceptions = 0;
section_black = 0;
continue;
}
/* skip lines that are not in a section we want */
if (!section_black && !section_exceptions)
continue;
/*
* read a wwid from the blacklist{_exceptions} section.
* does not recognize other non-wwid entries in the
* section, and skips those (should the entire mp
* config filtering be disabled if non-wwids are seen?
*/
if (!(p = strstr(word, "wwid")))
continue;
i += 4; /* skip "wwid" */
/*
* copy wwid value from the line.
* the wwids copied here need to match the
* wwids read from /etc/multipath/wwids,
* which are matched to wwids from sysfs.
*/
memset(wwid, 0, sizeof(wwid));
found_quote = 0;
found_type = 0;
j = 0;
for (; i < MAX_WWID_LINE; i++) {
if ((line[i] == '\n') || (line[i] == '\0'))
break;
if (!j && isspace(line[i]))
continue;
if (isspace(line[i]))
break;
/* quotes around wwid are optional */
if ((line[i] == '"') && !found_quote) {
found_quote = 1;
continue;
}
/* second quote is end of wwid */
if ((line[i] == '"') && found_quote)
break;
/* exclude initial 3/2/1 for naa/eui/t10 */
if (!j && !found_type &&
((line[i] == '3') || (line[i] == '2') || (line[i] == '1'))) {
found_type = 1;
continue;
}
wwid[j] = line[i];
j++;
}
if (j < 8)
continue;
log_debug("multipath wwid %s in %s %s",
wwid, section_exceptions ? "blacklist_exceptions" : "blacklist", path);
if (section_exceptions) {
if (!str_list_add(_wwid_mem, &_ignored_exceptions, dm_pool_strdup(_wwid_mem, wwid)))
stack;
} else {
if (!str_list_add(_wwid_mem, &_ignored, dm_pool_strdup(_wwid_mem, wwid)))
stack;
}
}
if (fclose(fp))
stack;
}
static void _read_wwid_exclusions(void)
{
char path[PATH_MAX] = { 0 };
DIR *dir;
struct dirent *de;
struct dm_str_list *sl, *sl2;
int rem_count = 0;
_read_blacklist_file("/etc/multipath.conf");
if ((dir = opendir("/etc/multipath/conf.d"))) {
while ((de = readdir(dir))) {
if (de->d_name[0] == '.')
continue;
snprintf(path, PATH_MAX-1, "/etc/multipath/conf.d/%s", de->d_name);
_read_blacklist_file(path);
}
closedir(dir);
}
/* for each wwid in ignored_exceptions, remove it from ignored */
dm_list_iterate_items_safe(sl, sl2, &_ignored) {
if (str_list_match_item(&_ignored_exceptions, sl->str))
str_list_del(&_ignored, sl->str);
}
/* for each wwid in ignored, remove it from wwid_hash */
dm_list_iterate_items(sl, &_ignored) {
dm_hash_remove_binary(_wwid_hash_tab, sl->str, strlen(sl->str));
rem_count++;
}
if (rem_count)
log_debug("multipath config ignored %d wwids", rem_count);
}
static void _read_wwid_file(const char *config_wwids_file, int *entries)
static void _read_wwid_file(const char *config_wwids_file)
{
FILE *fp;
char line[MAX_WWID_LINE];
char *wwid, *p;
char typestr[2] = { 0 };
int count = 0;
if (config_wwids_file[0] != '/') {
@@ -227,17 +71,8 @@ static void _read_wwid_file(const char *config_wwids_file, int *entries)
if (line[0] == '/')
wwid++;
/*
* the initial character is the id type,
* 1 is t10, 2 is eui, 3 is naa, 8 is scsi name.
* wwids are stored in the hash table without the type charater.
* It seems that sometimes multipath does not include
* the type charater (seen with t10 scsi_debug devs).
*/
typestr[0] = *wwid;
if (typestr[0] == '1' || typestr[0] == '2' || typestr[0] == '3')
wwid++;
/* skip the initial '3' */
wwid++;
if ((p = strchr(wwid, '/')))
*p = '\0';
@@ -250,7 +85,6 @@ static void _read_wwid_file(const char *config_wwids_file, int *entries)
stack;
log_debug("multipath wwids read %d from %s", count, config_wwids_file);
*entries = count;
}
int dev_mpath_init(const char *config_wwids_file)
@@ -258,10 +92,6 @@ 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;
int entries = 0;
dm_list_init(&_ignored);
dm_list_init(&_ignored_exceptions);
if (!(mem = dm_pool_create("mpath", 256))) {
log_error("mpath pool creation failed.");
@@ -274,7 +104,7 @@ int dev_mpath_init(const char *config_wwids_file)
return 0;
}
_wwid_mem = mem;
_hash_mem = mem;
_minor_hash_tab = minor_tab;
/* multipath_wwids_file="" disables the use of the file */
@@ -286,24 +116,16 @@ int dev_mpath_init(const char *config_wwids_file)
if (!(wwid_tab = dm_hash_create(110))) {
log_error("mpath hash table creation failed.");
dm_hash_destroy(_minor_hash_tab);
dm_pool_destroy(_wwid_mem);
dm_pool_destroy(_hash_mem);
_minor_hash_tab = NULL;
_wwid_mem = NULL;
_hash_mem = NULL;
return 0;
}
_wwid_hash_tab = wwid_tab;
if (config_wwids_file) {
_read_wwid_file(config_wwids_file, &entries);
_read_wwid_exclusions();
}
if (!entries) {
/* reading dev wwids is skipped with null wwid_hash_tab */
dm_hash_destroy(_wwid_hash_tab);
_wwid_hash_tab = NULL;
}
if (config_wwids_file)
_read_wwid_file(config_wwids_file);
return 1;
}
@@ -314,12 +136,12 @@ void dev_mpath_exit(void)
dm_hash_destroy(_minor_hash_tab);
if (_wwid_hash_tab)
dm_hash_destroy(_wwid_hash_tab);
if (_wwid_mem)
dm_pool_destroy(_wwid_mem);
if (_hash_mem)
dm_pool_destroy(_hash_mem);
_minor_hash_tab = NULL;
_wwid_hash_tab = NULL;
_wwid_mem = NULL;
_hash_mem = NULL;
}
@@ -450,12 +272,10 @@ static int _dev_is_mpath_component_udev(struct device *dev)
}
#endif
/* mpath_devno is major:minor of the dm multipath device currently using the component dev. */
static int _dev_is_mpath_component_sysfs(struct cmd_context *cmd, struct device *dev,
int primary_result, dev_t primary_dev, dev_t *mpath_devno)
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/" */
@@ -469,15 +289,25 @@ static int _dev_is_mpath_component_sysfs(struct cmd_context *cmd, struct device
int dm_dev_major;
int dm_dev_minor;
struct stat info;
dev_t primary_dev;
int is_mpath_component = 0;
switch (primary_result) {
/* 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. */
@@ -596,104 +426,50 @@ static int _dev_is_mpath_component_sysfs(struct cmd_context *cmd, struct device
if (closedir(dr))
stack;
if (is_mpath_component)
*mpath_devno = MKDEV(dm_dev_major, dm_dev_minor);
return is_mpath_component;
}
static int _dev_in_wwid_file(struct cmd_context *cmd, struct device *dev,
int primary_result, dev_t primary_dev)
static int _dev_in_wwid_file(struct cmd_context *cmd, struct device *dev)
{
char idbuf[DEV_WWID_SIZE] = { 0 };
struct dev_wwid *dw;
char *wwid, *full_wwid;
char sysbuf[PATH_MAX] = { 0 };
char *wwid;
long look;
if (!_wwid_hash_tab)
return 0;
/*
* Check the primary device, not the partition.
*/
if (primary_result == 2) {
if (!(dev = dev_cache_get_by_devt(cmd, primary_dev))) {
log_debug("dev_is_mpath_component %s no primary dev", dev_name(dev));
return 0;
}
}
if (!read_sys_block(cmd, dev, "device/wwid", sysbuf, sizeof(sysbuf)))
return 0;
/*
* sysfs wwid uses format: naa.<value>, eui.<value>, t10.<value>.
* multipath wwids file uses format: 3<value>, 2<value>, 1<value>.
*
* We omit the type prefix before looking up. The multipath/wwids
* values in the wwid_hash_tab have the initial character removed.
*
* There's no type prefix for "scsi name string" type 8 ids.
*
* First try looking up any wwids that have already been read.
*/
lookup:
dm_list_iterate_items(dw, &dev->wwids) {
if (dw->type == 1 || dw->type == 2 || dw->type == 3)
wwid = &dw->id[4];
else
wwid = dw->id;
if (dm_hash_lookup_binary(_wwid_hash_tab, wwid, strlen(wwid))) {
full_wwid = dw->id;
goto found;
}
}
/*
* The id from sysfs wwid may not be the id used by multipath,
* or a device may not have a vpd_pg83 file (e.g. nvme).
*/
if (!(dev->flags & DEV_ADDED_VPD_WWIDS) && dev_read_vpd_wwids(cmd, dev))
goto lookup;
if (!(dev->flags & DEV_ADDED_SYS_WWID) && dev_read_sys_wwid(cmd, dev, idbuf, sizeof(idbuf), &dw)) {
if (dw->type == 1 || dw->type == 2 || dw->type == 3)
wwid = &dw->id[4];
else
wwid = dw->id;
if (dm_hash_lookup_binary(_wwid_hash_tab, wwid, strlen(wwid))) {
full_wwid = dw->id;
goto found;
}
}
return 0;
found:
log_debug_devs("dev_is_mpath_component %s %s in wwids file", dev_name(dev), full_wwid);
return 1;
}
int dev_is_mpath_component(struct cmd_context *cmd, struct device *dev, dev_t *holder_devno)
{
struct dev_types *dt = cmd->dev_types;
int primary_result;
dev_t primary_dev;
/*
* multipath only uses SCSI or NVME devices
*/
if (!major_is_scsi_device(dt, MAJOR(dev->dev)) && !dev_is_nvme(dt, dev))
if (!sysbuf[0])
return 0;
/*
* primary_result 2: dev is a partition, primary_dev is the whole device
* primary_result 1: dev is a whole device
* sysfs prints wwid as <typestr>.<value>
* multipath wwid uses '3'<value>
* does "<typestr>." always correspond to "3"?
*/
primary_result = dev_get_primary_dev(dt, dev, &primary_dev);
if (!(wwid = strchr(sysbuf, '.')))
return 0;
if (_dev_is_mpath_component_sysfs(cmd, dev, primary_result, primary_dev, holder_devno) == 1)
/* 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, primary_result, primary_dev))
if (_dev_in_wwid_file(cmd, dev))
goto found;
if (external_device_info_source() == DEV_EXT_UDEV) {
@@ -701,12 +477,6 @@ int dev_is_mpath_component(struct cmd_context *cmd, struct device *dev, dev_t *h
goto found;
}
/*
* TODO: save the result of this function in dev->flags and use those
* flags on repeated calls to avoid repeating the work multiple times
* for the same device when there are partitions on the device.
*/
return 0;
found:
return 1;
@@ -725,7 +495,7 @@ const char *dev_mpath_component_wwid(struct cmd_context *cmd, struct device *dev
/* /sys/dev/block/253:7/slaves/sda/device/wwid */
if (dm_snprintf(slaves_path, sizeof(slaves_path), "%sdev/block/%d:%d/slaves",
if (dm_snprintf(slaves_path, sizeof(slaves_path), "%s/dev/block/%d:%d/slaves",
dm_sysfs_dir(), (int)MAJOR(dev->dev), (int)MINOR(dev->dev)) < 0) {
log_warn("Sysfs path to check mpath components is too long.");
return NULL;
@@ -755,7 +525,7 @@ const char *dev_mpath_component_wwid(struct cmd_context *cmd, struct device *dev
/* read /sys/block/sda/device/wwid */
if (dm_snprintf(wwid_path, sizeof(wwid_path), "%sblock/%s/device/wwid",
if (dm_snprintf(wwid_path, sizeof(wwid_path), "%s/block/%s/device/wwid",
dm_sysfs_dir(), slave_name) < 0) {
log_warn("Failed to create sysfs wwid path for %s", slave_name);
continue;

View File

@@ -42,6 +42,9 @@ int dev_is_swap(struct cmd_context *cmd, struct device *dev, uint64_t *offset_fo
unsigned page;
int ret = 0;
if (!scan_bcache)
return -EAGAIN;
if (!dev_get_size(dev, &size)) {
stack;
return -1;

View File

@@ -25,7 +25,7 @@
#include "device_mapper/misc/dm-ioctl.h"
#ifdef BLKID_WIPING_SUPPORT
#include <blkid/blkid.h>
#include <blkid.h>
#endif
#ifdef UDEV_SYNC_SUPPORT
@@ -548,7 +548,7 @@ static int _has_sys_partition(struct device *dev)
int minor = (int) MINOR(dev->dev);
/* check if dev is a partition */
if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d/partition",
if (dm_snprintf(path, sizeof(path), "%s/dev/block/%d:%d/partition",
dm_sysfs_dir(), major, minor) < 0) {
log_warn("WARNING: %s: partition path is too long.", dev_name(dev));
return 0;
@@ -674,6 +674,11 @@ static int _dev_is_partitioned_native(struct dev_types *dt, struct device *dev)
{
int r;
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))
return 1;
@@ -775,7 +780,7 @@ int dev_get_primary_dev(struct dev_types *dt, struct device *dev, dev_t *result)
* - basename ../../block/md0/md0 = md0
* Parent's 'dev' sysfs attribute = /sys/block/md0/dev
*/
if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d",
if (dm_snprintf(path, sizeof(path), "%s/dev/block/%d:%d",
dm_sysfs_dir(), major, minor) < 0) {
log_warn("WARNING: %s: major:minor sysfs path is too long.", dev_name(dev));
return 0;
@@ -787,7 +792,7 @@ int dev_get_primary_dev(struct dev_types *dt, struct device *dev, dev_t *result)
temp_path[size] = '\0';
if (dm_snprintf(path, sizeof(path), "%sblock/%s/dev",
if (dm_snprintf(path, sizeof(path), "%s/block/%s/dev",
dm_sysfs_dir(), basename(dirname(temp_path))) < 0) {
log_warn("WARNING: sysfs path for %s is too long.",
basename(dirname(temp_path)));
@@ -823,143 +828,26 @@ out:
}
#ifdef BLKID_WIPING_SUPPORT
int fs_block_size_and_type(const char *pathname, uint32_t *fs_block_size_bytes, char *fstype, int *nofs)
int get_fs_block_size(const char *pathname, uint32_t *fs_block_size)
{
blkid_probe probe = NULL;
const char *type_str = NULL, *size_str = NULL;
size_t len;
int ret = 1;
int rc;
char *block_size_str = NULL;
if (!(probe = blkid_new_probe_from_filename(pathname))) {
log_error("Failed libblkid probe setup for %s", pathname);
return 0;
}
blkid_probe_enable_superblocks(probe, 1);
blkid_probe_set_superblocks_flags(probe,
BLKID_SUBLKS_LABEL | BLKID_SUBLKS_LABELRAW |
BLKID_SUBLKS_UUID | BLKID_SUBLKS_UUIDRAW |
BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE |
BLKID_SUBLKS_USAGE | BLKID_SUBLKS_VERSION |
#ifdef BLKID_SUBLKS_FSINFO
BLKID_SUBLKS_FSINFO |
#endif
BLKID_SUBLKS_MAGIC);
rc = blkid_do_safeprobe(probe);
if (rc < 0) {
log_debug("Failed libblkid probe for %s", pathname);
ret = 0;
goto out;
} else if (rc == 1) {
/* no file system on the device */
log_debug("No file system found on %s.", pathname);
if (nofs)
*nofs = 1;
goto out;
}
if (!blkid_probe_lookup_value(probe, "TYPE", &type_str, &len) && len && type_str) {
if (fstype)
strncpy(fstype, type_str, FSTYPE_MAX);
if ((block_size_str = blkid_get_tag_value(NULL, "BLOCK_SIZE", pathname))) {
*fs_block_size = (uint32_t)atoi(block_size_str);
free(block_size_str);
log_debug("Found blkid BLOCK_SIZE %u for fs on %s", *fs_block_size, pathname);
return 1;
} else {
/* any difference from blkid_do_safeprobe rc=1? */
log_debug("No file system type on %s.", pathname);
if (nofs)
*nofs = 1;
goto out;
}
if (fs_block_size_bytes) {
if (!blkid_probe_lookup_value(probe, "BLOCK_SIZE", &size_str, &len) && len && size_str)
*fs_block_size_bytes = atoi(size_str);
else
*fs_block_size_bytes = 0;
}
log_debug("Found blkid fstype %s fsblocksize %s on %s",
type_str ?: "none", size_str ?: "unused", pathname);
out:
blkid_free_probe(probe);
return ret;
}
int fs_get_blkid(const char *pathname, struct fs_info *fsi)
{
blkid_probe probe = NULL;
const char *str;
size_t len;
uint64_t fslastblock = 0;
unsigned int fsblocksize = 0;
int rc;
if (!(probe = blkid_new_probe_from_filename(pathname))) {
log_error("Failed libblkid probe setup for %s", pathname);
log_debug("No blkid BLOCK_SIZE for fs on %s", pathname);
*fs_block_size = 0;
return 0;
}
blkid_probe_enable_superblocks(probe, 1);
blkid_probe_set_superblocks_flags(probe,
BLKID_SUBLKS_LABEL | BLKID_SUBLKS_LABELRAW |
BLKID_SUBLKS_UUID | BLKID_SUBLKS_UUIDRAW |
BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE |
BLKID_SUBLKS_USAGE | BLKID_SUBLKS_VERSION |
#ifdef BLKID_SUBLKS_FSINFO
BLKID_SUBLKS_FSINFO |
#endif
BLKID_SUBLKS_MAGIC);
rc = blkid_do_safeprobe(probe);
if (rc < 0) {
log_error("Failed libblkid probe for %s", pathname);
blkid_free_probe(probe);
return 0;
} else if (rc == 1) {
/* no file system on the device */
log_print("No file system found on %s.", pathname);
fsi->nofs = 1;
blkid_free_probe(probe);
return 1;
}
if (!blkid_probe_lookup_value(probe, "TYPE", &str, &len) && len)
strncpy(fsi->fstype, str, sizeof(fsi->fstype)-1);
else {
/* any difference from blkid_do_safeprobe rc=1? */
log_print("No file system type on %s.", pathname);
fsi->nofs = 1;
blkid_free_probe(probe);
return 1;
}
if (!blkid_probe_lookup_value(probe, "BLOCK_SIZE", &str, &len) && len)
fsi->fs_block_size_bytes = atoi(str);
if (!blkid_probe_lookup_value(probe, "FSLASTBLOCK", &str, &len) && len)
fslastblock = strtoull(str, NULL, 0);
if (!blkid_probe_lookup_value(probe, "FSBLOCKSIZE", &str, &len) && len)
fsblocksize = (unsigned int)atoi(str);
blkid_free_probe(probe);
if (fslastblock && fsblocksize)
fsi->fs_last_byte = fslastblock * fsblocksize;
log_debug("libblkid TYPE %s BLOCK_SIZE %d FSLASTBLOCK %llu FSBLOCKSIZE %u fs_last_byte %llu",
fsi->fstype, fsi->fs_block_size_bytes, (unsigned long long)fslastblock, fsblocksize,
(unsigned long long)fsi->fs_last_byte);
return 1;
}
#else
int fs_block_size_and_type(const char *pathname, uint32_t *fs_block_size_bytes, char *fstype, int *nofs)
int get_fs_block_size(const char *pathname, uint32_t *fs_block_size)
{
log_debug("Disabled blkid BLOCK_SIZE for fs.");
return 0;
}
int fs_get_blkid(const char *pathname, struct fs_info *fsi)
{
log_debug("Disabled blkid for fs info.");
*fs_block_size = 0;
return 0;
}
#endif
@@ -1212,7 +1100,7 @@ int wipe_known_signatures(struct cmd_context *cmd, struct device *dev,
static int _snprintf_attr(char *buf, size_t buf_size, const char *sysfs_dir,
const char *attribute, dev_t dev)
{
if (dm_snprintf(buf, buf_size, "%sdev/block/%d:%d/%s", sysfs_dir,
if (dm_snprintf(buf, buf_size, "%s/dev/block/%d:%d/%s", sysfs_dir,
(int)MAJOR(dev), (int)MINOR(dev),
attribute) < 0) {
log_warn("WARNING: sysfs path for %s attribute is too long.", attribute);

View File

@@ -18,7 +18,6 @@
#include "lib/device/device.h"
#include "lib/display/display.h"
#include "lib/label/label.h"
#include "lib/device/filesystem.h"
#define NUMBER_OF_MAJORS 4096
@@ -59,7 +58,7 @@ 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 cmd_context *cmd, struct device *dev, uint64_t *sb, int full);
int dev_is_mpath_component(struct cmd_context *cmd, struct device *dev, dev_t *mpath_devno);
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);
@@ -102,9 +101,7 @@ int dev_is_nvme(struct dev_types *dt, struct device *dev);
int dev_is_lv(struct device *dev);
#define FSTYPE_MAX 16
int fs_block_size_and_type(const char *pathname, uint32_t *fs_block_size_bytes, char *fstype, int *nofs);
int fs_get_blkid(const char *pathname, struct fs_info *fsi);
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);

View File

@@ -1,66 +0,0 @@
/*
* Copyright (C) 2013 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/device/device.h"
int device_id_list_remove(struct dm_list *list, struct device *dev)
{
struct device_id_list *dil;
dm_list_iterate_items(dil, list) {
if (dil->dev == dev) {
dm_list_del(&dil->list);
return 1;
}
}
return 0;
}
struct device_id_list *device_id_list_find_dev(struct dm_list *list, struct device *dev)
{
struct device_id_list *dil;
dm_list_iterate_items(dil, list) {
if (dil->dev == dev)
return dil;
}
return NULL;
}
int device_list_remove(struct dm_list *list, struct device *dev)
{
struct device_list *devl;
dm_list_iterate_items(devl, list) {
if (devl->dev == dev) {
dm_list_del(&devl->list);
return 1;
}
}
return 0;
}
struct device_list *device_list_find_dev(struct dm_list *list, struct device *dev)
{
struct device_list *devl;
dm_list_iterate_items(devl, list) {
if (devl->dev == dev)
return devl;
}
return NULL;
}

View File

@@ -32,8 +32,8 @@
#define DEV_NOT_O_NOATIME 0x00000400 /* Don't use O_NOATIME */
#define DEV_IN_BCACHE 0x00000800 /* dev fd is open and used in bcache */
#define DEV_BCACHE_EXCL 0x00001000 /* bcache_fd should be open EXCL */
#define DEV_ADDED_SYS_WWID 0x00002000 /* wwid has been added from sysfs wwid file */
#define DEV_ADDED_VPD_WWIDS 0x00004000 /* wwids have been added from vpd_pg83 */
#define DEV_FILTER_AFTER_SCAN 0x00002000 /* apply filter after bcache has data */
#define DEV_FILTER_OUT_SCAN 0x00004000 /* filtered out during label scan */
#define DEV_BCACHE_WRITE 0x00008000 /* bcache_fd is open with RDWR */
#define DEV_SCAN_FOUND_LABEL 0x00010000 /* label scan read dev and found label */
#define DEV_IS_MD_COMPONENT 0x00020000 /* device is an md component */
@@ -59,33 +59,14 @@ struct dev_ext {
void *handle;
};
#define DEV_ID_TYPE_SYS_WWID 1
#define DEV_ID_TYPE_SYS_SERIAL 2
#define DEV_ID_TYPE_MPATH_UUID 3
#define DEV_ID_TYPE_MD_UUID 4
#define DEV_ID_TYPE_LOOP_FILE 5
#define DEV_ID_TYPE_CRYPT_UUID 6
#define DEV_ID_TYPE_LVMLV_UUID 7
#define DEV_ID_TYPE_DEVNAME 8
#define DEV_ID_TYPE_WWID_NAA 9
#define DEV_ID_TYPE_WWID_EUI 10
#define DEV_ID_TYPE_WWID_T10 11
/* Max length of WWID_NAA, WWID_EUI, WWID_T10 */
#define DEV_WWID_SIZE 128
/*
* A wwid read from:
* /sys/dev/block/%d:%d/device/wwid
* /sys/dev/block/%d:%d/wwid
* /sys/dev/block/%d:%d/device/vpd_pg83
*/
struct dev_wwid {
struct dm_list list; /* dev->wwids */
int type; /* 1,2,3 for NAA,EUI,T10 */
char id[DEV_WWID_SIZE]; /* includes prefix naa.,eui.,t10. */
};
#define DEV_ID_TYPE_SYS_WWID 0x0001
#define DEV_ID_TYPE_SYS_SERIAL 0x0002
#define DEV_ID_TYPE_MPATH_UUID 0x0003
#define DEV_ID_TYPE_MD_UUID 0x0004
#define DEV_ID_TYPE_LOOP_FILE 0x0005
#define DEV_ID_TYPE_CRYPT_UUID 0x0006
#define DEV_ID_TYPE_LVMLV_UUID 0x0007
#define DEV_ID_TYPE_DEVNAME 0x0008
/*
* A device ID of a certain type for a device.
@@ -94,7 +75,7 @@ struct dev_wwid {
*/
struct dev_id {
struct dm_list list; /* dev->ids */
struct dm_list list;
struct device *dev;
uint16_t idtype; /* DEV_ID_TYPE_ */
char *idname; /* id string determined by idtype */
@@ -118,18 +99,12 @@ struct dev_use {
char *pvid;
};
struct dev_use_list {
struct dm_list list;
struct dev_use *du;
};
/*
* All devices in LVM will be represented by one of these.
* pointer comparisons are valid.
*/
struct device {
struct dm_list aliases; /* struct dm_str_list */
struct dm_list wwids; /* struct dev_wwid, used for multipath component detection */
struct dm_list ids; /* struct dev_id, different entries for different idtypes */
struct dev_id *id; /* points to the the ids entry being used for this dev */
dev_t dev;
@@ -179,12 +154,6 @@ struct device_list {
struct device *dev;
};
struct device_id_list {
struct dm_list list;
struct device *dev;
char pvid[ID_LEN + 1];
};
struct device_area {
struct device *dev;
uint64_t start; /* Bytes */
@@ -237,14 +206,5 @@ void dev_destroy_file(struct device *dev);
int dev_mpath_init(const char *config_wwids_file);
void dev_mpath_exit(void);
int parse_vpd_ids(const unsigned char *vpd_data, int vpd_datalen, struct dm_list *ids);
int format_t10_id(const unsigned char *in, int in_bytes, unsigned char *out, int out_bytes);
int parse_vpd_serial(const unsigned char *in, char *out, int outsize);
/* dev_util */
int device_id_list_remove(struct dm_list *devices, struct device *dev);
struct device_id_list *device_id_list_find_dev(struct dm_list *devices, struct device *dev);
int device_list_remove(struct dm_list *devices, struct device *dev);
struct device_list *device_list_find_dev(struct dm_list *devices, struct device *dev);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -28,23 +28,20 @@ int device_ids_use_devname(struct cmd_context *cmd);
int device_ids_read(struct cmd_context *cmd);
int device_ids_write(struct cmd_context *cmd);
int device_id_add(struct cmd_context *cmd, struct device *dev, const char *pvid,
const char *idtype_arg, const char *id_arg, int use_idtype_only);
const char *idtype_arg, const char *id_arg);
void device_id_pvremove(struct cmd_context *cmd, struct device *dev);
void device_ids_match(struct cmd_context *cmd);
int device_ids_match_dev(struct cmd_context *cmd, struct device *dev);
void device_ids_match_device_list(struct cmd_context *cmd);
void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs, int *device_ids_invalid, int noupdate);
int device_ids_version_unchanged(struct cmd_context *cmd);
void device_ids_check_serial(struct cmd_context *cmd, struct dm_list *scan_devs, int *update_needed, int noupdate);
void device_ids_find_renamed_devs(struct cmd_context *cmd, struct dm_list *dev_list, int *search_count, int noupdate);
const char *device_id_system_read(struct cmd_context *cmd, struct device *dev, uint16_t idtype);
void device_id_update_vg_uuid(struct cmd_context *cmd, struct volume_group *vg, struct id *old_vg_id);
struct dev_use *get_du_for_devno(struct cmd_context *cmd, dev_t devno);
struct dev_use *get_du_for_dev(struct cmd_context *cmd, struct device *dev);
struct dev_use *get_du_for_pvid(struct cmd_context *cmd, const char *pvid);
struct dev_use *get_du_for_devname(struct cmd_context *cmd, const char *devname);
struct dev_use *get_du_for_device_id(struct cmd_context *cmd, uint16_t idtype, const char *idname);
char *devices_file_version(void);
int devices_file_exists(struct cmd_context *cmd);
@@ -59,17 +56,7 @@ 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);
int read_sys_block_binary(struct cmd_context *cmd, struct device *dev,
const char *suffix, char *sysbuf, int sysbufsize, int *retlen);
int dev_has_mpath_uuid(struct cmd_context *cmd, struct device *dev, const char **idname_out);
int wwid_type_to_idtype(int wwid_type);
int idtype_to_wwid_type(int idtype);
void free_wwids(struct dm_list *ids);
struct dev_wwid *dev_add_wwid(char *id, int id_type, struct dm_list *ids);
int dev_read_vpd_wwids(struct cmd_context *cmd, struct device *dev);
int dev_read_sys_wwid(struct cmd_context *cmd, struct device *dev,
char *buf, int bufsize, struct dev_wwid **dw_out);
#endif

View File

@@ -1,548 +0,0 @@
/*
* Copyright (C) 2022 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "base/memory/zalloc.h"
#include "lib/misc/lib.h"
#include "lib/commands/toolcontext.h"
#include "lib/device/device.h"
#include "lib/device/dev-type.h"
#include "lib/misc/lvm-exec.h"
#include "lib/activate/dev_manager.h"
#include <dirent.h>
#include <mntent.h>
#include <sys/ioctl.h>
static const char *_lvresize_fs_helper_path;
static const char *_get_lvresize_fs_helper_path(void)
{
if (!_lvresize_fs_helper_path)
_lvresize_fs_helper_path = getenv("LVRESIZE_FS_HELPER_PATH");
if (!_lvresize_fs_helper_path)
_lvresize_fs_helper_path = LVRESIZE_FS_HELPER_PATH; /* from configure, usually in /usr/libexec */
return _lvresize_fs_helper_path;
}
/*
* Set the path of the dm-crypt device, i.e. /dev/dm-N, that is using the LV.
*/
static int _get_crypt_path(dev_t lv_devt, char *lv_path, char *crypt_path)
{
char holders_path[PATH_MAX];
char *holder_name;
DIR *dr;
struct stat st;
struct dirent *de;
int ret = 0;
if (dm_snprintf(holders_path, sizeof(holders_path), "%sdev/block/%d:%d/holders",
dm_sysfs_dir(), (int)MAJOR(lv_devt), (int)MINOR(lv_devt)) < 0)
return_0;
/* If the crypt dev is not active, there will be no LV holder. */
if (stat(holders_path, &st)) {
log_error("Missing %s for %s", crypt_path, lv_path);
return 0;
}
if (!(dr = opendir(holders_path))) {
log_error("Cannot open %s", holders_path);
return 0;
}
while ((de = readdir(dr))) {
if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
continue;
holder_name = de->d_name;
if (strncmp(holder_name, "dm", 2)) {
log_error("Unrecognized holder %s of %s", holder_name, lv_path);
ret = 0;
break;
}
/* We could read the holder's dm uuid to verify it's a crypt dev. */
if (dm_snprintf(crypt_path, PATH_MAX, "/dev/%s", holder_name) < 0) {
ret = 0;
stack;
break;
}
ret = 1;
break;
}
closedir(dr);
if (ret)
log_debug("Found holder %s of %s.", crypt_path, lv_path);
else
log_debug("No holder in %s", holders_path);
return ret;
}
int lv_crypt_is_active(struct cmd_context *cmd, char *lv_path)
{
char crypt_path[PATH_MAX];
struct stat st_lv;
if (stat(lv_path, &st_lv) < 0) {
log_error("Failed to get LV path %s", lv_path);
return 0;
}
return _get_crypt_path(st_lv.st_rdev, lv_path, crypt_path);
}
int fs_get_info(struct cmd_context *cmd, struct logical_volume *lv,
struct fs_info *fsi, int include_mount)
{
char lv_path[PATH_MAX];
char crypt_path[PATH_MAX];
struct stat st_lv;
struct stat st_crypt;
struct stat st_top;
struct stat stme;
struct fs_info info;
FILE *fme = NULL;
struct mntent *me;
int fd;
int ret;
if (dm_snprintf(lv_path, PATH_MAX, "%s%s/%s", lv->vg->cmd->dev_dir,
lv->vg->name, lv->name) < 0) {
log_error("Couldn't create LV path for %s.", display_lvname(lv));
return 0;
}
if (stat(lv_path, &st_lv) < 0) {
log_error("Failed to get LV path %s", lv_path);
return 0;
}
memset(&info, 0, sizeof(info));
if (!fs_get_blkid(lv_path, &info)) {
log_error("No file system info from blkid for %s", display_lvname(lv));
return 0;
}
if (fsi->nofs)
return 1;
/*
* If there's a LUKS dm-crypt layer over the LV, then
* return fs info from that layer, setting needs_crypt
* to indicate a crypt layer between the fs and LV.
*/
if (!strcmp(info.fstype, "crypto_LUKS")) {
if (!_get_crypt_path(st_lv.st_rdev, lv_path, crypt_path)) {
log_error("Cannot find active LUKS dm-crypt device using %s.",
display_lvname(lv));
return 0;
}
if (stat(crypt_path, &st_crypt) < 0) {
log_error("Failed to get crypt path %s", crypt_path);
return 0;
}
memset(&info, 0, sizeof(info));
log_print("Checking crypt device %s on LV %s.",
crypt_path, display_lvname(lv));
if ((fd = open(crypt_path, O_RDONLY)) < 0) {
log_error("Failed to open crypt path %s", crypt_path);
return 0;
}
if (ioctl(fd, BLKGETSIZE64, &info.crypt_dev_size_bytes) < 0) {
log_error("Failed to get crypt device size %s", crypt_path);
close(fd);
return 0;
}
close(fd);
if (!fs_get_blkid(crypt_path, &info)) {
log_error("No file system info from blkid for dm-crypt device %s on LV %s.",
crypt_path, display_lvname(lv));
return 0;
}
*fsi = info;
fsi->needs_crypt = 1;
fsi->crypt_devt = st_crypt.st_rdev;
memcpy(fsi->fs_dev_path, crypt_path, PATH_MAX);
st_top = st_crypt;
if (!get_crypt_table_offset(st_crypt.st_rdev, &fsi->crypt_offset_bytes)) {
log_error("Failed to get crypt data offset.");
return 0;
}
} else {
*fsi = info;
memcpy(fsi->fs_dev_path, lv_path, PATH_MAX);
st_top = st_lv;
}
if (!include_mount)
return 1;
if (!(fme = setmntent("/etc/mtab", "r")))
return_0;
ret = 1;
while ((me = getmntent(fme))) {
if (strcmp(me->mnt_type, fsi->fstype))
continue;
if (me->mnt_dir[0] != '/')
continue;
if (me->mnt_fsname[0] != '/')
continue;
if (stat(me->mnt_dir, &stme) < 0)
continue;
if (stme.st_dev != st_top.st_rdev)
continue;
log_debug("fs_get_info %s is mounted \"%s\"", fsi->fs_dev_path, me->mnt_dir);
fsi->mounted = 1;
strncpy(fsi->mount_dir, me->mnt_dir, PATH_MAX-1);
}
endmntent(fme);
fsi->unmounted = !fsi->mounted;
return ret;
}
int fs_mount_state_is_misnamed(struct cmd_context *cmd, struct logical_volume *lv, char *lv_path, char *fstype)
{
FILE *fp;
char proc_line[PATH_MAX];
char proc_fstype[FSTYPE_MAX];
char proc_devpath[1024];
char proc_mntpath[1024];
char lv_mapper_path[1024];
char mntent_mount_dir[1024];
char *dm_name;
struct stat st_lv;
struct stat stme;
FILE *fme = NULL;
struct mntent *me;
int renamed = 0;
int found_dir = 0;
int found_dev = 0;
int dev_match, dir_match;
if (stat(lv_path, &st_lv) < 0) {
log_error("Failed to get LV path %s", lv_path);
return 0;
}
/*
* If LVs have been renamed while their file systems were mounted, then
* inconsistencies appear in the device path and mount point info
* provided by getmntent and /proc/mounts. If there's any
* inconsistency or duplication of info for the LV name or the mount
* point, then give up and don't try fs resize which is likely to fail
* due to kernel problems where mounts reference old device names
* causing fs resizing tools to fail.
*/
if (!(fme = setmntent("/etc/mtab", "r")))
return_0;
while ((me = getmntent(fme))) {
if (strcmp(me->mnt_type, fstype))
continue;
if (me->mnt_dir[0] != '/')
continue;
if (me->mnt_fsname[0] != '/')
continue;
if (stat(me->mnt_dir, &stme) < 0)
continue;
if (stme.st_dev != st_lv.st_rdev)
continue;
strncpy(mntent_mount_dir, me->mnt_dir, PATH_MAX-1);
}
endmntent(fme);
if (!(dm_name = dm_build_dm_name(cmd->mem, lv->vg->name, lv->name, NULL)))
return_0;
if ((dm_snprintf(lv_mapper_path, 1024, "%s/%s", dm_dir(), dm_name) < 0))
return_0;
if (!(fp = fopen("/proc/mounts", "r")))
return_0;
while (fgets(proc_line, sizeof(proc_line), fp)) {
if (proc_line[0] != '/')
continue;
if (sscanf(proc_line, "%s %s %s", proc_devpath, proc_mntpath, proc_fstype) != 3)
continue;
if (strcmp(fstype, proc_fstype))
continue;
dir_match = !strcmp(mntent_mount_dir, proc_mntpath);
dev_match = !strcmp(lv_mapper_path, proc_devpath);
if (dir_match)
found_dir++;
if (dev_match)
found_dev++;
if (dir_match != dev_match) {
log_error("LV %s mounted at %s may have been renamed (from %s).",
lv_mapper_path, proc_mntpath, proc_devpath);
renamed = 1;
}
}
if (fclose(fp))
stack;
/*
* Don't try resizing if:
* - different device names apppear for the mount point
* (LVs probably renamed while mounted), or
* - the mount point for the LV appears multiple times, or
* - the LV device is listed for multiple mounts.
*/
if (renamed) {
log_error("File system resizing not supported: fs utilities do not support renamed devices.");
return 1;
}
/* These two are likely detected as renamed, but include checks in case. */
if (found_dir > 1) {
log_error("File system resizing not supported: %s appears more than once in /proc/mounts.", mntent_mount_dir);
return 1;
}
if (found_dev > 1) {
log_error("File system resizing not supported: %s appears more than once in /proc/mounts.", lv_mapper_path);
return 1;
}
return 0;
}
#define FS_CMD_MAX_ARGS 16
int crypt_resize_script(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi,
uint64_t newsize_bytes_fs)
{
char crypt_path[PATH_MAX];
char newsize_str[16] = { 0 };
const char *argv[FS_CMD_MAX_ARGS + 4];
int args = 0;
int status;
if (dm_snprintf(newsize_str, sizeof(newsize_str), "%llu", (unsigned long long)newsize_bytes_fs) < 0)
return_0;
if (dm_snprintf(crypt_path, sizeof(crypt_path), "/dev/dm-%d", (int)MINOR(fsi->crypt_devt)) < 0)
return_0;
argv[0] = _get_lvresize_fs_helper_path();
argv[++args] = "--cryptresize";
argv[++args] = "--cryptpath";
argv[++args] = crypt_path;
argv[++args] = "--newsizebytes";
argv[++args] = newsize_str;
argv[++args] = NULL;
if (!exec_cmd(cmd, argv, &status, 1)) {
log_error("Failed to resize crypt dev with lvresize_fs_helper.");
return 0;
}
return 1;
}
/*
* The helper script does the following steps for reduce:
* devpath = $cryptpath ? $cryptpath : $lvpath
* if needs_unmount
* umount $mountdir
* if needs_fsck
* e2fsck -f -p $devpath
* if needs_mount
* mount $devpath $tmpdir
* if $fstype == "ext"
* resize2fs $devpath $newsize_kb
* if needs_crypt
* cryptsetup resize --size $newsize_sectors $cryptpath
*
* Note: when a crypt layer is included, newsize_bytes_fs is smaller
* than newsize_bytes_lv because of the crypt header.
*/
int fs_reduce_script(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi,
uint64_t newsize_bytes_fs, char *fsmode)
{
char lv_path[PATH_MAX];
char crypt_path[PATH_MAX];
char newsize_str[16] = { 0 };
const char *argv[FS_CMD_MAX_ARGS + 4];
char *devpath;
int args = 0;
int status;
if (dm_snprintf(newsize_str, sizeof(newsize_str), "%llu", (unsigned long long)newsize_bytes_fs) < 0)
return_0;
if (dm_snprintf(lv_path, PATH_MAX, "%s%s/%s", lv->vg->cmd->dev_dir, lv->vg->name, lv->name) < 0)
return_0;
argv[0] = _get_lvresize_fs_helper_path();
argv[++args] = "--fsreduce";
argv[++args] = "--fstype";
argv[++args] = fsi->fstype;
argv[++args] = "--lvpath";
argv[++args] = lv_path;
if (newsize_bytes_fs) {
argv[++args] = "--newsizebytes";
argv[++args] = newsize_str;
}
if (fsi->mounted) {
argv[++args] = "--mountdir";
argv[++args] = fsi->mount_dir;
}
if (fsi->needs_unmount)
argv[++args] = "--unmount";
if (fsi->needs_mount)
argv[++args] = "--mount";
if (fsi->needs_fsck)
argv[++args] = "--fsck";
if (fsi->needs_crypt) {
if (dm_snprintf(crypt_path, sizeof(crypt_path), "/dev/dm-%d", (int)MINOR(fsi->crypt_devt)) < 0)
return_0;
argv[++args] = "--cryptresize";
argv[++args] = "--cryptpath";
argv[++args] = crypt_path;
}
/*
* fsmode manage means the fs should be remounted after
* resizing if it was unmounted.
*/
if (fsi->needs_unmount && !strcmp(fsmode, "manage"))
argv[++args] = "--remount";
argv[++args] = NULL;
devpath = fsi->needs_crypt ? crypt_path : (char *)display_lvname(lv);
log_print("Reducing file system %s to %s (%llu bytes) on %s...",
fsi->fstype, display_size(cmd, newsize_bytes_fs/512),
(unsigned long long)newsize_bytes_fs, devpath);
if (!exec_cmd(cmd, argv, &status, 1)) {
log_error("Failed to reduce file system with lvresize_fs_helper.");
return 0;
}
log_print("Reduced file system %s on %s.", fsi->fstype, devpath);
return 1;
}
/*
* The helper script does the following steps for extend:
* devpath = $cryptpath ? $cryptpath : $lvpath
* if needs_unmount
* umount $mountdir
* if needs_fsck
* e2fsck -f -p $devpath
* if needs_crypt
* cryptsetup resize $cryptpath
* if needs_mount
* mount $devpath $tmpdir
* if $fstype == "ext"
* resize2fs $devpath
* if $fstype == "xfs"
* xfs_growfs $devpath
*
* Note: when a crypt layer is included, newsize_bytes_fs is smaller
* than newsize_bytes_lv because of the crypt header.
*/
int fs_extend_script(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi,
uint64_t newsize_bytes_fs, char *fsmode)
{
char lv_path[PATH_MAX];
char crypt_path[PATH_MAX];
const char *argv[FS_CMD_MAX_ARGS + 4];
char *devpath;
int args = 0;
int status;
if (dm_snprintf(lv_path, PATH_MAX, "%s%s/%s", lv->vg->cmd->dev_dir, lv->vg->name, lv->name) < 0)
return_0;
argv[0] = _get_lvresize_fs_helper_path();
argv[++args] = "--fsextend";
argv[++args] = "--fstype";
argv[++args] = fsi->fstype;
argv[++args] = "--lvpath";
argv[++args] = lv_path;
if (fsi->mounted) {
argv[++args] = "--mountdir";
argv[++args] = fsi->mount_dir;
}
if (fsi->needs_unmount)
argv[++args] = "--unmount";
if (fsi->needs_mount)
argv[++args] = "--mount";
if (fsi->needs_fsck)
argv[++args] = "--fsck";
if (fsi->needs_crypt) {
if (dm_snprintf(crypt_path, sizeof(crypt_path), "/dev/dm-%d", (int)MINOR(fsi->crypt_devt)) < 0)
return_0;
argv[++args] = "--cryptresize";
argv[++args] = "--cryptpath";
argv[++args] = crypt_path;
}
/*
* fsmode manage means the fs should be remounted after
* resizing if it was unmounted.
*/
if (fsi->needs_unmount && !strcmp(fsmode, "manage"))
argv[++args] = "--remount";
argv[++args] = NULL;
devpath = fsi->needs_crypt ? crypt_path : (char *)display_lvname(lv);
log_print("Extending file system %s to %s (%llu bytes) on %s...",
fsi->fstype, display_size(cmd, newsize_bytes_fs/512),
(unsigned long long)newsize_bytes_fs, devpath);
if (!exec_cmd(cmd, argv, &status, 1)) {
log_error("Failed to extend file system with lvresize_fs_helper.");
return 0;
}
log_print("Extended file system %s on %s.", fsi->fstype, devpath);
return 1;
}

View File

@@ -1,55 +0,0 @@
/*
* Copyright (C) 2022 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _FILESYSTEM_H
#define _FILESYSTEM_H
#define FSTYPE_MAX 16
struct fs_info {
char fstype[FSTYPE_MAX];
char mount_dir[PATH_MAX];
char fs_dev_path[PATH_MAX]; /* usually lv dev, can be crypt dev */
unsigned int fs_block_size_bytes; /* 512 or 4k */
uint64_t fs_last_byte; /* last byte on the device used by the fs */
uint32_t crypt_offset_bytes; /* offset in bytes of crypt data on LV */
dev_t crypt_devt; /* dm-crypt device between the LV and FS */
uint64_t crypt_dev_size_bytes;
unsigned nofs:1;
unsigned unmounted:1;
unsigned mounted:1;
/* for resizing */
unsigned needs_reduce:1;
unsigned needs_extend:1;
unsigned needs_fsck:1;
unsigned needs_unmount:1;
unsigned needs_mount:1;
unsigned needs_crypt:1;
};
int fs_get_info(struct cmd_context *cmd, struct logical_volume *lv,
struct fs_info *fsi, int include_mount);
int fs_extend_script(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi,
uint64_t newsize_bytes, char *fsmode);
int fs_reduce_script(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi,
uint64_t newsize_bytes, char *fsmode);
int crypt_resize_script(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi,
uint64_t newsize_bytes_fs);
int fs_mount_state_is_misnamed(struct cmd_context *cmd, struct logical_volume *lv, char *lv_path, char *fstype);
int lv_crypt_is_active(struct cmd_context *cmd, char *lv_path);
#endif

View File

@@ -16,6 +16,7 @@
#include "lib/misc/lib.h"
#include "lib/commands/toolcontext.h"
#include "lib/device/device.h"
#include "lib/device/device_id.h"
#include "lib/device/online.h"
#include <dirent.h>
@@ -504,58 +505,3 @@ do_lookup:
if ((rv < 0) && stat(PVS_LOOKUP_DIR, &st))
log_error_pvscan(cmd, "Failed to create %s %d", PVS_LOOKUP_DIR, errno);
}
void online_lookup_file_remove(const char *vgname)
{
char path[PATH_MAX];
if (dm_snprintf(path, sizeof(path), "%s/%s", PVS_LOOKUP_DIR, vgname) < 0) {
log_error("Path %s/%s is too long.", PVS_LOOKUP_DIR, vgname);
return;
}
log_debug("Unlink pvs_lookup: %s", path);
if (unlink(path) && (errno != ENOENT))
log_sys_debug("unlink", path);
}
static int _online_pvid_file_remove(char *pvid)
{
char path[PATH_MAX];
if (dm_snprintf(path, sizeof(path), "%s/%s", PVS_ONLINE_DIR, pvid) < 0)
return_0;
if (!unlink(path))
return 1;
return 0;
}
/*
* Reboot automatically clearing tmpfs on /run is the main method of removing
* online files. It's important to note that removing the online files for a
* VG is not a technical requirement for anything and could easily be skipped
* if it had any downside. It's only done to clean up the space used in /run
* by the online files, e.g. if there happens to be an extreme amount of
* vgcreate/pvscan/vgremove between reboots that are leaving a large number of
* useless online files consuming tmpfs space.
*/
void online_vgremove(struct volume_group *vg)
{
char pvid[ID_LEN + 1] __attribute__((aligned(8))) = { 0 };
struct pv_list *pvl;
/*
* online files may not exist for the vg if there has been no
* pvscans or autoactivation.
*/
online_vg_file_remove(vg->name);
online_lookup_file_remove(vg->name);
dm_list_iterate_items(pvl, &vg->pvs) {
memcpy(pvid, &pvl->pv->id.uuid, ID_LEN);
_online_pvid_file_remove(pvid);
}
}

View File

@@ -54,7 +54,5 @@ void online_dir_setup(struct cmd_context *cmd);
int get_pvs_online(struct dm_list *pvs_online, const char *vgname);
int get_pvs_lookup(struct dm_list *pvs_online, const char *vgname);
void free_po_list(struct dm_list *list);
void online_lookup_file_remove(const char *vgname);
void online_vgremove(struct volume_group *vg);
#endif

View File

@@ -1,252 +0,0 @@
/*
* Copyright (C) 2022 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "base/memory/zalloc.h"
#include "lib/misc/lib.h"
#include "lib/commands/toolcontext.h"
#include "lib/device/device.h"
#include "lib/device/device_id.h"
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <ctype.h>
#include <limits.h>
#include <dirent.h>
#include <errno.h>
#include <stdbool.h>
#include <assert.h>
/*
* Replace series of spaces with a single _.
*/
int format_t10_id(const unsigned char *in, int in_bytes, unsigned char *out, int out_bytes)
{
int in_space = 0;
int retlen = 0;
int j = 0;
int i;
for (i = 0; i < in_bytes; i++) {
if (!in[i])
break;
if (j >= (out_bytes - 2))
break;
/* skip leading spaces */
if (!retlen && (in[i] == ' '))
continue;
/* replace one or more spaces with _ */
if (in[i] == ' ') {
in_space = 1;
continue;
}
/* spaces are finished so insert _ */
if (in_space) {
out[j++] = '_';
in_space = 0;
retlen++;
}
out[j++] = in[i];
retlen++;
}
return retlen;
}
static int _to_hex(const unsigned char *in, int in_bytes, unsigned char *out, int out_bytes)
{
int off = 0;
int num;
int i;
for (i = 0; i < in_bytes; i++) {
num = sprintf((char *)out + off, "%02x", in[i]);
if (num < 0)
break;
off += num;
if (off + 2 >= out_bytes)
break;
}
return off;
}
#define ID_BUFSIZE 1024
/*
* based on linux kernel function
*/
int parse_vpd_ids(const unsigned char *vpd_data, int vpd_datalen, struct dm_list *ids)
{
char id[ID_BUFSIZE];
unsigned char tmp_str[ID_BUFSIZE];
const unsigned char *d, *cur_id_str;
size_t id_len = ID_BUFSIZE;
int id_size = -1;
int type;
uint8_t cur_id_size = 0;
memset(id, 0, ID_BUFSIZE);
for (d = vpd_data + 4;
d < vpd_data + vpd_datalen;
d += d[3] + 4) {
memset(tmp_str, 0, sizeof(tmp_str));
switch (d[1] & 0xf) {
case 0x1:
/* T10 Vendor ID */
cur_id_size = d[3];
if (cur_id_size + 4 > id_len)
cur_id_size = id_len - 4;
cur_id_str = d + 4;
format_t10_id(cur_id_str, cur_id_size, tmp_str, sizeof(tmp_str));
id_size = snprintf(id, ID_BUFSIZE, "t10.%s", tmp_str);
if (id_size < 0)
break;
if (id_size >= ID_BUFSIZE)
id_size = ID_BUFSIZE - 1;
dev_add_wwid(id, 1, ids);
break;
case 0x2:
/* EUI-64 */
cur_id_size = d[3];
cur_id_str = d + 4;
switch (cur_id_size) {
case 8:
_to_hex(cur_id_str, 8, tmp_str, sizeof(tmp_str));
id_size = snprintf(id, ID_BUFSIZE, "eui.%s", tmp_str);
break;
case 12:
_to_hex(cur_id_str, 12, tmp_str, sizeof(tmp_str));
id_size = snprintf(id, ID_BUFSIZE, "eui.%s", tmp_str);
break;
case 16:
_to_hex(cur_id_str, 16, tmp_str, sizeof(tmp_str));
id_size = snprintf(id, ID_BUFSIZE, "eui.%s", tmp_str);
break;
default:
break;
}
if (id_size < 0)
break;
if (id_size >= ID_BUFSIZE)
id_size = ID_BUFSIZE - 1;
dev_add_wwid(id, 2, ids);
break;
case 0x3:
/* NAA */
cur_id_size = d[3];
cur_id_str = d + 4;
switch (cur_id_size) {
case 8:
_to_hex(cur_id_str, 8, tmp_str, sizeof(tmp_str));
id_size = snprintf(id, ID_BUFSIZE, "naa.%s", tmp_str);
break;
case 16:
_to_hex(cur_id_str, 16, tmp_str, sizeof(tmp_str));
id_size = snprintf(id, ID_BUFSIZE, "naa.%s", tmp_str);
break;
default:
break;
}
if (id_size < 0)
break;
if (id_size >= ID_BUFSIZE)
id_size = ID_BUFSIZE - 1;
dev_add_wwid(id, 3, ids);
break;
case 0x8:
/* SCSI name string */
cur_id_size = d[3];
cur_id_str = d + 4;
if (cur_id_size >= id_len)
cur_id_size = id_len - 1;
memcpy(id, cur_id_str, cur_id_size);
id_size = cur_id_size;
/*
* if naa or eui ids are provided as scsi names,
* consider them to be naa/eui types.
*/
if (!memcmp(id, "eui.", 4))
type = 2;
else if (!memcmp(id, "naa.", 4))
type = 3;
else
type = 8;
/*
* Not in the kernel version, copying multipath code,
* which checks if this string begins with naa or eui
* and if so does tolower() on the chars.
*/
if ((type == 2) || (type == 3)) {
int i;
for (i = 0; i < strlen(id); i++)
id[i] = tolower(id[i]);
}
dev_add_wwid(id, type, ids);
break;
default:
break;
}
}
return id_size;
}
int parse_vpd_serial(const unsigned char *in, char *out, int outsize)
{
uint8_t len_buf[2] __attribute__((aligned(8))) = { 0 };;
size_t len;
/* parsing code from multipath tools */
/* ignore in[0] and in[1] */
/* len is in[2] and in[3] */
/* serial begins at in[4] */
len_buf[0] = in[2];
len_buf[1] = in[3];
len = len_buf[0] << 8 | len_buf[1];
if (outsize == 0)
return 0;
if (len > DEV_WWID_SIZE)
len = DEV_WWID_SIZE;
/*
* Strip leading and trailing whitespace
*/
while (len > 0 && in[len + 3] == ' ')
--len;
while (len > 0 && in[4] == ' ') {
++in;
--len;
}
if (len >= outsize)
len = outsize - 1;
if (len > 0) {
memcpy(out, in + 4, len);
out[len] = '\0';
}
return len;
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright (C) 2006 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/filters/filter.h"
static DM_LIST_INIT(_allow_devs);
int internal_filter_allow(struct dm_pool *mem, struct device *dev)
{
struct device_list *devl;
if (!(devl = dm_pool_alloc(mem, sizeof(*devl)))) {
log_error("device_list element allocation failed");
return 0;
}
devl->dev = dev;
dm_list_add(&_allow_devs, &devl->list);
return 1;
}
void internal_filter_clear(void)
{
dm_list_init(&_allow_devs);
}
static int _passes_internal(struct cmd_context *cmd, struct dev_filter *f __attribute__((unused)),
struct device *dev, const char *use_filter_name)
{
struct device_list *devl;
dev->filtered_flags &= ~DEV_FILTERED_INTERNAL;
if (!internal_filtering())
return 1;
dm_list_iterate_items(devl, &_allow_devs) {
if (devl->dev == dev)
return 1;
}
dev->filtered_flags |= DEV_FILTERED_INTERNAL;
log_debug_devs("%s: Skipping for internal filtering.", dev_name(dev));
return 0;
}
static void _destroy(struct dev_filter *f)
{
if (f->use_count)
log_error(INTERNAL_ERROR "Destroying internal filter while in use %u times.", f->use_count);
free(f);
}
struct dev_filter *internal_filter_create(void)
{
struct dev_filter *f;
if (!(f = zalloc(sizeof(*f)))) {
log_error("md filter allocation failed");
return NULL;
}
f->passes_filter = _passes_internal;
f->destroy = _destroy;
f->use_count = 0;
f->name = "internal";
log_debug_devs("Internal filter initialised.");
return f;
}

View File

@@ -99,6 +99,14 @@ static int _passes_md_filter(struct cmd_context *cmd, struct dev_filter *f __att
return 1;
ret = dev_is_md_component(cmd, dev, NULL, cmd->use_full_md_check);
if (ret == -EAGAIN) {
/* let pass, call again after scan */
dev->flags |= DEV_FILTER_AFTER_SCAN;
log_debug_devs("filter md deferred %s", dev_name(dev));
return 1;
}
if (ret == 0)
return 1;

View File

@@ -15,41 +15,18 @@
#include "base/memory/zalloc.h"
#include "lib/misc/lib.h"
#include "lib/filters/filter.h"
#include "lib/device/device_id.h"
#ifdef __linux__
#include <dirent.h>
static int _lvmdevices_update_msg;
static int _ignore_mpath_component(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
{
dev_t mpath_devno = 0;
dev->filtered_flags &= ~DEV_FILTERED_MPATH_COMPONENT;
if (dev_is_mpath_component(cmd, dev, &mpath_devno)) {
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;
/*
* Warn about misconfig where an mpath component is
* in the devices file, but its mpath device is not.
*/
if ((dev->flags & DEV_MATCHED_USE_ID) && mpath_devno) {
if (!get_du_for_devno(cmd, mpath_devno)) {
struct device *mpath_dev = dev_cache_get_by_devt(cmd, mpath_devno);
log_warn("WARNING: devices file is missing %s (%d:%d) using multipath component %s.",
mpath_dev ? dev_name(mpath_dev) : "unknown",
(int)MAJOR(mpath_devno), (int)MINOR(mpath_devno), dev_name(dev));
if (!_lvmdevices_update_msg && strcmp(get_cmd_name(), "lvmdevices")) {
log_warn("See lvmdevices --update for devices file update.");
_lvmdevices_update_msg = 1;
}
}
}
return 0;
}

View File

@@ -30,6 +30,14 @@ static int _passes_partitioned_filter(struct cmd_context *cmd, struct dev_filter
dev->filtered_flags &= ~DEV_FILTERED_PARTITIONED;
ret = dev_is_partitioned(cmd, dev);
if (ret == -EAGAIN) {
/* let pass, call again after scan */
log_debug_devs("filter partitioned deferred %s", dev_name(dev));
dev->flags |= DEV_FILTER_AFTER_SCAN;
return 1;
}
if (ret) {
if (dev->ext.src == DEV_EXT_NONE)
log_debug_devs(MSG_SKIPPING, dev_name(dev));

View File

@@ -109,6 +109,8 @@ static int _lookup_p(struct cmd_context *cmd, struct dev_filter *f, struct devic
/* Uncached, check filters and cache the result */
if (!l) {
dev->flags &= ~DEV_FILTER_AFTER_SCAN;
pass = pf->real->passes_filter(cmd, pf->real, dev, use_filter_name);
if (!pass) {
@@ -118,13 +120,21 @@ static int _lookup_p(struct cmd_context *cmd, struct dev_filter *f, struct devic
* because the deferred result won't change the exclude.
*/
l = PF_BAD_DEVICE;
} else if (pass == 1) {
l = PF_GOOD_DEVICE;
} else {
log_error("Ignore invalid filter result %d %s", pass, dev_name(dev));
} else if ((pass == -EAGAIN) || (dev->flags & DEV_FILTER_AFTER_SCAN)) {
/*
* When the filter result is deferred, we let the device
* pass for now, but do not cache the result. We need to
* rerun the filters later. At that point the final result
* will be cached.
*/
log_debug_devs("filter cache deferred %s", dev_name(dev));
dev->flags |= DEV_FILTER_AFTER_SCAN;
pass = 1;
/* don't cache invalid result */
goto out;
} else if (pass) {
l = PF_GOOD_DEVICE;
}
if (!dev->filtered_flags) /* skipping reason already logged by filter */

View File

@@ -161,9 +161,6 @@ static int _accept_p(struct cmd_context *cmd, struct dev_filter *f, struct devic
if (cmd->enable_devices_list)
return 1;
if (cmd->filter_regex_skip)
return 1;
if (cmd->enable_devices_file && !cmd->filter_regex_with_devices_file) {
/* can't warn in create_filter because enable_devices_file is set later */
if (rf->config_filter && !rf->warned_filter) {
@@ -182,7 +179,7 @@ static int _accept_p(struct cmd_context *cmd, struct dev_filter *f, struct devic
if (m >= 0) {
if (dm_bit(rf->accept, m)) {
if (!first && !cmd->filter_regex_set_preferred_name_disable)
if (!first)
dev_set_preferred_name(sl, dev);
return 1;
@@ -253,48 +250,3 @@ struct dev_filter *regex_filter_create(const struct dm_config_value *patterns, i
dm_pool_destroy(mem);
return NULL;
}
static int _filter_contains_symlink(struct cmd_context *cmd, int filter_cfg)
{
const struct dm_config_node *cn;
const struct dm_config_value *cv;
const char *fname;
if ((cn = find_config_tree_array(cmd, filter_cfg, NULL))) {
for (cv = cn->v; cv; cv = cv->next) {
if (cv->type != DM_CFG_STRING)
continue;
if (!cv->v.str)
continue;
fname = cv->v.str;
if (fname[0] != 'a')
continue;
if (strstr(fname, "/dev/disk/"))
return 1;
if (strstr(fname, "/dev/mapper/"))
return 1;
/* In case /dev/disk/by was omitted */
if (strstr(fname, "lvm-pv-uuid"))
return 1;
if (strstr(fname, "dm-uuid"))
return 1;
if (strstr(fname, "wwn-"))
return 1;
if (strstr(fname, "pci-"))
return 1;
}
}
return 0;
}
int regex_filter_contains_symlink(struct cmd_context *cmd)
{
return _filter_contains_symlink(cmd, devices_filter_CFG) ||
_filter_contains_symlink(cmd, devices_global_filter_CFG);
}

View File

@@ -33,6 +33,13 @@ static int _ignore_signature(struct cmd_context *cmd, struct dev_filter *f __att
dev->filtered_flags &= ~DEV_FILTERED_SIGNATURE;
if (!scan_bcache) {
/* let pass, call again after scan */
log_debug_devs("filter signature deferred %s", dev_name(dev));
dev->flags |= DEV_FILTER_AFTER_SCAN;
return 1;
}
memset(buf, 0, BUFSIZE);
if (!dev_read_bytes(dev, 0, BUFSIZE, buf)) {

View File

@@ -32,6 +32,10 @@ struct dev_filter *sysfs_filter_create(void);
struct dev_filter *signature_filter_create(struct dev_types *dt);
struct dev_filter *deviceid_filter_create(struct cmd_context *cmd);
struct dev_filter *internal_filter_create(void);
int internal_filter_allow(struct dm_pool *mem, struct device *dev);
void internal_filter_clear(void);
/*
* patterns must be an array of strings of the form:
* [ra]<sep><regex><sep>, eg,
@@ -64,6 +68,4 @@ struct dev_filter *usable_filter_create(struct cmd_context *cmd, struct dev_type
#define DEV_FILTERED_DEVICES_LIST 0x00001000
#define DEV_FILTERED_IS_LV 0x00002000
int regex_filter_contains_symlink(struct cmd_context *cmd);
#endif /* _LVM_FILTER_H */

View File

@@ -219,7 +219,7 @@ static void _remove_expired(const char *dir, const char *vgname,
sum /= 1024 * 1024;
if (sum > 128 || archives_size > 8192)
log_print_unless_silent("Consider pruning %s VG archive with more then %u MiB in %u files (see archiving settings in lvm.conf).",
log_print_unless_silent("Consider pruning %s VG archive with more then %u MiB in %u files (check archiving is needed in lvm.conf).",
vgname, (unsigned)sum, archives_size);
}

View File

@@ -428,7 +428,7 @@ static struct volume_group *_vg_read_raw_area(struct cmd_context *cmd,
rlocn->checksum,
&when, &desc);
if (!vg && (!use_previous_vg || !*use_previous_vg)) {
if (!vg && !*use_previous_vg) {
log_warn("WARNING: Failed to read metadata text at %llu off %llu size %llu VG %s on %s",
(unsigned long long)(area->start + rlocn->offset),
(unsigned long long)rlocn->offset,

View File

@@ -146,6 +146,7 @@
#include "lib/label/hints.h"
#include "lib/device/dev-type.h"
#include "lib/device/device_id.h"
#include "lib/device/online.h"
#include <sys/stat.h>
#include <fcntl.h>

View File

@@ -27,7 +27,6 @@
#include "lib/format_text/layout.h"
#include "lib/device/device_id.h"
#include "lib/device/online.h"
#include "lib/filters/filter.h"
#include <sys/stat.h>
#include <fcntl.h>
@@ -460,6 +459,7 @@ static int _scan_dev_open(struct device *dev)
const char *name;
const char *modestr;
struct stat sbuf;
int retried = 0;
int flags = 0;
int fd, di;
@@ -479,23 +479,14 @@ static int _scan_dev_open(struct device *dev)
return 0;
}
next_name:
/*
* All the names for this device (major:minor) are kept on
* dev->aliases, the first one is the primary/preferred name.
*
* The default name preferences in dev-cache mean that the first
* name in dev->aliases is not a symlink for scsi devices, but is
* the /dev/mapper/ symlink for mpath devices.
*
* If preferred names are set to symlinks, should this
* first attempt to open using a non-symlink?
*
* dm_list_first() returns NULL if the list is empty.
*/
if (!(name_list = dm_list_first(&dev->aliases))) {
log_error("Device open %d:%d has no path names.",
(int)MAJOR(dev->dev), (int)MINOR(dev->dev));
/* Shouldn't happen */
log_error("Device open %s %d:%d has no path names.",
dev_name(dev), (int)MAJOR(dev->dev), (int)MINOR(dev->dev));
return 0;
}
name_sl = dm_list_item(name_list, struct dm_str_list);
@@ -523,34 +514,50 @@ static int _scan_dev_open(struct device *dev)
modestr = "ro";
}
retry_open:
fd = open(name, flags, 0777);
if (fd < 0) {
if ((errno == EBUSY) && (flags & O_EXCL)) {
log_error("Can't open %s exclusively. Mounted filesystem?",
dev_name(dev));
return 0;
} else {
/*
* drop name from dev->aliases and use verify_aliases to
* drop any other invalid aliases before retrying open with
* any remaining valid paths.
*/
log_debug("Drop alias for %d:%d failed open %s (%d)",
(int)MAJOR(dev->dev), (int)MINOR(dev->dev), name, errno);
dev_cache_failed_path(dev, name);
dev_cache_verify_aliases(dev);
goto next_name;
}
}
int major, minor;
/* Verify that major:minor from the path still match dev. */
if ((fstat(fd, &sbuf) < 0) || (sbuf.st_rdev != dev->dev)) {
log_warn("Invalid path %s for device %d:%d, trying different path.",
name, (int)MAJOR(dev->dev), (int)MINOR(dev->dev));
(void)close(fd);
dev_cache_failed_path(dev, name);
dev_cache_verify_aliases(dev);
goto next_name;
/*
* Shouldn't happen, if it does, print stat info to help figure
* out what's wrong.
*/
major = (int)MAJOR(dev->dev);
minor = (int)MINOR(dev->dev);
log_error("Device open %s %d:%d failed errno %d", name, major, minor, errno);
if (stat(name, &sbuf)) {
log_debug_devs("Device open %s %d:%d stat failed errno %d",
name, major, minor, errno);
} else if (sbuf.st_rdev != dev->dev) {
log_debug_devs("Device open %s %d:%d stat %d:%d does not match.",
name, major, minor,
(int)MAJOR(sbuf.st_rdev), (int)MINOR(sbuf.st_rdev));
}
if (!retried) {
/*
* FIXME: remove this, the theory for this retry is that
* there may be a udev race that we can sometimes mask by
* retrying. This is here until we can figure out if it's
* needed and if so fix the real problem.
*/
usleep(5000);
log_debug_devs("Device open %s retry", dev_name(dev));
retried = 1;
goto retry_open;
}
}
return 0;
}
dev->flags |= DEV_IN_BCACHE;
@@ -598,6 +605,37 @@ static int _scan_dev_close(struct device *dev)
return 1;
}
static void _drop_bad_aliases(struct device *dev)
{
struct dm_str_list *strl, *strl2;
const char *name;
struct stat sbuf;
int major = (int)MAJOR(dev->dev);
int minor = (int)MINOR(dev->dev);
int bad;
dm_list_iterate_items_safe(strl, strl2, &dev->aliases) {
name = strl->str;
bad = 0;
if (stat(name, &sbuf)) {
bad = 1;
log_debug_devs("Device path check %d:%d %s stat failed errno %d",
major, minor, name, errno);
} else if (sbuf.st_rdev != dev->dev) {
bad = 1;
log_debug_devs("Device path check %d:%d %s stat %d:%d does not match.",
major, minor, name,
(int)MAJOR(sbuf.st_rdev), (int)MINOR(sbuf.st_rdev));
}
if (bad) {
log_debug_devs("Device path check %d:%d dropping path %s.", major, minor, name);
dev_cache_failed_path(dev, name);
}
}
}
// Like bcache_invalidate, only it throws any dirty data away if the
// write fails.
static void _invalidate_di(struct bcache *cache, int di)
@@ -625,8 +663,10 @@ static int _scan_list(struct cmd_context *cmd, struct dev_filter *f,
char headers_buf[HEADERS_BUF_SIZE];
struct dm_list wait_devs;
struct dm_list done_devs;
struct dm_list reopen_devs;
struct device_list *devl, *devl2;
struct block *bb;
int retried_open = 0;
int scan_read_errors = 0;
int scan_process_errors = 0;
int scan_failed_count = 0;
@@ -637,6 +677,7 @@ static int _scan_list(struct cmd_context *cmd, struct dev_filter *f,
dm_list_init(&wait_devs);
dm_list_init(&done_devs);
dm_list_init(&reopen_devs);
log_debug_devs("Scanning %d devices for VG info", dm_list_size(devs));
@@ -660,9 +701,9 @@ static int _scan_list(struct cmd_context *cmd, struct dev_filter *f,
if (!_in_bcache(devl->dev)) {
if (!_scan_dev_open(devl->dev)) {
log_debug_devs("Scan failed to open %d:%d %s.",
(int)MAJOR(devl->dev->dev), (int)MINOR(devl->dev->dev), dev_name(devl->dev));
log_debug_devs("Scan failed to open %s.", dev_name(devl->dev));
dm_list_del(&devl->list);
dm_list_add(&reopen_devs, &devl->list);
devl->dev->flags |= DEV_SCAN_NOT_READ;
continue;
}
@@ -746,6 +787,41 @@ static int _scan_list(struct cmd_context *cmd, struct dev_filter *f,
if (!dm_list_empty(devs))
goto scan_more;
/*
* We're done scanning all the devs. If we failed to open any of them
* the first time through, refresh device paths and retry. We failed
* to open the devs on the reopen_devs list.
*
* FIXME: it's not clear if or why this helps.
*/
if (!dm_list_empty(&reopen_devs)) {
if (retried_open) {
/* Don't try again. */
scan_failed_count += dm_list_size(&reopen_devs);
dm_list_splice(&done_devs, &reopen_devs);
goto out;
}
retried_open = 1;
dm_list_iterate_items_safe(devl, devl2, &reopen_devs) {
_drop_bad_aliases(devl->dev);
if (dm_list_empty(&devl->dev->aliases)) {
log_warn("WARNING: Scan ignoring device %d:%d with no paths.",
(int)MAJOR(devl->dev->dev),
(int)MINOR(devl->dev->dev));
dm_list_del(&devl->list);
lvmcache_del_dev(devl->dev);
scan_failed_count++;
}
}
/* Put devs that failed to open back on the original list to retry. */
dm_list_splice(devs, &reopen_devs);
goto scan_more;
}
out:
log_debug_devs("Scanned devices: read errors %d process errors %d failed %d",
scan_read_errors, scan_process_errors, scan_failed_count);
@@ -802,7 +878,7 @@ static int _setup_bcache(void)
}
if (!(scan_bcache = bcache_create(BCACHE_BLOCK_SIZE_IN_SECTORS, cache_blocks, ioe))) {
log_error("Failed to set up io layer with %d blocks.", cache_blocks);
log_error("Failed to create bcache with %d cache blocks.", cache_blocks);
return 0;
}
@@ -1100,25 +1176,11 @@ int label_scan_vg_online(struct cmd_context *cmd, const char *vgname,
log_debug("Skipping device_id filtering due to devname ids.");
}
/*
* See corresponding code in pvscan. This function is used during
* startup autoactivation when udev has not created all symlinks, so
* regex filter containing symlinks doesn't work. pvscan has code
* to properly check devs against the filter using DEVLINKS. The
* pvscan will only create pvs_online files for devs that pass the
* filter. We get devs from the pvs_online files, so we inherit the
* regex filtering from pvscan and don't have to do it ourself.
*/
if (!cmd->enable_devices_file &&
!cmd->enable_devices_list &&
regex_filter_contains_symlink(cmd))
cmd->filter_regex_skip = 1;
cmd->filter_nodata_only = 1;
dm_list_iterate_items_safe(devl, devl2, &devs) {
if (!cmd->filter->passes_filter(cmd, cmd->filter, devl->dev, NULL)) {
log_print("%s excluded: %s.",
log_print("%s excluded by filters: %s.",
dev_name(devl->dev), dev_filtered_reason(devl->dev));
dm_list_del(&devl->list);
dm_list_add(&devs_drop, &devl->list);
@@ -1184,7 +1246,7 @@ int label_scan_vg_online(struct cmd_context *cmd, const char *vgname,
/* Applies all filters, including those that need data from dev. */
if (!cmd->filter->passes_filter(cmd, cmd->filter, devl->dev, NULL)) {
log_print("%s excluded: %s.",
log_print("%s excluded by filters: %s.",
dev_name(devl->dev), dev_filtered_reason(devl->dev));
dm_list_del(&devl->list);
dm_list_add(&devs_drop, &devl->list);
@@ -1194,8 +1256,6 @@ int label_scan_vg_online(struct cmd_context *cmd, const char *vgname,
if (relax_deviceid_filter)
cmd->filter_deviceid_skip = 0;
cmd->filter_regex_skip = 0;
free_po_list(&pvs_online);
if (dm_list_empty(&devs)) {
@@ -1309,7 +1369,7 @@ int label_scan(struct cmd_context *cmd)
* data to invalidate.)
*/
if (!(iter = dev_iter_create(NULL, 0))) {
log_error("Failed to get device list.");
log_error("Scanning failed to get devices.");
return 0;
}
while ((dev = dev_iter_get(cmd, iter))) {
@@ -1678,11 +1738,9 @@ void label_scan_invalidate_lvs(struct cmd_context *cmd, struct dm_list *lvs)
dev_t devt;
/*
* This is only needed when the command sees PVs stacked on LVs which
* will only happen with scan_lvs=1.
* FIXME: this is all unnecessary unless there are PVs stacked on LVs,
* so we can skip all of this if scan_lvs=0.
*/
if (!cmd->scan_lvs)
return;
log_debug("invalidating devs for any pvs on lvs");
if (get_device_list(NULL, &devs, &devs_features)) {

Some files were not shown because too many files have changed in this diff Show More