1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

Merge remote-tracking branch 'sourceware/master' into upstream

This commit is contained in:
Joe Thornber 2018-04-25 09:18:42 +01:00
commit 28a9fcd94b
144 changed files with 5551 additions and 7237 deletions

44
.gitignore vendored
View File

@ -35,3 +35,47 @@ make.tmpl
tools/man-generator
tools/man-generator.c
test/lib/lvchange
test/lib/lvconvert
test/lib/lvcreate
test/lib/lvdisplay
test/lib/lvextend
test/lib/lvmconfig
test/lib/lvmdiskscan
test/lib/lvmsadc
test/lib/lvmsar
test/lib/lvreduce
test/lib/lvremove
test/lib/lvrename
test/lib/lvresize
test/lib/lvs
test/lib/lvscan
test/lib/pvchange
test/lib/pvck
test/lib/pvcreate
test/lib/pvdisplay
test/lib/pvmove
test/lib/pvremove
test/lib/pvresize
test/lib/pvs
test/lib/pvscan
test/lib/vgcfgbackup
test/lib/vgcfgrestore
test/lib/vgchange
test/lib/vgck
test/lib/vgconvert
test/lib/vgcreate
test/lib/vgdisplay
test/lib/vgexport
test/lib/vgextend
test/lib/vgimport
test/lib/vgimportclone
test/lib/vgmerge
test/lib/vgmknodes
test/lib/vgreduce
test/lib/vgremove
test/lib/vgrename
test/lib/vgs
test/lib/vgscan
test/lib/vgsplit

View File

@ -212,28 +212,7 @@ endif
endif
ifeq ("$(TESTING)", "yes")
# testing and report generation
RUBY=ruby1.9 -Ireport-generators/lib -Ireport-generators/test
.PHONY: unit-test ruby-test test-programs
# FIXME: put dependencies on libdm and liblvm
# FIXME: Should be handled by Makefiles in subdirs, not here at top level.
test-programs:
cd unit-tests/regex && $(MAKE)
cd unit-tests/datastruct && $(MAKE)
cd unit-tests/mm && $(MAKE)
unit-test: test-programs
$(RUBY) report-generators/unit_test.rb $(shell find . -name TESTS)
$(RUBY) report-generators/title_page.rb
memcheck: test-programs
$(RUBY) report-generators/memcheck.rb $(shell find . -name TESTS)
$(RUBY) report-generators/title_page.rb
ruby-test:
$(RUBY) report-generators/test/ts.rb
include test/unit/Makefile
endif
ifneq ($(shell which ctags),)

210
aclocal.m4 vendored
View File

@ -69,32 +69,63 @@ AC_DEFUN([AX_PYTHON_MODULE],[
fi
])
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
# serial 1 (pkg-config-0.24)
#
# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
dnl pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
dnl serial 11 (pkg-config-0.29)
dnl
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
dnl
dnl This program is free software; you can redistribute it and/or modify
dnl it under the terms of the GNU General Public License as published by
dnl the Free Software Foundation; either version 2 of the License, or
dnl (at your option) any later version.
dnl
dnl This program is distributed in the hope that it will be useful, but
dnl WITHOUT ANY WARRANTY; without even the implied warranty of
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
dnl General Public License for more details.
dnl
dnl You should have received a copy of the GNU General Public License
dnl along with this program; if not, write to the Free Software
dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
dnl 02111-1307, USA.
dnl
dnl As a special exception to the GNU General Public License, if you
dnl distribute this file as part of a program that contains a
dnl configuration script generated by Autoconf, you may include it under
dnl the same distribution terms that you use for the rest of that
dnl program.
# PKG_PROG_PKG_CONFIG([MIN-VERSION])
# ----------------------------------
dnl PKG_PREREQ(MIN-VERSION)
dnl -----------------------
dnl Since: 0.29
dnl
dnl Verify that the version of the pkg-config macros are at least
dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's
dnl installed version of pkg-config, this checks the developer's version
dnl of pkg.m4 when generating configure.
dnl
dnl To ensure that this macro is defined, also add:
dnl m4_ifndef([PKG_PREREQ],
dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])])
dnl
dnl See the "Since" comment for each macro you use to see what version
dnl of the macros you require.
m4_defun([PKG_PREREQ],
[m4_define([PKG_MACROS_VERSION], [0.29])
m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
[m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
])dnl PKG_PREREQ
dnl PKG_PROG_PKG_CONFIG([MIN-VERSION])
dnl ----------------------------------
dnl Since: 0.16
dnl
dnl Search for the pkg-config tool and set the PKG_CONFIG variable to
dnl first found in the path. Checks that the version of pkg-config found
dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is
dnl used since that's the first version where most current features of
dnl pkg-config existed.
AC_DEFUN([PKG_PROG_PKG_CONFIG],
[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
@ -116,18 +147,19 @@ if test -n "$PKG_CONFIG"; then
PKG_CONFIG=""
fi
fi[]dnl
])# PKG_PROG_PKG_CONFIG
])dnl PKG_PROG_PKG_CONFIG
# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
#
# Check to see whether a particular set of modules exists. Similar
# to PKG_CHECK_MODULES(), but does not set variables or print errors.
#
# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
# only at the first occurence in configure.ac, so if the first place
# it's called might be skipped (such as if it is within an "if", you
# have to call PKG_CHECK_EXISTS manually
# --------------------------------------------------------------
dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
dnl -------------------------------------------------------------------
dnl Since: 0.18
dnl
dnl Check to see whether a particular set of modules exists. Similar to
dnl PKG_CHECK_MODULES(), but does not set variables or print errors.
dnl
dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
dnl only at the first occurence in configure.ac, so if the first place
dnl it's called might be skipped (such as if it is within an "if", you
dnl have to call PKG_CHECK_EXISTS manually
AC_DEFUN([PKG_CHECK_EXISTS],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
if test -n "$PKG_CONFIG" && \
@ -137,8 +169,10 @@ m4_ifvaln([$3], [else
$3])dnl
fi])
# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
# ---------------------------------------------
dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
dnl ---------------------------------------------
dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting
dnl pkg_failed based on the result.
m4_define([_PKG_CONFIG],
[if test -n "$$1"; then
pkg_cv_[]$1="$$1"
@ -150,10 +184,11 @@ m4_define([_PKG_CONFIG],
else
pkg_failed=untried
fi[]dnl
])# _PKG_CONFIG
])dnl _PKG_CONFIG
# _PKG_SHORT_ERRORS_SUPPORTED
# -----------------------------
dnl _PKG_SHORT_ERRORS_SUPPORTED
dnl ---------------------------
dnl Internal check to see if pkg-config supports short errors.
AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
@ -161,19 +196,17 @@ if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
else
_pkg_short_errors_supported=no
fi[]dnl
])# _PKG_SHORT_ERRORS_SUPPORTED
])dnl _PKG_SHORT_ERRORS_SUPPORTED
# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
# [ACTION-IF-NOT-FOUND])
#
#
# Note that if there is a possibility the first call to
# PKG_CHECK_MODULES might not happen, you should be sure to include an
# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
#
#
# --------------------------------------------------------------
dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
dnl [ACTION-IF-NOT-FOUND])
dnl --------------------------------------------------------------
dnl Since: 0.4.0
dnl
dnl Note that if there is a possibility the first call to
dnl PKG_CHECK_MODULES might not happen, you should be sure to include an
dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
AC_DEFUN([PKG_CHECK_MODULES],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
@ -227,16 +260,40 @@ else
AC_MSG_RESULT([yes])
$3
fi[]dnl
])# PKG_CHECK_MODULES
])dnl PKG_CHECK_MODULES
# PKG_INSTALLDIR(DIRECTORY)
# -------------------------
# Substitutes the variable pkgconfigdir as the location where a module
# should install pkg-config .pc files. By default the directory is
# $libdir/pkgconfig, but the default can be changed by passing
# DIRECTORY. The user can override through the --with-pkgconfigdir
# parameter.
dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
dnl [ACTION-IF-NOT-FOUND])
dnl ---------------------------------------------------------------------
dnl Since: 0.29
dnl
dnl Checks for existence of MODULES and gathers its build flags with
dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags
dnl and VARIABLE-PREFIX_LIBS from --libs.
dnl
dnl Note that if there is a possibility the first call to
dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to
dnl include an explicit call to PKG_PROG_PKG_CONFIG in your
dnl configure.ac.
AC_DEFUN([PKG_CHECK_MODULES_STATIC],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
_save_PKG_CONFIG=$PKG_CONFIG
PKG_CONFIG="$PKG_CONFIG --static"
PKG_CHECK_MODULES($@)
PKG_CONFIG=$_save_PKG_CONFIG[]dnl
])dnl PKG_CHECK_MODULES_STATIC
dnl PKG_INSTALLDIR([DIRECTORY])
dnl -------------------------
dnl Since: 0.27
dnl
dnl Substitutes the variable pkgconfigdir as the location where a module
dnl should install pkg-config .pc files. By default the directory is
dnl $libdir/pkgconfig, but the default can be changed by passing
dnl DIRECTORY. The user can override through the --with-pkgconfigdir
dnl parameter.
AC_DEFUN([PKG_INSTALLDIR],
[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
m4_pushdef([pkg_description],
@ -247,16 +304,18 @@ AC_ARG_WITH([pkgconfigdir],
AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
m4_popdef([pkg_default])
m4_popdef([pkg_description])
]) dnl PKG_INSTALLDIR
])dnl PKG_INSTALLDIR
# PKG_NOARCH_INSTALLDIR(DIRECTORY)
# -------------------------
# Substitutes the variable noarch_pkgconfigdir as the location where a
# module should install arch-independent pkg-config .pc files. By
# default the directory is $datadir/pkgconfig, but the default can be
# changed by passing DIRECTORY. The user can override through the
# --with-noarch-pkgconfigdir parameter.
dnl PKG_NOARCH_INSTALLDIR([DIRECTORY])
dnl --------------------------------
dnl Since: 0.27
dnl
dnl Substitutes the variable noarch_pkgconfigdir as the location where a
dnl module should install arch-independent pkg-config .pc files. By
dnl default the directory is $datadir/pkgconfig, but the default can be
dnl changed by passing DIRECTORY. The user can override through the
dnl --with-noarch-pkgconfigdir parameter.
AC_DEFUN([PKG_NOARCH_INSTALLDIR],
[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
m4_pushdef([pkg_description],
@ -267,13 +326,15 @@ AC_ARG_WITH([noarch-pkgconfigdir],
AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
m4_popdef([pkg_default])
m4_popdef([pkg_description])
]) dnl PKG_NOARCH_INSTALLDIR
])dnl PKG_NOARCH_INSTALLDIR
# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
# -------------------------------------------
# Retrieves the value of the pkg-config variable for the given module.
dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
dnl -------------------------------------------
dnl Since: 0.28
dnl
dnl Retrieves the value of the pkg-config variable for the given module.
AC_DEFUN([PKG_CHECK_VAR],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
@ -282,7 +343,7 @@ _PKG_CONFIG([$1], [variable="][$3]["], [$2])
AS_VAR_COPY([$1], [pkg_cv_][$1])
AS_VAR_IF([$1], [""], [$5], [$4])dnl
])# PKG_CHECK_VAR
])dnl PKG_CHECK_VAR
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
#
@ -536,5 +597,4 @@ AC_DEFUN([AM_RUN_LOG],
echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
(exit $ac_status); }])
m4_include([acinclude.m4])

View File

@ -59,22 +59,6 @@ devices {
# This configuration option is advanced.
scan = [ "/dev" ]
# Configuration option devices/use_aio.
# Use linux asynchronous I/O for parallel device access where possible.
# This configuration option has an automatic default value.
# use_aio = 1
# Configuration option devices/aio_max.
# Maximum number of asynchronous I/Os to issue concurrently.
# This configuration option has an automatic default value.
# aio_max = 128
# Configuration option devices/aio_memory.
# Approximate maximum total amount of memory (in MB) used
# for asynchronous I/O buffers.
# This configuration option has an automatic default value.
# aio_memory = 10
# Configuration option devices/obtain_device_list_from_udev.
# Obtain the list of available devices from udev.
# This avoids opening or using any inapplicable non-block devices or

23
configure vendored
View File

@ -886,6 +886,7 @@ infodir
docdir
oldincludedir
includedir
runstatedir
localstatedir
sharedstatedir
sysconfdir
@ -1101,6 +1102,7 @@ datadir='${datarootdir}'
sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
runstatedir='${localstatedir}/run'
includedir='${prefix}/include'
oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE}'
@ -1353,6 +1355,15 @@ do
| -silent | --silent | --silen | --sile | --sil)
silent=yes ;;
-runstatedir | --runstatedir | --runstatedi | --runstated \
| --runstate | --runstat | --runsta | --runst | --runs \
| --run | --ru | --r)
ac_prev=runstatedir ;;
-runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
| --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
| --run=* | --ru=* | --r=*)
runstatedir=$ac_optarg ;;
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@ -1490,7 +1501,7 @@ fi
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
datadir sysconfdir sharedstatedir localstatedir includedir \
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
libdir localedir mandir
libdir localedir mandir runstatedir
do
eval ac_val=\$$ac_var
# Remove trailing slashes.
@ -1643,6 +1654,7 @@ Fine tuning of the installation directories:
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
--runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
--libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include]
@ -12967,7 +12979,7 @@ if ${am_cv_pathless_PYTHON+:} false; then :
$as_echo_n "(cached) " >&6
else
for am_cv_pathless_PYTHON in python python2 python3 python3.5 python3.4 python3.3 python3.2 python3.1 python3.0 python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0 none; do
for am_cv_pathless_PYTHON in python python2 python3 python3.3 python3.2 python3.1 python3.0 python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0 none; do
test "$am_cv_pathless_PYTHON" = none && break
prog="import sys
# split strings by '.' and convert to numeric. Append some zeros
@ -13535,7 +13547,7 @@ if ${am_cv_pathless_PYTHON+:} false; then :
$as_echo_n "(cached) " >&6
else
for am_cv_pathless_PYTHON in python python2 python3 python3.5 python3.4 python3.3 python3.2 python3.1 python3.0 python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0 none; do
for am_cv_pathless_PYTHON in python python2 python3 python3.3 python3.2 python3.1 python3.0 python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0 none; do
test "$am_cv_pathless_PYTHON" = none && break
prog="import sys
# split strings by '.' and convert to numeric. Append some zeros
@ -15848,7 +15860,7 @@ _ACEOF
################################################################################
ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/dmfilemapd/Makefile daemons/lvmdbusd/Makefile daemons/lvmdbusd/lvmdbusd daemons/lvmdbusd/lvmdb.py daemons/lvmdbusd/lvm_shell_proxy.py daemons/lvmdbusd/path.py daemons/lvmetad/Makefile daemons/lvmpolld/Makefile daemons/lvmlockd/Makefile conf/Makefile conf/example.conf conf/lvmlocal.conf conf/command_profile_template.profile conf/metadata_profile_template.profile include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile include/lvm-version.h lib/raid/Makefile lib/snapshot/Makefile lib/thin/Makefile lib/cache_segtype/Makefile libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/com.redhat.lvmdbus1.service scripts/dm_event_systemd_red_hat.service scripts/dm_event_systemd_red_hat.socket scripts/lvm2_cluster_activation_red_hat.sh scripts/lvm2_cluster_activation_systemd_red_hat.service scripts/lvm2_clvmd_systemd_red_hat.service scripts/lvm2_cmirrord_systemd_red_hat.service scripts/lvm2_lvmdbusd_systemd_red_hat.service scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_lvmpolld_init_red_hat scripts/lvm2_lvmpolld_systemd_red_hat.service scripts/lvm2_lvmpolld_systemd_red_hat.socket scripts/lvm2_lvmlockd_systemd_red_hat.service scripts/lvm2_lvmlocking_systemd_red_hat.service scripts/lvm2_monitoring_init_red_hat scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_pvscan_systemd_red_hat@.service scripts/lvm2_tmpfiles_red_hat.conf scripts/lvmdump.sh scripts/Makefile test/Makefile test/api/Makefile test/unit/Makefile tools/Makefile udev/Makefile unit-tests/datastruct/Makefile unit-tests/regex/Makefile unit-tests/mm/Makefile"
ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/dmfilemapd/Makefile daemons/lvmdbusd/Makefile daemons/lvmdbusd/lvmdbusd daemons/lvmdbusd/lvmdb.py daemons/lvmdbusd/lvm_shell_proxy.py daemons/lvmdbusd/path.py daemons/lvmetad/Makefile daemons/lvmpolld/Makefile daemons/lvmlockd/Makefile conf/Makefile conf/example.conf conf/lvmlocal.conf conf/command_profile_template.profile conf/metadata_profile_template.profile include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile include/lvm-version.h lib/raid/Makefile lib/snapshot/Makefile lib/thin/Makefile lib/cache_segtype/Makefile libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/com.redhat.lvmdbus1.service scripts/dm_event_systemd_red_hat.service scripts/dm_event_systemd_red_hat.socket scripts/lvm2_cluster_activation_red_hat.sh scripts/lvm2_cluster_activation_systemd_red_hat.service scripts/lvm2_clvmd_systemd_red_hat.service scripts/lvm2_cmirrord_systemd_red_hat.service scripts/lvm2_lvmdbusd_systemd_red_hat.service scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_lvmpolld_init_red_hat scripts/lvm2_lvmpolld_systemd_red_hat.service scripts/lvm2_lvmpolld_systemd_red_hat.socket scripts/lvm2_lvmlockd_systemd_red_hat.service scripts/lvm2_lvmlocking_systemd_red_hat.service scripts/lvm2_monitoring_init_red_hat scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_pvscan_systemd_red_hat@.service scripts/lvm2_tmpfiles_red_hat.conf scripts/lvmdump.sh scripts/Makefile test/Makefile test/api/Makefile test/unit/Makefile tools/Makefile udev/Makefile"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
@ -16625,9 +16637,6 @@ do
"test/unit/Makefile") CONFIG_FILES="$CONFIG_FILES test/unit/Makefile" ;;
"tools/Makefile") CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;;
"udev/Makefile") CONFIG_FILES="$CONFIG_FILES udev/Makefile" ;;
"unit-tests/datastruct/Makefile") CONFIG_FILES="$CONFIG_FILES unit-tests/datastruct/Makefile" ;;
"unit-tests/regex/Makefile") CONFIG_FILES="$CONFIG_FILES unit-tests/regex/Makefile" ;;
"unit-tests/mm/Makefile") CONFIG_FILES="$CONFIG_FILES unit-tests/mm/Makefile" ;;
*) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
esac

View File

@ -39,7 +39,6 @@ case "$host_os" in
LDDEPS="$LDDEPS .export.sym"
LIB_SUFFIX=so
DEVMAPPER=yes
AIO=yes
BUILD_LVMETAD=no
BUILD_LVMPOLLD=no
LOCKDSANLOCK=no
@ -59,7 +58,6 @@ case "$host_os" in
CLDNOWHOLEARCHIVE=
LIB_SUFFIX=dylib
DEVMAPPER=yes
AIO=no
ODIRECT=no
DM_IOCTLS=no
SELINUX=no
@ -1124,24 +1122,6 @@ if test "$DEVMAPPER" = yes; then
AC_DEFINE([DEVMAPPER_SUPPORT], 1, [Define to 1 to enable LVM2 device-mapper interaction.])
fi
################################################################################
dnl -- Disable aio
AC_MSG_CHECKING(whether to use asynchronous I/O)
AC_ARG_ENABLE(aio,
AC_HELP_STRING([--disable-aio],
[disable asynchronous I/O]),
AIO=$enableval)
AC_MSG_RESULT($AIO)
if test "$AIO" = yes; then
AC_CHECK_LIB(aio, io_setup,
[AC_DEFINE([AIO_SUPPORT], 1, [Define to 1 if aio is available.])
AIO_LIBS="-laio"
AIO_SUPPORT=yes],
[AIO_LIBS=
AIO_SUPPORT=no ])
fi
################################################################################
dnl -- Build lvmetad
AC_MSG_CHECKING(whether to build LVMetaD)
@ -2081,11 +2061,9 @@ AC_SUBST(DEFAULT_USE_LVMETAD)
AC_SUBST(DEFAULT_USE_LVMPOLLD)
AC_SUBST(DEFAULT_USE_LVMLOCKD)
AC_SUBST(DEVMAPPER)
AC_SUBST(AIO)
AC_SUBST(DLM_CFLAGS)
AC_SUBST(DLM_LIBS)
AC_SUBST(DL_LIBS)
AC_SUBST(AIO_LIBS)
AC_SUBST(DMEVENTD_PATH)
AC_SUBST(DM_LIB_PATCHLEVEL)
AC_SUBST(ELDFLAGS)
@ -2276,9 +2254,6 @@ test/api/Makefile
test/unit/Makefile
tools/Makefile
udev/Makefile
unit-tests/datastruct/Makefile
unit-tests/regex/Makefile
unit-tests/mm/Makefile
])
AC_OUTPUT

View File

@ -74,7 +74,7 @@ TARGETS = \
include $(top_builddir)/make.tmpl
LIBS += $(LVMINTERNAL_LIBS) -ldevmapper $(PTHREAD_LIBS)
LIBS += $(LVMINTERNAL_LIBS) -ldevmapper $(PTHREAD_LIBS) -laio
CFLAGS += -fno-strict-aliasing $(EXTRA_EXEC_CFLAGS)
INSTALL_TARGETS = \

View File

@ -661,10 +661,9 @@ int do_refresh_cache(void)
return -1;
}
init_full_scan_done(0);
init_ignore_suspended_devices(1);
lvmcache_force_next_label_scan();
lvmcache_label_scan(cmd);
label_scan_destroy(cmd); /* destroys bcache (to close devs), keeps lvmcache */
dm_pool_empty(cmd->mem);
pthread_mutex_unlock(&lvm_lock);

View File

@ -1,215 +0,0 @@
Introducing asynchronous I/O to LVM
===================================
Issuing I/O asynchronously means instructing the kernel to perform specific
I/O and return immediately without waiting for it to complete. The data
is collected from the kernel later.
Advantages
----------
A1. While waiting for the I/O to happen, the program could perform other
operations.
A2. When LVM is searching for its Physical Volumes, it issues a small amount of
I/O to a large number of disks. If this was issued in parallel the overall
runtime might be shorter while there should be little effect on the cpu time.
A3. If more than one timeout occurs when accessing any devices, these can be
taken in parallel, again reducing the runtime. This applies globally,
not just while the code is searching for Physical Volumes, so reading,
writing and committing the metadata may occasionally benefit too to some
extent and there are probably maintenance advantages in using the same
method of I/O throughout the main body of the code.
A4. By introducing a simple callback function mechanism, the conversion can be
performed largely incrementally by first refactoring and continuing to
use synchronous I/O with the callbacks performed immediately. This allows the
callbacks to be introduced without changing the running sequence of the code
initially. Future projects could refactor some of the calling sites to
simplify the code structure and even eliminate some of the nesting.
This allows each part of what might ultimately amount to a large change to be
introduced and tested independently.
Disadvantages
-------------
D1. The resulting code may be more complex with more failure modes to
handle. Mitigate by thorough auditing and testing, rolling out
gradually, and offering a simple switch to revert to the old behaviour.
D2. The linux asynchronous I/O implementation is less mature than
its synchronous I/O implementation and might show up problems that
depend on the version of the kernel or library used. Fixes or
workarounds for some of these might require kernel changes. For
example, there are suggestions that despite being supposedly async,
there are still cases where system calls can block. There might be
resource dependencies on other processes running on the system that make
it unsuitable for use while any devices are suspended. Mitigation
as for D1.
D3. The error handling within callbacks becomes more complicated.
However we know that existing call paths can already sometimes discard
errors, sometimes deliberately, sometimes not, so this aspect is in need
of a complete review anyway and the new approach will make the error
handling more transparent. Aim initially for overall behaviour that is
no worse than that of the existing code, then work on improving it
later.
D4. The work will take a few weeks to code and test. This leads to a
significant opportunity cost when compared against other enhancements
that could be achieved in that time. However, the proof-of-concept work
performed while writing this design has satisfied me that the work could
proceed and be committed incrementally as a background task.
Observations regarding LVM's I/O Architecture
---------------------------------------------
H1. All device, metadata and config file I/O is constrained to pass through a
single route in lib/device.
H2. The first step of the analysis was to instrument this code path with
log_debug messages. I/O is split into the following categories:
"dev signatures",
"PV labels",
"VG metadata header",
"VG metadata content",
"extra VG metadata header",
"extra VG metadata content",
"LVM1 metadata",
"pool metadata",
"LV content",
"logging",
H3. A bounce buffer is used for most I/O.
H4. Most callers finish using the supplied data before any further I/O is
issued. The few that don't could be converted trivially to do so.
H5. There is one stream of I/O per metadata area on each device.
H6. Some reads fall at offsets close to immediately preceding reads, so it's
possible to avoid these by caching one "block" per metadata area I/O stream.
H7. Simple analysis suggests a minimum aligned read size of 8k would deliver
immediate gains from this caching. A larger size might perform worse because
almost all the time the extra data read would not be used, but this can be
re-examined and tuned after the code is in place.
Proposal
--------
P1. Retain the "single I/O path" but offer an asynchronous option.
P2. Eliminate the bounce buffer in most cases by improving alignment.
P3. Reduce the number of reads by always reading a minimum of an aligned
8k block.
P4. Eliminate repeated reads by caching the last block read and changing
the lib/device interface to return a pointer to read-only data within
this block.
P5. Only perform these interface changes for code on the critical path
for now by converting other code sites to use wrappers around the new
interface.
P6. Treat asynchronous I/O as the interface of choice and optimise only
for this case.
P7. Convert the callers on the critical path to pass callback functions
to the device layer. These functions will be called later with the
read-only data, a context pointer and a success/failure indicator.
Where an existing function performs a sequence of I/O, this has the
advantage of breaking up the large function into smaller ones and
wrapping the parameters used into structures. While this might look
rather messy and ad-hoc in the short-term, it's a first step towards
breaking up confusingly long functions into component parts and wrapping
the existing long parameter lists into more appropriate structures and
refactoring these parts of the code.
P8. Limit the resources used by the asynchronous I/O by using two
tunable parameters, one limiting the number of outstanding I/Os issued
and another limiting the total amount of memory used.
P9. Provide a fallback option if asynchronous I/O is unavailable by
sharing the code paths but issuing the I/O synchronously and calling the
callback immediately.
P10. Only allocate the buffer for the I/O at the point where the I/O is
about to be issued.
P11. If the thresholds are exceeded, add the request to a simple queue,
and process it later after some I/O has completed.
Future work
-----------
F1. Perform a complete review of the error tracking so that device
failures are handled and reported more cleanly, extending the existing
basic error counting mechanism.
F2. Consider whether some of the nested callbacks can be eliminated,
which would allow for additional simplifications.
F3. Adjust the contents of the adhoc context structs into more logical
arrangements and use them more widely.
F4. Perform wider refactoring of these areas of code.
Testing considerations
----------------------
T1. The changes touch code on the device path, so a thorough re-test of
the device layer is required. The new code needs a full audit down
through the library layer into the kernel to check that all the error
conditions that are currently implemented (such as EAGAIN) are handled
sensibly. (LVM's I/O layer needs to remain as solid as we can make it.)
T2. The current test suite provides a reasonably broad range of coverage
of this area but is far from comprehensive.
Acceptance criteria
-------------------
A1. The current test suite should pass to the same extent as before the
changes.
A2. When all debugging and logging is disabled, strace -c must show
improvements e.g. the expected fewer number of reads.
A3. Running a range of commands under valgrind must not reveal any
new leaks due to the changes.
A4. All new coverity reports from the change must be addressed.
A5. CPU time should be similar to that before, as the same work
is being done overall, just in a different order.
A6. Tests need to show improved behaviour in targetted areas. For example,
if several devices are slow and time out, the delays should occur
in parallel and the elapsed time should be less than before.
Release considerations
----------------------
R1. Async I/O should be widely available and largely reliable on linux
nowadays (even though parts of its interface and implementation remain a
matter of controversy) so we should try to make its use the default
whereever it is supported. If certain types of systems have problems we
should try to detect those cases and disable it automatically there.
R2. Because the implications of an unexpected problem in the new code
could be severe for the people affected, the roll out needs to be gentle
without a deadline to allow us plenty of time to gain confidence in the
new code. Our own testing will only be able to cover a tiny fraction of
the different setups our users have, so we need to look out for problems
caused by this proactively and encourage people to test it on their own
systems and report back. It must go into the tree near the start of a
release cycle rather than at the end to provide time for our confidence
in it to grow.

View File

@ -14,6 +14,7 @@
@top_srcdir@/lib/config/defaults.h
@top_srcdir@/lib/datastruct/btree.h
@top_srcdir@/lib/datastruct/str_list.h
@top_srcdir@/lib/device/bcache.h
@top_srcdir@/lib/device/dev-cache.h
@top_srcdir@/lib/device/dev-ext-udev-constants.h
@top_srcdir@/lib/device/dev-type.h

View File

@ -1,8 +1,5 @@
/* include/configure.h.in. Generated from configure.in by autoheader. */
/* Define to 1 if aio is available. */
#undef AIO_SUPPORT
/* Define to 1 to use libblkid detection of signatures when wiping. */
#undef BLKID_WIPING_SUPPORT
@ -350,9 +347,6 @@
/* Define to 1 if the system has the type `ptrdiff_t'. */
#undef HAVE_PTRDIFF_T
/* Define to 1 if the compiler has the `__builtin_clz` builtin. */
#undef HAVE___BUILTIN_CLZ
/* Define to 1 if you have the <readline/history.h> header file. */
#undef HAVE_READLINE_HISTORY_H
@ -481,9 +475,16 @@
/* Define to 1 if you have the `strtoull' function. */
#undef HAVE_STRTOULL
/* Define to 1 if `st_blocks' is a member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_BLOCKS
/* Define to 1 if `st_rdev' is a member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_RDEV
/* Define to 1 if your `struct stat' has `st_blocks'. Deprecated, use
`HAVE_STRUCT_STAT_ST_BLOCKS' instead. */
#undef HAVE_ST_BLOCKS
/* Define to 1 if you have the <syslog.h> header file. */
#undef HAVE_SYSLOG_H
@ -555,6 +556,9 @@
/* Define to 1 if you have the <sys/utsname.h> header file. */
#undef HAVE_SYS_UTSNAME_H
/* Define to 1 if you have the <sys/vfs.h> header file. */
#undef HAVE_SYS_VFS_H
/* Define to 1 if you have the <sys/wait.h> header file. */
#undef HAVE_SYS_WAIT_H
@ -594,6 +598,9 @@
/* Define to 1 if the system has the type `_Bool'. */
#undef HAVE__BOOL
/* Define to 1 if the system has the `__builtin_clz' built-in function */
#undef HAVE___BUILTIN_CLZ
/* Internalization package */
#undef INTL_PACKAGE

View File

@ -55,6 +55,7 @@ SOURCES =\
config/config.c \
datastruct/btree.c \
datastruct/str_list.c \
device/bcache.c \
device/dev-cache.c \
device/dev-ext.c \
device/dev-io.c \

View File

@ -28,6 +28,7 @@
#include "config.h"
#include "segtype.h"
#include "sharedlib.h"
#include "lvmcache.h"
#include <limits.h>
#include <fcntl.h>
@ -2172,6 +2173,17 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
if (!lv_info(cmd, lv, laopts->origin_only, &info, 0, 0))
goto_out;
/*
* Save old and new (current and precommitted) versions of the
* VG metadata for lv_resume() to use, since lv_resume can't
* read metadata given that devices are suspended. lv_resume()
* will resume LVs using the old/current metadata if the vg_commit
* did happen (or failed), and it will resume LVs using the
* new/precommitted metadata if the vg_commit succeeded.
*/
lvmcache_save_suspended_vg(lv->vg, 0);
lvmcache_save_suspended_vg(lv_pre->vg, 1);
if (!info.exists || info.suspended) {
if (!error_if_not_suspended) {
r = 1;
@ -2378,16 +2390,55 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
struct lv_activate_opts *laopts, int error_if_not_active,
const struct logical_volume *lv)
{
const struct logical_volume *lv_to_free = NULL;
struct dm_list *snh;
struct volume_group *vg = NULL;
struct logical_volume *lv_found = NULL;
const union lvid *lvid;
const char *vgid;
struct lvinfo info;
int r = 0;
if (!activation())
return 1;
if (!lv && !(lv_to_free = lv = lv_from_lvid(cmd, lvid_s, 0)))
goto_out;
/*
* When called in clvmd, lvid_s is set and lv is not. We need to
* get the VG metadata without reading disks because devs are
* suspended. lv_suspend() saved old and new VG metadata for us
* to use here. If vg_commit() happened, lvmcache_get_suspended_vg
* will return the new metadata for us to use in resuming LVs.
* If vg_commit() did not happen, lvmcache_get_suspended_vg
* returns the old metadata which we use to resume LVs.
*/
if (!lv && lvid_s) {
lvid = (const union lvid *) lvid_s;
vgid = (const char *)lvid->id[0].uuid;
if ((vg = lvmcache_get_suspended_vg(vgid))) {
log_debug_activation("Resuming LVID %s found saved vg seqno %d %s", lvid_s, vg->seqno, vg->name);
if ((lv_found = find_lv_in_vg_by_lvid(vg, lvid))) {
log_debug_activation("Resuming LVID %s found saved LV %s", lvid_s, display_lvname(lv_found));
lv = lv_found;
} else
log_debug_activation("Resuming LVID %s did not find saved LV", lvid_s);
} else
log_debug_activation("Resuming LVID %s did not find saved VG", lvid_s);
/*
* resume must have been called without a preceding suspend,
* so we need to read the vg.
*/
if (!lv) {
log_debug_activation("Resuming LVID %s reading VG", lvid_s);
if (!(lv_found = lv_from_lvid(cmd, lvid_s, 0))) {
log_debug_activation("Resuming LVID %s failed to read VG", lvid_s);
goto out;
}
lv = lv_found;
}
}
if (!lv_is_origin(lv) && !lv_is_thin_volume(lv) && !lv_is_thin_pool(lv))
laopts->origin_only = 0;
@ -2448,9 +2499,6 @@ needs_resume:
r = 1;
out:
if (lv_to_free)
release_vg(lv_to_free->vg);
return r;
}
@ -2587,6 +2635,10 @@ int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s,
int *activate_lv, const struct logical_volume *lv)
{
const struct logical_volume *lv_to_free = NULL;
struct volume_group *vg = NULL;
struct logical_volume *lv_found = NULL;
const union lvid *lvid;
const char *vgid;
int r = 0;
if (!activation()) {
@ -2594,6 +2646,24 @@ int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s,
return 1;
}
/*
* This function is called while devices are suspended,
* so try to use the copy of the vg that was saved in
* lv_suspend.
*/
if (!lv && lvid_s) {
lvid = (const union lvid *) lvid_s;
vgid = (const char *)lvid->id[0].uuid;
if ((vg = lvmcache_get_suspended_vg(vgid))) {
log_debug_activation("activation_filter for %s found saved VG seqno %d %s", lvid_s, vg->seqno, vg->name);
if ((lv_found = find_lv_in_vg_by_lvid(vg, lvid))) {
log_debug_activation("activation_filter for %s found saved LV %s", lvid_s, display_lvname(lv_found));
lv = lv_found;
}
}
}
if (!lv && !(lv_to_free = lv = lv_from_lvid(cmd, lvid_s, 0)))
goto_out;

1096
lib/cache/lvmcache.c vendored

File diff suppressed because it is too large Load Diff

40
lib/cache/lvmcache.h vendored
View File

@ -59,6 +59,8 @@ struct lvmcache_vgsummary {
const char *lock_type;
uint32_t mda_checksum;
size_t mda_size;
int zero_offset;
int seqno;
};
int lvmcache_init(void);
@ -66,14 +68,8 @@ void lvmcache_allow_reads_with_lvmetad(void);
void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans, int reset);
/*
* lvmcache_label_scan() will scan labels the first time it's
* called, but not on subsequent calls, unless
* lvmcache_force_next_label_scan() is called first
* to force the next lvmcache_label_scan() to scan again.
*/
void lvmcache_force_next_label_scan(void);
int lvmcache_label_scan(struct cmd_context *cmd);
int lvmcache_label_rescan_vg(struct cmd_context *cmd, const char *vgname, const char *vgid);
/* Add/delete a device */
struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
@ -82,10 +78,11 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
uint32_t vgstatus);
int lvmcache_add_orphan_vginfo(const char *vgname, struct format_type *fmt);
void lvmcache_del(struct lvmcache_info *info);
void lvmcache_del_dev(struct device *dev);
/* Update things */
int lvmcache_update_vgname_and_id(struct lvmcache_info *info,
const struct lvmcache_vgsummary *vgsummary);
struct lvmcache_vgsummary *vgsummary);
int lvmcache_update_vg(struct volume_group *vg, unsigned precommitted);
void lvmcache_lock_vgname(const char *vgname, int read_only);
@ -105,10 +102,8 @@ struct lvmcache_vginfo *lvmcache_vginfo_from_vgid(const char *vgid);
struct lvmcache_info *lvmcache_info_from_pvid(const char *pvid, struct device *dev, int valid_only);
const char *lvmcache_vgname_from_vgid(struct dm_pool *mem, const char *vgid);
const char *lvmcache_vgid_from_vgname(struct cmd_context *cmd, const char *vgname);
struct device *lvmcache_device_from_pvid(struct cmd_context *cmd, const struct id *pvid,
unsigned *scan_done_once, uint64_t *label_sector);
const char *lvmcache_pvid_from_devname(struct cmd_context *cmd,
const char *devname);
struct device *lvmcache_device_from_pvid(struct cmd_context *cmd, const struct id *pvid, uint64_t *label_sector);
const char *lvmcache_pvid_from_devname(struct cmd_context *cmd, const char *devname);
char *lvmcache_vgname_from_pvid(struct cmd_context *cmd, const char *pvid);
const char *lvmcache_vgname_from_info(struct lvmcache_info *info);
const struct format_type *lvmcache_fmt_from_info(struct lvmcache_info *info);
@ -134,9 +129,6 @@ int lvmcache_get_vgnameids(struct cmd_context *cmd, int include_internal,
struct dm_list *lvmcache_get_pvids(struct cmd_context *cmd, const char *vgname,
const char *vgid);
/* Returns cached volume group metadata. */
struct volume_group *lvmcache_get_vg(struct cmd_context *cmd, const char *vgname,
const char *vgid, unsigned precommitted);
void lvmcache_drop_metadata(const char *vgname, int drop_precommitted);
void lvmcache_commit_metadata(const char *vgname);
@ -146,8 +138,8 @@ int lvmcache_fid_add_mdas(struct lvmcache_info *info, struct format_instance *fi
int lvmcache_fid_add_mdas_pv(struct lvmcache_info *info, struct format_instance *fid);
int lvmcache_fid_add_mdas_vg(struct lvmcache_vginfo *vginfo, struct format_instance *fid);
int lvmcache_populate_pv_fields(struct lvmcache_info *info,
struct physical_volume *pv,
int scan_label_only);
struct volume_group *vg,
struct physical_volume *pv);
int lvmcache_check_format(struct lvmcache_info *info, const struct format_type *fmt);
void lvmcache_del_mdas(struct lvmcache_info *info);
void lvmcache_del_das(struct lvmcache_info *info);
@ -164,6 +156,8 @@ uint32_t lvmcache_ext_flags(struct lvmcache_info *info);
const struct format_type *lvmcache_fmt(struct lvmcache_info *info);
struct label *lvmcache_get_label(struct lvmcache_info *info);
struct label *lvmcache_get_dev_label(struct device *dev);
int lvmcache_has_dev_info(struct device *dev);
void lvmcache_update_pv(struct lvmcache_info *info, struct physical_volume *pv,
const struct format_type *fmt);
@ -187,7 +181,6 @@ int lvmcache_foreach_pv(struct lvmcache_vginfo *vginfo,
uint64_t lvmcache_device_size(struct lvmcache_info *info);
void lvmcache_set_device_size(struct lvmcache_info *info, uint64_t size);
struct device *lvmcache_device(struct lvmcache_info *info);
void lvmcache_make_valid(struct lvmcache_info *info);
int lvmcache_is_orphan(struct lvmcache_info *info);
int lvmcache_uncertain_ownership(struct lvmcache_info *info);
unsigned lvmcache_mda_count(struct lvmcache_info *info);
@ -215,4 +208,15 @@ void lvmcache_remove_unchosen_duplicate(struct device *dev);
int lvmcache_pvid_in_unchosen_duplicates(const char *pvid);
int lvmcache_get_vg_devs(struct cmd_context *cmd,
struct lvmcache_vginfo *vginfo,
struct dm_list *devs);
void lvmcache_set_independent_location(const char *vgname);
void lvmcache_save_suspended_vg(struct volume_group *vg, int precommitted);
struct volume_group *lvmcache_get_suspended_vg(const char *vgid);
void lvmcache_drop_suspended_vg(struct volume_group *vg);
int lvmcache_scan_mismatch(struct cmd_context *cmd, const char *vgname, const char *vgid);
#endif

487
lib/cache/lvmetad.c vendored
View File

@ -39,7 +39,7 @@ static int64_t _lvmetad_update_timeout;
static int _found_lvm1_metadata = 0;
static struct volume_group *_lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg);
static struct volume_group *_lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg, const char *vgid, struct format_type *fmt);
static uint64_t _monotonic_seconds(void)
{
@ -1093,14 +1093,17 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgna
* invalidated the cached vg.
*/
if (rescan) {
if (!(vg2 = _lvmetad_pvscan_vg(cmd, vg))) {
if (!(vg2 = _lvmetad_pvscan_vg(cmd, vg, vgid, fmt))) {
log_debug_lvmetad("VG %s from lvmetad not found during rescan.", vgname);
fid = NULL;
release_vg(vg);
vg = NULL;
goto out;
}
fid->ref_count++;
release_vg(vg);
fid->ref_count--;
fmt->ops->destroy_instance(fid);
vg = vg2;
fid = vg2->fid;
}
@ -1108,14 +1111,14 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgna
dm_list_iterate_items(pvl, &vg->pvs) {
if (!_pv_update_struct_pv(pvl->pv, fid)) {
vg = NULL;
goto_out; /* FIXME error path */
goto_out; /* FIXME: use an error path that disables lvmetad */
}
}
dm_list_iterate_items(pvl, &vg->pvs_outdated) {
if (!_pv_update_struct_pv(pvl->pv, fid)) {
vg = NULL;
goto_out; /* FIXME error path */
goto_out; /* FIXME: use an error path that disables lvmetad */
}
}
@ -1761,6 +1764,7 @@ int lvmetad_pv_gone_by_dev(struct device *dev)
*/
struct _lvmetad_pvscan_baton {
struct cmd_context *cmd;
struct volume_group *vg;
struct format_instance *fid;
};
@ -1771,7 +1775,7 @@ static int _lvmetad_pvscan_single(struct metadata_area *mda, void *baton)
struct volume_group *vg;
if (mda_is_ignored(mda) ||
!(vg = mda->ops->vg_read(b->fid, "", mda, NULL, NULL, 1, 0)))
!(vg = mda->ops->vg_read(b->fid, "", mda, NULL, NULL)))
return 1;
/* FIXME Also ensure contents match etc. */
@ -1783,6 +1787,33 @@ static int _lvmetad_pvscan_single(struct metadata_area *mda, void *baton)
return 1;
}
/*
* FIXME: handle errors and do proper comparison of metadata from each area
* like vg_read and fall back to real vg_read from disk if there's any problem.
*/
static int _lvmetad_pvscan_vg_single(struct metadata_area *mda, void *baton)
{
struct _lvmetad_pvscan_baton *b = baton;
struct volume_group *vg = NULL;
if (mda_is_ignored(mda))
return 1;
if (!(vg = mda->ops->vg_read(b->fid, "", mda, NULL, NULL)))
return 1;
if (!b->vg)
b->vg = vg;
else if (vg->seqno > b->vg->seqno) {
release_vg(b->vg);
b->vg = vg;
} else
release_vg(vg);
return 1;
}
/*
* The lock manager may detect that the vg cached in lvmetad is out of date,
* due to something like an lvcreate from another host.
@ -1792,41 +1823,41 @@ static int _lvmetad_pvscan_single(struct metadata_area *mda, void *baton)
* the VG, and that PV may have been reused for another VG.
*/
static struct volume_group *_lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg)
static struct volume_group *_lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg,
const char *vgid, struct format_type *fmt)
{
char pvid_s[ID_LEN + 1] __attribute__((aligned(8)));
char uuid[64] __attribute__((aligned(8)));
struct label *label;
struct volume_group *vg_ret = NULL;
struct dm_config_tree *vgmeta_ret = NULL;
struct dm_config_tree *vgmeta;
struct pv_list *pvl, *pvl_new;
struct device_list *devl, *devl_new, *devlsafe;
struct device_list *devl, *devlsafe;
struct dm_list pvs_scan;
struct dm_list pvs_drop;
struct dm_list pvs_new;
struct lvmcache_vginfo *vginfo = NULL;
struct lvmcache_info *info = NULL;
struct format_instance *fid;
struct format_instance_ctx fic = { .type = 0 };
struct _lvmetad_pvscan_baton baton;
struct volume_group *save_vg;
struct dm_config_tree *save_meta;
struct device *save_dev = NULL;
uint32_t save_seqno = 0;
int missing_devs = 0;
int check_new_pvs = 0;
int found_new_pvs = 0;
int retried_reads = 0;
int found;
save_vg = NULL;
save_meta = NULL;
save_dev = NULL;
save_seqno = 0;
dm_list_init(&pvs_scan);
dm_list_init(&pvs_drop);
dm_list_init(&pvs_new);
log_debug_lvmetad("Rescanning VG %s (seqno %u).", vg->name, vg->seqno);
log_debug_lvmetad("Rescan VG %s to update lvmetad (seqno %u).", vg->name, vg->seqno);
/*
* Another host may have added a PV to the VG, and some
* commands do not always populate their lvmcache with
* all devs from lvmetad, so they would fail to find
* the new PV when scanning the VG. So make sure this
* command knows about all PVs from lvmetad.
* Make sure this command knows about all PVs from lvmetad.
*/
lvmcache_seed_infos_from_lvmetad(cmd);
@ -1841,54 +1872,111 @@ static struct volume_group *_lvmetad_pvscan_vg(struct cmd_context *cmd, struct v
dm_list_add(&pvs_scan, &devl->list);
}
scan_more:
/*
* Rescan labels/metadata only from devs that we previously
* saw in the VG. If we find below that there are new PVs
* in the VG, we'll have to rescan all devices to find which
* device(s) are now being used.
*/
log_debug_lvmetad("Rescan VG %s scanning data from devs in previous metadata.", vg->name);
label_scan_devs(cmd, &pvs_scan);
/*
* Run the equivalent of lvmetad_pvscan_single on each dev in the VG.
* Check if any pvs_scan entries are no longer PVs.
* In that case, label_read/_find_label_header will have
* found no label_header, and would have dropped the
* info struct for the device from lvmcache. So, if
* we look up the info struct here and don't find it,
* we can infer it's no longer a PV.
*
* FIXME: we should record specific results from the
* label_read and then check specifically for whatever
* result means "no label was found", rather than going
* about this indirectly via the lvmcache side effects.
*/
dm_list_iterate_items_safe(devl, devlsafe, &pvs_scan) {
if (!(info = lvmcache_info_from_pvid(devl->dev->pvid, devl->dev, 0))) {
/* Another host removed this PV from the VG. */
log_debug_lvmetad("Rescan VG %s from %s dropping dev (no label).",
vg->name, dev_name(devl->dev));
dm_list_move(&pvs_drop, &devl->list);
}
}
fic.type = FMT_INSTANCE_MDAS | FMT_INSTANCE_AUX_MDAS;
fic.context.vg_ref.vg_name = vg->name;
fic.context.vg_ref.vg_id = vgid;
retry_reads:
if (!(fid = fmt->ops->create_instance(fmt, &fic))) {
/* FIXME: are there only internal reasons for failures here? */
log_error("Reading VG %s failed to create format instance.", vg->name);
return NULL;
}
/* FIXME: not sure if this is necessary */
fid->ref_count++;
baton.fid = fid;
baton.cmd = cmd;
/*
* FIXME: this vg_read path does not have the ability to repair
* any problems with the VG, e.g. VG on one dev has an older
* seqno. When vg_read() is reworked, we need to fall back
* to using that from here (and vg_read's from lvmetad) when
* there is a problem. Perhaps by disabling lvmetad when a
* VG problem is detected, causing commands to fully fall
* back to disk, which will repair the VG. Then lvmetad can
* be repopulated and re-enabled (possibly automatically.)
*/
/*
* Do a low level vg_read on each dev, verify the vg returned
* from metadata on each device is for the VG being read
* (the PV may have been removed from the VG being read and
* added to a different one), and return this vg to the caller
* as the current vg to use.
*
* The label scan above will have saved in lvmcache which
* vg each device is used in, so we could figure that part
* out without doing the vg_read.
*/
dm_list_iterate_items_safe(devl, devlsafe, &pvs_scan) {
if (!devl->dev)
continue;
log_debug_lvmetad("Rescan VG %s scanning %s.", vg->name, dev_name(devl->dev));
if (!label_read(devl->dev, &label, 0)) {
/* Another host removed this PV from the VG. */
log_debug_lvmetad("Rescan VG %s found %s was removed.", vg->name, dev_name(devl->dev));
if ((info = lvmcache_info_from_pvid(devl->dev->pvid, NULL, 0)))
lvmcache_del(info);
log_debug_lvmetad("Rescan VG %s getting metadata from %s.",
vg->name, dev_name(devl->dev));
/*
* The info struct for this dev knows what and where
* the mdas are for this dev (the label scan saved
* the mda locations for this dev on the lvmcache info struct).
*/
if (!(info = lvmcache_info_from_pvid(devl->dev->pvid, devl->dev, 0))) {
log_debug_lvmetad("Rescan VG %s from %s dropping dev (no info).",
vg->name, dev_name(devl->dev));
dm_list_move(&pvs_drop, &devl->list);
continue;
}
info = (struct lvmcache_info *) label->info;
baton.vg = NULL;
baton.fid = lvmcache_fmt(info)->ops->create_instance(lvmcache_fmt(info), &fic);
if (!baton.fid)
return_NULL;
if (baton.fid->fmt->features & FMT_OBSOLETE) {
log_debug_lvmetad("Ignoring obsolete format on PV %s in VG %s.", dev_name(devl->dev), vg->name);
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
dm_list_move(&pvs_drop, &devl->list);
continue;
}
/*
* Read VG metadata from this dev's mdas.
*/
lvmcache_foreach_mda(info, _lvmetad_pvscan_single, &baton);
lvmcache_foreach_mda(info, _lvmetad_pvscan_vg_single, &baton);
/*
* The PV may have been removed from the VG by another host
* since we last read the VG.
*/
if (!baton.vg) {
log_debug_lvmetad("Rescan VG %s did not find %s.", vg->name, dev_name(devl->dev));
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
log_debug_lvmetad("Rescan VG %s from %s dropping dev (no metadata).",
vg->name, dev_name(devl->dev));
dm_list_move(&pvs_drop, &devl->list);
continue;
}
@ -1898,10 +1986,15 @@ scan_more:
* different VG since we last read the VG.
*/
if (strcmp(baton.vg->name, vg->name)) {
log_debug_lvmetad("Rescan VG %s found different VG %s on PV %s.",
vg->name, baton.vg->name, dev_name(devl->dev));
log_debug_lvmetad("Rescan VG %s from %s dropping dev (other VG %s).",
vg->name, dev_name(devl->dev), baton.vg->name);
release_vg(baton.vg);
continue;
}
if (!(vgmeta = export_vg_to_config_tree(baton.vg))) {
log_error("VG export to config tree failed");
release_vg(baton.vg);
dm_list_move(&pvs_drop, &devl->list);
continue;
}
@ -1911,20 +2004,35 @@ scan_more:
* read from each other dev.
*/
if (!save_seqno)
save_seqno = baton.vg->seqno;
if (save_vg && (save_seqno != baton.vg->seqno)) {
/* FIXME: fall back to vg_read to correct this. */
log_warn("WARNING: inconsistent metadata for VG %s on devices %s seqno %u and %s seqno %u.",
vg->name, dev_name(save_dev), save_seqno,
dev_name(devl->dev), baton.vg->seqno);
log_warn("WARNING: temporarily disable lvmetad to repair metadata.");
if (!(vgmeta = export_vg_to_config_tree(baton.vg))) {
log_error("VG export to config tree failed");
release_vg(baton.vg);
return NULL;
/* Use the most recent */
if (save_seqno < baton.vg->seqno) {
release_vg(save_vg);
dm_config_destroy(save_meta);
save_vg = baton.vg;
save_meta = vgmeta;
save_seqno = baton.vg->seqno;
save_dev = devl->dev;
} else {
release_vg(baton.vg);
dm_config_destroy(vgmeta);
}
continue;
}
if (!vgmeta_ret) {
vgmeta_ret = vgmeta;
if (!save_vg) {
save_vg = baton.vg;
save_meta = vgmeta;
save_seqno = baton.vg->seqno;
save_dev = devl->dev;
} else {
struct dm_config_node *meta1 = vgmeta_ret->root;
struct dm_config_node *meta1 = save_meta->root;
struct dm_config_node *meta2 = vgmeta->root;
struct dm_config_node *sib1 = meta1->sib;
struct dm_config_node *sib2 = meta2->sib;
@ -1949,73 +2057,128 @@ scan_more:
meta2->sib = NULL;
if (compare_config(meta1, meta2)) {
/* FIXME: fall back to vg_read to correct this. */
log_warn("WARNING: inconsistent metadata for VG %s on devices %s seqno %u and %s seqno %u.",
vg->name, dev_name(save_dev), save_seqno,
dev_name(devl->dev), baton.vg->seqno);
log_warn("WARNING: temporarily disable lvmetad to repair metadata.");
log_error("VG %s metadata comparison failed for device %s vs %s",
vg->name, dev_name(devl->dev), save_dev ? dev_name(save_dev) : "none");
_log_debug_inequality(vg->name, vgmeta_ret->root, vgmeta->root);
_log_debug_inequality(vg->name, save_meta->root, vgmeta->root);
meta1->sib = sib1;
meta2->sib = sib2;
dm_config_destroy(vgmeta);
dm_config_destroy(vgmeta_ret);
/* no right choice, just use the previous copy */
release_vg(baton.vg);
return NULL;
dm_config_destroy(vgmeta);
}
meta1->sib = sib1;
meta2->sib = sib2;
release_vg(baton.vg);
dm_config_destroy(vgmeta);
}
}
/*
* Look for any new PVs in the VG metadata that were not in our
* previous version of the VG. Add them to pvs_new to be
* scanned in this loop just like the old PVs.
*/
if (!check_new_pvs) {
check_new_pvs = 1;
dm_list_iterate_items(pvl_new, &baton.vg->pvs) {
found = 0;
dm_list_iterate_items(pvl, &vg->pvs) {
if (pvl_new->pv->dev != pvl->pv->dev)
continue;
found = 1;
break;
}
if (found)
/* FIXME: see above */
fid->ref_count--;
/*
* Look for any new PVs in the VG metadata that were not in our
* previous version of the VG.
*
* (Don't look for new PVs after a rescan and retry.)
*/
found_new_pvs = 0;
if (save_vg && !retried_reads) {
dm_list_iterate_items(pvl_new, &save_vg->pvs) {
found = 0;
dm_list_iterate_items(pvl, &vg->pvs) {
if (pvl_new->pv->dev != pvl->pv->dev)
continue;
if (!pvl_new->pv->dev) {
strncpy(pvid_s, (char *) &pvl_new->pv->id, sizeof(pvid_s) - 1);
if (!id_write_format((const struct id *)&pvid_s, uuid, sizeof(uuid)))
stack;
log_error("Device not found for PV %s in VG %s", uuid, vg->name);
missing_devs++;
continue;
}
if (!(devl_new = dm_pool_zalloc(cmd->mem, sizeof(*devl_new))))
return_NULL;
devl_new->dev = pvl_new->pv->dev;
dm_list_add(&pvs_new, &devl_new->list);
log_debug_lvmetad("Rescan VG %s found %s was added.", vg->name, dev_name(devl_new->dev));
found = 1;
break;
}
/*
* PV in new VG metadata not found in old VG metadata.
* There's a good chance we don't know about this new
* PV or what device it's on; a label scan is needed
* of all devices so we know which device the VG is
* now using.
*/
if (!found) {
found_new_pvs++;
strncpy(pvid_s, (char *) &pvl_new->pv->id, sizeof(pvid_s) - 1);
if (!id_write_format((const struct id *)&pvid_s, uuid, sizeof(uuid)))
stack;
log_debug_lvmetad("Rescan VG %s found new PV %s.", vg->name, uuid);
}
}
}
release_vg(baton.vg);
if (!save_vg && retried_reads) {
log_error("VG %s not found after rescanning devices.", vg->name);
goto out;
}
/*
* Do the same scanning above for any new PVs.
* Do a full rescan of devices, then look up which devices the
* scan found for this VG name, and select those devices to
* read metadata from in the loop above (rather than the list
* of devices we created from our last copy of the vg metadata.)
*
* Case 1: VG we knew is no longer on any of the devices we knew it
* to be on (save_vg is NULL, which means the metadata wasn't found
* when reading mdas on each of the initial pvs_scan devices).
* Rescan all devs and then retry reading metadata from the devs that
* the scan finds associated with this VG.
*
* Case 2: VG has new PVs but we don't know what devices they are
* so rescan all devs and then retry reading metadata from the devs
* that the scan finds associated with this VG.
*
* (N.B. after a retry, we don't check for found_new_pvs.)
*/
if (!dm_list_empty(&pvs_new)) {
dm_list_init(&pvs_scan);
dm_list_splice(&pvs_scan, &pvs_new);
dm_list_init(&pvs_new);
log_debug_lvmetad("Rescan VG %s found new PVs to scan.", vg->name);
goto scan_more;
}
if (!save_vg || found_new_pvs) {
if (!save_vg)
log_debug_lvmetad("Rescan VG %s did not find VG on previous devs.", vg->name);
if (found_new_pvs)
log_debug_lvmetad("Rescan VG %s scanning all devs to find new PVs.", vg->name);
if (missing_devs) {
if (vgmeta_ret)
dm_config_destroy(vgmeta_ret);
return_NULL;
label_scan(cmd);
if (!(vginfo = lvmcache_vginfo_from_vgname(vg->name, NULL))) {
log_error("VG %s vg info not found after rescanning devices.", vg->name);
goto out;
}
/*
* Set pvs_scan to devs that the label scan found
* in the VG and retry the metadata reading loop.
*/
dm_list_init(&pvs_scan);
if (!lvmcache_get_vg_devs(cmd, vginfo, &pvs_scan)) {
log_error("VG %s info devs not found after rescanning devices.", vg->name);
goto out;
}
log_debug_lvmetad("Rescan VG %s has %d PVs after label scan.",
vg->name, dm_list_size(&pvs_scan));
if (save_vg)
release_vg(save_vg);
if (save_meta)
dm_config_destroy(save_meta);
save_vg = NULL;
save_meta = NULL;
save_dev = NULL;
save_seqno = 0;
found_new_pvs = 0;
retried_reads = 1;
goto retry_reads;
}
/*
@ -2024,52 +2187,50 @@ scan_more:
dm_list_iterate_items(devl, &pvs_drop) {
if (!devl->dev)
continue;
log_debug_lvmetad("Rescan VG %s dropping %s.", vg->name, dev_name(devl->dev));
if (!lvmetad_pv_gone_by_dev(devl->dev))
return_NULL;
log_debug_lvmetad("Rescan VG %s removing %s from lvmetad.", vg->name, dev_name(devl->dev));
if (!lvmetad_pv_gone_by_dev(devl->dev)) {
/* FIXME: use an error path that disables lvmetad */
log_error("Failed to remove %s from lvmetad.", dev_name(devl->dev));
}
}
/*
* Update the VG in lvmetad.
* Update lvmetad with the newly read version of the VG.
* When the seqno is unchanged the cached VG can be left.
*/
if (vgmeta_ret) {
fid = lvmcache_fmt(info)->ops->create_instance(lvmcache_fmt(info), &fic);
if (!(vg_ret = import_vg_from_config_tree(vgmeta_ret, fid))) {
log_error("VG import from config tree failed");
lvmcache_fmt(info)->ops->destroy_instance(fid);
goto out;
if (save_vg && (save_seqno != vg->seqno)) {
dm_list_iterate_items(devl, &pvs_scan) {
if (!devl->dev)
continue;
log_debug_lvmetad("Rescan VG %s removing %s from lvmetad to replace.",
vg->name, dev_name(devl->dev));
if (!lvmetad_pv_gone_by_dev(devl->dev)) {
/* FIXME: use an error path that disables lvmetad */
log_error("Failed to remove %s from lvmetad.", dev_name(devl->dev));
}
}
log_debug_lvmetad("Rescan VG %s updating lvmetad from seqno %u to seqno %u.",
vg->name, vg->seqno, save_seqno);
/*
* Update lvmetad with the newly read version of the VG.
* When the seqno is unchanged the cached VG can be left.
* If this vg_update fails the cached metadata in
* lvmetad will remain invalid.
*/
if (save_seqno != vg->seqno) {
dm_list_iterate_items(devl, &pvs_scan) {
if (!devl->dev)
continue;
log_debug_lvmetad("Rescan VG %s dropping to replace %s.", vg->name, dev_name(devl->dev));
if (!lvmetad_pv_gone_by_dev(devl->dev))
return_NULL;
}
log_debug_lvmetad("Rescan VG %s updating lvmetad from seqno %u to seqno %u.",
vg->name, vg->seqno, save_seqno);
/*
* If this vg_update fails the cached metadata in
* lvmetad will remain invalid.
*/
vg_ret->lvmetad_update_pending = 1;
if (!lvmetad_vg_update_finish(vg_ret))
log_error("Failed to update lvmetad with new VG meta");
save_vg->lvmetad_update_pending = 1;
if (!lvmetad_vg_update_finish(save_vg)) {
/* FIXME: use an error path that disables lvmetad */
log_error("Failed to update lvmetad with new VG meta");
}
dm_config_destroy(vgmeta_ret);
}
out:
if (vg_ret)
log_debug_lvmetad("Rescan VG %s done (seqno %u).", vg_ret->name, vg_ret->seqno);
return vg_ret;
if (!save_vg && fid)
fmt->ops->destroy_instance(fid);
if (save_meta)
dm_config_destroy(save_meta);
if (save_vg)
log_debug_lvmetad("Rescan VG %s done (new seqno %u).", save_vg->name, save_vg->seqno);
return save_vg;
}
int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
@ -2079,9 +2240,12 @@ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
struct label *label;
struct lvmcache_info *info;
struct _lvmetad_pvscan_baton baton;
const struct format_type *fmt;
/* Create a dummy instance. */
struct format_instance_ctx fic = { .type = 0 };
log_debug_lvmetad("Scan metadata from dev %s", dev_name(dev));
if (!lvmetad_used()) {
log_error("Cannot proceed since lvmetad is not active.");
return 0;
@ -2092,23 +2256,31 @@ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
return 1;
}
if (!label_read(dev, &label, 0)) {
log_print_unless_silent("No PV label found on %s.", dev_name(dev));
if (!(info = lvmcache_info_from_pvid(dev->pvid, dev, 0))) {
log_print_unless_silent("No PV info found on %s for PVID %s.", dev_name(dev), dev->pvid);
if (!lvmetad_pv_gone_by_dev(dev))
goto_bad;
return 1;
}
info = (struct lvmcache_info *) label->info;
if (!(label = lvmcache_get_label(info))) {
log_print_unless_silent("No PV label found for %s.", dev_name(dev));
if (!lvmetad_pv_gone_by_dev(dev))
goto_bad;
return 1;
}
fmt = lvmcache_fmt(info);
baton.cmd = cmd;
baton.vg = NULL;
baton.fid = lvmcache_fmt(info)->ops->create_instance(lvmcache_fmt(info), &fic);
baton.fid = fmt->ops->create_instance(fmt, &fic);
if (!baton.fid)
goto_bad;
if (baton.fid->fmt->features & FMT_OBSOLETE) {
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
if (fmt->features & FMT_OBSOLETE) {
fmt->ops->destroy_instance(baton.fid);
log_warn("WARNING: Disabling lvmetad cache which does not support obsolete (lvm1) metadata.");
lvmetad_set_disabled(cmd, LVMETAD_DISABLE_REASON_LVM1);
_found_lvm1_metadata = 1;
@ -2122,9 +2294,9 @@ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
lvmcache_foreach_mda(info, _lvmetad_pvscan_single, &baton);
if (!baton.vg)
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
fmt->ops->destroy_instance(baton.fid);
if (!lvmetad_pv_found(cmd, (const struct id *) &dev->pvid, dev, lvmcache_fmt(info),
if (!lvmetad_pv_found(cmd, (const struct id *) &dev->pvid, dev, fmt,
label->sector, baton.vg, found_vgnames, changed_vgnames)) {
release_vg(baton.vg);
goto_bad;
@ -2190,6 +2362,13 @@ int lvmetad_pvscan_all_devs(struct cmd_context *cmd, int do_wait)
replacing_other_update = 1;
}
label_scan(cmd);
if (lvmcache_found_duplicate_pvs()) {
log_warn("WARNING: Scan found duplicate PVs.");
return 0;
}
log_verbose("Scanning all devices to update lvmetad.");
if (!(iter = dev_iter_create(cmd->lvmetad_filter, 1))) {
@ -2372,11 +2551,18 @@ static int _lvmetad_get_pv_cache_list(struct cmd_context *cmd, struct dm_list *p
*/
static void _update_pv_in_udev(struct cmd_context *cmd, dev_t devt)
{
struct device *dev;
log_debug_devs("device %d:%d open to update udev",
/*
* FIXME: this is diabled as part of removing dev_opens
* to integrate bcache. If this is really needed, we
* can do a separate open/close here.
*/
log_debug_devs("SKIP device %d:%d open to update udev",
(int)MAJOR(devt), (int)MINOR(devt));
#if 0
struct device *dev;
if (!(dev = dev_cache_get_by_devt(devt, cmd->lvmetad_filter))) {
log_error("_update_pv_in_udev no dev found");
return;
@ -2389,6 +2575,7 @@ static void _update_pv_in_udev(struct cmd_context *cmd, dev_t devt)
if (!dev_close(dev))
stack;
#endif
}
/*
@ -2560,6 +2747,8 @@ void lvmetad_validate_global_cache(struct cmd_context *cmd, int force)
*/
_lvmetad_get_pv_cache_list(cmd, &pvc_before);
log_debug_lvmetad("Rescan all devices to validate global cache.");
/*
* Update the local lvmetad cache so it correctly reflects any
* changes made on remote hosts. (It's possible that this command
@ -2628,7 +2817,7 @@ void lvmetad_validate_global_cache(struct cmd_context *cmd, int force)
_update_changed_pvs_in_udev(cmd, &pvc_before, &pvc_after);
}
log_debug_lvmetad("Validating global lvmetad cache finished");
log_debug_lvmetad("Rescanned all devices");
}
int lvmetad_vg_is_foreign(struct cmd_context *cmd, const char *vgname, const char *vgid)

View File

@ -636,16 +636,6 @@ static int _process_config(struct cmd_context *cmd)
*/
cmd->default_settings.udev_fallback = udev_disabled ? 1 : -1;
#ifdef AIO_SUPPORT
cmd->use_aio = find_config_tree_bool(cmd, devices_use_aio_CFG, NULL);
#else
cmd->use_aio = 0;
#endif
if (cmd->use_aio && !dev_async_setup(cmd))
cmd->use_aio = 0;
log_debug_io("%ssing asynchronous I/O.", cmd->use_aio ? "U" : "Not u");
init_retry_deactivation(find_config_tree_bool(cmd, activation_retry_deactivation_CFG, NULL));
init_activation_checks(find_config_tree_bool(cmd, activation_checks_CFG, NULL));
@ -698,9 +688,6 @@ static int _process_config(struct cmd_context *cmd)
if (find_config_tree_bool(cmd, report_two_word_unknown_device_CFG, NULL))
init_unknown_device_name("unknown device");
init_detect_internal_vg_cache_corruption
(find_config_tree_bool(cmd, global_detect_internal_vg_cache_corruption_CFG, NULL));
if (!_init_system_id(cmd))
return_0;
@ -1298,7 +1285,7 @@ int init_filters(struct cmd_context *cmd, unsigned load_persistent_cache)
lvm_stat_ctim(&ts, &st);
cts = config_file_timestamp(cmd->cft);
if (timespeccmp(&ts, &cts, >) &&
!persistent_filter_load(cmd->mem, cmd->filter, NULL))
!persistent_filter_load(cmd->filter, NULL))
log_verbose("Failed to load existing device cache from %s",
dev_cache);
}
@ -1661,7 +1648,6 @@ static void _init_rand(struct cmd_context *cmd)
static void _init_globals(struct cmd_context *cmd)
{
init_full_scan_done(0);
init_mirror_in_sync(0);
}
@ -2020,7 +2006,6 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
if (set_filters && !init_filters(cmd, 1))
goto_out;
cmd->default_settings.cache_vgmetadata = 1;
cmd->current_settings = cmd->default_settings;
cmd->initialized.config = 1;
@ -2134,6 +2119,7 @@ int refresh_toolcontext(struct cmd_context *cmd)
activation_release();
lvmcache_destroy(cmd, 0, 0);
label_scan_destroy(cmd);
label_exit();
_destroy_segtypes(&cmd->segtypes);
_destroy_formats(cmd, &cmd->formats);
@ -2160,8 +2146,6 @@ int refresh_toolcontext(struct cmd_context *cmd)
cmd->lib_dir = NULL;
label_init();
if (!_init_lvm_conf(cmd))
return_0;
@ -2249,12 +2233,13 @@ void destroy_toolcontext(struct cmd_context *cmd)
int flags;
if (cmd->dump_filter && cmd->filter && cmd->filter->dump &&
!cmd->filter->dump(cmd->filter, cmd->mem, 1))
!cmd->filter->dump(cmd->filter, 1))
stack;
archive_exit(cmd);
backup_exit(cmd);
lvmcache_destroy(cmd, 0, 0);
label_scan_destroy(cmd);
label_exit();
_destroy_segtypes(&cmd->segtypes);
_destroy_formats(cmd, &cmd->formats);

View File

@ -165,11 +165,12 @@ struct cmd_context {
unsigned vg_notify:1;
unsigned lv_notify:1;
unsigned pv_notify:1;
unsigned use_aio:1;
unsigned activate_component:1; /* command activates component LV */
unsigned process_component_lvs:1; /* command processes also component LVs */
unsigned mirror_warn_printed:1; /* command already printed warning about non-monitored mirrors */
unsigned pvscan_cache_single:1;
unsigned can_use_one_scan:1;
/*
* Filtering.
*/

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2018 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@ -23,6 +23,7 @@
#include "toolcontext.h"
#include "lvm-file.h"
#include "memlock.h"
#include "label.h"
#include <sys/stat.h>
#include <sys/mman.h>
@ -279,7 +280,7 @@ struct dm_config_tree *config_file_open_and_read(const char *config_file,
}
log_very_verbose("Loading config file: %s", config_file);
if (!config_file_read(cmd->mem, cft)) {
if (!config_file_read(cft)) {
log_error("Failed to load config file %s", config_file);
goto bad;
}
@ -489,102 +490,32 @@ int override_config_tree_from_profile(struct cmd_context *cmd,
return 0;
}
struct process_config_file_params {
struct dm_config_tree *cft;
struct device *dev;
off_t offset;
size_t size;
off_t offset2;
size_t size2;
checksum_fn_t checksum_fn;
uint32_t checksum;
int checksum_only;
int no_dup_node_check;
lvm_callback_fn_t config_file_read_fd_callback;
void *config_file_read_fd_context;
int ret;
};
static void _process_config_file_buffer(int failed, unsigned ioflags, void *context, const void *data)
{
struct process_config_file_params *pcfp = context;
const char *fb = data, *fe;
if (failed) {
pcfp->ret = 0;
goto_out;
}
if (pcfp->checksum_fn && pcfp->checksum !=
(pcfp->checksum_fn(pcfp->checksum_fn(INITIAL_CRC, (const uint8_t *)fb, pcfp->size),
(const uint8_t *)(fb + pcfp->size), pcfp->size2))) {
log_error("%s: Checksum error at offset %" PRIu64, dev_name(pcfp->dev), (uint64_t) pcfp->offset);
pcfp->ret = 0;
goto out;
}
if (!pcfp->checksum_only) {
fe = fb + pcfp->size + pcfp->size2;
if (pcfp->no_dup_node_check) {
if (!dm_config_parse_without_dup_node_check(pcfp->cft, fb, fe))
pcfp->ret = 0;
} else if (!dm_config_parse(pcfp->cft, fb, fe))
pcfp->ret = 0;
}
out:
if (pcfp->config_file_read_fd_callback)
pcfp->config_file_read_fd_callback(!pcfp->ret, ioflags, pcfp->config_file_read_fd_context, NULL);
}
/*
* When checksum_only is set, the checksum of buffer is only matched
* and function avoids parsing of mda into config tree which
* remains unmodified and should not be used.
*/
int config_file_read_fd(struct dm_pool *mem, struct dm_config_tree *cft, struct device *dev, dev_io_reason_t reason,
int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_reason_t reason,
off_t offset, size_t size, off_t offset2, size_t size2,
checksum_fn_t checksum_fn, uint32_t checksum,
int checksum_only, int no_dup_node_check, unsigned ioflags,
lvm_callback_fn_t config_file_read_fd_callback, void *config_file_read_fd_context)
int checksum_only, int no_dup_node_check)
{
char *fb;
char *fb, *fe;
int r = 0;
off_t mmap_offset = 0;
int use_mmap = 1;
const char *buf = NULL;
unsigned circular = size2 ? 1 : 0; /* Wrapped around end of disk metadata buffer? */
off_t mmap_offset = 0;
char *buf = NULL;
struct config_source *cs = dm_config_get_custom(cft);
struct process_config_file_params *pcfp;
if (!_is_file_based_config_source(cs->type)) {
log_error(INTERNAL_ERROR "config_file_read_fd: expected file, special file "
"or profile config source, found %s config source.",
_config_source_names[cs->type]);
goto bad;
return 0;
}
if (!(pcfp = dm_pool_zalloc(mem, sizeof(*pcfp)))) {
log_debug("config_file_read_fd: process_config_file_params struct allocation failed");
goto bad;
}
pcfp->cft = cft;
pcfp->dev = dev;
pcfp->offset = offset;
pcfp->size = size;
pcfp->offset2 = offset2;
pcfp->size2 = size2;
pcfp->checksum_fn = checksum_fn;
pcfp->checksum = checksum;
pcfp->checksum_only = checksum_only;
pcfp->no_dup_node_check = no_dup_node_check;
pcfp->config_file_read_fd_callback = config_file_read_fd_callback;
pcfp->config_file_read_fd_context = config_file_read_fd_context;
pcfp->ret = 1;
/* Only use mmap with regular files */
if (!(dev->flags & DEV_REGULAR) || circular)
if (!(dev->flags & DEV_REGULAR) || size2)
use_mmap = 0;
if (use_mmap) {
@ -594,40 +525,67 @@ int config_file_read_fd(struct dm_pool *mem, struct dm_config_tree *cft, struct
MAP_PRIVATE, dev_fd(dev), offset - mmap_offset);
if (fb == (caddr_t) (-1)) {
log_sys_error("mmap", dev_name(dev));
goto bad;
goto out;
}
_process_config_file_buffer(0, ioflags, pcfp, fb + mmap_offset);
r = pcfp->ret;
fb = fb + mmap_offset;
} else {
if (!(buf = dm_malloc(size + size2))) {
log_error("Failed to allocate circular buffer.");
return 0;
}
if (!dev_read_bytes(dev, offset, size, buf))
goto out;
if (size2) {
if (!dev_read_bytes(dev, offset2, size2, buf + size))
goto out;
}
fb = buf;
}
/*
* The checksum passed in is the checksum from the mda_header
* preceding this metadata. They should always match.
* FIXME: handle case where mda_header checksum is bad,
* but the checksum calculated here is correct.
*/
if (checksum_fn && checksum !=
(checksum_fn(checksum_fn(INITIAL_CRC, (const uint8_t *)fb, size),
(const uint8_t *)(fb + size), size2))) {
log_error("%s: Checksum error at offset %" PRIu64, dev_name(dev), (uint64_t) offset);
goto out;
}
if (!checksum_only) {
fe = fb + size + size2;
if (no_dup_node_check) {
if (!dm_config_parse_without_dup_node_check(cft, fb, fe))
goto_out;
} else {
if (!dm_config_parse(cft, fb, fe))
goto_out;
}
}
r = 1;
out:
if (!use_mmap)
dm_free(buf);
else {
/* unmap the file */
if (munmap(fb, size + mmap_offset)) {
if (munmap(fb - mmap_offset, size + mmap_offset)) {
log_sys_error("munmap", dev_name(dev));
r = 0;
}
} else {
if (circular) {
if (!(buf = dev_read_circular(dev, (uint64_t) offset, size, (uint64_t) offset2, size2, reason)))
goto_out;
_process_config_file_buffer(0, ioflags, pcfp, buf);
dm_free((void *)buf);
} else {
dev_read_callback(dev, (uint64_t) offset, size, reason, ioflags, _process_config_file_buffer, pcfp);
if (config_file_read_fd_callback)
return 1;
}
r = pcfp->ret;
}
out:
return r;
bad:
if (config_file_read_fd_callback)
config_file_read_fd_callback(1, ioflags, config_file_read_fd_context, NULL);
return 0;
}
int config_file_read(struct dm_pool *mem, struct dm_config_tree *cft)
int config_file_read(struct dm_config_tree *cft)
{
const char *filename = NULL;
struct config_source *cs = dm_config_get_custom(cft);
@ -655,8 +613,8 @@ int config_file_read(struct dm_pool *mem, struct dm_config_tree *cft)
}
}
r = config_file_read_fd(mem, cft, cf->dev, DEV_IO_MDA_CONTENT, 0, (size_t) info.st_size, 0, 0,
(checksum_fn_t) NULL, 0, 0, 0, 0, NULL, NULL);
r = config_file_read_fd(cft, cf->dev, DEV_IO_MDA_CONTENT, 0, (size_t) info.st_size, 0, 0,
(checksum_fn_t) NULL, 0, 0, 0);
if (!cf->keep_open) {
if (!dev_close(cf->dev))

View File

@ -239,13 +239,11 @@ config_source_t config_get_source_type(struct dm_config_tree *cft);
typedef uint32_t (*checksum_fn_t) (uint32_t initial, const uint8_t *buf, uint32_t size);
struct dm_config_tree *config_open(config_source_t source, const char *filename, int keep_open);
int config_file_read_fd(struct dm_pool *mem, struct dm_config_tree *cft, struct device *dev, dev_io_reason_t reason,
int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_reason_t reason,
off_t offset, size_t size, off_t offset2, size_t size2,
checksum_fn_t checksum_fn, uint32_t checksum,
int skip_parse, int no_dup_node_check, unsigned ioflags,
lvm_callback_fn_t config_file_read_fd_callback, void *config_file_read_fd_context);
int config_file_read(struct dm_pool *mem, struct dm_config_tree *cft);
int skip_parse, int no_dup_node_check);
int config_file_read(struct dm_config_tree *cft);
struct dm_config_tree *config_file_open_and_read(const char *config_file, config_source_t source,
struct cmd_context *cmd);
int config_write(struct dm_config_tree *cft, struct config_def_tree_spec *tree_spec,

View File

@ -226,16 +226,6 @@ cfg(devices_dir_CFG, "dir", devices_CFG_SECTION, CFG_ADVANCED, CFG_TYPE_STRING,
cfg_array(devices_scan_CFG, "scan", devices_CFG_SECTION, CFG_ADVANCED, CFG_TYPE_STRING, "#S/dev", vsn(1, 0, 0), NULL, 0, NULL,
"Directories containing device nodes to use with LVM.\n")
cfg(devices_use_aio_CFG, "use_aio", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_USE_AIO, vsn(2, 2, 178), NULL, 0, NULL,
"Use linux asynchronous I/O for parallel device access where possible.\n")
cfg(devices_aio_max_CFG, "aio_max", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_AIO_MAX, vsn(2, 2, 178), NULL, 0, NULL,
"Maximum number of asynchronous I/Os to issue concurrently.\n")
cfg(devices_aio_memory_CFG, "aio_memory", devices_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_AIO_MEMORY, vsn(2, 2, 178), NULL, 0, NULL,
"Approximate maximum total amount of memory (in MB) used\n"
"for asynchronous I/O buffers.\n")
cfg_array(devices_loopfiles_CFG, "loopfiles", devices_CFG_SECTION, CFG_DEFAULT_UNDEFINED | CFG_UNSUPPORTED, CFG_TYPE_STRING, NULL, vsn(1, 2, 0), NULL, 0, NULL, NULL)
cfg(devices_obtain_device_list_from_udev_CFG, "obtain_device_list_from_udev", devices_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_OBTAIN_DEVICE_LIST_FROM_UDEV, vsn(2, 2, 85), NULL, 0, NULL,
@ -878,11 +868,8 @@ cfg(global_abort_on_internal_errors_CFG, "abort_on_internal_errors", global_CFG_
"Treat any internal errors as fatal errors, aborting the process that\n"
"encountered the internal error. Please only enable for debugging.\n")
cfg(global_detect_internal_vg_cache_corruption_CFG, "detect_internal_vg_cache_corruption", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_DETECT_INTERNAL_VG_CACHE_CORRUPTION, vsn(2, 2, 96), NULL, 0, NULL,
"Internal verification of VG structures.\n"
"Check if CRC matches when a parsed VG is used multiple times. This\n"
"is useful to catch unexpected changes to cached VG structures.\n"
"Please only enable for debugging.\n")
cfg(global_detect_internal_vg_cache_corruption_CFG, "detect_internal_vg_cache_corruption", global_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(2, 2, 96), NULL, vsn(2, 2, 174), NULL,
"No longer used.\n")
cfg(global_metadata_read_only_CFG, "metadata_read_only", global_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_METADATA_READ_ONLY, vsn(2, 2, 75), NULL, 0, NULL,
"No operations that change on-disk metadata are permitted.\n"

View File

@ -32,9 +32,6 @@
#define DEFAULT_SYSTEM_ID_SOURCE "none"
#define DEFAULT_OBTAIN_DEVICE_LIST_FROM_UDEV 1
#define DEFAULT_EXTERNAL_DEVICE_INFO_SOURCE "none"
#define DEFAULT_USE_AIO 1
#define DEFAULT_AIO_MAX 128
#define DEFAULT_AIO_MEMORY 10
#define DEFAULT_SYSFS_SCAN 1
#define DEFAULT_MD_COMPONENT_DETECTION 1
#define DEFAULT_FW_RAID_COMPONENT_DETECTION 0
@ -182,7 +179,6 @@
#define DEFAULT_LOGLEVEL 0
#define DEFAULT_INDENT 1
#define DEFAULT_ABORT_ON_INTERNAL_ERRORS 0
#define DEFAULT_DETECT_INTERNAL_VG_CACHE_CORRUPTION 0
#define DEFAULT_UNITS "r"
#define DEFAULT_SUFFIX 1
#define DEFAULT_HOSTTAGS 0

1182
lib/device/bcache.c Normal file

File diff suppressed because it is too large Load Diff

164
lib/device/bcache.h Normal file
View File

@ -0,0 +1,164 @@
/*
* Copyright (C) 2018 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 BCACHE_H
#define BCACHE_H
#include <linux/fs.h>
#include <stdint.h>
#include <stdbool.h>
#include "libdevmapper.h"
/*----------------------------------------------------------------*/
// FIXME: move somewhere more sensible
#define container_of(v, t, head) \
((t *)((const char *)(v) - (const char *)&((t *) 0)->head))
/*----------------------------------------------------------------*/
/*
* bcache-specific error numbers
* These supplement standard -EXXX error numbers and
* should not overlap.
*/
#define BCACHE_NO_BLOCK 201
enum dir {
DIR_READ,
DIR_WRITE
};
typedef uint64_t block_address;
typedef uint64_t sector_t;
typedef void io_complete_fn(void *context, int io_error);
struct io_engine {
void (*destroy)(struct io_engine *e);
bool (*issue)(struct io_engine *e, enum dir d, int fd,
sector_t sb, sector_t se, void *data, void *context);
bool (*wait)(struct io_engine *e, io_complete_fn fn);
unsigned (*max_io)(struct io_engine *e);
};
struct io_engine *create_async_io_engine(void);
/*----------------------------------------------------------------*/
struct bcache;
struct block {
/* clients may only access these three fields */
int fd;
uint64_t index;
void *data;
struct bcache *cache;
struct dm_list list;
struct dm_list hash;
unsigned flags;
unsigned ref_count;
int error;
enum dir io_dir;
};
/*
* Ownership of engine passes. Engine will be destroyed even if this fails.
*/
struct bcache *bcache_create(sector_t block_size, unsigned nr_cache_blocks,
struct io_engine *engine);
void bcache_destroy(struct bcache *cache);
enum bcache_get_flags {
/*
* The block will be zeroed before get_block returns it. This
* potentially avoids a read if the block is not already in the cache.
* GF_DIRTY is implicit.
*/
GF_ZERO = (1 << 0),
/*
* Indicates the caller is intending to change the data in the block, a
* writeback will occur after the block is released.
*/
GF_DIRTY = (1 << 1)
};
unsigned bcache_nr_cache_blocks(struct bcache *cache);
unsigned bcache_max_prefetches(struct bcache *cache);
/*
* Use the prefetch method to take advantage of asynchronous IO. For example,
* if you wanted to read a block from many devices concurrently you'd do
* something like this:
*
* dm_list_iterate_items (dev, &devices)
* bcache_prefetch(cache, dev->fd, block);
*
* dm_list_iterate_items (dev, &devices) {
* if (!bcache_get(cache, dev->fd, block, &b))
* fail();
*
* process_block(b);
* }
*
* It's slightly sub optimal, since you may not run the gets in the order that
* they complete. But we're talking a very small difference, and it's worth it
* to keep callbacks out of this interface.
*/
void bcache_prefetch(struct bcache *cache, int fd, block_address index);
/*
* Returns true on success.
*/
bool bcache_get(struct bcache *cache, int fd, block_address index,
unsigned flags, struct block **result, int *error);
void bcache_put(struct block *b);
/*
* flush() does not attempt to writeback locked blocks. flush will fail
* (return false), if any unlocked dirty data cannot be written back.
*/
bool bcache_flush(struct bcache *cache);
/*
* Removes a block from the cache. If the block is dirty it will be written
* back first. If the block is currently held a warning will be issued, and it
* will not be removed.
*/
void bcache_invalidate(struct bcache *cache, int fd, block_address index);
/*
* Invalidates all blocks on the given descriptor. Call this before closing
* the descriptor to make sure everything is written back.
*/
void bcache_invalidate_fd(struct bcache *cache, int fd);
/*
* Prefetches the blocks neccessary to satisfy a byte range.
*/
void bcache_prefetch_bytes(struct bcache *cache, int fd, off_t start, size_t len);
/*
* Reads and writes the bytes. Returns false if errors occur.
*/
bool bcache_read_bytes(struct bcache *cache, int fd, off_t start, size_t len, void *data);
bool bcache_write_bytes(struct bcache *cache, int fd, off_t start, size_t len, void *data);
bool bcache_write_zeros(struct bcache *cache, int fd, off_t start, size_t len);
/*----------------------------------------------------------------*/
#endif

View File

@ -1077,12 +1077,11 @@ static int _insert(const char *path, const struct stat *info,
return 1;
}
static void _full_scan(int dev_scan)
void dev_cache_scan(void)
{
struct dir_list *dl;
if (_cache.has_scanned && !dev_scan)
return;
_cache.has_scanned = 1;
_insert_dirs(&_cache.dirs);
@ -1090,9 +1089,6 @@ static void _full_scan(int dev_scan)
dm_list_iterate_items(dl, &_cache.files)
_insert_file(dl->dir);
_cache.has_scanned = 1;
init_full_scan_done(1);
}
int dev_cache_has_scanned(void)
@ -1100,14 +1096,6 @@ int dev_cache_has_scanned(void)
return _cache.has_scanned;
}
void dev_cache_scan(int do_scan)
{
if (!do_scan)
_cache.has_scanned = 1;
else
_full_scan(1);
}
static int _init_preferred_names(struct cmd_context *cmd)
{
const struct dm_config_node *cn;
@ -1171,7 +1159,6 @@ out:
int dev_cache_init(struct cmd_context *cmd)
{
_cache.names = NULL;
_cache.has_scanned = 0;
if (!(_cache.mem = dm_pool_create("dev_cache", 10 * 1024)))
return_0;
@ -1245,24 +1232,12 @@ int dev_cache_check_for_open_devices(void)
int dev_cache_exit(void)
{
struct btree_iter *b;
int num_open = 0;
dev_async_exit();
if (_cache.names)
if ((num_open = _check_for_open_devices(1)) > 0)
log_error(INTERNAL_ERROR "%d device(s) were left open and have been closed.", num_open);
if (_cache.devices) {
/* FIXME Replace with structured devbuf cache */
b = btree_first(_cache.devices);
while (b) {
devbufs_release(btree_get_data(b));
b = btree_next(b);
}
}
if (_cache.mem)
dm_pool_destroy(_cache.mem);
@ -1425,7 +1400,7 @@ struct device *dev_cache_get(const char *name, struct dev_filter *f)
_insert(name, info_available ? &buf : NULL, 0, obtain_device_list_from_udev());
d = (struct device *) dm_hash_lookup(_cache.names, name);
if (!d) {
_full_scan(0);
dev_cache_scan();
d = (struct device *) dm_hash_lookup(_cache.names, name);
}
}
@ -1481,7 +1456,7 @@ struct device *dev_cache_get_by_devt(dev_t dev, struct dev_filter *f)
}
}
_full_scan(0);
dev_cache_scan();
d = _dev_cache_seek_devt(dev);
}
@ -1489,17 +1464,7 @@ struct device *dev_cache_get_by_devt(dev_t dev, struct dev_filter *f)
f->passes_filter(f, d))) ? d : NULL;
}
void dev_cache_full_scan(struct dev_filter *f)
{
if (f && f->wipe) {
f->wipe(f); /* might call _full_scan(1) */
if (!full_scan_done())
_full_scan(1);
} else
_full_scan(1);
}
struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan)
struct dev_iter *dev_iter_create(struct dev_filter *f, int unused)
{
struct dev_iter *di = dm_malloc(sizeof(*di));
@ -1508,13 +1473,6 @@ struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan)
return NULL;
}
if (dev_scan && !trust_cache()) {
/* Flag gets reset between each command */
if (!full_scan_done())
dev_cache_full_scan(f);
} else
_full_scan(0);
di->current = btree_first(_cache.devices);
di->filter = f;
if (di->filter)

View File

@ -23,10 +23,10 @@
* predicate for devices.
*/
struct dev_filter {
int (*passes_filter) (struct dev_filter *f, struct device *dev);
void (*destroy) (struct dev_filter *f);
void (*wipe) (struct dev_filter *f);
int (*dump) (struct dev_filter *f, struct dm_pool *mem, int merge_existing);
int (*passes_filter) (struct dev_filter * f, struct device * dev);
void (*destroy) (struct dev_filter * f);
void (*wipe) (struct dev_filter * f);
int (*dump) (struct dev_filter * f, int merge_existing);
void *private;
unsigned use_count;
};
@ -46,10 +46,8 @@ int dev_cache_exit(void);
*/
int dev_cache_check_for_open_devices(void);
/* Trigger(1) or avoid(0) a scan */
void dev_cache_scan(int do_scan);
void dev_cache_scan(void);
int dev_cache_has_scanned(void);
void dev_cache_full_scan(struct dev_filter *f);
int dev_cache_add_dir(const char *path);
int dev_cache_add_loopfile(const char *path);
@ -66,7 +64,7 @@ void dev_set_preferred_name(struct dm_str_list *sl, struct device *dev);
* Object for iterating through the cache.
*/
struct dev_iter;
struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan);
struct dev_iter *dev_iter_create(struct dev_filter *f, int unused);
void dev_iter_destroy(struct dev_iter *iter);
struct device *dev_iter_get(struct dev_iter *iter);

View File

@ -53,12 +53,6 @@
# endif
#endif
/*
* Always read at least 8k from disk.
* This seems to be a good compromise for the existing LVM2 metadata layout.
*/
#define MIN_READ_SIZE (8 * 1024)
static DM_LIST_INIT(_open_devices);
static unsigned _dev_size_seqno = 1;
@ -80,319 +74,38 @@ static const char *_reason_text(dev_io_reason_t reason)
return _reasons[(unsigned) reason];
}
/*
* Release the memory holding the last data we read
*/
static void _release_devbuf(struct device_buffer *devbuf)
{
dm_free(devbuf->malloc_address);
devbuf->malloc_address = NULL;
}
void devbufs_release(struct device *dev)
{
if ((dev->flags & DEV_REGULAR))
return;
_release_devbuf(&dev->last_devbuf);
_release_devbuf(&dev->last_extra_devbuf);
}
#ifdef AIO_SUPPORT
# include <libaio.h>
static io_context_t _aio_ctx = 0;
static struct io_event *_aio_events = NULL;
static int _aio_max = 0;
static int64_t _aio_memory_max = 0;
static int _aio_must_queue = 0; /* Have we reached AIO capacity? */
static DM_LIST_INIT(_aio_queue);
#define DEFAULT_AIO_COLLECTION_EVENTS 32
int dev_async_setup(struct cmd_context *cmd)
{
int r;
_aio_max = find_config_tree_int(cmd, devices_aio_max_CFG, NULL);
_aio_memory_max = find_config_tree_int(cmd, devices_aio_memory_CFG, NULL) * INT64_C(1024 * 1024);
/* Threshold is zero? */
if (!_aio_max || !_aio_memory_max) {
if (_aio_ctx)
dev_async_exit();
return 1;
}
/* Already set up? */
if (_aio_ctx)
return 1;
log_debug_io("Setting up aio context for up to %" PRId64 " MB across %d events.", _aio_memory_max, _aio_max);
if (!_aio_events && !(_aio_events = dm_zalloc(sizeof(*_aio_events) * DEFAULT_AIO_COLLECTION_EVENTS))) {
log_error("Failed to allocate io_event array for asynchronous I/O.");
return 0;
}
if ((r = io_setup(_aio_max, &_aio_ctx)) < 0) {
/*
* Possible errors:
* ENOSYS - aio not available in current kernel
* EAGAIN - _aio_max is too big
* EFAULT - invalid pointer
* EINVAL - _aio_ctx != 0 or kernel aio limits exceeded
* ENOMEM
*/
log_warn("WARNING: Asynchronous I/O setup for %d events failed: %s", _aio_max, strerror(-r));
log_warn("WARNING: Using only synchronous I/O.");
dm_free(_aio_events);
_aio_events = NULL;
_aio_ctx = 0;
return 0;
}
return 1;
}
/* Reset aio context after fork */
int dev_async_reset(struct cmd_context *cmd)
{
log_debug_io("Resetting asynchronous I/O context.");
_aio_ctx = 0;
dm_free(_aio_events);
_aio_events = NULL;
return dev_async_setup(cmd);
}
/*
* Track the amount of in-flight async I/O.
* If it exceeds the defined threshold set _aio_must_queue.
*/
static void _update_aio_counters(int nr, ssize_t bytes)
{
static int64_t aio_bytes = 0;
static int aio_count = 0;
aio_bytes += bytes;
aio_count += nr;
if (aio_count >= _aio_max || aio_bytes > _aio_memory_max)
_aio_must_queue = 1;
else
_aio_must_queue = 0;
}
static int _io(struct device_buffer *devbuf, unsigned ioflags);
int dev_async_getevents(void)
{
struct device_buffer *devbuf, *tmp;
lvm_callback_fn_t dev_read_callback_fn;
void *dev_read_callback_context;
int r, event_nr;
if (!_aio_ctx)
return 1;
do {
/* FIXME Add timeout - currently NULL - waits for ever for at least 1 item */
r = io_getevents(_aio_ctx, 1, DEFAULT_AIO_COLLECTION_EVENTS, _aio_events, NULL);
if (r > 0)
break;
if (!r)
return 1; /* Timeout elapsed */
if (r == -EINTR)
continue;
if (r == -EAGAIN) {
usleep(100);
return 1; /* Give the caller the opportunity to do other work before repeating */
}
/*
* ENOSYS - not supported by kernel
* EFAULT - memory invalid
* EINVAL - _aio_ctx invalid or min_nr/nr/timeout out of range
*/
log_error("Asynchronous event collection failed: %s", strerror(-r));
return 0;
} while (1);
for (event_nr = 0; event_nr < r; event_nr++) {
devbuf = _aio_events[event_nr].obj->data;
dm_free(_aio_events[event_nr].obj);
_update_aio_counters(-1, -devbuf->where.size);
dev_read_callback_fn = devbuf->dev_read_callback_fn;
dev_read_callback_context = devbuf->dev_read_callback_context;
/* Clear the callbacks as a precaution */
devbuf->dev_read_callback_context = NULL;
devbuf->dev_read_callback_fn = NULL;
if (_aio_events[event_nr].res == devbuf->where.size) {
if (dev_read_callback_fn)
dev_read_callback_fn(0, AIO_SUPPORTED_CODE_PATH, dev_read_callback_context, (char *)devbuf->buf + devbuf->data_offset);
} else {
/* FIXME If partial read is possible, resubmit remainder */
log_error("%s: asynchronous read only I/O failed (" FMTd64 ") of " FMTu64 " bytes at " FMTu64 " (for %s): %s",
dev_name(devbuf->where.dev), _aio_events[event_nr].res,
(uint64_t) devbuf->where.size, (uint64_t) devbuf->where.start,
_reason_text(devbuf->reason),
(((int64_t)_aio_events[event_nr].res) < 0) ? strerror(-(int64_t)_aio_events[event_nr].res) : 0);
_release_devbuf(devbuf);
if (dev_read_callback_fn)
dev_read_callback_fn(1, AIO_SUPPORTED_CODE_PATH, dev_read_callback_context, NULL);
else
r = 0;
}
}
/* Submit further queued events if we can */
dm_list_iterate_items_gen_safe(devbuf, tmp, &_aio_queue, aio_queued) {
if (_aio_must_queue)
break;
dm_list_del(&devbuf->aio_queued);
_io(devbuf, 1);
}
return 1;
}
static int _io_async(struct device_buffer *devbuf)
{
struct device_area *where = &devbuf->where;
struct iocb *iocb;
int r;
_update_aio_counters(1, devbuf->where.size);
if (!(iocb = dm_malloc(sizeof(*iocb)))) {
log_error("Failed to allocate I/O control block array for asynchronous I/O.");
return 0;
}
io_prep_pread(iocb, dev_fd(where->dev), devbuf->buf, where->size, where->start);
iocb->data = devbuf;
do {
r = io_submit(_aio_ctx, 1L, &iocb);
if (r ==1)
break; /* Success */
if (r == -EAGAIN) {
/* Try to release some resources then retry */
usleep(100);
if (dev_async_getevents())
return_0;
/* FIXME Add counter/timeout so we can't get stuck here for ever */
continue;
}
/*
* Possible errors:
* EFAULT - invalid data
* ENOSYS - no aio support in kernel
* EBADF - bad file descriptor in iocb
* EINVAL - invalid _aio_ctx / iocb not initialised / invalid operation for this fd
*/
log_error("Asynchronous event submission failed: %s", strerror(-r));
return 0;
} while (1);
return 1;
}
void dev_async_exit(void)
{
struct device_buffer *devbuf, *tmp;
lvm_callback_fn_t dev_read_callback_fn;
void *dev_read_callback_context;
int r;
if (!_aio_ctx)
return;
/* Discard any queued requests */
dm_list_iterate_items_gen_safe(devbuf, tmp, &_aio_queue, aio_queued) {
dm_list_del(&devbuf->aio_queued);
_update_aio_counters(-1, -devbuf->where.size);
dev_read_callback_fn = devbuf->dev_read_callback_fn;
dev_read_callback_context = devbuf->dev_read_callback_context;
_release_devbuf(devbuf);
if (dev_read_callback_fn)
dev_read_callback_fn(1, AIO_SUPPORTED_CODE_PATH, dev_read_callback_context, NULL);
}
log_debug_io("Destroying aio context.");
if ((r = io_destroy(_aio_ctx)) < 0)
/* Returns -ENOSYS if aio not in kernel or -EINVAL if _aio_ctx invalid */
log_error("Failed to destroy asynchronous I/O context: %s", strerror(-r));
dm_free(_aio_events);
_aio_events = NULL;
_aio_ctx = 0;
}
static void _queue_aio(struct device_buffer *devbuf)
{
dm_list_add(&_aio_queue, &devbuf->aio_queued);
log_debug_io("Queueing aio.");
}
#else
static int _aio_ctx = 0;
static int _aio_must_queue = 0;
int dev_async_setup(struct cmd_context *cmd)
{
return 1;
}
int dev_async_reset(struct cmd_context *cmd)
{
return 1;
}
int dev_async_getevents(void)
{
return 1;
}
void dev_async_exit(void)
{
}
static int _io_async(struct device_buffer *devbuf)
{
return 0;
}
static void _queue_aio(struct device_buffer *devbuf)
{
}
#endif /* AIO_SUPPORT */
/*-----------------------------------------------------------------
* The standard io loop that keeps submitting an io until it's
* all gone.
*---------------------------------------------------------------*/
static int _io_sync(struct device_buffer *devbuf)
static int _io(struct device_area *where, char *buffer, int should_write, dev_io_reason_t reason)
{
struct device_area *where = &devbuf->where;
int fd = dev_fd(where->dev);
char *buffer = devbuf->buf;
ssize_t n = 0;
size_t total = 0;
if (fd < 0) {
log_error("Attempt to read an unopened device (%s).",
dev_name(where->dev));
return 0;
}
log_debug_io("%s %s:%8" PRIu64 " bytes (sync) at %" PRIu64 "%s (for %s)",
should_write ? "Write" : "Read ", dev_name(where->dev),
where->size, (uint64_t) where->start,
(should_write && test_mode()) ? " (test mode - suppressed)" : "", _reason_text(reason));
/*
* Skip all writes in test mode.
*/
if (should_write && test_mode())
return 1;
if (where->size > SSIZE_MAX) {
log_error("Read size too large: %" PRIu64, where->size);
return 0;
}
if (lseek(fd, (off_t) where->start, SEEK_SET) == (off_t) -1) {
log_error("%s: lseek %" PRIu64 " failed: %s",
dev_name(where->dev), (uint64_t) where->start,
@ -402,19 +115,18 @@ static int _io_sync(struct device_buffer *devbuf)
while (total < (size_t) where->size) {
do
n = devbuf->write ?
n = should_write ?
write(fd, buffer, (size_t) where->size - total) :
read(fd, buffer, (size_t) where->size - total);
while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN)));
if (n < 0)
log_error("%s: synchronous %s failed after %" PRIu64 " of %" PRIu64
" at %" PRIu64 " (for %s): %s", dev_name(where->dev),
devbuf->write ? "write" : "read",
(uint64_t) total,
(uint64_t) where->size, (uint64_t) where->start,
_reason_text(devbuf->reason),
strerror(errno));
log_error_once("%s: %s failed after %" PRIu64 " of %" PRIu64
" at %" PRIu64 ": %s", dev_name(where->dev),
should_write ? "write" : "read",
(uint64_t) total,
(uint64_t) where->size,
(uint64_t) where->start, strerror(errno));
if (n <= 0)
break;
@ -426,42 +138,6 @@ static int _io_sync(struct device_buffer *devbuf)
return (total == (size_t) where->size);
}
static int _io(struct device_buffer *devbuf, unsigned ioflags)
{
struct device_area *where = &devbuf->where;
int fd = dev_fd(where->dev);
int async = (!devbuf->write && _aio_ctx && aio_supported_code_path(ioflags) && devbuf->dev_read_callback_fn) ? 1 : 0;
if (fd < 0) {
log_error("Attempt to read an unopened device (%s).",
dev_name(where->dev));
return 0;
}
if (!devbuf->buf && !(devbuf->malloc_address = devbuf->buf = dm_malloc_aligned((size_t) devbuf->where.size, 0))) {
log_error("I/O buffer malloc failed");
return 0;
}
log_debug_io("%s %s(fd %d):%8" PRIu64 " bytes (%ssync) at %" PRIu64 "%s (for %s)",
devbuf->write ? "Write" : "Read ", dev_name(where->dev), fd,
where->size, async ? "a" : "", (uint64_t) where->start,
(devbuf->write && test_mode()) ? " (test mode - suppressed)" : "", _reason_text(devbuf->reason));
/*
* Skip all writes in test mode.
*/
if (devbuf->write && test_mode())
return 1;
if (where->size > SSIZE_MAX) {
log_error("Read size too large: %" PRIu64, where->size);
return 0;
}
return async ? _io_async(devbuf) : _io_sync(devbuf);
}
/*-----------------------------------------------------------------
* LVM2 uses O_DIRECT when performing metadata io, which requires
* block size aligned accesses. If any io is not aligned we have
@ -551,16 +227,15 @@ static void _widen_region(unsigned int block_size, struct device_area *region,
result->size += block_size - delta;
}
static int _aligned_io(struct device_area *where, char *write_buffer,
int should_write, dev_io_reason_t reason,
unsigned ioflags, lvm_callback_fn_t dev_read_callback_fn, void *dev_read_callback_context)
static int _aligned_io(struct device_area *where, char *buffer,
int should_write, dev_io_reason_t reason)
{
char *bounce, *bounce_buf;
unsigned int physical_block_size = 0;
unsigned int block_size = 0;
unsigned buffer_was_widened = 0;
uintptr_t mask;
struct device_area widened;
struct device_buffer *devbuf;
int r = 0;
if (!(where->dev->flags & DEV_REGULAR) &&
@ -569,11 +244,6 @@ static int _aligned_io(struct device_area *where, char *write_buffer,
if (!block_size)
block_size = lvm_getpagesize();
/* Apply minimum read size */
if (!should_write && block_size < MIN_READ_SIZE)
block_size = MIN_READ_SIZE;
mask = block_size - 1;
_widen_region(block_size, where, &widened);
@ -583,75 +253,50 @@ static int _aligned_io(struct device_area *where, char *write_buffer,
buffer_was_widened = 1;
log_debug_io("Widening request for %" PRIu64 " bytes at %" PRIu64 " to %" PRIu64 " bytes at %" PRIu64 " on %s (for %s)",
where->size, (uint64_t) where->start, widened.size, (uint64_t) widened.start, dev_name(where->dev), _reason_text(reason));
}
devbuf = DEV_DEVBUF(where->dev, reason);
_release_devbuf(devbuf);
devbuf->where.dev = where->dev;
devbuf->where.start = widened.start;
devbuf->where.size = widened.size;
devbuf->write = should_write;
devbuf->reason = reason;
devbuf->dev_read_callback_fn = dev_read_callback_fn;
devbuf->dev_read_callback_context = dev_read_callback_context;
/* Store location of requested data relative to start of buf */
devbuf->data_offset = where->start - devbuf->where.start;
if (should_write && !buffer_was_widened && !((uintptr_t) write_buffer & mask))
} else if (!((uintptr_t) buffer & mask))
/* Perform the I/O directly. */
devbuf->buf = write_buffer;
else if (!should_write)
/* Postpone buffer allocation until we're about to issue the I/O */
devbuf->buf = NULL;
else {
/* Allocate a bounce buffer with an extra block */
if (!(devbuf->malloc_address = devbuf->buf = dm_malloc((size_t) devbuf->where.size + block_size))) {
log_error("Bounce buffer malloc failed");
return 0;
}
return _io(where, buffer, should_write, reason);
/*
* Realign start of bounce buffer (using the extra sector)
*/
if (((uintptr_t) devbuf->buf) & mask)
devbuf->buf = (char *) ((((uintptr_t) devbuf->buf) + mask) & ~mask);
/* Allocate a bounce buffer with an extra block */
if (!(bounce_buf = bounce = dm_malloc((size_t) widened.size + block_size))) {
log_error("Bounce buffer malloc failed");
return 0;
}
/* If we've reached our concurrent AIO limit, add this request to the queue */
if (!devbuf->write && _aio_ctx && aio_supported_code_path(ioflags) && dev_read_callback_fn && _aio_must_queue) {
_queue_aio(devbuf);
return 1;
}
devbuf->write = 0;
/*
* Realign start of bounce buffer (using the extra sector)
*/
if (((uintptr_t) bounce) & mask)
bounce = (char *) ((((uintptr_t) bounce) + mask) & ~mask);
/* Do we need to read into the bounce buffer? */
if ((!should_write || buffer_was_widened) && !_io(devbuf, ioflags)) {
if ((!should_write || buffer_was_widened) &&
!_io(&widened, bounce, 0, reason)) {
if (!should_write)
goto_bad;
goto_out;
/* FIXME Handle errors properly! */
/* FIXME pre-extend the file */
memset(devbuf->buf, '\n', devbuf->where.size);
memset(bounce, '\n', widened.size);
}
if (!should_write)
return 1;
if (should_write) {
memcpy(bounce + (where->start - widened.start), buffer,
(size_t) where->size);
/* writes */
if (devbuf->malloc_address) {
memcpy((char *) devbuf->buf + devbuf->data_offset, write_buffer, (size_t) where->size);
log_debug_io("Overwriting %" PRIu64 " bytes at %" PRIu64 " (for %s)", where->size,
(uint64_t) where->start, _reason_text(devbuf->reason));
/* ... then we write */
if (!(r = _io(&widened, bounce, 1, reason)))
stack;
goto out;
}
/* ... then we write */
devbuf->write = 1;
if (!(r = _io(devbuf, 0)))
stack;
bad:
_release_devbuf(devbuf);
memcpy(buffer, bounce + (where->start - widened.start),
(size_t) where->size);
r = 1;
out:
dm_free(bounce_buf);
return r;
}
@ -685,6 +330,8 @@ static int _dev_get_size_file(struct device *dev, uint64_t *size)
static int _dev_get_size_dev(struct device *dev, uint64_t *size)
{
const char *name = dev_name(dev);
int fd = dev->bcache_fd;
int do_close = 0;
if (dev->size_seqno == _dev_size_seqno) {
log_very_verbose("%s: using cached size %" PRIu64 " sectors",
@ -693,12 +340,16 @@ static int _dev_get_size_dev(struct device *dev, uint64_t *size)
return 1;
}
if (!dev_open_readonly(dev))
return_0;
if (fd <= 0) {
if (!dev_open_readonly(dev))
return_0;
fd = dev_fd(dev);
do_close = 1;
}
if (ioctl(dev_fd(dev), BLKGETSIZE64, size) < 0) {
if (ioctl(fd, BLKGETSIZE64, size) < 0) {
log_sys_error("ioctl BLKGETSIZE64", name);
if (!dev_close(dev))
if (do_close && !dev_close(dev))
log_sys_error("close", name);
return 0;
}
@ -707,7 +358,7 @@ static int _dev_get_size_dev(struct device *dev, uint64_t *size)
dev->size = *size;
dev->size_seqno = _dev_size_seqno;
if (!dev_close(dev))
if (do_close && !dev_close(dev))
log_sys_error("close", name);
log_very_verbose("%s: size is %" PRIu64 " sectors", name, *size);
@ -984,17 +635,12 @@ int dev_open_readonly_quiet(struct device *dev)
int dev_test_excl(struct device *dev)
{
int flags;
int r;
int flags = 0;
flags = vg_write_lock_held() ? O_RDWR : O_RDONLY;
flags |= O_EXCL;
flags |= O_RDWR;
r = dev_open_flags(dev, flags, 1, 1);
if (r)
dev_close_immediate(dev);
return r;
return dev_open_flags(dev, flags, 1, 1);
}
static void _close(struct device *dev)
@ -1005,7 +651,6 @@ static void _close(struct device *dev)
dev->phys_block_size = -1;
dev->block_size = -1;
dm_list_del(&dev->open_list);
devbufs_release(dev);
log_debug_devs("Closed %s", dev_name(dev));
@ -1015,7 +660,6 @@ static void _close(struct device *dev)
static int _dev_close(struct device *dev, int immediate)
{
if (dev->fd < 0) {
log_error("Attempt to close device '%s' "
"which is not open.", dev_name(dev));
@ -1078,123 +722,57 @@ static void _dev_inc_error_count(struct device *dev)
dev->max_error_count, dev_name(dev));
}
/*
* Data is returned (read-only) at DEV_DEVBUF_DATA(dev, reason).
* If dev_read_callback_fn is supplied, we always return 1 and take
* responsibility for calling it exactly once. This might happen before the
* function returns (if there's an error or the I/O is synchronous) or after.
* Any error is passed to that function, which must track it if required.
*/
static int _dev_read_callback(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t reason,
unsigned ioflags, lvm_callback_fn_t dev_read_callback_fn, void *callback_context)
int dev_read(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t reason, void *buffer)
{
struct device_area where;
struct device_buffer *devbuf;
uint64_t buf_end;
int cached = 0;
int ret = 0;
int ret;
if (!dev->open_count) {
log_error(INTERNAL_ERROR "Attempt to access device %s while closed.", dev_name(dev));
goto out;
}
if (!dev->open_count)
return_0;
if (!_dev_is_valid(dev))
goto_out;
/*
* Can we satisfy this from data we stored last time we read?
*/
if ((devbuf = DEV_DEVBUF(dev, reason)) && devbuf->malloc_address) {
buf_end = devbuf->where.start + devbuf->where.size - 1;
if (offset >= devbuf->where.start && offset <= buf_end && offset + len - 1 <= buf_end) {
/* Reuse this buffer */
cached = 1;
devbuf->data_offset = offset - devbuf->where.start;
log_debug_io("Cached read for %" PRIu64 " bytes at %" PRIu64 " on %s (for %s)",
(uint64_t) len, (uint64_t) offset, dev_name(dev), _reason_text(reason));
ret = 1;
goto out;
}
}
return 0;
where.dev = dev;
where.start = offset;
where.size = len;
ret = _aligned_io(&where, NULL, 0, reason, ioflags, dev_read_callback_fn, callback_context);
if (!ret) {
log_debug("Read from %s failed (for %s).", dev_name(dev), _reason_text(reason));
ret = _aligned_io(&where, buffer, 0, reason);
if (!ret)
_dev_inc_error_count(dev);
}
out:
/* If we had an error or this was sync I/O, pass the result to any callback fn */
if ((!ret || !_aio_ctx || !aio_supported_code_path(ioflags) || cached) && dev_read_callback_fn) {
dev_read_callback_fn(!ret, ioflags, callback_context, DEV_DEVBUF_DATA(dev, reason));
return 1;
}
return ret;
}
void dev_read_callback(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t reason,
unsigned ioflags, lvm_callback_fn_t dev_read_callback_fn, void *callback_context)
/*
* Read from 'dev' into 'buf', possibly in 2 distinct regions, denoted
* by (offset,len) and (offset2,len2). Thus, the total size of
* 'buf' should be len+len2.
*/
int dev_read_circular(struct device *dev, uint64_t offset, size_t len,
uint64_t offset2, size_t len2, dev_io_reason_t reason, char *buf)
{
/* Always returns 1 if callback fn is supplied */
if (!_dev_read_callback(dev, offset, len, reason, ioflags, dev_read_callback_fn, callback_context))
log_error(INTERNAL_ERROR "_dev_read_callback failed");
}
if (!dev_read(dev, offset, len, reason, buf)) {
log_error("Read from %s failed", dev_name(dev));
return 0;
}
/* Returns pointer to read-only buffer. Caller does not free it. */
const char *dev_read(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t reason)
{
if (!_dev_read_callback(dev, offset, len, reason, 0, NULL, NULL))
return_NULL;
/*
* The second region is optional, and allows for
* a circular buffer on the device.
*/
if (!len2)
return 1;
return DEV_DEVBUF_DATA(dev, reason);
}
/* Read into supplied retbuf owned by the caller. */
int dev_read_buf(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t reason, void *retbuf)
{
if (!_dev_read_callback(dev, offset, len, reason, 0, NULL, NULL))
return_0;
memcpy(retbuf, DEV_DEVBUF_DATA(dev, reason), len);
if (!dev_read(dev, offset2, len2, reason, buf + len)) {
log_error("Circular read from %s failed",
dev_name(dev));
return 0;
}
return 1;
}
/*
* Read from 'dev' in 2 distinct regions, denoted by (offset,len) and (offset2,len2).
* Caller is responsible for dm_free().
*/
const char *dev_read_circular(struct device *dev, uint64_t offset, size_t len,
uint64_t offset2, size_t len2, dev_io_reason_t reason)
{
char *buf = NULL;
if (!(buf = dm_malloc(len + len2))) {
log_error("Buffer allocation failed for split metadata.");
return NULL;
}
if (!dev_read_buf(dev, offset, len, reason, buf)) {
log_error("Read from %s failed.", dev_name(dev));
dm_free(buf);
return NULL;
}
if (!dev_read_buf(dev, offset2, len2, reason, buf + len)) {
log_error("Circular read from %s failed.", dev_name(dev));
dm_free(buf);
return NULL;
}
return buf;
}
/* FIXME If O_DIRECT can't extend file, dev_extend first; dev_truncate after.
* But fails if concurrent processes writing
*/
@ -1238,7 +816,7 @@ int dev_write(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t r
dev->flags |= DEV_ACCESSED_W;
ret = _aligned_io(&where, buffer, 1, reason, 0, NULL, NULL);
ret = _aligned_io(&where, buffer, 1, reason);
if (!ret)
_dev_inc_error_count(dev);
@ -1248,7 +826,7 @@ int dev_write(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t r
int dev_set(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t reason, int value)
{
size_t s;
char buffer[4096] __attribute__((aligned(4096)));
char buffer[4096] __attribute__((aligned(8)));
if (!dev_open(dev))
return_0;

View File

@ -31,7 +31,7 @@ int dev_is_luks(struct device *dev, uint64_t *offset_found)
if (offset_found)
*offset_found = 0;
if (!dev_read_buf(dev, 0, LUKS_SIGNATURE_SIZE, DEV_IO_SIGNATURES, buf))
if (!dev_read(dev, 0, LUKS_SIGNATURE_SIZE, DEV_IO_SIGNATURES, buf))
goto_out;
ret = memcmp(buf, LUKS_SIGNATURE, LUKS_SIGNATURE_SIZE) ? 0 : 1;

View File

@ -37,7 +37,7 @@ static int _dev_has_md_magic(struct device *dev, uint64_t sb_offset)
uint32_t md_magic;
/* Version 1 is little endian; version 0.90.0 is machine endian */
if (dev_read_buf(dev, sb_offset, sizeof(uint32_t), DEV_IO_SIGNATURES, &md_magic) &&
if (dev_read(dev, sb_offset, sizeof(uint32_t), DEV_IO_SIGNATURES, &md_magic) &&
((md_magic == MD_SB_MAGIC) ||
((MD_SB_MAGIC != xlate32(MD_SB_MAGIC)) && (md_magic == xlate32(MD_SB_MAGIC)))))
return 1;

View File

@ -60,7 +60,8 @@ int dev_is_swap(struct device *dev, uint64_t *offset_found)
continue;
if (size < (page >> SECTOR_SHIFT))
break;
if (!dev_read_buf(dev, page - SIGNATURE_SIZE, SIGNATURE_SIZE, DEV_IO_SIGNATURES, buf)) {
if (!dev_read(dev, page - SIGNATURE_SIZE,
SIGNATURE_SIZE, DEV_IO_SIGNATURES, buf)) {
ret = -1;
break;
}

View File

@ -17,6 +17,8 @@
#include "xlate.h"
#include "config.h"
#include "metadata.h"
#include "bcache.h"
#include "label.h"
#include <libgen.h>
#include <ctype.h>
@ -363,7 +365,7 @@ static int _has_partition_table(struct device *dev)
uint16_t magic;
} __attribute__((packed)) buf; /* sizeof() == SECTOR_SIZE */
if (!dev_read_buf(dev, UINT64_C(0), sizeof(buf), DEV_IO_SIGNATURES, &buf))
if (!dev_read(dev, UINT64_C(0), sizeof(buf), DEV_IO_SIGNATURES, &buf))
return_0;
/* FIXME Check for other types of partition table too */
@ -675,7 +677,7 @@ static int _blkid_wipe(blkid_probe probe, struct device *dev, const char *name,
} else
log_verbose(_msg_wiping, type, name);
if (!dev_set(dev, offset_value, len, DEV_IO_SIGNATURES, 0)) {
if (!dev_write_zeros(dev, offset_value, len)) {
log_error("Failed to wipe %s signature on %s.", type, name);
return 0;
}
@ -772,7 +774,7 @@ static int _wipe_signature(struct device *dev, const char *type, const char *nam
}
log_print_unless_silent("Wiping %s on %s.", type, name);
if (!dev_set(dev, offset_found, wipe_len, DEV_IO_SIGNATURES, 0)) {
if (!dev_write_zeros(dev, offset_found, wipe_len)) {
log_error("Failed to wipe %s on %s.", type, name);
return 0;
}

View File

@ -31,18 +31,8 @@
#define DEV_USED_FOR_LV 0x00000100 /* Is device used for an LV */
#define DEV_ASSUMED_FOR_LV 0x00000200 /* Is device assumed for an LV */
#define DEV_NOT_O_NOATIME 0x00000400 /* Don't use O_NOATIME */
/* ioflags */
#define AIO_SUPPORTED_CODE_PATH 0x00000001 /* Set if the code path supports AIO */
#define aio_supported_code_path(ioflags) (((ioflags) & AIO_SUPPORTED_CODE_PATH) ? 1 : 0)
/*
* Standard format for callback functions.
* When provided, callback functions are called exactly once.
* If failed is set, data cannot be accessed.
*/
typedef void (*lvm_callback_fn_t)(int failed, unsigned ioflags, void *context, const void *data);
#define DEV_IN_BCACHE 0x00000800 /* dev fd is open and used in bcache */
#define DEV_BCACHE_EXCL 0x00001000 /* bcache_fd should be open EXCL */
/*
* Support for external device info.
@ -61,48 +51,6 @@ struct dev_ext {
void *handle;
};
/*
* All I/O is annotated with the reason it is performed.
*/
typedef enum dev_io_reason {
DEV_IO_SIGNATURES = 0, /* Scanning device signatures */
DEV_IO_LABEL, /* LVM PV disk label */
DEV_IO_MDA_HEADER, /* Text format metadata area header */
DEV_IO_MDA_CONTENT, /* Text format metadata area content */
DEV_IO_MDA_EXTRA_HEADER, /* Header of any extra metadata areas on device */
DEV_IO_MDA_EXTRA_CONTENT, /* Content of any extra metadata areas on device */
DEV_IO_FMT1, /* Original LVM1 metadata format */
DEV_IO_POOL, /* Pool metadata format */
DEV_IO_LV, /* Content written to an LV */
DEV_IO_LOG /* Logging messages */
} dev_io_reason_t;
/*
* Is this I/O for a device's extra metadata area?
*/
#define EXTRA_IO(reason) ((reason) == DEV_IO_MDA_EXTRA_HEADER || (reason) == DEV_IO_MDA_EXTRA_CONTENT)
#define DEV_DEVBUF(dev, reason) (EXTRA_IO((reason)) ? &(dev)->last_extra_devbuf : &(dev)->last_devbuf)
#define DEV_DEVBUF_DATA(dev, reason) ((char *) DEV_DEVBUF((dev), (reason))->buf + DEV_DEVBUF((dev), (reason))->data_offset)
struct device_area {
struct device *dev;
uint64_t start; /* Bytes */
uint64_t size; /* Bytes */
};
struct device_buffer {
uint64_t data_offset; /* Offset to start of requested data within buf */
void *malloc_address; /* Start of allocated memory */
void *buf; /* Aligned buffer that contains data within it */
struct device_area where; /* Location of buf */
dev_io_reason_t reason;
unsigned write:1; /* 1 if write; 0 if read */
lvm_callback_fn_t dev_read_callback_fn;
void *dev_read_callback_context;
struct dm_list aio_queued; /* Queue of async I/O waiting to be issued */
};
/*
* All devices in LVM will be represented by one of these.
* pointer comparisons are valid.
@ -119,14 +67,13 @@ struct device {
int phys_block_size;
int block_size;
int read_ahead;
int bcache_fd;
uint32_t flags;
unsigned size_seqno;
uint64_t size;
uint64_t end;
struct dm_list open_list;
struct dev_ext ext;
struct device_buffer last_devbuf; /* Last data buffer read from the device */
struct device_buffer last_extra_devbuf; /* Last data buffer read from the device for extra metadata area */
const char *vgid; /* if device is an LV */
const char *lvid; /* if device is an LV */
@ -135,11 +82,33 @@ struct device {
char _padding[7];
};
/*
* All I/O is annotated with the reason it is performed.
*/
typedef enum dev_io_reason {
DEV_IO_SIGNATURES = 0, /* Scanning device signatures */
DEV_IO_LABEL, /* LVM PV disk label */
DEV_IO_MDA_HEADER, /* Text format metadata area header */
DEV_IO_MDA_CONTENT, /* Text format metadata area content */
DEV_IO_MDA_EXTRA_HEADER, /* Header of any extra metadata areas on device */
DEV_IO_MDA_EXTRA_CONTENT, /* Content of any extra metadata areas on device */
DEV_IO_FMT1, /* Original LVM1 metadata format */
DEV_IO_POOL, /* Pool metadata format */
DEV_IO_LV, /* Content written to an LV */
DEV_IO_LOG /* Logging messages */
} dev_io_reason_t;
struct device_list {
struct dm_list list;
struct device *dev;
};
struct device_area {
struct device *dev;
uint64_t start; /* Bytes */
uint64_t size; /* Bytes */
};
/*
* Support for external device info.
*/
@ -179,19 +148,9 @@ int dev_test_excl(struct device *dev);
int dev_fd(struct device *dev);
const char *dev_name(const struct device *dev);
/* Returns a read-only buffer */
const char *dev_read(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t reason);
const char *dev_read_circular(struct device *dev, uint64_t offset, size_t len,
uint64_t offset2, size_t len2, dev_io_reason_t reason);
/* Passes the data (or error) to dev_read_callback_fn */
void dev_read_callback(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t reason,
unsigned ioflags, lvm_callback_fn_t dev_read_callback_fn, void *callback_context);
/* Read data and copy it into a supplied private buffer. */
/* Only use for tiny reads or on unimportant code paths. */
int dev_read_buf(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t reason, void *retbuf);
int dev_read(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t reason, void *buffer);
int dev_read_circular(struct device *dev, uint64_t offset, size_t len,
uint64_t offset2, size_t len2, dev_io_reason_t reason, char *buf);
int dev_write(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t reason, void *buffer);
int dev_append(struct device *dev, size_t len, dev_io_reason_t reason, char *buffer);
int dev_set(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t reason, int value);
@ -201,15 +160,7 @@ struct device *dev_create_file(const char *filename, struct device *dev,
struct dm_str_list *alias, int use_malloc);
void dev_destroy_file(struct device *dev);
void devbufs_release(struct device *dev);
/* Return a valid device name from the alias list; NULL otherwise */
const char *dev_name_confirmed(struct device *dev, int quiet);
struct cmd_context;
int dev_async_getevents(void);
int dev_async_setup(struct cmd_context *cmd);
void dev_async_exit(void);
int dev_async_reset(struct cmd_context *cmd);
#endif

View File

@ -52,13 +52,13 @@ static void _composite_destroy(struct dev_filter *f)
dm_free(f);
}
static int _dump(struct dev_filter *f, struct dm_pool *mem, int merge_existing)
static int _dump(struct dev_filter *f, int merge_existing)
{
struct dev_filter **filters;
for (filters = (struct dev_filter **) f->private; *filters; ++filters)
if ((*filters)->dump &&
!(*filters)->dump(*filters, mem, merge_existing))
!(*filters)->dump(*filters, merge_existing))
return_0;
return 1;

View File

@ -48,11 +48,7 @@ static void _persistent_filter_wipe(struct dev_filter *f)
{
struct pfilter *pf = (struct pfilter *) f->private;
log_verbose("Wiping cache of LVM-capable devices");
dm_hash_wipe(pf->devices);
/* Trigger complete device scan */
dev_cache_scan(1);
}
static int _read_array(struct pfilter *pf, struct dm_config_tree *cft,
@ -87,7 +83,7 @@ static int _read_array(struct pfilter *pf, struct dm_config_tree *cft,
return 1;
}
int persistent_filter_load(struct dm_pool *mem, struct dev_filter *f, struct dm_config_tree **cft_out)
int persistent_filter_load(struct dev_filter *f, struct dm_config_tree **cft_out)
{
struct pfilter *pf = (struct pfilter *) f->private;
struct dm_config_tree *cft;
@ -116,7 +112,7 @@ int persistent_filter_load(struct dm_pool *mem, struct dev_filter *f, struct dm_
if (!(cft = config_open(CONFIG_FILE_SPECIAL, pf->file, 1)))
return_0;
if (!config_file_read(mem, cft))
if (!config_file_read(cft))
goto_out;
log_debug_devs("Loading persistent filter cache from %s", pf->file);
@ -126,15 +122,6 @@ int persistent_filter_load(struct dm_pool *mem, struct dev_filter *f, struct dm_
/* _read_array(pf, cft, "persistent_filter_cache/invalid_devices",
PF_BAD_DEVICE); */
/* Did we find anything? */
if (dm_hash_get_num_entries(pf->devices)) {
/* We populated dev_cache ourselves */
dev_cache_scan(0);
if (!dev_cache_index_devs())
stack;
r = 1;
}
log_very_verbose("Loaded persistent filter cache from %s", pf->file);
out:
@ -175,7 +162,7 @@ static void _write_array(struct pfilter *pf, FILE *fp, const char *path,
fprintf(fp, "\n\t]\n");
}
static int _persistent_filter_dump(struct dev_filter *f, struct dm_pool *mem, int merge_existing)
static int _persistent_filter_dump(struct dev_filter *f, int merge_existing)
{
struct pfilter *pf;
char *tmp_file;
@ -234,7 +221,7 @@ static int _persistent_filter_dump(struct dev_filter *f, struct dm_pool *mem, in
lvm_stat_ctim(&ts, &info);
if (merge_existing && timespeccmp(&ts, &pf->ctime, !=))
/* Keep cft open to avoid losing lock */
persistent_filter_load(mem, f, &cft);
persistent_filter_load(f, &cft);
tmp_file = alloca(strlen(pf->file) + 5);
sprintf(tmp_file, "%s.tmp", pf->file);

View File

@ -53,6 +53,6 @@ typedef enum {
} filter_mode_t;
struct dev_filter *usable_filter_create(struct dev_types *dt, filter_mode_t mode);
int persistent_filter_load(struct dm_pool *mem, struct dev_filter *f, struct dm_config_tree **cft_out);
int persistent_filter_load(struct dev_filter *f, struct dm_config_tree **cft_out);
#endif /* _LVM_FILTER_H */

View File

@ -205,7 +205,7 @@ int munge_pvd(struct device *dev, struct pv_disk *pvd)
static int _read_pvd(struct device *dev, struct pv_disk *pvd)
{
if (!dev_read_buf(dev, UINT64_C(0), sizeof(*pvd), DEV_IO_FMT1, pvd)) {
if (!dev_read(dev, UINT64_C(0), sizeof(*pvd), DEV_IO_FMT1, pvd)) {
log_very_verbose("Failed to read PV data from %s",
dev_name(dev));
return 0;
@ -216,7 +216,7 @@ static int _read_pvd(struct device *dev, struct pv_disk *pvd)
static int _read_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk)
{
if (!dev_read_buf(dev, pos, sizeof(*disk), DEV_IO_FMT1, disk))
if (!dev_read(dev, pos, sizeof(*disk), DEV_IO_FMT1, disk))
return_0;
_xlate_lvd(disk);
@ -228,7 +228,7 @@ int read_vgd(struct device *dev, struct vg_disk *vgd, struct pv_disk *pvd)
{
uint64_t pos = pvd->vg_on_disk.base;
if (!dev_read_buf(dev, pos, sizeof(*vgd), DEV_IO_FMT1, vgd))
if (!dev_read(dev, pos, sizeof(*vgd), DEV_IO_FMT1, vgd))
return_0;
_xlate_vgd(vgd);
@ -252,7 +252,7 @@ static int _read_uuids(struct disk_list *data)
uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size;
while (pos < end && num_read < data->vgd.pv_cur) {
if (!dev_read_buf(data->dev, pos, sizeof(buffer), DEV_IO_FMT1, buffer))
if (!dev_read(data->dev, pos, sizeof(buffer), DEV_IO_FMT1, buffer))
return_0;
if (!(ul = dm_pool_alloc(data->mem, sizeof(*ul))))
@ -311,7 +311,7 @@ static int _read_extents(struct disk_list *data)
if (!extents)
return_0;
if (!dev_read_buf(data->dev, pos, len, DEV_IO_FMT1, extents))
if (!dev_read(data->dev, pos, len, DEV_IO_FMT1, extents))
return_0;
_xlate_extents(extents, data->pvd.pe_total);
@ -337,7 +337,6 @@ static void __update_lvmcache(const struct format_type *fmt,
lvmcache_set_device_size(info, ((uint64_t)xlate32(dl->pvd.pv_size)) << SECTOR_SHIFT);
lvmcache_del_mdas(info);
lvmcache_make_valid(info);
}
static struct disk_list *__read_disk(const struct format_type *fmt,

View File

@ -182,7 +182,7 @@ static struct volume_group *_format1_vg_read(struct format_instance *fid,
struct metadata_area *mda __attribute__((unused)),
struct cached_vg_fmtdata **vg_fmtdata __attribute__((unused)),
unsigned *use_previous_vg __attribute__((unused)),
int single_device __attribute__((unused)), unsigned ioflags)
int single_device __attribute__((unused)))
{
struct volume_group *vg;
struct disk_list *dl;

View File

@ -54,17 +54,15 @@ static int _lvm1_write(struct label *label __attribute__((unused)), void *buf __
return 0;
}
static int _lvm1_read(struct labeller *l, struct device *dev, void *buf, unsigned ioflags,
lvm_callback_fn_t read_label_callback_fn, void *read_label_callback_context)
static int _lvm1_read(struct labeller *l, struct device *dev, void *buf,
struct label **label)
{
struct pv_disk *pvd = (struct pv_disk *) buf;
struct vg_disk vgd;
struct lvmcache_info *info;
struct label *label = NULL;
const char *vgid = FMT_LVM1_ORPHAN_VG_NAME;
const char *vgname = FMT_LVM1_ORPHAN_VG_NAME;
unsigned exported = 0;
int r = 0;
munge_pvd(dev, pvd);
@ -78,24 +76,16 @@ static int _lvm1_read(struct labeller *l, struct device *dev, void *buf, unsigne
if (!(info = lvmcache_add(l, (char *)pvd->pv_uuid, dev, vgname, vgid,
exported)))
goto_out;
label = lvmcache_get_label(info);
return_0;
*label = lvmcache_get_label(info);
lvmcache_set_device_size(info, ((uint64_t)xlate32(pvd->pv_size)) << SECTOR_SHIFT);
lvmcache_set_ext_version(info, 0);
lvmcache_set_ext_flags(info, 0);
lvmcache_del_mdas(info);
lvmcache_del_bas(info);
lvmcache_make_valid(info);
r = 1;
out:
if (read_label_callback_fn)
read_label_callback_fn(!r, 0, read_label_callback_context, label);
return r;
return 1;
}
static int _lvm1_initialise_label(struct labeller *l __attribute__((unused)), struct label *label)

View File

@ -40,7 +40,7 @@ static int __read_pool_disk(const struct format_type *fmt, struct device *dev,
char buf[512] __attribute__((aligned(8)));
/* FIXME: Need to check the cache here first */
if (!dev_read_buf(dev, UINT64_C(0), 512, DEV_IO_POOL, buf)) {
if (!dev_read(dev, UINT64_C(0), 512, DEV_IO_POOL, buf)) {
log_very_verbose("Failed to read PV data from %s",
dev_name(dev));
return 0;
@ -111,7 +111,6 @@ int read_pool_label(struct pool_list *pl, struct labeller *l,
lvmcache_set_ext_flags(info, 0);
lvmcache_del_mdas(info);
lvmcache_del_bas(info);
lvmcache_make_valid(info);
pl->dev = dev;
pl->pv = NULL;
@ -379,8 +378,6 @@ int read_pool_pds(const struct format_type *fmt, const char *vg_name,
vg_name);
return 0;
}
if (full_scan > 0)
lvmcache_force_next_label_scan();
lvmcache_label_scan(fmt->cmd);
} while (1);

View File

@ -103,7 +103,7 @@ static struct volume_group *_pool_vg_read(struct format_instance *fid,
struct metadata_area *mda __attribute__((unused)),
struct cached_vg_fmtdata **vg_fmtdata __attribute__((unused)),
unsigned *use_previous_vg __attribute__((unused)),
int single_device __attribute__((unused)), unsigned ioflags)
int single_device __attribute__((unused)))
{
struct volume_group *vg;
struct user_subpool *usp;

View File

@ -55,19 +55,12 @@ static int _pool_write(struct label *label __attribute__((unused)), void *buf __
return 0;
}
static int _pool_read(struct labeller *l, struct device *dev, void *buf, unsigned ioflags,
lvm_callback_fn_t read_label_callback_fn, void *read_label_callback_context)
static int _pool_read(struct labeller *l, struct device *dev, void *buf,
struct label **label)
{
struct pool_list pl;
struct label *label;
int r;
r = read_pool_label(&pl, l, dev, buf, &label);
if (read_label_callback_fn)
read_label_callback_fn(!r, 0, read_label_callback_context, label);
return r;
return read_pool_label(&pl, l, dev, buf, label);
}
static int _pool_initialise_label(struct labeller *l __attribute__((unused)), struct label *label)

View File

@ -135,8 +135,8 @@ static struct dm_list *_scan_archive(struct dm_pool *mem,
dm_list_init(results);
/* Use versionsort to handle numbers beyond 5 digits */
if ((count = scandir(dir, &dirent, NULL, versionsort)) < 0) {
/* Sort fails beyond 5-digit indexes */
if ((count = scandir(dir, &dirent, NULL, alphasort)) < 0) {
log_error("Couldn't scan the archive directory (%s).", dir);
return 0;
}
@ -320,7 +320,7 @@ static void _display_archive(struct cmd_context *cmd, struct archive_file *af)
* retrieve the archive time and description.
*/
/* FIXME Use variation on _vg_read */
if (!(vg = text_vg_import_file(tf, af->path, &when, &desc))) {
if (!(vg = text_read_metadata_file(tf, af->path, &when, &desc))) {
log_error("Unable to read archive file.");
tf->fmt->ops->destroy_instance(tf);
return;

View File

@ -320,7 +320,7 @@ struct volume_group *backup_read_vg(struct cmd_context *cmd,
}
dm_list_iterate_items(mda, &tf->metadata_areas_in_use) {
if (!(vg = mda->ops->vg_read(tf, vg_name, mda, NULL, NULL, 0, 0)))
if (!(vg = mda->ops->vg_read(tf, vg_name, mda, NULL, NULL)))
stack;
break;
}
@ -488,19 +488,11 @@ int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg,
}
log_verbose("Zeroing start of device %s", pv_name);
if (!dev_open_quiet(dev)) {
log_error("%s not opened: device not zeroed", pv_name);
return 0;
}
if (!dev_set(dev, UINT64_C(0), (size_t) 2048, DEV_IO_LABEL, 0)) {
if (!dev_write_zeros(dev, 0, 2048)) {
log_error("%s not wiped: aborting", pv_name);
if (!dev_close(dev))
stack;
return 0;
}
if (!dev_close(dev))
stack;
}
}

View File

@ -23,7 +23,6 @@
#include "lvm-version.h"
#include "toolcontext.h"
#include "config-util.h"
#include "layout.h"
#include <stdarg.h>
#include <time.h>
@ -124,12 +123,11 @@ static int _extend_buffer(struct formatter *f)
log_debug_metadata("Doubling metadata output buffer to " FMTu32,
f->data.buf.size * 2);
if (!(newbuf = dm_malloc_aligned(f->data.buf.size * 2, 0)))
return_0;
memcpy(newbuf, f->data.buf.start, f->data.buf.size);
free(f->data.buf.start);
if (!(newbuf = dm_realloc(f->data.buf.start,
f->data.buf.size * 2))) {
log_error("Buffer reallocation failed.");
return 0;
}
f->data.buf.start = newbuf;
f->data.buf.size *= 2;
@ -1066,7 +1064,7 @@ size_t text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf)
return_0;
f->data.buf.size = 65536; /* Initial metadata limit */
if (!(f->data.buf.start = dm_malloc_aligned(f->data.buf.size, 0))) {
if (!(f->data.buf.start = dm_malloc(f->data.buf.size))) {
log_error("text_export buffer allocation failed");
goto out;
}
@ -1081,12 +1079,7 @@ size_t text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf)
goto_out;
}
f->data.buf.used += 1; /* Terminating NUL */
/* Zero fill up to next alignment boundary */
memset(f->data.buf.start + f->data.buf.used, 0, MDA_ALIGNMENT - f->data.buf.used % MDA_ALIGNMENT);
r = f->data.buf.used;
r = f->data.buf.used + 1;
*buf = f->data.buf.start;
out:

File diff suppressed because it is too large Load Diff

View File

@ -49,7 +49,6 @@ struct text_vg_version_ops {
int (*check_version) (const struct dm_config_tree * cf);
struct volume_group *(*read_vg) (struct format_instance * fid,
const struct dm_config_tree *cf,
unsigned use_cached_pvs,
unsigned allow_lvmetad_extensions);
void (*read_desc) (struct dm_pool * mem, const struct dm_config_tree *cf,
time_t *when, char **desc);
@ -68,29 +67,26 @@ int read_segtype_lvflags(uint64_t *status, char *segtype_str);
int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp);
size_t text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf);
struct volume_group *text_vg_import_file(struct format_instance *fid,
struct volume_group *text_read_metadata_file(struct format_instance *fid,
const char *file,
time_t *when, char **desc);
struct volume_group *text_vg_import_fd(struct format_instance *fid,
struct volume_group *text_read_metadata(struct format_instance *fid,
const char *file,
struct cached_vg_fmtdata **vg_fmtdata,
unsigned *use_previous_vg,
int single_device,
struct device *dev, int primary_mda,
off_t offset, uint32_t size,
off_t offset2, uint32_t size2,
checksum_fn_t checksum_fn,
uint32_t checksum, unsigned ioflags,
uint32_t checksum,
time_t *when, char **desc);
int text_vgsummary_import(const struct format_type *fmt,
int text_read_metadata_summary(const struct format_type *fmt,
struct device *dev, dev_io_reason_t reason,
off_t offset, uint32_t size,
off_t offset2, uint32_t size2,
checksum_fn_t checksum_fn,
int checksum_only, unsigned ioflags,
struct lvmcache_vgsummary *vgsummary,
lvm_callback_fn_t process_vgsummary_fn,
void *process_vgsummary_context);
int checksum_only,
struct lvmcache_vgsummary *vgsummary);
#endif

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2018 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@ -16,7 +16,6 @@
#include "lib.h"
#include "metadata.h"
#include "import-export.h"
#include "toolcontext.h"
/* FIXME Use tidier inclusion method */
static struct text_vg_version_ops *(_text_vsn_list[2]);
@ -33,102 +32,70 @@ static void _init_text_import(void)
_text_import_initialised = 1;
}
struct import_vgsummary_params {
const struct format_type *fmt;
struct dm_config_tree *cft;
int checksum_only;
struct lvmcache_vgsummary *vgsummary;
lvm_callback_fn_t process_vgsummary_fn;
void *process_vgsummary_context;
int ret;
};
static void _import_vgsummary(int failed, unsigned ioflags, void *context, const void *data)
/*
* Find out vgname on a given device.
*/
int text_read_metadata_summary(const struct format_type *fmt,
struct device *dev, dev_io_reason_t reason,
off_t offset, uint32_t size,
off_t offset2, uint32_t size2,
checksum_fn_t checksum_fn,
int checksum_only,
struct lvmcache_vgsummary *vgsummary)
{
struct import_vgsummary_params *ivsp = context;
struct dm_config_tree *cft;
struct text_vg_version_ops **vsn;
int r = 0;
if (failed) {
ivsp->ret = 0;
goto_out;
_init_text_import();
if (!(cft = config_open(CONFIG_FILE_SPECIAL, NULL, 0)))
return_0;
if (dev) {
log_debug_metadata("Reading metadata summary from %s at %llu size %d (+%d)",
dev_name(dev), (unsigned long long)offset,
size, size2);
if (!config_file_read_fd(cft, dev, reason, offset, size,
offset2, size2, checksum_fn,
vgsummary->mda_checksum,
checksum_only, 1)) {
/* FIXME: handle errors */
log_error("Couldn't read volume group metadata from %s.", dev_name(dev));
goto out;
}
} else {
if (!config_file_read(cft)) {
log_error("Couldn't read volume group metadata from file.");
goto out;
}
}
if (ivsp->checksum_only)
if (checksum_only) {
/* Checksum matches already-cached content - no need to reparse. */
log_debug_metadata("Skipped parsing metadata on %s", dev_name(dev));
r = 1;
goto out;
}
/*
* Find a set of version functions that can read this file
*/
for (vsn = &_text_vsn_list[0]; *vsn; vsn++) {
if (!(*vsn)->check_version(ivsp->cft))
if (!(*vsn)->check_version(cft))
continue;
if (!(*vsn)->read_vgsummary(ivsp->fmt, ivsp->cft, ivsp->vgsummary)) {
ivsp->ret = 0;
if (!(*vsn)->read_vgsummary(fmt, cft, vgsummary))
goto_out;
}
goto out;
r = 1;
break;
}
/* Nothing found */
ivsp->ret = 0;
out:
config_destroy(ivsp->cft);
if (ivsp->process_vgsummary_fn)
ivsp->process_vgsummary_fn(!ivsp->ret, ioflags, ivsp->process_vgsummary_context, NULL);
}
/*
* Find out vgname on a given device.
*/
int text_vgsummary_import(const struct format_type *fmt,
struct device *dev, dev_io_reason_t reason,
off_t offset, uint32_t size,
off_t offset2, uint32_t size2,
checksum_fn_t checksum_fn,
int checksum_only, unsigned ioflags,
struct lvmcache_vgsummary *vgsummary,
lvm_callback_fn_t process_vgsummary_fn,
void *process_vgsummary_context)
{
struct import_vgsummary_params *ivsp;
_init_text_import();
if (!(ivsp = dm_pool_zalloc(fmt->cmd->mem, sizeof(*ivsp)))) {
log_error("Failed to allocate import_vgsummary_params struct.");
return 0;
}
if (!(ivsp->cft = config_open(CONFIG_FILE_SPECIAL, NULL, 0)))
return_0;
ivsp->fmt = fmt;
ivsp->checksum_only = checksum_only;
ivsp->vgsummary = vgsummary;
ivsp->process_vgsummary_fn = process_vgsummary_fn;
ivsp->process_vgsummary_context = process_vgsummary_context;
ivsp->ret = 1;
if (!dev) {
if (!config_file_read(fmt->cmd->mem, ivsp->cft)) {
log_error("Couldn't read volume group metadata.");
ivsp->ret = 0;
}
_import_vgsummary(!ivsp->ret, ioflags, ivsp, NULL);
} else if (!config_file_read_fd(fmt->cmd->mem, ivsp->cft, dev, reason, offset, size,
offset2, size2, checksum_fn,
vgsummary->mda_checksum,
checksum_only, 1, ioflags, &_import_vgsummary, ivsp)) {
log_error("Couldn't read volume group metadata.");
return 0;
}
return ivsp->ret;
out:
config_destroy(cft);
return r;
}
struct cached_vg_fmtdata {
@ -136,30 +103,74 @@ struct cached_vg_fmtdata {
size_t cached_mda_size;
};
struct import_vg_params {
struct format_instance *fid;
struct dm_config_tree *cft;
int single_device;
int skip_parse;
unsigned *use_previous_vg;
struct volume_group *vg;
uint32_t checksum;
uint32_t total_size;
time_t *when;
struct cached_vg_fmtdata **vg_fmtdata;
char **desc;
};
static void _import_vg(int failed, unsigned ioflags, void *context, const void *data)
struct volume_group *text_read_metadata(struct format_instance *fid,
const char *file,
struct cached_vg_fmtdata **vg_fmtdata,
unsigned *use_previous_vg,
struct device *dev, int primary_mda,
off_t offset, uint32_t size,
off_t offset2, uint32_t size2,
checksum_fn_t checksum_fn,
uint32_t checksum,
time_t *when, char **desc)
{
struct import_vg_params *ivp = context;
struct volume_group *vg = NULL;
struct dm_config_tree *cft;
struct text_vg_version_ops **vsn;
int skip_parse;
ivp->vg = NULL;
/*
* This struct holds the checksum and size of the VG metadata
* that was read from a previous device. When we read the VG
* metadata from this device, we can skip parsing it into a
* cft (saving time) if the checksum of the metadata buffer
* we read from this device matches the size/checksum saved in
* the mda_header/rlocn struct on this device, and matches the
* size/checksum from the previous device.
*/
if (vg_fmtdata && !*vg_fmtdata &&
!(*vg_fmtdata = dm_pool_zalloc(fid->mem, sizeof(**vg_fmtdata)))) {
log_error("Failed to allocate VG fmtdata for text format.");
return NULL;
}
if (ivp->skip_parse) {
if (ivp->use_previous_vg)
*ivp->use_previous_vg = 1;
_init_text_import();
*desc = NULL;
*when = 0;
if (!(cft = config_open(CONFIG_FILE_SPECIAL, file, 0)))
return_NULL;
/* Does the metadata match the already-cached VG? */
skip_parse = vg_fmtdata &&
((*vg_fmtdata)->cached_mda_checksum == checksum) &&
((*vg_fmtdata)->cached_mda_size == (size + size2));
if (dev) {
log_debug_metadata("Reading metadata from %s at %llu size %d (+%d)",
dev_name(dev), (unsigned long long)offset,
size, size2);
if (!config_file_read_fd(cft, dev, MDA_CONTENT_REASON(primary_mda), offset, size,
offset2, size2, checksum_fn, checksum,
skip_parse, 1)) {
/* FIXME: handle errors */
log_error("Couldn't read volume group metadata from %s.", dev_name(dev));
goto out;
}
} else {
if (!config_file_read(cft)) {
log_error("Couldn't read volume group metadata from file.");
goto out;
}
}
if (skip_parse) {
if (use_previous_vg)
*use_previous_vg = 1;
log_debug_metadata("Skipped parsing metadata on %s", dev_name(dev));
goto out;
}
@ -167,98 +178,36 @@ static void _import_vg(int failed, unsigned ioflags, void *context, const void *
* Find a set of version functions that can read this file
*/
for (vsn = &_text_vsn_list[0]; *vsn; vsn++) {
if (!(*vsn)->check_version(ivp->cft))
if (!(*vsn)->check_version(cft))
continue;
if (!(ivp->vg = (*vsn)->read_vg(ivp->fid, ivp->cft, ivp->single_device, 0)))
if (!(vg = (*vsn)->read_vg(fid, cft, 0)))
goto_out;
(*vsn)->read_desc(ivp->vg->vgmem, ivp->cft, ivp->when, ivp->desc);
(*vsn)->read_desc(vg->vgmem, cft, when, desc);
break;
}
if (ivp->vg && ivp->vg_fmtdata && *ivp->vg_fmtdata) {
(*ivp->vg_fmtdata)->cached_mda_size = ivp->total_size;
(*ivp->vg_fmtdata)->cached_mda_checksum = ivp->checksum;
if (vg && vg_fmtdata && *vg_fmtdata) {
(*vg_fmtdata)->cached_mda_size = (size + size2);
(*vg_fmtdata)->cached_mda_checksum = checksum;
}
if (ivp->use_previous_vg)
*ivp->use_previous_vg = 0;
if (use_previous_vg)
*use_previous_vg = 0;
out:
config_destroy(ivp->cft);
out:
config_destroy(cft);
return vg;
}
struct volume_group *text_vg_import_fd(struct format_instance *fid,
const char *file,
struct cached_vg_fmtdata **vg_fmtdata,
unsigned *use_previous_vg,
int single_device,
struct device *dev, int primary_mda,
off_t offset, uint32_t size,
off_t offset2, uint32_t size2,
checksum_fn_t checksum_fn,
uint32_t checksum, unsigned ioflags,
time_t *when, char **desc)
{
struct import_vg_params *ivp;
if (vg_fmtdata && !*vg_fmtdata &&
!(*vg_fmtdata = dm_pool_zalloc(fid->mem, sizeof(**vg_fmtdata)))) {
log_error("Failed to allocate VG fmtdata for text format.");
return NULL;
}
if (!(ivp = dm_pool_zalloc(fid->fmt->cmd->mem, sizeof(*ivp)))) {
log_error("Failed to allocate import_vgsummary_params struct.");
return NULL;
}
_init_text_import();
ivp->fid = fid;
ivp->when = when;
*ivp->when = 0;
ivp->desc = desc;
*ivp->desc = NULL;
ivp->single_device = single_device;
ivp->use_previous_vg = use_previous_vg;
ivp->checksum = checksum;
ivp->total_size = size + size2;
ivp->vg_fmtdata = vg_fmtdata;
if (!(ivp->cft = config_open(CONFIG_FILE_SPECIAL, file, 0)))
return_NULL;
/* Does the metadata match the already-cached VG? */
ivp->skip_parse = vg_fmtdata &&
((*vg_fmtdata)->cached_mda_checksum == checksum) &&
((*vg_fmtdata)->cached_mda_size == ivp->total_size);
if (!dev && !config_file_read(fid->mem, ivp->cft)) {
config_destroy(ivp->cft);
return_NULL;
}
if (dev) {
if (!config_file_read_fd(fid->mem, ivp->cft, dev, MDA_CONTENT_REASON(primary_mda), offset, size,
offset2, size2, checksum_fn, checksum,
ivp->skip_parse, 1, ioflags, &_import_vg, ivp)) {
config_destroy(ivp->cft);
return_NULL;
}
} else
_import_vg(0, 0, ivp, NULL);
return ivp->vg;
}
struct volume_group *text_vg_import_file(struct format_instance *fid,
struct volume_group *text_read_metadata_file(struct format_instance *fid,
const char *file,
time_t *when, char **desc)
{
return text_vg_import_fd(fid, file, NULL, NULL, 0, NULL, 0, (off_t)0, 0, (off_t)0, 0, NULL, 0,
0, when, desc);
return text_read_metadata(fid, file, NULL, NULL, NULL, 0,
(off_t)0, 0, (off_t)0, 0, NULL, 0,
when, desc);
}
static struct volume_group *_import_vg_from_config_tree(const struct dm_config_tree *cft,
@ -278,7 +227,7 @@ static struct volume_group *_import_vg_from_config_tree(const struct dm_config_t
* The only path to this point uses cached vgmetadata,
* so it can use cached PV state too.
*/
if (!(vg = (*vsn)->read_vg(fid, cft, 1, allow_lvmetad_extensions)))
if (!(vg = (*vsn)->read_vg(fid, cft, allow_lvmetad_extensions)))
stack;
else if ((vg_missing = vg_missing_pv_count(vg))) {
log_verbose("There are %d physical volumes missing.",

View File

@ -32,9 +32,7 @@ typedef int (*section_fn) (struct format_instance * fid,
struct volume_group * vg, const struct dm_config_node * pvn,
const struct dm_config_node * vgn,
struct dm_hash_table * pv_hash,
struct dm_hash_table * lv_hash,
unsigned *scan_done_once,
unsigned report_missing_devices);
struct dm_hash_table * lv_hash);
#define _read_int32(root, path, result) \
dm_config_get_uint32(root, path, (uint32_t *) (result))
@ -180,9 +178,7 @@ static int _read_pv(struct format_instance *fid,
struct volume_group *vg, const struct dm_config_node *pvn,
const struct dm_config_node *vgn __attribute__((unused)),
struct dm_hash_table *pv_hash,
struct dm_hash_table *lv_hash __attribute__((unused)),
unsigned *scan_done_once,
unsigned report_missing_devices)
struct dm_hash_table *lv_hash __attribute__((unused)))
{
struct dm_pool *mem = vg->vgmem;
struct physical_volume *pv;
@ -220,16 +216,16 @@ static int _read_pv(struct format_instance *fid,
/*
* Convert the uuid into a device.
*/
if (!(pv->dev = lvmcache_device_from_pvid(fid->fmt->cmd, &pv->id, scan_done_once,
&pv->label_sector))) {
if (!(pv->dev = lvmcache_device_from_pvid(fid->fmt->cmd, &pv->id, &pv->label_sector))) {
char buffer[64] __attribute__((aligned(8)));
if (!id_write_format(&pv->id, buffer, sizeof(buffer)))
buffer[0] = '\0';
if (report_missing_devices)
if (fid->fmt->cmd && !fid->fmt->cmd->pvscan_cache_single)
log_error_once("Couldn't find device with uuid %s.", buffer);
else
log_very_verbose("Couldn't find device with uuid %s.", buffer);
log_debug_metadata("Couldn't find device with uuid %s.", buffer);
}
if (!(pv->vg_name = dm_pool_strdup(mem, vg->name)))
@ -574,9 +570,7 @@ static int _read_lvnames(struct format_instance *fid __attribute__((unused)),
struct volume_group *vg, const struct dm_config_node *lvn,
const struct dm_config_node *vgn __attribute__((unused)),
struct dm_hash_table *pv_hash __attribute__((unused)),
struct dm_hash_table *lv_hash,
unsigned *scan_done_once __attribute__((unused)),
unsigned report_missing_devices __attribute__((unused)))
struct dm_hash_table *lv_hash)
{
struct dm_pool *mem = vg->vgmem;
struct logical_volume *lv;
@ -731,9 +725,7 @@ static int _read_historical_lvnames(struct format_instance *fid __attribute__((u
struct volume_group *vg, const struct dm_config_node *hlvn,
const struct dm_config_node *vgn __attribute__((unused)),
struct dm_hash_table *pv_hash __attribute__((unused)),
struct dm_hash_table *lv_hash __attribute__((unused)),
unsigned *scan_done_once __attribute__((unused)),
unsigned report_missing_devices __attribute__((unused)))
struct dm_hash_table *lv_hash __attribute__((unused)))
{
struct dm_pool *mem = vg->vgmem;
struct generic_logical_volume *glv;
@ -802,9 +794,7 @@ static int _read_historical_lvnames_interconnections(struct format_instance *fid
struct volume_group *vg, const struct dm_config_node *hlvn,
const struct dm_config_node *vgn __attribute__((unused)),
struct dm_hash_table *pv_hash __attribute__((unused)),
struct dm_hash_table *lv_hash __attribute__((unused)),
unsigned *scan_done_once __attribute__((unused)),
unsigned report_missing_devices __attribute__((unused)))
struct dm_hash_table *lv_hash __attribute__((unused)))
{
struct dm_pool *mem = vg->vgmem;
const char *historical_lv_name, *origin_name = NULL;
@ -914,9 +904,7 @@ static int _read_lvsegs(struct format_instance *fid,
struct volume_group *vg, const struct dm_config_node *lvn,
const struct dm_config_node *vgn __attribute__((unused)),
struct dm_hash_table *pv_hash,
struct dm_hash_table *lv_hash,
unsigned *scan_done_once __attribute__((unused)),
unsigned report_missing_devices __attribute__((unused)))
struct dm_hash_table *lv_hash)
{
struct logical_volume *lv;
@ -977,12 +965,9 @@ static int _read_sections(struct format_instance *fid,
struct volume_group *vg, const struct dm_config_node *vgn,
struct dm_hash_table *pv_hash,
struct dm_hash_table *lv_hash,
int optional,
unsigned *scan_done_once)
int optional)
{
const struct dm_config_node *n;
/* Only report missing devices when doing a scan */
unsigned report_missing_devices = scan_done_once ? !*scan_done_once : 1;
if (!dm_config_get_section(vgn, section, &n)) {
if (!optional) {
@ -994,8 +979,7 @@ static int _read_sections(struct format_instance *fid,
}
for (n = n->child; n; n = n->sib) {
if (!fn(fid, vg, n, vgn, pv_hash, lv_hash,
scan_done_once, report_missing_devices))
if (!fn(fid, vg, n, vgn, pv_hash, lv_hash))
return_0;
}
@ -1004,7 +988,6 @@ static int _read_sections(struct format_instance *fid,
static struct volume_group *_read_vg(struct format_instance *fid,
const struct dm_config_tree *cft,
unsigned use_cached_pvs,
unsigned allow_lvmetad_extensions)
{
const struct dm_config_node *vgn;
@ -1012,7 +995,6 @@ static struct volume_group *_read_vg(struct format_instance *fid,
const char *str, *format_str, *system_id;
struct volume_group *vg;
struct dm_hash_table *pv_hash = NULL, *lv_hash = NULL;
unsigned scan_done_once = use_cached_pvs;
uint64_t vgstatus;
/* skip any top-level values */
@ -1167,7 +1149,7 @@ static struct volume_group *_read_vg(struct format_instance *fid,
}
if (!_read_sections(fid, "physical_volumes", _read_pv, vg,
vgn, pv_hash, lv_hash, 0, &scan_done_once)) {
vgn, pv_hash, lv_hash, 0)) {
log_error("Couldn't find all physical volumes for volume "
"group %s.", vg->name);
goto bad;
@ -1175,7 +1157,7 @@ static struct volume_group *_read_vg(struct format_instance *fid,
if (allow_lvmetad_extensions)
_read_sections(fid, "outdated_pvs", _read_pv, vg,
vgn, pv_hash, lv_hash, 1, &scan_done_once);
vgn, pv_hash, lv_hash, 1);
else if (dm_config_has_node(vgn, "outdated_pvs"))
log_error(INTERNAL_ERROR "Unexpected outdated_pvs section in metadata of VG %s.", vg->name);
@ -1187,28 +1169,28 @@ static struct volume_group *_read_vg(struct format_instance *fid,
}
if (!_read_sections(fid, "logical_volumes", _read_lvnames, vg,
vgn, pv_hash, lv_hash, 1, NULL)) {
vgn, pv_hash, lv_hash, 1)) {
log_error("Couldn't read all logical volume names for volume "
"group %s.", vg->name);
goto bad;
}
if (!_read_sections(fid, "historical_logical_volumes", _read_historical_lvnames, vg,
vgn, pv_hash, lv_hash, 1, NULL)) {
vgn, pv_hash, lv_hash, 1)) {
log_error("Couldn't read all historical logical volumes for volume "
"group %s.", vg->name);
goto bad;
}
if (!_read_sections(fid, "logical_volumes", _read_lvsegs, vg,
vgn, pv_hash, lv_hash, 1, NULL)) {
vgn, pv_hash, lv_hash, 1)) {
log_error("Couldn't read all logical volumes for "
"volume group %s.", vg->name);
goto bad;
}
if (!_read_sections(fid, "historical_logical_volumes", _read_historical_lvnames_interconnections,
vg, vgn, pv_hash, lv_hash, 1, NULL)) {
vg, vgn, pv_hash, lv_hash, 1)) {
log_error("Couldn't read all removed logical volume interconnections "
"for volume group %s.", vg->name);
goto bad;
@ -1310,6 +1292,12 @@ static int _read_vgsummary(const struct format_type *fmt, const struct dm_config
(!(vgsummary->lock_type = dm_pool_strdup(mem, str))))
return_0;
if (!_read_int32(vgn, "seqno", &vgsummary->seqno)) {
log_error("Couldn't read seqno for volume group %s.",
vgsummary->vgname);
return 0;
}
return 1;
}

View File

@ -17,7 +17,6 @@
#define _LVM_TEXT_LAYOUT_H
#include "config.h"
#include "format-text.h"
#include "metadata.h"
#include "lvmcache.h"
#include "uuid.h"
@ -81,9 +80,8 @@ struct mda_header {
struct raw_locn raw_locns[0]; /* NULL-terminated list */
} __attribute__ ((packed));
struct mda_header *raw_read_mda_header(struct dm_pool *mem, struct device_area *dev_area, int primary_mda);
int raw_read_mda_header_callback(struct dm_pool *mem, struct device_area *dev_area, int primary_mda,
unsigned ioflags, lvm_callback_fn_t mdah_callback_fn, void *mdah_callback_context);
struct mda_header *raw_read_mda_header(const struct format_type *fmt,
struct device_area *dev_area, int primary_mda);
struct mda_lists {
struct dm_list dirs;
@ -105,11 +103,9 @@ struct mda_context {
#define LVM2_LABEL "LVM2 001"
#define MDA_SIZE_MIN (8 * (unsigned) lvm_getpagesize())
#define MDA_ORIGINAL_ALIGNMENT 512 /* Original alignment used for start of VG metadata content */
#define MDA_ALIGNMENT 4096 /* Default alignment in bytes since 2.02.177 for start of VG metadata content. */
int vgname_from_mda(const struct format_type *fmt, const struct mda_header *mdah, int primary_mda,
int read_metadata_location_summary(const struct format_type *fmt, struct mda_header *mdah, int primary_mda,
struct device_area *dev_area, struct lvmcache_vgsummary *vgsummary,
uint64_t *mda_free_sectors, unsigned ioflags,
lvm_callback_fn_t update_vgsummary_callback_fn, void *update_vgsummary_callback_context);
uint64_t *mda_free_sectors);
#endif

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2018 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@ -19,7 +19,6 @@
#include "label.h"
#include "xlate.h"
#include "lvmcache.h"
#include "toolcontext.h"
#include <sys/stat.h>
#include <fcntl.h>
@ -36,14 +35,14 @@ static int _text_can_handle(struct labeller *l __attribute__((unused)),
return 0;
}
struct dl_setup_baton {
struct _dl_setup_baton {
struct disk_locn *pvh_dlocn_xl;
struct device *dev;
};
static int _da_setup(struct disk_locn *da, void *baton)
{
struct dl_setup_baton *p = baton;
struct _dl_setup_baton *p = baton;
p->pvh_dlocn_xl->offset = xlate64(da->offset);
p->pvh_dlocn_xl->size = xlate64(da->size);
p->pvh_dlocn_xl++;
@ -57,7 +56,7 @@ static int _ba_setup(struct disk_locn *ba, void *baton)
static int _mda_setup(struct metadata_area *mda, void *baton)
{
struct dl_setup_baton *p = baton;
struct _dl_setup_baton *p = baton;
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
if (mdac->area.dev != p->dev)
@ -72,7 +71,7 @@ static int _mda_setup(struct metadata_area *mda, void *baton)
static int _dl_null_termination(void *baton)
{
struct dl_setup_baton *p = baton;
struct _dl_setup_baton *p = baton;
p->pvh_dlocn_xl->offset = xlate64(UINT64_C(0));
p->pvh_dlocn_xl->size = xlate64(UINT64_C(0));
@ -87,7 +86,7 @@ static int _text_write(struct label *label, void *buf)
struct pv_header *pvhdr;
struct pv_header_extension *pvhdr_ext;
struct lvmcache_info *info;
struct dl_setup_baton baton;
struct _dl_setup_baton baton;
char buffer[64] __attribute__((aligned(8)));
int ba1, da1, mda1, mda2;
@ -319,62 +318,23 @@ static int _text_initialise_label(struct labeller *l __attribute__((unused)),
return 1;
}
struct update_mda_baton {
struct _update_mda_baton {
struct lvmcache_info *info;
struct label *label;
int nr_outstanding_mdas;
unsigned ioflags;
lvm_callback_fn_t read_label_callback_fn;
void *read_label_callback_context;
int ret;
};
struct process_mda_header_params {
struct update_mda_baton *umb;
struct metadata_area *mda;
struct device *dev;
struct lvmcache_vgsummary vgsummary;
int ret;
};
static void _process_vgsummary(int failed, unsigned ioflags, void *context, const void *data)
static int _read_mda_header_and_metadata(struct metadata_area *mda, void *baton)
{
struct process_mda_header_params *pmp = context;
const struct lvmcache_vgsummary *vgsummary = data;
--pmp->umb->nr_outstanding_mdas;
/* FIXME Need to distinguish genuine errors here */
if (failed)
goto_out;
if (!lvmcache_update_vgname_and_id(pmp->umb->info, vgsummary)) {
pmp->umb->ret = 0;
pmp->ret = 0;
}
out:
if (!pmp->umb->nr_outstanding_mdas && pmp->umb->ret)
lvmcache_make_valid(pmp->umb->info);
if (!dev_close(pmp->dev))
stack;
if (!pmp->umb->nr_outstanding_mdas && pmp->umb->read_label_callback_fn)
pmp->umb->read_label_callback_fn(!pmp->umb->ret, ioflags, pmp->umb->read_label_callback_context, pmp->umb->label);
}
static void _process_mda_header(int failed, unsigned ioflags, void *context, const void *data)
{
struct process_mda_header_params *pmp = context;
const struct mda_header *mdah = data;
struct update_mda_baton *umb = pmp->umb;
const struct format_type *fmt = umb->label->labeller->fmt;
struct metadata_area *mda = pmp->mda;
struct _update_mda_baton *p = baton;
const struct format_type *fmt = p->label->labeller->fmt;
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
struct mda_header *mdah;
struct lvmcache_vgsummary vgsummary = { 0 };
if (failed)
goto_bad;
if (!(mdah = raw_read_mda_header(fmt, &mdac->area, mda_is_primary(mda)))) {
log_error("Failed to read mda header from %s", dev_name(mdac->area.dev));
goto fail;
}
mda_set_ignored(mda, rlocn_is_ignored(mdah->raw_locns));
@ -382,102 +342,53 @@ static void _process_mda_header(int failed, unsigned ioflags, void *context, con
log_debug_metadata("Ignoring mda on device %s at offset " FMTu64,
dev_name(mdac->area.dev),
mdac->area.start);
goto bad;
return 1;
}
if (!vgname_from_mda(fmt, mdah, mda_is_primary(mda), &mdac->area, &pmp->vgsummary, &mdac->free_sectors, ioflags, _process_vgsummary, pmp)) {
/* FIXME Separate fatal and non-fatal error cases? */
goto_bad;
if (!read_metadata_location_summary(fmt, mdah, mda_is_primary(mda), &mdac->area,
&vgsummary, &mdac->free_sectors)) {
if (vgsummary.zero_offset)
return 1;
log_error("Failed to read metadata summary from %s", dev_name(mdac->area.dev));
goto fail;
}
return;
bad:
_process_vgsummary(1, ioflags, pmp, NULL);
return;
}
static int _count_mda(struct metadata_area *mda, void *baton)
{
struct update_mda_baton *umb = baton;
umb->nr_outstanding_mdas++;
if (!lvmcache_update_vgname_and_id(p->info, &vgsummary)) {
log_error("Failed to save lvm summary for %s", dev_name(mdac->area.dev));
goto fail;
}
return 1;
fail:
lvmcache_del(p->info);
return 0;
}
static int _update_mda(struct metadata_area *mda, void *baton)
static int _text_read(struct labeller *l, struct device *dev, void *label_buf,
struct label **label)
{
struct process_mda_header_params *pmp;
struct update_mda_baton *umb = baton;
const struct format_type *fmt = umb->label->labeller->fmt;
struct dm_pool *mem = umb->label->labeller->fmt->cmd->mem;
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
unsigned ioflags = umb->ioflags;
if (!(pmp = dm_pool_zalloc(mem, sizeof(*pmp)))) {
log_error("struct process_mda_header_params allocation failed");
return 0;
}
/*
* Using the labeller struct to preserve info about
* the last parsed vgname, vgid, creation host
*
* TODO: make lvmcache smarter and move this cache logic there
*/
pmp->dev = mdac->area.dev;
pmp->umb = umb;
pmp->mda = mda;
if (!dev_open_readonly(mdac->area.dev)) {
mda_set_ignored(mda, 1);
stack;
if (!--umb->nr_outstanding_mdas && umb->read_label_callback_fn)
umb->read_label_callback_fn(!umb->ret, ioflags, umb->read_label_callback_context, umb->label);
return 1;
}
pmp->ret = 1;
if (!raw_read_mda_header_callback(fmt->cmd->mem, &mdac->area, mda_is_primary(mda), ioflags, _process_mda_header, pmp)) {
_process_vgsummary(1, ioflags, pmp, NULL);
stack;
return 1;
}
if (umb->read_label_callback_fn)
return 1;
else
return pmp->ret;
}
static int _text_read(struct labeller *l, struct device *dev, void *buf, unsigned ioflags,
lvm_callback_fn_t read_label_callback_fn, void *read_label_callback_context)
{
struct label_header *lh = (struct label_header *) buf;
struct label_header *lh = (struct label_header *) label_buf;
struct pv_header *pvhdr;
struct pv_header_extension *pvhdr_ext;
struct lvmcache_info *info;
struct disk_locn *dlocn_xl;
uint64_t offset;
uint32_t ext_version;
struct dm_pool *mem = l->fmt->cmd->mem;
struct update_mda_baton *umb;
struct label *label;
struct _update_mda_baton baton;
/*
* PV header base
*/
pvhdr = (struct pv_header *) ((char *) buf + xlate32(lh->offset_xl));
pvhdr = (struct pv_header *) ((char *) label_buf + xlate32(lh->offset_xl));
if (!(info = lvmcache_add(l, (char *)pvhdr->pv_uuid, dev,
FMT_TEXT_ORPHAN_VG_NAME,
FMT_TEXT_ORPHAN_VG_NAME, 0)))
goto_bad;
return_0;
label = lvmcache_get_label(info);
*label = lvmcache_get_label(info);
lvmcache_set_device_size(info, xlate64(pvhdr->device_size_xl));
@ -523,41 +434,23 @@ static int _text_read(struct labeller *l, struct device *dev, void *buf, unsigne
lvmcache_add_ba(info, offset, xlate64(dlocn_xl->size));
dlocn_xl++;
}
out:
if (!(umb = dm_pool_zalloc(mem, sizeof(*umb)))) {
log_error("baton allocation failed");
goto_bad;
baton.info = info;
baton.label = *label;
/*
* In the vg_read phase, we compare all mdas and decide which to use
* which are bad and need repair.
*
* FIXME: this quits if the first mda is bad, but we need something
* smarter to be able to use the second mda if it's good.
*/
if (!lvmcache_foreach_mda(info, _read_mda_header_and_metadata, &baton)) {
log_error("Failed to scan VG from %s", dev_name(dev));
return 0;
}
umb->info = info;
umb->label = label;
umb->ioflags = ioflags;
umb->read_label_callback_fn = read_label_callback_fn;
umb->read_label_callback_context = read_label_callback_context;
umb->ret = 1;
if (!lvmcache_foreach_mda(info, _count_mda, umb))
goto_bad;
if (!umb->nr_outstanding_mdas) {
lvmcache_make_valid(info);
if (read_label_callback_fn)
read_label_callback_fn(0, ioflags, read_label_callback_context, label);
return 1;
}
if (!lvmcache_foreach_mda(info, _update_mda, umb))
goto_bad;
return 1;
bad:
if (read_label_callback_fn)
read_label_callback_fn(1, ioflags, read_label_callback_context, NULL);
return 0;
}
static void _text_destroy_label(struct labeller *l __attribute__((unused)),

File diff suppressed because it is too large Load Diff

View File

@ -18,6 +18,8 @@
#include "uuid.h"
#include "device.h"
#include "bcache.h"
#include "toolcontext.h"
#define LABEL_ID "LABELONE"
#define LABEL_SIZE SECTOR_SIZE /* Think very carefully before changing this */
@ -62,8 +64,8 @@ struct label_ops {
/*
* Read a label from a volume.
*/
int (*read) (struct labeller *l, struct device *dev, void *buf,
unsigned ioflags, lvm_callback_fn_t label_read_callback_fn, void *label_read_callback_context);
int (*read) (struct labeller * l, struct device * dev,
void *label_buf, struct label ** label);
/*
* Populate label_type etc.
@ -94,12 +96,31 @@ int label_register_handler(struct labeller *handler);
struct labeller *label_get_handler(const char *name);
int label_remove(struct device *dev);
int label_read(struct device *dev, struct label **result,
uint64_t scan_sector);
int label_read_callback(struct device *dev, uint64_t scan_sector,
unsigned ioflags, lvm_callback_fn_t process_label_data_fn, void *process_label_data_context);
int label_write(struct device *dev, struct label *label);
struct label *label_create(struct labeller *labeller);
void label_destroy(struct label *label);
extern struct bcache *scan_bcache;
int label_scan(struct cmd_context *cmd);
int label_scan_devs(struct cmd_context *cmd, struct dm_list *devs);
int label_scan_devs_excl(struct dm_list *devs);
void label_scan_invalidate(struct device *dev);
void label_scan_invalidate_lv(struct cmd_context *cmd, struct logical_volume *lv);
void label_scan_drop(struct cmd_context *cmd);
void label_scan_destroy(struct cmd_context *cmd);
int label_read(struct device *dev, struct label **labelp, uint64_t unused_sector);
int label_read_sector(struct device *dev, struct label **labelp, uint64_t scan_sector);
void label_scan_confirm(struct device *dev);
int label_scan_setup_bcache(void);
int label_scan_open(struct device *dev);
/*
* Wrappers around bcache equivalents.
* (these make it easier to disable bcache and revert to direct rw if needed)
*/
bool dev_read_bytes(struct device *dev, off_t start, size_t len, void *data);
bool dev_write_bytes(struct device *dev, off_t start, size_t len, void *data);
bool dev_write_zeros(struct device *dev, off_t start, size_t len);
#endif

View File

@ -3805,7 +3805,7 @@ int lv_add_mirror_lvs(struct logical_volume *lv,
return_0;
if (region_size && region_size != seg->region_size) {
log_error("Conflicting region_size.");
log_error("Conflicting region_size %u != %u.", region_size, seg->region_size);
return 0;
}

View File

@ -377,6 +377,19 @@ struct pv_segment {
*/
#define FMT_INSTANCE_PRIVATE_MDAS 0x00000008U
/*
* Each VG has its own fid struct. The fid for a VG describes where
* the metadata for that VG can be found. The lists hold mda locations.
*
* label scan finds the metadata locations (devs and offsets) for a VG,
* and saves this info in lvmcache vginfo/info lists.
*
* vg_read() then creates an fid for a given VG, and the mda locations
* from lvmcache are copied onto the fid lists. Those mda locations
* are read again by vg_read() to get VG metadata that is used to
* create the 'vg' struct.
*/
struct format_instance {
unsigned ref_count; /* Refs to this fid from VG and PV structs */
struct dm_pool *mem;

View File

@ -241,6 +241,7 @@ static int _pvcreate_check(struct cmd_context *cmd, const char *name,
name);
goto out;
}
dev_close(dev);
if (!wipe_known_signatures(cmd, dev, name,
TYPE_LVM1_MEMBER | TYPE_LVM2_MEMBER,
@ -272,7 +273,6 @@ out:
}
if (scan_needed) {
lvmcache_force_next_label_scan();
if (!lvmcache_label_scan(cmd)) {
stack;
r = 0;
@ -314,7 +314,7 @@ struct physical_volume *pvcreate_vol(struct cmd_context *cmd, const char *pv_nam
}
if (pp->pva.idp) {
if ((dev = lvmcache_device_from_pvid(cmd, pp->pva.idp, NULL, NULL)) &&
if ((dev = lvmcache_device_from_pvid(cmd, pp->pva.idp, NULL)) &&
(dev != dev_cache_get(pv_name, cmd->full_filter))) {
if (!id_write_format((const struct id*)&pp->pva.idp->uuid,
buffer, sizeof(buffer)))
@ -491,6 +491,7 @@ static int _pvremove_check(struct cmd_context *cmd, const char *name,
{
static const char really_wipe_msg[] = "Really WIPE LABELS from physical volume";
struct device *dev;
struct label *label;
struct pv_list *pvl;
struct physical_volume *pv = NULL;
int used;
@ -505,7 +506,7 @@ static int _pvremove_check(struct cmd_context *cmd, const char *name,
/* Is there a pv here already? */
/* If not, this is an error unless you used -f. */
if (!label_read(dev, NULL, 0)) {
if (!label_read(dev, &label, 0)) {
if (force_count)
return 1;
log_error("No PV label found on %s.", name);

View File

@ -38,10 +38,9 @@
#include <sys/param.h>
static struct physical_volume *_pv_read(struct cmd_context *cmd,
struct dm_pool *pvmem,
const char *pv_name,
struct format_instance *fid,
uint32_t warn_flags, int scan_label_only);
const struct format_type *fmt,
struct volume_group *vg,
struct lvmcache_info *info);
static int _alignment_overrides_default(unsigned long data_alignment,
unsigned long default_pe_align)
@ -330,37 +329,6 @@ bad:
return NULL;
}
int get_pv_from_vg_by_id(const struct format_type *fmt, const char *vg_name,
const char *vgid, const char *pvid,
struct physical_volume *pv)
{
struct volume_group *vg;
struct pv_list *pvl;
uint32_t warn_flags = WARN_PV_READ | WARN_INCONSISTENT;
int r = 0, consistent = 0;
if (!(vg = vg_read_internal(fmt->cmd, vg_name, vgid, warn_flags, &consistent))) {
log_error("get_pv_from_vg_by_id: vg_read_internal failed to read VG %s",
vg_name);
return 0;
}
dm_list_iterate_items(pvl, &vg->pvs) {
if (id_equal(&pvl->pv->id, (const struct id *) pvid)) {
if (!_copy_pv(fmt->cmd->mem, pv, pvl->pv)) {
log_error("internal PV duplication failed");
r = 0;
goto out;
}
r = 1;
goto out;
}
}
out:
release_vg(vg);
return r;
}
static int _move_pv(struct volume_group *vg_from, struct volume_group *vg_to,
const char *pv_name, int enforce_pv_from_source)
{
@ -719,7 +687,12 @@ int check_pv_dev_sizes(struct volume_group *vg)
* source file. All the following and more are only used by liblvm:
*
* . get_pvs()
* . get_vgids()
* . get_vgnames()
* . lvmcache_get_vgids()
* . lvmcache_get_vgnames()
* . the vg->pvs_to_write list and pv_to_write struct
* . _pvcreate_write()
*/
int vg_extend_each_pv(struct volume_group *vg, struct pvcreate_params *pp)
@ -1442,28 +1415,24 @@ static int _pvcreate_write(struct cmd_context *cmd, struct pv_to_write *pvw)
struct device *dev = pv->dev;
const char *pv_name = dev_name(dev);
if (!label_scan_open(dev)) {
log_error("%s not opened: device not written", pv_name);
return 0;
}
if (pvw->new_pv) {
/* Wipe existing label first */
if (!label_remove(pv_dev(pv))) {
if (!label_remove(dev)) {
log_error("Failed to wipe existing label on %s", pv_name);
return 0;
}
if (pvw->pp->zero) {
log_verbose("Zeroing start of device %s", pv_name);
if (!dev_open_quiet(dev)) {
log_error("%s not opened: device not zeroed", pv_name);
return 0;
}
if (!dev_set(dev, UINT64_C(0), (size_t) 2048, DEV_IO_LABEL, 0)) {
if (!dev_write_zeros(dev, 0, 2048)) {
log_error("%s not wiped: aborting", pv_name);
if (!dev_close(dev))
stack;
return 0;
}
if (!dev_close(dev))
stack;
}
}
@ -3242,9 +3211,7 @@ static int _check_mda_in_use(struct metadata_area *mda, void *_in_use)
struct _vg_read_orphan_baton {
struct cmd_context *cmd;
struct volume_group *vg;
uint32_t warn_flags;
int consistent;
int repair;
const struct format_type *fmt;
};
/*
@ -3341,8 +3308,7 @@ static int _vg_read_orphan_pv(struct lvmcache_info *info, void *baton)
uint32_t ext_version;
uint32_t ext_flags;
if (!(pv = _pv_read(b->vg->cmd, b->vg->vgmem, dev_name(lvmcache_device(info)),
b->vg->fid, b->warn_flags, 0))) {
if (!(pv = _pv_read(b->cmd, b->fmt, b->vg, info))) {
stack;
return 1;
}
@ -3426,8 +3392,6 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd,
struct pv_list head;
dm_list_init(&head.list);
lvmcache_label_scan(cmd);
lvmcache_seed_infos_from_lvmetad(cmd);
if (!(vginfo = lvmcache_vginfo_from_vgname(orphan_vgname, NULL)))
return_NULL;
@ -3449,10 +3413,22 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd,
vg->free_count = 0;
baton.cmd = cmd;
baton.warn_flags = warn_flags;
baton.fmt = fmt;
baton.vg = vg;
baton.consistent = 1;
baton.repair = *consistent;
/*
* vg_read for a normal VG will rescan labels for all the devices
* in the VG, in case something changed on disk between the initial
* label scan and acquiring the VG lock. We don't rescan labels
* here because this is only called in two ways:
*
* 1. for reporting, in which case it doesn't matter if something
* changed between the label scan and printing the PVs here
*
* 2. pvcreate_each_device() for pvcreate//vgcreate/vgextend,
* which already does the label rescan after taking the
* orphan lock.
*/
while ((pvl = (struct pv_list *) dm_list_first(&head.list))) {
dm_list_del(&pvl->list);
@ -3464,7 +3440,6 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd,
if (!lvmcache_foreach_pv(vginfo, _vg_read_orphan_pv, &baton))
return_NULL;
*consistent = baton.consistent;
return vg;
}
@ -3786,8 +3761,8 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
struct pv_list *pvl;
struct dm_list all_pvs;
char uuid[64] __attribute__((aligned(8)));
int skipped_rescan = 0;
unsigned seqno = 0;
int reappeared = 0;
struct cached_vg_fmtdata *vg_fmtdata = NULL; /* Additional format-specific data about the vg */
unsigned use_previous_vg;
@ -3808,7 +3783,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
}
if (lvmetad_used() && !use_precommitted) {
if ((correct_vg = lvmcache_get_vg(cmd, vgname, vgid, precommitted))) {
if ((correct_vg = lvmetad_vg_lookup(cmd, vgname, vgid))) {
dm_list_iterate_items(pvl, &correct_vg->pvs)
reappeared += _check_reappeared_pv(correct_vg, pvl->pv, *consistent);
if (reappeared && *consistent)
@ -3833,42 +3808,73 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
release_vg(correct_vg);
return_NULL;
}
/*
* When a command reads the vg from lvmetad, and then
* writes the vg, the write path does some disk reads
* of the devs.
* FIXME: when a command is going to write the vg,
* we should just read the vg from disk entirely
* and skip reading it from lvmetad.
*/
dm_list_iterate_items(pvl, &correct_vg->pvs)
label_scan_open(pvl->pv->dev);
}
return correct_vg;
}
/*
* If cached metadata was inconsistent and *consistent is set
* then repair it now. Otherwise just return it.
* Also return if use_precommitted is set due to the FIXME in
* the missing PV logic below.
* Rescan the devices that are associated with this vg in lvmcache.
* This repeats what was done by the command's initial label scan,
* but only the devices associated with this VG.
*
* The lvmcache info about these devs is from the initial label scan
* performed by the command before the vg lock was held. Now the VG
* lock is held, so we rescan all the info from the devs in case
* something changed between the initial scan and now that the lock
* is held.
*
* Some commands (e.g. reporting) are fine reporting data read by
* the label scan. It doesn't matter if the devs changed between
* the label scan and here, we can report what was seen in the
* scan, even though it is the old state, since we will not be
* making any modifications. If the VG was being modified during
* the scan, and caused us to see inconsistent metadata on the
* different PVs in the VG, then we do want to rescan the devs
* here to get a consistent view of the VG. Note that we don't
* know if the scan found all the PVs in the VG at this point.
* We don't know that until vg_read looks at the list of PVs in
* the metadata and compares that to the devices found by the scan.
*
* It's possible that a change made to the VG during scan was
* adding or removing a PV from the VG. In this case, the list
* of devices associated with the VG in lvmcache would change
* due to the rescan.
*
* The devs in the VG may be persistently inconsistent due to some
* previous problem. In this case, rescanning the labels here will
* find the same inconsistency. The VG repair (mistakenly done by
* vg_read below) is supposed to fix that.
*
* FIXME: sort out the usage of the global lock (which is mixed up
* with the orphan lock), and when we can tell that the global
* lock is taken prior to the label scan, and still held here,
* we can also skip the rescan in that case.
*/
if ((correct_vg = lvmcache_get_vg(cmd, vgname, vgid, precommitted)) &&
(use_precommitted || !*consistent)) {
*consistent = 1;
return correct_vg;
if (!cmd->can_use_one_scan || lvmcache_scan_mismatch(cmd, vgname, vgid)) {
skipped_rescan = 0;
log_debug_metadata("Rescanning devices for for %s", vgname);
lvmcache_label_rescan_vg(cmd, vgname, vgid);
} else {
if (correct_vg && correct_vg->seqno > seqno)
seqno = correct_vg->seqno;
release_vg(correct_vg);
correct_vg = NULL;
log_debug_metadata("Skipped rescanning devices for %s", vgname);
skipped_rescan = 1;
}
/* Find the vgname in the cache */
/* If it's not there we must do full scan to be completely sure */
if (!(fmt = lvmcache_fmt_from_vgname(cmd, vgname, vgid, 1))) {
lvmcache_label_scan(cmd);
if (!(fmt = lvmcache_fmt_from_vgname(cmd, vgname, vgid, 1))) {
/* Independent MDAs aren't supported under low memory */
if (!cmd->independent_metadata_areas && prioritized_section())
return_NULL;
lvmcache_force_next_label_scan();
lvmcache_label_scan(cmd);
if (!(fmt = lvmcache_fmt_from_vgname(cmd, vgname, vgid, 0)))
return_NULL;
}
if (!(fmt = lvmcache_fmt_from_vgname(cmd, vgname, vgid, 0))) {
log_debug_metadata("Cache did not find fmt for vgname %s", vgname);
return_NULL;
}
/* Now determine the correct vgname if none was supplied */
@ -3886,6 +3892,36 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
if (use_precommitted && !(fmt->features & FMT_PRECOMMIT))
use_precommitted = 0;
/*
* A "format instance" is an abstraction for a VG location,
* i.e. where a VG's metadata exists on disk.
*
* An fic (format_instance_ctx) is a temporary struct used
* to create an fid (format_instance). The fid hangs around
* and is used to create a 'vg' to which it connected (vg->fid).
*
* The 'fic' describes a VG in terms of fmt/name/id.
*
* The 'fid' describes a VG in more detail than the fic,
* holding information about where to find the VG metadata.
*
* The 'vg' describes the VG in the most detail representing
* all the VG metadata.
*
* The fic and fid are set up by create_instance() to describe
* the VG location. This happens before the VG metadata is
* assembled into the more familiar struct volume_group "vg".
*
* The fid has one main purpose: to keep track of the metadata
* locations for a given VG. It does this by putting 'mda'
* structs on fid->metadata_areas_in_use, which specify where
* metadata is located on disk. It gets this information
* (metadata locations for a specific VG) from the command's
* initial label scan. The info is passed indirectly via
* lvmcache info/vginfo structs, which are created by the
* label scan and then copied into fid by create_instance().
*/
/* create format instance with appropriate metadata area */
fic.type = FMT_INSTANCE_MDAS | FMT_INSTANCE_AUX_MDAS;
fic.context.vg_ref.vg_name = vgname;
@ -3909,12 +3945,16 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
/* Ensure contents of all metadata areas match - else do recovery */
inconsistent_mda_count=0;
dm_list_iterate_items(mda, &fid->metadata_areas_in_use) {
struct device *mda_dev = mda_get_device(mda);
use_previous_vg = 0;
log_debug_metadata("Reading VG %s from %s", vgname, dev_name(mda_dev));
if ((use_precommitted &&
!(vg = mda->ops->vg_read_precommit(fid, vgname, mda, &vg_fmtdata, &use_previous_vg, 0)) && !use_previous_vg) ||
!(vg = mda->ops->vg_read_precommit(fid, vgname, mda, &vg_fmtdata, &use_previous_vg)) && !use_previous_vg) ||
(!use_precommitted &&
!(vg = mda->ops->vg_read(fid, vgname, mda, &vg_fmtdata, &use_previous_vg, 0, 0)) && !use_previous_vg)) {
!(vg = mda->ops->vg_read(fid, vgname, mda, &vg_fmtdata, &use_previous_vg)) && !use_previous_vg)) {
inconsistent = 1;
vg_fmtdata = NULL;
continue;
@ -3933,10 +3973,8 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
/* FIXME Also ensure contents same - checksum compare? */
if (correct_vg->seqno != vg->seqno) {
if (cmd->metadata_read_only)
log_very_verbose("Not repairing VG %s metadata seqno (%d != %d) "
"as global/metadata_read_only is set.",
vgname, vg->seqno, correct_vg->seqno);
if (cmd->metadata_read_only || skipped_rescan)
log_warn("Not repairing metadata for VG %s.", vgname);
else
inconsistent = 1;
@ -3997,7 +4035,29 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
return_NULL;
}
log_debug_metadata("Empty mda found for VG %s.", vgname);
log_debug_metadata("Empty mda found for VG %s on %s.",
vgname, dev_name(pvl->pv->dev));
#if 0
/*
* If we are going to do any repair we have to be using
* the latest metadata on disk, so we have to rescan devs
* if we skipped that at the start of the vg_read. We'll
* likely come back through here, but without having
* skipped_rescan.
*
* FIXME: in some cases we don't want to do this.
*/
if (skipped_rescan && cmd->can_use_one_scan) {
log_debug_metadata("Restarting read to rescan devs.");
cmd->can_use_one_scan = 0;
release_vg(correct_vg);
correct_vg = NULL;
lvmcache_del(info);
label_read(pvl->pv->dev, NULL, 0);
goto restart_scan;
}
#endif
if (inconsistent_mdas)
continue;
@ -4076,8 +4136,6 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
/* Independent MDAs aren't supported under low memory */
if (!cmd->independent_metadata_areas && prioritized_section())
return_NULL;
lvmcache_force_next_label_scan();
lvmcache_label_scan(cmd);
if (!(fmt = lvmcache_fmt_from_vgname(cmd, vgname, vgid, 0)))
return_NULL;
@ -4104,9 +4162,9 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
use_previous_vg = 0;
if ((use_precommitted &&
!(vg = mda->ops->vg_read_precommit(fid, vgname, mda, &vg_fmtdata, &use_previous_vg, 0)) && !use_previous_vg) ||
!(vg = mda->ops->vg_read_precommit(fid, vgname, mda, &vg_fmtdata, &use_previous_vg)) && !use_previous_vg) ||
(!use_precommitted &&
!(vg = mda->ops->vg_read(fid, vgname, mda, &vg_fmtdata, &use_previous_vg, 0, 0)) && !use_previous_vg)) {
!(vg = mda->ops->vg_read(fid, vgname, mda, &vg_fmtdata, &use_previous_vg)) && !use_previous_vg)) {
inconsistent = 1;
vg_fmtdata = NULL;
continue;
@ -4137,10 +4195,8 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
/* FIXME Also ensure contents same - checksums same? */
if (correct_vg->seqno != vg->seqno) {
/* Ignore inconsistent seqno if told to skip repair logic */
if (cmd->metadata_read_only)
log_very_verbose("Not repairing VG %s metadata seqno (%d != %d) "
"as global/metadata_read_only is set.",
vgname, vg->seqno, correct_vg->seqno);
if (cmd->metadata_read_only || skipped_rescan)
log_warn("Not repairing metadata for VG %s.", vgname);
else
inconsistent = 1;
@ -4220,6 +4276,13 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
return correct_vg;
}
if (skipped_rescan) {
log_warn("Not repairing metadata for VG %s.", vgname);
_free_pv_list(&all_pvs);
release_vg(correct_vg);
return_NULL;
}
/* Don't touch if vgids didn't match */
if (inconsistent_vgid) {
log_warn("WARNING: Inconsistent metadata UUIDs found for "
@ -4266,14 +4329,16 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
}
/* We have the VG now finally, check if PV ext info is in sync with VG metadata. */
if (!_check_or_repair_pv_ext(cmd, correct_vg, *consistent, &inconsistent_pvs)) {
if (!_check_or_repair_pv_ext(cmd, correct_vg,
skipped_rescan ? 0 : *consistent,
&inconsistent_pvs)) {
release_vg(correct_vg);
return_NULL;
}
*consistent = !inconsistent_pvs;
if (correct_vg && *consistent) {
if (correct_vg && *consistent && !skipped_rescan) {
if (update_old_pv_ext && !_vg_update_old_pv_ext_if_needed(correct_vg)) {
release_vg(correct_vg);
return_NULL;
@ -4499,21 +4564,10 @@ static struct volume_group *_vg_read_by_vgid(struct cmd_context *cmd,
unsigned precommitted)
{
const char *vgname;
struct dm_list *vgnames;
struct volume_group *vg;
struct dm_str_list *strl;
uint32_t warn_flags = WARN_PV_READ | WARN_INCONSISTENT;
int consistent = 0;
/* Is corresponding vgname already cached? */
if (lvmcache_vgid_is_cached(vgid)) {
if ((vg = _vg_read(cmd, NULL, vgid, warn_flags, &consistent, precommitted)) &&
id_equal(&vg->id, (const struct id *)vgid)) {
return vg;
}
release_vg(vg);
}
/*
* When using lvmlockd we should never reach this point.
* The VG is locked, then vg_read() is done, which gets
@ -4526,36 +4580,52 @@ static struct volume_group *_vg_read_by_vgid(struct cmd_context *cmd,
/* Mustn't scan if memory locked: ensure cache gets pre-populated! */
if (critical_section())
return_NULL;
log_debug_metadata("Reading VG by vgid in critical section pre %d vgid %.8s", precommitted, vgid);
/* FIXME Need a genuine read by ID here - don't vg_read_internal by name! */
/* FIXME Disabled vgrenames while active for now because we aren't
* allowed to do a full scan here any more. */
if (!(vgname = lvmcache_vgname_from_vgid(cmd->mem, vgid))) {
log_debug_metadata("Reading VG by vgid %.8s no VG name found, retrying.", vgid);
lvmcache_destroy(cmd, 0, 0);
label_scan_destroy(cmd);
lvmcache_label_scan(cmd);
}
// The slow way - full scan required to cope with vgrename
lvmcache_force_next_label_scan();
lvmcache_label_scan(cmd);
if (!(vgnames = get_vgnames(cmd, 0))) {
log_error("vg_read_by_vgid: get_vgnames failed");
if (!(vgname = lvmcache_vgname_from_vgid(cmd->mem, vgid))) {
log_debug_metadata("Reading VG by vgid %.8s no VG name found.", vgid);
return NULL;
}
dm_list_iterate_items(strl, vgnames) {
vgname = strl->str;
if (!vgname)
continue; // FIXME Unnecessary?
consistent = 0;
if ((vg = _vg_read(cmd, vgname, vgid, warn_flags, &consistent, precommitted)) &&
id_equal(&vg->id, (const struct id *)vgid)) {
if (!consistent) {
release_vg(vg);
return NULL;
}
return vg;
}
release_vg(vg);
consistent = 0;
label_scan_setup_bcache();
if (!(vg = _vg_read(cmd, vgname, vgid, warn_flags, &consistent, precommitted))) {
log_error("Rescan devices to look for missing VG.");
goto scan;
}
if (vg_missing_pv_count(vg)) {
log_error("Rescan devices to look for missing PVs.");
release_vg(vg);
goto scan;
}
label_scan_destroy(cmd); /* drop bcache to close devs, keep lvmcache */
return vg;
scan:
lvmcache_destroy(cmd, 0, 0);
label_scan_destroy(cmd);
lvmcache_label_scan(cmd);
if (!(vg = _vg_read(cmd, vgname, vgid, warn_flags, &consistent, precommitted)))
goto fail;
label_scan_destroy(cmd); /* drop bcache to close devs, keep lvmcache */
return vg;
fail:
label_scan_destroy(cmd); /* drop bache to close devs, keep lvmcache */
log_debug_metadata("Reading VG by vgid %.8s not found.", vgid);
return NULL;
}
@ -4571,7 +4641,7 @@ struct logical_volume *lv_from_lvid(struct cmd_context *cmd, const char *lvid_s,
log_very_verbose("Finding %svolume group for uuid %s", precommitted ? "precommitted " : "", lvid_s);
if (!(vg = _vg_read_by_vgid(cmd, (const char *)lvid->id[0].uuid, precommitted))) {
log_error("Volume group for uuid not found: %s", lvid_s);
log_error("Reading VG not found for LVID %s", lvid_s);
return NULL;
}
@ -4640,86 +4710,40 @@ const char *find_vgname_from_pvname(struct cmd_context *cmd,
return find_vgname_from_pvid(cmd, pvid);
}
/* FIXME Use label functions instead of PV functions */
static struct physical_volume *_pv_read(struct cmd_context *cmd,
struct dm_pool *pvmem,
const char *pv_name,
struct format_instance *fid,
uint32_t warn_flags, int scan_label_only)
const struct format_type *fmt,
struct volume_group *vg,
struct lvmcache_info *info)
{
struct physical_volume *pv;
struct label *label;
struct lvmcache_info *info;
struct device *dev;
const struct format_type *fmt;
int found;
struct device *dev = lvmcache_device(info);
if (!(dev = dev_cache_get(pv_name, cmd->filter)))
return_NULL;
if (lvmetad_used()) {
info = lvmcache_info_from_pvid(dev->pvid, dev, 0);
if (!info) {
if (!lvmetad_pv_lookup_by_dev(cmd, dev, &found))
return_NULL;
if (!found) {
if (warn_flags & WARN_PV_READ)
log_error("No physical volume found in lvmetad cache for %s",
pv_name);
return NULL;
}
if (!(info = lvmcache_info_from_pvid(dev->pvid, dev, 0))) {
if (warn_flags & WARN_PV_READ)
log_error("No cache info in lvmetad cache for %s.",
pv_name);
return NULL;
}
}
label = lvmcache_get_label(info);
} else {
if (!(label_read(dev, &label, UINT64_C(0)))) {
if (warn_flags & WARN_PV_READ)
log_error("No physical volume label read from %s",
pv_name);
return NULL;
}
info = (struct lvmcache_info *) label->info;
}
fmt = lvmcache_fmt(info);
pv = _alloc_pv(pvmem, dev);
if (!pv) {
log_error("pv allocation for '%s' failed", pv_name);
if (!(pv = _alloc_pv(vg->vgmem, NULL))) {
log_error("pv allocation failed");
return NULL;
}
pv->label_sector = label->sector;
/* FIXME Move more common code up here */
if (!(lvmcache_fmt(info)->ops->pv_read(lvmcache_fmt(info), pv_name, pv, scan_label_only))) {
log_error("Failed to read existing physical volume '%s'",
pv_name);
goto bad;
if (fmt->ops->pv_read) {
/* format1 and pool */
if (!(fmt->ops->pv_read(fmt, dev_name(dev), pv, 0))) {
log_error("Failed to read existing physical volume '%s'", dev_name(dev));
goto bad;
}
} else {
/* format text */
if (!lvmcache_populate_pv_fields(info, vg, pv))
goto_bad;
}
if (!pv->size)
goto bad;
if (!alloc_pv_segment_whole_pv(pvmem, pv))
if (!alloc_pv_segment_whole_pv(vg->vgmem, pv))
goto_bad;
if (fid)
lvmcache_fid_add_mdas(info, fid, (const char *) &pv->id, ID_LEN);
else {
lvmcache_fid_add_mdas(info, fmt->orphan_vg->fid, (const char *) &pv->id, ID_LEN);
pv_set_fid(pv, fmt->orphan_vg->fid);
}
lvmcache_fid_add_mdas(info, vg->fid, (const char *) &pv->id, ID_LEN);
pv_set_fid(pv, vg->fid);
return pv;
bad:
free_pv_fid(pv);
dm_pool_free(pvmem, pv);
dm_pool_free(vg->vgmem, pv);
return NULL;
}
@ -5621,7 +5645,6 @@ uint32_t vg_lock_newname(struct cmd_context *cmd, const char *vgname)
unlock_vg(cmd, NULL, vgname);
return FAILED_LOCKING;
}
lvmcache_force_next_label_scan();
lvmcache_label_scan(cmd);
if (!lvmcache_fmt_from_vgname(cmd, vgname, NULL, 0))
return SUCCESS; /* vgname not found after scanning */

View File

@ -48,6 +48,7 @@
*/
#define dm_round_up(n, sz) (dm_div_up((n), (sz)) * (sz))
/* Various flags */
/* See metadata-exported.h for the complete list. */
/* Note that the bits no longer necessarily correspond to LVM1 disk format */
@ -79,13 +80,12 @@ struct metadata_area_ops {
const char *vg_name,
struct metadata_area * mda,
struct cached_vg_fmtdata **vg_fmtdata,
unsigned *use_previous_vg,
int single_device, unsigned ioflags);
unsigned *use_previous_vg);
struct volume_group *(*vg_read_precommit) (struct format_instance * fi,
const char *vg_name,
struct metadata_area * mda,
struct cached_vg_fmtdata **vg_fmtdata,
unsigned *use_previous_vg, unsigned ioflags);
unsigned *use_previous_vg);
/*
* Write out complete VG metadata. You must ensure internal
* consistency before calling. eg. PEs can't refer to PVs not
@ -182,6 +182,11 @@ void mda_set_ignored(struct metadata_area *mda, unsigned mda_ignored);
unsigned mda_locns_match(struct metadata_area *mda1, struct metadata_area *mda2);
struct device *mda_get_device(struct metadata_area *mda);
/*
* fic is used to create an fid. It's used to pass fmt/vgname/vgid args
* to create_instance() which creates an fid for the specified vg.
*/
struct format_instance_ctx {
uint32_t type;
union {
@ -366,12 +371,6 @@ uint32_t vg_bad_status_bits(const struct volume_group *vg, uint64_t status);
int add_pv_to_vg(struct volume_group *vg, const char *pv_name,
struct physical_volume *pv, int new_pv);
/* Find a PV within a given VG */
int get_pv_from_vg_by_id(const struct format_type *fmt, const char *vg_name,
const char *vgid, const char *pvid,
struct physical_volume *pv);
struct logical_volume *find_lv_in_vg_by_lvid(struct volume_group *vg,
const union lvid *lvid);

View File

@ -97,11 +97,6 @@ void release_vg(struct volume_group *vg)
if (!vg || (vg->fid && vg == vg->fid->fmt->orphan_vg))
return;
/* Check if there are any vginfo holders */
if (vg->vginfo &&
!lvmcache_vginfo_holders_dec_and_test_for_zero(vg->vginfo))
return;
release_vg(vg->vg_committed);
release_vg(vg->vg_precommitted);
_free_vg(vg);

View File

@ -28,7 +28,6 @@ static int _md_filtering = 0;
static int _internal_filtering = 0;
static int _fwraid_filtering = 0;
static int _pvmove = 0;
static int _full_scan_done = 0; /* Restrict to one full scan during each cmd */
static int _obtain_device_list_from_udev = DEFAULT_OBTAIN_DEVICE_LIST_FROM_UDEV;
static enum dev_ext_e _external_device_info_source = DEV_EXT_NONE;
static int _trust_cache = 0; /* Don't scan when incomplete VGs encountered */
@ -53,8 +52,6 @@ static int _activation_checks = 0;
static char _sysfs_dir_path[PATH_MAX] = "";
static int _dev_disable_after_error_count = DEFAULT_DISABLE_AFTER_ERROR_COUNT;
static uint64_t _pv_min_size = (DEFAULT_PV_MIN_SIZE_KB * 1024L >> SECTOR_SHIFT);
static int _detect_internal_vg_cache_corruption =
DEFAULT_DETECT_INTERNAL_VG_CACHE_CORRUPTION;
static const char *_unknown_device_name = DEFAULT_UNKNOWN_DEVICE_NAME;
void init_verbose(int level)
@ -94,11 +91,6 @@ void init_pvmove(int level)
_pvmove = level;
}
void init_full_scan_done(int level)
{
_full_scan_done = level;
}
void init_obtain_device_list_from_udev(int device_list_from_udev)
{
_obtain_device_list_from_udev = device_list_from_udev;
@ -197,11 +189,6 @@ void init_pv_min_size(uint64_t sectors)
_pv_min_size = sectors;
}
void init_detect_internal_vg_cache_corruption(int detect)
{
_detect_internal_vg_cache_corruption = detect;
}
void set_cmd_name(const char *cmd)
{
(void) dm_strncpy(_cmd_name, cmd, sizeof(_cmd_name));
@ -260,11 +247,6 @@ int pvmove_mode(void)
return _pvmove;
}
int full_scan_done(void)
{
return _full_scan_done;
}
int obtain_device_list_from_udev(void)
{
return _obtain_device_list_from_udev;
@ -384,11 +366,6 @@ uint64_t pv_min_size(void)
return _pv_min_size;
}
int detect_internal_vg_cache_corruption(void)
{
return _detect_internal_vg_cache_corruption;
}
const char *unknown_device_name(void)
{
return _unknown_device_name;

View File

@ -29,7 +29,6 @@ void init_md_filtering(int level);
void init_internal_filtering(int level);
void init_fwraid_filtering(int level);
void init_pvmove(int level);
void init_full_scan_done(int level);
void init_external_device_info_source(enum dev_ext_e src);
void init_obtain_device_list_from_udev(int device_list_from_udev);
void init_trust_cache(int trustcache);
@ -51,7 +50,6 @@ void init_udev_checking(int checking);
void init_dev_disable_after_error_count(int value);
void init_pv_min_size(uint64_t sectors);
void init_activation_checks(int checks);
void init_detect_internal_vg_cache_corruption(int detect);
void init_retry_deactivation(int retry);
void init_unknown_device_name(const char *name);
@ -64,7 +62,6 @@ int md_filtering(void);
int internal_filtering(void);
int fwraid_filtering(void);
int pvmove_mode(void);
int full_scan_done(void);
int obtain_device_list_from_udev(void);
enum dev_ext_e external_device_info_source(void);
int trust_cache(void);
@ -85,7 +82,6 @@ int udev_checking(void);
const char *sysfs_dir_path(void);
uint64_t pv_min_size(void);
int activation_checks(void);
int detect_internal_vg_cache_corruption(void);
int retry_deactivation(void);
const char *unknown_device_name(void);

View File

@ -963,7 +963,7 @@ static const char *_find_config_str(const void *start, node_lookup_fn find_fn,
if (n && n->v) {
if ((n->v->type == DM_CFG_STRING) &&
(allow_empty || (*n->v->v.str))) {
log_very_verbose("Setting %s to %s", path, n->v->v.str);
/* log_very_verbose("Setting %s to %s", path, n->v->v.str); */
return n->v->v.str;
}
if ((n->v->type != DM_CFG_STRING) || (!allow_empty && fail))
@ -994,7 +994,7 @@ static int64_t _find_config_int64(const void *start, node_lookup_fn find,
const struct dm_config_node *n = find(start, path);
if (n && n->v && n->v->type == DM_CFG_INT) {
log_very_verbose("Setting %s to %" PRId64, path, n->v->v.i);
/* log_very_verbose("Setting %s to %" PRId64, path, n->v->v.i); */
return n->v->v.i;
}
@ -1009,7 +1009,7 @@ static float _find_config_float(const void *start, node_lookup_fn find,
const struct dm_config_node *n = find(start, path);
if (n && n->v && n->v->type == DM_CFG_FLOAT) {
log_very_verbose("Setting %s to %f", path, n->v->v.f);
/* log_very_verbose("Setting %s to %f", path, n->v->v.f); */
return n->v->v.f;
}
@ -1058,12 +1058,12 @@ static int _find_config_bool(const void *start, node_lookup_fn find,
switch (v->type) {
case DM_CFG_INT:
b = v->v.i ? 1 : 0;
log_very_verbose("Setting %s to %d", path, b);
/* log_very_verbose("Setting %s to %d", path, b); */
return b;
case DM_CFG_STRING:
b = _str_to_bool(v->v.str, fail);
log_very_verbose("Setting %s to %d", path, b);
/* log_very_verbose("Setting %s to %d", path, b); */
return b;
default:
;

View File

@ -43,7 +43,7 @@ LDDEPS += $(top_builddir)/lib/liblvm-internal.a
include $(top_builddir)/make.tmpl
LDFLAGS += -L$(top_builddir)/lib -L$(top_builddir)/daemons/dmeventd
LIBS += $(LVMINTERNAL_LIBS) -ldevmapper
LIBS += $(LVMINTERNAL_LIBS) -ldevmapper -laio
.PHONY: install_dynamic install_static install_include install_pkgconfig

View File

@ -219,6 +219,8 @@ static vg_t _lvm_vg_open(lvm_t libh, const char *vgname, const char *mode,
return NULL;
}
lvmcache_label_scan((struct cmd_context *)libh);
vg = vg_read((struct cmd_context *)libh, vgname, NULL, internal_flags, 0);
if (vg_read_error(vg)) {
/* FIXME: use log_errno either here in inside vg_read */
@ -512,7 +514,6 @@ int lvm_scan(lvm_t libh)
int rc = 0;
struct saved_env e = store_user_env((struct cmd_context *)libh);
lvmcache_force_next_label_scan();
if (!lvmcache_label_scan((struct cmd_context *)libh))
rc = -1;

View File

@ -13,6 +13,12 @@
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
ifeq ($(V),1)
Q=
else
Q=@
endif
SHELL = @SHELL@
@SET_MAKE@
@ -62,8 +68,7 @@ CLDFLAGS += @CLDFLAGS@
ELDFLAGS += @ELDFLAGS@
LDDEPS += @LDDEPS@
LIB_SUFFIX = @LIB_SUFFIX@
LVMINTERNAL_LIBS = -llvm-internal $(DMEVENT_LIBS) $(DAEMON_LIBS) $(SYSTEMD_LIBS) $(UDEV_LIBS) $(DL_LIBS) $(BLKID_LIBS) $(AIO_LIBS)
AIO_LIBS = @AIO_LIBS@
LVMINTERNAL_LIBS = -llvm-internal $(DMEVENT_LIBS) $(DAEMON_LIBS) $(SYSTEMD_LIBS) $(UDEV_LIBS) $(DL_LIBS) $(BLKID_LIBS)
DL_LIBS = @DL_LIBS@
RT_LIBS = @RT_LIBS@
M_LIBS = @M_LIBS@
@ -439,59 +444,70 @@ endif
.LIBPATTERNS = lib%.so lib%.a
%.o: %.c
$(CC) -c $(INCLUDES) $(VALGRIND_CFLAGS) $(PROGS_CFLAGS) $(DEFS) $(DEFS_$@) $(WFLAGS) $(WCFLAGS) $(CFLAGS) $(CFLAGS_$@) $< -o $@
@echo " [CC] $<"
$(Q) $(CC) -c $(INCLUDES) $(VALGRIND_CFLAGS) $(PROGS_CFLAGS) $(DEFS) $(DEFS_$@) $(WFLAGS) $(WCFLAGS) $(CFLAGS) $(CFLAGS_$@) $< -o $@
%.o: %.cpp
$(CXX) -c $(INCLUDES) $(VALGRIND_CFLAGS) $(DEFS) $(DEFS_$@) $(WFLAGS) $(CXXFLAGS) $(CXXFLAGS_$@) $< -o $@
@echo " [CXX] $<"
$(Q) $(CXX) -c $(INCLUDES) $(VALGRIND_CFLAGS) $(DEFS) $(DEFS_$@) $(WFLAGS) $(CXXFLAGS) $(CXXFLAGS_$@) $< -o $@
%.pot: %.c Makefile
$(CC) -E $(INCLUDES) $(VALGRIND_CFLAGS) $(PROGS_CFLAGS) -include $(top_builddir)/include/pogen.h $(DEFS) $(WFLAGS) $(CFLAGS) $< >$@
@echo " [CC] $@"
$(Q) $(CC) -E $(INCLUDES) $(VALGRIND_CFLAGS) $(PROGS_CFLAGS) -include $(top_builddir)/include/pogen.h $(DEFS) $(WFLAGS) $(CFLAGS) $< >$@
%.so: %.o
$(CC) -c $(CFLAGS) $(CLDFLAGS) $< $(LIBS) -o $@
@echo " [CC] $<"
$(Q) $(CC) -c $(CFLAGS) $(CLDFLAGS) $< $(LIBS) -o $@
ifneq (,$(LIB_SHARED))
TARGETS += $(LIB_SHARED).$(LIB_VERSION)
$(LIB_SHARED).$(LIB_VERSION): $(OBJECTS) $(LDDEPS)
@echo " [CC] $@"
ifeq ("@LIB_SUFFIX@","so")
$(CC) -shared -Wl,-soname,$(notdir $@) \
$(Q) $(CC) -shared -Wl,-soname,$(notdir $@) \
$(CFLAGS) $(CLDFLAGS) $(OBJECTS) $(LIBS) -o $@
endif
ifeq ("@LIB_SUFFIX@","dylib")
$(CC) -dynamiclib -dylib_current_version,$(LIB_VERSION) \
$(Q) $(CC) -dynamiclib -dylib_current_version,$(LIB_VERSION) \
$(CFLAGS) $(CLDFLAGS) $(OBJECTS) $(LIBS) -o $@
endif
$(LIB_SHARED): $(LIB_SHARED).$(LIB_VERSION)
$(LN_S) -f $(<F) $@
@echo " [LN] $<"
$(Q) $(LN_S) -f $(<F) $@
CLEAN_TARGETS += $(LDDEPS) .exported_symbols_generated
install_lib_shared: $(LIB_SHARED)
$(INSTALL_PROGRAM) -D $< $(libdir)/$(<F).$(LIB_VERSION)
$(INSTALL_DIR) $(usrlibdir)
$(LN_S) -f $(USRLIB_RELPATH)$(<F).$(LIB_VERSION) $(usrlibdir)/$(<F)
@echo " [INSTALL] $<"
$(Q) $(INSTALL_PROGRAM) -D $< $(libdir)/$(<F).$(LIB_VERSION)
$(Q) $(INSTALL_DIR) $(usrlibdir)
$(Q) $(LN_S) -f $(USRLIB_RELPATH)$(<F).$(LIB_VERSION) $(usrlibdir)/$(<F)
# FIXME: plugins are installed to subdirs
# and for compatibility links in libdir are created
# when the code is fixed links could be removed.
install_dm_plugin: $(LIB_SHARED)
$(INSTALL_PROGRAM) -D $< $(libdir)/device-mapper/$(<F)
$(LN_S) -f device-mapper/$(<F) $(libdir)/$(<F)
@echo " [INSTALL] $<"
$(Q) $(INSTALL_PROGRAM) -D $< $(libdir)/device-mapper/$(<F)
$(Q) $(LN_S) -f device-mapper/$(<F) $(libdir)/$(<F)
install_lvm2_plugin: $(LIB_SHARED)
$(INSTALL_PROGRAM) -D $< $(libdir)/lvm2/$(<F)
$(LN_S) -f lvm2/$(<F) $(libdir)/$(<F)
$(LN_S) -f $(<F) $(libdir)/$(<F).$(LIB_VERSION)
@echo " [INSTALL] $<"
$(Q) $(INSTALL_PROGRAM) -D $< $(libdir)/lvm2/$(<F)
$(Q) $(LN_S) -f lvm2/$(<F) $(libdir)/$(<F)
$(Q) $(LN_S) -f $(<F) $(libdir)/$(<F).$(LIB_VERSION)
endif
$(LIB_STATIC): $(OBJECTS)
$(RM) $@
$(AR) rsv $@ $(OBJECTS)
@echo " [AR] $@"
$(Q) $(RM) $@
$(Q) $(AR) rsv $@ $(OBJECTS) > /dev/null
%.d: %.c $(INC_LNS)
$(MKDIR_P) $(dir $@); \
@echo " [DEP] $<"
$(Q) $(MKDIR_P) $(dir $@); \
set -e; \
FILE=`echo $@ | sed 's/\\//\\\\\\//g;s/\\.d//g'`; \
DEPS=`echo $(DEPS) | sed -e 's/\\//\\\\\\//g'`; \
@ -502,7 +518,8 @@ $(LIB_STATIC): $(OBJECTS)
[ -s $@ ] || $(RM) $@
%.mo: %.po
$(MSGFMT) -o $@ $<
@echo " [MSGFMT] $<"
$(Q) $(MSGFMT) -o $@ $<
CLEAN_TARGETS += \
$(SOURCES:%.c=%.d) $(SOURCES:%.c=%.gcno) $(SOURCES:%.c=%.gcda) \
@ -524,7 +541,7 @@ endif
$(RM) $(DISTCLEAN_TARGETS) Makefile
.exported_symbols_generated: $(EXPORTED_HEADER) .exported_symbols $(DEPS)
set -e; \
$(Q) set -e; \
( cat $(srcdir)/.exported_symbols; \
if test -n "$(EXPORTED_HEADER)"; then \
$(CC) -E -P $(INCLUDES) $(DEFS) $(EXPORTED_HEADER) | \
@ -537,13 +554,13 @@ EXPORTED_SYMBOLS := $(wildcard $(srcdir)/.exported_symbols.Base $(srcdir)/.expor
.export.sym: .exported_symbols_generated $(EXPORTED_SYMBOLS)
ifeq (,$(firstword $(EXPORTED_SYMBOLS)))
set -e; (echo "Base {"; echo " global:";\
$(Q) set -e; (echo "Base {"; echo " global:";\
$(SED) "s/^/ /;s/$$/;/" $<;\
echo "};";\
echo "Local {"; echo " local:"; echo " *;"; echo "};";\
) > $@
else
set -e;\
$(Q) set -e;\
R=$$($(SORT) $^ | uniq -u);\
test -z "$$R" || { echo "Mismatch between symbols in shared library and lists in .exported_symbols.* files: $$R"; false; } ;\
( for i in $$(echo $(EXPORTED_SYMBOLS) | tr ' ' '\n' | $(SORT) -rnt_ -k5 ); do\

View File

@ -16,6 +16,12 @@ srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = @top_builddir@
ifeq ($(V),1)
Q=
else
Q=@
endif
FSADMMAN = fsadm.8
BLKDEACTIVATEMAN = blkdeactivate.8
DMEVENTDMAN = dmeventd.8
@ -46,20 +52,6 @@ MAN8DM=dmsetup.8 dmstats.8
MAN8CLUSTER=
MAN8SYSTEMD_GENERATORS=lvm2-activation-generator.8
ifeq ("$(origin V)", "command line")
BUILD_VERBOSE = $(V)
endif
ifndef BUILD_VERBOSE
BUILD_VERBOSE = 0
endif
ifeq ($(BUILD_VERBOSE),1)
Q =
else
Q = @
endif
ifeq ($(MAKECMDGOALS),all_man)
MAN_ALL="yes"
endif
@ -164,13 +156,6 @@ SEE_ALSO=$(srcdir)/see_also.end
.PRECIOUS: %.8_gen
%.8_gen: $(srcdir)/%.8_des $(srcdir)/%.8_end $(MANGENERATOR) $(TESTMAN)
$(Q)( \
if [ ! -s $(TESTMAN) ] ; then \
echo "Copying pre-generated template $@" ; \
else \
echo "Generating template $@" ; \
fi \
)
$(Q)set -e ; ( \
if [ ! -s $(TESTMAN) ] ; then \
cat $(srcdir)/$(@:%.8_gen=%.8_pregen) ; \
@ -184,7 +169,6 @@ SEE_ALSO=$(srcdir)/see_also.end
) > $@
define SUBSTVARS
$(Q)echo "Generating $@"
$(Q)$(SED) -e "s+#VERSION#+$(LVM_VERSION)+" \
-e "s+#DEFAULT_SYS_DIR#+$(DEFAULT_SYS_DIR)+" \
-e "s+#DEFAULT_ARCHIVE_DIR#+$(DEFAULT_ARCHIVE_DIR)+" \
@ -237,51 +221,62 @@ $(Q)$(SED) -i -e "s+\([ [:alpha:]]\)-\{7\}+\1\\\-\\\-\\\-\\\-\\\-\\\-\\\-+g" \
endef
%.5: $(srcdir)/%.5_main
$(SUBSTVARS)
$(ESCAPEHYPHENS)
@echo " [MAN] $@"
$(Q) $(SUBSTVARS)
$(Q) $(ESCAPEHYPHENS)
%.7: $(srcdir)/%.7_main
$(SUBSTVARS)
$(ESCAPEHYPHENS)
@echo " [MAN] $@"
$(Q) $(SUBSTVARS)
$(Q) $(ESCAPEHYPHENS)
%.8: $(srcdir)/%.8_main
$(SUBSTVARS)
$(ESCAPEHYPHENS)
@echo " [MAN] $@"
$(Q) $(SUBSTVARS)
$(Q) $(ESCAPEHYPHENS)
%.8: %.8_gen
$(SUBSTVARS)
$(ESCAPEHYPHENS)
@echo " [MAN] $@"
$(Q) $(SUBSTVARS)
$(Q) $(ESCAPEHYPHENS)
$(MAN8SO): lvmconfig.8
echo ".so $<" > $@
@echo " [MAN] $@"
$(Q) echo ".so $<" > $@
install_man5: $(MAN5)
$(INSTALL) -d $(MAN5DIR)
$(INSTALL_DATA) $(MAN5) $(MAN5DIR)/
@echo " [INSTALL] $<"
$(Q) $(INSTALL) -d $(MAN5DIR)
$(Q) $(INSTALL_DATA) $(MAN5) $(MAN5DIR)/
install_man7: $(MAN7)
$(INSTALL) -d $(MAN7DIR)
$(INSTALL_DATA) $(MAN7) $(MAN7DIR)/
@echo " [INSTALL] $<"
$(Q) $(INSTALL) -d $(MAN7DIR)
$(Q) $(INSTALL_DATA) $(MAN7) $(MAN7DIR)/
install_man8: $(MAN8) $(MAN8SO)
$(INSTALL) -d $(MAN8DIR)
$(INSTALL_DATA) $(MAN8) $(MAN8SO) $(MAN8DIR)/
@echo " [INSTALL] $<"
$(Q) $(INSTALL) -d $(MAN8DIR)
$(Q) $(INSTALL_DATA) $(MAN8) $(MAN8SO) $(MAN8DIR)/
install_lvm2: install_man5 install_man7 install_man8
install_cluster: $(MAN8CLUSTER)
ifdef MAN8CLUSTER
$(INSTALL) -d $(MAN8DIR)
$(INSTALL_DATA) $(MAN8CLUSTER) $(MAN8DIR)/
@echo " [INSTALL] $<"
$(Q) $(INSTALL) -d $(MAN8DIR)
$(Q) $(INSTALL_DATA) $(MAN8CLUSTER) $(MAN8DIR)/
endif
install_device-mapper: $(MAN8DM)
$(INSTALL) -d $(MAN8DIR)
$(INSTALL_DATA) $(MAN8DM) $(MAN8DIR)/
@echo " [INSTALL] $<"
$(Q) $(INSTALL) -d $(MAN8DIR)
$(Q) $(INSTALL_DATA) $(MAN8DM) $(MAN8DIR)/
install_systemd_generators: $(MAN8SYSTEMD_GENERATORS)
$(INSTALL) -d $(MAN8DIR)
$(INSTALL_DATA) $(MAN8SYSTEMD_GENERATORS) $(MAN8DIR)/
@echo " [INSTALL] $<"
$(Q) $(INSTALL) -d $(MAN8DIR)
$(Q) $(INSTALL_DATA) $(MAN8SYSTEMD_GENERATORS) $(MAN8DIR)/
install: install_lvm2 install_device-mapper install_cluster

View File

@ -1 +0,0 @@
!Makefile

View File

@ -1,5 +0,0 @@
config_t: config_t.c
gcc -g -I../../include config_t.c -L../../lib -llvm -o config_t
clean:
rm config_t

View File

@ -1,37 +0,0 @@
/*
* Test program that reads, then writes a config file.
*/
#include <stdio.h>
#include "config.h"
int main(int argc, char **argv)
{
struct config_file *cf;
if (argc != 2) {
fprintf(stderr, "Usage: %s <config_file>\n", argv[0]);
exit(1);
}
cf = create_config_file();
if (cf == NULL) {
fprintf(stderr, "Couldn't create config_file object.\n");
exit(1);
}
if (!read_config(cf, argv[1])) {
fprintf(stderr, "Couldn't read config file '%s'\n", argv[0]);
exit(1);
}
if (!write_config(cf, "out")) {
fprintf(stderr, "Couldn't write config file 'out'\n");
exit(1);
}
destroy_config_file(cf);
dump_memory();
return 0;
}

View File

@ -1 +0,0 @@
foo = []

View File

@ -1,169 +0,0 @@
# This file was originally generated by the LVM2 library
# Generated: Wed Jul 17 22:41:37 2002
description = "Created *after* executing 'lvcreate --quiet -s -n snap -c 512k -L200M vg0/origin /dev/hda8'"
creation_time = 1026942097
vg0 {
id = "Qmd96y-771S-Esbb-Zp6u-8xo9-Cfmt-YvndHY"
seqno = 2
status = ["RESIZEABLE", "READ", "WRITE"]
system_id = "reti1014805292"
extent_size = 8192 # 4 Megabytes
max_lv = 255
max_pv = 255
physical_volumes {
pv0 {
id = "8nRQub-EquY-VR1C-Ipdv-6hEO-FuFT-wnlN5R"
device = "/dev/discs/disc0/part8" # Hint only
status = ["ALLOCATABLE"]
pe_start = 256
pe_count = 501 # 1.95703 Gigabytes
}
pv1 {
id = "mRU6Mf-z1Sv-Kuqw-Ct1v-eC42-mnqs-YD1RrL"
device = "/dev/discs/disc1/part2" # Hint only
status = ["ALLOCATABLE"]
pe_start = 384
pe_count = 7269 # 28.3945 Gigabytes
}
}
logical_volumes {
music {
id = "000000-0000-0000-0000-0000-0000-000000"
status = ["READ", "WRITE", "ALLOC_SIMPLE"]
read_ahead = 0
segment_count = 2
segment1 {
start_extent = 0
extent_count = 1024 # 4 Gigabytes
stripes = 1
areas = [
"pv1", 0
]
}
segment2 {
start_extent = 1024
extent_count = 2560 # 10 Gigabytes
stripes = 1
areas = [
"pv1", 3584
]
}
}
photos {
id = "000000-0000-0000-0000-0000-0000-000002"
status = ["READ", "WRITE", "ALLOC_SIMPLE"]
read_ahead = 0
segment_count = 1
segment1 {
start_extent = 0
extent_count = 1024 # 4 Gigabytes
stripes = 1
areas = [
"pv1", 2048
]
}
}
repositories {
id = "000000-0000-0000-0000-0000-0000-000003"
status = ["READ", "WRITE", "ALLOC_SIMPLE"]
read_ahead = 0
segment_count = 1
segment1 {
start_extent = 0
extent_count = 512 # 2 Gigabytes
stripes = 1
areas = [
"pv1", 3072
]
}
}
origin {
id = "000000-0000-0000-0000-0000-0000-000004"
status = ["READ", "WRITE", "ALLOC_SIMPLE"]
read_ahead = 0
segment_count = 1
segment1 {
start_extent = 0
extent_count = 50 # 200 Megabytes
stripes = 1
areas = [
"pv1", 6144
]
}
}
packages {
id = "000000-0000-0000-0000-0000-0000-000006"
status = ["READ", "WRITE", "ALLOC_SIMPLE"]
read_ahead = 0
segment_count = 2
segment1 {
start_extent = 0
extent_count = 451 # 1.76172 Gigabytes
stripes = 1
areas = [
"pv0", 50
]
}
segment2 {
start_extent = 451
extent_count = 573 # 2.23828 Gigabytes
stripes = 1
areas = [
"pv1", 6194
]
}
}
snap {
id = "000000-0000-0000-0000-0000-0000-000001"
status = ["READ", "WRITE", "ALLOC_SIMPLE"]
read_ahead = 0
segment_count = 1
segment1 {
start_extent = 0
extent_count = 50 # 200 Megabytes
stripes = 1
areas = [
"pv0", 0
]
}
}
}
snapshots {
snapshot0 {
chunk_size = 1024
origin = "origin"
cow_store = "snap"
}
}
}

View File

@ -1,106 +0,0 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
static void _help(FILE *fp, const char *prog)
{
fprintf(fp, "Usage : %s <table size> <num_entries>\n", prog);
}
struct key_list {
struct key_list *next;
char key[1];
};
static struct key_list *_create_word(int n)
{
struct key_list *kl = dbg_malloc(sizeof(*kl) + 32);
snprintf(kl->key, 32, "abc%ddef%d", n, n);
kl->next = 0;
return kl;
}
static struct key_list *_create_word_from_file(int n)
{
char word[128], *ptr;
struct key_list *kl;
if (!fgets(word, sizeof(word), stdin))
return 0;
for (ptr = word; *ptr; ptr++) {
if (*ptr == '\n') {
*ptr = 0;
break;
}
}
kl = dbg_malloc(sizeof(*kl) + 32);
snprintf(kl->key, 32, "%s", word);
kl->next = 0;
return kl;
}
static void _do_test(int table_size, int num_entries)
{
int i;
hash_table_t ht = hash_create(table_size);
struct key_list *tmp, *key, *all = 0;
for (i = 0; i < num_entries; i++) {
/* make up a word */
if (!(key = _create_word_from_file(i))) {
log_error("Ran out of words !\n");
exit(1);
}
/* insert it */
hash_insert(ht, key->key, key);
key->next = all;
all = key;
}
for (key = all; key; key = key->next) {
tmp = (struct key_list *) hash_lookup(ht, key->key);
if (!tmp || (tmp != key)) {
log_error("lookup failed\n");
exit(1);
}
}
for (key = all; key; key = tmp) {
tmp = key->next;
dbg_free(key);
}
hash_destroy(ht);
}
int main(int argc, char **argv)
{
init_log();
if (argc != 3) {
_help(stderr, argv[0]);
exit(1);
}
_do_test(atoi(argv[1]), atoi(argv[2]));
dump_memory();
fin_log();
return 0;
}

View File

@ -1,54 +0,0 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "dev-cache.h"
#include "log.h"
#include <stdio.h>
int main(int argc, char **argv)
{
int i;
struct device *dev;
struct dev_iter *iter;
init_log();
if (!dev_cache_init()) {
log_error("couldn't initialise dev_cache_init failed\n");
exit(1);
}
for (i = 1; i < argc; i++) {
if (!dev_cache_add_dir(argv[i])) {
log_error("couldn't add '%s' to dev_cache\n");
exit(1);
}
}
if (!(iter = dev_iter_create(NULL))) {
log_error("couldn't create iterator\n");
exit(1);
}
while ((dev = dev_iter_next(iter)))
printf("%s\n", dev->name);
dev_iter_destroy(iter):
dev_cache_exit();
dump_memory();
fin_log();
return 0;
}

View File

@ -1,29 +0,0 @@
#
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004 Red Hat, Inc. All rights reserved.
#
# This file is part of LVM2.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = @top_builddir@
VPATH = @srcdir@
SOURCES=\
dev_cache_t.c
TARGETS=dev_cache_t
include $(top_builddir)/make.tmpl
dev_cache_t: dev_cache_t.o $(top_srcdir)/lib/liblvm.a
$(CC) -o dev_cache_t dev_cache_t.o -L$(top_builddir)/lib -llvm

View File

@ -1,70 +0,0 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "dev-cache.h"
#include "log.h"
#include <stdio.h>
int main(int argc, char **argv)
{
int i;
struct device *dev;
struct dev_iter *iter;
struct list_head *tmp;
struct dm_str_list *sl;
if (argc < 2) {
fprintf(stderr, "usage: %s <dir>\n", argv[0]);
exit(1);
}
init_log(stderr);
init_debug(_LOG_INFO);
if (!dev_cache_init()) {
log_err("couldn't initialise dev_cache_init failed");
exit(1);
}
for (i = 1; i < argc; i++) {
if (!dev_cache_add_dir(argv[i])) {
log_err("couldn't add '%s' to dev_cache", argv[i]);
exit(1);
}
}
if (!(iter = dev_iter_create(NULL))) {
log_err("couldn't create iterator");
exit(1);
}
while ((dev = dev_iter_get(iter))) {
printf("%s", dev->name);
list_for_each(tmp, &dev->aliases) {
sl = list_entry(tmp, struct dm_str_list, list);
printf(", %s", sl->str);
}
printf("\n");
}
dev_iter_destroy(iter);
dev_cache_exit();
dump_memory();
fin_log();
return 0;
}

View File

@ -1,27 +0,0 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "device.h"
#include "random.h"
#include <stdio.h>
int main(int argc, char **argv)
{
}

View File

@ -1,116 +0,0 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "random.h"
#include "log.h"
int32_t _a[56];
int32_t *_r;
static inline int32_t _mod_diff(int32_t x, int32_t y)
{
return (x - y) & 0x7fffffff;
}
static int32_t _flip_cycle(void)
{
int32_t *ii, *jj;
for (ii = _a + 1, jj = _a + 32; jj <= _a + 55; ii++, jj++)
*ii = _mod_diff(*ii, *jj);
for (jj = _a + 1; ii <= _a + 55; ii++, jj++)
*ii = _mod_diff(*ii, *jj);
_r = _a + 54;
return _a[55];
}
static void rand_init(int32_t seed)
{
int64_t i;
int64_t prev = seed, next = 1;
seed = prev = _mod_diff(prev, 0); /* strip the sign */
_a[55] = prev;
for (i = 21; i; i = (i + 21) % 55) {
_a[i] = next;
next = _mod_diff(prev, next);
if(seed & 1)
seed = 0x40000000L + (seed >> 1);
else
seed >>= 1;
next = _mod_diff(next, seed);
prev = _a[i];
}
_flip_cycle();
_flip_cycle();
_flip_cycle();
_flip_cycle();
_flip_cycle();
}
/*
* FIXME: move this to be an inline in the
* header.
*/
int32_t rand_get(void)
{
return (*_r >= 0) ? *_r-- : _flip_cycle();
}
/*
* just used by rand_check
*/
#define t31 0x80000000
static int32_t _uniform(int32_t m)
{
uint32_t t = t31 - (t31 % m);
int32_t r;
do
r = next_rand(sc);
while (t <= (uint32_t) r);
return r % m;
}
/*
* Checks I've copied the code correctly.
*/
int rand_check(void)
{
int j;
rand_init(-314159L);
if (next_rand(sc) != 119318998) {
log_err("Random number generator failed check 1");
return 0;
}
for(j = 1; j <= 133; j++)
rand_get();
if (_uniform(0x55555555L) != 748103812) {
log_err("Random number generator failed check 2");
return 0;
}
return 1;
}

View File

@ -1,32 +0,0 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* Random number generator snarfed from the
* Stanford Graphbase.
*/
#ifndef _LVM_RANDOM_H
#define _LVM_RANDOM_H
void rand_init(int32_t seed);
int32_t rand_get(void);
/*
* Note this will reset the seed.
*/
int rand_check(void);
#endif

View File

@ -1,35 +0,0 @@
#
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004 Red Hat, Inc. All rights reserved.
#
# This file is part of LVM2.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = @top_builddir@
VPATH = @srcdir@
SOURCES=\
rfilter_t.c \
pfilter_t.c
TARGETS=\
rfilter_t \
pfilter_t
include $(top_builddir)/make.tmpl
rfilter_t: rfilter_t.o $(top_srcdir)/lib/liblvm.a
$(CC) -o rfilter_t rfilter_t.o -L$(top_builddir)/lib -llvm
pfilter_t: pfilter_t.o $(top_srcdir)/lib/liblvm.a
$(CC) -o pfilter_t pfilter_t.o -L$(top_builddir)/lib -llvm

View File

@ -1,121 +0,0 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "filter-persistent.h"
#include "log.h"
#include "config.h"
#include "filter-regex.h"
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
int main(int argc, char **argv)
{
struct config_file *cft;
struct config_node *cn;
struct dev_filter *rfilter, *pfilter;
struct dev_iter *iter;
struct device *dev;
if (argc < 2) {
fprintf(stderr, "Usage : %s <regex config>\n",
argv[0]);
exit(1);
}
init_log(stderr);
init_debug(_LOG_DEBUG);
if (!dev_cache_init()) {
fprintf(stderr, "couldn't initialise dev_cache_init failed\n");
exit(1);
}
if (!dev_cache_add_dir("/dev")) {
fprintf(stderr, "couldn't add '/dev' to dev_cache\n");
exit(1);
}
if (!(cft = create_config_file())) {
fprintf(stderr, "couldn't create config file\n");
exit(1);
}
if (!read_config(cft, argv[1])) {
fprintf(stderr, "couldn't read config file\n");
exit(1);
}
if (!(cn = find_config_node(cft->root, "/devices/filter", '/'))) {
fprintf(stderr, "couldn't find filter section\n");
exit(1);
}
if (!(rfilter = regex_filter_create(cn->v))) {
fprintf(stderr, "couldn't build filter\n");
exit(1);
}
if (!(pfilter = persistent_filter_create(rfilter, "./pfilter.cfg"))) {
fprintf(stderr, "couldn't build filter\n");
exit(1);
}
if (!(iter = dev_iter_create(pfilter))) {
log_err("couldn't create iterator");
exit(1);
}
fprintf(stderr, "filling cache\n");
while ((dev = dev_iter_get(iter)))
;
dev_iter_destroy(iter);
fprintf(stderr, "dumping\n");
if (!persistent_filter_dump(pfilter)) {
fprintf(stderr, "couldn't dump pfilter\n");
exit(1);
}
fprintf(stderr, "loading\n");
if (!persistent_filter_load(pfilter)) {
fprintf(stderr, "couldn't load pfilter\n");
exit(1);
}
if (!(iter = dev_iter_create(pfilter))) {
log_err("couldn't create iterator");
exit(1);
}
while ((dev = dev_iter_get(iter)))
printf("%s\n", dev_name(dev));
dev_iter_destroy(iter);
pfilter->destroy(pfilter);
dev_cache_exit();
destroy_config_file(cft);
dump_memory();
fin_log();
return 0;
}

View File

@ -1,92 +0,0 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "filter-regex.h"
#include "config.h"
#include "log.h"
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
int main(int argc, char **argv)
{
struct config_file *cft;
struct config_node *cn;
struct dev_filter *filter;
struct dev_iter *iter;
struct device *dev;
if (argc < 2) {
fprintf(stderr, "Usage : %s <config_file>\n", argv[0]);
exit(1);
}
init_log(stderr);
init_debug(_LOG_DEBUG);
if (!(cft = create_config_file())) {
fprintf(stderr, "couldn't create config file\n");
exit(1);
}
if (!read_config(cft, argv[1])) {
fprintf(stderr, "couldn't read config file\n");
exit(1);
}
if (!(cn = find_config_node(cft->root, "/devices/filter", '/'))) {
fprintf(stderr, "couldn't find filter section\n");
exit(1);
}
if (!dev_cache_init()) {
fprintf(stderr, "couldn't initialise dev_cache_init failed\n");
exit(1);
}
if (!dev_cache_add_dir("/dev")) {
fprintf(stderr, "couldn't add '/dev' to dev_cache\n");
exit(1);
}
if (!(filter = regex_filter_create(cn->v))) {
fprintf(stderr, "couldn't build filter\n");
exit(1);
}
if (!(iter = dev_iter_create(filter))) {
log_err("couldn't create iterator");
exit(1);
}
while ((dev = dev_iter_get(iter)))
printf("%s\n", dev_name(dev));
dev_iter_destroy(iter);
filter->destroy(filter);
dev_cache_exit();
destroy_config_file(cft);
dump_memory();
fin_log();
return 0;
}

View File

@ -1,21 +0,0 @@
devices {
# first match is final, eg. /dev/ide/cdrom
# get's rejected due to the first pattern
filter=["r/cdrom/", # don't touch the music !
"a/hd[a-d][0-9]+/",
"a/ide/",
"a/sd/",
"a/md/",
"a|loop/[0-9]+|", # accept devfs style loop back
"r/loop/", # and reject old style
"a/dasd/",
"a/dac960/",
"a/nbd/",
"a/ida/",
"a/cciss/",
"a/ubd/",
"r/.*/"] # reject all others
}

View File

@ -1,52 +0,0 @@
#
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004 Red Hat, Inc. All rights reserved.
#
# This file is part of LVM2.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = @top_builddir@
VPATH = @srcdir@
SOURCES=\
read_vg_t.c \
write_vg_t.c \
pretty_print.c \
get_pvs_t.c \
read_pv_t.c \
get_vgs_t.c
TARGETS=\
read_vg_t \
write_vg_t \
get_pvs_t \
read_pv_t \
get_vgs_t
include $(top_builddir)/make.tmpl
read_vg_t: read_vg_t.o pretty_print.o $(top_builddir)/lib/liblvm.a
$(CC) -o read_vg_t read_vg_t.o pretty_print.o -L$(top_builddir)/lib -llvm
write_vg_t: write_vg_t.o pretty_print.o $(top_builddir)/lib/liblvm.a
$(CC) -o write_vg_t write_vg_t.o pretty_print.o \
-L$(top_builddir)/lib -llvm
get_pvs_t: get_pvs_t.o pretty_print.o $(top_builddir)/lib/liblvm.a
$(CC) -o get_pvs_t get_pvs_t.o pretty_print.o -L$(top_builddir)/lib -llvm
read_pv_t: read_pv_t.o pretty_print.o $(top_builddir)/lib/liblvm.a
$(CC) -o read_pv_t read_pv_t.o pretty_print.o -L$(top_builddir)/lib -llvm
get_vgs_t: get_vgs_t.o pretty_print.o $(top_builddir)/lib/liblvm.a
$(CC) -o get_vgs_t get_vgs_t.o pretty_print.o -L$(top_builddir)/lib -llvm

View File

@ -1,73 +0,0 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "log.h"
#include "format1.h"
#include "pretty_print.h"
#include "list.h"
#include <stdio.h>
int main(int argc, char **argv)
{
struct io_space *ios;
struct list_head *pvs, *tmp;
struct dm_pool *mem;
init_log(stderr);
init_debug(_LOG_INFO);
if (!dev_cache_init()) {
fprintf(stderr, "init of dev-cache failed\n");
exit(1);
}
if (!dev_cache_add_dir("/dev/loop")) {
fprintf(stderr, "couldn't add /dev to dir-cache\n");
exit(1);
}
if (!(mem = dm_pool_create(10 * 1024))) {
fprintf(stderr, "couldn't create pool\n");
exit(1);
}
ios = create_lvm1_format("/dev", mem, NULL);
if (!ios) {
fprintf(stderr, "failed to create io_space for format1\n");
exit(1);
}
pvs = ios->get_pvs(ios);
if (!pvs) {
fprintf(stderr, "couldn't read vg %s\n", argv[1]);
exit(1);
}
list_for_each(tmp, pvs) {
struct pv_list *pvl = list_entry(tmp, struct pv_list, list);
dump_pv(&pvl->pv, stdout);
}
ios->destroy(ios);
dm_pool_destroy(mem);
dev_cache_exit();
dump_memory();
fin_log();
return 0;
}

View File

@ -1,69 +0,0 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "log.h"
#include "format1.h"
#include "pretty_print.h"
#include "list.h"
#include <stdio.h>
int main(int argc, char **argv)
{
struct io_space *ios;
struct list_head *vgs;
struct dm_pool *mem;
init_log(stderr);
init_debug(_LOG_INFO);
if (!dev_cache_init()) {
fprintf(stderr, "init of dev-cache failed\n");
exit(1);
}
if (!dev_cache_add_dir("/dev/loop")) {
fprintf(stderr, "couldn't add /dev to dir-cache\n");
exit(1);
}
if (!(mem = dm_pool_create(10 * 1024))) {
fprintf(stderr, "couldn't create pool\n");
exit(1);
}
ios = create_lvm1_format("/dev", mem, NULL);
if (!ios) {
fprintf(stderr, "failed to create io_space for format1\n");
exit(1);
}
vgs = ios->get_vgs(ios);
if (!vgs) {
fprintf(stderr, "couldn't read vg names\n");
exit(1);
}
dump_vg_names(vgs, stdout);
ios->destroy(ios);
dm_pool_destroy(mem);
dev_cache_exit();
dump_memory();
fin_log();
return 0;
}

View File

@ -1,86 +0,0 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "pretty_print.h"
void dump_pv(struct physical_volume *pv, FILE *fp)
{
fprintf(fp, "physical_volume {\n");
fprintf(fp, "\tname = '%s'\n", pv->dev->name);
fprintf(fp, "\tvg_name = '%s'\n", pv->vg_name);
fprintf(fp, "\tsize = %llu\n", pv->size);
fprintf(fp, "\tpe_size = %llu\n", pv->pe_size);
fprintf(fp, "\tpe_start = %llu\n", pv->pe_start);
fprintf(fp, "\tpe_count = %u\n", pv->pe_count);
fprintf(fp, "\tpe_allocated = %u\n", pv->pe_allocated);
fprintf(fp, "}\n\n");
}
void dump_lv(struct logical_volume *lv, FILE *fp)
{
int i;
fprintf(fp, "logical_volume {\n");
fprintf(fp, "\tname = '%s'\n", lv->name);
fprintf(fp, "\tsize = %llu\n", lv->size);
fprintf(fp, "\tle_count = %u\n", lv->le_count);
fprintf(fp, "\tmap {\n");
for (i = 0; i < lv->le_count; i++) {
struct physical_volume *pv = lv->map[i].pv;
fprintf(fp, "\t\tpv = '%s', ",
pv ? pv->dev->name : "null ???");
fprintf(fp, "\textent = %u\n", lv->map[i].pe);
}
fprintf(fp, "\t}\n}\n\n");
}
void dump_vg(struct volume_group *vg, FILE *fp)
{
struct list_head *tmp;
fprintf(fp, "volume_group {\n");
fprintf(fp, "\tname = '%s'\n", vg->name);
fprintf(fp, "\textent_size = %llu\n", vg->extent_size);
fprintf(fp, "\textent_count = %d\n", vg->extent_count);
fprintf(fp, "\tfree_count = %d\n", vg->free_count);
fprintf(fp, "\tmax_lv = %d\n", vg->max_lv);
fprintf(fp, "\tmax_pv = %d\n", vg->max_pv);
fprintf(fp, "\tpv_count = %d\n", vg->pv_count);
fprintf(fp, "\tlv_count = %d\n", vg->lv_count);
fprintf(fp, "}\n\n");
list_for_each(tmp, &vg->pvs) {
struct pv_list *pvl = list_entry(tmp, struct pv_list, list);
dump_pv(&pvl->pv, fp);
}
list_for_each(tmp, &vg->lvs) {
struct lv_list *lvl = list_entry(tmp, struct lv_list, list);
dump_lv(&lvl->lv, fp);
}
}
void dump_vg_names(struct list_head *vg_names, FILE *fp)
{
struct list_head *tmp;
struct name_list *nl;
list_for_each(tmp, vg_names) {
nl = list_entry(tmp, struct name_list, list);
fprintf(fp, "%s\n", nl->name);
}
}

View File

@ -1,28 +0,0 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _LVM_PRETTY_PRINT
#define _LVM_PRETTY_PRINT
#include "metadata.h"
#include <stdio.h>
void dump_pv(struct physical_volume *pv, FILE *fp);
void dump_lv(struct logical_volume *lv, FILE *fp);
void dump_vg(struct volume_group *vg, FILE *fp);
void dump_vg_names(struct list_head *vg_names, FILE *fp);
#endif

View File

@ -1,75 +0,0 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "log.h"
#include "format1.h"
#include "pretty_print.h"
#include "list.h"
#include <stdio.h>
int main(int argc, char **argv)
{
struct io_space *ios;
struct physical_volume *pv;
struct dm_pool *mem;
struct device *dev;
if (argc != 2) {
fprintf(stderr, "usage: read_pv_t <device>\n");
exit(1);
}
init_log(stderr);
init_debug(_LOG_INFO);
if (!dev_cache_init()) {
fprintf(stderr, "init of dev-cache failed\n");
exit(1);
}
if (!dev_cache_add_dir("/dev/loop")) {
fprintf(stderr, "couldn't add /dev to dir-cache\n");
exit(1);
}
if (!(mem = dm_pool_create(10 * 1024))) {
fprintf(stderr, "couldn't create pool\n");
exit(1);
}
ios = create_lvm1_format("/dev", mem, NULL);
if (!ios) {
fprintf(stderr, "failed to create io_space for format1\n");
exit(1);
}
pv = ios->pv_read(ios, argv[1]);
if (!pv) {
fprintf(stderr, "couldn't read pv %s\n", dev->name);
exit(1);
}
dump_pv(pv, stdout);
ios->destroy(ios);
dm_pool_destroy(mem);
dev_cache_exit();
dump_memory();
fin_log();
return 0;
}

View File

@ -1,75 +0,0 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "log.h"
#include "format1.h"
#include "pretty_print.h"
#include <stdio.h>
int main(int argc, char **argv)
{
struct io_space *ios;
struct volume_group *vg;
struct dm_pool *mem;
if (argc != 2) {
fprintf(stderr, "usage: read_vg_t <vg_name>\n");
exit(1);
}
init_log(stderr);
init_debug(_LOG_INFO);
if (!dev_cache_init()) {
fprintf(stderr, "init of dev-cache failed\n");
exit(1);
}
if (!dev_cache_add_dir("/dev/loop")) {
fprintf(stderr, "couldn't add /dev to dir-cache\n");
exit(1);
}
if (!(mem = dm_pool_create(10 * 1024))) {
fprintf(stderr, "couldn't create pool\n");
exit(1);
}
ios = create_lvm1_format("/dev", mem, NULL);
if (!ios) {
fprintf(stderr, "failed to create io_space for format1\n");
exit(1);
}
vg = ios->vg_read(ios, argv[1]);
if (!vg) {
fprintf(stderr, "couldn't read vg %s\n", argv[1]);
exit(1);
}
dump_vg(vg, stdout);
ios->destroy(ios);
dm_pool_destroy(mem);
dev_cache_exit();
dump_memory();
fin_log();
return 0;
}

View File

@ -1,77 +0,0 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "log.h"
#include "format1.h"
#include "pretty_print.h"
#include <stdio.h>
int main(int argc, char **argv)
{
struct io_space *ios;
struct volume_group *vg;
struct dm_pool *mem;
if (argc != 2) {
fprintf(stderr, "usage: read_vg_t <vg_name>\n");
exit(1);
}
init_log(stderr);
init_debug(_LOG_INFO);
if (!dev_cache_init()) {
fprintf(stderr, "init of dev-cache failed\n");
exit(1);
}
if (!dev_cache_add_dir("/dev/loop")) {
fprintf(stderr, "couldn't add /dev to dir-cache\n");
exit(1);
}
if (!(mem = dm_pool_create(10 * 1024))) {
fprintf(stderr, "couldn't create pool\n");
exit(1);
}
ios = create_lvm1_format("/dev", mem, NULL);
if (!ios) {
fprintf(stderr, "failed to create io_space for format1\n");
exit(1);
}
vg = ios->vg_read(ios, argv[1]);
if (!vg) {
fprintf(stderr, "couldn't read vg %s\n", argv[1]);
exit(1);
}
if (!ios->vg_write(ios, vg)) {
fprintf(stderr, "couldn't write vg\n");
exit(1);
}
ios->destroy(ios);
dm_pool_destroy(mem);
dev_cache_exit();
dump_memory();
fin_log();
return 0;
}

View File

@ -1,33 +0,0 @@
#
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004 Red Hat, Inc. All rights reserved.
#
# This file is part of LVM2.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = @top_builddir@
VPATH = @srcdir@
SOURCES=\
dbg_malloc_t.c
TARGETS=dbg_malloc_t
include $(top_builddir)/make.tmpl
dbg_malloc_t: dbg_malloc_t.o
$(CC) $(CFLAGS) -o dbg_malloc_t dbg_malloc_t.o \
-L$(top_builddir)/lib -llvm
pool_t: pool_t.o
$(CC) $(CFLAGS) -o pool_t pool_t.o -L$(top_builddir)/lib -llvm

View File

@ -1,156 +0,0 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "log.h"
#include <stdio.h>
#include <unistd.h>
static void _print_help(FILE *out, const char *prog)
{
fprintf(out, "usage : %s [-hlbufd]\n\n", prog);
fprintf(out, " h : this message\n");
fprintf(out, " l : cause memory leak\n");
fprintf(out, " b : overrun memory block\n");
fprintf(out, " u : underrun memory block\n");
fprintf(out, " f : free random pointer\n");
fprintf(out, " d : free block twice\n");
}
struct block_list {
struct block_list *next;
char dummy[9];
};
static void _leak_memory(void)
{
int i;
struct block_list *b, *head, **l = &head, *n;
/* allocate a list of blocks */
for (i = 0; i < 1000; i++) {
if (!(b = dbg_malloc(sizeof(*b)))) {
log_fatal("Couldn't allocate memory");
exit(1);
}
b->next = 0;
*l = b;
l = &b->next;
}
/* free off every other block */
for (b = head, i = 0; b; b = n, i++) {
n = b->next;
if(i & 0x1)
dbg_free(b);
}
}
static void _bounds_overrun(void)
{
char *b;
/* allocate a block */
b = dbg_malloc(534);
/* overrun */
b[534] = 56;
/* free it, which should trigger the bounds error */
dbg_free(b);
}
static void _bounds_underrun(void)
{
char *b;
/* allocate a block */
b = dbg_malloc(534);
/* underrun */
*(b - 1) = 56;
/* free it, which should trigger the bounds error */
dbg_free(b);
}
static void _free_dud(void)
{
char *b;
/* allocate a block */
b = dbg_malloc(534);
/* free it, which should trigger the bounds error */
dbg_free(b + 100);
}
static void _free_twice(void)
{
char *b;
/* allocate a block */
b = dbg_malloc(534);
/* free it, which should trigger the bounds error */
dbg_free(b);
dbg_free(b);
}
int main(int argc, char **argv)
{
char opt;
init_log(stderr);
init_debug(_LOG_DEBUG);
opt = getopt(argc, argv, "hlbufd");
switch(opt) {
case EOF:
case 'h':
_print_help(stdout, argv[0]);
break;
case 'l':
_leak_memory();
break;
case 'b':
_bounds_overrun();
break;
case 'u':
_bounds_underrun();
break;
case 'f':
_free_dud();
break;
case 'd':
_free_twice();
break;
case '?':
fprintf(stderr, "Unknown option -%c\n", opt);
exit(1);
}
dump_memory();
fin_log();
return 0;
}

View File

@ -28,7 +28,7 @@ ifeq ("@APPLIB@", "yes")
ifeq ("@BUILD_DMEVENTD@", "yes")
LDFLAGS += -Wl,-rpath-link,$(top_builddir)/daemons/dmeventd
endif
LVMLIBS = @LVM2APP_LIB@ -ldevmapper
LVMLIBS = @LVM2APP_LIB@ -ldevmapper -laio
endif
LVM_SCRIPTS = lvmdump.sh lvmconf.sh

View File

@ -27,7 +27,7 @@ datarootdir = @datarootdir@
LVM_TEST_RESULTS ?= results
SUBDIRS = api unit
SUBDIRS = api
SOURCES = lib/not.c lib/harness.c
CXXSOURCES = lib/runner.cpp
CXXFLAGS += $(EXTRA_EXEC_CFLAGS)

View File

@ -1,2 +1 @@
export LVM_TEST_LOCKING=3
export LVM_TEST_LVM1=1

View File

@ -1,2 +1 @@
export LVM_TEST_LOCKING=1
export LVM_TEST_LVM1=1

View File

@ -1,3 +1,2 @@
export LVM_TEST_LOCKING=3
export LVM_TEST_DEVDIR=/dev
export LVM_TEST_LVM1=1

View File

@ -1,3 +1,2 @@
export LVM_TEST_LOCKING=1
export LVM_TEST_DEVDIR=/dev
export LVM_TEST_LVM1=1

View File

@ -1,6 +1,6 @@
#!/usr/bin/env bash
# Copyright (C) 2014 Red Hat, Inc. All rights reserved.
# Copyright (C) 2018 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
@ -16,26 +16,27 @@ SKIP_WITH_LVMLOCKD=1
. lib/inittest
aux prepare_pvs 3
aux prepare_pvs 3 100
get_devs
vgcreate -s 64k "$vg" "${DEVICES[@]}"
lvcreate -aey -l10 --type mirror -m1 -n $lv1 $vg "$dev1" "$dev2"
# Use zero devices for big mirror legs
aux zero_dev "$dev2" $(get first_extent_sector "$dev2"):
aux zero_dev "$dev3" $(get first_extent_sector "$dev3"):
# Slow down device so we are able to start next conversion in parallel
aux delay_dev "$dev3" 0 200
lvcreate -aey -L90 --type mirror --corelog --regionsize 16k -m1 -n $lv1 $vg "$dev1" "$dev2"
lvconvert -m+1 -b $vg/$lv1 "$dev3"
# To fix - wait helps here....
#lvconvert $vg/$lv1
# We want here ongoing conversion
lvs -a -o+seg_pe_ranges $vg
# Now it should be able to drop 2nd. leg
lvconvert -m-1 $vg/$lv1 "$dev2"
lvs -a $vg
#
# It fails so use 'should' and -vvvv for now
#
should lvconvert -vvvv -m-1 $vg/$lv1 "$dev2"
vgremove -f $vg

View File

@ -1,6 +1,6 @@
#!/usr/bin/env bash
# Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved.
# Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
@ -17,7 +17,7 @@ export LVM_TEST_LVMETAD_DEBUG_OPTS=${LVM_TEST_LVMETAD_DEBUG_OPTS-}
. lib/inittest
aux prepare_pvs 5 20
aux prepare_pvs 5 100
get_devs
# proper DEVRANGE needs to be set according to extent size
@ -78,56 +78,6 @@ lvcreate -aey -l2 -n $lv1 $vg "$dev1"
not lvconvert -m+1 --mirrorlog core $vg/$lv1 "$dev1"
lvremove -ff $vg
# Start w/ 3-way mirror
# Test pulling primary image before mirror in-sync (should fail)
# Test pulling primary image after mirror in-sync (should work)
# Test that the correct devices remain in the mirror
offset=$(get first_extent_sector "$dev2")
offset=$(( offset + 2 ))
# put 1 single slowing delayed sector
# update in case mirror ever gets faster and allows parallel read
aux delay_dev "$dev2" 0 10 ${offset}:1
lvcreate -aey -l10 -Zn -Wn --type mirror --regionsize 16k -m2 -n $lv1 $vg "$dev1" "$dev2" "$dev4" "$dev3:$DEVRANGE"
lvs -a -o+seg_pe_ranges $vg
not lvconvert -m-1 $vg/$lv1 "$dev1"
lvconvert $vg/$lv1 # wait
lvs -a $vg
aux enable_dev "$dev2"
lvconvert $vg/$lv1 # wait
lvconvert -m2 $vg/$lv1 "$dev1" "$dev2" "$dev4" "$dev3:0" # If the above "should" failed...
aux wait_for_sync $vg $lv1
lvconvert -m-1 $vg/$lv1 "$dev1"
check mirror_images_on $vg $lv1 "$dev2" "$dev4"
lvconvert -m-1 $vg/$lv1 "$dev2"
check linear $vg $lv1
check lv_on $vg $lv1 "$dev4"
lvremove -ff $vg
# FIXME: lots of unneeded extents here for log - it needs to be at least region_size in size
# No parallel lvconverts on a single LV please
lvcreate -aey -Zn -Wn -l8 --type mirror -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:0-8"
check mirror $vg $lv1
check mirror_legs $vg $lv1 2
offset=$(get first_extent_sector "$dev4")
offset=$(( offset + 2 ))
aux delay_dev "$dev4" 0 2000 ${offset}:
LVM_TEST_TAG="kill_me_$PREFIX" lvconvert -m+1 -b $vg/$lv1 "$dev4"
# Next convert should fail b/c we can't have 2 at once
not lvconvert -m+1 $vg/$lv1 "$dev5"
aux enable_dev "$dev4"
lvconvert $vg/$lv1 # wait
lvconvert -m2 $vg/$lv1 # In case the above "should" actually failed
check mirror $vg $lv1 "$dev3"
check mirror_no_temporaries $vg $lv1
check mirror_legs $vg $lv1 3
lvremove -ff $vg
# add 1 mirror to core log mirror, but
# implicitly keep log as 'core'
lvcreate -aey -l2 --type mirror -m1 --mirrorlog core -n $lv1 $vg "$dev1" "$dev2"
@ -240,13 +190,6 @@ lvremove -ff $vg
# ---------------------------------------------------------------------
# "rhbz440405: lvconvert -m0 incorrectly fails if all PEs allocated"
lvcreate -aey -l "$(get pv_field "$dev1" pe_count)" --type mirror -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:$DEVRANGE"
aux wait_for_sync $vg $lv1
lvconvert -m0 $vg/$lv1 "$dev1"
check linear $vg $lv1
lvremove -ff $vg
# "rhbz264241: lvm mirror doesn't lose it's "M" --nosync attribute
# after being down and the up converted"
lvcreate -aey -l2 --type mirror -m1 -n $lv1 --nosync $vg
@ -300,6 +243,7 @@ lvcreate -aey -l15 -n $lv1 $vg
not lvconvert --type mirror -m1 --corelog --stripes 2 $vg/$lv1
lvremove -ff $vg
# Linear to mirror with mirrored log using --alloc anywhere
lvcreate -aey -l2 -n $lv1 $vg "$dev1"
if test -e LOCAL_CLVMD; then
@ -311,9 +255,10 @@ check mirror $vg $lv1
fi
lvremove -ff $vg
# FIXME - cases which needs to be fixed to work in cluster
test -e LOCAL_CLVMD && exit 0
if test -e LOCAL_CLVMD; then
: # FIXME - cases which needs to be fixed to work in cluster
else
# Should not be able to add images to --nosync mirror
# but should be able to after 'lvchange --resync'
lvcreate -aey --type mirror -m 1 -l1 -n $lv1 $vg --nosync
@ -359,5 +304,67 @@ lvcreate -l2 -n $lv1 $vg
lvconvert --type mirror -i1 -m1 $vg/$lv1 | tee out
grep -e "$vg/$lv1: Converted:" out || die "Missing sync info in foreground mode"
lvremove -ff $vg
fi
#########################################################################
# Start w/ 3-way mirror
# Test that the correct devices remain in the mirror
# Make $dev2 & $dev4 zero backend device so large mirrors can be user
# without consuming any real space. Clearly such mirrors can't be read back
# but tests here are validating possibilies of those conversions
#
# Test pulling primary image before mirror in-sync (should fail)
# Test pulling primary image after mirror in-sync (should work)
#
aux zero_dev "$dev2" $(get first_extent_sector "$dev2"):
aux zero_dev "$dev4" $(get first_extent_sector "$dev4"):
# Use large enough mirror that takes time to sychronize with small regionsize
lvcreate -aey -L80 -Zn -Wn --type mirror --regionsize 16k -m2 -n $lv1 $vg "$dev1" "$dev2" "$dev4" "$dev3:$DEVRANGE"
not lvconvert -m-1 $vg/$lv1 "$dev1" 2>&1 | tee out
grep "not in-sync" out
lvconvert $vg/$lv1 # wait
lvconvert -m-1 $vg/$lv1 "$dev1"
check mirror_images_on $vg $lv1 "$dev2" "$dev4"
lvconvert -m-1 $vg/$lv1 "$dev2"
check linear $vg $lv1
check lv_on $vg $lv1 "$dev4"
lvremove -ff $vg
# No parallel lvconverts on a single LV please
# Use big enough mirror size and small regionsize to run on all test machines succesfully
lvcreate -aey -Zn -Wn -L80 --type mirror --regionsize 16k -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:0-8"
check mirror $vg $lv1
check mirror_legs $vg $lv1 2
LVM_TEST_TAG="kill_me_$PREFIX" lvconvert -m+1 -b $vg/$lv1 "$dev4"
# ATM upconversion should be running
# Next convert should fail b/c we can't have 2 at once
not lvconvert -m+1 $vg/$lv1 "$dev5" 2>&1 | tee out
grep "is already being converted" out
lvconvert $vg/$lv1 # wait
check mirror $vg $lv1 "$dev3"
check mirror_no_temporaries $vg $lv1
check mirror_legs $vg $lv1 3
lvremove -ff $vg
lvs -a $vg
dmsetup table
losetup -a
ls -lRa $PWD
# "rhbz440405: lvconvert -m0 incorrectly fails if all PEs allocated"
lvcreate -aey -l "$(get pv_field "$dev1" pe_count)" --type mirror -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:$DEVRANGE"
lvs -a -o+seg_pe_ranges $vg
aux wait_for_sync $vg $lv1
lvconvert -m0 $vg/$lv1 "$dev1"
check linear $vg $lv1
lvremove -ff $vg
vgremove -ff $vg

View File

@ -25,6 +25,9 @@ vgextend $vg1 "$dev1"
dd if=badmda of="$dev1" bs=256K count=1
# the vg_read in vgck (and other commands) will repair the metadata
vgck $vg1
# dev1 is part of vg1 (as witnessed by metadata on dev2 and dev3), but its mda
# was corrupt (written over by a backup from time dev1 was an orphan)
check pv_field "$dev1" vg_name $vg1

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