summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore44
-rw-r--r--Makefile.in23
-rw-r--r--aclocal.m4222
-rw-r--r--conf/example.conf.in16
-rwxr-xr-xconfigure23
-rw-r--r--configure.in25
-rw-r--r--daemons/clvmd/Makefile.in2
-rw-r--r--daemons/clvmd/lvm-functions.c3
-rw-r--r--doc/aio_design.txt215
-rw-r--r--include/.symlinks.in1
-rw-r--r--include/configure.h.in19
-rw-r--r--lib/Makefile.in1
-rw-r--r--lib/activate/activate.c82
-rw-r--r--lib/cache/lvmcache.c1076
-rw-r--r--lib/cache/lvmcache.h40
-rw-r--r--lib/cache/lvmetad.c485
-rw-r--r--lib/commands/toolcontext.c23
-rw-r--r--lib/commands/toolcontext.h5
-rw-r--r--lib/config/config.c166
-rw-r--r--lib/config/config.h8
-rw-r--r--lib/config/config_settings.h17
-rw-r--r--lib/config/defaults.h4
-rw-r--r--lib/device/bcache.c1182
-rw-r--r--lib/device/bcache.h164
-rw-r--r--lib/device/dev-cache.c52
-rw-r--r--lib/device/dev-cache.h14
-rw-r--r--lib/device/dev-io.c628
-rw-r--r--lib/device/dev-luks.c2
-rw-r--r--lib/device/dev-md.c2
-rw-r--r--lib/device/dev-swap.c3
-rw-r--r--lib/device/dev-type.c8
-rw-r--r--lib/device/device.h105
-rw-r--r--lib/filters/filter-composite.c4
-rw-r--r--lib/filters/filter-persistent.c21
-rw-r--r--lib/filters/filter.h2
-rw-r--r--lib/format1/disk-rep.c11
-rw-r--r--lib/format1/format1.c2
-rw-r--r--lib/format1/lvm1-label.c20
-rw-r--r--lib/format_pool/disk_rep.c5
-rw-r--r--lib/format_pool/format_pool.c2
-rw-r--r--lib/format_pool/pool_label.c13
-rw-r--r--lib/format_text/archive.c6
-rw-r--r--lib/format_text/archiver.c12
-rw-r--r--lib/format_text/export.c21
-rw-r--r--lib/format_text/format-text.c907
-rw-r--r--lib/format_text/import-export.h16
-rw-r--r--lib/format_text/import.c281
-rw-r--r--lib/format_text/import_vsn1.c60
-rw-r--r--lib/format_text/layout.h12
-rw-r--r--lib/format_text/text_label.c205
-rw-r--r--lib/label/label.c998
-rw-r--r--lib/label/label.h33
-rw-r--r--lib/metadata/lv_manip.c2
-rw-r--r--lib/metadata/metadata-exported.h13
-rw-r--r--lib/metadata/metadata-liblvm.c7
-rw-r--r--lib/metadata/metadata.c429
-rw-r--r--lib/metadata/metadata.h17
-rw-r--r--lib/metadata/vg.c5
-rw-r--r--lib/misc/lvm-globals.c23
-rw-r--r--lib/misc/lvm-globals.h4
-rw-r--r--libdm/libdm-config.c10
-rw-r--r--liblvm/Makefile.in2
-rw-r--r--liblvm/lvm_vg.c3
-rw-r--r--make.tmpl.in65
-rw-r--r--man/Makefile.in81
-rw-r--r--old-tests/config/.gitignore1
-rw-r--r--old-tests/config/Makefile5
-rw-r--r--old-tests/config/config_t.c37
-rw-r--r--old-tests/config/empty_array.conf1
-rw-r--r--old-tests/config/vg0169
-rw-r--r--old-tests/datastruct/hash_t.c106
-rw-r--r--old-tests/dev-mgr/dev_cache_t.c54
-rw-r--r--old-tests/device/Makefile.in29
-rw-r--r--old-tests/device/dev_cache_t.c70
-rw-r--r--old-tests/device/fill_device.c27
-rw-r--r--old-tests/device/random.c116
-rw-r--r--old-tests/device/random.h32
-rw-r--r--old-tests/filters/Makefile.in35
-rw-r--r--old-tests/filters/pfilter_t.c121
-rw-r--r--old-tests/filters/rfilter_t.c92
-rw-r--r--old-tests/filters/sample.cfg21
-rw-r--r--old-tests/format1/Makefile.in52
-rw-r--r--old-tests/format1/get_pvs_t.c73
-rw-r--r--old-tests/format1/get_vgs_t.c69
-rw-r--r--old-tests/format1/pretty_print.c86
-rw-r--r--old-tests/format1/pretty_print.h28
-rw-r--r--old-tests/format1/read_pv_t.c75
-rw-r--r--old-tests/format1/read_vg_t.c75
-rw-r--r--old-tests/format1/write_vg_t.c77
-rw-r--r--old-tests/mm/Makefile.in33
-rw-r--r--old-tests/mm/dbg_malloc_t.c156
-rw-r--r--scripts/Makefile.in2
-rw-r--r--test/Makefile.in2
-rw-r--r--test/lib/flavour-ndev-cluster.sh1
-rw-r--r--test/lib/flavour-ndev-vanilla.sh1
-rw-r--r--test/lib/flavour-udev-cluster.sh1
-rw-r--r--test/lib/flavour-udev-vanilla.sh1
-rw-r--r--test/shell/lvconvert-mirror-updown.sh25
-rw-r--r--test/shell/lvconvert-mirror.sh129
-rw-r--r--test/shell/mda-rollback.sh3
-rw-r--r--test/shell/vgck.sh8
-rw-r--r--test/shell/vgsplit-usage.sh2
-rw-r--r--test/unit/Makefile.in53
-rw-r--r--test/unit/bcache_t.c636
-rw-r--r--test/unit/run.c1
-rw-r--r--test/unit/units.h1
-rw-r--r--tools/Makefile.in75
-rw-r--r--tools/command.c15
-rw-r--r--tools/commands.h18
-rw-r--r--tools/lvchange.c4
-rw-r--r--tools/lvconvert.c7
-rw-r--r--tools/lvmcmdline.c19
-rw-r--r--tools/lvmdiskscan.c7
-rw-r--r--tools/polldaemon.c20
-rw-r--r--tools/pvck.c2
-rw-r--r--tools/pvscan.c53
-rw-r--r--tools/toollib.c181
-rw-r--r--tools/tools.h10
-rw-r--r--tools/vgcfgrestore.c2
-rw-r--r--tools/vgchange.c17
-rw-r--r--tools/vgcreate.c27
-rw-r--r--tools/vgimportclone.c1
-rw-r--r--tools/vgmerge.c3
-rw-r--r--tools/vgrename.c5
-rw-r--r--tools/vgsplit.c3
-rw-r--r--unit-tests/datastruct/Makefile.in32
-rw-r--r--unit-tests/datastruct/TESTS1
-rw-r--r--unit-tests/datastruct/bitset_t.c133
-rw-r--r--unit-tests/mm/Makefile.in31
-rw-r--r--unit-tests/mm/TESTS1
-rwxr-xr-xunit-tests/mm/check_results31
-rw-r--r--unit-tests/mm/pool_valgrind_t.c181
-rw-r--r--unit-tests/regex/Makefile.in37
-rw-r--r--unit-tests/regex/TESTS3
-rw-r--r--unit-tests/regex/dev_patterns2
-rw-r--r--unit-tests/regex/devices.list880
-rw-r--r--unit-tests/regex/matcher_t.c156
-rw-r--r--unit-tests/regex/matcher_t.expected16
-rw-r--r--unit-tests/regex/matcher_t.expected21
-rw-r--r--unit-tests/regex/matcher_t.expected33
-rw-r--r--unit-tests/regex/nonprint_input4
-rw-r--r--unit-tests/regex/nonprint_regexes3
-rw-r--r--unit-tests/regex/parse_t.c118
-rw-r--r--unit-tests/regex/random_regexes100
144 files changed, 5487 insertions, 7173 deletions
diff --git a/.gitignore b/.gitignore
index 28846b194..7e031bfb6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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
diff --git a/Makefile.in b/Makefile.in
index 31d428d9b..146ed558a 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -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),)
diff --git a/aclocal.m4 b/aclocal.m4
index 4ab64a82f..07ea0b664 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -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.
-
-# PKG_PROG_PKG_CONFIG([MIN-VERSION])
-# ----------------------------------
+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.
+
+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
-
-# 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_PROG_PKG_CONFIG
+
+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
-
-
-# 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
+
+
+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
-
-
-# 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_INSTALLDIR
+
+
+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])
diff --git a/conf/example.conf.in b/conf/example.conf.in
index 3b0638f60..aab274d74 100644
--- a/conf/example.conf.in
+++ b/conf/example.conf.in
@@ -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
diff --git a/configure b/configure
index 5409f6847..50110897c 100755
--- a/configure
+++ b/configure
@@ -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
diff --git a/configure.in b/configure.in
index 605b6b212..0d268e83f 100644
--- a/configure.in
+++ b/configure.in
@@ -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
@@ -1125,24 +1123,6 @@ if test "$DEVMAPPER" = yes; then
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)
AC_ARG_ENABLE(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
diff --git a/daemons/clvmd/Makefile.in b/daemons/clvmd/Makefile.in
index 7b1b49bf9..83af00e20 100644
--- a/daemons/clvmd/Makefile.in
+++ b/daemons/clvmd/Makefile.in
@@ -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 = \
diff --git a/daemons/clvmd/lvm-functions.c b/daemons/clvmd/lvm-functions.c
index c845e6d51..6254122ee 100644
--- a/daemons/clvmd/lvm-functions.c
+++ b/daemons/clvmd/lvm-functions.c
@@ -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);
diff --git a/doc/aio_design.txt b/doc/aio_design.txt
deleted file mode 100644
index c6eb44352..000000000
--- a/doc/aio_design.txt
+++ /dev/null
@@ -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.
-
diff --git a/include/.symlinks.in b/include/.symlinks.in
index a1b5c1e05..3d5075058 100644
--- a/include/.symlinks.in
+++ b/include/.symlinks.in
@@ -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
diff --git a/include/configure.h.in b/include/configure.h.in
index a4918071f..a4c93d6f2 100644
--- a/include/configure.h.in
+++ b/include/configure.h.in
@@ -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
diff --git a/lib/Makefile.in b/lib/Makefile.in
index 1fdaca8ee..bd68edc34 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -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 \
diff --git a/lib/activate/activate.c b/lib/activate/activate.c
index 6611e99e7..565e643ec 100644
--- a/lib/activate/activate.c
+++ b/lib/activate/activate.c
@@ -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;
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
index 5ff28274c..f1fd68375 100644
--- a/lib/cache/lvmcache.c
+++ b/lib/cache/lvmcache.c
@@ -29,7 +29,6 @@
#include "lvmetad.h"
#include "lvmetad-client.h"
-#define CACHE_INVALID 0x00000001
#define CACHE_LOCKED 0x00000002
/* One per device */
@@ -63,15 +62,44 @@ struct lvmcache_vginfo {
char *lock_type;
uint32_t mda_checksum;
size_t mda_size;
- size_t vgmetadata_size;
- char *vgmetadata; /* Copy of VG metadata as format_text string */
- struct dm_config_tree *cft; /* Config tree created from vgmetadata */
- /* Lifetime is directly tied to vgmetadata */
- struct volume_group *cached_vg;
- unsigned holders;
- unsigned vg_use_count; /* Counter of vg reusage */
- unsigned precommitted; /* Is vgmetadata live or precommitted? */
- unsigned cached_vg_invalidated; /* Signal to regenerate cached_vg */
+ int seqno;
+ int independent_metadata_location; /* metadata read from independent areas */
+ int scan_summary_mismatch; /* vgsummary from devs had mismatching seqno or checksum */
+
+ /*
+ * The following are not related to lvmcache or vginfo,
+ * but are borrowing the vginfo to store the data.
+ *
+ * suspended_vg_* are used only by clvmd suspend/resume.
+ * In suspend, both old (current) and new (precommitted)
+ * metadata is saved. (Each in three forms: buffer, cft,
+ * and vg). In resume, if the vg was committed
+ * (suspended_vg_committed is set), then LVs are resumed
+ * using the new metadata, but if the vg wasn't committed,
+ * then LVs are resumed using the old metadata.
+ *
+ * suspended_vg_committed is set to 1 when clvmd gets
+ * LCK_VG_COMMIT from vg_commit().
+ *
+ * These fields are only used between suspend and resume
+ * in clvmd, and should never be used in any other way.
+ * The contents of this data are never changed. This
+ * data does not really belong in lvmcache, it's unrelated
+ * to lvmcache or vginfo, but it's just a convenient place
+ * for clvmd to stash the VG between suspend and resume
+ * (since the same caller isn't present to pass the VG to
+ * both suspend and resume in the case of clvmd.)
+ *
+ * This data is not really a "cache" of the VG, it is just
+ * a location to pass the VG between suspend and resume.
+ */
+ int suspended_vg_committed;
+ char *suspended_vg_old_buf;
+ struct dm_config_tree *suspended_vg_old_cft;
+ struct volume_group *suspended_vg_old;
+ char *suspended_vg_new_buf;
+ struct dm_config_tree *suspended_vg_new_cft;
+ struct volume_group *suspended_vg_new;
};
static struct dm_hash_table *_pvid_hash = NULL;
@@ -130,6 +158,8 @@ void lvmcache_seed_infos_from_lvmetad(struct cmd_context *cmd)
if (!lvmetad_used() || _has_scanned)
return;
+ dev_cache_scan();
+
if (!lvmetad_pv_list_to_lvmcache(cmd)) {
stack;
return;
@@ -138,148 +168,157 @@ void lvmcache_seed_infos_from_lvmetad(struct cmd_context *cmd)
_has_scanned = 1;
}
-/* Volume Group metadata cache functions */
-static void _free_cached_vgmetadata(struct lvmcache_vginfo *vginfo)
+static void _update_cache_info_lock_state(struct lvmcache_info *info, int locked)
+{
+ if (locked)
+ info->status |= CACHE_LOCKED;
+ else
+ info->status &= ~CACHE_LOCKED;
+}
+
+static void _update_cache_vginfo_lock_state(struct lvmcache_vginfo *vginfo,
+ int locked)
{
struct lvmcache_info *info;
- if (!vginfo || !vginfo->vgmetadata)
+ dm_list_iterate_items(info, &vginfo->infos)
+ _update_cache_info_lock_state(info, locked);
+}
+
+static void _update_cache_lock_state(const char *vgname, int locked)
+{
+ struct lvmcache_vginfo *vginfo;
+
+ if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, NULL)))
return;
- dm_free(vginfo->vgmetadata);
+ _update_cache_vginfo_lock_state(vginfo, locked);
+}
- vginfo->vgmetadata = NULL;
+static void _suspended_vg_free(struct lvmcache_vginfo *vginfo, int free_old, int free_new)
+{
+ if (free_old) {
+ if (vginfo->suspended_vg_old_buf)
+ dm_free(vginfo->suspended_vg_old_buf);
+ if (vginfo->suspended_vg_old_cft)
+ dm_config_destroy(vginfo->suspended_vg_old_cft);
+ if (vginfo->suspended_vg_old)
+ release_vg(vginfo->suspended_vg_old);
- /* Release also cached config tree */
- if (vginfo->cft) {
- dm_config_destroy(vginfo->cft);
- vginfo->cft = NULL;
+ vginfo->suspended_vg_old_buf = NULL;
+ vginfo->suspended_vg_old_cft = NULL;
+ vginfo->suspended_vg_old = NULL;
}
- /* Invalidate any cached device buffers */
- dm_list_iterate_items(info, &vginfo->infos)
- devbufs_release(info->dev);
-
- log_debug_cache("lvmcache: VG %s wiped.", vginfo->vgname);
+ if (free_new) {
+ if (vginfo->suspended_vg_new_buf)
+ dm_free(vginfo->suspended_vg_new_buf);
+ if (vginfo->suspended_vg_new_cft)
+ dm_config_destroy(vginfo->suspended_vg_new_cft);
+ if (vginfo->suspended_vg_new)
+ release_vg(vginfo->suspended_vg_new);
- release_vg(vginfo->cached_vg);
+ vginfo->suspended_vg_new_buf = NULL;
+ vginfo->suspended_vg_new_cft = NULL;
+ vginfo->suspended_vg_new = NULL;
+ }
}
-/*
- * Cache VG metadata against the vginfo with matching vgid.
- */
-static void _store_metadata(struct volume_group *vg, unsigned precommitted)
+static void _drop_metadata(const char *vgname, int drop_precommitted)
{
- char uuid[64] __attribute__((aligned(8)));
struct lvmcache_vginfo *vginfo;
- char *data;
- size_t size;
- if (!(vginfo = lvmcache_vginfo_from_vgid((const char *)&vg->id))) {
- stack;
+ if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, NULL)))
return;
- }
- if (!(size = export_vg_to_buffer(vg, &data))) {
- stack;
- _free_cached_vgmetadata(vginfo);
- return;
- }
+ if (drop_precommitted)
+ _suspended_vg_free(vginfo, 0, 1);
+ else
+ _suspended_vg_free(vginfo, 1, 1);
+}
- /* Avoid reparsing of the same data string */
- if (vginfo->vgmetadata && vginfo->vgmetadata_size == size &&
- strcmp(vginfo->vgmetadata, data) == 0)
- dm_free(data);
- else {
- _free_cached_vgmetadata(vginfo);
- vginfo->vgmetadata_size = size;
- vginfo->vgmetadata = data;
- }
+void lvmcache_save_suspended_vg(struct volume_group *vg, int precommitted)
+{
+ struct lvmcache_vginfo *vginfo;
+ struct format_instance *fid;
+ struct format_instance_ctx fic;
+ struct volume_group *susp_vg = NULL;
+ struct dm_config_tree *susp_cft = NULL;
+ char *susp_buf = NULL;
+ size_t size;
+ int new = precommitted;
+ int old = !precommitted;
- vginfo->precommitted = precommitted;
+ if (!(vginfo = lvmcache_vginfo_from_vgid((const char *)&vg->id)))
+ goto_bad;
- if (!id_write_format((const struct id *)vginfo->vgid, uuid, sizeof(uuid))) {
- stack;
+ /* already saved */
+ if (old && vginfo->suspended_vg_old &&
+ (vginfo->suspended_vg_old->seqno == vg->seqno))
return;
- }
- log_debug_cache("lvmcache: VG %s (%s) stored (%" PRIsize_t " bytes%s).",
- vginfo->vgname, uuid, size,
- precommitted ? ", precommitted" : "");
-}
+ /* already saved */
+ if (new && vginfo->suspended_vg_new &&
+ (vginfo->suspended_vg_new->seqno == vg->seqno))
+ return;
-static void _update_cache_info_lock_state(struct lvmcache_info *info,
- int locked,
- int *cached_vgmetadata_valid)
-{
- int was_locked = (info->status & CACHE_LOCKED) ? 1 : 0;
+ _suspended_vg_free(vginfo, old, new);
- /*
- * Cache becomes invalid whenever lock state changes unless
- * exclusive VG_GLOBAL is held (i.e. while scanning).
- */
- if (!lvmcache_vgname_is_locked(VG_GLOBAL) && (was_locked != locked)) {
- info->status |= CACHE_INVALID;
- *cached_vgmetadata_valid = 0;
- }
+ if (!(size = export_vg_to_buffer(vg, &susp_buf)))
+ goto_bad;
- if (locked)
- info->status |= CACHE_LOCKED;
- else
- info->status &= ~CACHE_LOCKED;
-}
+ fic.type = FMT_INSTANCE_MDAS | FMT_INSTANCE_AUX_MDAS;
+ fic.context.vg_ref.vg_name = vginfo->vgname;
+ fic.context.vg_ref.vg_id = vginfo->vgid;
+ if (!(fid = vginfo->fmt->ops->create_instance(vginfo->fmt, &fic)))
+ goto_bad;
-static void _update_cache_vginfo_lock_state(struct lvmcache_vginfo *vginfo,
- int locked)
-{
- struct lvmcache_info *info;
- int cached_vgmetadata_valid = 1;
+ if (!(susp_cft = config_tree_from_string_without_dup_node_check(susp_buf)))
+ goto_bad;
- dm_list_iterate_items(info, &vginfo->infos)
- _update_cache_info_lock_state(info, locked,
- &cached_vgmetadata_valid);
+ if (!(susp_vg = import_vg_from_config_tree(susp_cft, fid)))
+ goto_bad;
+
+ if (old) {
+ vginfo->suspended_vg_old_buf = susp_buf;
+ vginfo->suspended_vg_old_cft = susp_cft;
+ vginfo->suspended_vg_old = susp_vg;
+ log_debug_cache("lvmcache saved suspended vg old seqno %d %s", vg->seqno, vg->name);
+ } else {
+ vginfo->suspended_vg_new_buf = susp_buf;
+ vginfo->suspended_vg_new_cft = susp_cft;
+ vginfo->suspended_vg_new = susp_vg;
+ log_debug_cache("lvmcache saved suspended vg new seqno %d %s", vg->seqno, vg->name);
+ }
+ return;
- if (!cached_vgmetadata_valid)
- _free_cached_vgmetadata(vginfo);
+bad:
+ _suspended_vg_free(vginfo, old, new);
+ log_debug_cache("lvmcache failed to save suspended pre %d vg %s", precommitted, vg->name);
}
-static void _update_cache_lock_state(const char *vgname, int locked)
+struct volume_group *lvmcache_get_suspended_vg(const char *vgid)
{
struct lvmcache_vginfo *vginfo;
- if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, NULL)))
- return;
+ if (!(vginfo = lvmcache_vginfo_from_vgid(vgid)))
+ return_NULL;
- _update_cache_vginfo_lock_state(vginfo, locked);
+
+ if (vginfo->suspended_vg_committed)
+ return vginfo->suspended_vg_new;
+ else
+ return vginfo->suspended_vg_old;
}
-static void _drop_metadata(const char *vgname, int drop_precommitted)
+void lvmcache_drop_suspended_vg(struct volume_group *vg)
{
struct lvmcache_vginfo *vginfo;
- struct lvmcache_info *info;
- if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, NULL)))
+ if (!(vginfo = lvmcache_vginfo_from_vgid((const char *)&vg->id)))
return;
- /*
- * Invalidate cached PV labels.
- * If cached precommitted metadata exists that means we
- * already invalidated the PV labels (before caching it)
- * and we must not do it again.
- */
- if (!drop_precommitted && vginfo->precommitted && !vginfo->vgmetadata)
- log_error(INTERNAL_ERROR "metadata commit (or revert) missing before "
- "dropping metadata from cache.");
-
- if (drop_precommitted || !vginfo->precommitted)
- dm_list_iterate_items(info, &vginfo->infos)
- info->status |= CACHE_INVALID;
-
- _free_cached_vgmetadata(vginfo);
-
- /* VG revert */
- if (drop_precommitted)
- vginfo->precommitted = 0;
+ _suspended_vg_free(vginfo, 1, 1);
}
/*
@@ -294,11 +333,7 @@ void lvmcache_commit_metadata(const char *vgname)
if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, NULL)))
return;
- if (vginfo->precommitted) {
- log_debug_cache("lvmcache: Upgraded pre-committed VG %s metadata to committed.",
- vginfo->vgname);
- vginfo->precommitted = 0;
- }
+ vginfo->suspended_vg_committed = 1;
}
void lvmcache_drop_metadata(const char *vgname, int drop_precommitted)
@@ -311,9 +346,6 @@ void lvmcache_drop_metadata(const char *vgname, int drop_precommitted)
_drop_metadata(FMT_TEXT_ORPHAN_VG_NAME, 0);
_drop_metadata(FMT_LVM1_ORPHAN_VG_NAME, 0);
_drop_metadata(FMT_POOL_ORPHAN_VG_NAME, 0);
-
- /* Indicate that PVs could now be missing from the cache */
- init_full_scan_done(0);
} else
_drop_metadata(vgname, drop_precommitted);
}
@@ -360,7 +392,7 @@ int lvmcache_verify_lock_order(const char *vgname)
return 1;
if (!_lock_hash)
- return_0;
+ return 1;
dm_hash_iterate(n, _lock_hash) {
if (!dm_hash_get_data(_lock_hash, n))
@@ -592,7 +624,7 @@ const struct format_type *lvmcache_fmt_from_vgname(struct cmd_context *cmd,
dm_list_iterate_safe(devh, tmp, &devs) {
devl = dm_list_item(devh, struct device_list);
- (void) label_read(devl->dev, NULL, UINT64_C(0));
+ label_read(devl->dev, NULL, UINT64_C(0));
dm_list_del(&devl->list);
dm_free(devl);
}
@@ -658,51 +690,6 @@ const char *lvmcache_vgid_from_vgname(struct cmd_context *cmd, const char *vgnam
return NULL;
}
-static int _info_is_valid(struct lvmcache_info *info)
-{
- if (info->status & CACHE_INVALID)
- return 0;
-
- /*
- * The caller must hold the VG lock to manipulate metadata.
- * In a cluster, remote nodes sometimes read metadata in the
- * knowledge that the controlling node is holding the lock.
- * So if the VG appears to be unlocked here, it should be safe
- * to use the cached value.
- */
- if (info->vginfo && !lvmcache_vgname_is_locked(info->vginfo->vgname))
- return 1;
-
- if (!(info->status & CACHE_LOCKED))
- return 0;
-
- return 1;
-}
-
-static int _vginfo_is_valid(struct lvmcache_vginfo *vginfo)
-{
- struct lvmcache_info *info;
-
- /* Invalid if any info is invalid */
- dm_list_iterate_items(info, &vginfo->infos)
- if (!_info_is_valid(info))
- return 0;
-
- return 1;
-}
-
-/* vginfo is invalid if it does not contain at least one valid info */
-static int _vginfo_is_invalid(struct lvmcache_vginfo *vginfo)
-{
- struct lvmcache_info *info;
-
- dm_list_iterate_items(info, &vginfo->infos)
- if (_info_is_valid(info))
- return 0;
-
- return 1;
-}
-
/*
* If valid_only is set, data will only be returned if the cached data is
* known still to be valid.
@@ -732,9 +719,6 @@ struct lvmcache_info *lvmcache_info_from_pvid(const char *pvid, struct device *d
return NULL;
}
- if (valid_only && !_info_is_valid(info))
- return NULL;
-
return info;
}
@@ -755,7 +739,7 @@ char *lvmcache_vgname_from_pvid(struct cmd_context *cmd, const char *pvid)
struct lvmcache_info *info;
char *vgname;
- if (!lvmcache_device_from_pvid(cmd, (const struct id *)pvid, NULL, NULL)) {
+ if (!lvmcache_device_from_pvid(cmd, (const struct id *)pvid, NULL)) {
log_error("Couldn't find device with uuid %s.", pvid);
return NULL;
}
@@ -771,36 +755,6 @@ char *lvmcache_vgname_from_pvid(struct cmd_context *cmd, const char *pvid)
return vgname;
}
-static void _rescan_entry(struct lvmcache_info *info)
-{
- if (info->status & CACHE_INVALID)
- (void) label_read(info->dev, NULL, UINT64_C(0));
-}
-
-static int _scan_invalid(void)
-{
- dm_hash_iter(_pvid_hash, (dm_hash_iterate_fn) _rescan_entry);
-
- return 1;
-}
-
-/*
- * lvmcache_label_scan() remembers that it has already
- * been called, and will not scan labels if it's called
- * again. (It will rescan "INVALID" devices if called again.)
- *
- * To force lvmcache_label_scan() to rescan labels on all devices,
- * call lvmcache_force_next_label_scan() before calling
- * lvmcache_label_scan().
- */
-
-static int _force_label_scan;
-
-void lvmcache_force_next_label_scan(void)
-{
- _force_label_scan = 1;
-}
-
/*
* Check if any PVs in vg->pvs have the same PVID as any
* entries in _unused_duplicate_devices.
@@ -1096,36 +1050,137 @@ next:
goto next;
}
-/* Track the number of outstanding label reads */
-/* FIXME Switch to struct and also track failed */
-static void _process_label_data(int failed, unsigned ioflags, void *context, const void *data)
+/*
+ * The initial label_scan at the start of the command is done without
+ * holding VG locks. Then for each VG identified during the label_scan,
+ * vg_read(vgname) is called while holding the VG lock. The labels
+ * and metadata on this VG's devices could have changed between the
+ * initial unlocked label_scan and the current vg_read(). So, we reread
+ * the labels/metadata for each device in the VG now that we hold the
+ * lock, and use this for processing the VG.
+ *
+ * A label scan is ultimately creating associations between devices
+ * and VGs so that when vg_read wants to get VG metadata, it knows
+ * which devices to read.
+ *
+ * It's possible that a VG is being modified during the first label
+ * scan, causing the scan to see inconsistent metadata on different
+ * devs in the VG. It's possible that those modifications are
+ * adding/removing devs from the VG, in which case the device/VG
+ * associations in lvmcache after the scan are not correct.
+ * NB. It's even possible the VG was removed completely between
+ * label scan and here, in which case we'd not find the VG in
+ * lvmcache after this rescan.
+ *
+ * A scan will also create in incorrect/incomplete picture of a VG
+ * when devices have no metadata areas. The scan does not use
+ * VG metadata to figure out that a dev with no metadata belongs
+ * to a particular VG, so a device with no mdas will not be linked
+ * to that VG after a scan.
+ *
+ * (In the special case where VG metadata is stored in files on the
+ * file system (configured in lvm.conf), the
+ * vginfo->independent_metadata_location flag is set during label scan.
+ * When we get here to rescan, we are revalidating the device to VG
+ * mapping from label scan by repeating the label scan on a subset of
+ * devices. If we see independent_metadata_location is set from the
+ * initial label scan, we know that there is nothing to do because
+ * there is no device to VG mapping to revalidate, since the VG metadata
+ * comes directly from files.)
+ */
+
+int lvmcache_label_rescan_vg(struct cmd_context *cmd, const char *vgname, const char *vgid)
{
- int *nr_labels_outstanding = context;
+ struct dm_list devs;
+ struct device_list *devl;
+ struct lvmcache_vginfo *vginfo;
+ struct lvmcache_info *info, *info2;
- if (!*nr_labels_outstanding) {
- log_error(INTERNAL_ERROR "_process_label_data called too many times");
- return;
+ if (lvmetad_used())
+ return 1;
+
+ dm_list_init(&devs);
+
+ if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, vgid)))
+ return_0;
+
+ /*
+ * When the VG metadata is from an independent location,
+ * then rescanning the devices in the VG won't find the
+ * metadata, and will destroy the vginfo/info associations
+ * that were created during label scan when the
+ * independent locations were read.
+ */
+ if (vginfo->independent_metadata_location)
+ return 1;
+
+ dm_list_iterate_items(info, &vginfo->infos) {
+ if (!(devl = dm_malloc(sizeof(*devl)))) {
+ log_error("device_list element allocation failed");
+ return 0;
+ }
+ devl->dev = info->dev;
+ dm_list_add(&devs, &devl->list);
}
- (*nr_labels_outstanding)--;
+ dm_list_iterate_items_safe(info, info2, &vginfo->infos)
+ lvmcache_del(info);
+
+ /* Dropping the last info struct is supposed to drop vginfo. */
+ if ((vginfo = lvmcache_vginfo_from_vgname(vgname, vgid)))
+ log_warn("VG info not dropped before rescan of %s", vgname);
+
+ /* FIXME: should we also rescan unused_duplicate_devs for devs
+ being rescanned here and then repeat resolving the duplicates? */
+
+ label_scan_devs(cmd, &devs);
+
+ return 1;
}
+/*
+ * Uses label_scan to populate lvmcache with 'vginfo' struct for each VG
+ * and associated 'info' structs for those VGs. Only VG summary information
+ * is used to assemble the vginfo/info during the scan, so the resulting
+ * representation of VG/PV state is incomplete and even incorrect.
+ * Specifically, PVs with no MDAs are considered orphans and placed in the
+ * orphan vginfo by lvmcache_label_scan. This is corrected during the
+ * processing phase as each vg_read() uses VG metadata for each VG to correct
+ * the lvmcache state, i.e. it moves no-MDA PVs from the orphan vginfo onto
+ * the correct vginfo. Once vg_read() is finished for all VGs, all of the
+ * incorrectly placed PVs should have been moved from the orphan vginfo
+ * onto their correct vginfo's, and the orphan vginfo should (in theory)
+ * represent only real orphan PVs. (Note: if lvmcache_label_scan is run
+ * after vg_read udpates to lvmcache state, then the lvmcache will be
+ * incorrect again, so do not run lvmcache_label_scan during the
+ * processing phase.)
+ *
+ * TODO: in this label scan phase, don't stash no-MDA PVs into the
+ * orphan VG. We know that's a fiction, and it can have harmful/damaging
+ * results. Instead, put them into a temporary list where they can be
+ * pulled from later when vg_read uses metadata to resolve which VG
+ * they actually belong to.
+ */
+
int lvmcache_label_scan(struct cmd_context *cmd)
{
struct dm_list del_cache_devs;
struct dm_list add_cache_devs;
struct lvmcache_info *info;
+ struct lvmcache_vginfo *vginfo;
struct device_list *devl;
- struct dev_iter *iter;
- struct device *dev;
struct format_type *fmt;
- int dev_count = 0;
- int nr_labels_outstanding = 0;
+ int vginfo_count = 0;
int r = 0;
- if (lvmetad_used())
+ if (lvmetad_used()) {
+ if (!label_scan_setup_bcache())
+ return 0;
return 1;
+ }
+
+ log_debug_cache("Finding VG info");
/* Avoid recursion when a PVID can't be found! */
if (_scanning_in_progress)
@@ -1138,43 +1193,26 @@ int lvmcache_label_scan(struct cmd_context *cmd)
goto out;
}
- if (_has_scanned && !_force_label_scan) {
- r = _scan_invalid();
- goto out;
- }
-
- if (_force_label_scan && (cmd->full_filter && !cmd->full_filter->use_count) && !refresh_filters(cmd))
- goto_out;
-
- if (!cmd->full_filter || !(iter = dev_iter_create(cmd->full_filter, _force_label_scan))) {
- log_error("dev_iter creation failed");
+ if (!cmd->full_filter) {
+ log_error("label scan is missing full filter");
goto out;
}
- log_very_verbose("Scanning device labels");
-
/*
* Duplicates found during this label scan are added to _found_duplicate_devs().
*/
_destroy_duplicate_device_list(&_found_duplicate_devs);
- while ((dev = dev_iter_get(iter))) {
- log_debug_io("Scanning device %s", dev_name(dev));
- nr_labels_outstanding++;
- if (!label_read_callback(dev, UINT64_C(0), AIO_SUPPORTED_CODE_PATH, _process_label_data, &nr_labels_outstanding))
- nr_labels_outstanding--;
- dev_count++;
- }
-
- dev_iter_destroy(iter);
-
- while (nr_labels_outstanding) {
- log_very_verbose("Scanned %d device labels (%d outstanding)", dev_count, nr_labels_outstanding);
- if (!dev_async_getevents())
- return_0;
- }
-
- log_very_verbose("Scanned %d device labels (%d outstanding)", dev_count, nr_labels_outstanding);
+ /*
+ * Do the actual scanning. This populates lvmcache
+ * with infos/vginfos based on reading headers from
+ * each device, and a vg summary from each mda.
+ *
+ * Note that this will *skip* scanning a device if
+ * an info struct already exists in lvmcache for
+ * the device.
+ */
+ label_scan(cmd);
/*
* _choose_preferred_devs() returns:
@@ -1198,6 +1236,8 @@ int lvmcache_label_scan(struct cmd_context *cmd)
dm_list_init(&del_cache_devs);
dm_list_init(&add_cache_devs);
+ log_debug_cache("Resolving duplicate devices");
+
_choose_preferred_devs(cmd, &del_cache_devs, &add_cache_devs);
dm_list_iterate_items(devl, &del_cache_devs) {
@@ -1208,152 +1248,33 @@ int lvmcache_label_scan(struct cmd_context *cmd)
dm_list_iterate_items(devl, &add_cache_devs) {
log_debug_cache("Rescan preferred device %s for lvmcache", dev_name(devl->dev));
- (void) label_read(devl->dev, NULL, UINT64_C(0));
+ label_read(devl->dev, NULL, UINT64_C(0));
}
dm_list_splice(&_unused_duplicate_devs, &del_cache_devs);
}
- _has_scanned = 1;
-
/* Perform any format-specific scanning e.g. text files */
if (cmd->independent_metadata_areas)
dm_list_iterate_items(fmt, &cmd->formats)
if (fmt->ops->scan && !fmt->ops->scan(fmt, NULL))
goto out;
- /*
- * If we are a long-lived process, write out the updated persistent
- * device cache for the benefit of short-lived processes.
- */
- if (_force_label_scan && cmd->is_long_lived &&
- cmd->dump_filter && cmd->full_filter && cmd->full_filter->dump &&
- !cmd->full_filter->dump(cmd->full_filter, cmd->mem, 0))
- stack;
-
r = 1;
out:
_scanning_in_progress = 0;
- _force_label_scan = 0;
-
- return r;
-}
-
-struct volume_group *lvmcache_get_vg(struct cmd_context *cmd, const char *vgname,
- const char *vgid, unsigned precommitted)
-{
- struct lvmcache_vginfo *vginfo;
- struct volume_group *vg = NULL;
- struct format_instance *fid;
- struct format_instance_ctx fic;
- /*
- * We currently do not store precommitted metadata in lvmetad at
- * all. This means that any request for precommitted metadata is served
- * using the classic scanning mechanics, and read from disk or from
- * lvmcache.
- */
- if (lvmetad_used() && !precommitted) {
- /* Still serve the locally cached VG if available */
- if (vgid && (vginfo = lvmcache_vginfo_from_vgid(vgid)) &&
- vginfo->vgmetadata && (vg = vginfo->cached_vg))
- goto out;
- return lvmetad_vg_lookup(cmd, vgname, vgid);
+ dm_list_iterate_items(vginfo, &_vginfos) {
+ if (is_orphan_vg(vginfo->vgname))
+ continue;
+ vginfo_count++;
}
- if (!vgid || !(vginfo = lvmcache_vginfo_from_vgid(vgid)) || !vginfo->vgmetadata)
- return NULL;
-
- if (!_vginfo_is_valid(vginfo))
- return NULL;
-
- /*
- * Don't return cached data if either:
- * (i) precommitted metadata is requested but we don't have it cached
- * - caller should read it off disk;
- * (ii) live metadata is requested but we have precommitted metadata cached
- * and no devices are suspended so caller may read it off disk.
- *
- * If live metadata is requested but we have precommitted metadata cached
- * and devices are suspended, we assume this precommitted metadata has
- * already been preloaded and committed so it's OK to return it as live.
- * Note that we do not clear the PRECOMMITTED flag.
- */
- if ((precommitted && !vginfo->precommitted) ||
- (!precommitted && vginfo->precommitted && !critical_section()))
- return NULL;
-
- /* Use already-cached VG struct when available */
- if ((vg = vginfo->cached_vg) && !vginfo->cached_vg_invalidated)
- goto out;
-
- release_vg(vginfo->cached_vg);
-
- fic.type = FMT_INSTANCE_MDAS | FMT_INSTANCE_AUX_MDAS;
- fic.context.vg_ref.vg_name = vginfo->vgname;
- fic.context.vg_ref.vg_id = vgid;
- if (!(fid = vginfo->fmt->ops->create_instance(vginfo->fmt, &fic)))
- return_NULL;
-
- /* Build config tree from vgmetadata, if not yet cached */
- if (!vginfo->cft &&
- !(vginfo->cft =
- config_tree_from_string_without_dup_node_check(vginfo->vgmetadata)))
- goto_bad;
-
- if (!(vg = import_vg_from_config_tree(vginfo->cft, fid)))
- goto_bad;
-
- /* Cache VG struct for reuse */
- vginfo->cached_vg = vg;
- vginfo->holders = 1;
- vginfo->vg_use_count = 0;
- vginfo->cached_vg_invalidated = 0;
- vg->vginfo = vginfo;
-
- if (!dm_pool_lock(vg->vgmem, detect_internal_vg_cache_corruption()))
- goto_bad;
-
-out:
- vginfo->holders++;
- vginfo->vg_use_count++;
- log_debug_cache("Using cached %smetadata for VG %s with %u holder(s).",
- vginfo->precommitted ? "pre-committed " : "",
- vginfo->vgname, vginfo->holders);
-
- return vg;
-
-bad:
- _free_cached_vgmetadata(vginfo);
- return NULL;
-}
-
-// #if 0
-int lvmcache_vginfo_holders_dec_and_test_for_zero(struct lvmcache_vginfo *vginfo)
-{
- log_debug_cache("VG %s decrementing %d holder(s) at %p.",
- vginfo->cached_vg->name, vginfo->holders, vginfo->cached_vg);
-
- if (--vginfo->holders)
- return 0;
-
- if (vginfo->vg_use_count > 1)
- log_debug_cache("VG %s reused %d times.",
- vginfo->cached_vg->name, vginfo->vg_use_count);
-
- /* Debug perform crc check only when it's been used more then once */
- if (!dm_pool_unlock(vginfo->cached_vg->vgmem,
- detect_internal_vg_cache_corruption() &&
- (vginfo->vg_use_count > 1)))
- stack;
-
- vginfo->cached_vg->vginfo = NULL;
- vginfo->cached_vg = NULL;
+ log_debug_cache("Found VG info for %d VGs", vginfo_count);
- return 1;
+ return r;
}
-// #endif
int lvmcache_get_vgnameids(struct cmd_context *cmd, int include_internal,
struct dm_list *vgnameids)
@@ -1361,8 +1282,6 @@ int lvmcache_get_vgnameids(struct cmd_context *cmd, int include_internal,
struct vgnameid_list *vgnl;
struct lvmcache_vginfo *vginfo;
- lvmcache_label_scan(cmd);
-
dm_list_iterate_items(vginfo, &_vginfos) {
if (!include_internal && is_orphan_vg(vginfo->vgname))
continue;
@@ -1467,61 +1386,45 @@ struct dm_list *lvmcache_get_pvids(struct cmd_context *cmd, const char *vgname,
return pvids;
}
-static struct device *_device_from_pvid(const struct id *pvid,
- uint64_t *label_sector)
+int lvmcache_get_vg_devs(struct cmd_context *cmd,
+ struct lvmcache_vginfo *vginfo,
+ struct dm_list *devs)
{
struct lvmcache_info *info;
- struct label *label;
+ struct device_list *devl;
- if ((info = lvmcache_info_from_pvid((const char *) pvid, NULL, 0))) {
- if (lvmetad_used()) {
- if (info->label && label_sector)
- *label_sector = info->label->sector;
- return info->dev;
- }
+ dm_list_iterate_items(info, &vginfo->infos) {
+ if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
+ return_0;
- if (label_read(info->dev, &label, UINT64_C(0))) {
- info = (struct lvmcache_info *) label->info;
- if (id_equal(pvid, (struct id *) &info->dev->pvid)) {
- if (label_sector)
- *label_sector = label->sector;
- return info->dev;
- }
- }
+ devl->dev = info->dev;
+ dm_list_add(devs, &devl->list);
}
- return NULL;
+ return 1;
}
-struct device *lvmcache_device_from_pvid(struct cmd_context *cmd, const struct id *pvid,
- unsigned *scan_done_once, uint64_t *label_sector)
+static struct device *_device_from_pvid(const struct id *pvid, uint64_t *label_sector)
{
- struct device *dev;
-
- /* Already cached ? */
- dev = _device_from_pvid(pvid, label_sector);
- if (dev)
- return dev;
-
- lvmcache_label_scan(cmd);
+ struct lvmcache_info *info;
- /* Try again */
- dev = _device_from_pvid(pvid, label_sector);
- if (dev)
- return dev;
+ if ((info = lvmcache_info_from_pvid((const char *) pvid, NULL, 0))) {
+ if (info->label && label_sector)
+ *label_sector = info->label->sector;
+ return info->dev;
+ }
- if (critical_section() || (scan_done_once && *scan_done_once))
- return NULL;
+ return NULL;
+}
- lvmcache_force_next_label_scan();
- lvmcache_label_scan(cmd);
- if (scan_done_once)
- *scan_done_once = 1;
+struct device *lvmcache_device_from_pvid(struct cmd_context *cmd, const struct id *pvid, uint64_t *label_sector)
+{
+ struct device *dev;
- /* Try again */
dev = _device_from_pvid(pvid, label_sector);
if (dev)
return dev;
+ log_debug_devs("No device with uuid %s.", (const char *)pvid);
return NULL;
}
@@ -1558,8 +1461,6 @@ static int _free_vginfo(struct lvmcache_vginfo *vginfo)
struct lvmcache_vginfo *primary_vginfo, *vginfo2;
int r = 1;
- _free_cached_vgmetadata(vginfo);
-
vginfo2 = primary_vginfo = lvmcache_vginfo_from_vgname(vginfo->vgname, NULL);
if (vginfo == primary_vginfo) {
@@ -1582,6 +1483,7 @@ static int _free_vginfo(struct lvmcache_vginfo *vginfo)
dm_free(vginfo->system_id);
dm_free(vginfo->vgname);
dm_free(vginfo->creation_host);
+ _suspended_vg_free(vginfo, 1, 1);
if (*vginfo->vgid && _vgid_hash &&
lvmcache_vginfo_from_vgid(vginfo->vgid) == vginfo)
@@ -1625,6 +1527,14 @@ void lvmcache_del(struct lvmcache_info *info)
dm_free(info);
}
+void lvmcache_del_dev(struct device *dev)
+{
+ struct lvmcache_info *info;
+
+ if ((info = lvmcache_info_from_pvid((const char *)dev->pvid, dev, 0)))
+ lvmcache_del(info);
+}
+
/*
* vginfo must be info->vginfo unless info is NULL (orphans)
*/
@@ -1761,10 +1671,8 @@ static int _lvmcache_update_vgname(struct lvmcache_info *info,
uint32_t vgstatus, const char *creation_host,
const struct format_type *fmt)
{
- struct lvmcache_vginfo *vginfo, *primary_vginfo, *orphan_vginfo;
- struct lvmcache_info *info2, *info3;
+ struct lvmcache_vginfo *vginfo, *primary_vginfo;
char mdabuf[32];
- // struct lvmcache_vginfo *old_vginfo, *next;
if (!vgname || (info && info->vginfo && !strcmp(info->vginfo->vgname, vgname)))
return 1;
@@ -1773,44 +1681,12 @@ static int _lvmcache_update_vgname(struct lvmcache_info *info,
if (info)
_drop_vginfo(info, info->vginfo);
- /* Get existing vginfo or create new one */
if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, vgid))) {
-/*** FIXME - vginfo ends up duplicated instead of renamed.
- // Renaming? This lookup fails.
- if ((vginfo = vginfo_from_vgid(vgid))) {
- next = vginfo->next;
- old_vginfo = vginfo_from_vgname(vginfo->vgname, NULL);
- if (old_vginfo == vginfo) {
- dm_hash_remove(_vgname_hash, old_vginfo->vgname);
- if (old_vginfo->next) {
- if (!dm_hash_insert(_vgname_hash, old_vginfo->vgname, old_vginfo->next)) {
- log_error("vg hash re-insertion failed: %s",
- old_vginfo->vgname);
- return 0;
- }
- }
- } else do {
- if (old_vginfo->next == vginfo) {
- old_vginfo->next = vginfo->next;
- break;
- }
- } while ((old_vginfo = old_vginfo->next));
- vginfo->next = NULL;
-
- dm_free(vginfo->vgname);
- if (!(vginfo->vgname = dm_strdup(vgname))) {
- log_error("cache vgname alloc failed for %s", vgname);
- return 0;
- }
+ /*
+ * Create a vginfo struct for this VG and put the vginfo
+ * into the hash table.
+ */
- // Rename so can assume new name does not already exist
- if (!dm_hash_insert(_vgname_hash, vginfo->vgname, vginfo->next)) {
- log_error("vg hash re-insertion failed: %s",
- vginfo->vgname);
- return 0;
- }
- } else {
-***/
if (!(vginfo = dm_zalloc(sizeof(*vginfo)))) {
log_error("lvmcache_update_vgname: list alloc failed");
return 0;
@@ -1823,52 +1699,24 @@ static int _lvmcache_update_vgname(struct lvmcache_info *info,
dm_list_init(&vginfo->infos);
/*
- * If we're scanning and there's an invalidated entry, remove it.
- * Otherwise we risk bogus warnings of duplicate VGs.
+ * A different VG (different uuid) can exist with the same name.
+ * In this case, the two VGs will have separate vginfo structs,
+ * but the second will be linked onto the existing vginfo->next,
+ * not in the hash.
*/
- while ((primary_vginfo = lvmcache_vginfo_from_vgname(vgname, NULL)) &&
- _scanning_in_progress && _vginfo_is_invalid(primary_vginfo)) {
- orphan_vginfo = lvmcache_vginfo_from_vgname(primary_vginfo->fmt->orphan_vg_name, NULL);
- if (!orphan_vginfo) {
- log_error(INTERNAL_ERROR "Orphan vginfo %s lost from cache.",
- primary_vginfo->fmt->orphan_vg_name);
- dm_free(vginfo->vgname);
- dm_free(vginfo);
- return 0;
- }
- dm_list_iterate_items_safe(info2, info3, &primary_vginfo->infos) {
- _vginfo_detach_info(info2);
- _vginfo_attach_info(orphan_vginfo, info2);
- if (info2->mdas.n)
- sprintf(mdabuf, " with %u mdas",
- dm_list_size(&info2->mdas));
- else
- mdabuf[0] = '\0';
- log_debug_cache("lvmcache: %s: now in VG %s%s%s%s%s",
- dev_name(info2->dev),
- vgname, orphan_vginfo->vgid[0] ? " (" : "",
- orphan_vginfo->vgid[0] ? orphan_vginfo->vgid : "",
- orphan_vginfo->vgid[0] ? ")" : "", mdabuf);
- }
+ primary_vginfo = lvmcache_vginfo_from_vgname(vgname, NULL);
- if (!_drop_vginfo(NULL, primary_vginfo))
- return_0;
- }
-
- if (!_insert_vginfo(vginfo, vgid, vgstatus, creation_host,
- primary_vginfo)) {
+ if (!_insert_vginfo(vginfo, vgid, vgstatus, creation_host, primary_vginfo)) {
dm_free(vginfo->vgname);
dm_free(vginfo);
return 0;
}
+
/* Ensure orphans appear last on list_iterate */
if (is_orphan_vg(vgname))
dm_list_add(&_vginfos, &vginfo->list);
else
dm_list_add_h(&_vginfos, &vginfo->list);
-/***
- }
-***/
}
if (info)
@@ -1969,28 +1817,6 @@ out:
return 1;
}
-static int _lvmcache_update_vg_mda_info(struct lvmcache_info *info, uint32_t mda_checksum,
- size_t mda_size)
-{
- if (!info || !info->vginfo || !mda_size)
- return 1;
-
- if (info->vginfo->mda_checksum == mda_checksum || info->vginfo->mda_size == mda_size)
- return 1;
-
- info->vginfo->mda_checksum = mda_checksum;
- info->vginfo->mda_size = mda_size;
-
- /* FIXME Add checksum index */
-
- log_debug_cache("lvmcache %s: VG %s: stored metadata checksum 0x%08"
- PRIx32 " with size %" PRIsize_t ".",
- dev_name(info->dev), info->vginfo->vgname,
- mda_checksum, mda_size);
-
- return 1;
-}
-
int lvmcache_add_orphan_vginfo(const char *vgname, struct format_type *fmt)
{
if (!_lock_hash && !lvmcache_init()) {
@@ -2001,10 +1827,18 @@ int lvmcache_add_orphan_vginfo(const char *vgname, struct format_type *fmt)
return _lvmcache_update_vgname(NULL, vgname, vgname, 0, "", fmt);
}
-int lvmcache_update_vgname_and_id(struct lvmcache_info *info, const struct lvmcache_vgsummary *vgsummary)
+/*
+ * FIXME: get rid of other callers of this function which call it
+ * in odd cases to "fix up" some bit of lvmcache state. Make those
+ * callers fix up what they need to directly, and leave this function
+ * with one purpose and caller.
+ */
+
+int lvmcache_update_vgname_and_id(struct lvmcache_info *info, struct lvmcache_vgsummary *vgsummary)
{
const char *vgname = vgsummary->vgname;
const char *vgid = (char *)&vgsummary->vgid;
+ struct lvmcache_vginfo *vginfo;
if (!vgname && !info->vginfo) {
log_error(INTERNAL_ERROR "NULL vgname handed to cache");
@@ -2019,22 +1853,80 @@ int lvmcache_update_vgname_and_id(struct lvmcache_info *info, const struct lvmca
!is_orphan_vg(info->vginfo->vgname) && critical_section())
return 1;
- /* If making a PV into an orphan, any cached VG metadata may become
- * invalid, incorrectly still referencing device structs.
- * (Example: pvcreate -ff) */
- if (is_orphan_vg(vgname) && info->vginfo && !is_orphan_vg(info->vginfo->vgname))
- info->vginfo->cached_vg_invalidated = 1;
-
- /* If moving PV from orphan to real VG, always mark it valid */
- if (!is_orphan_vg(vgname))
- info->status &= ~CACHE_INVALID;
-
- if (!_lvmcache_update_vgname(info, vgname, vgid, vgsummary->vgstatus,
- vgsummary->creation_host, info->fmt) ||
- !_lvmcache_update_vgid(info, info->vginfo, vgid) ||
- !_lvmcache_update_vgstatus(info, vgsummary->vgstatus, vgsummary->creation_host, vgsummary->lock_type, vgsummary->system_id) ||
- !_lvmcache_update_vg_mda_info(info, vgsummary->mda_checksum, vgsummary->mda_size))
- return_0;
+ /*
+ * Creates a new vginfo struct for this vgname/vgid if none exists,
+ * and attaches the info struct for the dev to the vginfo.
+ * Puts the vginfo into the vgname hash table.
+ */
+ if (!_lvmcache_update_vgname(info, vgname, vgid, vgsummary->vgstatus, vgsummary->creation_host, info->fmt)) {
+ log_error("Failed to update VG %s info in lvmcache.", vgname);
+ return 0;
+ }
+
+ /*
+ * Puts the vginfo into the vgid hash table.
+ */
+ if (!_lvmcache_update_vgid(info, info->vginfo, vgid)) {
+ log_error("Failed to update VG %s info in lvmcache.", vgname);
+ return 0;
+ }
+
+ /*
+ * FIXME: identify which case this is and why this is needed, then
+ * change that so it doesn't use this function and we can remove
+ * this special case.
+ * (I think this distinguishes the scan path, where these things
+ * are set from the vg_read path where lvmcache_update_vg() is
+ * called which calls this function without seqno/mda_size/mda_checksum.)
+ */
+ if (!vgsummary->seqno && !vgsummary->mda_size && !vgsummary->mda_checksum)
+ return 1;
+
+ if (!(vginfo = info->vginfo))
+ return 1;
+
+ if (!vginfo->seqno) {
+ vginfo->seqno = vgsummary->seqno;
+
+ log_debug_cache("lvmcache %s: VG %s: set seqno to %d",
+ dev_name(info->dev), vginfo->vgname, vginfo->seqno);
+
+ } else if (vgsummary->seqno != vginfo->seqno) {
+ log_warn("Scan of VG %s from %s found metadata seqno %d vs previous %d.",
+ vgname, dev_name(info->dev), vgsummary->seqno, vginfo->seqno);
+ vginfo->scan_summary_mismatch = 1;
+ /* If we don't return success, this dev info will be removed from lvmcache,
+ and then we won't be able to rescan it or repair it. */
+ return 1;
+ }
+
+ if (!vginfo->mda_size) {
+ vginfo->mda_checksum = vgsummary->mda_checksum;
+ vginfo->mda_size = vgsummary->mda_size;
+
+ log_debug_cache("lvmcache %s: VG %s: set mda_checksum to %x mda_size to %zu",
+ dev_name(info->dev), vginfo->vgname,
+ vginfo->mda_checksum, vginfo->mda_size);
+
+ } else if ((vginfo->mda_size != vgsummary->mda_size) || (vginfo->mda_checksum != vgsummary->mda_checksum)) {
+ log_warn("Scan of VG %s from %s found mda_checksum %x mda_size %zu vs previous %x %zu",
+ vgname, dev_name(info->dev), vgsummary->mda_checksum, vgsummary->mda_size,
+ vginfo->mda_checksum, vginfo->mda_size);
+ vginfo->scan_summary_mismatch = 1;
+ /* If we don't return success, this dev info will be removed from lvmcache,
+ and then we won't be able to rescan it or repair it. */
+ return 1;
+ }
+
+ /*
+ * If a dev has an unmatching checksum, ignore the other
+ * info from it, keeping the info we already saved.
+ */
+ if (!_lvmcache_update_vgstatus(info, vgsummary->vgstatus, vgsummary->creation_host,
+ vgsummary->lock_type, vgsummary->system_id)) {
+ log_error("Failed to update VG %s info in lvmcache.", vgname);
+ return 0;
+ }
return 1;
}
@@ -2060,10 +1952,6 @@ int lvmcache_update_vg(struct volume_group *vg, unsigned precommitted)
return_0;
}
- /* store text representation of vg to cache */
- if (vg->cmd->current_settings.cache_vgmetadata)
- _store_metadata(vg, precommitted);
-
return 1;
}
@@ -2233,8 +2121,6 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller,
}
}
- info->status |= CACHE_INVALID;
-
/*
* Add or update the _pvid_hash mapping, pvid to info.
*/
@@ -2310,7 +2196,8 @@ static void _lvmcache_destroy_lockname(struct dm_hash_node *n)
void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans, int reset)
{
struct dm_hash_node *n;
- log_verbose("Wiping internal VG cache");
+
+ log_debug_cache("Dropping VG info");
_has_scanned = 0;
@@ -2397,56 +2284,29 @@ int lvmcache_fid_add_mdas_vg(struct lvmcache_vginfo *vginfo, struct format_insta
return 1;
}
-static int _get_pv_if_in_vg(struct lvmcache_info *info,
- struct physical_volume *pv)
-{
- char vgname[NAME_LEN + 1];
- char vgid[ID_LEN + 1];
-
- if (info->vginfo && info->vginfo->vgname &&
- !is_orphan_vg(info->vginfo->vgname)) {
- /*
- * get_pv_from_vg_by_id() may call
- * lvmcache_label_scan() and drop cached
- * vginfo so make a local copy of string.
- */
- (void) dm_strncpy(vgname, info->vginfo->vgname, sizeof(vgname));
- memcpy(vgid, info->vginfo->vgid, sizeof(vgid));
-
- if (get_pv_from_vg_by_id(info->fmt, vgname, vgid,
- info->dev->pvid, pv))
- return 1;
- }
-
- return 0;
-}
-
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)
{
struct data_area_list *da;
-
- /* Have we already cached vgname? */
- if (!scan_label_only && _get_pv_if_in_vg(info, pv))
- return 1;
-
- /* Perform full scan (just the first time) and try again */
- if (!scan_label_only && !critical_section() && !full_scan_done()) {
- lvmcache_force_next_label_scan();
- lvmcache_label_scan(info->fmt->cmd);
-
- if (_get_pv_if_in_vg(info, pv))
- return 1;
+
+ if (!info->label) {
+ log_error("No cached label for orphan PV %s", pv_dev_name(pv));
+ return 0;
}
- /* Orphan */
+ pv->label_sector = info->label->sector;
pv->dev = info->dev;
pv->fmt = info->fmt;
pv->size = info->device_size >> SECTOR_SHIFT;
pv->vg_name = FMT_TEXT_ORPHAN_VG_NAME;
memcpy(&pv->id, &info->dev->pvid, sizeof(pv->id));
+ if (!pv->size) {
+ log_error("PV %s size is zero.", dev_name(info->dev));
+ return 0;
+ }
+
/* Currently only support exactly one data area */
if (dm_list_size(&info->das) != 1) {
log_error("Must be exactly one data area (found %d) on PV %s",
@@ -2619,6 +2479,25 @@ int lvmcache_foreach_ba(struct lvmcache_info *info,
return 1;
}
+struct label *lvmcache_get_dev_label(struct device *dev)
+{
+ struct lvmcache_info *info;
+
+ if ((info = lvmcache_info_from_pvid(dev->pvid, NULL, 0))) {
+ /* dev would be different for a duplicate */
+ if (info->dev == dev)
+ return info->label;
+ }
+ return NULL;
+}
+
+int lvmcache_has_dev_info(struct device *dev)
+{
+ if (lvmcache_info_from_pvid(dev->pvid, NULL, 0))
+ return 1;
+ return 0;
+}
+
/*
* The lifetime of the label returned is tied to the lifetime of the
* lvmcache_info which is the same as lvmcache itself.
@@ -2627,10 +2506,6 @@ struct label *lvmcache_get_label(struct lvmcache_info *info) {
return info->label;
}
-void lvmcache_make_valid(struct lvmcache_info *info) {
- info->status &= ~CACHE_INVALID;
-}
-
uint64_t lvmcache_device_size(struct lvmcache_info *info) {
return info->device_size;
}
@@ -2682,6 +2557,14 @@ int lvmcache_vgid_is_cached(const char *vgid) {
return 1;
}
+void lvmcache_set_independent_location(const char *vgname)
+{
+ struct lvmcache_vginfo *vginfo;
+
+ if ((vginfo = lvmcache_vginfo_from_vgname(vgname, NULL)))
+ vginfo->independent_metadata_location = 1;
+}
+
/*
* Return true iff it is impossible to find out from this info alone whether the
* PV in question is or is not an orphan.
@@ -2717,6 +2600,7 @@ int lvmcache_lookup_mda(struct lvmcache_vgsummary *vgsummary)
vgsummary->vgname = vginfo->vgname;
vgsummary->creation_host = vginfo->creation_host;
vgsummary->vgstatus = vginfo->status;
+ vgsummary->seqno = vginfo->seqno;
/* vginfo->vgid has 1 extra byte then vgsummary->vgid */
memcpy(&vgsummary->vgid, vginfo->vgid, sizeof(vgsummary->vgid));
@@ -2777,3 +2661,47 @@ int lvmcache_vg_is_foreign(struct cmd_context *cmd, const char *vgname, const ch
return ret;
}
+/*
+ * Example of reading four devs in sequence from the same VG:
+ *
+ * dev1:
+ * lvmcache: creates vginfo with initial values
+ *
+ * dev2: all checksums match.
+ * mda_header checksum matches vginfo from dev1
+ * metadata checksum matches vginfo from dev1
+ * metadata is not parsed, and the vgsummary values copied
+ * from lvmcache from dev1 and passed back to lvmcache for dev2.
+ * lvmcache: attach info for dev2 to existing vginfo
+ *
+ * dev3: mda_header and metadata have unmatching checksums.
+ * mda_header checksum matches vginfo from dev1
+ * metadata checksum doesn't match vginfo from dev1
+ * produces read error in config.c
+ * lvmcache: info for dev3 is deleted, FIXME: use a defective state
+ *
+ * dev4: mda_header and metadata have matching checksums, but
+ * does not match checksum in lvmcache from prev dev.
+ * mda_header checksum doesn't match vginfo from dev1
+ * lvmcache_lookup_mda returns 0, no vgname, no checksum_only
+ * lvmcache: update_vgname_and_id sees checksum from dev4 does not
+ * match vginfo from dev1, so vginfo->scan_summary_mismatch is set.
+ * attach info for dev4 to existing vginfo
+ *
+ * dev5: config parsing error.
+ * lvmcache: info for dev5 is deleted, FIXME: use a defective state
+ */
+
+int lvmcache_scan_mismatch(struct cmd_context *cmd, const char *vgname, const char *vgid)
+{
+ struct lvmcache_vginfo *vginfo;
+
+ if (!vgname || !vgid)
+ return 1;
+
+ if ((vginfo = lvmcache_vginfo_from_vgid(vgid)))
+ return vginfo->scan_summary_mismatch;
+
+ return 1;
+}
+
diff --git a/lib/cache/lvmcache.h b/lib/cache/lvmcache.h
index 3c76b780b..ad478bd27 100644
--- a/lib/cache/lvmcache.h
+++ b/lib/cache/lvmcache.h
@@ -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
diff --git a/lib/cache/lvmetad.c b/lib/cache/lvmetad.c
index 589b48eae..ed0bcde32 100644
--- a/lib/cache/lvmetad.c
+++ b/lib/cache/lvmetad.c
@@ -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. */
@@ -1784,6 +1788,33 @@ static int _lvmetad_pvscan_single(struct metadata_area *mda, void *baton)
}
/*
+ * 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.
* This is limited to changes that only affect the vg (not global state like
@@ -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 (!devl->dev)
- continue;
+ 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);
+ }
+ }
- log_debug_lvmetad("Rescan VG %s scanning %s.", vg->name, dev_name(devl->dev));
+ fic.type = FMT_INSTANCE_MDAS | FMT_INSTANCE_AUX_MDAS;
+ fic.context.vg_ref.vg_name = vg->name;
+ fic.context.vg_ref.vg_id = vgid;
- 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));
+ retry_reads:
- if ((info = lvmcache_info_from_pvid(devl->dev->pvid, NULL, 0)))
- lvmcache_del(info);
+ 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;
+ }
- dm_list_move(&pvs_drop, &devl->list);
- continue;
- }
+ /* FIXME: not sure if this is necessary */
+ fid->ref_count++;
- info = (struct lvmcache_info *) label->info;
+ baton.fid = fid;
+ baton.cmd = cmd;
- baton.vg = NULL;
- baton.fid = lvmcache_fmt(info)->ops->create_instance(lvmcache_fmt(info), &fic);
- if (!baton.fid)
- return_NULL;
+ /*
+ * 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.)
+ */
- 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);
+ /*
+ * 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 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;
}
+ baton.vg = NULL;
+
/*
* 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 (!(vgmeta = export_vg_to_config_tree(baton.vg))) {
- log_error("VG export to config tree failed");
- release_vg(baton.vg);
- return NULL;
+ 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.");
+
+ /* 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)
- 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++;
+ /* 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 (!(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)) {
+ 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);
+
+ 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);
- 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 (missing_devs) {
- if (vgmeta_ret)
- dm_config_destroy(vgmeta_ret);
- return_NULL;
+ 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;
+ }
+
+ 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;
}
- info = (struct lvmcache_info *) label->info;
+ 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)
diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c
index b613b8f72..a54f4d7b5 100644
--- a/lib/commands/toolcontext.c
+++ b/lib/commands/toolcontext.c
@@ -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);
diff --git a/lib/commands/toolcontext.h b/lib/commands/toolcontext.h
index 89d1088ee..24742641c 100644
--- a/lib/commands/toolcontext.h
+++ b/lib/commands/toolcontext.h
@@ -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.
*/
diff --git a/lib/config/config.c b/lib/config/config.c
index 97c5db8a1..ad816c209 100644
--- a/lib/config/config.c
+++ b/lib/config/config.c
@@ -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;
- }
-
- if (!(pcfp = dm_pool_zalloc(mem, sizeof(*pcfp)))) {
- log_debug("config_file_read_fd: process_config_file_params struct allocation failed");
- goto bad;
+ return 0;
}
- 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;
- }
- _process_config_file_buffer(0, ioflags, pcfp, fb + mmap_offset);
- r = pcfp->ret;
- /* unmap the file */
- if (munmap(fb, size + mmap_offset)) {
- log_sys_error("munmap", dev_name(dev));
- r = 0;
+ goto out;
}
+ fb = fb + mmap_offset;
} else {
- if (circular) {
- if (!(buf = dev_read_circular(dev, (uint64_t) offset, size, (uint64_t) offset2, size2, reason)))
+ 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;
- _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;
+ if (!dm_config_parse(cft, fb, fe))
+ goto_out;
}
- r = pcfp->ret;
}
-out:
- return r;
+ r = 1;
-bad:
- if (config_file_read_fd_callback)
- config_file_read_fd_callback(1, ioflags, config_file_read_fd_context, NULL);
+ out:
+ if (!use_mmap)
+ dm_free(buf);
+ else {
+ /* unmap the file */
+ if (munmap(fb - mmap_offset, size + mmap_offset)) {
+ log_sys_error("munmap", dev_name(dev));
+ r = 0;
+ }
+ }
- return 0;
+ return r;
}
-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))
diff --git a/lib/config/config.h b/lib/config/config.h
index 4517cb7b0..d01306b36 100644
--- a/lib/config/config.h
+++ b/lib/config/config.h
@@ -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,
diff --git a/lib/config/config_settings.h b/lib/config/config_settings.h
index f1db79786..b778f4c1c 100644
--- a/lib/config/config_settings.h
+++ b/lib/config/config_settings.h
@@ -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"
diff --git a/lib/config/defaults.h b/lib/config/defaults.h
index 1c730a9ce..7cebd8481 100644
--- a/lib/config/defaults.h
+++ b/lib/config/defaults.h
@@ -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
diff --git a/lib/device/bcache.c b/lib/device/bcache.c
new file mode 100644
index 000000000..ea8f70299
--- /dev/null
+++ b/lib/device/bcache.c
@@ -0,0 +1,1182 @@
+/*
+ * 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
+ */
+
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <libaio.h>
+#include <unistd.h>
+#include <linux/fs.h>
+#include <sys/ioctl.h>
+#include <sys/user.h>
+
+#include "bcache.h"
+#include "dm-logging.h"
+#include "log.h"
+
+#define SECTOR_SHIFT 9L
+
+//----------------------------------------------------------------
+
+static void log_sys_warn(const char *syscall)
+{
+ log_warn("%s failed: %s", syscall, strerror(errno));
+}
+
+// Assumes the list is not empty.
+static inline struct dm_list *_list_pop(struct dm_list *head)
+{
+ struct dm_list *l;
+
+ l = head->n;
+ dm_list_del(l);
+ return l;
+}
+
+//----------------------------------------------------------------
+
+struct control_block {
+ struct dm_list list;
+ void *context;
+ struct iocb cb;
+};
+
+struct cb_set {
+ struct dm_list free;
+ struct dm_list allocated;
+ struct control_block *vec;
+} control_block_set;
+
+static struct cb_set *_cb_set_create(unsigned nr)
+{
+ int i;
+ struct cb_set *cbs = dm_malloc(sizeof(*cbs));
+
+ if (!cbs)
+ return NULL;
+
+ cbs->vec = dm_malloc(nr * sizeof(*cbs->vec));
+ if (!cbs->vec) {
+ dm_free(cbs);
+ return NULL;
+ }
+
+ dm_list_init(&cbs->free);
+ dm_list_init(&cbs->allocated);
+
+ for (i = 0; i < nr; i++)
+ dm_list_add(&cbs->free, &cbs->vec[i].list);
+
+ return cbs;
+}
+
+static void _cb_set_destroy(struct cb_set *cbs)
+{
+ // We know this is always called after a wait_all. So there should
+ // never be in flight IO.
+ if (!dm_list_empty(&cbs->allocated)) {
+ // bail out
+ log_error("async io still in flight");
+ return;
+ }
+
+ dm_free(cbs->vec);
+ dm_free(cbs);
+}
+
+static struct control_block *_cb_alloc(struct cb_set *cbs, void *context)
+{
+ struct control_block *cb;
+
+ if (dm_list_empty(&cbs->free))
+ return NULL;
+
+ cb = dm_list_item(_list_pop(&cbs->free), struct control_block);
+ cb->context = context;
+ dm_list_add(&cbs->allocated, &cb->list);
+
+ return cb;
+}
+
+static void _cb_free(struct cb_set *cbs, struct control_block *cb)
+{
+ dm_list_del(&cb->list);
+ dm_list_add_h(&cbs->free, &cb->list);
+}
+
+static struct control_block *_iocb_to_cb(struct iocb *icb)
+{
+ return dm_list_struct_base(icb, struct control_block, cb);
+}
+
+//----------------------------------------------------------------
+
+// FIXME: write a sync engine too
+struct async_engine {
+ struct io_engine e;
+ io_context_t aio_context;
+ struct cb_set *cbs;
+};
+
+static struct async_engine *_to_async(struct io_engine *e)
+{
+ return container_of(e, struct async_engine, e);
+}
+
+static void _async_destroy(struct io_engine *ioe)
+{
+ int r;
+ struct async_engine *e = _to_async(ioe);
+
+ _cb_set_destroy(e->cbs);
+
+ // io_destroy is really slow
+ r = io_destroy(e->aio_context);
+ if (r)
+ log_sys_warn("io_destroy");
+
+ dm_free(e);
+}
+
+static bool _async_issue(struct io_engine *ioe, enum dir d, int fd,
+ sector_t sb, sector_t se, void *data, void *context)
+{
+ int r;
+ struct iocb *cb_array[1];
+ struct control_block *cb;
+ struct async_engine *e = _to_async(ioe);
+
+ if (((uint64_t) data) & (PAGE_SIZE - 1)) {
+ log_warn("misaligned data buffer");
+ return false;
+ }
+
+ cb = _cb_alloc(e->cbs, context);
+ if (!cb) {
+ log_warn("couldn't allocate control block");
+ return false;
+ }
+
+ memset(&cb->cb, 0, sizeof(cb->cb));
+
+ cb->cb.aio_fildes = (int) fd;
+ cb->cb.u.c.buf = data;
+ cb->cb.u.c.offset = sb << SECTOR_SHIFT;
+ cb->cb.u.c.nbytes = (se - sb) << SECTOR_SHIFT;
+ cb->cb.aio_lio_opcode = (d == DIR_READ) ? IO_CMD_PREAD : IO_CMD_PWRITE;
+
+ cb_array[0] = &cb->cb;
+ do {
+ r = io_submit(e->aio_context, 1, cb_array);
+ } while (r == -EAGAIN);
+
+ if (r < 0) {
+ log_sys_warn("io_submit");
+ _cb_free(e->cbs, cb);
+ return false;
+ }
+
+ return true;
+}
+
+#define MAX_IO 1024
+#define MAX_EVENT 64
+
+static bool _async_wait(struct io_engine *ioe, io_complete_fn fn)
+{
+ int i, r;
+ struct io_event event[MAX_EVENT];
+ struct control_block *cb;
+ struct async_engine *e = _to_async(ioe);
+
+ memset(&event, 0, sizeof(event));
+ do {
+ r = io_getevents(e->aio_context, 1, MAX_EVENT, event, NULL);
+ } while (r == -EINTR);
+
+ if (r < 0) {
+ log_sys_warn("io_getevents");
+ return false;
+ }
+
+ for (i = 0; i < r; i++) {
+ struct io_event *ev = event + i;
+
+ cb = _iocb_to_cb((struct iocb *) ev->obj);
+
+ if (ev->res == cb->cb.u.c.nbytes)
+ fn((void *) cb->context, 0);
+
+ else if ((int) ev->res < 0)
+ fn(cb->context, (int) ev->res);
+
+ // FIXME: dct added this. a short read is ok?!
+ else if (ev->res >= (1 << SECTOR_SHIFT)) {
+ /* minimum acceptable read is 1 sector */
+ fn((void *) cb->context, 0);
+
+ } else {
+ fn(cb->context, -ENODATA);
+ }
+
+ _cb_free(e->cbs, cb);
+ }
+
+ return true;
+}
+
+static unsigned _async_max_io(struct io_engine *e)
+{
+ return MAX_IO;
+}
+
+struct io_engine *create_async_io_engine(void)
+{
+ int r;
+ struct async_engine *e = dm_malloc(sizeof(*e));
+
+ if (!e)
+ return NULL;
+
+ e->e.destroy = _async_destroy;
+ e->e.issue = _async_issue;
+ e->e.wait = _async_wait;
+ e->e.max_io = _async_max_io;
+
+ e->aio_context = 0;
+ r = io_setup(MAX_IO, &e->aio_context);
+ if (r < 0) {
+ log_warn("io_setup failed");
+ dm_free(e);
+ return NULL;
+ }
+
+ e->cbs = _cb_set_create(MAX_IO);
+ if (!e->cbs) {
+ log_warn("couldn't create control block set");
+ dm_free(e);
+ return NULL;
+ }
+
+ return &e->e;
+}
+
+//----------------------------------------------------------------
+
+#define MIN_BLOCKS 16
+#define WRITEBACK_LOW_THRESHOLD_PERCENT 33
+#define WRITEBACK_HIGH_THRESHOLD_PERCENT 66
+
+//----------------------------------------------------------------
+
+static void *_alloc_aligned(size_t len, size_t alignment)
+{
+ void *result = NULL;
+ int r = posix_memalign(&result, alignment, len);
+ if (r)
+ return NULL;
+
+ return result;
+}
+
+//----------------------------------------------------------------
+
+static bool _test_flags(struct block *b, unsigned bits)
+{
+ return (b->flags & bits) != 0;
+}
+
+static void _set_flags(struct block *b, unsigned bits)
+{
+ b->flags |= bits;
+}
+
+static void _clear_flags(struct block *b, unsigned bits)
+{
+ b->flags &= ~bits;
+}
+
+//----------------------------------------------------------------
+
+enum block_flags {
+ BF_IO_PENDING = (1 << 0),
+ BF_DIRTY = (1 << 1),
+};
+
+struct bcache {
+ sector_t block_sectors;
+ uint64_t nr_data_blocks;
+ uint64_t nr_cache_blocks;
+ unsigned max_io;
+
+ struct io_engine *engine;
+
+ void *raw_data;
+ struct block *raw_blocks;
+
+ /*
+ * Lists that categorise the blocks.
+ */
+ unsigned nr_locked;
+ unsigned nr_dirty;
+ unsigned nr_io_pending;
+
+ struct dm_list free;
+ struct dm_list errored;
+ struct dm_list dirty;
+ struct dm_list clean;
+ struct dm_list io_pending;
+
+ /*
+ * Hash table.
+ */
+ unsigned nr_buckets;
+ unsigned hash_mask;
+ struct dm_list *buckets;
+
+ /*
+ * Statistics
+ */
+ unsigned read_hits;
+ unsigned read_misses;
+ unsigned write_zeroes;
+ unsigned write_hits;
+ unsigned write_misses;
+ unsigned prefetches;
+};
+
+//----------------------------------------------------------------
+
+/* 2^63 + 2^61 - 2^57 + 2^54 - 2^51 - 2^18 + 1 */
+#define GOLDEN_RATIO_PRIME_64 0x9e37fffffffc0001UL
+
+static unsigned _hash(struct bcache *cache, int fd, uint64_t index)
+{
+ uint64_t h = (index << 10) & fd;
+ h *= GOLDEN_RATIO_PRIME_64;
+ return h & cache->hash_mask;
+}
+
+static struct block *_hash_lookup(struct bcache *cache, int fd, uint64_t index)
+{
+ struct block *b;
+ unsigned h = _hash(cache, fd, index);
+
+ dm_list_iterate_items_gen (b, cache->buckets + h, hash)
+ if (b->fd == fd && b->index == index)
+ return b;
+
+ return NULL;
+}
+
+static void _hash_insert(struct block *b)
+{
+ unsigned h = _hash(b->cache, b->fd, b->index);
+ dm_list_add_h(b->cache->buckets + h, &b->hash);
+}
+
+static inline void _hash_remove(struct block *b)
+{
+ dm_list_del(&b->hash);
+}
+
+/*
+ * Must return a power of 2.
+ */
+static unsigned _calc_nr_buckets(unsigned nr_blocks)
+{
+ unsigned r = 8;
+ unsigned n = nr_blocks / 4;
+
+ if (n < 8)
+ n = 8;
+
+ while (r < n)
+ r <<= 1;
+
+ return r;
+}
+
+static bool _hash_table_init(struct bcache *cache, unsigned nr_entries)
+{
+ unsigned i;
+
+ cache->nr_buckets = _calc_nr_buckets(nr_entries);
+ cache->hash_mask = cache->nr_buckets - 1;
+ cache->buckets = dm_malloc(cache->nr_buckets * sizeof(*cache->buckets));
+ if (!cache->buckets)
+ return false;
+
+ for (i = 0; i < cache->nr_buckets; i++)
+ dm_list_init(cache->buckets + i);
+
+ return true;
+}
+
+static void _hash_table_exit(struct bcache *cache)
+{
+ dm_free(cache->buckets);
+}
+
+//----------------------------------------------------------------
+
+static bool _init_free_list(struct bcache *cache, unsigned count)
+{
+ unsigned i;
+ size_t block_size = cache->block_sectors << SECTOR_SHIFT;
+ unsigned char *data =
+ (unsigned char *) _alloc_aligned(count * block_size, PAGE_SIZE);
+
+ /* Allocate the data for each block. We page align the data. */
+ if (!data)
+ return false;
+
+ cache->raw_data = data;
+ cache->raw_blocks = dm_malloc(count * sizeof(*cache->raw_blocks));
+
+ if (!cache->raw_blocks)
+ dm_free(cache->raw_data);
+
+ for (i = 0; i < count; i++) {
+ struct block *b = cache->raw_blocks + i;
+ b->cache = cache;
+ b->data = data + (block_size * i);
+ dm_list_add(&cache->free, &b->list);
+ }
+
+ return true;
+}
+
+static void _exit_free_list(struct bcache *cache)
+{
+ dm_free(cache->raw_data);
+ dm_free(cache->raw_blocks);
+}
+
+static struct block *_alloc_block(struct bcache *cache)
+{
+ if (dm_list_empty(&cache->free))
+ return NULL;
+
+ return dm_list_struct_base(_list_pop(&cache->free), struct block, list);
+}
+
+/*----------------------------------------------------------------
+ * Clean/dirty list management.
+ * Always use these methods to ensure nr_dirty_ is correct.
+ *--------------------------------------------------------------*/
+
+static void _unlink_block(struct block *b)
+{
+ if (_test_flags(b, BF_DIRTY))
+ b->cache->nr_dirty--;
+
+ dm_list_del(&b->list);
+}
+
+static void _link_block(struct block *b)
+{
+ struct bcache *cache = b->cache;
+
+ if (_test_flags(b, BF_DIRTY)) {
+ dm_list_add(&cache->dirty, &b->list);
+ cache->nr_dirty++;
+ } else
+ dm_list_add(&cache->clean, &b->list);
+}
+
+static void _relink(struct block *b)
+{
+ _unlink_block(b);
+ _link_block(b);
+}
+
+/*----------------------------------------------------------------
+ * Low level IO handling
+ *
+ * We cannot have two concurrent writes on the same block.
+ * eg, background writeback, put with dirty, flush?
+ *
+ * To avoid this we introduce some restrictions:
+ *
+ * i) A held block can never be written back.
+ * ii) You cannot get a block until writeback has completed.
+ *
+ *--------------------------------------------------------------*/
+
+static void _complete_io(void *context, int err)
+{
+ struct block *b = context;
+ struct bcache *cache = b->cache;
+
+ b->error = err;
+ _clear_flags(b, BF_IO_PENDING);
+ cache->nr_io_pending--;
+
+ /*
+ * b is on the io_pending list, so we don't want to use unlink_block.
+ * Which would incorrectly adjust nr_dirty.
+ */
+ dm_list_del(&b->list);
+
+ if (b->error)
+ memset(b->data, 0, cache->block_sectors << SECTOR_SHIFT);
+
+ /* Things don't work with this block of code, but work without it. */
+#if 0
+ if (b->error) {
+ log_warn("bcache io error %d fd %d", b->error, b->fd);
+ if (b->io_dir == DIR_READ) {
+ // We can just forget about this block, since there's
+ // no dirty data to be written back.
+ _hash_remove(b);
+ dm_list_add(&cache->free, &b->list);
+
+ } else
+ dm_list_add(&cache->errored, &b->list);
+
+ } else {
+ _clear_flags(b, BF_DIRTY);
+ _link_block(b);
+ }
+#endif
+ _clear_flags(b, BF_DIRTY);
+ _link_block(b);
+}
+
+/*
+ * |b->list| should be valid (either pointing to itself, on one of the other
+ * lists.
+ */
+static void _issue_low_level(struct block *b, enum dir d)
+{
+ struct bcache *cache = b->cache;
+ sector_t sb = b->index * cache->block_sectors;
+ sector_t se = sb + cache->block_sectors;
+
+ if (_test_flags(b, BF_IO_PENDING))
+ return;
+
+ b->io_dir = d;
+ _set_flags(b, BF_IO_PENDING);
+ dm_list_add(&cache->io_pending, &b->list);
+
+ if (!cache->engine->issue(cache->engine, d, b->fd, sb, se, b->data, b)) {
+ /* FIXME: if io_submit() set an errno, return that instead of EIO? */
+ _complete_io(b, -EIO);
+ return;
+ }
+
+}
+
+static inline void _issue_read(struct block *b)
+{
+ _issue_low_level(b, DIR_READ);
+}
+
+static inline void _issue_write(struct block *b)
+{
+ _issue_low_level(b, DIR_WRITE);
+}
+
+static bool _wait_io(struct bcache *cache)
+{
+ return cache->engine->wait(cache->engine, _complete_io);
+}
+
+/*----------------------------------------------------------------
+ * High level IO handling
+ *--------------------------------------------------------------*/
+
+static void _wait_all(struct bcache *cache)
+{
+ while (!dm_list_empty(&cache->io_pending))
+ _wait_io(cache);
+}
+
+static void _wait_specific(struct block *b)
+{
+ while (_test_flags(b, BF_IO_PENDING))
+ _wait_io(b->cache);
+}
+
+static unsigned _writeback(struct bcache *cache, unsigned count)
+{
+ unsigned actual = 0;
+ struct block *b, *tmp;
+
+ dm_list_iterate_items_gen_safe (b, tmp, &cache->dirty, list) {
+ if (actual == count)
+ break;
+
+ // We can't writeback anything that's still in use.
+ if (!b->ref_count) {
+ _issue_write(b);
+ actual++;
+ }
+ }
+
+ return actual;
+}
+
+/*----------------------------------------------------------------
+ * High level allocation
+ *--------------------------------------------------------------*/
+
+static struct block *_find_unused_clean_block(struct bcache *cache)
+{
+ struct block *b;
+
+ dm_list_iterate_items (b, &cache->clean) {
+ if (!b->ref_count) {
+ _unlink_block(b);
+ _hash_remove(b);
+ return b;
+ }
+ }
+
+ return NULL;
+}
+
+static struct block *_new_block(struct bcache *cache, int fd, block_address index, bool can_wait)
+{
+ struct block *b;
+
+ b = _alloc_block(cache);
+ while (!b && !dm_list_empty(&cache->clean)) {
+ b = _find_unused_clean_block(cache);
+ if (!b) {
+ if (can_wait) {
+ if (dm_list_empty(&cache->io_pending))
+ _writeback(cache, 16); // FIXME: magic number
+ _wait_io(cache);
+ } else {
+ log_error("bcache no new blocks for fd %d index %u",
+ fd, (uint32_t)index);
+ return NULL;
+ }
+ }
+ }
+
+ if (b) {
+ dm_list_init(&b->list);
+ dm_list_init(&b->hash);
+ b->flags = 0;
+ b->fd = fd;
+ b->index = index;
+ b->ref_count = 0;
+ b->error = 0;
+
+ _hash_insert(b);
+ }
+
+ if (!b) {
+ log_error("bcache no new blocks for fd %d index %u "
+ "clean %u free %u dirty %u pending %u nr_data_blocks %u nr_cache_blocks %u",
+ fd, (uint32_t)index,
+ dm_list_size(&cache->clean),
+ dm_list_size(&cache->free),
+ dm_list_size(&cache->dirty),
+ dm_list_size(&cache->io_pending),
+ (uint32_t)cache->nr_data_blocks,
+ (uint32_t)cache->nr_cache_blocks);
+ }
+
+ return b;
+}
+
+/*----------------------------------------------------------------
+ * Block reference counting
+ *--------------------------------------------------------------*/
+static void _zero_block(struct block *b)
+{
+ b->cache->write_zeroes++;
+ memset(b->data, 0, b->cache->block_sectors << SECTOR_SHIFT);
+ _set_flags(b, BF_DIRTY);
+}
+
+static void _hit(struct block *b, unsigned flags)
+{
+ struct bcache *cache = b->cache;
+
+ if (flags & (GF_ZERO | GF_DIRTY))
+ cache->write_hits++;
+ else
+ cache->read_hits++;
+
+ _relink(b);
+}
+
+static void _miss(struct bcache *cache, unsigned flags)
+{
+ if (flags & (GF_ZERO | GF_DIRTY))
+ cache->write_misses++;
+ else
+ cache->read_misses++;
+}
+
+static struct block *_lookup_or_read_block(struct bcache *cache,
+ int fd, block_address index,
+ unsigned flags)
+{
+ struct block *b = _hash_lookup(cache, fd, index);
+
+ if (b) {
+ // FIXME: this is insufficient. We need to also catch a read
+ // lock of a write locked block. Ref count needs to distinguish.
+ if (b->ref_count && (flags & (GF_DIRTY | GF_ZERO))) {
+ log_warn("concurrent write lock attempted");
+ return NULL;
+ }
+
+ if (_test_flags(b, BF_IO_PENDING)) {
+ _miss(cache, flags);
+ _wait_specific(b);
+
+ } else
+ _hit(b, flags);
+
+ _unlink_block(b);
+
+ if (flags & GF_ZERO)
+ _zero_block(b);
+
+ } else {
+ _miss(cache, flags);
+
+ b = _new_block(cache, fd, index, true);
+ if (b) {
+ if (flags & GF_ZERO)
+ _zero_block(b);
+
+ else {
+ _issue_read(b);
+ _wait_specific(b);
+
+ // we know the block is clean and unerrored.
+ _unlink_block(b);
+ }
+ }
+ }
+
+ if (b) {
+ if (flags & (GF_DIRTY | GF_ZERO))
+ _set_flags(b, BF_DIRTY);
+
+ _link_block(b);
+ return b;
+ }
+
+ return NULL;
+}
+
+static void _preemptive_writeback(struct bcache *cache)
+{
+ // FIXME: this ignores those blocks that are in the error state. Track
+ // nr_clean instead?
+ unsigned nr_available = cache->nr_cache_blocks - (cache->nr_dirty - cache->nr_io_pending);
+ if (nr_available < (WRITEBACK_LOW_THRESHOLD_PERCENT * cache->nr_cache_blocks / 100))
+ _writeback(cache, (WRITEBACK_HIGH_THRESHOLD_PERCENT * cache->nr_cache_blocks / 100) - nr_available);
+
+}
+
+/*----------------------------------------------------------------
+ * Public interface
+ *--------------------------------------------------------------*/
+struct bcache *bcache_create(sector_t block_sectors, unsigned nr_cache_blocks,
+ struct io_engine *engine)
+{
+ struct bcache *cache;
+ unsigned max_io = engine->max_io(engine);
+
+ if (!nr_cache_blocks) {
+ log_warn("bcache must have at least one cache block");
+ return NULL;
+ }
+
+ if (!block_sectors) {
+ log_warn("bcache must have a non zero block size");
+ return NULL;
+ }
+
+ if (block_sectors & ((PAGE_SIZE >> SECTOR_SHIFT) - 1)) {
+ log_warn("bcache block size must be a multiple of page size");
+ return NULL;
+ }
+
+ cache = dm_malloc(sizeof(*cache));
+ if (!cache)
+ return NULL;
+
+ cache->block_sectors = block_sectors;
+ cache->nr_cache_blocks = nr_cache_blocks;
+ cache->max_io = nr_cache_blocks < max_io ? nr_cache_blocks : max_io;
+ cache->engine = engine;
+ cache->nr_locked = 0;
+ cache->nr_dirty = 0;
+ cache->nr_io_pending = 0;
+
+ dm_list_init(&cache->free);
+ dm_list_init(&cache->errored);
+ dm_list_init(&cache->dirty);
+ dm_list_init(&cache->clean);
+ dm_list_init(&cache->io_pending);
+
+ if (!_hash_table_init(cache, nr_cache_blocks)) {
+ cache->engine->destroy(cache->engine);
+ dm_free(cache);
+ return NULL;
+ }
+
+ cache->read_hits = 0;
+ cache->read_misses = 0;
+ cache->write_zeroes = 0;
+ cache->write_hits = 0;
+ cache->write_misses = 0;
+ cache->prefetches = 0;
+
+ if (!_init_free_list(cache, nr_cache_blocks)) {
+ cache->engine->destroy(cache->engine);
+ _hash_table_exit(cache);
+ dm_free(cache);
+ return NULL;
+ }
+
+ return cache;
+}
+
+void bcache_destroy(struct bcache *cache)
+{
+ if (cache->nr_locked)
+ log_warn("some blocks are still locked");
+
+ bcache_flush(cache);
+ _wait_all(cache);
+ _exit_free_list(cache);
+ _hash_table_exit(cache);
+ cache->engine->destroy(cache->engine);
+ dm_free(cache);
+}
+
+unsigned bcache_nr_cache_blocks(struct bcache *cache)
+{
+ return cache->nr_cache_blocks;
+}
+
+unsigned bcache_max_prefetches(struct bcache *cache)
+{
+ return cache->max_io;
+}
+
+void bcache_prefetch(struct bcache *cache, int fd, block_address index)
+{
+ struct block *b = _hash_lookup(cache, fd, index);
+
+ if (!b) {
+ if (cache->nr_io_pending < cache->max_io) {
+ b = _new_block(cache, fd, index, false);
+ if (b) {
+ cache->prefetches++;
+ _issue_read(b);
+ }
+ }
+ }
+}
+
+bool bcache_get(struct bcache *cache, int fd, block_address index,
+ unsigned flags, struct block **result, int *error)
+{
+ struct block *b;
+
+ b = _lookup_or_read_block(cache, fd, index, flags);
+ if (b) {
+ if (!b->ref_count)
+ cache->nr_locked++;
+ b->ref_count++;
+
+ *result = b;
+
+ if (error)
+ *error = b->error;
+
+ if (b->error)
+ return false;
+ return true;
+ }
+
+ *result = NULL;
+
+ if (error)
+ *error = -BCACHE_NO_BLOCK;
+
+ log_error("bcache failed to get block %u fd %d", (uint32_t)index, fd);
+ return false;
+}
+
+static void _put_ref(struct block *b)
+{
+ if (!b->ref_count) {
+ log_warn("ref count on bcache block already zero");
+ return;
+ }
+
+ b->ref_count--;
+ if (!b->ref_count)
+ b->cache->nr_locked--;
+}
+
+void bcache_put(struct block *b)
+{
+ _put_ref(b);
+
+ if (_test_flags(b, BF_DIRTY))
+ _preemptive_writeback(b->cache);
+}
+
+bool bcache_flush(struct bcache *cache)
+{
+ // Only dirty data is on the errored list, since bad read blocks get
+ // recycled straight away. So we put these back on the dirty list, and
+ // try and rewrite everything.
+ dm_list_splice(&cache->dirty, &cache->errored);
+
+ while (!dm_list_empty(&cache->dirty)) {
+ struct block *b = dm_list_item(_list_pop(&cache->dirty), struct block);
+ if (b->ref_count || _test_flags(b, BF_IO_PENDING)) {
+ // The superblock may well be still locked.
+ continue;
+ }
+
+ _issue_write(b);
+ }
+
+ _wait_all(cache);
+
+ return dm_list_empty(&cache->errored);
+}
+
+static void _recycle_block(struct bcache *cache, struct block *b)
+{
+ _unlink_block(b);
+ _hash_remove(b);
+ dm_list_add(&cache->free, &b->list);
+}
+
+/*
+ * You can safely call this with a NULL block.
+ */
+static void _invalidate_block(struct bcache *cache, struct block *b)
+{
+ if (!b)
+ return;
+
+ if (_test_flags(b, BF_IO_PENDING))
+ _wait_specific(b);
+
+ if (b->ref_count)
+ log_warn("bcache_invalidate: block (%d, %llu) still held",
+ b->fd, (unsigned long long) index);
+ else {
+ if (_test_flags(b, BF_DIRTY)) {
+ _issue_write(b);
+ _wait_specific(b);
+ }
+
+ _recycle_block(cache, b);
+ }
+}
+
+void bcache_invalidate(struct bcache *cache, int fd, block_address index)
+{
+ _invalidate_block(cache, _hash_lookup(cache, fd, index));
+}
+
+// FIXME: switch to a trie, or maybe 1 hash table per fd? To save iterating
+// through the whole cache.
+void bcache_invalidate_fd(struct bcache *cache, int fd)
+{
+ struct block *b, *tmp;
+
+ // Start writing back any dirty blocks on this fd.
+ dm_list_iterate_items_safe (b, tmp, &cache->dirty)
+ if (b->fd == fd)
+ _issue_write(b);
+
+ _wait_all(cache);
+
+ // Everything should be in the clean list now.
+ dm_list_iterate_items_safe (b, tmp, &cache->clean)
+ if (b->fd == fd)
+ _invalidate_block(cache, b);
+
+ // Except they could be in the errored list :)
+ dm_list_iterate_items_safe (b, tmp, &cache->errored)
+ if (b->fd == fd)
+ _recycle_block(cache, b);
+}
+
+static void byte_range_to_block_range(struct bcache *cache, off_t start, size_t len,
+ block_address *bb, block_address *be)
+{
+ block_address block_size = cache->block_sectors << SECTOR_SHIFT;
+ *bb = start / block_size;
+ *be = (start + len + block_size - 1) / block_size;
+}
+
+void bcache_prefetch_bytes(struct bcache *cache, int fd, off_t start, size_t len)
+{
+ block_address bb, be;
+
+ byte_range_to_block_range(cache, start, len, &bb, &be);
+ while (bb < be) {
+ bcache_prefetch(cache, fd, bb);
+ bb++;
+ }
+}
+
+static off_t _min(off_t lhs, off_t rhs)
+{
+ if (rhs < lhs)
+ return rhs;
+
+ return lhs;
+}
+
+bool bcache_read_bytes(struct bcache *cache, int fd, off_t start, size_t len, void *data)
+{
+ struct block *b;
+ block_address bb, be, i;
+ unsigned char *udata = data;
+ off_t block_size = cache->block_sectors << SECTOR_SHIFT;
+ int errors = 0;
+
+ byte_range_to_block_range(cache, start, len, &bb, &be);
+ for (i = bb; i < be; i++)
+ bcache_prefetch(cache, fd, i);
+
+ for (i = bb; i < be; i++) {
+ if (!bcache_get(cache, fd, i, 0, &b, NULL)) {
+ log_error("bcache_read failed to get block %u fd %d bb %u be %u",
+ (uint32_t)i, fd, (uint32_t)bb, (uint32_t)be);
+ errors++;
+ continue;
+ }
+
+ if (i == bb) {
+ off_t block_offset = start % block_size;
+ size_t blen = _min(block_size - block_offset, len);
+ memcpy(udata, ((unsigned char *) b->data) + block_offset, blen);
+ len -= blen;
+ udata += blen;
+ } else {
+ size_t blen = _min(block_size, len);
+ memcpy(udata, b->data, blen);
+ len -= blen;
+ udata += blen;
+ }
+
+ bcache_put(b);
+ }
+
+ return errors ? false : true;
+}
+
+bool bcache_write_bytes(struct bcache *cache, int fd, off_t start, size_t len, void *data)
+{
+ struct block *b;
+ block_address bb, be, i;
+ unsigned char *udata = data;
+ off_t block_size = cache->block_sectors << SECTOR_SHIFT;
+ int errors = 0;
+
+ byte_range_to_block_range(cache, start, len, &bb, &be);
+ for (i = bb; i < be; i++)
+ bcache_prefetch(cache, fd, i);
+
+ for (i = bb; i < be; i++) {
+ if (!bcache_get(cache, fd, i, 0, &b, NULL)) {
+ log_error("bcache_write failed to get block %u fd %d bb %u be %u",
+ (uint32_t)i, fd, (uint32_t)bb, (uint32_t)be);
+ errors++;
+ break;
+ }
+
+ if (i == bb) {
+ off_t block_offset = start % block_size;
+ size_t blen = _min(block_size - block_offset, len);
+ memcpy(((unsigned char *) b->data) + block_offset, udata, blen);
+ len -= blen;
+ udata += blen;
+ } else {
+ size_t blen = _min(block_size, len);
+ memcpy(b->data, udata, blen);
+ len -= blen;
+ udata += blen;
+ }
+
+ _set_flags(b, BF_DIRTY);
+ _unlink_block(b);
+ _link_block(b);
+ _put_ref(b);
+ }
+
+ if (!bcache_flush(cache))
+ errors++;
+
+ return errors ? false : true;
+}
+
+#define ZERO_BUF_LEN 4096
+
+bool bcache_write_zeros(struct bcache *cache, int fd, off_t start, size_t len)
+{
+ char zerobuf[ZERO_BUF_LEN];
+ size_t plen;
+ size_t poff;
+
+ memset(zerobuf, 0, sizeof(zerobuf));
+
+ if (len <= ZERO_BUF_LEN)
+ return bcache_write_bytes(cache, fd, start, len, &zerobuf);
+
+ poff = 0;
+ plen = ZERO_BUF_LEN;
+
+ while (1) {
+ if (!bcache_write_bytes(cache, fd, start + poff, plen, &zerobuf))
+ return false;
+
+ poff += plen;
+ len -= plen;
+
+ if (!len)
+ break;
+
+ if (len < ZERO_BUF_LEN)
+ plen = len;
+ }
+
+ return true;
+}
+
+
+//----------------------------------------------------------------
+
diff --git a/lib/device/bcache.h b/lib/device/bcache.h
new file mode 100644
index 000000000..4ce137ae3
--- /dev/null
+++ b/lib/device/bcache.h
@@ -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
diff --git a/lib/device/dev-cache.c b/lib/device/dev-cache.c
index 711c2d88b..52edad845 100644
--- a/lib/device/dev-cache.c
+++ b/lib/device/dev-cache.c
@@ -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)
diff --git a/lib/device/dev-cache.h b/lib/device/dev-cache.h
index 560355387..479727473 100644
--- a/lib/device/dev-cache.h
+++ b/lib/device/dev-cache.h
@@ -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);
diff --git a/lib/device/dev-io.c b/lib/device/dev-io.c
index d631b8613..39d5d30f3 100644
--- a/lib/device/dev-io.c
+++ b/lib/device/dev-io.c
@@ -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)
+/*-----------------------------------------------------------------
+ * The standard io loop that keeps submitting an io until it's
+ * all gone.
+ *---------------------------------------------------------------*/
+static int _io(struct device_area *where, char *buffer, int should_write, dev_io_reason_t reason)
{
- 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;
- }
+ int fd = dev_fd(where->dev);
+ ssize_t n = 0;
+ size_t total = 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;
+ if (fd < 0) {
+ log_error("Attempt to read an unopened device (%s).",
+ dev_name(where->dev));
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;
+ 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));
- if (!_aio_ctx)
+ /*
+ * Skip all writes in test mode.
+ */
+ if (should_write && test_mode())
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.");
+ if (where->size > SSIZE_MAX) {
+ log_error("Read size too large: %" PRIu64, where->size);
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)
-{
- 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 (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;
- }
-
- /*
- * Realign start of bounce buffer (using the extra sector)
- */
- if (((uintptr_t) devbuf->buf) & mask)
- devbuf->buf = (char *) ((((uintptr_t) devbuf->buf) + mask) & ~mask);
- }
+ return _io(where, buffer, should_write, reason);
- /* 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;
+ /* 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;
}
- 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;
-
- /* writes */
+ if (should_write) {
+ memcpy(bounce + (where->start - widened.start), buffer,
+ (size_t) where->size);
- 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,121 +722,55 @@ 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)
-{
- /* 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");
-}
-
-/* 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;
-
- 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);
-
- return 1;
-}
-
/*
- * Read from 'dev' in 2 distinct regions, denoted by (offset,len) and (offset2,len2).
- * Caller is responsible for dm_free().
+ * 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.
*/
-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)
+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)
{
- char *buf = NULL;
-
- if (!(buf = dm_malloc(len + len2))) {
- log_error("Buffer allocation failed for split metadata.");
- return NULL;
+ if (!dev_read(dev, offset, len, reason, buf)) {
+ log_error("Read from %s failed", dev_name(dev));
+ return 0;
}
- if (!dev_read_buf(dev, offset, len, reason, buf)) {
- log_error("Read from %s failed.", dev_name(dev));
- dm_free(buf);
- return NULL;
- }
+ /*
+ * The second region is optional, and allows for
+ * a circular buffer on the device.
+ */
+ if (!len2)
+ return 1;
- 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;
+ if (!dev_read(dev, offset2, len2, reason, buf + len)) {
+ log_error("Circular read from %s failed",
+ dev_name(dev));
+ return 0;
}
- return buf;
+ return 1;
}
/* FIXME If O_DIRECT can't extend file, dev_extend first; dev_truncate after.
@@ -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;
diff --git a/lib/device/dev-luks.c b/lib/device/dev-luks.c
index f29161508..8513e1462 100644
--- a/lib/device/dev-luks.c
+++ b/lib/device/dev-luks.c
@@ -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;
diff --git a/lib/device/dev-md.c b/lib/device/dev-md.c
index 1a5d47062..92ee2144b 100644
--- a/lib/device/dev-md.c
+++ b/lib/device/dev-md.c
@@ -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;
diff --git a/lib/device/dev-swap.c b/lib/device/dev-swap.c
index 094eb05e4..a7ff10bb1 100644
--- a/lib/device/dev-swap.c
+++ b/lib/device/dev-swap.c
@@ -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;
}
diff --git a/lib/device/dev-type.c b/lib/device/dev-type.c
index b9e77f81e..992394310 100644
--- a/lib/device/dev-type.c
+++ b/lib/device/dev-type.c
@@ -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;
}
diff --git a/lib/device/device.h b/lib/device/device.h
index ea71d00a4..36d1e3e0f 100644
--- a/lib/device/device.h
+++ b/lib/device/device.h
@@ -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.
@@ -62,48 +52,6 @@ struct dev_ext {
};
/*
- * 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
diff --git a/lib/filters/filter-composite.c b/lib/filters/filter-composite.c
index 83a0f02bb..c63589640 100644
--- a/lib/filters/filter-composite.c
+++ b/lib/filters/filter-composite.c
@@ -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;
diff --git a/lib/filters/filter-persistent.c b/lib/filters/filter-persistent.c
index 7542e0200..a4151c289 100644
--- a/lib/filters/filter-persistent.c
+++ b/lib/filters/filter-persistent.c
@@ -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);
diff --git a/lib/filters/filter.h b/lib/filters/filter.h
index 5dbf0b497..d75f6e11c 100644
--- a/lib/filters/filter.h
+++ b/lib/filters/filter.h
@@ -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 */
diff --git a/lib/format1/disk-rep.c b/lib/format1/disk-rep.c
index cf34e91cb..281adc106 100644
--- a/lib/format1/disk-rep.c
+++ b/lib/format1/disk-rep.c
@@ -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,
diff --git a/lib/format1/format1.c b/lib/format1/format1.c
index 7d84e6981..b3569e08e 100644
--- a/lib/format1/format1.c
+++ b/lib/format1/format1.c
@@ -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;
diff --git a/lib/format1/lvm1-label.c b/lib/format1/lvm1-label.c
index d334fdc2e..691a05a4a 100644
--- a/lib/format1/lvm1-label.c
+++ b/lib/format1/lvm1-label.c
@@ -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)
diff --git a/lib/format_pool/disk_rep.c b/lib/format_pool/disk_rep.c
index 4b2e7fb12..fe9b03ea9 100644
--- a/lib/format_pool/disk_rep.c
+++ b/lib/format_pool/disk_rep.c
@@ -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);
diff --git a/lib/format_pool/format_pool.c b/lib/format_pool/format_pool.c
index c6990580b..f6e5e011b 100644
--- a/lib/format_pool/format_pool.c
+++ b/lib/format_pool/format_pool.c
@@ -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;
diff --git a/lib/format_pool/pool_label.c b/lib/format_pool/pool_label.c
index 888a2eb8c..2e30a7b19 100644
--- a/lib/format_pool/pool_label.c
+++ b/lib/format_pool/pool_label.c
@@ -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)
diff --git a/lib/format_text/archive.c b/lib/format_text/archive.c
index 2186de860..690bc7408 100644
--- a/lib/format_text/archive.c
+++ b/lib/format_text/archive.c
@@ -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;
diff --git a/lib/format_text/archiver.c b/lib/format_text/archiver.c
index 2c8e75145..c8aeb47cb 100644
--- a/lib/format_text/archiver.c
+++ b/lib/format_text/archiver.c
@@ -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;
}
}
diff --git a/lib/format_text/export.c b/lib/format_text/export.c
index 08e1cda43..e5352376d 100644
--- a/lib/format_text/export.c
+++ b/lib/format_text/export.c
@@ -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:
diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c
index 2e7e2b85e..792d75a4d 100644
--- a/lib/format_text/format-text.c
+++ b/lib/format_text/format-text.c
@@ -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-2012 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -37,12 +37,6 @@
#include <dirent.h>
#include <ctype.h>
-/*
- * Round up offset within buffer to next location that is an exact multiple of alignment.
- * (We shouldn't assume the start of the metadata area was aligned the same way when it was created.)
- */
-#define ALIGN_ABSOLUTE(offset, buffer_start, alignment) ((offset) + (alignment) - UINT64_C(1) - ((buffer_start) + (offset) + (alignment) - UINT64_C(1)) % (alignment))
-
static struct format_instance *_text_create_text_instance(const struct format_type *fmt,
const struct format_instance_ctx *fic);
@@ -182,10 +176,9 @@ static int _pv_analyze_mda_raw (const struct format_type * fmt,
uint64_t offset2;
size_t size;
size_t size2;
- const char *buf = NULL;
+ char *buf=NULL;
struct device_area *area;
struct mda_context *mdac;
- unsigned circular = 0;
int r=0;
mdac = (struct mda_context *) mda->metadata_locn;
@@ -194,10 +187,7 @@ static int _pv_analyze_mda_raw (const struct format_type * fmt,
FMTu64, mdac->area.start, mdac->area.size);
area = &mdac->area;
- if (!dev_open_readonly(area->dev))
- return_0;
-
- if (!(mdah = raw_read_mda_header(fmt->cmd->mem, area, mda_is_primary(mda))))
+ if (!(mdah = raw_read_mda_header(fmt, area, mda_is_primary(mda))))
goto_out;
rlocn = mdah->raw_locns;
@@ -226,7 +216,6 @@ static int _pv_analyze_mda_raw (const struct format_type * fmt,
prev_sector);
if (prev_sector > prev_sector2)
goto_out;
-
/*
* FIXME: for some reason, the whole metadata region from
* area->start to area->start+area->size is not used.
@@ -235,14 +224,26 @@ static int _pv_analyze_mda_raw (const struct format_type * fmt,
* "dm_config_maybe_section" returning true when there's no valid
* metadata in a sector (sectors with all nulls).
*/
+ if (!(buf = dm_malloc(size + size2)))
+ goto_out;
- circular = size2 ? 1 : 0;
+ if (!dev_read_bytes(area->dev, offset, size, buf)) {
+ log_error("Failed to read dev %s offset %llu size %llu",
+ dev_name(area->dev),
+ (unsigned long long)offset,
+ (unsigned long long)size);
+ goto out;
+ }
- if (circular) {
- if (!(buf = dev_read_circular(area->dev, offset, size, offset2, size2, MDA_CONTENT_REASON(mda_is_primary(mda)))))
- goto_out;
- } else if (!(buf = dev_read(area->dev, offset, size, MDA_CONTENT_REASON(mda_is_primary(mda)))))
- goto_out;
+ if (size2) {
+ if (!dev_read_bytes(area->dev, offset2, size2, buf + size)) {
+ log_error("Failed to read dev %s offset %llu size %llu",
+ dev_name(area->dev),
+ (unsigned long long)offset2,
+ (unsigned long long)size2);
+ goto out;
+ }
+ }
/*
* FIXME: We could add more sophisticated metadata detection
@@ -272,20 +273,18 @@ static int _pv_analyze_mda_raw (const struct format_type * fmt,
size += SECTOR_SIZE;
}
}
- if (circular)
- dm_free((void *)buf);
+ dm_free(buf);
buf = NULL;
}
r = 1;
out:
- if (circular)
- dm_free((void *)buf);
- if (!dev_close(area->dev))
- stack;
+ dm_free(buf);
return r;
}
+
+
static int _text_lv_setup(struct format_instance *fid __attribute__((unused)),
struct logical_volume *lv)
{
@@ -326,120 +325,66 @@ static void _xlate_mdah(struct mda_header *mdah)
}
}
-struct process_raw_mda_header_params {
- struct mda_header *mdah;
- struct device_area dev_area;
- lvm_callback_fn_t mdah_callback_fn;
- void *mdah_callback_context;
- int ret;
-};
-
-static void _process_raw_mda_header(int failed, unsigned ioflags, void *context, const void *data)
+static int _raw_read_mda_header(struct mda_header *mdah, struct device_area *dev_area, int primary_mda)
{
- struct process_raw_mda_header_params *prmp = context;
- struct mda_header *mdah = prmp->mdah;
- struct device_area *dev_area = &prmp->dev_area;
+ log_debug_metadata("Reading mda header sector from %s at %llu",
+ dev_name(dev_area->dev), (unsigned long long)dev_area->start);
- if (!dev_close(dev_area->dev))
- goto_bad;
-
- if (failed)
- goto_bad;
-
- memcpy(mdah, data, MDA_HEADER_SIZE);
+ if (!dev_read_bytes(dev_area->dev, dev_area->start, MDA_HEADER_SIZE, mdah)) {
+ log_error("Failed to read metadata area header on %s at %llu",
+ dev_name(dev_area->dev), (unsigned long long)dev_area->start);
+ return 0;
+ }
if (mdah->checksum_xl != xlate32(calc_crc(INITIAL_CRC, (uint8_t *)mdah->magic,
MDA_HEADER_SIZE -
sizeof(mdah->checksum_xl)))) {
- log_error("Incorrect metadata area header checksum on %s"
- " at offset " FMTu64, dev_name(dev_area->dev),
- dev_area->start);
- goto bad;
+ log_error("Incorrect checksum in metadata area header on %s at %llu",
+ dev_name(dev_area->dev), (unsigned long long)dev_area->start);
+ return 0;
}
_xlate_mdah(mdah);
if (strncmp((char *)mdah->magic, FMTT_MAGIC, sizeof(mdah->magic))) {
- log_error("Wrong magic number in metadata area header on %s"
- " at offset " FMTu64, dev_name(dev_area->dev),
- dev_area->start);
- goto bad;
+ log_error("Wrong magic number in metadata area header on %s at %llu",
+ dev_name(dev_area->dev), (unsigned long long)dev_area->start);
+ return 0;
}
if (mdah->version != FMTT_VERSION) {
- log_error("Incompatible metadata area header version: %d on %s"
- " at offset " FMTu64, mdah->version,
- dev_name(dev_area->dev), dev_area->start);
- goto bad;
+ log_error("Incompatible version %u metadata area header on %s at %llu",
+ mdah->version,
+ dev_name(dev_area->dev), (unsigned long long)dev_area->start);
+ return 0;
}
if (mdah->start != dev_area->start) {
- log_error("Incorrect start sector in metadata area header: "
- FMTu64 " on %s at offset " FMTu64, mdah->start,
- dev_name(dev_area->dev), dev_area->start);
- goto bad;
+ log_error("Incorrect start sector %llu in metadata area header on %s at %llu",
+ (unsigned long long)mdah->start,
+ dev_name(dev_area->dev), (unsigned long long)dev_area->start);
+ return 0;
}
- goto out;
-
-bad:
- prmp->ret = 0;
-out:
- if (prmp->mdah_callback_fn)
- prmp->mdah_callback_fn(!prmp->ret, ioflags, prmp->mdah_callback_context, mdah);
+ return 1;
}
-static struct mda_header *_raw_read_mda_header(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_header *mdah;
- struct process_raw_mda_header_params *prmp;
- if (!(mdah = dm_pool_alloc(mem, MDA_HEADER_SIZE))) {
+ if (!(mdah = dm_pool_alloc(fmt->cmd->mem, MDA_HEADER_SIZE))) {
log_error("struct mda_header allocation failed");
return NULL;
}
- if (!(prmp = dm_pool_zalloc(mem, sizeof (*prmp)))) {
- log_error("struct process_raw_mda_header_params allocation failed");
- dm_pool_free(mem, mdah);
+ if (!_raw_read_mda_header(mdah, dev_area, primary_mda)) {
+ dm_pool_free(fmt->cmd->mem, mdah);
return NULL;
}
- if (!dev_open_readonly(dev_area->dev)) {
- dm_pool_free(mem, mdah);
- return_NULL;
- }
-
- prmp->mdah = mdah;
- prmp->dev_area = *dev_area;
- prmp->mdah_callback_fn = mdah_callback_fn;
- prmp->mdah_callback_context = mdah_callback_context;
- prmp->ret = 1;
-
- dev_read_callback(dev_area->dev, dev_area->start, MDA_HEADER_SIZE, MDA_HEADER_REASON(primary_mda),
- ioflags, _process_raw_mda_header, prmp);
- if (mdah_callback_fn)
- return mdah;
-
- if (!prmp->ret)
- return_NULL;
- else
- return mdah;
-}
-
-struct mda_header *raw_read_mda_header(struct dm_pool *mem, struct device_area *dev_area, int primary_mda)
-{
- return _raw_read_mda_header(mem, dev_area, primary_mda, 0, NULL, NULL);
-}
-
-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)
-{
- if (!_raw_read_mda_header(mem, dev_area, primary_mda, ioflags, mdah_callback_fn, mdah_callback_context))
- return_0;
-
- return 1;
+ return mdah;
}
static int _raw_write_mda_header(const struct format_type *fmt,
@@ -455,25 +400,32 @@ static int _raw_write_mda_header(const struct format_type *fmt,
MDA_HEADER_SIZE -
sizeof(mdah->checksum_xl)));
- if (!dev_write(dev, start_byte, MDA_HEADER_SIZE, MDA_HEADER_REASON(primary_mda), mdah))
- return_0;
+ if (!dev_write_bytes(dev, start_byte, MDA_HEADER_SIZE, mdah)) {
+ log_error("Failed to write mda header to %s fd %d", dev_name(dev), dev->bcache_fd);
+ return 0;
+ }
return 1;
}
-static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area,
+/*
+ * FIXME: unify this with read_metadata_location() which is used
+ * in the label scanning path.
+ */
+
+static struct raw_locn *_read_metadata_location_vg(struct device_area *dev_area,
struct mda_header *mdah, int primary_mda,
const char *vgname,
int *precommitted)
{
size_t len;
+ char vgnamebuf[NAME_LEN + 2] __attribute__((aligned(8)));
struct raw_locn *rlocn, *rlocn_precommitted;
struct lvmcache_info *info;
struct lvmcache_vgsummary vgsummary_orphan = {
.vgname = FMT_TEXT_ORPHAN_VG_NAME,
};
int rlocn_was_ignored;
- const char *buf;
memcpy(&vgsummary_orphan.vgid, FMT_TEXT_ORPHAN_VG_NAME, sizeof(FMT_TEXT_ORPHAN_VG_NAME));
@@ -506,22 +458,23 @@ static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area,
if (rlocn_was_ignored)
return rlocn;
- /* FIXME Loop through rlocns two-at-a-time. List null-terminated. */
- /* FIXME Ignore if checksum incorrect!!! */
- if (!(buf = dev_read(dev_area->dev, dev_area->start + rlocn->offset,
- NAME_LEN + 2, MDA_CONTENT_REASON(primary_mda))))
- goto_bad;
+ /*
+ * Verify that the VG metadata pointed to by the rlocn
+ * begins with a valid vgname.
+ */
+ memset(vgnamebuf, 0, sizeof(vgnamebuf));
- if (!strncmp(buf, vgname, len = strlen(vgname)) &&
- (isspace(*(buf + len)) || *(buf + len) == '{'))
+ dev_read_bytes(dev_area->dev, dev_area->start + rlocn->offset, NAME_LEN, vgnamebuf);
+
+ if (!strncmp(vgnamebuf, vgname, len = strlen(vgname)) &&
+ (isspace(vgnamebuf[len]) || vgnamebuf[len] == '{'))
return rlocn;
- log_debug_metadata("Volume group name found in %smetadata on %s at " FMTu64 " does "
- "not match expected name %s.",
- *precommitted ? "precommitted " : "",
- dev_name(dev_area->dev), dev_area->start + rlocn->offset, vgname);
+ log_error("Metadata on %s at %llu has wrong VG name \"%s\" expected %s.",
+ dev_name(dev_area->dev),
+ (unsigned long long)(dev_area->start + rlocn->offset),
+ vgnamebuf, vgname);
- bad:
if ((info = lvmcache_info_from_pvid(dev_area->dev->pvid, dev_area->dev, 0)) &&
!lvmcache_update_vgname_and_id(info, &vgsummary_orphan))
stack;
@@ -530,46 +483,25 @@ static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area,
}
/*
- * Find first aligned offset after end of existing metadata.
- * Based on the alignment provided, this is the exact offset to use for the new metadata.
- * The caller is responsible for validating the result.
+ * Determine offset for uncommitted metadata
*/
static uint64_t _next_rlocn_offset(struct raw_locn *rlocn, struct mda_header *mdah, uint64_t mdac_area_start, uint64_t alignment)
{
- uint64_t old_end, new_start_offset;
- int old_wrapped = 0; /* Does the old metadata wrap around? */
+ uint64_t new_start_offset;
if (!rlocn)
/* Find an empty slot */
- /* FIXME Assumes only one VG per mdah for now */
- return ALIGN_ABSOLUTE(MDA_HEADER_SIZE, mdac_area_start, alignment);
-
- /* First find the end of the old metadata */
- old_end = rlocn->offset + rlocn->size;
-
- if (old_end > mdah->size) {
- old_wrapped = 1;
- old_end -= (mdah->size - MDA_HEADER_SIZE);
- }
+ /* FIXME Assume only one VG per mdah for now */
+ return alignment;
- /* Calculate new start position relative to start of buffer rounded up to absolute alignment */
- new_start_offset = ALIGN_ABSOLUTE(old_end, mdac_area_start, alignment);
+ /* Calculate new start position within buffer rounded up to absolute alignment */
+ new_start_offset = rlocn->offset + rlocn->size +
+ (alignment - (mdac_area_start + rlocn->offset + rlocn->size) % alignment);
- /* If new location is beyond the end of the buffer, return to start of circular buffer and realign */
- if (new_start_offset >= mdah->size) {
- /* If the start of the buffer is occupied, move past it */
- if (old_wrapped || rlocn->offset == MDA_HEADER_SIZE)
- new_start_offset = old_end;
- else
- new_start_offset = MDA_HEADER_SIZE;
-
- new_start_offset = ALIGN_ABSOLUTE(new_start_offset, mdac_area_start, alignment);
- }
+ /* If new location is beyond the end of the buffer, wrap around back to start of circular buffer */
+ if (new_start_offset > mdah->size - MDA_HEADER_SIZE)
+ new_start_offset -= (mdah->size - MDA_HEADER_SIZE);
- /*
- * Note that we don't check here that this location isn't inside the existing metadata.
- * If it is, then it means this value of alignment cannot be used.
- */
return new_start_offset;
}
@@ -580,18 +512,12 @@ static int _raw_holds_vgname(struct format_instance *fid,
int noprecommit = 0;
struct mda_header *mdah;
- if (!dev_open_readonly(dev_area->dev))
- return_0;
-
- if (!(mdah = raw_read_mda_header(fid->fmt->cmd->mem, dev_area, 0)))
+ if (!(mdah = raw_read_mda_header(fid->fmt, dev_area, 0)))
return_0;
- if (_find_vg_rlocn(dev_area, mdah, 0, vgname, &noprecommit))
+ if (_read_metadata_location_vg(dev_area, mdah, 0, vgname, &noprecommit))
r = 1;
- if (!dev_close(dev_area->dev))
- stack;
-
return r;
}
@@ -600,8 +526,8 @@ static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
struct device_area *area,
struct cached_vg_fmtdata **vg_fmtdata,
unsigned *use_previous_vg,
- int precommitted, unsigned ioflags,
- int single_device, int primary_mda)
+ int precommitted,
+ int primary_mda)
{
struct volume_group *vg = NULL;
struct raw_locn *rlocn;
@@ -610,10 +536,12 @@ static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
char *desc;
uint32_t wrap = 0;
- if (!(mdah = raw_read_mda_header(fid->fmt->cmd->mem, area, primary_mda)))
+ if (!(mdah = raw_read_mda_header(fid->fmt, area, primary_mda))) {
+ log_error("Failed to read vg %s from %s", vgname, dev_name(area->dev));
goto_out;
+ }
- if (!(rlocn = _find_vg_rlocn(area, mdah, primary_mda, vgname, &precommitted))) {
+ if (!(rlocn = _read_metadata_location_vg(area, mdah, primary_mda, vgname, &precommitted))) {
log_debug_metadata("VG %s not found on %s", vgname, dev_name(area->dev));
goto out;
}
@@ -622,31 +550,32 @@ static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
wrap = (uint32_t) ((rlocn->offset + rlocn->size) - mdah->size);
if (wrap > rlocn->offset) {
- log_error("VG %s metadata on %s (" FMTu64 " bytes) too large for circular buffer (" FMTu64 " bytes)",
- vgname, dev_name(area->dev), rlocn->size, mdah->size - MDA_HEADER_SIZE);
+ log_error("Metadata for VG %s on %s at %llu size %llu is too large for circular buffer.",
+ vgname, dev_name(area->dev),
+ (unsigned long long)(area->start + rlocn->offset),
+ (unsigned long long)rlocn->size);
goto out;
}
- /* FIXME 64-bit */
- if (!(vg = text_vg_import_fd(fid, NULL, vg_fmtdata, use_previous_vg, single_device, area->dev,
- primary_mda,
- (off_t) (area->start + rlocn->offset),
- (uint32_t) (rlocn->size - wrap),
- (off_t) (area->start + MDA_HEADER_SIZE),
- wrap, calc_crc, rlocn->checksum, ioflags, &when,
- &desc)) && (!use_previous_vg || !*use_previous_vg))
- goto_out;
+ vg = text_read_metadata(fid, NULL, vg_fmtdata, use_previous_vg, area->dev, primary_mda,
+ (off_t) (area->start + rlocn->offset),
+ (uint32_t) (rlocn->size - wrap),
+ (off_t) (area->start + MDA_HEADER_SIZE),
+ wrap,
+ calc_crc,
+ rlocn->checksum,
+ &when, &desc);
- if (vg)
- log_debug_metadata("Read %s %smetadata (%u) from %s at " FMTu64 " size "
- FMTu64, vg->name, precommitted ? "pre-commit " : "",
- vg->seqno, dev_name(area->dev),
- area->start + rlocn->offset, rlocn->size);
- else
- log_debug_metadata("Skipped reading %smetadata from %s at " FMTu64 " size "
- FMTu64 " with matching checksum.", precommitted ? "pre-commit " : "",
- dev_name(area->dev),
- area->start + rlocn->offset, rlocn->size);
+ if (!vg) {
+ /* FIXME: detect and handle errors, and distinguish from the optimization
+ that skips parsing the metadata which also returns NULL. */
+ }
+
+ log_debug_metadata("Found metadata on %s at %llu size %llu for VG %s",
+ dev_name(area->dev),
+ (unsigned long long)(area->start + rlocn->offset),
+ (unsigned long long)rlocn->size,
+ vgname);
if (vg && precommitted)
vg->status |= PRECOMMITTED;
@@ -659,19 +588,12 @@ static struct volume_group *_vg_read_raw(struct format_instance *fid,
const char *vgname,
struct metadata_area *mda,
struct cached_vg_fmtdata **vg_fmtdata,
- unsigned *use_previous_vg,
- int single_device, unsigned ioflags)
+ unsigned *use_previous_vg)
{
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
struct volume_group *vg;
- if (!dev_open_readonly(mdac->area.dev))
- return_NULL;
-
- vg = _vg_read_raw_area(fid, vgname, &mdac->area, vg_fmtdata, use_previous_vg, 0, ioflags, single_device, mda_is_primary(mda));
-
- if (!dev_close(mdac->area.dev))
- stack;
+ vg = _vg_read_raw_area(fid, vgname, &mdac->area, vg_fmtdata, use_previous_vg, 0, mda_is_primary(mda));
return vg;
}
@@ -680,75 +602,16 @@ static struct volume_group *_vg_read_precommit_raw(struct format_instance *fid,
const char *vgname,
struct metadata_area *mda,
struct cached_vg_fmtdata **vg_fmtdata,
- unsigned *use_previous_vg, unsigned ioflags)
+ unsigned *use_previous_vg)
{
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
struct volume_group *vg;
- if (!dev_open_readonly(mdac->area.dev))
- return_NULL;
-
- vg = _vg_read_raw_area(fid, vgname, &mdac->area, vg_fmtdata, use_previous_vg, 1, ioflags, 0, mda_is_primary(mda));
-
- if (!dev_close(mdac->area.dev))
- stack;
+ vg = _vg_read_raw_area(fid, vgname, &mdac->area, vg_fmtdata, use_previous_vg, 1, mda_is_primary(mda));
return vg;
}
-static int _metadata_fits_into_buffer(struct mda_context *mdac, struct mda_header *mdah,
- struct raw_locn *rlocn, uint64_t new_wrap)
-{
- uint64_t old_wrap = 0; /* Amount of wrap around in existing metadata */
- uint64_t old_end = 0; /* The (byte after the) end of the existing metadata */
- uint64_t new_end; /* The (byte after the) end of the new metadata */
- uint64_t old_start = 0; /* The start of the existing metadata */
- uint64_t new_start = mdac->rlocn.offset; /* The proposed start of the new metadata */
-
- /*
- * If the (aligned) start of the new metadata is already beyond the end
- * of the buffer this means it didn't fit with the given alignment.
- * (The caller has already tried to wrap it back to the start
- * of the buffer but the alignment pushed it back outside.)
- */
- if (new_start >= mdah->size)
- return_0;
-
- /* Does the total amount of metadata, old and new, fit inside the buffer? */
- if (MDA_HEADER_SIZE + (rlocn ? rlocn->size : 0) + mdac->rlocn.size >= mdah->size)
- return_0;
-
- /* If there's existing metadata, set old_start, old_end and old_wrap. */
- if (rlocn) {
- old_start = rlocn->offset;
- old_end = old_start + rlocn->size;
-
- /* Does the existing metadata wrap around the end of the buffer? */
- if (old_end > mdah->size)
- old_wrap = old_end - mdah->size;
- }
-
- new_end = new_wrap ? new_wrap + MDA_HEADER_SIZE : new_start + mdac->rlocn.size;
-
- /* If both wrap around, there's necessarily overlap */
- if (new_wrap && old_wrap)
- return_0;
-
- /* If there's no existing metadata, we're OK */
- if (!rlocn)
- return 1;
-
- /* If either wraps around, there's overlap if the new end falls beyond the old start */
- if ((new_wrap || old_wrap) && (new_end > old_start))
- return_0;
-
- /* If there's no wrap, check there's no overlap */
- if (!new_wrap && !old_wrap && (old_end > new_start) && (old_start < new_end))
- return_0;
-
- return 1;
-}
-
static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
struct metadata_area *mda)
{
@@ -758,12 +621,10 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
struct mda_header *mdah;
struct pv_list *pvl;
int r = 0;
- uint64_t new_wrap = 0; /* Number of bytes of new metadata that wrap around to start of buffer */
- uint64_t alignment = MDA_ALIGNMENT;
+ uint64_t new_wrap = 0, old_wrap = 0, new_end;
int found = 0;
int noprecommit = 0;
const char *old_vg_name = NULL;
- uint64_t new_size_rounded = 0;
/* Ignore any mda on a PV outside the VG. vgsplit relies on this */
dm_list_iterate_items(pvl, &vg->pvs) {
@@ -778,19 +639,9 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
if (!found)
return 1;
- /*
- * This is paired with the following closes:
- * - at the end of this fn if returning 0
- * - in _vg_commit_raw_rlocn regardless of return code
- * which handles commit (but not pre-commit) and revert.
- */
- if (!dev_open(mdac->area.dev))
- return_0;
-
- if (!(mdah = raw_read_mda_header(fid->fmt->cmd->mem, &mdac->area, mda_is_primary(mda))))
+ if (!(mdah = raw_read_mda_header(fid->fmt, &mdac->area, mda_is_primary(mda))))
goto_out;
- /* Following space is zero-filled up to the next MDA_ALIGNMENT boundary */
if (!fidtc->raw_metadata_buf &&
!(fidtc->raw_metadata_buf_size =
text_vg_export_raw(vg, "", &fidtc->raw_metadata_buf))) {
@@ -798,74 +649,53 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
goto out;
}
- rlocn = _find_vg_rlocn(&mdac->area, mdah, mda_is_primary(mda), old_vg_name ? : vg->name, &noprecommit);
+ rlocn = _read_metadata_location_vg(&mdac->area, mdah, mda_is_primary(mda), old_vg_name ? : vg->name, &noprecommit);
+ mdac->rlocn.offset = _next_rlocn_offset(rlocn, mdah, mdac->area.start, MDA_ORIGINAL_ALIGNMENT);
mdac->rlocn.size = fidtc->raw_metadata_buf_size;
- /* Find where the new metadata would be written with our preferred alignment */
- mdac->rlocn.offset = _next_rlocn_offset(rlocn, mdah, mdac->area.start, alignment);
-
- /* If metadata extends beyond the buffer, return to the start instead of wrapping it */
if (mdac->rlocn.offset + mdac->rlocn.size > mdah->size)
- mdac->rlocn.offset = ALIGN_ABSOLUTE(MDA_HEADER_SIZE, mdac->area.start, alignment);
+ new_wrap = (mdac->rlocn.offset + mdac->rlocn.size) - mdah->size;
- /*
- * If the metadata doesn't fit into the buffer correctly with these
- * settings, fall back to the 512-byte alignment used by the original
- * LVM2 code and allow the metadata to be split into two parts,
- * wrapping around from the end of the circular buffer back to the
- * beginning.
- */
- if (!_metadata_fits_into_buffer(mdac, mdah, rlocn, 0)) {
- alignment = MDA_ORIGINAL_ALIGNMENT;
- mdac->rlocn.offset = _next_rlocn_offset(rlocn, mdah, mdac->area.start, alignment);
+ if (rlocn && (rlocn->offset + rlocn->size > mdah->size))
+ old_wrap = (rlocn->offset + rlocn->size) - mdah->size;
- /* Does the new metadata wrap around? */
- if (mdac->rlocn.offset + mdac->rlocn.size > mdah->size)
- new_wrap = (mdac->rlocn.offset + mdac->rlocn.size) - mdah->size;
- else
- new_wrap = 0;
+ new_end = new_wrap ? new_wrap + MDA_HEADER_SIZE :
+ mdac->rlocn.offset + mdac->rlocn.size;
- if (!_metadata_fits_into_buffer(mdac, mdah, rlocn, new_wrap)) {
- log_error("VG %s metadata on %s (" FMTu64 " bytes) too large for circular buffer (" FMTu64 " bytes with " FMTu64 " used)",
- vg->name, dev_name(mdac->area.dev), mdac->rlocn.size, mdah->size - MDA_HEADER_SIZE, rlocn ? rlocn->size : 0);
- goto out;
- }
-
- new_size_rounded = mdac->rlocn.size;
- } else {
- /* Round up to a multiple of the new alignment */
- if (mdac->rlocn.offset + new_size_rounded < mdah->size)
- new_size_rounded = (mdac->rlocn.size | (alignment - 1)) + 1;
- else
- new_size_rounded = mdac->rlocn.size;
+ if ((new_wrap && old_wrap) ||
+ (rlocn && (new_wrap || old_wrap) && (new_end > rlocn->offset)) ||
+ (MDA_HEADER_SIZE + (rlocn ? rlocn->size : 0) + mdac->rlocn.size >= mdah->size)) {
+ log_error("VG %s metadata on %s (" FMTu64 " bytes) too large for circular buffer (" FMTu64 " bytes with " FMTu64 " used)",
+ vg->name, dev_name(mdac->area.dev), mdac->rlocn.size, mdah->size - MDA_HEADER_SIZE, rlocn ? rlocn->size : 0);
+ goto out;
}
- log_debug_metadata("Writing %s metadata to %s at " FMTu64 " len " FMTu64 " (rounded to " FMTu64 ") of " FMTu64 " aligned to " FMTu64,
- vg->name, dev_name(mdac->area.dev), mdac->area.start +
- mdac->rlocn.offset, mdac->rlocn.size - new_wrap, new_size_rounded, mdac->rlocn.size, alignment);
+ log_debug_metadata("Writing metadata for VG %s to %s at %llu len %llu (wrap %llu)",
+ vg->name, dev_name(mdac->area.dev),
+ (unsigned long long)(mdac->area.start + mdac->rlocn.offset),
+ (unsigned long long)(mdac->rlocn.size - new_wrap),
+ (unsigned long long)new_wrap);
- if (!new_wrap) {
- /* Write text out, in alignment-sized blocks */
- if (!dev_write(mdac->area.dev, mdac->area.start + mdac->rlocn.offset,
- (size_t) new_size_rounded, MDA_CONTENT_REASON(mda_is_primary(mda)),
- fidtc->raw_metadata_buf))
- goto_out;
- } else {
- /* Write text out, circularly */
- if (!dev_write(mdac->area.dev, mdac->area.start + mdac->rlocn.offset,
- (size_t) (mdac->rlocn.size - new_wrap), MDA_CONTENT_REASON(mda_is_primary(mda)),
- fidtc->raw_metadata_buf))
- goto_out;
+ if (!dev_write_bytes(mdac->area.dev, mdac->area.start + mdac->rlocn.offset,
+ (size_t) (mdac->rlocn.size - new_wrap),
+ fidtc->raw_metadata_buf)) {
+ log_error("Failed to write metadata to %s fd %d", dev_name(mdac->area.dev), mdac->area.dev->bcache_fd);
+ goto out;
+ }
- log_debug_metadata("Writing wrapped metadata to %s at " FMTu64 " len " FMTu64 " of " FMTu64,
- dev_name(mdac->area.dev), mdac->area.start +
- MDA_HEADER_SIZE, new_wrap, mdac->rlocn.size);
+ if (new_wrap) {
+ log_debug_metadata("Writing metadata for VG %s to %s at %llu len %llu (wrapped)",
+ vg->name, dev_name(mdac->area.dev),
+ (unsigned long long)(mdac->area.start + MDA_HEADER_SIZE),
+ (unsigned long long)new_wrap);
- if (!dev_write(mdac->area.dev, mdac->area.start + MDA_HEADER_SIZE,
- (size_t) new_wrap, MDA_CONTENT_REASON(mda_is_primary(mda)),
- fidtc->raw_metadata_buf + mdac->rlocn.size - new_wrap))
- goto_out;
+ if (!dev_write_bytes(mdac->area.dev, mdac->area.start + MDA_HEADER_SIZE,
+ (size_t) new_wrap,
+ fidtc->raw_metadata_buf + mdac->rlocn.size - new_wrap)) {
+ log_error("Failed to write metadata wrap to %s fd %d", dev_name(mdac->area.dev), mdac->area.dev->bcache_fd);
+ goto out;
+ }
}
mdac->rlocn.checksum = calc_crc(INITIAL_CRC, (uint8_t *)fidtc->raw_metadata_buf,
@@ -881,9 +711,6 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
out:
if (!r) {
- if (!dev_close(mdac->area.dev))
- stack;
-
dm_free(fidtc->raw_metadata_buf);
fidtc->raw_metadata_buf = NULL;
}
@@ -919,10 +746,10 @@ static int _vg_commit_raw_rlocn(struct format_instance *fid,
if (!found)
return 1;
- if (!(mdah = raw_read_mda_header(fid->fmt->cmd->mem, &mdac->area, mda_is_primary(mda))))
+ if (!(mdah = raw_read_mda_header(fid->fmt, &mdac->area, mda_is_primary(mda))))
goto_out;
- if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, mda_is_primary(mda), old_vg_name ? : vg->name, &noprecommit))) {
+ if (!(rlocn = _read_metadata_location_vg(&mdac->area, mdah, mda_is_primary(mda), old_vg_name ? : vg->name, &noprecommit))) {
mdah->raw_locns[0].offset = 0;
mdah->raw_locns[0].size = 0;
mdah->raw_locns[0].checksum = 0;
@@ -957,9 +784,10 @@ static int _vg_commit_raw_rlocn(struct format_instance *fid,
rlocn->offset = mdac->rlocn.offset;
rlocn->size = mdac->rlocn.size;
rlocn->checksum = mdac->rlocn.checksum;
- log_debug_metadata("%sCommitting %s %smetadata (%u) to %s header at " FMTu64 " (offset " FMTu64 ", size " FMTu64 ")",
- precommit ? "Pre-" : "", vg->name, mda_is_ignored(mda) ? "(ignored) " : "", vg->seqno,
- dev_name(mdac->area.dev), mdac->area.start, mdac->rlocn.offset, mdac->rlocn.size);
+ log_debug_metadata("%sCommitting %s %smetadata (%u) to %s header at "
+ FMTu64, precommit ? "Pre-" : "", vg->name,
+ mda_is_ignored(mda) ? "(ignored) " : "", vg->seqno,
+ dev_name(mdac->area.dev), mdac->area.start);
} else
log_debug_metadata("Wiping pre-committed %s %smetadata from %s "
"header at " FMTu64, vg->name,
@@ -979,10 +807,6 @@ static int _vg_commit_raw_rlocn(struct format_instance *fid,
out:
if (!precommit) {
- /* This is an paired with the open at the start of _vg_write_raw */
- if (!dev_close(mdac->area.dev))
- stack;
-
dm_free(fidtc->raw_metadata_buf);
fidtc->raw_metadata_buf = NULL;
}
@@ -1036,15 +860,28 @@ static int _vg_remove_raw(struct format_instance *fid, struct volume_group *vg,
int r = 0;
int noprecommit = 0;
- if (!dev_open(mdac->area.dev))
- return_0;
+ if (!(mdah = dm_pool_alloc(fid->fmt->cmd->mem, MDA_HEADER_SIZE))) {
+ log_error("struct mda_header allocation failed");
+ return 0;
+ }
- if (!(mdah = raw_read_mda_header(fid->fmt->cmd->mem, &mdac->area, mda_is_primary(mda))))
- goto_out;
+ /*
+ * FIXME: what's the point of reading the mda_header and metadata,
+ * since we zero the rlocn fields whether we can read them or not.
+ */
- if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, mda_is_primary(mda), vg->name, &noprecommit))) {
+ if (!_raw_read_mda_header(mdah, &mdac->area, mda_is_primary(mda))) {
+ log_warn("WARNING: Removing metadata location on %s with bad mda header.",
+ dev_name(mdac->area.dev));
rlocn = &mdah->raw_locns[0];
mdah->raw_locns[1].offset = 0;
+ } else {
+ if (!(rlocn = _read_metadata_location_vg(&mdac->area, mdah, mda_is_primary(mda), vg->name, &noprecommit))) {
+ log_warn("WARNING: Removing metadata location on %s with bad metadata.",
+ dev_name(mdac->area.dev));
+ rlocn = &mdah->raw_locns[0];
+ mdah->raw_locns[1].offset = 0;
+ }
}
rlocn->offset = 0;
@@ -1062,9 +899,6 @@ static int _vg_remove_raw(struct format_instance *fid, struct volume_group *vg,
r = 1;
out:
- if (!dev_close(mdac->area.dev))
- stack;
-
return r;
}
@@ -1076,8 +910,10 @@ static struct volume_group *_vg_read_file_name(struct format_instance *fid,
time_t when;
char *desc;
- if (!(vg = text_vg_import_file(fid, read_path, &when, &desc)))
- return_NULL;
+ if (!(vg = text_read_metadata_file(fid, read_path, &when, &desc))) {
+ log_error("Failed to read VG %s from %s", vgname, read_path);
+ return NULL;
+ }
/*
* Currently you can only have a single volume group per
@@ -1101,9 +937,7 @@ static struct volume_group *_vg_read_file(struct format_instance *fid,
const char *vgname,
struct metadata_area *mda,
struct cached_vg_fmtdata **vg_fmtdata,
- unsigned *use_previous_vg __attribute__((unused)),
- int single_device __attribute__((unused)),
- unsigned ioflags __attribute__((unused)))
+ unsigned *use_previous_vg __attribute__((unused)))
{
struct text_context *tc = (struct text_context *) mda->metadata_locn;
@@ -1114,8 +948,7 @@ static struct volume_group *_vg_read_precommit_file(struct format_instance *fid,
const char *vgname,
struct metadata_area *mda,
struct cached_vg_fmtdata **vg_fmtdata,
- unsigned *use_previous_vg __attribute__((unused)),
- unsigned ioflags __attribute__((unused)))
+ unsigned *use_previous_vg __attribute__((unused)))
{
struct text_context *tc = (struct text_context *) mda->metadata_locn;
struct volume_group *vg;
@@ -1300,6 +1133,9 @@ static int _scan_file(const struct format_type *fmt, const char *vgname)
dir_list = &((struct mda_lists *) fmt->private)->dirs;
+ if (!dm_list_empty(dir_list))
+ log_debug_metadata("Scanning independent files for %s", vgname ? vgname : "VGs");
+
dm_list_iterate_items(dl, dir_list) {
if (!(d = opendir(dl->dir))) {
log_sys_error("opendir", dl->dir);
@@ -1332,10 +1168,14 @@ static int _scan_file(const struct format_type *fmt, const char *vgname)
stack;
break;
}
+
+ log_debug_metadata("Scanning independent file %s for VG %s", path, scanned_vgname);
+
if ((vg = _vg_read_file_name(fid, scanned_vgname,
path))) {
/* FIXME Store creation host in vg */
lvmcache_update_vg(vg, 0);
+ lvmcache_set_independent_location(vg->name);
release_vg(vg);
}
}
@@ -1347,83 +1187,39 @@ static int _scan_file(const struct format_type *fmt, const char *vgname)
return 1;
}
-struct vgname_from_mda_params{
- const struct format_type *fmt;
- const struct mda_header *mdah;
- struct device_area *dev_area;
- int primary_mda;
- struct lvmcache_vgsummary *vgsummary;
- uint64_t *mda_free_sectors;
- lvm_callback_fn_t update_vgsummary_fn;
- void *update_vgsummary_context;
- uint32_t wrap;
- unsigned used_cached_metadata;
- int ret;
-};
-
-static void _vgname_from_mda_process(int failed, unsigned ioflags, void *context, const void *data)
+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)
{
- struct vgname_from_mda_params *vfmp = context;
- const struct mda_header *mdah = vfmp->mdah;
- struct device_area *dev_area = vfmp->dev_area;
- struct lvmcache_vgsummary *vgsummary = vfmp->vgsummary;
- uint64_t *mda_free_sectors = vfmp->mda_free_sectors;
- const struct raw_locn *rlocn = mdah->raw_locns;
+ struct raw_locn *rlocn;
+ uint32_t wrap = 0;
+ unsigned int len = 0;
+ char buf[NAME_LEN + 1] __attribute__((aligned(8)));
uint64_t buffer_size, current_usage;
- if (failed) {
- vfmp->ret = 0;
- goto_out;
- }
-
- /* Ignore this entry if the characters aren't permissible */
- if (!validate_name(vgsummary->vgname)) {
- vfmp->ret = 0;
- goto_out;
- }
-
- log_debug_metadata("%s: %s metadata at " FMTu64 " size " FMTu64 " with wrap " FMTu32
- " (in area at " FMTu64 " size " FMTu64
- ") for %s (" FMTVGID ")",
- dev_name(dev_area->dev),
- vfmp->used_cached_metadata ? "Using cached" : "Found",
- dev_area->start + rlocn->offset,
- rlocn->size, vfmp->wrap, dev_area->start, dev_area->size, vgsummary->vgname,
- (char *)&vgsummary->vgid);
-
- if (mda_free_sectors) {
- current_usage = ALIGN_ABSOLUTE(rlocn->size, dev_area->start + rlocn->offset, MDA_ALIGNMENT);
-
- buffer_size = mdah->size - MDA_HEADER_SIZE;
+ if (mda_free_sectors)
+ *mda_free_sectors = ((dev_area->size - MDA_HEADER_SIZE) / 2) >> SECTOR_SHIFT;
- if (current_usage * 2 >= buffer_size)
- *mda_free_sectors = UINT64_C(0);
- else
- *mda_free_sectors = ((buffer_size - 2 * current_usage) / 2) >> SECTOR_SHIFT;
+ if (!mdah) {
+ log_error(INTERNAL_ERROR "read_metadata_location_summary called with NULL pointer for mda_header");
+ return 0;
}
-out:
- vfmp->update_vgsummary_fn(!vfmp->ret, ioflags, vfmp->update_vgsummary_context, vfmp->vgsummary);
-}
-
-static void _vgname_from_mda_validate(int failed, unsigned ioflags, void *context, const void *data)
-{
- struct vgname_from_mda_params *vfmp = context;
- const char *buffer = data;
- const struct format_type *fmt = vfmp->fmt;
- const struct mda_header *mdah = vfmp->mdah;
- struct device_area *dev_area = vfmp->dev_area;
- struct lvmcache_vgsummary *vgsummary = vfmp->vgsummary;
- const struct raw_locn *rlocn = mdah->raw_locns;
- unsigned len = 0;
- char buf[NAME_LEN + 1] __attribute__((aligned(8)));
+ /* FIXME Cope with returning a list */
+ rlocn = mdah->raw_locns;
- if (failed) {
- vfmp->ret = 0;
- goto_out;
+ /*
+ * If no valid offset, do not try to search for vgname
+ */
+ if (!rlocn->offset) {
+ log_debug_metadata("Metadata location on %s at %llu has offset 0.",
+ dev_name(dev_area->dev),
+ (unsigned long long)(dev_area->start + rlocn->offset));
+ vgsummary->zero_offset = 1;
+ return 0;
}
- memcpy(buf, buffer, NAME_LEN);
+ dev_read_bytes(dev_area->dev, dev_area->start + rlocn->offset, NAME_LEN, buf);
while (buf[len] && !isspace(buf[len]) && buf[len] != '{' &&
len < (NAME_LEN - 1))
@@ -1433,97 +1229,105 @@ static void _vgname_from_mda_validate(int failed, unsigned ioflags, void *contex
/* Ignore this entry if the characters aren't permissible */
if (!validate_name(buf)) {
- vfmp->ret = 0;
- goto_out;
+ log_error("Metadata location on %s at %llu begins with invalid VG name.",
+ dev_name(dev_area->dev),
+ (unsigned long long)(dev_area->start + rlocn->offset));
+ return 0;
}
/* We found a VG - now check the metadata */
if (rlocn->offset + rlocn->size > mdah->size)
- vfmp->wrap = (uint32_t) ((rlocn->offset + rlocn->size) - mdah->size);
+ wrap = (uint32_t) ((rlocn->offset + rlocn->size) - mdah->size);
- if (vfmp->wrap > rlocn->offset) {
- log_error("%s: metadata (" FMTu64 " bytes) too large for circular buffer (" FMTu64 " bytes)",
- dev_name(dev_area->dev), rlocn->size, mdah->size - MDA_HEADER_SIZE);
- vfmp->ret = 0;
- goto out;
+ if (wrap > rlocn->offset) {
+ log_error("Metadata location on %s at %llu is too large for circular buffer.",
+ dev_name(dev_area->dev),
+ (unsigned long long)(dev_area->start + rlocn->offset));
+ return 0;
}
- /* Did we see this metadata before? */
+ /*
+ * Did we see this metadata before?
+ * Look in lvmcache to see if there is vg info matching
+ * the checksum/size that we see in the mda_header (rlocn)
+ * on this device. If so, then vgsummary->name is is set
+ * and controls if the "checksum_only" flag passed to
+ * text_read_metadata_summary() is 1 or 0.
+ *
+ * If checksum_only = 1, then text_read_metadata_summary()
+ * will read the metadata from this device, and run the
+ * checksum function on it. If the calculated checksum
+ * of the metadata matches the checksum in the mda_header,
+ * which also matches the checksum saved in vginfo from
+ * another device, then it skips parsing the metadata into
+ * a config tree, which saves considerable cpu time.
+ *
+ * (NB. there can be different VGs with different metadata
+ * and checksums, but with the same name.)
+ *
+ * FIXME: handle the case where mda_header checksum is bad
+ * but metadata checksum is good.
+ */
+
+ /*
+ * If the checksum we compute of the metadata differs from
+ * the checksum from mda_header that we save here, then we
+ * ignore the device. FIXME: we need to classify a device
+ * with errors like this as defective.
+ *
+ * If the checksum from mda_header and computed from metadata
+ * does not match the checksum saved in lvmcache from a prev
+ * device, then we do not skip parsing/saving metadata from
+ * this dev. It's parsed, fields saved in vgsummary, which
+ * is passed into lvmcache (update_vgname_and_id), and
+ * there we'll see a checksum mismatch.
+ */
vgsummary->mda_checksum = rlocn->checksum;
vgsummary->mda_size = rlocn->size;
+ lvmcache_lookup_mda(vgsummary);
- if (lvmcache_lookup_mda(vgsummary))
- vfmp->used_cached_metadata = 1;
-
- /* FIXME 64-bit */
- if (!text_vgsummary_import(fmt, dev_area->dev, MDA_CONTENT_REASON(vfmp->primary_mda),
+ if (!text_read_metadata_summary(fmt, dev_area->dev, MDA_CONTENT_REASON(primary_mda),
(off_t) (dev_area->start + rlocn->offset),
- (uint32_t) (rlocn->size - vfmp->wrap),
+ (uint32_t) (rlocn->size - wrap),
(off_t) (dev_area->start + MDA_HEADER_SIZE),
- vfmp->wrap, calc_crc, vgsummary->vgname ? 1 : 0, ioflags,
- vgsummary, _vgname_from_mda_process, vfmp)) {
- vfmp->ret = 0;
- goto_out;
+ wrap, calc_crc, vgsummary->vgname ? 1 : 0,
+ vgsummary)) {
+ log_error("Metadata location on %s at %llu has invalid summary for VG.",
+ dev_name(dev_area->dev),
+ (unsigned long long)(dev_area->start + rlocn->offset));
+ return 0;
}
-out:
- if (!vfmp->ret && vfmp->update_vgsummary_fn)
- vfmp->update_vgsummary_fn(1, ioflags, vfmp->update_vgsummary_context, vfmp->vgsummary);
-}
-
-int vgname_from_mda(const struct format_type *fmt,
- const 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_fn, void *update_vgsummary_context)
-{
- const struct raw_locn *rlocn;
- struct vgname_from_mda_params *vfmp;
-
- if (mda_free_sectors)
- *mda_free_sectors = ((dev_area->size - MDA_HEADER_SIZE) / 2) >> SECTOR_SHIFT;
-
- if (!mdah) {
- log_error(INTERNAL_ERROR "vgname_from_mda called with NULL pointer for mda_header");
+ /* Ignore this entry if the characters aren't permissible */
+ if (!validate_name(vgsummary->vgname)) {
+ log_error("Metadata location on %s at %llu has invalid VG name.",
+ dev_name(dev_area->dev),
+ (unsigned long long)(dev_area->start + rlocn->offset));
return 0;
}
- /* FIXME Cope with returning a list */
- rlocn = mdah->raw_locns;
+ log_debug_metadata("Found metadata summary on %s at %llu size %llu for VG %s",
+ dev_name(dev_area->dev),
+ (unsigned long long)(dev_area->start + rlocn->offset),
+ (unsigned long long)rlocn->size,
+ vgsummary->vgname);
- /*
- * If no valid offset, do not try to search for vgname
- */
- if (!rlocn->offset) {
- log_debug("%s: found metadata with offset 0.",
- dev_name(dev_area->dev));
- return 0;
- }
+ if (mda_free_sectors) {
+ current_usage = (rlocn->size + SECTOR_SIZE - UINT64_C(1)) -
+ (rlocn->size + SECTOR_SIZE - UINT64_C(1)) % SECTOR_SIZE;
+ buffer_size = mdah->size - MDA_HEADER_SIZE;
- if (!(vfmp = dm_pool_zalloc(fmt->cmd->mem, sizeof(*vfmp)))) {
- log_error("vgname_from_mda_params allocation failed");
- return 0;
+ if (current_usage * 2 >= buffer_size)
+ *mda_free_sectors = UINT64_C(0);
+ else
+ *mda_free_sectors = ((buffer_size - 2 * current_usage) / 2) >> SECTOR_SHIFT;
}
- vfmp->fmt = fmt;
- vfmp->mdah = mdah;
- vfmp->dev_area = dev_area;
- vfmp->vgsummary = vgsummary;
- vfmp->primary_mda = primary_mda;
- vfmp->mda_free_sectors = mda_free_sectors;
- vfmp->update_vgsummary_fn = update_vgsummary_fn;
- vfmp->update_vgsummary_context = update_vgsummary_context;
- vfmp->ret = 1;
-
- /* Do quick check for a vgname */
- /* We cannot read the full metadata here because the name has to be validated before we use the size field */
- dev_read_callback(dev_area->dev, dev_area->start + rlocn->offset, NAME_LEN, MDA_CONTENT_REASON(primary_mda),
- ioflags, _vgname_from_mda_validate, vfmp);
- if (update_vgsummary_fn)
- return 1;
- else
- return vfmp->ret;
+ return 1;
}
+/* used for independent_metadata_areas */
+
static int _scan_raw(const struct format_type *fmt, const char *vgname __attribute__((unused)))
{
struct raw_list *rl;
@@ -1535,39 +1339,40 @@ static int _scan_raw(const struct format_type *fmt, const char *vgname __attribu
raw_list = &((struct mda_lists *) fmt->private)->raws;
+ if (!dm_list_empty(raw_list))
+ log_debug_metadata("Scanning independent raw locations for %s", vgname ? vgname : "VGs");
+
fid.fmt = fmt;
dm_list_init(&fid.metadata_areas_in_use);
dm_list_init(&fid.metadata_areas_ignored);
dm_list_iterate_items(rl, raw_list) {
- /* FIXME We're reading mdah twice here... */
- if (!dev_open_readonly(rl->dev_area.dev)) {
- stack;
- continue;
- }
+ log_debug_metadata("Scanning independent dev %s", dev_name(rl->dev_area.dev));
- if (!(mdah = raw_read_mda_header(fmt->cmd->mem, &rl->dev_area, 0))) {
+ if (!(mdah = raw_read_mda_header(fmt, &rl->dev_area, 0))) {
stack;
- goto close_dev;
+ continue;
}
- /* TODO: caching as in vgname_from_mda() (trigger this code?) */
- if (vgname_from_mda(fmt, mdah, 0, &rl->dev_area, &vgsummary, NULL, 0, NULL, NULL)) {
- vg = _vg_read_raw_area(&fid, vgsummary.vgname, &rl->dev_area, NULL, NULL, 0, 0, 0, 0);
- if (vg)
+ if (read_metadata_location_summary(fmt, mdah, 0, &rl->dev_area, &vgsummary, NULL)) {
+ vg = _vg_read_raw_area(&fid, vgsummary.vgname, &rl->dev_area, NULL, NULL, 0, 0);
+ if (vg) {
lvmcache_update_vg(vg, 0);
+ lvmcache_set_independent_location(vg->name);
+ }
}
- close_dev:
- if (!dev_close(rl->dev_area.dev))
- stack;
}
return 1;
}
+/* used for independent_metadata_areas */
+
static int _text_scan(const struct format_type *fmt, const char *vgname)
{
- return (_scan_file(fmt, vgname) & _scan_raw(fmt, vgname));
+ _scan_file(fmt, vgname);
+ _scan_raw(fmt, vgname);
+ return 1;
}
struct _write_single_mda_baton {
@@ -1589,8 +1394,6 @@ static int _write_single_mda(struct metadata_area *mda, void *baton)
if (!_raw_write_mda_header(p->fmt, mdac->area.dev, mda_is_primary(mda),
mdac->area.start, mdah)) {
- if (!dev_close(p->pv->dev))
- stack;
return_0;
}
return 1;
@@ -1685,9 +1488,6 @@ static int _text_pv_write(const struct format_type *fmt, struct physical_volume
if (!lvmcache_update_das(info, pv))
return_0;
- if (!dev_open(pv->dev))
- return_0;
-
baton.pv = pv;
baton.fmt = fmt;
@@ -1699,8 +1499,6 @@ static int _text_pv_write(const struct format_type *fmt, struct physical_volume
if (!label_write(pv->dev, label)) {
stack;
- if (!dev_close(pv->dev))
- stack;
return 0;
}
@@ -1710,9 +1508,6 @@ static int _text_pv_write(const struct format_type *fmt, struct physical_volume
* update the cache afterwards?
*/
- if (!dev_close(pv->dev))
- return_0;
-
return 1;
}
@@ -1796,36 +1591,6 @@ static uint64_t _metadata_locn_offset_raw(void *metadata_locn)
return mdac->area.start;
}
-static int _text_pv_read(const struct format_type *fmt, const char *pv_name,
- struct physical_volume *pv, int scan_label_only)
-{
- struct lvmcache_info *info;
- struct device *dev;
-
- if (!(dev = dev_cache_get(pv_name, fmt->cmd->filter)))
- return_0;
-
- if (lvmetad_used()) {
- info = lvmcache_info_from_pvid(dev->pvid, dev, 0);
- if (!info && !lvmetad_pv_lookup_by_dev(fmt->cmd, dev, NULL))
- return 0;
- info = lvmcache_info_from_pvid(dev->pvid, dev, 0);
- } else {
- struct label *label;
- if (!(label_read(dev, &label, UINT64_C(0))))
- return_0;
- info = label->info;
- }
-
- if (!info)
- return_0;
-
- if (!lvmcache_populate_pv_fields(info, pv, scan_label_only))
- return 0;
-
- return 1;
-}
-
static int _text_pv_initialise(const struct format_type *fmt,
struct pv_create_args *pva,
struct physical_volume *pv)
@@ -2019,13 +1784,22 @@ static struct metadata_area_ops _metadata_text_raw_ops = {
.mda_import_text = _mda_import_text_raw
};
+/* used only for sending info to lvmetad */
+
static int _mda_export_text_raw(struct metadata_area *mda,
struct dm_config_tree *cft,
struct dm_config_node *parent)
{
struct mda_context *mdc = (struct mda_context *) mda->metadata_locn;
+ char mdah[MDA_HEADER_SIZE]; /* temporary */
- if (!mdc || !_raw_read_mda_header(cft->mem, &mdc->area, mda_is_primary(mda), 0, NULL, NULL))
+ if (!mdc) {
+ log_error(INTERNAL_ERROR "mda_export_text_raw no mdc");
+ return 1; /* pretend the MDA does not exist */
+ }
+
+ /* FIXME: why aren't ignore,start,size,free_sectors available? */
+ if (!_raw_read_mda_header((struct mda_header *)mdah, &mdc->area, mda_is_primary(mda)))
return 1; /* pretend the MDA does not exist */
return config_make_nodes(cft, parent, NULL,
@@ -2036,6 +1810,8 @@ static int _mda_export_text_raw(struct metadata_area *mda,
NULL) ? 1 : 0;
}
+/* used only for receiving info from lvmetad */
+
static int _mda_import_text_raw(struct lvmcache_info *info, const struct dm_config_node *cn)
{
struct device *device;
@@ -2265,22 +2041,6 @@ static int _create_vg_text_instance(struct format_instance *fid,
}
if (type & FMT_INSTANCE_MDAS) {
- /*
- * TODO in theory, this function should be never reached
- * while in critical_section(), because lvmcache's
- * cached_vg should be valid. However, this assumption
- * sometimes fails (possibly due to inconsistent
- * (precommit) metadata and/or missing devices), and
- * calling lvmcache_label_scan inside the critical
- * section may be fatal (i.e. deadlock).
- */
- if (!critical_section())
- /* Scan PVs in VG for any further MDAs */
- /*
- * FIXME Only scan PVs believed to be in the VG.
- */
- lvmcache_label_scan(fid->fmt->cmd);
-
if (!(vginfo = lvmcache_vginfo_from_vgname(vg_name, vg_id)))
goto_out;
if (!lvmcache_fid_add_mdas_vg(vginfo, fid))
@@ -2358,6 +2118,7 @@ static int _text_pv_add_metadata_area(const struct format_type *fmt,
uint64_t mda_start;
uint64_t adjustment, limit, tmp_mda_size;
uint64_t wipe_size = 8 << SECTOR_SHIFT;
+ uint64_t zero_len;
size_t page_size = lvm_getpagesize();
struct metadata_area *mda;
struct mda_context *mdac;
@@ -2565,13 +2326,14 @@ static int _text_pv_add_metadata_area(const struct format_type *fmt,
}
/* Wipe metadata area with zeroes. */
- if (!dev_set(pv->dev, mda_start,
- (size_t) ((mda_size > wipe_size) ? wipe_size : mda_size),
- MDA_HEADER_REASON(!mda_index), 0)) {
- log_error("Failed to wipe new metadata area "
- "at the %s of the %s",
- mda_index ? "end" : "start",
- pv_dev_name(pv));
+
+ zero_len = (mda_size > wipe_size) ? wipe_size : mda_size;
+
+ if (!dev_write_zeros(pv->dev, mda_start, zero_len)) {
+ log_error("Failed to wipe new metadata area on %s at %llu len %llu",
+ pv_dev_name(pv),
+ (unsigned long long)mda_start,
+ (unsigned long long)zero_len);
return 0;
}
@@ -2679,7 +2441,6 @@ static struct format_instance *_text_create_text_instance(const struct format_ty
static struct format_handler _text_handler = {
.scan = _text_scan,
- .pv_read = _text_pv_read,
.pv_initialise = _text_pv_initialise,
.pv_setup = _text_pv_setup,
.pv_add_metadata_area = _text_pv_add_metadata_area,
@@ -2750,7 +2511,7 @@ static int _get_config_disk_area(struct cmd_context *cmd,
return 0;
}
- if (!(dev_area.dev = lvmcache_device_from_pvid(cmd, &id, NULL, NULL))) {
+ if (!(dev_area.dev = lvmcache_device_from_pvid(cmd, &id, NULL))) {
char buffer[64] __attribute__((aligned(8)));
if (!id_write_format(&id, buffer, sizeof(buffer)))
diff --git a/lib/format_text/import-export.h b/lib/format_text/import-export.h
index 2c329d076..920eb3e83 100644
--- a/lib/format_text/import-export.h
+++ b/lib/format_text/import-export.h
@@ -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
diff --git a/lib/format_text/import.c b/lib/format_text/import.c
index 0138ddd8b..4b344856f 100644
--- a/lib/format_text/import.c
+++ b/lib/format_text/import.c
@@ -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,133 +32,50 @@ 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)
-{
- struct import_vgsummary_params *ivsp = context;
- struct text_vg_version_ops **vsn;
-
- if (failed) {
- ivsp->ret = 0;
- goto_out;
- }
-
- if (ivsp->checksum_only)
- /* Checksum matches already-cached content - no need to reparse. */
- 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))
- continue;
-
- if (!(*vsn)->read_vgsummary(ivsp->fmt, ivsp->cft, ivsp->vgsummary)) {
- ivsp->ret = 0;
- goto_out;
- }
-
- goto out;
- }
-
- /* 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,
+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)
{
- struct import_vgsummary_params *ivsp;
+ struct dm_config_tree *cft;
+ struct text_vg_version_ops **vsn;
+ int r = 0;
_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)))
+ if (!(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;
+ 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;
}
- _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;
-}
-
-struct cached_vg_fmtdata {
- uint32_t cached_mda_checksum;
- 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 import_vg_params *ivp = context;
- struct text_vg_version_ops **vsn;
-
- ivp->vg = NULL;
-
- if (ivp->skip_parse) {
- if (ivp->use_previous_vg)
- *ivp->use_previous_vg = 1;
+ 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;
}
@@ -167,98 +83,131 @@ 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 (!(*vsn)->read_vgsummary(fmt, cft, vgsummary))
goto_out;
- (*vsn)->read_desc(ivp->vg->vgmem, ivp->cft, ivp->when, ivp->desc);
+ r = 1;
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 (ivp->use_previous_vg)
- *ivp->use_previous_vg = 0;
-
-out:
- config_destroy(ivp->cft);
+ out:
+ config_destroy(cft);
+ return r;
}
-struct volume_group *text_vg_import_fd(struct format_instance *fid,
+struct cached_vg_fmtdata {
+ uint32_t cached_mda_checksum;
+ size_t cached_mda_size;
+};
+
+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)
{
- struct import_vg_params *ivp;
+ struct volume_group *vg = NULL;
+ struct dm_config_tree *cft;
+ struct text_vg_version_ops **vsn;
+ int skip_parse;
+ /*
+ * 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 = 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)))
+ *desc = NULL;
+ *when = 0;
+
+ if (!(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);
+ skip_parse = vg_fmtdata &&
+ ((*vg_fmtdata)->cached_mda_checksum == checksum) &&
+ ((*vg_fmtdata)->cached_mda_size == (size + size2));
- 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;
+ 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;
}
- } else
- _import_vg(0, 0, ivp, NULL);
+ }
+
+ if (skip_parse) {
+ if (use_previous_vg)
+ *use_previous_vg = 1;
+ log_debug_metadata("Skipped parsing metadata on %s", dev_name(dev));
+ 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(cft))
+ continue;
+
+ if (!(vg = (*vsn)->read_vg(fid, cft, 0)))
+ goto_out;
- return ivp->vg;
+ (*vsn)->read_desc(vg->vgmem, cft, when, desc);
+ break;
+ }
+
+ if (vg && vg_fmtdata && *vg_fmtdata) {
+ (*vg_fmtdata)->cached_mda_size = (size + size2);
+ (*vg_fmtdata)->cached_mda_checksum = checksum;
+ }
+
+ if (use_previous_vg)
+ *use_previous_vg = 0;
+
+ out:
+ config_destroy(cft);
+ return 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.",
diff --git a/lib/format_text/import_vsn1.c b/lib/format_text/import_vsn1.c
index 9267d4581..e038a273f 100644
--- a/lib/format_text/import_vsn1.c
+++ b/lib/format_text/import_vsn1.c
@@ -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;
}
diff --git a/lib/format_text/layout.h b/lib/format_text/layout.h
index 98a0b362f..2671bbf02 100644
--- a/lib/format_text/layout.h
+++ b/lib/format_text/layout.h
@@ -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
diff --git a/lib/format_text/text_label.c b/lib/format_text/text_label.c
index 45136e9c4..7d10e065b 100644
--- a/lib/format_text/text_label.c
+++ b/lib/format_text/text_label.c
@@ -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)
-{
- 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)
+static int _read_mda_header_and_metadata(struct metadata_area *mda, void *baton)
{
- 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;
- }
-
- 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;
+ return 1;
}
- 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++;
-
- return 1;
-}
-
-static int _update_mda(struct metadata_area *mda, void *baton)
-{
- 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 (!read_metadata_location_summary(fmt, mdah, mda_is_primary(mda), &mdac->area,
+ &vgsummary, &mdac->free_sectors)) {
+ if (vgsummary.zero_offset)
+ return 1;
- if (!(pmp = dm_pool_zalloc(mem, sizeof(*pmp)))) {
- log_error("struct process_mda_header_params allocation failed");
- return 0;
+ log_error("Failed to read metadata summary from %s", dev_name(mdac->area.dev));
+ goto fail;
}
- /*
- * 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;
+ 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;
}
- 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;
- }
+ return 1;
- if (umb->read_label_callback_fn)
- return 1;
- else
- return pmp->ret;
+fail:
+ lvmcache_del(p->info);
+ return 0;
}
-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)
+static int _text_read(struct labeller *l, struct device *dev, void *label_buf,
+ struct label **label)
{
- 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;
- }
-
- 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;
+ baton.info = info;
+ baton.label = *label;
- 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;
+ /*
+ * 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;
}
- 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)),
diff --git a/lib/label/label.c b/lib/label/label.c
index 32fad826f..4b18f5682 100644
--- a/lib/label/label.c
+++ b/lib/label/label.c
@@ -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-2007 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -18,14 +18,17 @@
#include "crc.h"
#include "xlate.h"
#include "lvmcache.h"
+#include "bcache.h"
+#include "toolcontext.h"
+#include "activate.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
+#include <sys/time.h>
-/* FIXME Allow for larger labels? Restricted to single sector currently */
-static struct dm_pool *_labeller_mem;
+/* FIXME Allow for larger labels? Restricted to single sector currently */
/*
* Internal labeller struct.
@@ -59,13 +62,7 @@ static struct labeller_i *_alloc_li(const char *name, struct labeller *l)
int label_init(void)
{
- if (!(_labeller_mem = dm_pool_create("label scan", 128))) {
- log_error("Labeller pool creation failed.");
- return 0;
- }
-
dm_list_init(&_labellers);
-
return 1;
}
@@ -80,8 +77,6 @@ void label_exit(void)
}
dm_list_init(&_labellers);
-
- dm_pool_destroy(_labeller_mem);
}
int label_register_handler(struct labeller *handler)
@@ -106,343 +101,892 @@ struct labeller *label_get_handler(const char *name)
return NULL;
}
-static void _update_lvmcache_orphan(struct lvmcache_info *info)
+/* FIXME Also wipe associated metadata area headers? */
+int label_remove(struct device *dev)
{
- struct lvmcache_vgsummary vgsummary_orphan = {
- .vgname = lvmcache_fmt(info)->orphan_vg_name,
- };
+ char readbuf[LABEL_SIZE] __attribute__((aligned(8)));
+ int r = 1;
+ uint64_t sector;
+ int wipe;
+ struct labeller_i *li;
+ struct label_header *lh;
+ struct lvmcache_info *info;
- memcpy(&vgsummary_orphan.vgid, lvmcache_fmt(info)->orphan_vg_name, strlen(lvmcache_fmt(info)->orphan_vg_name));
+ log_very_verbose("Scanning for labels to wipe from %s", dev_name(dev));
- if (!lvmcache_update_vgname_and_id(info, &vgsummary_orphan))
- stack;
-}
+ if (!label_scan_open(dev)) {
+ log_error("Failed to open device %s", dev_name(dev));
+ return 0;
+ }
-struct find_labeller_params {
- struct device *dev;
- uint64_t scan_sector; /* Sector to be scanned */
- uint64_t label_sector; /* Sector where label found */
- lvm_callback_fn_t process_label_data_fn;
- void *process_label_data_context;
+ /* Scan first few sectors for anything looking like a label */
+ for (sector = 0; sector < LABEL_SCAN_SECTORS;
+ sector += LABEL_SIZE >> SECTOR_SHIFT) {
- struct label **result;
+ memset(readbuf, 0, sizeof(readbuf));
- int ret;
-};
+ if (!dev_read_bytes(dev, sector << SECTOR_SHIFT, LABEL_SIZE, readbuf)) {
+ log_error("Failed to read label from %s sector %llu",
+ dev_name(dev), (unsigned long long)sector);
+ continue;
+ }
+
+ lh = (struct label_header *)readbuf;
+
+ wipe = 0;
+
+ if (!strncmp((char *)lh->id, LABEL_ID, sizeof(lh->id))) {
+ if (xlate64(lh->sector_xl) == sector)
+ wipe = 1;
+ } else {
+ dm_list_iterate_items(li, &_labellers) {
+ if (li->l->ops->can_handle(li->l, (char *)lh, sector)) {
+ wipe = 1;
+ break;
+ }
+ }
+ }
+
+ if (wipe) {
+ log_very_verbose("%s: Wiping label at sector %llu",
+ dev_name(dev), (unsigned long long)sector);
+
+ if (!dev_write_zeros(dev, sector << SECTOR_SHIFT, LABEL_SIZE)) {
+ log_error("Failed to remove label from %s at sector %llu",
+ dev_name(dev), (unsigned long long)sector);
+ r = 0;
+ } else {
+ /* Also remove the PV record from cache. */
+ info = lvmcache_info_from_pvid(dev->pvid, dev, 0);
+ if (info)
+ lvmcache_del(info);
+ }
+ }
+ }
-static void _set_label_read_result(int failed, unsigned ioflags, void *context, const void *data)
+ return r;
+}
+
+/* Caller may need to use label_get_handler to create label struct! */
+int label_write(struct device *dev, struct label *label)
{
- struct find_labeller_params *flp = context;
- struct label **result = flp->result;
- struct label *label = (struct label *) data;
+ char buf[LABEL_SIZE] __attribute__((aligned(8)));
+ struct label_header *lh = (struct label_header *) buf;
+ int r = 1;
- if (failed) {
- flp->ret = 0;
- goto_out;
+ if (!label->labeller->ops->write) {
+ log_error("Label handler does not support label writes");
+ return 0;
}
- /* Fix up device and label sector which the low-level code doesn't set */
- if (label) {
- label->dev = flp->dev;
- label->sector = flp->label_sector;
+ if ((LABEL_SIZE + (label->sector << SECTOR_SHIFT)) > LABEL_SCAN_SIZE) {
+ log_error("Label sector %" PRIu64 " beyond range (%ld)",
+ label->sector, LABEL_SCAN_SECTORS);
+ return 0;
}
- if (result)
- *result = (struct label *) label;
+ memset(buf, 0, LABEL_SIZE);
+
+ strncpy((char *)lh->id, LABEL_ID, sizeof(lh->id));
+ lh->sector_xl = xlate64(label->sector);
+ lh->offset_xl = xlate32(sizeof(*lh));
+
+ if (!(label->labeller->ops->write)(label, buf))
+ return_0;
-out:
- if (!dev_close(flp->dev))
- stack;
+ lh->crc_xl = xlate32(calc_crc(INITIAL_CRC, (uint8_t *)&lh->offset_xl, LABEL_SIZE -
+ ((uint8_t *) &lh->offset_xl - (uint8_t *) lh)));
- if (flp->process_label_data_fn) {
- log_debug_io("Completed label reading for %s", dev_name(flp->dev));
- flp->process_label_data_fn(!flp->ret, ioflags, flp->process_label_data_context, NULL);
+ log_very_verbose("%s: Writing label to sector %" PRIu64 " with stored offset %"
+ PRIu32 ".", dev_name(dev), label->sector,
+ xlate32(lh->offset_xl));
+
+ if (!label_scan_open(dev)) {
+ log_error("Failed to open device %s", dev_name(dev));
+ return 0;
+ }
+
+ if (!dev_write_bytes(dev, label->sector << SECTOR_SHIFT, LABEL_SIZE, buf)) {
+ log_debug_devs("Failed to write label to %s", dev_name(dev));
+ r = 0;
}
+
+ return r;
+}
+
+void label_destroy(struct label *label)
+{
+ label->labeller->ops->destroy_label(label->labeller, label);
+ dm_free(label);
}
-static void _find_labeller(int failed, unsigned ioflags, void *context, const void *data)
+struct label *label_create(struct labeller *labeller)
+{
+ struct label *label;
+
+ if (!(label = dm_zalloc(sizeof(*label)))) {
+ log_error("label allocaction failed");
+ return NULL;
+ }
+
+ label->labeller = labeller;
+
+ labeller->ops->initialise_label(labeller, label);
+
+ return label;
+}
+
+
+/* global variable for accessing the bcache populated by label scan */
+struct bcache *scan_bcache;
+
+#define BCACHE_BLOCK_SIZE_IN_SECTORS 256 /* 256*512 = 128K */
+
+static bool _in_bcache(struct device *dev)
+{
+ if (!dev)
+ return NULL;
+ return (dev->flags & DEV_IN_BCACHE) ? true : false;
+}
+
+static struct labeller *_find_lvm_header(struct device *dev,
+ char *scan_buf,
+ char *label_buf,
+ uint64_t *label_sector,
+ uint64_t scan_sector)
{
- struct find_labeller_params *flp = context;
- const char *readbuf = data;
- struct device *dev = flp->dev;
- uint64_t scan_sector = flp->scan_sector;
- char labelbuf[LABEL_SIZE] __attribute__((aligned(8)));
struct labeller_i *li;
- struct labeller *l = NULL; /* Set when a labeller claims the label */
- const struct label_header *lh;
- struct lvmcache_info *info;
+ struct labeller *labeller_ret = NULL;
+ struct label_header *lh;
uint64_t sector;
+ int found = 0;
- if (failed) {
- log_debug_devs("%s: Failed to read label area", dev_name(dev));
- _set_label_read_result(1, ioflags, flp, NULL);
- return;
- }
+ /*
+ * Find which sector in scan_buf starts with a valid label,
+ * and copy it into label_buf.
+ */
- /* Scan a few sectors for a valid label */
for (sector = 0; sector < LABEL_SCAN_SECTORS;
sector += LABEL_SIZE >> SECTOR_SHIFT) {
- lh = (struct label_header *) (readbuf + (sector << SECTOR_SHIFT));
+ lh = (struct label_header *) (scan_buf + (sector << SECTOR_SHIFT));
if (!strncmp((char *)lh->id, LABEL_ID, sizeof(lh->id))) {
- if (l) {
- log_error("Ignoring additional label on %s at "
- "sector %" PRIu64, dev_name(dev),
- sector + scan_sector);
+ if (found) {
+ log_error("Ignoring additional label on %s at sector %llu",
+ dev_name(dev), (unsigned long long)(sector + scan_sector));
}
if (xlate64(lh->sector_xl) != sector + scan_sector) {
- log_very_verbose("%s: Label for sector %" PRIu64
- " found at sector %" PRIu64
- " - ignoring", dev_name(dev),
- (uint64_t)xlate64(lh->sector_xl),
- sector + scan_sector);
+ log_very_verbose("%s: Label for sector %llu found at sector %llu - ignoring.",
+ dev_name(dev),
+ (unsigned long long)xlate64(lh->sector_xl),
+ (unsigned long long)(sector + scan_sector));
continue;
}
if (calc_crc(INITIAL_CRC, (uint8_t *)&lh->offset_xl, LABEL_SIZE -
((uint8_t *) &lh->offset_xl - (uint8_t *) lh)) !=
xlate32(lh->crc_xl)) {
- log_very_verbose("Label checksum incorrect on %s - "
- "ignoring", dev_name(dev));
+ log_very_verbose("Label checksum incorrect on %s - ignoring", dev_name(dev));
continue;
}
- if (l)
+ if (found)
continue;
}
dm_list_iterate_items(li, &_labellers) {
- if (li->l->ops->can_handle(li->l, (char *) lh,
- sector + scan_sector)) {
- log_very_verbose("%s: %s label detected at "
- "sector %" PRIu64,
+ if (li->l->ops->can_handle(li->l, (char *) lh, sector + scan_sector)) {
+ log_very_verbose("%s: %s label detected at sector %llu",
dev_name(dev), li->name,
- sector + scan_sector);
- if (l) {
- log_error("Ignoring additional label "
- "on %s at sector %" PRIu64,
+ (unsigned long long)(sector + scan_sector));
+ if (found) {
+ log_error("Ignoring additional label on %s at sector %llu",
dev_name(dev),
- sector + scan_sector);
+ (unsigned long long)(sector + scan_sector));
continue;
}
- memcpy(labelbuf, lh, LABEL_SIZE);
- flp->label_sector = sector + scan_sector;
- l = li->l;
+
+ labeller_ret = li->l;
+ found = 1;
+
+ memcpy(label_buf, lh, LABEL_SIZE);
+ if (label_sector)
+ *label_sector = sector + scan_sector;
break;
}
}
}
- if (!l) {
- if ((info = lvmcache_info_from_pvid(dev->pvid, dev, 0)))
- _update_lvmcache_orphan(info);
- log_very_verbose("%s: No label detected", dev_name(dev));
- flp->ret = 0;
- _set_label_read_result(1, ioflags, flp, NULL);
- } else
- (void) (l->ops->read)(l, dev, labelbuf, ioflags, &_set_label_read_result, flp);
+ return labeller_ret;
}
-/* FIXME Also wipe associated metadata area headers? */
-int label_remove(struct device *dev)
+/*
+ * Process/parse the headers from the data read from a device.
+ * Populates lvmcache with device / mda locations / vgname
+ * so that vg_read(vgname) will know which devices/locations
+ * to read metadata from.
+ *
+ * If during processing, headers/metadata are found to be needed
+ * beyond the range of the scanned block, then additional reads
+ * are performed in the processing functions to get that data.
+ */
+static int _process_block(struct device *dev, struct block *bb, int *is_lvm_device)
{
- char labelbuf[LABEL_SIZE] __attribute__((aligned(8)));
- int r = 1;
+ char label_buf[LABEL_SIZE] __attribute__((aligned(8)));
+ struct label *label = NULL;
+ struct labeller *labeller;
uint64_t sector;
- int wipe;
- struct labeller_i *li;
- struct label_header *lh;
- struct lvmcache_info *info;
- const char *readbuf = NULL;
+ int ret = 0;
- memset(labelbuf, 0, LABEL_SIZE);
+ /*
+ * Finds the data sector containing the label and copies into label_buf.
+ * label_buf: struct label_header + struct pv_header + struct pv_header_extension
+ *
+ * FIXME: we don't need to copy one sector from bb->data into label_buf,
+ * we can just point label_buf at one sector in ld->buf.
+ */
+ if (!(labeller = _find_lvm_header(dev, bb->data, label_buf, &sector, 0))) {
- log_very_verbose("Scanning for labels to wipe from %s", dev_name(dev));
+ /*
+ * Non-PVs exit here
+ *
+ * FIXME: check for PVs with errors that also exit here!
+ * i.e. this code cannot distinguish between a non-lvm
+ * device an an lvm device with errors.
+ */
- if (!dev_open(dev))
- return_0;
+ log_very_verbose("%s: No lvm label detected", dev_name(dev));
+
+ lvmcache_del_dev(dev); /* FIXME: if this is needed, fix it. */
+
+ *is_lvm_device = 0;
+ goto_out;
+ }
+
+ *is_lvm_device = 1;
/*
- * We flush the device just in case someone is stupid
- * enough to be trying to import an open pv into lvm.
+ * This is the point where the scanning code dives into the rest of
+ * lvm. ops->read() is usually _text_read() which reads the pv_header,
+ * mda locations, mda contents. As these bits of data are read, they
+ * are saved into lvmcache as info/vginfo structs.
*/
- dev_flush(dev);
- if (!(readbuf = dev_read(dev, UINT64_C(0), LABEL_SCAN_SIZE, DEV_IO_LABEL))) {
- log_debug_devs("%s: Failed to read label area", dev_name(dev));
- goto out;
+ if ((ret = (labeller->ops->read)(labeller, dev, label_buf, &label)) && label) {
+ label->dev = dev;
+ label->sector = sector;
+ } else {
+ /* FIXME: handle errors */
+ lvmcache_del_dev(dev);
}
+ out:
+ return ret;
+}
- /* Scan first few sectors for anything looking like a label */
- for (sector = 0; sector < LABEL_SCAN_SECTORS;
- sector += LABEL_SIZE >> SECTOR_SHIFT) {
- lh = (struct label_header *) (readbuf + (sector << SECTOR_SHIFT));
+static int _scan_dev_open(struct device *dev)
+{
+ const char *name;
+ int flags = 0;
+ int fd;
- wipe = 0;
+ if (!dev)
+ return 0;
- if (!strncmp((char *)lh->id, LABEL_ID, sizeof(lh->id))) {
- if (xlate64(lh->sector_xl) == sector)
- wipe = 1;
+ if (dev->flags & DEV_IN_BCACHE) {
+ log_error("scan_dev_open %s DEV_IN_BCACHE already set", dev_name(dev));
+ dev->flags &= ~DEV_IN_BCACHE;
+ }
+
+ if (dev->bcache_fd > 0) {
+ log_error("scan_dev_open %s already open with fd %d",
+ dev_name(dev), dev->bcache_fd);
+ return 0;
+ }
+
+ if (!(name = dev_name_confirmed(dev, 1))) {
+ log_error("scan_dev_open %s no name", dev_name(dev));
+ return 0;
+ }
+
+ flags |= O_RDWR;
+ flags |= O_DIRECT;
+ flags |= O_NOATIME;
+
+ if (dev->flags & DEV_BCACHE_EXCL)
+ flags |= O_EXCL;
+
+ fd = open(name, flags, 0777);
+
+ if (fd < 0) {
+ if ((errno == EBUSY) && (flags & O_EXCL)) {
+ log_error("Can't open %s exclusively. Mounted filesystem?",
+ dev_name(dev));
} else {
- dm_list_iterate_items(li, &_labellers) {
- if (li->l->ops->can_handle(li->l, (char *) lh,
- sector)) {
- wipe = 1;
- break;
- }
+ log_error("scan_dev_open %s failed errno %d", dev_name(dev), errno);
+ }
+ return 0;
+ }
+
+ dev->flags |= DEV_IN_BCACHE;
+ dev->bcache_fd = fd;
+ return 1;
+}
+
+static int _scan_dev_close(struct device *dev)
+{
+ if (!(dev->flags & DEV_IN_BCACHE))
+ log_error("scan_dev_close %s no DEV_IN_BCACHE set", dev_name(dev));
+
+ dev->flags &= ~DEV_IN_BCACHE;
+ dev->flags &= ~DEV_BCACHE_EXCL;
+
+ if (dev->bcache_fd < 0) {
+ log_error("scan_dev_close %s already closed", dev_name(dev));
+ return 0;
+ }
+
+ if (close(dev->bcache_fd))
+ log_warn("close %s errno %d", dev_name(dev), errno);
+ dev->bcache_fd = -1;
+ return 1;
+}
+
+/*
+ * Read or reread label/metadata from selected devs.
+ *
+ * Reads and looks at label_header, pv_header, pv_header_extension,
+ * mda_header, raw_locns, vg metadata from each device.
+ *
+ * Effect is populating lvmcache with latest info/vginfo (PV/VG) data
+ * from the devs. If a scanned device does not have a label_header,
+ * its info is removed from lvmcache.
+ */
+
+static int _scan_list(struct dm_list *devs, int *failed)
+{
+ struct dm_list wait_devs;
+ struct dm_list done_devs;
+ struct device_list *devl, *devl2;
+ struct block *bb;
+ int scan_open_errors = 0;
+ int scan_read_errors = 0;
+ int scan_process_errors = 0;
+ int scan_failed_count = 0;
+ int rem_prefetches;
+ int scan_failed;
+ int is_lvm_device;
+ int error;
+ int ret;
+
+ dm_list_init(&wait_devs);
+ dm_list_init(&done_devs);
+
+ log_debug_devs("Scanning %d devices for VG info", dm_list_size(devs));
+
+ scan_more:
+ rem_prefetches = bcache_max_prefetches(scan_bcache);
+
+ dm_list_iterate_items_safe(devl, devl2, devs) {
+
+ /*
+ * If we prefetch more devs than blocks in the cache, then the
+ * cache will wait for earlier reads to complete, toss the
+ * results, and reuse those blocks before we've had a chance to
+ * use them. So, prefetch as many as are available, wait for
+ * and process them, then repeat.
+ */
+ if (!rem_prefetches)
+ break;
+
+ if (!_in_bcache(devl->dev)) {
+ if (!_scan_dev_open(devl->dev)) {
+ log_debug_devs("Scan failed to open %s.", dev_name(devl->dev));
+ dm_list_del(&devl->list);
+ dm_list_add(&done_devs, &devl->list);
+ scan_open_errors++;
+ scan_failed_count++;
+ continue;
}
}
- if (wipe) {
- log_very_verbose("%s: Wiping label at sector %" PRIu64,
- dev_name(dev), sector);
- if (dev_write(dev, sector << SECTOR_SHIFT, LABEL_SIZE, DEV_IO_LABEL, labelbuf)) {
- /* Also remove the PV record from cache. */
- info = lvmcache_info_from_pvid(dev->pvid, dev, 0);
- if (info)
- lvmcache_del(info);
- } else {
- log_error("Failed to remove label from %s at "
- "sector %" PRIu64, dev_name(dev),
- sector);
- r = 0;
+ bcache_prefetch(scan_bcache, devl->dev->bcache_fd, 0);
+
+ rem_prefetches--;
+
+ dm_list_del(&devl->list);
+ dm_list_add(&wait_devs, &devl->list);
+ }
+
+ dm_list_iterate_items_safe(devl, devl2, &wait_devs) {
+ bb = NULL;
+ error = 0;
+ scan_failed = 0;
+ is_lvm_device = 0;
+
+ if (!bcache_get(scan_bcache, devl->dev->bcache_fd, 0, 0, &bb, &error)) {
+ log_debug_devs("Scan failed to read %s error %d.", dev_name(devl->dev), error);
+ scan_failed = 1;
+ scan_read_errors++;
+ scan_failed_count++;
+ lvmcache_del_dev(devl->dev);
+ } else {
+ log_debug_devs("Processing data from device %s fd %d block %p", dev_name(devl->dev), devl->dev->bcache_fd, bb);
+
+ ret = _process_block(devl->dev, bb, &is_lvm_device);
+
+ if (!ret && is_lvm_device) {
+ log_debug_devs("Scan failed to process %s", dev_name(devl->dev));
+ scan_failed = 1;
+ scan_process_errors++;
+ scan_failed_count++;
+ lvmcache_del_dev(devl->dev);
}
}
+
+ if (bb)
+ bcache_put(bb);
+
+ /*
+ * Keep the bcache block of lvm devices we have processed so
+ * that the vg_read phase can reuse it. If bcache failed to
+ * read the block, or the device does not belong to lvm, then
+ * drop it from bcache.
+ */
+ if (scan_failed || !is_lvm_device) {
+ bcache_invalidate_fd(scan_bcache, devl->dev->bcache_fd);
+ _scan_dev_close(devl->dev);
+ }
+
+ dm_list_del(&devl->list);
+ dm_list_add(&done_devs, &devl->list);
}
- out:
- if (!dev_close(dev))
- stack;
+ if (!dm_list_empty(devs))
+ goto scan_more;
- return r;
+ log_debug_devs("Scanned devices: open errors %d read errors %d process errors %d",
+ scan_open_errors, scan_read_errors, scan_process_errors);
+
+ if (failed)
+ *failed = scan_failed_count;
+
+ dm_list_splice(devs, &done_devs);
+
+ return 1;
}
-static int _label_read(struct device *dev, uint64_t scan_sector, struct label **result,
- unsigned ioflags, lvm_callback_fn_t process_label_data_fn, void *process_label_data_context)
+#define MIN_BCACHE_BLOCKS 32
+
+static int _setup_bcache(int cache_blocks)
{
- struct lvmcache_info *info;
- struct find_labeller_params *flp;
-
- if ((info = lvmcache_info_from_pvid(dev->pvid, dev, 1))) {
- log_debug_devs("Reading label from lvmcache for %s", dev_name(dev));
- if (result)
- *result = lvmcache_get_label(info);
- if (process_label_data_fn) {
- log_debug_io("Completed label reading for %s", dev_name(dev));
- process_label_data_fn(0, ioflags, process_label_data_context, NULL);
- }
- return 1;
+ struct io_engine *ioe;
+
+ /* No devices can happen, just create bcache with any small number. */
+ if (cache_blocks < MIN_BCACHE_BLOCKS)
+ cache_blocks = MIN_BCACHE_BLOCKS;
+
+ /*
+ * 100 is arbitrary, it's the max number of concurrent aio's
+ * possible, i.e, the number of devices that can be read at
+ * once. Should this be configurable?
+ */
+ if (!(ioe = create_async_io_engine())) {
+ log_error("Failed to create bcache io engine.");
+ return 0;
}
- if (!(flp = dm_pool_zalloc(_labeller_mem, sizeof *flp))) {
- log_error("find_labeller_params allocation failed.");
+ /*
+ * Configure one cache block for each device on the system.
+ * We won't generally need to cache that many because some
+ * of the devs will not be lvm devices, and we don't need
+ * an entry for those. We might want to change this.
+ */
+ if (!(scan_bcache = bcache_create(BCACHE_BLOCK_SIZE_IN_SECTORS, cache_blocks, ioe))) {
+ log_error("Failed to create bcache with %d cache blocks.", cache_blocks);
return 0;
}
- flp->dev = dev;
- flp->scan_sector = scan_sector;
- flp->result = result;
- flp->process_label_data_fn = process_label_data_fn;
- flp->process_label_data_context = process_label_data_context;
- flp->ret = 1;
+ return 1;
+}
- /* Ensure result is always wiped as a precaution */
- if (result)
- *result = NULL;
+/*
+ * Scan and cache lvm data from all devices on the system.
+ * The cache should be empty/reset before calling this.
+ */
+
+int label_scan(struct cmd_context *cmd)
+{
+ struct dm_list all_devs;
+ struct dev_iter *iter;
+ struct device_list *devl;
+ struct device *dev;
- log_debug_devs("Reading label from device %s", dev_name(dev));
+ log_debug_devs("Finding devices to scan");
- if (!dev_open_readonly(dev)) {
- stack;
+ dm_list_init(&all_devs);
- if ((info = lvmcache_info_from_pvid(dev->pvid, dev, 0)))
- _update_lvmcache_orphan(info);
+ /*
+ * Iterate through all the devices in dev-cache (block devs that appear
+ * under /dev that could possibly hold a PV and are not excluded by
+ * filters). Read each to see if it's an lvm device, and if so
+ * populate lvmcache with some basic info about the device and the VG
+ * on it. This info will be used by the vg_read() phase of the
+ * command.
+ */
+ dev_cache_scan();
+ if (!(iter = dev_iter_create(cmd->full_filter, 0))) {
+ log_error("Scanning failed to get devices.");
return 0;
}
- dev_read_callback(dev, scan_sector << SECTOR_SHIFT, LABEL_SCAN_SIZE, DEV_IO_LABEL, ioflags, _find_labeller, flp);
- if (process_label_data_fn)
- return 1;
- else
- return flp->ret;
+ while ((dev = dev_iter_get(iter))) {
+ if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
+ return 0;
+ devl->dev = dev;
+ dm_list_add(&all_devs, &devl->list);
+
+ /*
+ * label_scan should not generally be called a second time,
+ * so this will usually not be true.
+ */
+ if (_in_bcache(dev)) {
+ bcache_invalidate_fd(scan_bcache, dev->bcache_fd);
+ _scan_dev_close(dev);
+ }
+ };
+ dev_iter_destroy(iter);
+
+ log_debug_devs("Found %d devices to scan", dm_list_size(&all_devs));
+
+ if (!scan_bcache) {
+ /*
+ * FIXME: there should probably be some max number of
+ * cache blocks we use when setting up bcache.
+ */
+ if (!_setup_bcache(dm_list_size(&all_devs)))
+ return 0;
+ }
+
+ _scan_list(&all_devs, NULL);
+
+ return 1;
}
-/* result may be NULL if caller doesn't need it */
-int label_read(struct device *dev, struct label **result, uint64_t scan_sector)
+/*
+ * Scan and cache lvm data from the listed devices. If a device is already
+ * scanned and cached, this replaces the previously cached lvm data for the
+ * device. This is called when vg_read() wants to guarantee that it is using
+ * the latest data from the devices in the VG (since the scan populated bcache
+ * without a lock.)
+ */
+
+int label_scan_devs(struct cmd_context *cmd, struct dm_list *devs)
{
- return _label_read(dev, scan_sector, result, 0, NULL, NULL);
+ struct device_list *devl;
+
+ /* FIXME: get rid of this, it's only needed for lvmetad in which
+ case we should be setting up bcache in one place. */
+ if (!scan_bcache) {
+ if (!_setup_bcache(0))
+ return 0;
+ }
+
+ dm_list_iterate_items(devl, devs) {
+ if (_in_bcache(devl->dev)) {
+ bcache_invalidate_fd(scan_bcache, devl->dev->bcache_fd);
+ _scan_dev_close(devl->dev);
+ }
+ }
+
+ _scan_list(devs, NULL);
+
+ /* FIXME: this function should probably fail if any devs couldn't be scanned */
+
+ return 1;
}
-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_scan_devs_excl(struct dm_list *devs)
{
- return _label_read(dev, scan_sector, NULL, ioflags, process_label_data_fn, process_label_data_context);
+ struct device_list *devl;
+ int failed = 0;
+
+ dm_list_iterate_items(devl, devs) {
+ if (_in_bcache(devl->dev)) {
+ bcache_invalidate_fd(scan_bcache, devl->dev->bcache_fd);
+ _scan_dev_close(devl->dev);
+ }
+ /*
+ * With this flag set, _scan_dev_open() done by
+ * _scan_list() will do open EXCL
+ */
+ devl->dev->flags |= DEV_BCACHE_EXCL;
+ }
+
+ _scan_list(devs, &failed);
+
+ if (failed)
+ return 0;
+ return 1;
}
-/* Caller may need to use label_get_handler to create label struct! */
-int label_write(struct device *dev, struct label *label)
+void label_scan_invalidate(struct device *dev)
{
- char buf[LABEL_SIZE] __attribute__((aligned(8)));
- struct label_header *lh = (struct label_header *) buf;
- int r = 1;
+ if (_in_bcache(dev)) {
+ bcache_invalidate_fd(scan_bcache, dev->bcache_fd);
+ _scan_dev_close(dev);
+ }
+}
- if (!label->labeller->ops->write) {
- log_error("Label handler does not support label writes");
- return 0;
+/*
+ * If a PV is stacked on an LV, then the LV is kept open
+ * in bcache, and needs to be closed so the open fd doesn't
+ * interfere with processing the LV.
+ */
+
+void label_scan_invalidate_lv(struct cmd_context *cmd, struct logical_volume *lv)
+{
+ struct lvinfo lvinfo;
+ struct device *dev;
+ dev_t devt;
+
+ lv_info(cmd, lv, 0, &lvinfo, 0, 0);
+ devt = MKDEV(lvinfo.major, lvinfo.minor);
+ if ((dev = dev_cache_get_by_devt(devt, cmd->filter)))
+ label_scan_invalidate(dev);
+}
+
+/*
+ * Empty the bcache of all blocks and close all open fds,
+ * but keep the bcache set up.
+ */
+
+void label_scan_drop(struct cmd_context *cmd)
+{
+ struct dev_iter *iter;
+ struct device *dev;
+
+ if (!(iter = dev_iter_create(cmd->full_filter, 0))) {
+ return;
}
- if ((LABEL_SIZE + (label->sector << SECTOR_SHIFT)) > LABEL_SCAN_SIZE) {
- log_error("Label sector %" PRIu64 " beyond range (%ld)",
- label->sector, LABEL_SCAN_SECTORS);
+ while ((dev = dev_iter_get(iter))) {
+ if (_in_bcache(dev))
+ _scan_dev_close(dev);
+ }
+ dev_iter_destroy(iter);
+}
+
+/*
+ * Close devices that are open because bcache is holding blocks for them.
+ * Destroy the bcache.
+ */
+
+void label_scan_destroy(struct cmd_context *cmd)
+{
+ if (!scan_bcache)
+ return;
+
+ label_scan_drop(cmd);
+
+ bcache_destroy(scan_bcache);
+ scan_bcache = NULL;
+}
+
+/*
+ * Read (or re-read) and process (or re-process) the data for a device. This
+ * will reset (clear and repopulate) the bcache and lvmcache info for this
+ * device. There are only a couple odd places that want to reread a specific
+ * device, this is not a commonly used function.
+ */
+
+/* FIXME: remove unused_sector arg */
+
+int label_read(struct device *dev, struct label **labelp, uint64_t unused_sector)
+{
+ struct dm_list one_dev;
+ struct device_list *devl;
+ int failed = 0;
+
+ /* scanning is done by list, so make a single item list for this dev */
+ if (!(devl = dm_zalloc(sizeof(*devl))))
return 0;
+ devl->dev = dev;
+ dm_list_init(&one_dev);
+ dm_list_add(&one_dev, &devl->list);
+
+ if (_in_bcache(dev)) {
+ bcache_invalidate_fd(scan_bcache, dev->bcache_fd);
+ _scan_dev_close(dev);
}
- memset(buf, 0, LABEL_SIZE);
+ _scan_list(&one_dev, &failed);
- strncpy((char *)lh->id, LABEL_ID, sizeof(lh->id));
- lh->sector_xl = xlate64(label->sector);
- lh->offset_xl = xlate32(sizeof(*lh));
+ /*
+ * FIXME: this ugliness of returning a pointer to the label is
+ * temporary until the callers can be updated to not use this.
+ */
+ if (labelp) {
+ struct lvmcache_info *info;
- if (!(label->labeller->ops->write)(label, buf))
- return_0;
+ info = lvmcache_info_from_pvid(dev->pvid, dev, 1);
+ if (info)
+ *labelp = lvmcache_get_label(info);
+ }
- lh->crc_xl = xlate32(calc_crc(INITIAL_CRC, (uint8_t *)&lh->offset_xl, LABEL_SIZE -
- ((uint8_t *) &lh->offset_xl - (uint8_t *) lh)));
+ if (failed)
+ return 0;
+ return 1;
+}
- if (!dev_open(dev))
- return_0;
+/*
+ * Read a label from a specfic, non-zero sector. This is used in only
+ * one place: pvck -> pv_analyze.
+ */
- log_very_verbose("%s: Writing label to sector %" PRIu64 " with stored offset %"
- PRIu32 ".", dev_name(dev), label->sector,
- xlate32(lh->offset_xl));
- if (!dev_write(dev, label->sector << SECTOR_SHIFT, LABEL_SIZE, DEV_IO_LABEL, buf)) {
- log_debug_devs("Failed to write label to %s", dev_name(dev));
- r = 0;
+int label_read_sector(struct device *dev, struct label **labelp, uint64_t scan_sector)
+{
+ if (scan_sector) {
+ /* TODO: not yet implemented */
+ /* When is this done? When does it make sense? Is it actually possible? */
+ return 0;
}
- if (!dev_close(dev))
- stack;
+ return label_read(dev, labelp, 0);
+}
- return r;
+/*
+ * This is only needed when commands are using lvmetad, in which case they
+ * don't do an initial label_scan, but may later need to rescan certain devs
+ * from disk and call this function. FIXME: is there some better number to
+ * choose here?
+ */
+
+int label_scan_setup_bcache(void)
+{
+ if (!scan_bcache) {
+ if (!_setup_bcache(0))
+ return 0;
+ }
+
+ return 1;
}
-void label_destroy(struct label *label)
+/*
+ * This is needed to write to a new non-lvm device.
+ * Scanning that dev would not keep it open or in
+ * bcache, but to use bcache_write we need the dev
+ * to be open so we can use dev->bcache_fd to write.
+ */
+
+int label_scan_open(struct device *dev)
{
- label->labeller->ops->destroy_label(label->labeller, label);
- dm_free(label);
+ if (!_in_bcache(dev))
+ return _scan_dev_open(dev);
+ return 1;
}
-struct label *label_create(struct labeller *labeller)
+bool dev_read_bytes(struct device *dev, off_t start, size_t len, void *data)
{
- struct label *label;
+ int ret;
- if (!(label = dm_zalloc(sizeof(*label)))) {
- log_error("label allocaction failed");
- return NULL;
+ if (!scan_bcache) {
+ if (!dev_open_readonly(dev))
+ return false;
+
+ ret = dev_read(dev, start, len, 0, data);
+
+ if (!dev_close(dev))
+ stack;
+
+ return ret ? true : false;
}
- label->labeller = labeller;
+ if (dev->bcache_fd <= 0) {
+ /* This is not often needed, perhaps only with lvmetad. */
+ if (!label_scan_open(dev)) {
+ log_error("dev_read_bytes %s cannot open dev", dev_name(dev));
+ return false;
+ }
+ }
- labeller->ops->initialise_label(labeller, label);
+ if (!bcache_read_bytes(scan_bcache, dev->bcache_fd, start, len, data)) {
+ log_error("dev_read_bytes %s at %u failed invalidate fd %d",
+ dev_name(dev), (uint32_t)start, dev->bcache_fd);
+ label_scan_invalidate(dev);
+ return false;
+ }
+ return true;
- return label;
}
+
+bool dev_write_bytes(struct device *dev, off_t start, size_t len, void *data)
+{
+ int ret;
+
+ if (test_mode())
+ return true;
+
+ if (!scan_bcache) {
+ if (!dev_open(dev))
+ return false;
+
+ ret = dev_write(dev, start, len, 0, data);
+
+ if (!dev_close(dev))
+ stack;
+
+ return ret ? true : false;
+ }
+
+ if (dev->bcache_fd <= 0) {
+ /* This is not often needed, perhaps only with lvmetad. */
+ if (!label_scan_open(dev)) {
+ log_error("dev_write_bytes %s cannot open dev", dev_name(dev));
+ return false;
+ }
+ }
+
+ if (!bcache_write_bytes(scan_bcache, dev->bcache_fd, start, len, data)) {
+ log_error("dev_write_bytes %s at %u failed invalidate fd %d",
+ dev_name(dev), (uint32_t)start, dev->bcache_fd);
+ label_scan_invalidate(dev);
+ return false;
+ }
+ return true;
+}
+
+bool dev_write_zeros(struct device *dev, off_t start, size_t len)
+{
+ int ret;
+
+ if (test_mode())
+ return true;
+
+ if (!scan_bcache) {
+ if (!dev_open(dev))
+ return false;
+
+ ret = dev_set(dev, start, len, 0, 0);
+
+ if (!dev_close(dev))
+ stack;
+
+ return ret ? true : false;
+ }
+
+ if (dev->bcache_fd <= 0) {
+ /* This is not often needed, perhaps only with lvmetad. */
+ if (!label_scan_open(dev)) {
+ log_error("dev_write_zeros %s cannot open dev", dev_name(dev));
+ return false;
+ }
+ }
+
+ if (!bcache_write_zeros(scan_bcache, dev->bcache_fd, start, len)) {
+ log_error("dev_write_zeros %s at %u failed invalidate fd %d",
+ dev_name(dev), (uint32_t)start, dev->bcache_fd);
+ label_scan_invalidate(dev);
+ return false;
+ }
+ return true;
+}
+
diff --git a/lib/label/label.h b/lib/label/label.h
index 6d31eb053..55e92e8d4 100644
--- a/lib/label/label.h
+++ b/lib/label/label.h
@@ -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
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index 160943f90..7f9cf0b4e 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -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;
}
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 2bc7927fe..73041cf32 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -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;
diff --git a/lib/metadata/metadata-liblvm.c b/lib/metadata/metadata-liblvm.c
index d192b1597..b0b678ac8 100644
--- a/lib/metadata/metadata-liblvm.c
+++ b/lib/metadata/metadata-liblvm.c
@@ -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);
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index b5b97c2f4..2df9abeb7 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -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;
- }
+ 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;
-
- 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;
- }
+ struct device *dev = lvmcache_device(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 */
diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h
index f6b19f44b..83983b427 100644
--- a/lib/metadata/metadata.h
+++ b/lib/metadata/metadata.h
@@ -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);
diff --git a/lib/metadata/vg.c b/lib/metadata/vg.c
index 4c808da54..0b69e42d4 100644
--- a/lib/metadata/vg.c
+++ b/lib/metadata/vg.c
@@ -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);
diff --git a/lib/misc/lvm-globals.c b/lib/misc/lvm-globals.c
index 0575d21a4..994148971 100644
--- a/lib/misc/lvm-globals.c
+++ b/lib/misc/lvm-globals.c
@@ -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;
diff --git a/lib/misc/lvm-globals.h b/lib/misc/lvm-globals.h
index 14a7d4366..b3838911f 100644
--- a/lib/misc/lvm-globals.h
+++ b/lib/misc/lvm-globals.h
@@ -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);
diff --git a/libdm/libdm-config.c b/libdm/libdm-config.c
index 746ef0742..3f0d2510e 100644
--- a/libdm/libdm-config.c
+++ b/libdm/libdm-config.c
@@ -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:
;
diff --git a/liblvm/Makefile.in b/liblvm/Makefile.in
index 6d0325c60..be3049a9e 100644
--- a/liblvm/Makefile.in
+++ b/liblvm/Makefile.in
@@ -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
diff --git a/liblvm/lvm_vg.c b/liblvm/lvm_vg.c
index 559357953..616c78fde 100644
--- a/liblvm/lvm_vg.c
+++ b/liblvm/lvm_vg.c
@@ -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;
diff --git a/make.tmpl.in b/make.tmpl.in
index 414b1dd5c..75134caa7 100644
--- a/make.tmpl.in
+++ b/make.tmpl.in
@@ -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\
diff --git a/man/Makefile.in b/man/Makefile.in
index cd1106f11..a40e1689e 100644
--- a/man/Makefile.in
+++ b/man/Makefile.in
@@ -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
diff --git a/old-tests/config/.gitignore b/old-tests/config/.gitignore
deleted file mode 100644
index 24600083d..000000000
--- a/old-tests/config/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-!Makefile
diff --git a/old-tests/config/Makefile b/old-tests/config/Makefile
deleted file mode 100644
index d753b646c..000000000
--- a/old-tests/config/Makefile
+++ /dev/null
@@ -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 \ No newline at end of file
diff --git a/old-tests/config/config_t.c b/old-tests/config/config_t.c
deleted file mode 100644
index 9b9e56e60..000000000
--- a/old-tests/config/config_t.c
+++ /dev/null
@@ -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;
-}
diff --git a/old-tests/config/empty_array.conf b/old-tests/config/empty_array.conf
deleted file mode 100644
index 0cc2f283f..000000000
--- a/old-tests/config/empty_array.conf
+++ /dev/null
@@ -1 +0,0 @@
-foo = [] \ No newline at end of file
diff --git a/old-tests/config/vg0 b/old-tests/config/vg0
deleted file mode 100644
index bfa956789..000000000
--- a/old-tests/config/vg0
+++ /dev/null
@@ -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"
- }
- }
-}
diff --git a/old-tests/datastruct/hash_t.c b/old-tests/datastruct/hash_t.c
deleted file mode 100644
index 7c9e435ef..000000000
--- a/old-tests/datastruct/hash_t.c
+++ /dev/null
@@ -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;
-}
diff --git a/old-tests/dev-mgr/dev_cache_t.c b/old-tests/dev-mgr/dev_cache_t.c
deleted file mode 100644
index af9539f5c..000000000
--- a/old-tests/dev-mgr/dev_cache_t.c
+++ /dev/null
@@ -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;
-}
diff --git a/old-tests/device/Makefile.in b/old-tests/device/Makefile.in
deleted file mode 100644
index a389eb101..000000000
--- a/old-tests/device/Makefile.in
+++ /dev/null
@@ -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
-
diff --git a/old-tests/device/dev_cache_t.c b/old-tests/device/dev_cache_t.c
deleted file mode 100644
index c3d8c287d..000000000
--- a/old-tests/device/dev_cache_t.c
+++ /dev/null
@@ -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;
-}
diff --git a/old-tests/device/fill_device.c b/old-tests/device/fill_device.c
deleted file mode 100644
index 5947b61bf..000000000
--- a/old-tests/device/fill_device.c
+++ /dev/null
@@ -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)
-{
-
-}
diff --git a/old-tests/device/random.c b/old-tests/device/random.c
deleted file mode 100644
index 96479f572..000000000
--- a/old-tests/device/random.c
+++ /dev/null
@@ -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;
-}
diff --git a/old-tests/device/random.h b/old-tests/device/random.h
deleted file mode 100644
index 4663988cd..000000000
--- a/old-tests/device/random.h
+++ /dev/null
@@ -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
diff --git a/old-tests/filters/Makefile.in b/old-tests/filters/Makefile.in
deleted file mode 100644
index 69e7ca907..000000000
--- a/old-tests/filters/Makefile.in
+++ /dev/null
@@ -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
-
diff --git a/old-tests/filters/pfilter_t.c b/old-tests/filters/pfilter_t.c
deleted file mode 100644
index e83c3ed5a..000000000
--- a/old-tests/filters/pfilter_t.c
+++ /dev/null
@@ -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;
-}
-
diff --git a/old-tests/filters/rfilter_t.c b/old-tests/filters/rfilter_t.c
deleted file mode 100644
index 488378db8..000000000
--- a/old-tests/filters/rfilter_t.c
+++ /dev/null
@@ -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;
-}
-
diff --git a/old-tests/filters/sample.cfg b/old-tests/filters/sample.cfg
deleted file mode 100644
index 02f98dea8..000000000
--- a/old-tests/filters/sample.cfg
+++ /dev/null
@@ -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
-
-}
diff --git a/old-tests/format1/Makefile.in b/old-tests/format1/Makefile.in
deleted file mode 100644
index e4b51d245..000000000
--- a/old-tests/format1/Makefile.in
+++ /dev/null
@@ -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
-
diff --git a/old-tests/format1/get_pvs_t.c b/old-tests/format1/get_pvs_t.c
deleted file mode 100644
index d17f0b0df..000000000
--- a/old-tests/format1/get_pvs_t.c
+++ /dev/null
@@ -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;
-}
diff --git a/old-tests/format1/get_vgs_t.c b/old-tests/format1/get_vgs_t.c
deleted file mode 100644
index 4910c6ded..000000000
--- a/old-tests/format1/get_vgs_t.c
+++ /dev/null
@@ -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;
-}
diff --git a/old-tests/format1/pretty_print.c b/old-tests/format1/pretty_print.c
deleted file mode 100644
index 62e089abd..000000000
--- a/old-tests/format1/pretty_print.c
+++ /dev/null
@@ -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);
- }
-}
diff --git a/old-tests/format1/pretty_print.h b/old-tests/format1/pretty_print.h
deleted file mode 100644
index 20bd0394c..000000000
--- a/old-tests/format1/pretty_print.h
+++ /dev/null
@@ -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
diff --git a/old-tests/format1/read_pv_t.c b/old-tests/format1/read_pv_t.c
deleted file mode 100644
index 271cc1e1d..000000000
--- a/old-tests/format1/read_pv_t.c
+++ /dev/null
@@ -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;
-}
diff --git a/old-tests/format1/read_vg_t.c b/old-tests/format1/read_vg_t.c
deleted file mode 100644
index 1fb141496..000000000
--- a/old-tests/format1/read_vg_t.c
+++ /dev/null
@@ -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;
-}
-
diff --git a/old-tests/format1/write_vg_t.c b/old-tests/format1/write_vg_t.c
deleted file mode 100644
index 29682ad2e..000000000
--- a/old-tests/format1/write_vg_t.c
+++ /dev/null
@@ -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;
-}
diff --git a/old-tests/mm/Makefile.in b/old-tests/mm/Makefile.in
deleted file mode 100644
index ec60fa604..000000000
--- a/old-tests/mm/Makefile.in
+++ /dev/null
@@ -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
-
diff --git a/old-tests/mm/dbg_malloc_t.c b/old-tests/mm/dbg_malloc_t.c
deleted file mode 100644
index 8536405ce..000000000
--- a/old-tests/mm/dbg_malloc_t.c
+++ /dev/null
@@ -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;
-}
diff --git a/scripts/Makefile.in b/scripts/Makefile.in
index d06766f67..720ae9f0e 100644
--- a/scripts/Makefile.in
+++ b/scripts/Makefile.in
@@ -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
diff --git a/test/Makefile.in b/test/Makefile.in
index 230ce5bb6..097b2fa21 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -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)
diff --git a/test/lib/flavour-ndev-cluster.sh b/test/lib/flavour-ndev-cluster.sh
index 3082b112a..362906952 100644
--- a/test/lib/flavour-ndev-cluster.sh
+++ b/test/lib/flavour-ndev-cluster.sh
@@ -1,2 +1 @@
export LVM_TEST_LOCKING=3
-export LVM_TEST_LVM1=1
diff --git a/test/lib/flavour-ndev-vanilla.sh b/test/lib/flavour-ndev-vanilla.sh
index c106e6129..1899c948e 100644
--- a/test/lib/flavour-ndev-vanilla.sh
+++ b/test/lib/flavour-ndev-vanilla.sh
@@ -1,2 +1 @@
export LVM_TEST_LOCKING=1
-export LVM_TEST_LVM1=1
diff --git a/test/lib/flavour-udev-cluster.sh b/test/lib/flavour-udev-cluster.sh
index 1cab55826..a9025a618 100644
--- a/test/lib/flavour-udev-cluster.sh
+++ b/test/lib/flavour-udev-cluster.sh
@@ -1,3 +1,2 @@
export LVM_TEST_LOCKING=3
export LVM_TEST_DEVDIR=/dev
-export LVM_TEST_LVM1=1
diff --git a/test/lib/flavour-udev-vanilla.sh b/test/lib/flavour-udev-vanilla.sh
index 6fbdafee5..ca778a6d8 100644
--- a/test/lib/flavour-udev-vanilla.sh
+++ b/test/lib/flavour-udev-vanilla.sh
@@ -1,3 +1,2 @@
export LVM_TEST_LOCKING=1
export LVM_TEST_DEVDIR=/dev
-export LVM_TEST_LVM1=1
diff --git a/test/shell/lvconvert-mirror-updown.sh b/test/shell/lvconvert-mirror-updown.sh
index 5c7b13004..d5059c242 100644
--- a/test/shell/lvconvert-mirror-updown.sh
+++ b/test/shell/lvconvert-mirror-updown.sh
@@ -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
-lvs -a $vg
+# We want here ongoing conversion
-#
-# It fails so use 'should' and -vvvv for now
-#
-should lvconvert -vvvv -m-1 $vg/$lv1 "$dev2"
+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
vgremove -f $vg
diff --git a/test/shell/lvconvert-mirror.sh b/test/shell/lvconvert-mirror.sh
index 4e182125c..a45e6e722 100644
--- a/test/shell/lvconvert-mirror.sh
+++ b/test/shell/lvconvert-mirror.sh
@@ -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
diff --git a/test/shell/mda-rollback.sh b/test/shell/mda-rollback.sh
index dbfdc7d51..34080faaf 100644
--- a/test/shell/mda-rollback.sh
+++ b/test/shell/mda-rollback.sh
@@ -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
diff --git a/test/shell/vgck.sh b/test/shell/vgck.sh
index 2f3fba4c1..186704c70 100644
--- a/test/shell/vgck.sh
+++ b/test/shell/vgck.sh
@@ -22,18 +22,18 @@ dd if=/dev/urandom bs=512 seek=2 count=32 of="$dev2"
# TODO: aux lvmconf "global/locking_type = 4"
-vgscan 2>&1 | tee vgscan.out
+vgscan 2>&1 | tee vgscan.out || true
if test -e LOCAL_LVMETAD; then
- not grep "Inconsistent metadata found for VG $vg" vgscan.out
+ not grep "Failed" vgscan.out
else
- grep "Inconsistent metadata found for VG $vg" vgscan.out
+ grep "Failed" vgscan.out
fi
dd if=/dev/urandom bs=512 seek=2 count=32 of="$dev2"
aux notify_lvmetad "$dev2"
-vgck $vg 2>&1 | tee vgck.out
+vgck $vg 2>&1 | tee vgck.out || true
grep Incorrect vgck.out
vgremove -ff $vg
diff --git a/test/shell/vgsplit-usage.sh b/test/shell/vgsplit-usage.sh
index 98818abb0..a112e8621 100644
--- a/test/shell/vgsplit-usage.sh
+++ b/test/shell/vgsplit-usage.sh
@@ -184,6 +184,7 @@ check pvlv_counts $vg1 2 1 0
vgremove -f $vg1
# vgsplit rejects split because metadata types differ
+if test -n "$LVM_TEST_LVM1" ; then
pvcreate -ff -M1 "$dev3" "$dev4"
pvcreate -ff "$dev1" "$dev2"
vgcreate -M1 $vg1 "$dev3" "$dev4"
@@ -192,3 +193,4 @@ not vgsplit $vg1 $vg2 "$dev3" 2>err;
grep "Metadata types differ" err
vgremove -f $vg1 $vg2
fi
+fi
diff --git a/test/unit/Makefile.in b/test/unit/Makefile.in
index 3de30f2e7..a070329ac 100644
--- a/test/unit/Makefile.in
+++ b/test/unit/Makefile.in
@@ -1,4 +1,4 @@
-# Copyright (C) 2011-2017 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2011-2018 Red Hat, Inc. All rights reserved.
#
# This file is part of LVM2.
#
@@ -10,43 +10,30 @@
# 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@
+UNIT_SOURCE=\
+ test/unit/bcache_t.c \
-VPATH = $(srcdir)
-UNITS = \
- bitset_t.c\
- config_t.c\
- dmlist_t.c\
- dmstatus_t.c\
- matcher_t.c\
- percent_t.c\
- string_t.c\
- run.c
-ifeq ("@TESTING@", "yes")
-SOURCES = $(UNITS)
-TARGETS = run
-endif
+# test/unit/run.c
-include $(top_builddir)/make.tmpl
+# test/unit/bitset_t.c\
+# test/unit/config_t.c\
+# test/unit/dmlist_t.c\
+# test/unit/dmstatus_t.c\
+# test/unit/matcher_t.c\
+# test/unit/percent_t.c\
+# test/unit/string_t.c\
-ifeq ($(MAKECMDGOALS),distclean)
-SOURCES = $(UNITS)
-endif
+UNIT_OBJECTS=$(UNIT_SOURCE:%.c=%.o)
-ifeq ("$(TESTING)", "yes")
-LDLIBS += -ldevmapper @CUNIT_LIBS@
-CFLAGS += @CUNIT_CFLAGS@
+UNIT_LDLIBS += $(LVMINTERNAL_LIBS) -ldevmapper -laio
-check: unit
+test/unit/run: $(UNIT_OBJECTS) libdm/libdevmapper.$(LIB_SUFFIX) lib/liblvm-internal.a
+ @echo " [LD] $@"
+ $(Q) $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) -L$(top_builddir)/libdm \
+ -o $@ $(UNIT_OBJECTS) $(UNIT_LDLIBS)
-$(TARGETS): $(OBJECTS) $(top_builddir)/libdm/libdevmapper.$(LIB_SUFFIX)
- $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) -L$(top_builddir)/libdm \
- -o $@ $(OBJECTS) $(LDLIBS)
-
-unit: $(TARGETS)
+.PHONEY: unit-test
+unit-test: test/unit/run
@echo Running unit tests
- LD_LIBRARY_PATH=$(top_builddir)/libdm ./$(TARGETS)
-endif
+ LD_LIBRARY_PATH=libdm test/unit/run
diff --git a/test/unit/bcache_t.c b/test/unit/bcache_t.c
new file mode 100644
index 000000000..07a45fe22
--- /dev/null
+++ b/test/unit/bcache_t.c
@@ -0,0 +1,636 @@
+/*
+ * 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 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>
+#include <stdlib.h>
+#include <unistd.h>
+#include <setjmp.h>
+
+#include "bcache.h"
+
+#define SHOW_MOCK_CALLS 0
+
+/*----------------------------------------------------------------
+ * Assertions
+ *--------------------------------------------------------------*/
+
+static jmp_buf _test_k;
+#define TEST_FAILED 1
+
+static void _fail(const char *fmt, ...)
+ __attribute__((format (printf, 1, 2)));
+
+
+static void _fail(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+
+ longjmp(_test_k, TEST_FAILED);
+}
+
+#define T_ASSERT(e) if (!(e)) {_fail("assertion failed: '%s'", # e);}
+
+/*----------------------------------------------------------------
+ * Mock engine
+ *--------------------------------------------------------------*/
+struct mock_engine {
+ struct io_engine e;
+ struct dm_list expected_calls;
+ struct dm_list issued_io;
+ unsigned max_io;
+ sector_t block_size;
+};
+
+enum method {
+ E_DESTROY,
+ E_ISSUE,
+ E_WAIT,
+ E_MAX_IO
+};
+
+struct mock_call {
+ struct dm_list list;
+ enum method m;
+
+ bool match_args;
+ enum dir d;
+ int fd;
+ block_address b;
+};
+
+struct mock_io {
+ struct dm_list list;
+ int fd;
+ sector_t sb;
+ sector_t se;
+ void *data;
+ void *context;
+};
+
+static const char *_show_method(enum method m)
+{
+ switch (m) {
+ case E_DESTROY:
+ return "destroy()";
+ case E_ISSUE:
+ return "issue()";
+ case E_WAIT:
+ return "wait()";
+ case E_MAX_IO:
+ return "max_io()";
+ }
+
+ return "<unknown>";
+}
+
+static void _expect(struct mock_engine *e, enum method m)
+{
+ struct mock_call *mc = malloc(sizeof(*mc));
+ mc->m = m;
+ mc->match_args = false;
+ dm_list_add(&e->expected_calls, &mc->list);
+}
+
+static void _expect_read(struct mock_engine *e, int fd, block_address b)
+{
+ struct mock_call *mc = malloc(sizeof(*mc));
+ mc->m = E_ISSUE;
+ mc->match_args = true;
+ mc->d = DIR_READ;
+ mc->fd = fd;
+ mc->b = b;
+ dm_list_add(&e->expected_calls, &mc->list);
+}
+
+static void _expect_write(struct mock_engine *e, int fd, block_address b)
+{
+ struct mock_call *mc = malloc(sizeof(*mc));
+ mc->m = E_ISSUE;
+ mc->match_args = true;
+ mc->d = DIR_WRITE;
+ mc->fd = fd;
+ mc->b = b;
+ dm_list_add(&e->expected_calls, &mc->list);
+}
+
+static struct mock_call *_match_pop(struct mock_engine *e, enum method m)
+{
+
+ struct mock_call *mc;
+
+ if (dm_list_empty(&e->expected_calls))
+ _fail("unexpected call to method %s\n", _show_method(m));
+
+ mc = dm_list_item(e->expected_calls.n, struct mock_call);
+ dm_list_del(&mc->list);
+
+ if (mc->m != m)
+ _fail("expected %s, but got %s\n", _show_method(mc->m), _show_method(m));
+#if SHOW_MOCK_CALLS
+ else
+ fprintf(stderr, "%s called (expected)\n", _show_method(m));
+#endif
+
+ return mc;
+}
+
+static void _match(struct mock_engine *e, enum method m)
+{
+ free(_match_pop(e, m));
+}
+
+static void _no_outstanding_expectations(struct mock_engine *e)
+{
+ struct mock_call *mc;
+
+ if (!dm_list_empty(&e->expected_calls)) {
+ fprintf(stderr, "unsatisfied expectations:\n");
+ dm_list_iterate_items (mc, &e->expected_calls)
+ fprintf(stderr, " %s\n", _show_method(mc->m));
+ }
+ T_ASSERT(dm_list_empty(&e->expected_calls));
+}
+
+static struct mock_engine *_to_mock(struct io_engine *e)
+{
+ return container_of(e, struct mock_engine, e);
+}
+
+static void _mock_destroy(struct io_engine *e)
+{
+ struct mock_engine *me = _to_mock(e);
+
+ _match(me, E_DESTROY);
+ T_ASSERT(dm_list_empty(&me->issued_io));
+ T_ASSERT(dm_list_empty(&me->expected_calls));
+ free(_to_mock(e));
+}
+
+static bool _mock_issue(struct io_engine *e, enum dir d, int fd,
+ sector_t sb, sector_t se, void *data, void *context)
+{
+ struct mock_io *io;
+ struct mock_call *mc;
+ struct mock_engine *me = _to_mock(e);
+
+ mc = _match_pop(me, E_ISSUE);
+ if (mc->match_args) {
+ T_ASSERT(d == mc->d);
+ T_ASSERT(fd == mc->fd);
+ T_ASSERT(sb == mc->b * me->block_size);
+ T_ASSERT(se == (mc->b + 1) * me->block_size);
+ }
+ free(mc);
+
+ io = malloc(sizeof(*io));
+ if (!io)
+ abort();
+
+ io->fd = fd;
+ io->sb = sb;
+ io->se = se;
+ io->data = data;
+ io->context = context;
+
+ dm_list_add(&me->issued_io, &io->list);
+ return true;
+}
+
+static bool _mock_wait(struct io_engine *e, io_complete_fn fn)
+{
+ struct mock_io *io;
+ struct mock_engine *me = _to_mock(e);
+ _match(me, E_WAIT);
+
+ // FIXME: provide a way to control how many are completed and whether
+ // they error.
+ T_ASSERT(!dm_list_empty(&me->issued_io));
+ io = dm_list_item(me->issued_io.n, struct mock_io);
+ dm_list_del(&io->list);
+ fn(io->context, 0);
+ return true;
+}
+
+static unsigned _mock_max_io(struct io_engine *e)
+{
+ struct mock_engine *me = _to_mock(e);
+ _match(me, E_MAX_IO);
+ return me->max_io;
+}
+
+static struct mock_engine *_mock_create(unsigned max_io, sector_t block_size)
+{
+ struct mock_engine *m = malloc(sizeof(*m));
+
+ m->e.destroy = _mock_destroy;
+ m->e.issue = _mock_issue;
+ m->e.wait = _mock_wait;
+ m->e.max_io = _mock_max_io;
+
+ m->max_io = max_io;
+ m->block_size = block_size;
+ dm_list_init(&m->expected_calls);
+ dm_list_init(&m->issued_io);
+
+ return m;
+}
+
+/*----------------------------------------------------------------
+ * Fixtures
+ *--------------------------------------------------------------*/
+struct fixture {
+ struct mock_engine *me;
+ struct bcache *cache;
+};
+
+static struct fixture *_fixture_init(sector_t block_size, unsigned nr_cache_blocks)
+{
+ struct fixture *f = malloc(sizeof(*f));
+
+ f->me = _mock_create(16, block_size);
+ T_ASSERT(f->me);
+
+ _expect(f->me, E_MAX_IO);
+ f->cache = bcache_create(block_size, nr_cache_blocks, &f->me->e);
+ T_ASSERT(f->cache);
+
+ return f;
+}
+
+static void _fixture_exit(struct fixture *f)
+{
+ _expect(f->me, E_DESTROY);
+ bcache_destroy(f->cache);
+
+ free(f);
+}
+
+static void *_small_fixture_init(void)
+{
+ return _fixture_init(128, 16);
+}
+
+static void _small_fixture_exit(void *context)
+{
+ _fixture_exit(context);
+}
+
+static void *_large_fixture_init(void)
+{
+ return _fixture_init(128, 1024);
+}
+
+static void _large_fixture_exit(void *context)
+{
+ _fixture_exit(context);
+}
+
+/*----------------------------------------------------------------
+ * Tests
+ *--------------------------------------------------------------*/
+#define MEG 2048
+#define SECTOR_SHIFT 9
+
+static void good_create(sector_t block_size, unsigned nr_cache_blocks)
+{
+ struct bcache *cache;
+ struct mock_engine *me = _mock_create(16, 128);
+
+ _expect(me, E_MAX_IO);
+ cache = bcache_create(block_size, nr_cache_blocks, &me->e);
+ T_ASSERT(cache);
+
+ _expect(me, E_DESTROY);
+ bcache_destroy(cache);
+}
+
+static void bad_create(sector_t block_size, unsigned nr_cache_blocks)
+{
+ struct bcache *cache;
+ struct mock_engine *me = _mock_create(16, 128);
+
+ _expect(me, E_MAX_IO);
+ cache = bcache_create(block_size, nr_cache_blocks, &me->e);
+ T_ASSERT(!cache);
+
+ _expect(me, E_DESTROY);
+ me->e.destroy(&me->e);
+}
+
+static void test_create(void *fixture)
+{
+ good_create(8, 16);
+}
+
+static void test_nr_cache_blocks_must_be_positive(void *fixture)
+{
+ bad_create(8, 0);
+}
+
+static void test_block_size_must_be_positive(void *fixture)
+{
+ bad_create(0, 16);
+}
+
+static void test_block_size_must_be_multiple_of_page_size(void *fixture)
+{
+ static unsigned _bad_examples[] = {3, 9, 13, 1025};
+
+ unsigned i;
+
+ for (i = 0; i < DM_ARRAY_SIZE(_bad_examples); i++)
+ bad_create(_bad_examples[i], 16);
+
+ for (i = 1; i < 1000; i++)
+ good_create(i * 8, 16);
+}
+
+static void test_get_triggers_read(void *context)
+{
+ struct fixture *f = context;
+
+ int fd = 17; // arbitrary key
+ struct block *b;
+
+ _expect_read(f->me, fd, 0);
+ _expect(f->me, E_WAIT);
+ T_ASSERT(bcache_get(f->cache, fd, 0, 0, &b));
+ bcache_put(b);
+}
+
+static void test_repeated_reads_are_cached(void *context)
+{
+ struct fixture *f = context;
+
+ int fd = 17; // arbitrary key
+ unsigned i;
+ struct block *b;
+
+ _expect_read(f->me, fd, 0);
+ _expect(f->me, E_WAIT);
+ for (i = 0; i < 100; i++) {
+ T_ASSERT(bcache_get(f->cache, fd, 0, 0, &b));
+ bcache_put(b);
+ }
+}
+
+static void test_block_gets_evicted_with_many_reads(void *context)
+{
+ struct fixture *f = context;
+
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+ const unsigned nr_cache_blocks = 16;
+
+ int fd = 17; // arbitrary key
+ unsigned i;
+ struct block *b;
+
+ for (i = 0; i < nr_cache_blocks; i++) {
+ _expect_read(me, fd, i);
+ _expect(me, E_WAIT);
+ T_ASSERT(bcache_get(cache, fd, i, 0, &b));
+ bcache_put(b);
+ }
+
+ // Not enough cache blocks to hold this one
+ _expect_read(me, fd, nr_cache_blocks);
+ _expect(me, E_WAIT);
+ T_ASSERT(bcache_get(cache, fd, nr_cache_blocks, 0, &b));
+ bcache_put(b);
+
+ // Now if we run through we should find one block has been
+ // evicted. We go backwards because the oldest is normally
+ // evicted first.
+ _expect(me, E_ISSUE);
+ _expect(me, E_WAIT);
+ for (i = nr_cache_blocks; i; i--) {
+ T_ASSERT(bcache_get(cache, fd, i - 1, 0, &b));
+ bcache_put(b);
+ }
+}
+
+static void test_prefetch_issues_a_read(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+ const unsigned nr_cache_blocks = 16;
+
+ int fd = 17; // arbitrary key
+ unsigned i;
+ struct block *b;
+
+ for (i = 0; i < nr_cache_blocks; i++) {
+ // prefetch should not wait
+ _expect_read(me, fd, i);
+ bcache_prefetch(cache, fd, i);
+ }
+
+
+ for (i = 0; i < nr_cache_blocks; i++) {
+ _expect(me, E_WAIT);
+ T_ASSERT(bcache_get(cache, fd, i, 0, &b));
+ bcache_put(b);
+ }
+}
+
+static void test_too_many_prefetches_does_not_trigger_a_wait(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+
+ const unsigned nr_cache_blocks = 16;
+ int fd = 17; // arbitrary key
+ unsigned i;
+
+ for (i = 0; i < 10 * nr_cache_blocks; i++) {
+ // prefetch should not wait
+ if (i < nr_cache_blocks)
+ _expect_read(me, fd, i);
+ bcache_prefetch(cache, fd, i);
+ }
+
+ // Destroy will wait for any in flight IO triggered by prefetches.
+ for (i = 0; i < nr_cache_blocks; i++)
+ _expect(me, E_WAIT);
+}
+
+static void test_dirty_data_gets_written_back(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+
+ int fd = 17; // arbitrary key
+ struct block *b;
+
+ // Expect the read
+ _expect_read(me, fd, 0);
+ _expect(me, E_WAIT);
+ T_ASSERT(bcache_get(cache, fd, 0, GF_DIRTY, &b));
+ bcache_put(b);
+
+ // Expect the write
+ _expect_write(me, fd, 0);
+ _expect(me, E_WAIT);
+}
+
+static void test_zeroed_data_counts_as_dirty(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+
+ int fd = 17; // arbitrary key
+ struct block *b;
+
+ // No read
+ T_ASSERT(bcache_get(cache, fd, 0, GF_ZERO, &b));
+ bcache_put(b);
+
+ // Expect the write
+ _expect_write(me, fd, 0);
+ _expect(me, E_WAIT);
+}
+
+static void test_flush_waits_for_all_dirty(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+
+ const unsigned count = 16;
+ int fd = 17; // arbitrary key
+ unsigned i;
+ struct block *b;
+
+ for (i = 0; i < count; i++) {
+ if (i % 2) {
+ T_ASSERT(bcache_get(cache, fd, i, GF_ZERO, &b));
+ } else {
+ _expect_read(me, fd, i);
+ _expect(me, E_WAIT);
+ T_ASSERT(bcache_get(cache, fd, i, 0, &b));
+ }
+ bcache_put(b);
+ }
+
+ for (i = 0; i < count; i++) {
+ if (i % 2)
+ _expect_write(me, fd, i);
+ }
+
+ for (i = 0; i < count; i++) {
+ if (i % 2)
+ _expect(me, E_WAIT);
+ }
+
+ bcache_flush(cache);
+ _no_outstanding_expectations(me);
+}
+
+static void test_multiple_files(void * context)
+{
+ static int _fds[] = {1, 128, 345, 678, 890};
+
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+ struct block *b;
+ unsigned i;
+
+ for (i = 0; i < DM_ARRAY_SIZE(_fds); i++) {
+ _expect_read(me, _fds[i], 0);
+ _expect(me, E_WAIT);
+
+ T_ASSERT(bcache_get(cache, _fds[i], 0, 0, &b));
+ bcache_put(b);
+ }
+}
+
+// Tests to be written
+// Open multiple files and prove the blocks are coming from the correct file
+// show invalidate works
+// show invalidate_fd works
+// show writeback is working
+// check zeroing
+
+struct test_details {
+ const char *path;
+ const char *desc;
+ void (*fn)(void *);
+ void *(*fixture_init)(void);
+ void (*fixture_exit)(void *);
+};
+
+#define PATH "device/bcache/"
+#define TEST(path, name, fn) {PATH path, name, fn, NULL, NULL}
+#define TEST_S(path, name, fn) {PATH path, name, fn, _small_fixture_init, _small_fixture_exit}
+#define TEST_L(path, name, fn) {PATH path, name, fn, _large_fixture_init, _large_fixture_exit}
+
+int main(int argc, char **argv)
+{
+ static struct test_details _tests[] = {
+ TEST("create-destroy", "simple create/destroy", test_create),
+ TEST("cache-blocks-positive", "nr cache blocks must be positive", test_nr_cache_blocks_must_be_positive),
+ TEST("block-size-positive", "block size must be positive", test_block_size_must_be_positive),
+ TEST("block-size-multiple-page", "block size must be a multiple of page size", test_block_size_must_be_multiple_of_page_size),
+ TEST_S("get-reads", "bcache_get() triggers read", test_get_triggers_read),
+ TEST_S("reads-cached", "repeated reads are cached", test_repeated_reads_are_cached),
+ TEST_S("blocks-get-evicted", "block get evicted with many reads", test_block_gets_evicted_with_many_reads),
+ TEST_S("prefetch-reads", "prefetch issues a read", test_prefetch_issues_a_read),
+ TEST_S("prefetch-never-waits", "too many prefetches does not trigger a wait", test_too_many_prefetches_does_not_trigger_a_wait),
+ TEST_S("writeback-occurs", "dirty data gets written back", test_dirty_data_gets_written_back),
+ TEST_S("zero-flag-dirties", "zeroed data counts as dirty", test_zeroed_data_counts_as_dirty),
+ TEST_L("flush waits for all dirty", "flush waits for all dirty", test_flush_waits_for_all_dirty),
+ TEST_S("read-multiple-files", "read from multiple files", test_multiple_files),
+ };
+
+ // We have to declare these as volatile because of the setjmp()
+ volatile unsigned i = 0, passed = 0;
+
+ for (i = 0; i < DM_ARRAY_SIZE(_tests); i++) {
+ void *fixture;
+ struct test_details *t = _tests + i;
+ fprintf(stderr, "[RUN ] %s\n", t->path);
+
+ if (setjmp(_test_k))
+ fprintf(stderr, "[ FAIL] %s\n", t->path);
+ else {
+ if (t->fixture_init)
+ fixture = t->fixture_init();
+ else
+ fixture = NULL;
+
+ t->fn(fixture);
+
+ if (t->fixture_exit)
+ t->fixture_exit(fixture);
+
+ passed++;
+ fprintf(stderr, "[ OK] %s\n", t->path);
+ }
+ }
+
+ fprintf(stderr, "\n%u/%lu tests passed\n", passed, DM_ARRAY_SIZE(_tests));
+
+ return 0;
+}
diff --git a/test/unit/run.c b/test/unit/run.c
index 7372138d5..82090ba55 100644
--- a/test/unit/run.c
+++ b/test/unit/run.c
@@ -13,6 +13,7 @@
.pTests = n##_list }
CU_SuiteInfo suites[] = {
+ USE(bcache),
USE(bitset),
USE(config),
USE(dmlist),
diff --git a/test/unit/units.h b/test/unit/units.h
index 9eaa82f25..319e7ceb9 100644
--- a/test/unit/units.h
+++ b/test/unit/units.h
@@ -23,6 +23,7 @@
int n ## _init(void); \
int n ## _fini(void);
+DECL(bcache);
DECL(bitset);
DECL(config);
DECL(dmlist);
diff --git a/tools/Makefile.in b/tools/Makefile.in
index de5b628f8..103b76732 100644
--- a/tools/Makefile.in
+++ b/tools/Makefile.in
@@ -95,7 +95,7 @@ ifeq ("@STATIC_LINK@", "yes")
INSTALL_CMDLIB_TARGETS += install_cmdlib_static
endif
-LVMLIBS = $(LVMINTERNAL_LIBS) -ldevmapper
+LVMLIBS = $(LVMINTERNAL_LIBS) -ldevmapper -laio
LIB_VERSION = $(LIB_VERSION_LVM)
CLEAN_TARGETS = liblvm2cmd.$(LIB_SUFFIX) $(TARGETS_DM) \
@@ -123,11 +123,13 @@ device-mapper: $(TARGETS_DM)
CFLAGS_dmsetup.o += $(UDEV_CFLAGS) $(EXTRA_EXEC_CFLAGS)
dmsetup: dmsetup.o $(top_builddir)/libdm/libdevmapper.$(LIB_SUFFIX)
- $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) \
+ @echo " [CC] $@"
+ $(Q) $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) \
-o $@ dmsetup.o -ldevmapper $(LIBS)
dmsetup.static: dmsetup.o $(interfacebuilddir)/libdevmapper.a
- $(CC) $(CFLAGS) $(LDFLAGS) -static -L$(interfacebuilddir) \
+ @echo " [CC] $@"
+ $(Q) $(CC) $(CFLAGS) $(LDFLAGS) -static -L$(interfacebuilddir) \
-o $@ dmsetup.o -ldevmapper $(M_LIBS) $(PTHREAD_LIBS) $(STATIC_LIBS) $(LIBS)
all: device-mapper
@@ -137,15 +139,18 @@ CFLAGS_lvm.o += $(EXTRA_EXEC_CFLAGS)
INCLUDES += -I$(top_builddir)/tools
lvm: $(OBJECTS) lvm.o $(top_builddir)/lib/liblvm-internal.a
- $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) -o $@ $(OBJECTS) lvm.o \
+ @echo " [CC] $@"
+ $(Q) $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) -o $@ $(OBJECTS) lvm.o \
$(LVMLIBS) $(READLINE_LIBS) $(LIBS)
DEFS_man-generator.o += -DMAN_PAGE_GENERATOR
man-generator.c: command.c
- $(LN_S) -f $< $@
+ @echo " [LN] $@"
+ $(Q) $(LN_S) -f $< $@
man-generator: man-generator.o
+ @echo " [CC] $@"
$(CC) $(CFLAGS) -o $@ $<
ifeq ("@BUILD_LVMETAD@", "yes")
@@ -153,32 +158,39 @@ lvm: $(top_builddir)/libdaemon/client/libdaemonclient.a
endif
lvm.static: $(OBJECTS) lvm-static.o $(top_builddir)/lib/liblvm-internal.a $(interfacebuilddir)/libdevmapper.a
- $(CC) $(CFLAGS) $(LDFLAGS) -static -L$(interfacebuilddir) -o $@ \
+ @echo " [CC] $@"
+ $(Q) $(CC) $(CFLAGS) $(LDFLAGS) -static -L$(interfacebuilddir) -o $@ \
$(OBJECTS) lvm-static.o $(LVMLIBS) $(STATIC_LIBS) $(LIBS)
liblvm2cmd.a: $(top_builddir)/lib/liblvm-internal.a $(OBJECTS) lvmcmdlib.o lvm2cmd.o
- cat $(top_builddir)/lib/liblvm-internal.a > $@
- $(AR) rs $@ $(OBJECTS) lvmcmdlib.o lvm2cmd.o
+ @echo " [AR] $@"
+ $(Q) cat $(top_builddir)/lib/liblvm-internal.a > $@
+ $(Q) $(AR) rs $@ $(OBJECTS) lvmcmdlib.o lvm2cmd.o > /dev/null
liblvm2cmd-static.a: $(top_builddir)/lib/liblvm-internal.a $(OBJECTS) lvmcmdlib.o lvm2cmd-static.o
- cat $(top_builddir)/lib/liblvm-internal.a > $@
- $(AR) rs $@ $(OBJECTS) lvmcmdlib.o lvm2cmd-static.o
+ @echo " [AR] $@"
+ $(Q) cat $(top_builddir)/lib/liblvm-internal.a > $@
+ $(Q) $(AR) rs $@ $(OBJECTS) lvmcmdlib.o lvm2cmd-static.o > /dev/null
liblvm2cmd.$(LIB_SUFFIX): liblvm2cmd.a $(LDDEPS)
- $(CC) -shared -Wl,-soname,$@.$(LIB_VERSION) \
+ @echo " [CC] $@"
+ $(Q) $(CC) -shared -Wl,-soname,$@.$(LIB_VERSION) \
$(CFLAGS) $(CLDFLAGS) -o $@ \
@CLDWHOLEARCHIVE@ liblvm2cmd.a @CLDNOWHOLEARCHIVE@ \
$(LVMLIBS) $(LIBS)
liblvm2cmd.$(LIB_SUFFIX).$(LIB_VERSION): liblvm2cmd.$(LIB_SUFFIX)
- $(LN_S) -f $< $@
+ @echo " [LN] $@"
+ $(Q) $(LN_S) -f $< $@
.commands: $(srcdir)/commands.h $(srcdir)/cmdnames.h Makefile
- $(CC) -E -P $(srcdir)/cmdnames.h 2> /dev/null | \
+ @echo " [CC] $<"
+ $(Q) $(CC) -E -P $(srcdir)/cmdnames.h 2> /dev/null | \
$(EGREP) -v '^ *(|#.*|config|devtypes|dumpconfig|formats|fullreport|help|lastlog|lvmchange|lvpoll|pvdata|segtypes|systemid|tags|version) *$$' > .commands
command-count.h: $(srcdir)/command-lines.in Makefile
- set -o pipefail && \
+ @echo " [GEN] $@"
+ $(Q) set -o pipefail && \
( cat $(top_srcdir)/tools/license.inc && \
echo "/* Do not edit. This file is generated by the Makefile. */" && \
echo -n "#define COMMAND_COUNT " && \
@@ -186,7 +198,8 @@ command-count.h: $(srcdir)/command-lines.in Makefile
) > $@
cmds.h: $(srcdir)/command-lines.in Makefile
- set -o pipefail && \
+ @echo " [GEN] $@"
+ $(Q) set -o pipefail && \
( cat $(top_srcdir)/tools/license.inc && \
echo "/* Do not edit. This file is generated by the Makefile. */" && \
echo "cmd(CMD_NONE, none)" && \
@@ -195,7 +208,8 @@ cmds.h: $(srcdir)/command-lines.in Makefile
) > $@
command-lines-input.h: $(srcdir)/command-lines.in Makefile
- set -o pipefail && \
+ @echo " [GEN] $@"
+ $(Q) set -o pipefail && \
( cat $(top_srcdir)/tools/license.inc && \
echo "/* Do not edit. This file is generated by the Makefile. */" && \
echo -en "const char _command_input[] =\n\n\"" && \
@@ -217,18 +231,22 @@ endif
install_dmsetup_dynamic install_dmsetup_static
install_cmdlib_include: $(srcdir)/lvm2cmd.h
- $(INSTALL_DATA) -D $< $(includedir)/$(<F)
+ @echo " [INSTALL] $<"
+ $(Q) $(INSTALL_DATA) -D $< $(includedir)/$(<F)
install_cmdlib_dynamic: liblvm2cmd.$(LIB_SUFFIX)
- $(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)
install_cmdlib_static: liblvm2cmd-static.a
- $(INSTALL_DATA) -D $< $(usrlibdir)/liblvm2cmd.a
+ @echo " [INSTALL] $<"
+ $(Q) $(INSTALL_DATA) -D $< $(usrlibdir)/liblvm2cmd.a
install_tools_dynamic: lvm .commands
- $(INSTALL_PROGRAM) -D lvm $(sbindir)/lvm
+ @echo " [INSTALL] $<"
+ $(Q) $(INSTALL_PROGRAM) -D lvm $(sbindir)/lvm
@echo Creating symbolic links for individual commands in $(sbindir)
@for v in `cat .commands`; do \
echo "$(LN_S) -f lvm $(sbindir)/$$v"; \
@@ -236,15 +254,18 @@ install_tools_dynamic: lvm .commands
done;
install_tools_static: lvm.static
- $(INSTALL_PROGRAM) -D $< $(staticdir)/$(<F)
+ @echo " [INSTALL] $<"
+ $(Q) $(INSTALL_PROGRAM) -D $< $(staticdir)/$(<F)
install_dmsetup_dynamic: dmsetup
- $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
- $(LN_S) -f $(<F) $(sbindir)/dmstats
+ @echo " [INSTALL] $<"
+ $(Q) $(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
+ $(Q) $(LN_S) -f $(<F) $(sbindir)/dmstats
install_dmsetup_static: dmsetup.static
- $(INSTALL_PROGRAM) -D $< $(staticdir)/$(<F)
- $(LN_S) -f $(<F) $(staticdir)/dmstats
+ @echo " [INSTALL] $<"
+ $(Q) $(INSTALL_PROGRAM) -D $< $(staticdir)/$(<F)
+ $(Q) $(LN_S) -f $(<F) $(staticdir)/dmstats
install_device-mapper: $(INSTALL_DMSETUP_TARGETS)
diff --git a/tools/command.c b/tools/command.c
index a40b327b4..377d03f0f 100644
--- a/tools/command.c
+++ b/tools/command.c
@@ -134,13 +134,13 @@ static inline int configtype_arg(struct cmd_context *cmd __attribute__((unused))
#define ALLOW_UUID_AS_NAME 0x00000010
#define LOCKD_VG_SH 0x00000020
#define NO_METADATA_PROCESSING 0x00000040
-#define REQUIRES_FULL_LABEL_SCAN 0x00000080
+#define IGNORE_PERSISTENT_FILTER 0x00000080
#define MUST_USE_ALL_ARGS 0x00000100
#define NO_LVMETAD_AUTOSCAN 0x00000200
#define ENABLE_DUPLICATE_DEVS 0x00000400
#define DISALLOW_TAG_ARGS 0x00000800
#define GET_VGNAME_FROM_OPTIONS 0x00001000
-#define IGNORE_PERSISTENT_FILTER 0x00002000
+#define CAN_USE_ONE_SCAN 0x00002000
/* create foo_CMD enums for command def ID's in command-lines.in */
@@ -1357,11 +1357,13 @@ static void _create_opt_names_alpha(void)
qsort(opt_names_alpha, ARG_COUNT, sizeof(long), _long_name_compare);
}
-static int _copy_line(char *line, int max_line, int *position, int *len)
+static int _copy_line(char *line, int max_line, int *position)
{
int p = *position;
int i = 0;
+ memset(line, 0, max_line);
+
while (1) {
line[i] = _command_input[p];
i++;
@@ -1375,9 +1377,7 @@ static int _copy_line(char *line, int max_line, int *position, int *len)
if (i == (max_line - 1))
break;
}
- line[i] = '\0';
*position = p;
- *len = i + 1;
return 1;
}
@@ -1395,7 +1395,6 @@ int define_commands(struct cmd_context *cmdtool, const char *run_name)
int prev_was_oo = 0;
int prev_was_op = 0;
int copy_pos = 0;
- int copy_len = 0;
int skip = 0;
int i;
@@ -1406,14 +1405,14 @@ int define_commands(struct cmd_context *cmdtool, const char *run_name)
/* Process each line of command-lines-input.h (from command-lines.in) */
- while (_copy_line(line, MAX_LINE, &copy_pos, &copy_len)) {
+ while (_copy_line(line, MAX_LINE, &copy_pos)) {
if (line[0] == '\n')
break;
if ((n = strchr(line, '\n')))
*n = '\0';
- memcpy(line_orig, line, copy_len);
+ memcpy(line_orig, line, sizeof(line));
_split_line(line, &line_argc, line_argv, ' ');
if (!line_argc)
diff --git a/tools/commands.h b/tools/commands.h
index d65330a88..4af92c87f 100644
--- a/tools/commands.h
+++ b/tools/commands.h
@@ -43,7 +43,7 @@ xx(lastlog,
xx(lvchange,
"Change the attributes of logical volume(s)",
- CACHE_VGMETADATA | PERMITTED_READ_ONLY)
+ PERMITTED_READ_ONLY)
xx(lvconvert,
"Change logical volume layout",
@@ -55,7 +55,7 @@ xx(lvcreate,
xx(lvdisplay,
"Display information about a logical volume",
- PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH)
+ PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN)
xx(lvextend,
"Add space to a logical volume",
@@ -99,7 +99,7 @@ xx(lvresize,
xx(lvs,
"Display information about logical volumes",
- PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH)
+ PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN)
xx(lvscan,
"List all logical volumes in all volume groups",
@@ -127,7 +127,7 @@ xx(pvdata,
xx(pvdisplay,
"Display various attributes of physical volume(s)",
- CACHE_VGMETADATA | PERMITTED_READ_ONLY | ENABLE_ALL_DEVS | ENABLE_DUPLICATE_DEVS | LOCKD_VG_SH)
+ PERMITTED_READ_ONLY | ENABLE_ALL_DEVS | ENABLE_DUPLICATE_DEVS | LOCKD_VG_SH | CAN_USE_ONE_SCAN)
/* ALL_VGS_IS_DEFAULT is for polldaemon to find pvmoves in-progress using process_each_vg. */
@@ -145,7 +145,7 @@ xx(pvremove,
xx(pvs,
"Display information about physical volumes",
- CACHE_VGMETADATA | PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | ENABLE_ALL_DEVS | ENABLE_DUPLICATE_DEVS | LOCKD_VG_SH)
+ PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | ENABLE_ALL_DEVS | ENABLE_DUPLICATE_DEVS | LOCKD_VG_SH | CAN_USE_ONE_SCAN)
xx(pvscan,
"List all physical volumes",
@@ -173,7 +173,7 @@ xx(vgcfgrestore,
xx(vgchange,
"Change volume group attributes",
- CACHE_VGMETADATA | PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT)
+ PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT)
xx(vgck,
"Check the consistency of volume group(s)",
@@ -189,7 +189,7 @@ xx(vgcreate,
xx(vgdisplay,
"Display volume group information",
- PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH)
+ PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN)
xx(vgexport,
"Unregister volume group(s) from the system",
@@ -225,11 +225,11 @@ xx(vgremove,
xx(vgrename,
"Rename a volume group",
- ALLOW_UUID_AS_NAME | REQUIRES_FULL_LABEL_SCAN)
+ ALLOW_UUID_AS_NAME)
xx(vgs,
"Display information about volume groups",
- PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH)
+ PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN)
xx(vgscan,
"Search for all volume groups",
diff --git a/tools/lvchange.c b/tools/lvchange.c
index 0aac5ac19..e1be4cbb2 100644
--- a/tools/lvchange.c
+++ b/tools/lvchange.c
@@ -1603,6 +1603,10 @@ static int _lvchange_monitor_poll_single(struct cmd_context *cmd,
struct logical_volume *lv,
struct processing_handle *handle)
{
+ /* Mirror is using different table line when un/monitored */
+ if (lv_is_mirror(lv) && !lv_refresh(cmd, lv))
+ return_ECMD_FAILED;
+
if (arg_is_set(cmd, monitor_ARG) &&
!_lvchange_monitoring(cmd, lv))
return_ECMD_FAILED;
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 44fdd1608..abdcf2c2d 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -758,6 +758,13 @@ static int _lvconvert_mirrors_parse_params(struct cmd_context *cmd,
if (*old_mimage_count != *new_mimage_count)
log_verbose("Adjusting mirror image count of %s", lv->name);
+ /* If region size is not given by user - use value from mirror */
+ if (lv_is_mirrored(lv) && !lp->region_size_supplied) {
+ lp->region_size = first_seg(lv)->region_size;
+ log_debug("Copying region size %s from existing mirror.",
+ display_size(lv->vg->cmd, lp->region_size));
+ }
+
/*
* Adjust log type
*
diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c
index 26510bc8b..0600b1c32 100644
--- a/tools/lvmcmdline.c
+++ b/tools/lvmcmdline.c
@@ -2281,7 +2281,6 @@ static int _get_current_settings(struct cmd_context *cmd)
cmd->current_settings.archive = arg_int_value(cmd, autobackup_ARG, cmd->current_settings.archive);
cmd->current_settings.backup = arg_int_value(cmd, autobackup_ARG, cmd->current_settings.backup);
- cmd->current_settings.cache_vgmetadata = cmd->cname->flags & CACHE_VGMETADATA ? 1 : 0;
if (arg_is_set(cmd, readonly_ARG)) {
cmd->current_settings.activation = 0;
@@ -2292,6 +2291,9 @@ static int _get_current_settings(struct cmd_context *cmd)
if (cmd->cname->flags & LOCKD_VG_SH)
cmd->lockd_vg_default_sh = 1;
+ if (cmd->cname->flags & CAN_USE_ONE_SCAN)
+ cmd->can_use_one_scan = 1;
+
cmd->partial_activation = 0;
cmd->degraded_activation = 0;
activation_mode = find_config_tree_str(cmd, activation_mode_CFG, NULL);
@@ -2447,7 +2449,6 @@ static void _apply_current_settings(struct cmd_context *cmd)
_apply_current_output_settings(cmd);
init_test(cmd->current_settings.test);
- init_full_scan_done(0);
init_mirror_in_sync(0);
init_dmeventd_monitor(DEFAULT_DMEVENTD_MONITOR);
@@ -2728,11 +2729,6 @@ static int _cmd_no_lvmetad_autoscan(struct cmd_context *cmd)
return cmd->cname->flags & NO_LVMETAD_AUTOSCAN;
}
-static int _cmd_requires_full_label_scan(struct cmd_context *cmd)
-{
- return cmd->cname->flags & REQUIRES_FULL_LABEL_SCAN;
-}
-
static int _cmd_ignores_persistent_filter(struct cmd_context *cmd)
{
return cmd->cname->flags & IGNORE_PERSISTENT_FILTER;
@@ -2866,7 +2862,7 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
* Similarly ignore the persistent cache if the command is going to discard it regardless.
*/
if (!cmd->initialized.filters && !_cmd_no_meta_proc(cmd) &&
- !init_filters(cmd, !(refresh_done || _cmd_requires_full_label_scan(cmd) || _cmd_ignores_persistent_filter(cmd))))
+ !init_filters(cmd, !(refresh_done || _cmd_ignores_persistent_filter(cmd))))
return_ECMD_FAILED;
if (arg_is_set(cmd, readonly_ARG))
@@ -3014,10 +3010,9 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
lvmnotify_send(cmd);
out:
- if (test_mode()) {
- log_verbose("Test mode: Wiping internal cache");
- lvmcache_destroy(cmd, 1, 0);
- }
+
+ lvmcache_destroy(cmd, 1, 1);
+ label_scan_destroy(cmd);
if ((config_string_cft = remove_config_tree_by_source(cmd, CONFIG_STRING)))
dm_config_destroy(config_string_cft);
diff --git a/tools/lvmdiskscan.c b/tools/lvmdiskscan.c
index cb688b5ca..7e2fc8878 100644
--- a/tools/lvmdiskscan.c
+++ b/tools/lvmdiskscan.c
@@ -87,7 +87,6 @@ int lvmdiskscan(struct cmd_context *cmd, int argc __attribute__((unused)),
uint64_t size;
struct dev_iter *iter;
struct device *dev;
- struct label *label;
/* initialise these here to avoid problems with the lvm shell */
disks_found = 0;
@@ -105,10 +104,10 @@ int lvmdiskscan(struct cmd_context *cmd, int argc __attribute__((unused)),
return ECMD_FAILED;
}
- /* Do scan */
+ label_scan(cmd);
+
for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter)) {
- /* Try if it is a PV first */
- if ((label_read(dev, &label, UINT64_C(0)))) {
+ if (lvmcache_has_dev_info(dev)) {
if (!dev_get_size(dev, &size)) {
log_error("Couldn't get size of \"%s\"",
dev_name(dev));
diff --git a/tools/polldaemon.c b/tools/polldaemon.c
index d69284d47..83f0424dc 100644
--- a/tools/polldaemon.c
+++ b/tools/polldaemon.c
@@ -123,13 +123,20 @@ static void _nanosleep(unsigned secs, unsigned allow_zero_time)
while (!nanosleep(&wtime, &wtime) && errno == EINTR) {}
}
-static void _sleep_and_rescan_devices(struct daemon_parms *parms)
+static void _sleep_and_rescan_devices(struct cmd_context *cmd, struct daemon_parms *parms)
{
if (parms->interval && !parms->aborting) {
+ /*
+ * FIXME: do we really need to drop everything and then rescan
+ * everything between each iteration? What change exactly does
+ * each iteration check for, and does seeing that require
+ * rescanning everything?
+ */
+ lvmcache_destroy(cmd, 1, 0);
+ label_scan_destroy(cmd);
dev_close_all();
_nanosleep(parms->interval, 1);
- /* Devices might have changed while we slept */
- init_full_scan_done(0);
+ lvmcache_label_scan(cmd);
}
}
@@ -142,10 +149,13 @@ int wait_for_single_lv(struct cmd_context *cmd, struct poll_operation_id *id,
uint32_t lockd_state = 0;
int ret;
+ if (!parms->wait_before_testing)
+ lvmcache_label_scan(cmd);
+
/* Poll for completion */
while (!finished) {
if (parms->wait_before_testing)
- _sleep_and_rescan_devices(parms);
+ _sleep_and_rescan_devices(cmd, parms);
/*
* An ex VG lock is needed because the check can call finish_copy
@@ -218,7 +228,7 @@ int wait_for_single_lv(struct cmd_context *cmd, struct poll_operation_id *id,
* continue polling an LV that doesn't have a "status".
*/
if (!parms->wait_before_testing && !finished)
- _sleep_and_rescan_devices(parms);
+ _sleep_and_rescan_devices(cmd, parms);
}
return 1;
diff --git a/tools/pvck.c b/tools/pvck.c
index 0fedb4a6c..634b38d19 100644
--- a/tools/pvck.c
+++ b/tools/pvck.c
@@ -23,6 +23,8 @@ int pvck(struct cmd_context *cmd, int argc, char **argv)
/* FIXME: validate cmdline options */
/* FIXME: what does the cmdline look like? */
+ label_scan_setup_bcache();
+
/*
* Use what's on the cmdline directly, and avoid calling into
* some of the other infrastructure functions, so as to avoid
diff --git a/tools/pvscan.c b/tools/pvscan.c
index 6581990f8..1fcf606a2 100644
--- a/tools/pvscan.c
+++ b/tools/pvscan.c
@@ -288,8 +288,6 @@ static int _pvscan_autoactivate(struct cmd_context *cmd, struct pvscan_aa_params
pp->refresh_all = 1;
}
- dev_cache_full_scan(cmd->full_filter);
-
ret = process_each_vg(cmd, 0, NULL, NULL, vgnames, 0, 0, handle, _pvscan_autoactivate_single);
destroy_processing_handle(cmd, handle);
@@ -300,8 +298,10 @@ static int _pvscan_autoactivate(struct cmd_context *cmd, struct pvscan_aa_params
static int _pvscan_cache(struct cmd_context *cmd, int argc, char **argv)
{
struct pvscan_aa_params pp = { 0 };
+ struct dm_list single_devs;
struct dm_list found_vgnames;
struct device *dev;
+ struct device_list *devl;
const char *pv_name;
const char *reason = NULL;
int32_t major = -1;
@@ -434,8 +434,12 @@ static int _pvscan_cache(struct cmd_context *cmd, int argc, char **argv)
* to drop any devices that have left.)
*/
- if (argc || devno_args)
+ if (argc || devno_args) {
log_verbose("Scanning devices on command line.");
+ cmd->pvscan_cache_single = 1;
+ }
+
+ dm_list_init(&single_devs);
while (argc--) {
pv_name = *argv++;
@@ -453,8 +457,11 @@ static int _pvscan_cache(struct cmd_context *cmd, int argc, char **argv)
} else {
/* Add device path to lvmetad. */
log_debug("Scanning dev %s for lvmetad cache.", pv_name);
- if (!lvmetad_pvscan_single(cmd, dev, &found_vgnames, &pp.changed_vgnames))
- add_errors++;
+
+ if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
+ return_0;
+ devl->dev = dev;
+ dm_list_add(&single_devs, &devl->list);
}
} else {
if (sscanf(pv_name, "%d:%d", &major, &minor) != 2) {
@@ -471,8 +478,11 @@ static int _pvscan_cache(struct cmd_context *cmd, int argc, char **argv)
} else {
/* Add major:minor to lvmetad. */
log_debug("Scanning dev %d:%d for lvmetad cache.", major, minor);
- if (!lvmetad_pvscan_single(cmd, dev, &found_vgnames, &pp.changed_vgnames))
- add_errors++;
+
+ if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
+ return_0;
+ devl->dev = dev;
+ dm_list_add(&single_devs, &devl->list);
}
}
@@ -482,9 +492,21 @@ static int _pvscan_cache(struct cmd_context *cmd, int argc, char **argv)
}
}
+ if (!dm_list_empty(&single_devs)) {
+ dev_cache_scan();
+ label_scan_devs(cmd, &single_devs);
+
+ dm_list_iterate_items(devl, &single_devs) {
+ if (!lvmetad_pvscan_single(cmd, devl->dev, &found_vgnames, &pp.changed_vgnames))
+ add_errors++;
+ }
+ }
+
if (!devno_args)
goto activate;
+ dm_list_init(&single_devs);
+
/* Process any grouped --major --minor args */
dm_list_iterate_items(current_group, &cmd->arg_value_groups) {
major = grouped_arg_int_value(current_group->arg_values, major_ARG, major);
@@ -503,8 +525,11 @@ static int _pvscan_cache(struct cmd_context *cmd, int argc, char **argv)
} else {
/* Add major:minor to lvmetad. */
log_debug("Scanning dev %d:%d for lvmetad cache.", major, minor);
- if (!lvmetad_pvscan_single(cmd, dev, &found_vgnames, &pp.changed_vgnames))
- add_errors++;
+
+ if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
+ return_0;
+ devl->dev = dev;
+ dm_list_add(&single_devs, &devl->list);
}
if (sigint_caught()) {
@@ -513,6 +538,16 @@ static int _pvscan_cache(struct cmd_context *cmd, int argc, char **argv)
}
}
+ if (!dm_list_empty(&single_devs)) {
+ dev_cache_scan();
+ label_scan_devs(cmd, &single_devs);
+
+ dm_list_iterate_items(devl, &single_devs) {
+ if (!lvmetad_pvscan_single(cmd, devl->dev, &found_vgnames, &pp.changed_vgnames))
+ add_errors++;
+ }
+ }
+
/*
* In the process of scanning devices, lvmetad may have become
* disabled. If so, revert to scanning for the autoactivation step.
diff --git a/tools/toollib.c b/tools/toollib.c
index 3f27a7af4..6b71f2dcc 100644
--- a/tools/toollib.c
+++ b/tools/toollib.c
@@ -116,7 +116,6 @@ int become_daemon(struct cmd_context *cmd, int skip_lvm)
/* FIXME Clean up properly here */
_exit(ECMD_FAILED);
}
- dev_async_reset(cmd);
dev_close_all();
return 1;
@@ -1486,6 +1485,12 @@ int change_tag(struct cmd_context *cmd, struct volume_group *vg,
return 1;
}
+/*
+ * FIXME: replace process_each_label() with process_each_vg() which is
+ * based on performing vg_read(), which provides a correct representation
+ * of VGs/PVs, that is not provided by lvmcache_label_scan().
+ */
+
int process_each_label(struct cmd_context *cmd, int argc, char **argv,
struct processing_handle *handle,
process_single_label_fn_t process_single_label)
@@ -1494,13 +1499,20 @@ int process_each_label(struct cmd_context *cmd, int argc, char **argv,
struct label *label;
struct dev_iter *iter;
struct device *dev;
-
+ struct lvmcache_info *info;
+ struct dm_list process_duplicates;
+ struct device_list *devl;
int ret_max = ECMD_PROCESSED;
int ret;
int opt = 0;
+ dm_list_init(&process_duplicates);
+
log_set_report_object_type(LOG_REPORT_OBJECT_TYPE_LABEL);
+ lvmcache_label_scan(cmd);
+ lvmcache_seed_infos_from_lvmetad(cmd);
+
if (argc) {
for (; opt < argc; opt++) {
if (!(dev = dev_cache_get(argv[opt], cmd->full_filter))) {
@@ -1510,14 +1522,54 @@ int process_each_label(struct cmd_context *cmd, int argc, char **argv,
continue;
}
+ if (!(label = lvmcache_get_dev_label(dev))) {
+ if (!lvmcache_dev_is_unchosen_duplicate(dev)) {
+ log_error("No physical volume label read from %s.", argv[opt]);
+ ret_max = ECMD_FAILED;
+ } else {
+ if (!(devl = dm_malloc(sizeof(*devl))))
+ return_0;
+ devl->dev = dev;
+ dm_list_add(&process_duplicates, &devl->list);
+ }
+ continue;
+ }
+
log_set_report_object_name_and_id(dev_name(dev), NULL);
- if (!label_read(dev, &label, 0)) {
- log_error("No physical volume label read from %s.",
- argv[opt]);
- ret_max = ECMD_FAILED;
+ ret = process_single_label(cmd, label, handle);
+ report_log_ret_code(ret);
+
+ if (ret > ret_max)
+ ret_max = ret;
+
+ log_set_report_object_name_and_id(NULL, NULL);
+
+ if (sigint_caught())
+ break;
+ }
+
+ dm_list_iterate_items(devl, &process_duplicates) {
+ /*
+ * remove the existing dev for this pvid from lvmcache
+ * so that the duplicate dev can replace it.
+ */
+ if ((info = lvmcache_info_from_pvid(devl->dev->pvid, NULL, 0)))
+ lvmcache_del(info);
+
+ /*
+ * add info to lvmcache from the duplicate dev.
+ */
+ label_read(devl->dev, NULL, 0);
+
+ /*
+ * the info/label should now be found because
+ * the label_read should have added it.
+ */
+ if (!(label = lvmcache_get_dev_label(devl->dev)))
continue;
- }
+
+ log_set_report_object_name_and_id(dev_name(dev), NULL);
ret = process_single_label(cmd, label, handle);
report_log_ret_code(ret);
@@ -1542,7 +1594,7 @@ int process_each_label(struct cmd_context *cmd, int argc, char **argv,
while ((dev = dev_iter_get(iter)))
{
- if (!label_read(dev, &label, 0))
+ if (!(label = lvmcache_get_dev_label(dev)))
continue;
log_set_report_object_name_and_id(dev_name(label->dev), NULL);
@@ -1980,7 +2032,7 @@ static int _process_vgnameid_list(struct cmd_context *cmd, uint32_t read_flags,
(!dm_list_empty(arg_tags) && str_list_match_list(arg_tags, &vg->tags, NULL))) &&
select_match_vg(cmd, handle, vg) && _select_matches(handle)) {
- log_very_verbose("Processing VG %s %s", vg_name, vg_uuid ? uuid : "");
+ log_very_verbose("Running command for VG %s %s", vg_name, vg_uuid ? uuid : "");
ret = process_single_vg(cmd, vg_name, vg, handle);
_update_selection_result(handle, &whole_selected);
@@ -2229,14 +2281,10 @@ int process_each_vg(struct cmd_context *cmd,
}
/*
- * First rescan for available devices, then force the next
- * label scan to be done. get_vgnameids() will scan labels
- * (when not using lvmetad).
+ * Scan all devices to populate lvmcache with initial
+ * list of PVs and VGs.
*/
- if (cmd->cname->flags & REQUIRES_FULL_LABEL_SCAN) {
- dev_cache_full_scan(cmd->full_filter);
- lvmcache_force_next_label_scan();
- }
+ lvmcache_label_scan(cmd);
/*
* A list of all VGs on the system is needed when:
@@ -3121,6 +3169,14 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
}
log_set_report_object_name_and_id(NULL, NULL);
+ /*
+ * If a PV is stacked on an LV, then the LV is kept open
+ * in bcache, and needs to be closed so the open fd doesn't
+ * interfere with processing the LV.
+ */
+ dm_list_iterate_items(lvl, &final_lvs)
+ label_scan_invalidate_lv(cmd, lvl->lv);
+
dm_list_iterate_items(lvl, &final_lvs) {
lv_uuid[0] = '\0';
if (!id_write_format(&lvl->lv->lvid.id[1], lv_uuid, sizeof(lv_uuid)))
@@ -3746,6 +3802,12 @@ int process_each_lv(struct cmd_context *cmd,
}
/*
+ * Scan all devices to populate lvmcache with initial
+ * list of PVs and VGs.
+ */
+ lvmcache_label_scan(cmd);
+
+ /*
* A list of all VGs on the system is needed when:
* . processing all VGs on the system
* . A VG name is specified which may refer to one
@@ -4452,9 +4514,13 @@ int process_each_pv(struct cmd_context *cmd,
* before process_each_pv is called.
*/
if (!trust_cache() && !orphans_locked) {
- log_debug("Scanning for available devices");
lvmcache_destroy(cmd, 1, 0);
- dev_cache_full_scan(cmd->full_filter);
+
+ /*
+ * Scan all devices to populate lvmcache with initial
+ * list of PVs and VGs.
+ */
+ lvmcache_label_scan(cmd);
}
if (!get_vgnameids(cmd, &all_vgnameids, only_this_vgname, 1)) {
@@ -5030,16 +5096,6 @@ static int _pvcreate_check_single(struct cmd_context *cmd,
log_debug("Checking pvcreate arg %s which has existing PVID: %.32s.",
pv_dev_name(pv), pv->dev->pvid[0] ? pv->dev->pvid : "<none>");
- /*
- * This test will fail if the device belongs to an MD array.
- */
- if (!dev_test_excl(pv->dev)) {
- /* FIXME Detect whether device-mapper itself is still using it */
- log_error("Can't open %s exclusively. Mounted filesystem?",
- pv_dev_name(pv));
- dm_list_move(&pp->arg_fail, &pd->list);
- return 1;
- }
/*
* Don't allow using a device with duplicates.
@@ -5171,14 +5227,6 @@ static int _pv_confirm_single(struct cmd_context *cmd,
if (!found)
return 1;
- /* Repeat the same from check_single. */
- if (!dev_test_excl(pv->dev)) {
- /* FIXME Detect whether device-mapper itself is still using it */
- log_error("Can't open %s exclusively. Mounted filesystem?",
- pv_dev_name(pv));
- goto fail;
- }
-
/*
* What kind of device is this: an orphan PV, an uninitialized/unused
* device, a PV used in a VG.
@@ -5245,7 +5293,6 @@ static int _pvremove_check_single(struct cmd_context *cmd,
struct pvcreate_params *pp = (struct pvcreate_params *) handle->custom_handle;
struct pvcreate_device *pd;
struct pvcreate_prompt *prompt;
- struct label *label;
int found = 0;
if (!pv->dev)
@@ -5271,29 +5318,17 @@ static int _pvremove_check_single(struct cmd_context *cmd,
log_debug("Checking device %s for pvremove %.32s.",
pv_dev_name(pv), pv->dev->pvid[0] ? pv->dev->pvid : "");
- /*
- * This test will fail if the device belongs to an MD array.
- */
- if (!dev_test_excl(pv->dev)) {
- /* FIXME Detect whether device-mapper itself is still using it */
- log_error("Can't open %s exclusively. Mounted filesystem?",
- pv_dev_name(pv));
- dm_list_move(&pp->arg_fail, &pd->list);
- return 1;
- }
/*
* Is there a pv here already?
* If not, this is an error unless you used -f.
*/
- if (!label_read(pd->dev, &label, 0)) {
+ if (!lvmcache_has_dev_info(pv->dev)) {
if (pp->force) {
dm_list_move(&pp->arg_process, &pd->list);
return 1;
} else {
- log_error("No PV label found on %s.", pd->name);
- dm_list_move(&pp->arg_fail, &pd->list);
- return 1;
+ pd->is_not_pv = 1;
}
}
@@ -5302,7 +5337,11 @@ static int _pvremove_check_single(struct cmd_context *cmd,
* device, a PV used in a VG.
*/
- if (vg && !is_orphan_vg(vg->name)) {
+ if (pd->is_not_pv) {
+ /* Device is not a PV. */
+ log_debug("Found pvremove arg %s: device is not a PV.", pd->name);
+
+ } else if (vg && !is_orphan_vg(vg->name)) {
/* Device is a PV used in a VG. */
log_debug("Found pvremove arg %s: pv is used in %s.", pd->name, vg->name);
pd->is_vg_pv = 1;
@@ -5324,6 +5363,7 @@ static int _pvremove_check_single(struct cmd_context *cmd,
else
pp->orphan_vg_name = FMT_TEXT_ORPHAN_VG_NAME;
} else {
+ /* FIXME: is it possible to reach here? */
log_debug("Found pvremove arg %s: device is not a PV.", pd->name);
/* Device is not a PV. */
pd->is_not_pv = 1;
@@ -5403,8 +5443,10 @@ int pvcreate_each_device(struct cmd_context *cmd,
struct volume_group *orphan_vg;
struct dm_list remove_duplicates;
struct dm_list arg_sort;
+ struct dm_list rescan_devs;
struct pv_list *pvl;
struct pv_list *vgpvl;
+ struct device_list *devl;
const char *pv_name;
int consistent = 0;
int must_use_all = (cmd->cname->flags & MUST_USE_ALL_ARGS);
@@ -5415,6 +5457,7 @@ int pvcreate_each_device(struct cmd_context *cmd,
dm_list_init(&remove_duplicates);
dm_list_init(&arg_sort);
+ dm_list_init(&rescan_devs);
handle->custom_handle = pp;
@@ -5466,7 +5509,7 @@ int pvcreate_each_device(struct cmd_context *cmd,
return 0;
}
- dev_cache_full_scan(cmd->full_filter);
+ lvmcache_label_scan(cmd);
/*
* Translate arg names into struct device's.
@@ -5622,6 +5665,8 @@ int pvcreate_each_device(struct cmd_context *cmd,
goto out;
}
+ lvmcache_label_scan(cmd);
+
/*
* The device args began on the arg_devices list, then the first check
* loop moved those entries to arg_process as they were found. Devices
@@ -5656,6 +5701,19 @@ int pvcreate_each_device(struct cmd_context *cmd,
do_command:
+ dm_list_iterate_items(pd, &pp->arg_process) {
+ if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
+ goto bad;
+ devl->dev = pd->dev;
+ dm_list_add(&rescan_devs, &devl->list);
+ }
+
+ log_debug("Rescanning devices with exclusive open");
+ if (!label_scan_devs_excl(&rescan_devs)) {
+ log_debug("Failed to rescan devs excl");
+ goto bad;
+ }
+
/*
* Reorder arg_process entries to match the original order of args.
*/
@@ -5674,6 +5732,8 @@ do_command:
* Wipe signatures on devices being created.
*/
dm_list_iterate_items_safe(pd, pd2, &pp->arg_create) {
+ label_scan_open(pd->dev);
+
log_verbose("Wiping signatures on new PV %s.", pd->name);
if (!wipe_known_signatures(cmd, pd->dev, pd->name, TYPE_LVM1_MEMBER | TYPE_LVM2_MEMBER,
@@ -5751,6 +5811,8 @@ do_command:
pv_name = pd->name;
+ label_scan_open(pd->dev);
+
log_debug("Creating a new PV on %s.", pv_name);
if (!(pv = pv_create(cmd, pd->dev, &pp->pva))) {
@@ -5762,6 +5824,7 @@ do_command:
log_verbose("Set up physical volume for \"%s\" with %" PRIu64
" available sectors.", pv_name, pv_size(pv));
+
if (!label_remove(pv->dev)) {
log_error("Failed to wipe existing label on %s.", pv_name);
dm_list_move(&pp->arg_fail, &pd->list);
@@ -5771,21 +5834,11 @@ do_command:
if (pp->zero) {
log_verbose("Zeroing start of device %s.", pv_name);
- if (!dev_open_quiet(pv->dev)) {
- log_error("%s not opened: device not zeroed.", pv_name);
- dm_list_move(&pp->arg_fail, &pd->list);
- continue;
- }
-
- if (!dev_set(pv->dev, UINT64_C(0), (size_t) 2048, DEV_IO_LABEL, 0)) {
+ if (!dev_write_zeros(pv->dev, 0, 2048)) {
log_error("%s not wiped: aborting.", pv_name);
- if (!dev_close(pv->dev))
- stack;
dm_list_move(&pp->arg_fail, &pd->list);
continue;
}
- if (!dev_close(pv->dev))
- stack;
}
log_verbose("Writing physical volume data to disk \"%s\".", pv_name);
diff --git a/tools/tools.h b/tools/tools.h
index 33cbf1071..5fe3ba86f 100644
--- a/tools/tools.h
+++ b/tools/tools.h
@@ -113,7 +113,6 @@ struct arg_value_group_list {
uint32_t prio;
};
-#define CACHE_VGMETADATA 0x00000001
#define PERMITTED_READ_ONLY 0x00000002
/* Process all VGs if none specified on the command line. */
#define ALL_VGS_IS_DEFAULT 0x00000004
@@ -125,8 +124,8 @@ struct arg_value_group_list {
#define LOCKD_VG_SH 0x00000020
/* Command does not process any metadata. */
#define NO_METADATA_PROCESSING 0x00000040
-/* Command wants to scan for new devices and force labels to be read from them all. */
-#define REQUIRES_FULL_LABEL_SCAN 0x00000080
+/* Command must not load the contents saved by the persistent filter */
+#define IGNORE_PERSISTENT_FILTER 0x00000080
/* Command must use all specified arg names and fail if all cannot be used. */
#define MUST_USE_ALL_ARGS 0x00000100
/* Command wants to control the device scan for lvmetad itself. */
@@ -137,8 +136,9 @@ struct arg_value_group_list {
#define DISALLOW_TAG_ARGS 0x00000800
/* Command may need to find VG name in an option value. */
#define GET_VGNAME_FROM_OPTIONS 0x00001000
-/* Command must not load the contents saved by the persistent filter */
-#define IGNORE_PERSISTENT_FILTER 0x00002000
+/* The data read from disk by label scan can be used for vg_read. */
+#define CAN_USE_ONE_SCAN 0x00002000
+
void usage(const char *name);
diff --git a/tools/vgcfgrestore.c b/tools/vgcfgrestore.c
index b5a2add12..e9f1a4c34 100644
--- a/tools/vgcfgrestore.c
+++ b/tools/vgcfgrestore.c
@@ -74,6 +74,8 @@ int vgcfgrestore(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED;
}
+ lvmcache_label_scan(cmd);
+
cmd->handles_unknown_segments = 1;
if (!(arg_is_set(cmd, file_ARG) ?
diff --git a/tools/vgchange.c b/tools/vgchange.c
index 7cfaab6a1..61b78dfd0 100644
--- a/tools/vgchange.c
+++ b/tools/vgchange.c
@@ -209,14 +209,19 @@ int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg,
cmd->handles_missing_pvs = 1;
/* FIXME: Force argument to deactivate them? */
- if (!do_activate && (lv_open = lvs_in_vg_opened(vg))) {
+ if (!do_activate) {
dm_list_iterate_items(lvl, &vg->lvs)
- if (lv_is_visible(lvl->lv) &&
- !lv_check_not_in_use(lvl->lv, 1)) {
- log_error("Can't deactivate volume group \"%s\" with %d open "
- "logical volume(s)", vg->name, lv_open);
- return 0;
+ label_scan_invalidate_lv(cmd, lvl->lv);
+
+ if ((lv_open = lvs_in_vg_opened(vg))) {
+ dm_list_iterate_items(lvl, &vg->lvs) {
+ if (lv_is_visible(lvl->lv) && !lv_check_not_in_use(lvl->lv, 1)) {
+ log_error("Can't deactivate volume group \"%s\" with %d open logical volume(s)",
+ vg->name, lv_open);
+ return 0;
+ }
}
+ }
}
/* FIXME Move into library where clvmd can use it */
diff --git a/tools/vgcreate.c b/tools/vgcreate.c
index af0c36364..0c4c42854 100644
--- a/tools/vgcreate.c
+++ b/tools/vgcreate.c
@@ -26,7 +26,6 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
const char *clustered_message = "";
char *vg_name;
struct arg_value_group_list *current_group;
- uint32_t rc;
if (!argc) {
log_error("Please provide volume group name and "
@@ -66,17 +65,29 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
return_ECMD_FAILED;
cmd->lockd_gl_disable = 1;
- lvmcache_seed_infos_from_lvmetad(cmd);
-
/*
* Check if the VG name already exists. This should be done before
* creating PVs on any of the devices.
+ *
+ * When searching if a VG name exists, acquire the VG lock,
+ * then do the initial label scan which reads all devices and
+ * populates lvmcache with any VG name it finds. If the VG name
+ * we want to use exists, then the label scan will find it,
+ * and the fmt_from_vgname call (used to check if the name exists)
+ * will return non-NULL.
*/
- if ((rc = vg_lock_newname(cmd, vp_new.vg_name)) != SUCCESS) {
- if (rc == FAILED_EXIST)
- log_error("A volume group called %s already exists.", vp_new.vg_name);
- else
- log_error("Can't get lock for %s.", vp_new.vg_name);
+
+ if (!lock_vol(cmd, vp_new.vg_name, LCK_VG_WRITE, NULL)) {
+ log_error("Can't get lock for %s.", vp_new.vg_name);
+ return ECMD_FAILED;
+ }
+
+ lvmcache_label_scan(cmd); /* Does nothing when using lvmetad. */
+ lvmcache_seed_infos_from_lvmetad(cmd); /* Does nothing unless using lvmetad. */
+
+ if (lvmcache_fmt_from_vgname(cmd, vp_new.vg_name, NULL, 0)) {
+ unlock_vg(cmd, NULL, vp_new.vg_name);
+ log_error("A volume group called %s already exists.", vp_new.vg_name);
return ECMD_FAILED;
}
diff --git a/tools/vgimportclone.c b/tools/vgimportclone.c
index 146d3b4bf..224d0b546 100644
--- a/tools/vgimportclone.c
+++ b/tools/vgimportclone.c
@@ -332,7 +332,6 @@ retry_name:
dm_list_iterate_items(vd, &vp.arg_import)
internal_filter_allow(cmd->mem, vd->dev);
lvmcache_destroy(cmd, 1, 0);
- dev_cache_full_scan(cmd->full_filter);
log_debug("Changing VG %s to %s.", vp.old_vgname, vp.new_vgname);
diff --git a/tools/vgmerge.c b/tools/vgmerge.c
index 013bef47d..67c349864 100644
--- a/tools/vgmerge.c
+++ b/tools/vgmerge.c
@@ -72,6 +72,9 @@ static int _vgmerge_single(struct cmd_context *cmd, const char *vg_name_to,
return ECMD_FAILED;
}
+ lvmcache_label_scan(cmd);
+ lvmcache_seed_infos_from_lvmetad(cmd);
+
if (strcmp(vg_name_to, vg_name_from) > 0)
lock_vg_from_first = 1;
diff --git a/tools/vgrename.c b/tools/vgrename.c
index 5c69faf26..4f2a08bb6 100644
--- a/tools/vgrename.c
+++ b/tools/vgrename.c
@@ -59,11 +59,6 @@ static int _vgrename_single(struct cmd_context *cmd, const char *vg_name,
/*
* Check if a VG already exists with the new VG name.
*
- * When not using lvmetad, it's essential that a full scan has
- * been done to ensure we see all existing VG names, so we
- * do not use an existing name. This has been done by
- * process_each_vg REQUIRES_FULL_LABEL_SCAN.
- *
* (FIXME: We could look for the new name in the list of all
* VGs that process_each_vg created, but we don't have access
* to that list here, so we have to look in lvmcache.
diff --git a/tools/vgsplit.c b/tools/vgsplit.c
index 46c891167..2d391119d 100644
--- a/tools/vgsplit.c
+++ b/tools/vgsplit.c
@@ -581,6 +581,9 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED;
}
+ lvmcache_label_scan(cmd);
+ lvmcache_seed_infos_from_lvmetad(cmd);
+
if (strcmp(vg_name_to, vg_name_from) < 0)
lock_vg_from_first = 0;
diff --git a/unit-tests/datastruct/Makefile.in b/unit-tests/datastruct/Makefile.in
deleted file mode 100644
index 4f0e7a49b..000000000
--- a/unit-tests/datastruct/Makefile.in
+++ /dev/null
@@ -1,32 +0,0 @@
-#
-# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
-# Copyright (C) 2004-2010 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@
-
-SOURCES=\
- bitset_t.c
-
-TARGETS=\
- bitset_t
-
-include $(top_builddir)/make.tmpl
-
-INCLUDES += -I$(top_srcdir)/libdm
-DM_DEPS = $(top_builddir)/libdm/libdevmapper.so
-DM_LIBS = -ldevmapper $(LIBS)
-
-bitset_t: bitset_t.o $(DM_DEPS)
- $(CC) $(CFLAGS) $(LDFLAGS) -o $@ bitset_t.o $(DM_LIBS)
diff --git a/unit-tests/datastruct/TESTS b/unit-tests/datastruct/TESTS
deleted file mode 100644
index ba88fb784..000000000
--- a/unit-tests/datastruct/TESTS
+++ /dev/null
@@ -1 +0,0 @@
-bitset iteration:$TEST_TOOL ./bitset_t \ No newline at end of file
diff --git a/unit-tests/datastruct/bitset_t.c b/unit-tests/datastruct/bitset_t.c
deleted file mode 100644
index be9b8fd9d..000000000
--- a/unit-tests/datastruct/bitset_t.c
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2010 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 "libdevmapper.h"
-
-#include <assert.h>
-
-enum {
- NR_BITS = 137
-};
-
-static void test_get_next(struct dm_pool *mem)
-{
- int i, j, last, first;
- dm_bitset_t bs = dm_bitset_create(mem, NR_BITS);
-
- for (i = 0; i < NR_BITS; i++)
- assert(!dm_bit(bs, i));
-
- for (i = 0, j = 1; i < NR_BITS; i += j, j++)
- dm_bit_set(bs, i);
-
- first = 1;
- for (i = 0, j = 1; i < NR_BITS; i += j, j++) {
- if (first) {
- last = dm_bit_get_first(bs);
- first = 0;
- } else
- last = dm_bit_get_next(bs, last);
-
- assert(last == i);
- }
-
- assert(dm_bit_get_next(bs, last) == -1);
-}
-
-static void bit_flip(dm_bitset_t bs, int bit)
-{
- int old = dm_bit(bs, bit);
- if (old)
- dm_bit_clear(bs, bit);
- else
- dm_bit_set(bs, bit);
-}
-
-static void test_equal(struct dm_pool *mem)
-{
- dm_bitset_t bs1 = dm_bitset_create(mem, NR_BITS);
- dm_bitset_t bs2 = dm_bitset_create(mem, NR_BITS);
-
- int i, j;
- for (i = 0, j = 1; i < NR_BITS; i += j, j++) {
- dm_bit_set(bs1, i);
- dm_bit_set(bs2, i);
- }
-
- assert(dm_bitset_equal(bs1, bs2));
- assert(dm_bitset_equal(bs2, bs1));
-
- for (i = 0; i < NR_BITS; i++) {
- bit_flip(bs1, i);
- assert(!dm_bitset_equal(bs1, bs2));
- assert(!dm_bitset_equal(bs2, bs1));
-
- assert(dm_bitset_equal(bs1, bs1)); /* comparing with self */
- bit_flip(bs1, i);
- }
-}
-
-static void test_and(struct dm_pool *mem)
-{
- dm_bitset_t bs1 = dm_bitset_create(mem, NR_BITS);
- dm_bitset_t bs2 = dm_bitset_create(mem, NR_BITS);
- dm_bitset_t bs3 = dm_bitset_create(mem, NR_BITS);
-
- int i, j;
- for (i = 0, j = 1; i < NR_BITS; i += j, j++) {
- dm_bit_set(bs1, i);
- dm_bit_set(bs2, i);
- }
-
- dm_bit_and(bs3, bs1, bs2);
-
- assert(dm_bitset_equal(bs1, bs2));
- assert(dm_bitset_equal(bs1, bs3));
- assert(dm_bitset_equal(bs2, bs3));
-
- dm_bit_clear_all(bs1);
- dm_bit_clear_all(bs2);
-
- for (i = 0; i < NR_BITS; i++) {
- if (i % 2)
- dm_bit_set(bs1, i);
- else
- dm_bit_set(bs2, i);
- }
-
- dm_bit_and(bs3, bs1, bs2);
- for (i = 0; i < NR_BITS; i++)
- assert(!dm_bit(bs3, i));
-}
-
-int main(int argc, char **argv)
-{
- typedef void (*test_fn)(struct dm_pool *);
- static test_fn tests[] = {
- test_get_next,
- test_equal,
- test_and
- };
-
- int i;
- for (i = 0; i < DM_ARRAY_SIZE(tests); ++i) {
- struct dm_pool *mem = dm_pool_create("bitset test", 1024);
- assert(mem);
- tests[i](mem);
- dm_pool_destroy(mem);
- }
-
- return 0;
-}
-
diff --git a/unit-tests/mm/Makefile.in b/unit-tests/mm/Makefile.in
deleted file mode 100644
index a40e2e235..000000000
--- a/unit-tests/mm/Makefile.in
+++ /dev/null
@@ -1,31 +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=\
- pool_valgrind_t.c
-
-TARGETS=\
- pool_valgrind_t
-
-include $(top_builddir)/make.tmpl
-DM_LIBS = -ldevmapper $(LIBS)
-
-pool_valgrind_t: pool_valgrind_t.o
- $(CC) $(CFLAGS) -o $@ pool_valgrind_t.o $(LDFLAGS) $(DM_LIBS)
-
diff --git a/unit-tests/mm/TESTS b/unit-tests/mm/TESTS
deleted file mode 100644
index 3bf31544a..000000000
--- a/unit-tests/mm/TESTS
+++ /dev/null
@@ -1 +0,0 @@
-valgrind pool awareness:valgrind ./pool_valgrind_t 2>&1 | ./check_results
diff --git a/unit-tests/mm/check_results b/unit-tests/mm/check_results
deleted file mode 100755
index a7b0975a5..000000000
--- a/unit-tests/mm/check_results
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/usr/bin/env ruby1.9
-
-require 'pp'
-
-patterns = [
- /Invalid read of size 1/,
- /Invalid write of size 1/,
- /Invalid read of size 1/,
- /still reachable: [0-9,]+ bytes in 3 blocks/
- ]
-
-lines = STDIN.readlines
-pp lines
-
-result = catch(:done) do
- patterns.each do |pat|
- loop do
- throw(:done, false) if lines.size == 0
-
- line = lines.shift
- if line =~ pat
- STDERR.puts "matched #{pat}"
- break;
- end
- end
- end
-
- throw(:done, true)
-end
-
-exit(result ? 0 : 1)
diff --git a/unit-tests/mm/pool_valgrind_t.c b/unit-tests/mm/pool_valgrind_t.c
deleted file mode 100644
index 704f1168e..000000000
--- a/unit-tests/mm/pool_valgrind_t.c
+++ /dev/null
@@ -1,181 +0,0 @@
-#include "libdevmapper.h"
-
-#include <assert.h>
-
-/*
- * Checks that valgrind is picking up unallocated pool memory as
- * uninitialised, even if the chunk has been recycled.
- *
- * $ valgrind --track-origins=yes ./pool_valgrind_t
- *
- * ==7023== Memcheck, a memory error detector
- * ==7023== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
- * ==7023== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
- * ==7023== Command: ./pool_valgrind_t
- * ==7023==
- * first branch worked (as expected)
- * ==7023== Conditional jump or move depends on uninitialised value(s)
- * ==7023== at 0x4009AC: main (in /home/ejt/work/lvm2/unit-tests/mm/pool_valgrind_t)
- * ==7023== Uninitialised value was created by a client request
- * ==7023== at 0x4E40CB8: dm_pool_free (in /home/ejt/work/lvm2/libdm/ioctl/libdevmapper.so.1.02)
- * ==7023== by 0x4009A8: main (in /home/ejt/work/lvm2/unit-tests/mm/pool_valgrind_t)
- * ==7023==
- * second branch worked (valgrind should have flagged this as an error)
- * ==7023==
- * ==7023== HEAP SUMMARY:
- * ==7023== in use at exit: 0 bytes in 0 blocks
- * ==7023== total heap usage: 2 allocs, 2 frees, 2,104 bytes allocated
- * ==7023==
- * ==7023== All heap blocks were freed -- no leaks are possible
- * ==7023==
- * ==7023== For counts of detected and suppressed errors, rerun with: -v
- * ==7023== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4)
- */
-
-#define COUNT 10
-
-static void check_free()
-{
- int i;
- char *blocks[COUNT];
- struct dm_pool *p = dm_pool_create("blah", 1024);
-
- for (i = 0; i < COUNT; i++)
- blocks[i] = dm_pool_alloc(p, 37);
-
- /* check we can access the last block */
- blocks[COUNT - 1][0] = 'E';
- if (blocks[COUNT - 1][0] == 'E')
- printf("first branch worked (as expected)\n");
-
- dm_pool_free(p, blocks[5]);
-
- if (blocks[COUNT - 1][0] == 'E')
- printf("second branch worked (valgrind should have flagged this as an error)\n");
-
- dm_pool_destroy(p);
-}
-
-/* Checks that freed chunks are marked NOACCESS */
-static void check_free2()
-{
- struct dm_pool *p = dm_pool_create("", 900); /* 900 will get
- * rounded up to 1024,
- * 1024 would have got
- * rounded up to
- * 2048 */
- char *data1, *data2;
-
- assert(p);
- data1 = dm_pool_alloc(p, 123);
- assert(data1);
-
- data1 = dm_pool_alloc(p, 1024);
- assert(data1);
-
- data2 = dm_pool_alloc(p, 123);
- assert(data2);
-
- data2[0] = 'A'; /* should work fine */
-
- dm_pool_free(p, data1);
-
- /*
- * so now the first chunk is active, the second chunk has become
- * the free one.
- */
- data2[0] = 'B'; /* should prompt an invalid write error */
-
- dm_pool_destroy(p);
-}
-
-static void check_alignment()
-{
- /*
- * Pool always tries to allocate blocks with particular alignment.
- * So there are potentially small gaps between allocations. This
- * test checks that valgrind is spotting illegal accesses to these
- * gaps.
- */
-
- int i, sum;
- struct dm_pool *p = dm_pool_create("blah", 1024);
- char *data1, *data2;
- char buffer[16];
-
-
- data1 = dm_pool_alloc_aligned(p, 1, 4);
- assert(data1);
- data2 = dm_pool_alloc_aligned(p, 1, 4);
- assert(data1);
-
- snprintf(buffer, sizeof(buffer), "%c", *(data1 + 1)); /* invalid read size 1 */
- dm_pool_destroy(p);
-}
-
-/*
- * Looking at the code I'm not sure allocations that are near the chunk
- * size are working. So this test is trying to exhibit a specific problem.
- */
-static void check_allocation_near_chunk_size()
-{
- int i;
- char *data;
- struct dm_pool *p = dm_pool_create("", 900);
-
- /*
- * allocate a lot and then free everything so we know there
- * is a spare chunk.
- */
- for (i = 0; i < 1000; i++) {
- data = dm_pool_alloc(p, 37);
- memset(data, 0, 37);
- assert(data);
- }
-
- dm_pool_empty(p);
-
- /* now we allocate something close to the chunk size ... */
- data = dm_pool_alloc(p, 1020);
- assert(data);
- memset(data, 0, 1020);
-
- dm_pool_destroy(p);
-}
-
-/* FIXME: test the dbg_malloc at exit (this test should be in dbg_malloc) */
-static void check_leak_detection()
-{
- int i;
- struct dm_pool *p = dm_pool_create("", 1024);
-
- for (i = 0; i < 10; i++)
- dm_pool_alloc(p, (i + 1) * 37);
-}
-
-/* we shouldn't get any errors from this one */
-static void check_object_growth()
-{
- int i;
- struct dm_pool *p = dm_pool_create("", 32);
- char data[100] = { 0 };
- void *obj;
-
- dm_pool_begin_object(p, 43);
- for (i = 1; i < 100; i++)
- dm_pool_grow_object(p, data, i);
- obj = dm_pool_end_object(p);
-
- dm_pool_destroy(p);
-}
-
-int main(int argc, char **argv)
-{
- check_free();
- check_free2();
- check_alignment();
- check_allocation_near_chunk_size();
- check_leak_detection();
- check_object_growth();
- return 0;
-}
diff --git a/unit-tests/regex/Makefile.in b/unit-tests/regex/Makefile.in
deleted file mode 100644
index 76b7dee36..000000000
--- a/unit-tests/regex/Makefile.in
+++ /dev/null
@@ -1,37 +0,0 @@
-#
-# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
-# Copyright (C) 2004-2010 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@
-
-SOURCES=\
- parse_t.c \
- matcher_t.c
-
-TARGETS=\
- parse_t \
- matcher_t
-
-include $(top_builddir)/make.tmpl
-
-INCLUDES += -I$(top_srcdir)/libdm
-DM_DEPS = $(top_builddir)/libdm/libdevmapper.so
-DM_LIBS = -ldevmapper $(LIBS)
-
-parse_t: parse_t.o $(DM_DEPS)
- $(CC) $(CFLAGS) $(LDFLAGS) -o $@ parse_t.o $(DM_LIBS)
-
-matcher_t: matcher_t.o $(DM_DEPS)
- $(CC) $(CFLAGS) $(LDFLAGS) -o $@ matcher_t.o $(DM_LIBS)
diff --git a/unit-tests/regex/TESTS b/unit-tests/regex/TESTS
deleted file mode 100644
index 329794293..000000000
--- a/unit-tests/regex/TESTS
+++ /dev/null
@@ -1,3 +0,0 @@
-dfa matching:$TEST_TOOL ./matcher_t --fingerprint dev_patterns < devices.list > matcher_t.output && diff -u matcher_t.expected matcher_t.output
-dfa matching:$TEST_TOOL ./matcher_t --fingerprint random_regexes < /dev/null > matcher_t.output && diff -u matcher_t.expected2 matcher_t.output
-dfa with non-print regex chars:$TEST_TOOL ./matcher_t nonprint_regexes < nonprint_input > matcher_t.output && diff -u matcher_t.expected3 matcher_t.output \ No newline at end of file
diff --git a/unit-tests/regex/dev_patterns b/unit-tests/regex/dev_patterns
deleted file mode 100644
index 34459ba60..000000000
--- a/unit-tests/regex/dev_patterns
+++ /dev/null
@@ -1,2 +0,0 @@
-"loop/[0-9]+"
-"hd[a-d][0-5]+"
diff --git a/unit-tests/regex/devices.list b/unit-tests/regex/devices.list
deleted file mode 100644
index 91af305e1..000000000
--- a/unit-tests/regex/devices.list
+++ /dev/null
@@ -1,880 +0,0 @@
-/dev
-/dev/.devfsd
-/dev/cpu
-/dev/cpu/mtrr
-/dev/netlink
-/dev/netlink/route
-/dev/netlink/skip
-/dev/netlink/USERSOCK
-/dev/netlink/fwmonitor
-/dev/netlink/ARPD
-/dev/netlink/ROUTE6
-/dev/netlink/IP6_FW
-/dev/netlink/tap0
-/dev/netlink/tap1
-/dev/netlink/tap2
-/dev/netlink/tap3
-/dev/netlink/tap4
-/dev/netlink/tap5
-/dev/netlink/tap6
-/dev/netlink/tap7
-/dev/netlink/tap8
-/dev/netlink/tap9
-/dev/netlink/tap10
-/dev/netlink/tap11
-/dev/netlink/tap12
-/dev/netlink/tap13
-/dev/netlink/tap14
-/dev/netlink/tap15
-/dev/shm
-/dev/mem
-/dev/kmem
-/dev/null
-/dev/port
-/dev/zero
-/dev/full
-/dev/random
-/dev/urandom
-/dev/tty
-/dev/console
-/dev/vc
-/dev/vc/1
-/dev/vc/2
-/dev/vc/3
-/dev/vc/4
-/dev/vc/5
-/dev/vc/6
-/dev/vc/7
-/dev/vc/8
-/dev/vc/9
-/dev/vc/10
-/dev/vc/11
-/dev/vc/12
-/dev/vc/13
-/dev/vc/14
-/dev/vc/15
-/dev/vc/16
-/dev/vc/17
-/dev/vc/18
-/dev/vc/19
-/dev/vc/20
-/dev/vc/21
-/dev/vc/22
-/dev/vc/23
-/dev/vc/24
-/dev/vc/25
-/dev/vc/26
-/dev/vc/27
-/dev/vc/28
-/dev/vc/29
-/dev/vc/30
-/dev/vc/31
-/dev/vc/32
-/dev/vc/33
-/dev/vc/34
-/dev/vc/35
-/dev/vc/36
-/dev/vc/37
-/dev/vc/38
-/dev/vc/39
-/dev/vc/40
-/dev/vc/41
-/dev/vc/42
-/dev/vc/43
-/dev/vc/44
-/dev/vc/45
-/dev/vc/46
-/dev/vc/47
-/dev/vc/48
-/dev/vc/49
-/dev/vc/50
-/dev/vc/51
-/dev/vc/52
-/dev/vc/53
-/dev/vc/54
-/dev/vc/55
-/dev/vc/56
-/dev/vc/57
-/dev/vc/58
-/dev/vc/59
-/dev/vc/60
-/dev/vc/61
-/dev/vc/62
-/dev/vc/63
-/dev/vc/0
-/dev/ptmx
-/dev/misc
-/dev/misc/psaux
-/dev/pty
-/dev/pty/m0
-/dev/pty/m1
-/dev/pty/m2
-/dev/pty/m3
-/dev/pty/m4
-/dev/pty/m5
-/dev/pty/m6
-/dev/pty/m7
-/dev/pty/m8
-/dev/pty/m9
-/dev/pty/m10
-/dev/pty/m11
-/dev/pty/m12
-/dev/pty/m13
-/dev/pty/m14
-/dev/pty/m15
-/dev/pty/m16
-/dev/pty/m17
-/dev/pty/m18
-/dev/pty/m19
-/dev/pty/m20
-/dev/pty/m21
-/dev/pty/m22
-/dev/pty/m23
-/dev/pty/m24
-/dev/pty/m25
-/dev/pty/m26
-/dev/pty/m27
-/dev/pty/m28
-/dev/pty/m29
-/dev/pty/m30
-/dev/pty/m31
-/dev/pty/m32
-/dev/pty/m33
-/dev/pty/m34
-/dev/pty/m35
-/dev/pty/m36
-/dev/pty/m37
-/dev/pty/m38
-/dev/pty/m39
-/dev/pty/m40
-/dev/pty/m41
-/dev/pty/m42
-/dev/pty/m43
-/dev/pty/m44
-/dev/pty/m45
-/dev/pty/m46
-/dev/pty/m47
-/dev/pty/m48
-/dev/pty/m49
-/dev/pty/m50
-/dev/pty/m51
-/dev/pty/m52
-/dev/pty/m53
-/dev/pty/m54
-/dev/pty/m55
-/dev/pty/m56
-/dev/pty/m57
-/dev/pty/m58
-/dev/pty/m59
-/dev/pty/m60
-/dev/pty/m61
-/dev/pty/m62
-/dev/pty/m63
-/dev/pty/m64
-/dev/pty/m65
-/dev/pty/m66
-/dev/pty/m67
-/dev/pty/m68
-/dev/pty/m69
-/dev/pty/m70
-/dev/pty/m71
-/dev/pty/m72
-/dev/pty/m73
-/dev/pty/m74
-/dev/pty/m75
-/dev/pty/m76
-/dev/pty/m77
-/dev/pty/m78
-/dev/pty/m79
-/dev/pty/m80
-/dev/pty/m81
-/dev/pty/m82
-/dev/pty/m83
-/dev/pty/m84
-/dev/pty/m85
-/dev/pty/m86
-/dev/pty/m87
-/dev/pty/m88
-/dev/pty/m89
-/dev/pty/m90
-/dev/pty/m91
-/dev/pty/m92
-/dev/pty/m93
-/dev/pty/m94
-/dev/pty/m95
-/dev/pty/m96
-/dev/pty/m97
-/dev/pty/m98
-/dev/pty/m99
-/dev/pty/m100
-/dev/pty/m101
-/dev/pty/m102
-/dev/pty/m103
-/dev/pty/m104
-/dev/pty/m105
-/dev/pty/m106
-/dev/pty/m107
-/dev/pty/m108
-/dev/pty/m109
-/dev/pty/m110
-/dev/pty/m111
-/dev/pty/m112
-/dev/pty/m113
-/dev/pty/m114
-/dev/pty/m115
-/dev/pty/m116
-/dev/pty/m117
-/dev/pty/m118
-/dev/pty/m119
-/dev/pty/m120
-/dev/pty/m121
-/dev/pty/m122
-/dev/pty/m123
-/dev/pty/m124
-/dev/pty/m125
-/dev/pty/m126
-/dev/pty/m127
-/dev/pty/m128
-/dev/pty/m129
-/dev/pty/m130
-/dev/pty/m131
-/dev/pty/m132
-/dev/pty/m133
-/dev/pty/m134
-/dev/pty/m135
-/dev/pty/m136
-/dev/pty/m137
-/dev/pty/m138
-/dev/pty/m139
-/dev/pty/m140
-/dev/pty/m141
-/dev/pty/m142
-/dev/pty/m143
-/dev/pty/m144
-/dev/pty/m145
-/dev/pty/m146
-/dev/pty/m147
-/dev/pty/m148
-/dev/pty/m149
-/dev/pty/m150
-/dev/pty/m151
-/dev/pty/m152
-/dev/pty/m153
-/dev/pty/m154
-/dev/pty/m155
-/dev/pty/m156
-/dev/pty/m157
-/dev/pty/m158
-/dev/pty/m159
-/dev/pty/m160
-/dev/pty/m161
-/dev/pty/m162
-/dev/pty/m163
-/dev/pty/m164
-/dev/pty/m165
-/dev/pty/m166
-/dev/pty/m167
-/dev/pty/m168
-/dev/pty/m169
-/dev/pty/m170
-/dev/pty/m171
-/dev/pty/m172
-/dev/pty/m173
-/dev/pty/m174
-/dev/pty/m175
-/dev/pty/m176
-/dev/pty/m177
-/dev/pty/m178
-/dev/pty/m179
-/dev/pty/m180
-/dev/pty/m181
-/dev/pty/m182
-/dev/pty/m183
-/dev/pty/m184
-/dev/pty/m185
-/dev/pty/m186
-/dev/pty/m187
-/dev/pty/m188
-/dev/pty/m189
-/dev/pty/m190
-/dev/pty/m191
-/dev/pty/m192
-/dev/pty/m193
-/dev/pty/m194
-/dev/pty/m195
-/dev/pty/m196
-/dev/pty/m197
-/dev/pty/m198
-/dev/pty/m199
-/dev/pty/m200
-/dev/pty/m201
-/dev/pty/m202
-/dev/pty/m203
-/dev/pty/m204
-/dev/pty/m205
-/dev/pty/m206
-/dev/pty/m207
-/dev/pty/m208
-/dev/pty/m209
-/dev/pty/m210
-/dev/pty/m211
-/dev/pty/m212
-/dev/pty/m213
-/dev/pty/m214
-/dev/pty/m215
-/dev/pty/m216
-/dev/pty/m217
-/dev/pty/m218
-/dev/pty/m219
-/dev/pty/m220
-/dev/pty/m221
-/dev/pty/m222
-/dev/pty/m223
-/dev/pty/m224
-/dev/pty/m225
-/dev/pty/m226
-/dev/pty/m227
-/dev/pty/m228
-/dev/pty/m229
-/dev/pty/m230
-/dev/pty/m231
-/dev/pty/m232
-/dev/pty/m233
-/dev/pty/m234
-/dev/pty/m235
-/dev/pty/m236
-/dev/pty/m237
-/dev/pty/m238
-/dev/pty/m239
-/dev/pty/m240
-/dev/pty/m241
-/dev/pty/m242
-/dev/pty/m243
-/dev/pty/m244
-/dev/pty/m245
-/dev/pty/m246
-/dev/pty/m247
-/dev/pty/m248
-/dev/pty/m249
-/dev/pty/m250
-/dev/pty/m251
-/dev/pty/m252
-/dev/pty/m253
-/dev/pty/m254
-/dev/pty/m255
-/dev/pts
-/dev/pts/0
-/dev/pts/1
-/dev/pts/2
-/dev/pts/3
-/dev/pts/4
-/dev/pts/5
-/dev/pts/6
-/dev/pts/7
-/dev/vcc
-/dev/vcc/0
-/dev/vcc/a
-/dev/vcc/1
-/dev/vcc/a1
-/dev/vcc/2
-/dev/vcc/a2
-/dev/vcc/3
-/dev/vcc/a3
-/dev/vcc/5
-/dev/vcc/a5
-/dev/vcc/4
-/dev/vcc/a4
-/dev/vcc/6
-/dev/vcc/a6
-/dev/vcc/7
-/dev/vcc/a7
-/dev/tts
-/dev/tts/0
-/dev/cua
-/dev/cua/0
-/dev/ide
-/dev/ide/host0
-/dev/ide/host0/bus0
-/dev/ide/host0/bus0/target0
-/dev/ide/host0/bus0/target0/lun0
-/dev/ide/host0/bus0/target0/lun0/disc
-/dev/ide/host0/bus0/target0/lun0/part1
-/dev/ide/host0/bus0/target0/lun0/part2
-/dev/ide/host0/bus0/target0/lun0/part3
-/dev/ide/host0/bus0/target0/lun0/part4
-/dev/ide/host0/bus0/target0/lun0/part5
-/dev/ide/host0/bus0/target0/lun0/part6
-/dev/ide/host0/bus0/target0/lun0/part7
-/dev/ide/host0/bus0/target0/lun0/part8
-/dev/ide/host0/bus0/target1
-/dev/ide/host0/bus0/target1/lun0
-/dev/ide/host0/bus0/target1/lun0/disc
-/dev/ide/host0/bus0/target1/lun0/part1
-/dev/ide/host0/bus1
-/dev/ide/host0/bus1/target0
-/dev/ide/host0/bus1/target0/lun0
-/dev/ide/host0/bus1/target0/lun0/disc
-/dev/ide/host0/bus1/target0/lun0/part1
-/dev/ide/host0/bus1/target1
-/dev/ide/host0/bus1/target1/lun0
-/dev/discs
-/dev/discs/disc0
-/dev/discs/disc1
-/dev/discs/disc2
-/dev/floppy
-/dev/floppy/0u1440
-/dev/floppy/0u1680
-/dev/floppy/0u1722
-/dev/floppy/0u1743
-/dev/floppy/0u1760
-/dev/floppy/0u1920
-/dev/floppy/0u1840
-/dev/floppy/0u1600
-/dev/floppy/0u360
-/dev/floppy/0u720
-/dev/floppy/0u820
-/dev/floppy/0u830
-/dev/floppy/0u1040
-/dev/floppy/0u1120
-/dev/floppy/0u800
-/dev/floppy/0
-/dev/loop
-/dev/loop/0
-/dev/loop/1
-/dev/loop/2
-/dev/loop/3
-/dev/loop/4
-/dev/loop/5
-/dev/loop/6
-/dev/loop/7
-/dev/cdroms
-/dev/sound
-/dev/sound/dsp
-/dev/sound/dsp1
-/dev/sound/mixer
-/dev/sound/midi
-/dev/usb
-/dev/root
-/dev/initctl
-/dev/xconsole
-/dev/fd
-/dev/stdin
-/dev/stdout
-/dev/stderr
-/dev/route
-/dev/skip
-/dev/USERSOCK
-/dev/fwmonitor
-/dev/ARPD
-/dev/ROUTE6
-/dev/IP6_FW
-/dev/tap0
-/dev/tap1
-/dev/tap2
-/dev/tap3
-/dev/tap4
-/dev/tap5
-/dev/tap6
-/dev/tap7
-/dev/tap8
-/dev/tap9
-/dev/tap10
-/dev/tap11
-/dev/tap12
-/dev/tap13
-/dev/tap14
-/dev/tap15
-/dev/tty1
-/dev/tty2
-/dev/tty3
-/dev/tty4
-/dev/tty5
-/dev/tty6
-/dev/tty7
-/dev/tty8
-/dev/tty9
-/dev/tty10
-/dev/tty11
-/dev/tty12
-/dev/tty13
-/dev/tty14
-/dev/tty15
-/dev/tty16
-/dev/tty17
-/dev/tty18
-/dev/tty19
-/dev/tty20
-/dev/tty21
-/dev/tty22
-/dev/tty23
-/dev/tty24
-/dev/tty25
-/dev/tty26
-/dev/tty27
-/dev/tty28
-/dev/tty29
-/dev/tty30
-/dev/tty31
-/dev/tty32
-/dev/tty33
-/dev/tty34
-/dev/tty35
-/dev/tty36
-/dev/tty37
-/dev/tty38
-/dev/tty39
-/dev/tty40
-/dev/tty41
-/dev/tty42
-/dev/tty43
-/dev/tty44
-/dev/tty45
-/dev/tty46
-/dev/tty47
-/dev/tty48
-/dev/tty49
-/dev/tty50
-/dev/tty51
-/dev/tty52
-/dev/tty53
-/dev/tty54
-/dev/tty55
-/dev/tty56
-/dev/tty57
-/dev/tty58
-/dev/tty59
-/dev/tty60
-/dev/tty61
-/dev/tty62
-/dev/tty63
-/dev/tty0
-/dev/psaux
-/dev/ptyp0
-/dev/ptyp1
-/dev/ptyp2
-/dev/ptyp3
-/dev/ptyp4
-/dev/ptyp5
-/dev/ptyp6
-/dev/ptyp7
-/dev/ptyp8
-/dev/ptyp9
-/dev/ptypa
-/dev/ptypb
-/dev/ptypc
-/dev/ptypd
-/dev/ptype
-/dev/ptypf
-/dev/ptyq0
-/dev/ptyq1
-/dev/ptyq2
-/dev/ptyq3
-/dev/ptyq4
-/dev/ptyq5
-/dev/ptyq6
-/dev/ptyq7
-/dev/ptyq8
-/dev/ptyq9
-/dev/ptyqa
-/dev/ptyqb
-/dev/ptyqc
-/dev/ptyqd
-/dev/ptyqe
-/dev/ptyqf
-/dev/ptyr0
-/dev/ptyr1
-/dev/ptyr2
-/dev/ptyr3
-/dev/ptyr4
-/dev/ptyr5
-/dev/ptyr6
-/dev/ptyr7
-/dev/ptyr8
-/dev/ptyr9
-/dev/ptyra
-/dev/ptyrb
-/dev/ptyrc
-/dev/ptyrd
-/dev/ptyre
-/dev/ptyrf
-/dev/ptys0
-/dev/ptys1
-/dev/ptys2
-/dev/ptys3
-/dev/ptys4
-/dev/ptys5
-/dev/ptys6
-/dev/ptys7
-/dev/ptys8
-/dev/ptys9
-/dev/ptysa
-/dev/ptysb
-/dev/ptysc
-/dev/ptysd
-/dev/ptyse
-/dev/ptysf
-/dev/ptyt0
-/dev/ptyt1
-/dev/ptyt2
-/dev/ptyt3
-/dev/ptyt4
-/dev/ptyt5
-/dev/ptyt6
-/dev/ptyt7
-/dev/ptyt8
-/dev/ptyt9
-/dev/ptyta
-/dev/ptytb
-/dev/ptytc
-/dev/ptytd
-/dev/ptyte
-/dev/ptytf
-/dev/ptyu0
-/dev/ptyu1
-/dev/ptyu2
-/dev/ptyu3
-/dev/ptyu4
-/dev/ptyu5
-/dev/ptyu6
-/dev/ptyu7
-/dev/ptyu8
-/dev/ptyu9
-/dev/ptyua
-/dev/ptyub
-/dev/ptyuc
-/dev/ptyud
-/dev/ptyue
-/dev/ptyuf
-/dev/ptyv0
-/dev/ptyv1
-/dev/ptyv2
-/dev/ptyv3
-/dev/ptyv4
-/dev/ptyv5
-/dev/ptyv6
-/dev/ptyv7
-/dev/ptyv8
-/dev/ptyv9
-/dev/ptyva
-/dev/ptyvb
-/dev/ptyvc
-/dev/ptyvd
-/dev/ptyve
-/dev/ptyvf
-/dev/ptyw0
-/dev/ptyw1
-/dev/ptyw2
-/dev/ptyw3
-/dev/ptyw4
-/dev/ptyw5
-/dev/ptyw6
-/dev/ptyw7
-/dev/ptyw8
-/dev/ptyw9
-/dev/ptywa
-/dev/ptywb
-/dev/ptywc
-/dev/ptywd
-/dev/ptywe
-/dev/ptywf
-/dev/ptyx0
-/dev/ptyx1
-/dev/ptyx2
-/dev/ptyx3
-/dev/ptyx4
-/dev/ptyx5
-/dev/ptyx6
-/dev/ptyx7
-/dev/ptyx8
-/dev/ptyx9
-/dev/ptyxa
-/dev/ptyxb
-/dev/ptyxc
-/dev/ptyxd
-/dev/ptyxe
-/dev/ptyxf
-/dev/ptyy0
-/dev/ptyy1
-/dev/ptyy2
-/dev/ptyy3
-/dev/ptyy4
-/dev/ptyy5
-/dev/ptyy6
-/dev/ptyy7
-/dev/ptyy8
-/dev/ptyy9
-/dev/ptyya
-/dev/ptyyb
-/dev/ptyyc
-/dev/ptyyd
-/dev/ptyye
-/dev/ptyyf
-/dev/ptyz0
-/dev/ptyz1
-/dev/ptyz2
-/dev/ptyz3
-/dev/ptyz4
-/dev/ptyz5
-/dev/ptyz6
-/dev/ptyz7
-/dev/ptyz8
-/dev/ptyz9
-/dev/ptyza
-/dev/ptyzb
-/dev/ptyzc
-/dev/ptyzd
-/dev/ptyze
-/dev/ptyzf
-/dev/ptya0
-/dev/ptya1
-/dev/ptya2
-/dev/ptya3
-/dev/ptya4
-/dev/ptya5
-/dev/ptya6
-/dev/ptya7
-/dev/ptya8
-/dev/ptya9
-/dev/ptyaa
-/dev/ptyab
-/dev/ptyac
-/dev/ptyad
-/dev/ptyae
-/dev/ptyaf
-/dev/ptyb0
-/dev/ptyb1
-/dev/ptyb2
-/dev/ptyb3
-/dev/ptyb4
-/dev/ptyb5
-/dev/ptyb6
-/dev/ptyb7
-/dev/ptyb8
-/dev/ptyb9
-/dev/ptyba
-/dev/ptybb
-/dev/ptybc
-/dev/ptybd
-/dev/ptybe
-/dev/ptybf
-/dev/ptyc0
-/dev/ptyc1
-/dev/ptyc2
-/dev/ptyc3
-/dev/ptyc4
-/dev/ptyc5
-/dev/ptyc6
-/dev/ptyc7
-/dev/ptyc8
-/dev/ptyc9
-/dev/ptyca
-/dev/ptycb
-/dev/ptycc
-/dev/ptycd
-/dev/ptyce
-/dev/ptycf
-/dev/ptyd0
-/dev/ptyd1
-/dev/ptyd2
-/dev/ptyd3
-/dev/ptyd4
-/dev/ptyd5
-/dev/ptyd6
-/dev/ptyd7
-/dev/ptyd8
-/dev/ptyd9
-/dev/ptyda
-/dev/ptydb
-/dev/ptydc
-/dev/ptydd
-/dev/ptyde
-/dev/ptydf
-/dev/ptye0
-/dev/ptye1
-/dev/ptye2
-/dev/ptye3
-/dev/ptye4
-/dev/ptye5
-/dev/ptye6
-/dev/ptye7
-/dev/ptye8
-/dev/ptye9
-/dev/ptyea
-/dev/ptyeb
-/dev/ptyec
-/dev/ptyed
-/dev/ptyee
-/dev/ptyef
-/dev/vcs
-/dev/vcsa
-/dev/vcs1
-/dev/vcsa1
-/dev/ttyS0
-/dev/cua0
-/dev/hda
-/dev/hda1
-/dev/hda2
-/dev/hda3
-/dev/hda4
-/dev/hda5
-/dev/hda6
-/dev/hda7
-/dev/hda8
-/dev/hdb
-/dev/hdb1
-/dev/hdc
-/dev/hdc1
-/dev/fd0u1440
-/dev/fd0u1680
-/dev/fd0u1722
-/dev/fd0u1743
-/dev/fd0u1760
-/dev/fd0u1920
-/dev/fd0u1840
-/dev/fd0u1600
-/dev/fd0u360
-/dev/fd0u720
-/dev/fd0u820
-/dev/fd0u830
-/dev/fd0u1040
-/dev/fd0u1120
-/dev/fd0u800
-/dev/fd0
-/dev/loop0
-/dev/loop1
-/dev/loop2
-/dev/loop3
-/dev/loop4
-/dev/loop5
-/dev/loop6
-/dev/loop7
-/dev/dsp
-/dev/dsp1
-/dev/mixer
-/dev/midi
-/dev/lvm
-/dev/vg0
-/dev/vg0/group
-/dev/vg0/packages
-/dev/vg0/photos
-/dev/vg0/music
-/dev/log
-/dev/MAKEDEV
-/dev/printer
-/dev/vcs2
-/dev/vcsa2
-/dev/vcs3
-/dev/vcsa3
-/dev/vcs5
-/dev/vcsa5
-/dev/vcs4
-/dev/vcsa4
-/dev/vcs6
-/dev/vcsa6
-/dev/nvidia0
-/dev/nvidia1
-/dev/nvidia2
-/dev/nvidia3
-/dev/nvidiactl
-/dev/vcs7
-/dev/vcsa7
diff --git a/unit-tests/regex/matcher_t.c b/unit-tests/regex/matcher_t.c
deleted file mode 100644
index 24975a11c..000000000
--- a/unit-tests/regex/matcher_t.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2010 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 "libdevmapper.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>
-
-
-static int _read_spec(const char *file, char ***regex, int *nregex)
-{
- char buffer[1024], *start, *ptr;
- FILE *fp = fopen(file, "r");
- int asize = 100;
- char **rx = dm_malloc(sizeof(*rx) * asize);
- int nr = 0;
-
- if (!fp)
- return 0;
-
- while (fgets(buffer, sizeof(buffer),fp)) {
-
- /* trim leading whitespace */
- for (ptr = buffer; *ptr && isspace((int) *ptr); ptr++);
-
- if (!*ptr || *ptr == '#')
- continue;
-
- if (*ptr == '\"') {
- ptr++;
- start = ptr;
- while (*ptr && *ptr != '\"') {
- if (*ptr == '\\')
- ptr++;
- ptr++;
- }
-
- if (!*ptr) {
- fprintf(stderr, "Formatting error : "
- "No terminating quote\n");
- return 0;
- }
-
- rx[nr] = dm_malloc((ptr - start) + 1);
- strncpy(rx[nr], start, ptr - start);
- rx[nr][ptr - start] = '\0';
- nr++;
- } else {
- fprintf(stderr, "%s", ptr);
- fprintf(stderr, "Formatting error : \"<regex>\" "
- "<token_name>\n");
- return 0;
- }
- }
-
- *regex = rx;
- *nregex = nr;
- return 1;
-}
-
-static void _free_regex(char **regex, int nregex)
-{
- int i;
- for (i = 0; i < nregex; i++)
- dm_free(regex[i]);
-
- dm_free(regex);
-}
-
-static void _scan_input(struct dm_regex *m, char **regex)
-{
- char buffer[256], *ptr;
- int r;
-
- while (fgets(buffer, sizeof(buffer), stdin)) {
- if ((ptr = strchr(buffer, '\n')))
- *ptr = '\0';
-
- r = dm_regex_match(m, buffer);
-
- if (r >= 0)
- printf("%s : %s\n", buffer, regex[r]);
- }
-}
-
-int main(int argc, char **argv)
-{
- struct dm_pool *mem;
- struct dm_regex *scanner;
- char **regex;
- int nregex;
- int ret = 0;
- int want_finger_print = 0, i;
- const char *pattern_file = NULL;
-
- for (i = 1; i < argc; i++)
- if (!strcmp(argv[i], "--fingerprint"))
- want_finger_print = 1;
-
- else
- pattern_file = argv[i];
-
- if (!pattern_file) {
- fprintf(stderr, "Usage : %s [--fingerprint] <pattern_file>\n", argv[0]);
- exit(1);
- }
-
- dm_log_init_verbose(_LOG_DEBUG);
-
- if (!(mem = dm_pool_create("match_regex", 10 * 1024))) {
- fprintf(stderr, "Couldn't create pool\n");
- ret = 2;
- goto err;
- }
-
- if (!_read_spec(pattern_file, &regex, &nregex)) {
- fprintf(stderr, "Couldn't read the lex specification\n");
- ret = 3;
- goto err;
- }
-
- if (!(scanner = dm_regex_create(mem, (const char **)regex, nregex))) {
- fprintf(stderr, "Couldn't build the lexer\n");
- ret = 4;
- goto err;
- }
-
- if (want_finger_print)
- printf("fingerprint: %x\n", dm_regex_fingerprint(scanner));
- _scan_input(scanner, regex);
- _free_regex(regex, nregex);
-
- err:
- dm_pool_destroy(mem);
-
- return ret;
-}
diff --git a/unit-tests/regex/matcher_t.expected b/unit-tests/regex/matcher_t.expected
deleted file mode 100644
index 0b986b0bf..000000000
--- a/unit-tests/regex/matcher_t.expected
+++ /dev/null
@@ -1,16 +0,0 @@
-fingerprint: 352b6c4f
-/dev/loop/0 : loop/[0-9]+
-/dev/loop/1 : loop/[0-9]+
-/dev/loop/2 : loop/[0-9]+
-/dev/loop/3 : loop/[0-9]+
-/dev/loop/4 : loop/[0-9]+
-/dev/loop/5 : loop/[0-9]+
-/dev/loop/6 : loop/[0-9]+
-/dev/loop/7 : loop/[0-9]+
-/dev/hda1 : hd[a-d][0-5]+
-/dev/hda2 : hd[a-d][0-5]+
-/dev/hda3 : hd[a-d][0-5]+
-/dev/hda4 : hd[a-d][0-5]+
-/dev/hda5 : hd[a-d][0-5]+
-/dev/hdb1 : hd[a-d][0-5]+
-/dev/hdc1 : hd[a-d][0-5]+
diff --git a/unit-tests/regex/matcher_t.expected2 b/unit-tests/regex/matcher_t.expected2
deleted file mode 100644
index 735993769..000000000
--- a/unit-tests/regex/matcher_t.expected2
+++ /dev/null
@@ -1 +0,0 @@
-fingerprint: eed8ceb8
diff --git a/unit-tests/regex/matcher_t.expected3 b/unit-tests/regex/matcher_t.expected3
deleted file mode 100644
index fa561497a..000000000
--- a/unit-tests/regex/matcher_t.expected3
+++ /dev/null
@@ -1,3 +0,0 @@
-foo€bar : €
-fooÂb : fooÂb
-€ : €
diff --git a/unit-tests/regex/nonprint_input b/unit-tests/regex/nonprint_input
deleted file mode 100644
index 92a1807fb..000000000
--- a/unit-tests/regex/nonprint_input
+++ /dev/null
@@ -1,4 +0,0 @@
-foo.bar
-foo€bar
-fooÂb
-€
diff --git a/unit-tests/regex/nonprint_regexes b/unit-tests/regex/nonprint_regexes
deleted file mode 100644
index e164c213c..000000000
--- a/unit-tests/regex/nonprint_regexes
+++ /dev/null
@@ -1,3 +0,0 @@
-"foo€bar"
-"fooÂb"
-"€"
diff --git a/unit-tests/regex/parse_t.c b/unit-tests/regex/parse_t.c
deleted file mode 100644
index d536e5af4..000000000
--- a/unit-tests/regex/parse_t.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2010 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
- */
-
-/* hack - using unexported internal function */
-#define DEBUG
-#include "regex/parse_rx.c"
-
-#include <stdio.h>
-#include <ctype.h>
-
-static void _pretty_print(struct rx_node *rx, int depth)
-{
- int i;
- for (i = 0; i < depth; i++)
- printf(" ");
-
- /* display info about the node */
- switch (rx->type) {
- case CAT:
- printf("Cat");
- break;
-
- case OR:
- printf("Or");
- break;
-
- case STAR:
- printf("Star");
- break;
-
- case PLUS:
- printf("Plus");
- break;
-
- case QUEST:
- printf("Quest");
- break;
-
- case CHARSET:
- printf("Charset : ");
- for (i = 0; i < 256; i++) {
- if (dm_bit(rx->charset, i) && isprint(i))
- printf("%c", (char) i);
- }
- break;
-
- default:
- printf("Unknown type");
- }
- printf("\n");
-
- if (rx->left)
- _pretty_print(rx->left, depth + 1);
-
- if (rx->right)
- _pretty_print(rx->right, depth + 1);
-}
-
-int main(int argc, char **argv)
-{
- struct dm_pool *mem;
- struct rx_node *rx;
- int regex_print = 0;
- int show_nodes = 0;
- int regex_arg = 1;
-
- if (argc == 3 && !strcmp(argv[1], "-r")) {
- regex_print++;
- regex_arg++;
- argc--;
- }
-
- if (argc == 3 && !strcmp(argv[1], "-R")) {
- regex_print++;
- show_nodes++;
- regex_arg++;
- argc--;
- }
-
- if (argc != 2) {
- fprintf(stderr, "Usage : %s [-r] <regex>\n", argv[0]);
- exit(0);
- }
-
- dm_log_init_verbose(_LOG_DEBUG);
-
- if (!(mem = dm_pool_create("parse_regex", 1024))) {
- fprintf(stderr, "Couldn't create pool\n");
- exit(1);
- }
-
- if (!(rx = rx_parse_str(mem, argv[regex_arg]))) {
- dm_pool_destroy(mem);
- fprintf(stderr, "Couldn't parse regex\n");
- exit(1);
- }
-
- if (regex_print)
- _regex_print(rx, 0, show_nodes);
- else
- _pretty_print(rx, 0);
-
- dm_pool_destroy(mem);
-
- return 0;
-}
diff --git a/unit-tests/regex/random_regexes b/unit-tests/regex/random_regexes
deleted file mode 100644
index 7b9362d8b..000000000
--- a/unit-tests/regex/random_regexes
+++ /dev/null
@@ -1,100 +0,0 @@
-"(((a?)(([Ub]*)|z))((([qr]|X)+)([Qn]*)))+"
-"[HZejtuw]*"
-"((B|s)*)|(((([Fv]l)(N+))(([el]|C)(tJ)))?)"
-"((([Ma]?)|(t*))*)|((([cm]E)|(M?))|(([BE][EV])|([Qj][Mh])))"
-"(((([bw]*)|([IO]*))((zK)*))|(((pU)|(i|q))|((z?)|([HL]?))))*"
-"((([Pt]?)|[Tr])?)((Hq)*)"
-"[HOXcfgikosvwxz]"
-"[BCEFGHNPTUWfjlprsy]"
-"((((aD)*)|([Xo]+))+)(([HKn](([Eq]|[JQ])(I*)))*)"
-"([LNWYeghv]|e)*"
-"(((y(L*))*)|((([EP]+)(W+))*))*"
-"U*"
-"((((R+)(W|[Qr]))|([py]+))+)([LM]*)"
-"(([DOjx](D(b?)))|([Ke]*))*"
-"((([ls](c|[FT]))*)([JS]*))*"
-"((l?)|(([Gz]+)|(D*)))*"
-"[ABgjn]"
-"(((q|[dg])?)|([Uk]*))((([Fl]?)|([Ry]+))|(([IR]|c)|(T?)))"
-"((([an]|P)|[Jw])((a*)|(m*)))*"
-"((((R[ht])(h+))?)|(([pz](n?))+))+"
-"(((([Dc]b)([Sp][Ii]))|((k|F)*))|[Uiovz])*"
-"[Res]*"
-"[Zl]|a"
-"^[ANZdf]$"
-"[En]|(((Q+)(U+))([pt]*))"
-"[ADEIMQUWXZhklrsvz]"
-"(((S(y*))*)|(j*))*"
-"n*"
-"[NUau]*"
-"((((Z*)(D|[Nd]))|(([np]|B)+))|(([Xy][Fi])*))+"
-"((([EZ]?)|(d[HR]))*)((([Hg]|q)(P+))*)"
-"q"
-"((m*)|(p|B))|((((x?)|(t+))(([Sb][PX])(O|[HM])))+)"
-"((((A*)(z[RS]))*)|(((z+)(Q*))+))*"
-"(((M*)([Uu]*))+)|[Uk]"
-"[imv]"
-"[GLSchtw](([Yw]((F[Dd])|([Tw]+)))?)"
-"([MOZj]*)(S|[Wknr])"
-"((G|q)*)[BHKN]"
-"((((NW)|([Ao]?))|((l|[UV])+))+)|((i|(z*))*)"
-"((((Z+)|([IR]?))|(L*))|([JKQ]+))+"
-"([Bdin](S*))+"
-"[HLNSTp]*"
-"(((J*)([Bq]|[Yu]))*)|([Kv]*)"
-"(((([BJ]|[Zy])(wI))*)(y*))+"
-"(((hF)+)|(H*))*"
-"((([QU][Pj])([GQ]?))+)|[PWo]"
-"(((([cq][BX])?)|((f[DI])*))*)(([GM]*)[SVYr])"
-"(([Zt]*)|((qx)|(([BV]+)(f?))))*"
-"[ILWYhsx]*"
-"(([Uy]*)|[sv])|([NSc]*)"
-"((c*)|([JUfhy]?))+"
-"(((q*)([So]*))(((g[jq])(j?))+))*"
-"((b+)|(((T+)([fw]T))?))*"
-"((([DS]?)|([Th]|u))(Q*))*"
-"[FKLX]|((([fw](L?))(([gq]*)|(O?)))?)"
-"((([HZ]+)u)*)|[APWijn]"
-"(e*)|(((v?)|((J+)(Hb)))?)"
-"(e|((w+)f))*"
-"[BEHKPQVdelnqy]"
-"((((B|N)(s*))|[Rr])(((g?)|([rv]+))+))+"
-"(((s*)|(K*))([AP]G))*"
-"[CELTp]"
-"(([Fq]?)|([Al]+))*"
-"((((r?)|(y[jx]))|([mp]*))+)|((B(S*))*)"
-"((([Eq]+)|(Y[ds]))|(x|(i|[Ku])))[IJNrvy]"
-"((([NO]*)[Ix])+)([Jenq]+)"
-"(((([HP]*)(j|y))*)[Ylqvy])*"
-"[PTv]+"
-"[AINSZhpx]|([EOYZ]*)"
-"([ABCFQv]*)((([Zx]|h)+)|([ej]*))"
-"((([pr]*)|(([Dq]|p)|(H?)))?)([NRUXmoq]*)"
-"(([er]*)|([mx]*))(((nV)([am]?))+)"
-"[BHPRlpu]"
-"(((([Ah]|[tx])|(e|[uy]))?)((([fl]+)([Vz]|v))*))*"
-"[AGdm]"
-"(((K*)^(O*)$)|(B?))*"
-"((([Ks]|[Ka])*)|([FSTab]?))?"
-"(([kw]+)[ei])(([Hy]*)(([Mc]*)|(G|f)))"
-"((((e*)|(Zf))|(R|[nq]))((([Jz]v)([Rj]+))+))*"
-"(((a?)|(e?))(([Uc]*)(S+)))*"
-"((((E+)([MZ]?))+)|(((s|[Az])|z)*))?"
-"((((i[MO])*)|((LH)*))|(((BA)|([AI]+))|[Ug]))*"
-"[EGHILcho]*"
-"(((Z[vw])?)((z|g)+))(((H|U)([iv]Q))|([qw]?))"
-"(([ehmr]|((L[Uw])*))+)((a+)I)"
-"[EKNSWYagj](((v|[TX])|([Uk]+))*)"
-"(((R[Mo])|(O*))|([Fm]|([qw]*)))((m*)|((S|[Ki])?))"
-"((((kP)|c)?)((([do]+)|([Gi]?))*))*"
-"((^(B|W)$|([Ww]+))([no]*))|((([iv]?)|(M*))|((x|L)?))"
-"[AEGPRSbcfhsy]"
-"[Wbcf]|((([MO]?)|([NT]|m))(([Oo]?)([Wg]*)))"
-"(((YZ)*)[PQVei])*"
-"[GJKYt][AEGWdegmnt]"
-"^[CDEGJKNUVYZagkv]$"
-"([DPWbx]*)|(((q|B)|(P|u))((M[Bq])*))"
-"[FHIJRTVYZdiorsuvz]*"
-"([MWoqvz]*)|^(l*)"
-"(((I|[Rx])*)((X[Mf])([Xa]L)))([Ha]|([HY]*))"
-"(((l|[Sd])*)((([Ix]+)|([XY]?))(Z*)))+"