mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
Merge remote-tracking branch 'sourceware/master' into upstream
This commit is contained in:
commit
28a9fcd94b
44
.gitignore
vendored
44
.gitignore
vendored
@ -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
|
||||
|
23
Makefile.in
23
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),)
|
||||
|
210
aclocal.m4
vendored
210
aclocal.m4
vendored
@ -69,32 +69,63 @@ AC_DEFUN([AX_PYTHON_MODULE],[
|
||||
fi
|
||||
])
|
||||
|
||||
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
|
||||
# serial 1 (pkg-config-0.24)
|
||||
#
|
||||
# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
dnl pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
|
||||
dnl serial 11 (pkg-config-0.29)
|
||||
dnl
|
||||
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
|
||||
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
|
||||
dnl
|
||||
dnl This program is free software; you can redistribute it and/or modify
|
||||
dnl it under the terms of the GNU General Public License as published by
|
||||
dnl the Free Software Foundation; either version 2 of the License, or
|
||||
dnl (at your option) any later version.
|
||||
dnl
|
||||
dnl This program is distributed in the hope that it will be useful, but
|
||||
dnl WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
dnl General Public License for more details.
|
||||
dnl
|
||||
dnl You should have received a copy of the GNU General Public License
|
||||
dnl along with this program; if not, write to the Free Software
|
||||
dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
dnl 02111-1307, USA.
|
||||
dnl
|
||||
dnl As a special exception to the GNU General Public License, if you
|
||||
dnl distribute this file as part of a program that contains a
|
||||
dnl configuration script generated by Autoconf, you may include it under
|
||||
dnl the same distribution terms that you use for the rest of that
|
||||
dnl program.
|
||||
|
||||
# PKG_PROG_PKG_CONFIG([MIN-VERSION])
|
||||
# ----------------------------------
|
||||
dnl PKG_PREREQ(MIN-VERSION)
|
||||
dnl -----------------------
|
||||
dnl Since: 0.29
|
||||
dnl
|
||||
dnl Verify that the version of the pkg-config macros are at least
|
||||
dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's
|
||||
dnl installed version of pkg-config, this checks the developer's version
|
||||
dnl of pkg.m4 when generating configure.
|
||||
dnl
|
||||
dnl To ensure that this macro is defined, also add:
|
||||
dnl m4_ifndef([PKG_PREREQ],
|
||||
dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])])
|
||||
dnl
|
||||
dnl See the "Since" comment for each macro you use to see what version
|
||||
dnl of the macros you require.
|
||||
m4_defun([PKG_PREREQ],
|
||||
[m4_define([PKG_MACROS_VERSION], [0.29])
|
||||
m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
|
||||
[m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
|
||||
])dnl PKG_PREREQ
|
||||
|
||||
dnl PKG_PROG_PKG_CONFIG([MIN-VERSION])
|
||||
dnl ----------------------------------
|
||||
dnl Since: 0.16
|
||||
dnl
|
||||
dnl Search for the pkg-config tool and set the PKG_CONFIG variable to
|
||||
dnl first found in the path. Checks that the version of pkg-config found
|
||||
dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is
|
||||
dnl used since that's the first version where most current features of
|
||||
dnl pkg-config existed.
|
||||
AC_DEFUN([PKG_PROG_PKG_CONFIG],
|
||||
[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
|
||||
m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
|
||||
@ -116,18 +147,19 @@ if test -n "$PKG_CONFIG"; then
|
||||
PKG_CONFIG=""
|
||||
fi
|
||||
fi[]dnl
|
||||
])# PKG_PROG_PKG_CONFIG
|
||||
])dnl PKG_PROG_PKG_CONFIG
|
||||
|
||||
# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||
#
|
||||
# Check to see whether a particular set of modules exists. Similar
|
||||
# to PKG_CHECK_MODULES(), but does not set variables or print errors.
|
||||
#
|
||||
# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
|
||||
# only at the first occurence in configure.ac, so if the first place
|
||||
# it's called might be skipped (such as if it is within an "if", you
|
||||
# have to call PKG_CHECK_EXISTS manually
|
||||
# --------------------------------------------------------------
|
||||
dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||
dnl -------------------------------------------------------------------
|
||||
dnl Since: 0.18
|
||||
dnl
|
||||
dnl Check to see whether a particular set of modules exists. Similar to
|
||||
dnl PKG_CHECK_MODULES(), but does not set variables or print errors.
|
||||
dnl
|
||||
dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
|
||||
dnl only at the first occurence in configure.ac, so if the first place
|
||||
dnl it's called might be skipped (such as if it is within an "if", you
|
||||
dnl have to call PKG_CHECK_EXISTS manually
|
||||
AC_DEFUN([PKG_CHECK_EXISTS],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||||
if test -n "$PKG_CONFIG" && \
|
||||
@ -137,8 +169,10 @@ m4_ifvaln([$3], [else
|
||||
$3])dnl
|
||||
fi])
|
||||
|
||||
# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
|
||||
# ---------------------------------------------
|
||||
dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
|
||||
dnl ---------------------------------------------
|
||||
dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting
|
||||
dnl pkg_failed based on the result.
|
||||
m4_define([_PKG_CONFIG],
|
||||
[if test -n "$$1"; then
|
||||
pkg_cv_[]$1="$$1"
|
||||
@ -150,10 +184,11 @@ m4_define([_PKG_CONFIG],
|
||||
else
|
||||
pkg_failed=untried
|
||||
fi[]dnl
|
||||
])# _PKG_CONFIG
|
||||
])dnl _PKG_CONFIG
|
||||
|
||||
# _PKG_SHORT_ERRORS_SUPPORTED
|
||||
# -----------------------------
|
||||
dnl _PKG_SHORT_ERRORS_SUPPORTED
|
||||
dnl ---------------------------
|
||||
dnl Internal check to see if pkg-config supports short errors.
|
||||
AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
|
||||
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
|
||||
@ -161,19 +196,17 @@ if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
|
||||
else
|
||||
_pkg_short_errors_supported=no
|
||||
fi[]dnl
|
||||
])# _PKG_SHORT_ERRORS_SUPPORTED
|
||||
])dnl _PKG_SHORT_ERRORS_SUPPORTED
|
||||
|
||||
|
||||
# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
|
||||
# [ACTION-IF-NOT-FOUND])
|
||||
#
|
||||
#
|
||||
# Note that if there is a possibility the first call to
|
||||
# PKG_CHECK_MODULES might not happen, you should be sure to include an
|
||||
# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
|
||||
#
|
||||
#
|
||||
# --------------------------------------------------------------
|
||||
dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
|
||||
dnl [ACTION-IF-NOT-FOUND])
|
||||
dnl --------------------------------------------------------------
|
||||
dnl Since: 0.4.0
|
||||
dnl
|
||||
dnl Note that if there is a possibility the first call to
|
||||
dnl PKG_CHECK_MODULES might not happen, you should be sure to include an
|
||||
dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
|
||||
AC_DEFUN([PKG_CHECK_MODULES],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||||
AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
|
||||
@ -227,16 +260,40 @@ else
|
||||
AC_MSG_RESULT([yes])
|
||||
$3
|
||||
fi[]dnl
|
||||
])# PKG_CHECK_MODULES
|
||||
])dnl PKG_CHECK_MODULES
|
||||
|
||||
|
||||
# PKG_INSTALLDIR(DIRECTORY)
|
||||
# -------------------------
|
||||
# Substitutes the variable pkgconfigdir as the location where a module
|
||||
# should install pkg-config .pc files. By default the directory is
|
||||
# $libdir/pkgconfig, but the default can be changed by passing
|
||||
# DIRECTORY. The user can override through the --with-pkgconfigdir
|
||||
# parameter.
|
||||
dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
|
||||
dnl [ACTION-IF-NOT-FOUND])
|
||||
dnl ---------------------------------------------------------------------
|
||||
dnl Since: 0.29
|
||||
dnl
|
||||
dnl Checks for existence of MODULES and gathers its build flags with
|
||||
dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags
|
||||
dnl and VARIABLE-PREFIX_LIBS from --libs.
|
||||
dnl
|
||||
dnl Note that if there is a possibility the first call to
|
||||
dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to
|
||||
dnl include an explicit call to PKG_PROG_PKG_CONFIG in your
|
||||
dnl configure.ac.
|
||||
AC_DEFUN([PKG_CHECK_MODULES_STATIC],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||||
_save_PKG_CONFIG=$PKG_CONFIG
|
||||
PKG_CONFIG="$PKG_CONFIG --static"
|
||||
PKG_CHECK_MODULES($@)
|
||||
PKG_CONFIG=$_save_PKG_CONFIG[]dnl
|
||||
])dnl PKG_CHECK_MODULES_STATIC
|
||||
|
||||
|
||||
dnl PKG_INSTALLDIR([DIRECTORY])
|
||||
dnl -------------------------
|
||||
dnl Since: 0.27
|
||||
dnl
|
||||
dnl Substitutes the variable pkgconfigdir as the location where a module
|
||||
dnl should install pkg-config .pc files. By default the directory is
|
||||
dnl $libdir/pkgconfig, but the default can be changed by passing
|
||||
dnl DIRECTORY. The user can override through the --with-pkgconfigdir
|
||||
dnl parameter.
|
||||
AC_DEFUN([PKG_INSTALLDIR],
|
||||
[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
|
||||
m4_pushdef([pkg_description],
|
||||
@ -247,16 +304,18 @@ AC_ARG_WITH([pkgconfigdir],
|
||||
AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
|
||||
m4_popdef([pkg_default])
|
||||
m4_popdef([pkg_description])
|
||||
]) dnl PKG_INSTALLDIR
|
||||
])dnl PKG_INSTALLDIR
|
||||
|
||||
|
||||
# PKG_NOARCH_INSTALLDIR(DIRECTORY)
|
||||
# -------------------------
|
||||
# Substitutes the variable noarch_pkgconfigdir as the location where a
|
||||
# module should install arch-independent pkg-config .pc files. By
|
||||
# default the directory is $datadir/pkgconfig, but the default can be
|
||||
# changed by passing DIRECTORY. The user can override through the
|
||||
# --with-noarch-pkgconfigdir parameter.
|
||||
dnl PKG_NOARCH_INSTALLDIR([DIRECTORY])
|
||||
dnl --------------------------------
|
||||
dnl Since: 0.27
|
||||
dnl
|
||||
dnl Substitutes the variable noarch_pkgconfigdir as the location where a
|
||||
dnl module should install arch-independent pkg-config .pc files. By
|
||||
dnl default the directory is $datadir/pkgconfig, but the default can be
|
||||
dnl changed by passing DIRECTORY. The user can override through the
|
||||
dnl --with-noarch-pkgconfigdir parameter.
|
||||
AC_DEFUN([PKG_NOARCH_INSTALLDIR],
|
||||
[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
|
||||
m4_pushdef([pkg_description],
|
||||
@ -267,13 +326,15 @@ AC_ARG_WITH([noarch-pkgconfigdir],
|
||||
AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
|
||||
m4_popdef([pkg_default])
|
||||
m4_popdef([pkg_description])
|
||||
]) dnl PKG_NOARCH_INSTALLDIR
|
||||
])dnl PKG_NOARCH_INSTALLDIR
|
||||
|
||||
|
||||
# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
|
||||
# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||
# -------------------------------------------
|
||||
# Retrieves the value of the pkg-config variable for the given module.
|
||||
dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
|
||||
dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||
dnl -------------------------------------------
|
||||
dnl Since: 0.28
|
||||
dnl
|
||||
dnl Retrieves the value of the pkg-config variable for the given module.
|
||||
AC_DEFUN([PKG_CHECK_VAR],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||||
AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
|
||||
@ -282,7 +343,7 @@ _PKG_CONFIG([$1], [variable="][$3]["], [$2])
|
||||
AS_VAR_COPY([$1], [pkg_cv_][$1])
|
||||
|
||||
AS_VAR_IF([$1], [""], [$5], [$4])dnl
|
||||
])# PKG_CHECK_VAR
|
||||
])dnl PKG_CHECK_VAR
|
||||
|
||||
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
|
||||
#
|
||||
@ -536,5 +597,4 @@ AC_DEFUN([AM_RUN_LOG],
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
|
||||
(exit $ac_status); }])
|
||||
|
||||
|
||||
m4_include([acinclude.m4])
|
||||
|
@ -59,22 +59,6 @@ devices {
|
||||
# This configuration option is advanced.
|
||||
scan = [ "/dev" ]
|
||||
|
||||
# Configuration option devices/use_aio.
|
||||
# Use linux asynchronous I/O for parallel device access where possible.
|
||||
# This configuration option has an automatic default value.
|
||||
# use_aio = 1
|
||||
|
||||
# Configuration option devices/aio_max.
|
||||
# Maximum number of asynchronous I/Os to issue concurrently.
|
||||
# This configuration option has an automatic default value.
|
||||
# aio_max = 128
|
||||
|
||||
# Configuration option devices/aio_memory.
|
||||
# Approximate maximum total amount of memory (in MB) used
|
||||
# for asynchronous I/O buffers.
|
||||
# This configuration option has an automatic default value.
|
||||
# aio_memory = 10
|
||||
|
||||
# Configuration option devices/obtain_device_list_from_udev.
|
||||
# Obtain the list of available devices from udev.
|
||||
# This avoids opening or using any inapplicable non-block devices or
|
||||
|
23
configure
vendored
23
configure
vendored
@ -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
|
||||
|
25
configure.in
25
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
|
||||
@ -1124,24 +1122,6 @@ if test "$DEVMAPPER" = yes; then
|
||||
AC_DEFINE([DEVMAPPER_SUPPORT], 1, [Define to 1 to enable LVM2 device-mapper interaction.])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Disable aio
|
||||
AC_MSG_CHECKING(whether to use asynchronous I/O)
|
||||
AC_ARG_ENABLE(aio,
|
||||
AC_HELP_STRING([--disable-aio],
|
||||
[disable asynchronous I/O]),
|
||||
AIO=$enableval)
|
||||
AC_MSG_RESULT($AIO)
|
||||
|
||||
if test "$AIO" = yes; then
|
||||
AC_CHECK_LIB(aio, io_setup,
|
||||
[AC_DEFINE([AIO_SUPPORT], 1, [Define to 1 if aio is available.])
|
||||
AIO_LIBS="-laio"
|
||||
AIO_SUPPORT=yes],
|
||||
[AIO_LIBS=
|
||||
AIO_SUPPORT=no ])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Build lvmetad
|
||||
AC_MSG_CHECKING(whether to build LVMetaD)
|
||||
@ -2081,11 +2061,9 @@ AC_SUBST(DEFAULT_USE_LVMETAD)
|
||||
AC_SUBST(DEFAULT_USE_LVMPOLLD)
|
||||
AC_SUBST(DEFAULT_USE_LVMLOCKD)
|
||||
AC_SUBST(DEVMAPPER)
|
||||
AC_SUBST(AIO)
|
||||
AC_SUBST(DLM_CFLAGS)
|
||||
AC_SUBST(DLM_LIBS)
|
||||
AC_SUBST(DL_LIBS)
|
||||
AC_SUBST(AIO_LIBS)
|
||||
AC_SUBST(DMEVENTD_PATH)
|
||||
AC_SUBST(DM_LIB_PATCHLEVEL)
|
||||
AC_SUBST(ELDFLAGS)
|
||||
@ -2276,9 +2254,6 @@ test/api/Makefile
|
||||
test/unit/Makefile
|
||||
tools/Makefile
|
||||
udev/Makefile
|
||||
unit-tests/datastruct/Makefile
|
||||
unit-tests/regex/Makefile
|
||||
unit-tests/mm/Makefile
|
||||
])
|
||||
AC_OUTPUT
|
||||
|
||||
|
@ -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 = \
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 \
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "config.h"
|
||||
#include "segtype.h"
|
||||
#include "sharedlib.h"
|
||||
#include "lvmcache.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <fcntl.h>
|
||||
@ -2172,6 +2173,17 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
|
||||
if (!lv_info(cmd, lv, laopts->origin_only, &info, 0, 0))
|
||||
goto_out;
|
||||
|
||||
/*
|
||||
* Save old and new (current and precommitted) versions of the
|
||||
* VG metadata for lv_resume() to use, since lv_resume can't
|
||||
* read metadata given that devices are suspended. lv_resume()
|
||||
* will resume LVs using the old/current metadata if the vg_commit
|
||||
* did happen (or failed), and it will resume LVs using the
|
||||
* new/precommitted metadata if the vg_commit succeeded.
|
||||
*/
|
||||
lvmcache_save_suspended_vg(lv->vg, 0);
|
||||
lvmcache_save_suspended_vg(lv_pre->vg, 1);
|
||||
|
||||
if (!info.exists || info.suspended) {
|
||||
if (!error_if_not_suspended) {
|
||||
r = 1;
|
||||
@ -2378,16 +2390,55 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
|
||||
struct lv_activate_opts *laopts, int error_if_not_active,
|
||||
const struct logical_volume *lv)
|
||||
{
|
||||
const struct logical_volume *lv_to_free = NULL;
|
||||
struct dm_list *snh;
|
||||
struct volume_group *vg = NULL;
|
||||
struct logical_volume *lv_found = NULL;
|
||||
const union lvid *lvid;
|
||||
const char *vgid;
|
||||
struct lvinfo info;
|
||||
int r = 0;
|
||||
|
||||
if (!activation())
|
||||
return 1;
|
||||
|
||||
if (!lv && !(lv_to_free = lv = lv_from_lvid(cmd, lvid_s, 0)))
|
||||
goto_out;
|
||||
/*
|
||||
* When called in clvmd, lvid_s is set and lv is not. We need to
|
||||
* get the VG metadata without reading disks because devs are
|
||||
* suspended. lv_suspend() saved old and new VG metadata for us
|
||||
* to use here. If vg_commit() happened, lvmcache_get_suspended_vg
|
||||
* will return the new metadata for us to use in resuming LVs.
|
||||
* If vg_commit() did not happen, lvmcache_get_suspended_vg
|
||||
* returns the old metadata which we use to resume LVs.
|
||||
*/
|
||||
if (!lv && lvid_s) {
|
||||
lvid = (const union lvid *) lvid_s;
|
||||
vgid = (const char *)lvid->id[0].uuid;
|
||||
|
||||
if ((vg = lvmcache_get_suspended_vg(vgid))) {
|
||||
log_debug_activation("Resuming LVID %s found saved vg seqno %d %s", lvid_s, vg->seqno, vg->name);
|
||||
if ((lv_found = find_lv_in_vg_by_lvid(vg, lvid))) {
|
||||
log_debug_activation("Resuming LVID %s found saved LV %s", lvid_s, display_lvname(lv_found));
|
||||
lv = lv_found;
|
||||
} else
|
||||
log_debug_activation("Resuming LVID %s did not find saved LV", lvid_s);
|
||||
} else
|
||||
log_debug_activation("Resuming LVID %s did not find saved VG", lvid_s);
|
||||
|
||||
/*
|
||||
* resume must have been called without a preceding suspend,
|
||||
* so we need to read the vg.
|
||||
*/
|
||||
|
||||
if (!lv) {
|
||||
log_debug_activation("Resuming LVID %s reading VG", lvid_s);
|
||||
if (!(lv_found = lv_from_lvid(cmd, lvid_s, 0))) {
|
||||
log_debug_activation("Resuming LVID %s failed to read VG", lvid_s);
|
||||
goto out;
|
||||
}
|
||||
|
||||
lv = lv_found;
|
||||
}
|
||||
}
|
||||
|
||||
if (!lv_is_origin(lv) && !lv_is_thin_volume(lv) && !lv_is_thin_pool(lv))
|
||||
laopts->origin_only = 0;
|
||||
@ -2448,9 +2499,6 @@ needs_resume:
|
||||
|
||||
r = 1;
|
||||
out:
|
||||
if (lv_to_free)
|
||||
release_vg(lv_to_free->vg);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -2587,6 +2635,10 @@ int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s,
|
||||
int *activate_lv, const struct logical_volume *lv)
|
||||
{
|
||||
const struct logical_volume *lv_to_free = NULL;
|
||||
struct volume_group *vg = NULL;
|
||||
struct logical_volume *lv_found = NULL;
|
||||
const union lvid *lvid;
|
||||
const char *vgid;
|
||||
int r = 0;
|
||||
|
||||
if (!activation()) {
|
||||
@ -2594,6 +2646,24 @@ int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called while devices are suspended,
|
||||
* so try to use the copy of the vg that was saved in
|
||||
* lv_suspend.
|
||||
*/
|
||||
if (!lv && lvid_s) {
|
||||
lvid = (const union lvid *) lvid_s;
|
||||
vgid = (const char *)lvid->id[0].uuid;
|
||||
|
||||
if ((vg = lvmcache_get_suspended_vg(vgid))) {
|
||||
log_debug_activation("activation_filter for %s found saved VG seqno %d %s", lvid_s, vg->seqno, vg->name);
|
||||
if ((lv_found = find_lv_in_vg_by_lvid(vg, lvid))) {
|
||||
log_debug_activation("activation_filter for %s found saved LV %s", lvid_s, display_lvname(lv_found));
|
||||
lv = lv_found;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!lv && !(lv_to_free = lv = lv_from_lvid(cmd, lvid_s, 0)))
|
||||
goto_out;
|
||||
|
||||
|
1096
lib/cache/lvmcache.c
vendored
1096
lib/cache/lvmcache.c
vendored
File diff suppressed because it is too large
Load Diff
40
lib/cache/lvmcache.h
vendored
40
lib/cache/lvmcache.h
vendored
@ -59,6 +59,8 @@ struct lvmcache_vgsummary {
|
||||
const char *lock_type;
|
||||
uint32_t mda_checksum;
|
||||
size_t mda_size;
|
||||
int zero_offset;
|
||||
int seqno;
|
||||
};
|
||||
|
||||
int lvmcache_init(void);
|
||||
@ -66,14 +68,8 @@ void lvmcache_allow_reads_with_lvmetad(void);
|
||||
|
||||
void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans, int reset);
|
||||
|
||||
/*
|
||||
* lvmcache_label_scan() will scan labels the first time it's
|
||||
* called, but not on subsequent calls, unless
|
||||
* lvmcache_force_next_label_scan() is called first
|
||||
* to force the next lvmcache_label_scan() to scan again.
|
||||
*/
|
||||
void lvmcache_force_next_label_scan(void);
|
||||
int lvmcache_label_scan(struct cmd_context *cmd);
|
||||
int lvmcache_label_rescan_vg(struct cmd_context *cmd, const char *vgname, const char *vgid);
|
||||
|
||||
/* Add/delete a device */
|
||||
struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
||||
@ -82,10 +78,11 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
||||
uint32_t vgstatus);
|
||||
int lvmcache_add_orphan_vginfo(const char *vgname, struct format_type *fmt);
|
||||
void lvmcache_del(struct lvmcache_info *info);
|
||||
void lvmcache_del_dev(struct device *dev);
|
||||
|
||||
/* Update things */
|
||||
int lvmcache_update_vgname_and_id(struct lvmcache_info *info,
|
||||
const struct lvmcache_vgsummary *vgsummary);
|
||||
struct lvmcache_vgsummary *vgsummary);
|
||||
int lvmcache_update_vg(struct volume_group *vg, unsigned precommitted);
|
||||
|
||||
void lvmcache_lock_vgname(const char *vgname, int read_only);
|
||||
@ -105,10 +102,8 @@ struct lvmcache_vginfo *lvmcache_vginfo_from_vgid(const char *vgid);
|
||||
struct lvmcache_info *lvmcache_info_from_pvid(const char *pvid, struct device *dev, int valid_only);
|
||||
const char *lvmcache_vgname_from_vgid(struct dm_pool *mem, const char *vgid);
|
||||
const char *lvmcache_vgid_from_vgname(struct cmd_context *cmd, const char *vgname);
|
||||
struct device *lvmcache_device_from_pvid(struct cmd_context *cmd, const struct id *pvid,
|
||||
unsigned *scan_done_once, uint64_t *label_sector);
|
||||
const char *lvmcache_pvid_from_devname(struct cmd_context *cmd,
|
||||
const char *devname);
|
||||
struct device *lvmcache_device_from_pvid(struct cmd_context *cmd, const struct id *pvid, uint64_t *label_sector);
|
||||
const char *lvmcache_pvid_from_devname(struct cmd_context *cmd, const char *devname);
|
||||
char *lvmcache_vgname_from_pvid(struct cmd_context *cmd, const char *pvid);
|
||||
const char *lvmcache_vgname_from_info(struct lvmcache_info *info);
|
||||
const struct format_type *lvmcache_fmt_from_info(struct lvmcache_info *info);
|
||||
@ -134,9 +129,6 @@ int lvmcache_get_vgnameids(struct cmd_context *cmd, int include_internal,
|
||||
struct dm_list *lvmcache_get_pvids(struct cmd_context *cmd, const char *vgname,
|
||||
const char *vgid);
|
||||
|
||||
/* Returns cached volume group metadata. */
|
||||
struct volume_group *lvmcache_get_vg(struct cmd_context *cmd, const char *vgname,
|
||||
const char *vgid, unsigned precommitted);
|
||||
void lvmcache_drop_metadata(const char *vgname, int drop_precommitted);
|
||||
void lvmcache_commit_metadata(const char *vgname);
|
||||
|
||||
@ -146,8 +138,8 @@ int lvmcache_fid_add_mdas(struct lvmcache_info *info, struct format_instance *fi
|
||||
int lvmcache_fid_add_mdas_pv(struct lvmcache_info *info, struct format_instance *fid);
|
||||
int lvmcache_fid_add_mdas_vg(struct lvmcache_vginfo *vginfo, struct format_instance *fid);
|
||||
int lvmcache_populate_pv_fields(struct lvmcache_info *info,
|
||||
struct physical_volume *pv,
|
||||
int scan_label_only);
|
||||
struct volume_group *vg,
|
||||
struct physical_volume *pv);
|
||||
int lvmcache_check_format(struct lvmcache_info *info, const struct format_type *fmt);
|
||||
void lvmcache_del_mdas(struct lvmcache_info *info);
|
||||
void lvmcache_del_das(struct lvmcache_info *info);
|
||||
@ -164,6 +156,8 @@ uint32_t lvmcache_ext_flags(struct lvmcache_info *info);
|
||||
|
||||
const struct format_type *lvmcache_fmt(struct lvmcache_info *info);
|
||||
struct label *lvmcache_get_label(struct lvmcache_info *info);
|
||||
struct label *lvmcache_get_dev_label(struct device *dev);
|
||||
int lvmcache_has_dev_info(struct device *dev);
|
||||
|
||||
void lvmcache_update_pv(struct lvmcache_info *info, struct physical_volume *pv,
|
||||
const struct format_type *fmt);
|
||||
@ -187,7 +181,6 @@ int lvmcache_foreach_pv(struct lvmcache_vginfo *vginfo,
|
||||
uint64_t lvmcache_device_size(struct lvmcache_info *info);
|
||||
void lvmcache_set_device_size(struct lvmcache_info *info, uint64_t size);
|
||||
struct device *lvmcache_device(struct lvmcache_info *info);
|
||||
void lvmcache_make_valid(struct lvmcache_info *info);
|
||||
int lvmcache_is_orphan(struct lvmcache_info *info);
|
||||
int lvmcache_uncertain_ownership(struct lvmcache_info *info);
|
||||
unsigned lvmcache_mda_count(struct lvmcache_info *info);
|
||||
@ -215,4 +208,15 @@ void lvmcache_remove_unchosen_duplicate(struct device *dev);
|
||||
|
||||
int lvmcache_pvid_in_unchosen_duplicates(const char *pvid);
|
||||
|
||||
int lvmcache_get_vg_devs(struct cmd_context *cmd,
|
||||
struct lvmcache_vginfo *vginfo,
|
||||
struct dm_list *devs);
|
||||
void lvmcache_set_independent_location(const char *vgname);
|
||||
|
||||
void lvmcache_save_suspended_vg(struct volume_group *vg, int precommitted);
|
||||
struct volume_group *lvmcache_get_suspended_vg(const char *vgid);
|
||||
void lvmcache_drop_suspended_vg(struct volume_group *vg);
|
||||
|
||||
int lvmcache_scan_mismatch(struct cmd_context *cmd, const char *vgname, const char *vgid);
|
||||
|
||||
#endif
|
||||
|
487
lib/cache/lvmetad.c
vendored
487
lib/cache/lvmetad.c
vendored
@ -39,7 +39,7 @@ static int64_t _lvmetad_update_timeout;
|
||||
|
||||
static int _found_lvm1_metadata = 0;
|
||||
|
||||
static struct volume_group *_lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg);
|
||||
static struct volume_group *_lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg, const char *vgid, struct format_type *fmt);
|
||||
|
||||
static uint64_t _monotonic_seconds(void)
|
||||
{
|
||||
@ -1093,14 +1093,17 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgna
|
||||
* invalidated the cached vg.
|
||||
*/
|
||||
if (rescan) {
|
||||
if (!(vg2 = _lvmetad_pvscan_vg(cmd, vg))) {
|
||||
if (!(vg2 = _lvmetad_pvscan_vg(cmd, vg, vgid, fmt))) {
|
||||
log_debug_lvmetad("VG %s from lvmetad not found during rescan.", vgname);
|
||||
fid = NULL;
|
||||
release_vg(vg);
|
||||
vg = NULL;
|
||||
goto out;
|
||||
}
|
||||
fid->ref_count++;
|
||||
release_vg(vg);
|
||||
fid->ref_count--;
|
||||
fmt->ops->destroy_instance(fid);
|
||||
vg = vg2;
|
||||
fid = vg2->fid;
|
||||
}
|
||||
@ -1108,14 +1111,14 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgna
|
||||
dm_list_iterate_items(pvl, &vg->pvs) {
|
||||
if (!_pv_update_struct_pv(pvl->pv, fid)) {
|
||||
vg = NULL;
|
||||
goto_out; /* FIXME error path */
|
||||
goto_out; /* FIXME: use an error path that disables lvmetad */
|
||||
}
|
||||
}
|
||||
|
||||
dm_list_iterate_items(pvl, &vg->pvs_outdated) {
|
||||
if (!_pv_update_struct_pv(pvl->pv, fid)) {
|
||||
vg = NULL;
|
||||
goto_out; /* FIXME error path */
|
||||
goto_out; /* FIXME: use an error path that disables lvmetad */
|
||||
}
|
||||
}
|
||||
|
||||
@ -1761,6 +1764,7 @@ int lvmetad_pv_gone_by_dev(struct device *dev)
|
||||
*/
|
||||
|
||||
struct _lvmetad_pvscan_baton {
|
||||
struct cmd_context *cmd;
|
||||
struct volume_group *vg;
|
||||
struct format_instance *fid;
|
||||
};
|
||||
@ -1771,7 +1775,7 @@ static int _lvmetad_pvscan_single(struct metadata_area *mda, void *baton)
|
||||
struct volume_group *vg;
|
||||
|
||||
if (mda_is_ignored(mda) ||
|
||||
!(vg = mda->ops->vg_read(b->fid, "", mda, NULL, NULL, 1, 0)))
|
||||
!(vg = mda->ops->vg_read(b->fid, "", mda, NULL, NULL)))
|
||||
return 1;
|
||||
|
||||
/* FIXME Also ensure contents match etc. */
|
||||
@ -1783,6 +1787,33 @@ static int _lvmetad_pvscan_single(struct metadata_area *mda, void *baton)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: handle errors and do proper comparison of metadata from each area
|
||||
* like vg_read and fall back to real vg_read from disk if there's any problem.
|
||||
*/
|
||||
|
||||
static int _lvmetad_pvscan_vg_single(struct metadata_area *mda, void *baton)
|
||||
{
|
||||
struct _lvmetad_pvscan_baton *b = baton;
|
||||
struct volume_group *vg = NULL;
|
||||
|
||||
if (mda_is_ignored(mda))
|
||||
return 1;
|
||||
|
||||
if (!(vg = mda->ops->vg_read(b->fid, "", mda, NULL, NULL)))
|
||||
return 1;
|
||||
|
||||
if (!b->vg)
|
||||
b->vg = vg;
|
||||
else if (vg->seqno > b->vg->seqno) {
|
||||
release_vg(b->vg);
|
||||
b->vg = vg;
|
||||
} else
|
||||
release_vg(vg);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The lock manager may detect that the vg cached in lvmetad is out of date,
|
||||
* due to something like an lvcreate from another host.
|
||||
@ -1792,41 +1823,41 @@ static int _lvmetad_pvscan_single(struct metadata_area *mda, void *baton)
|
||||
* the VG, and that PV may have been reused for another VG.
|
||||
*/
|
||||
|
||||
static struct volume_group *_lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg)
|
||||
static struct volume_group *_lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
const char *vgid, struct format_type *fmt)
|
||||
{
|
||||
char pvid_s[ID_LEN + 1] __attribute__((aligned(8)));
|
||||
char uuid[64] __attribute__((aligned(8)));
|
||||
struct label *label;
|
||||
struct volume_group *vg_ret = NULL;
|
||||
struct dm_config_tree *vgmeta_ret = NULL;
|
||||
struct dm_config_tree *vgmeta;
|
||||
struct pv_list *pvl, *pvl_new;
|
||||
struct device_list *devl, *devl_new, *devlsafe;
|
||||
struct device_list *devl, *devlsafe;
|
||||
struct dm_list pvs_scan;
|
||||
struct dm_list pvs_drop;
|
||||
struct dm_list pvs_new;
|
||||
struct lvmcache_vginfo *vginfo = NULL;
|
||||
struct lvmcache_info *info = NULL;
|
||||
struct format_instance *fid;
|
||||
struct format_instance_ctx fic = { .type = 0 };
|
||||
struct _lvmetad_pvscan_baton baton;
|
||||
struct volume_group *save_vg;
|
||||
struct dm_config_tree *save_meta;
|
||||
struct device *save_dev = NULL;
|
||||
uint32_t save_seqno = 0;
|
||||
int missing_devs = 0;
|
||||
int check_new_pvs = 0;
|
||||
int found_new_pvs = 0;
|
||||
int retried_reads = 0;
|
||||
int found;
|
||||
|
||||
save_vg = NULL;
|
||||
save_meta = NULL;
|
||||
save_dev = NULL;
|
||||
save_seqno = 0;
|
||||
|
||||
dm_list_init(&pvs_scan);
|
||||
dm_list_init(&pvs_drop);
|
||||
dm_list_init(&pvs_new);
|
||||
|
||||
log_debug_lvmetad("Rescanning VG %s (seqno %u).", vg->name, vg->seqno);
|
||||
log_debug_lvmetad("Rescan VG %s to update lvmetad (seqno %u).", vg->name, vg->seqno);
|
||||
|
||||
/*
|
||||
* Another host may have added a PV to the VG, and some
|
||||
* commands do not always populate their lvmcache with
|
||||
* all devs from lvmetad, so they would fail to find
|
||||
* the new PV when scanning the VG. So make sure this
|
||||
* command knows about all PVs from lvmetad.
|
||||
* Make sure this command knows about all PVs from lvmetad.
|
||||
*/
|
||||
lvmcache_seed_infos_from_lvmetad(cmd);
|
||||
|
||||
@ -1841,54 +1872,111 @@ static struct volume_group *_lvmetad_pvscan_vg(struct cmd_context *cmd, struct v
|
||||
dm_list_add(&pvs_scan, &devl->list);
|
||||
}
|
||||
|
||||
scan_more:
|
||||
/*
|
||||
* Rescan labels/metadata only from devs that we previously
|
||||
* saw in the VG. If we find below that there are new PVs
|
||||
* in the VG, we'll have to rescan all devices to find which
|
||||
* device(s) are now being used.
|
||||
*/
|
||||
log_debug_lvmetad("Rescan VG %s scanning data from devs in previous metadata.", vg->name);
|
||||
|
||||
label_scan_devs(cmd, &pvs_scan);
|
||||
|
||||
/*
|
||||
* Run the equivalent of lvmetad_pvscan_single on each dev in the VG.
|
||||
* Check if any pvs_scan entries are no longer PVs.
|
||||
* In that case, label_read/_find_label_header will have
|
||||
* found no label_header, and would have dropped the
|
||||
* info struct for the device from lvmcache. So, if
|
||||
* we look up the info struct here and don't find it,
|
||||
* we can infer it's no longer a PV.
|
||||
*
|
||||
* FIXME: we should record specific results from the
|
||||
* label_read and then check specifically for whatever
|
||||
* result means "no label was found", rather than going
|
||||
* about this indirectly via the lvmcache side effects.
|
||||
*/
|
||||
dm_list_iterate_items_safe(devl, devlsafe, &pvs_scan) {
|
||||
if (!(info = lvmcache_info_from_pvid(devl->dev->pvid, devl->dev, 0))) {
|
||||
/* Another host removed this PV from the VG. */
|
||||
log_debug_lvmetad("Rescan VG %s from %s dropping dev (no label).",
|
||||
vg->name, dev_name(devl->dev));
|
||||
dm_list_move(&pvs_drop, &devl->list);
|
||||
}
|
||||
}
|
||||
|
||||
fic.type = FMT_INSTANCE_MDAS | FMT_INSTANCE_AUX_MDAS;
|
||||
fic.context.vg_ref.vg_name = vg->name;
|
||||
fic.context.vg_ref.vg_id = vgid;
|
||||
|
||||
retry_reads:
|
||||
|
||||
if (!(fid = fmt->ops->create_instance(fmt, &fic))) {
|
||||
/* FIXME: are there only internal reasons for failures here? */
|
||||
log_error("Reading VG %s failed to create format instance.", vg->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* FIXME: not sure if this is necessary */
|
||||
fid->ref_count++;
|
||||
|
||||
baton.fid = fid;
|
||||
baton.cmd = cmd;
|
||||
|
||||
/*
|
||||
* FIXME: this vg_read path does not have the ability to repair
|
||||
* any problems with the VG, e.g. VG on one dev has an older
|
||||
* seqno. When vg_read() is reworked, we need to fall back
|
||||
* to using that from here (and vg_read's from lvmetad) when
|
||||
* there is a problem. Perhaps by disabling lvmetad when a
|
||||
* VG problem is detected, causing commands to fully fall
|
||||
* back to disk, which will repair the VG. Then lvmetad can
|
||||
* be repopulated and re-enabled (possibly automatically.)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Do a low level vg_read on each dev, verify the vg returned
|
||||
* from metadata on each device is for the VG being read
|
||||
* (the PV may have been removed from the VG being read and
|
||||
* added to a different one), and return this vg to the caller
|
||||
* as the current vg to use.
|
||||
*
|
||||
* The label scan above will have saved in lvmcache which
|
||||
* vg each device is used in, so we could figure that part
|
||||
* out without doing the vg_read.
|
||||
*/
|
||||
dm_list_iterate_items_safe(devl, devlsafe, &pvs_scan) {
|
||||
if (!devl->dev)
|
||||
continue;
|
||||
|
||||
log_debug_lvmetad("Rescan VG %s scanning %s.", vg->name, dev_name(devl->dev));
|
||||
|
||||
if (!label_read(devl->dev, &label, 0)) {
|
||||
/* Another host removed this PV from the VG. */
|
||||
log_debug_lvmetad("Rescan VG %s found %s was removed.", vg->name, dev_name(devl->dev));
|
||||
|
||||
if ((info = lvmcache_info_from_pvid(devl->dev->pvid, NULL, 0)))
|
||||
lvmcache_del(info);
|
||||
log_debug_lvmetad("Rescan VG %s getting metadata from %s.",
|
||||
vg->name, dev_name(devl->dev));
|
||||
|
||||
/*
|
||||
* The info struct for this dev knows what and where
|
||||
* the mdas are for this dev (the label scan saved
|
||||
* the mda locations for this dev on the lvmcache info struct).
|
||||
*/
|
||||
if (!(info = lvmcache_info_from_pvid(devl->dev->pvid, devl->dev, 0))) {
|
||||
log_debug_lvmetad("Rescan VG %s from %s dropping dev (no info).",
|
||||
vg->name, dev_name(devl->dev));
|
||||
dm_list_move(&pvs_drop, &devl->list);
|
||||
continue;
|
||||
}
|
||||
|
||||
info = (struct lvmcache_info *) label->info;
|
||||
|
||||
baton.vg = NULL;
|
||||
baton.fid = lvmcache_fmt(info)->ops->create_instance(lvmcache_fmt(info), &fic);
|
||||
if (!baton.fid)
|
||||
return_NULL;
|
||||
|
||||
if (baton.fid->fmt->features & FMT_OBSOLETE) {
|
||||
log_debug_lvmetad("Ignoring obsolete format on PV %s in VG %s.", dev_name(devl->dev), vg->name);
|
||||
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
|
||||
dm_list_move(&pvs_drop, &devl->list);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read VG metadata from this dev's mdas.
|
||||
*/
|
||||
lvmcache_foreach_mda(info, _lvmetad_pvscan_single, &baton);
|
||||
lvmcache_foreach_mda(info, _lvmetad_pvscan_vg_single, &baton);
|
||||
|
||||
/*
|
||||
* The PV may have been removed from the VG by another host
|
||||
* since we last read the VG.
|
||||
*/
|
||||
if (!baton.vg) {
|
||||
log_debug_lvmetad("Rescan VG %s did not find %s.", vg->name, dev_name(devl->dev));
|
||||
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
|
||||
log_debug_lvmetad("Rescan VG %s from %s dropping dev (no metadata).",
|
||||
vg->name, dev_name(devl->dev));
|
||||
dm_list_move(&pvs_drop, &devl->list);
|
||||
continue;
|
||||
}
|
||||
@ -1898,10 +1986,15 @@ scan_more:
|
||||
* different VG since we last read the VG.
|
||||
*/
|
||||
if (strcmp(baton.vg->name, vg->name)) {
|
||||
log_debug_lvmetad("Rescan VG %s found different VG %s on PV %s.",
|
||||
vg->name, baton.vg->name, dev_name(devl->dev));
|
||||
log_debug_lvmetad("Rescan VG %s from %s dropping dev (other VG %s).",
|
||||
vg->name, dev_name(devl->dev), baton.vg->name);
|
||||
release_vg(baton.vg);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(vgmeta = export_vg_to_config_tree(baton.vg))) {
|
||||
log_error("VG export to config tree failed");
|
||||
release_vg(baton.vg);
|
||||
dm_list_move(&pvs_drop, &devl->list);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1911,20 +2004,35 @@ scan_more:
|
||||
* read from each other dev.
|
||||
*/
|
||||
|
||||
if (!save_seqno)
|
||||
save_seqno = baton.vg->seqno;
|
||||
if (save_vg && (save_seqno != baton.vg->seqno)) {
|
||||
/* FIXME: fall back to vg_read to correct this. */
|
||||
log_warn("WARNING: inconsistent metadata for VG %s on devices %s seqno %u and %s seqno %u.",
|
||||
vg->name, dev_name(save_dev), save_seqno,
|
||||
dev_name(devl->dev), baton.vg->seqno);
|
||||
log_warn("WARNING: temporarily disable lvmetad to repair metadata.");
|
||||
|
||||
if (!(vgmeta = export_vg_to_config_tree(baton.vg))) {
|
||||
log_error("VG export to config tree failed");
|
||||
release_vg(baton.vg);
|
||||
return NULL;
|
||||
/* Use the most recent */
|
||||
if (save_seqno < baton.vg->seqno) {
|
||||
release_vg(save_vg);
|
||||
dm_config_destroy(save_meta);
|
||||
save_vg = baton.vg;
|
||||
save_meta = vgmeta;
|
||||
save_seqno = baton.vg->seqno;
|
||||
save_dev = devl->dev;
|
||||
} else {
|
||||
release_vg(baton.vg);
|
||||
dm_config_destroy(vgmeta);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!vgmeta_ret) {
|
||||
vgmeta_ret = vgmeta;
|
||||
if (!save_vg) {
|
||||
save_vg = baton.vg;
|
||||
save_meta = vgmeta;
|
||||
save_seqno = baton.vg->seqno;
|
||||
save_dev = devl->dev;
|
||||
} else {
|
||||
struct dm_config_node *meta1 = vgmeta_ret->root;
|
||||
struct dm_config_node *meta1 = save_meta->root;
|
||||
struct dm_config_node *meta2 = vgmeta->root;
|
||||
struct dm_config_node *sib1 = meta1->sib;
|
||||
struct dm_config_node *sib2 = meta2->sib;
|
||||
@ -1949,73 +2057,128 @@ scan_more:
|
||||
meta2->sib = NULL;
|
||||
|
||||
if (compare_config(meta1, meta2)) {
|
||||
/* FIXME: fall back to vg_read to correct this. */
|
||||
log_warn("WARNING: inconsistent metadata for VG %s on devices %s seqno %u and %s seqno %u.",
|
||||
vg->name, dev_name(save_dev), save_seqno,
|
||||
dev_name(devl->dev), baton.vg->seqno);
|
||||
log_warn("WARNING: temporarily disable lvmetad to repair metadata.");
|
||||
log_error("VG %s metadata comparison failed for device %s vs %s",
|
||||
vg->name, dev_name(devl->dev), save_dev ? dev_name(save_dev) : "none");
|
||||
_log_debug_inequality(vg->name, vgmeta_ret->root, vgmeta->root);
|
||||
_log_debug_inequality(vg->name, save_meta->root, vgmeta->root);
|
||||
|
||||
meta1->sib = sib1;
|
||||
meta2->sib = sib2;
|
||||
dm_config_destroy(vgmeta);
|
||||
dm_config_destroy(vgmeta_ret);
|
||||
|
||||
/* no right choice, just use the previous copy */
|
||||
release_vg(baton.vg);
|
||||
return NULL;
|
||||
dm_config_destroy(vgmeta);
|
||||
}
|
||||
meta1->sib = sib1;
|
||||
meta2->sib = sib2;
|
||||
release_vg(baton.vg);
|
||||
dm_config_destroy(vgmeta);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Look for any new PVs in the VG metadata that were not in our
|
||||
* previous version of the VG. Add them to pvs_new to be
|
||||
* scanned in this loop just like the old PVs.
|
||||
*/
|
||||
if (!check_new_pvs) {
|
||||
check_new_pvs = 1;
|
||||
dm_list_iterate_items(pvl_new, &baton.vg->pvs) {
|
||||
found = 0;
|
||||
dm_list_iterate_items(pvl, &vg->pvs) {
|
||||
if (pvl_new->pv->dev != pvl->pv->dev)
|
||||
continue;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
if (found)
|
||||
/* FIXME: see above */
|
||||
fid->ref_count--;
|
||||
|
||||
/*
|
||||
* Look for any new PVs in the VG metadata that were not in our
|
||||
* previous version of the VG.
|
||||
*
|
||||
* (Don't look for new PVs after a rescan and retry.)
|
||||
*/
|
||||
found_new_pvs = 0;
|
||||
|
||||
if (save_vg && !retried_reads) {
|
||||
dm_list_iterate_items(pvl_new, &save_vg->pvs) {
|
||||
found = 0;
|
||||
dm_list_iterate_items(pvl, &vg->pvs) {
|
||||
if (pvl_new->pv->dev != pvl->pv->dev)
|
||||
continue;
|
||||
if (!pvl_new->pv->dev) {
|
||||
strncpy(pvid_s, (char *) &pvl_new->pv->id, sizeof(pvid_s) - 1);
|
||||
if (!id_write_format((const struct id *)&pvid_s, uuid, sizeof(uuid)))
|
||||
stack;
|
||||
log_error("Device not found for PV %s in VG %s", uuid, vg->name);
|
||||
missing_devs++;
|
||||
continue;
|
||||
}
|
||||
if (!(devl_new = dm_pool_zalloc(cmd->mem, sizeof(*devl_new))))
|
||||
return_NULL;
|
||||
devl_new->dev = pvl_new->pv->dev;
|
||||
dm_list_add(&pvs_new, &devl_new->list);
|
||||
log_debug_lvmetad("Rescan VG %s found %s was added.", vg->name, dev_name(devl_new->dev));
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* PV in new VG metadata not found in old VG metadata.
|
||||
* There's a good chance we don't know about this new
|
||||
* PV or what device it's on; a label scan is needed
|
||||
* of all devices so we know which device the VG is
|
||||
* now using.
|
||||
*/
|
||||
if (!found) {
|
||||
found_new_pvs++;
|
||||
strncpy(pvid_s, (char *) &pvl_new->pv->id, sizeof(pvid_s) - 1);
|
||||
if (!id_write_format((const struct id *)&pvid_s, uuid, sizeof(uuid)))
|
||||
stack;
|
||||
log_debug_lvmetad("Rescan VG %s found new PV %s.", vg->name, uuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
release_vg(baton.vg);
|
||||
if (!save_vg && retried_reads) {
|
||||
log_error("VG %s not found after rescanning devices.", vg->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do the same scanning above for any new PVs.
|
||||
* Do a full rescan of devices, then look up which devices the
|
||||
* scan found for this VG name, and select those devices to
|
||||
* read metadata from in the loop above (rather than the list
|
||||
* of devices we created from our last copy of the vg metadata.)
|
||||
*
|
||||
* Case 1: VG we knew is no longer on any of the devices we knew it
|
||||
* to be on (save_vg is NULL, which means the metadata wasn't found
|
||||
* when reading mdas on each of the initial pvs_scan devices).
|
||||
* Rescan all devs and then retry reading metadata from the devs that
|
||||
* the scan finds associated with this VG.
|
||||
*
|
||||
* Case 2: VG has new PVs but we don't know what devices they are
|
||||
* so rescan all devs and then retry reading metadata from the devs
|
||||
* that the scan finds associated with this VG.
|
||||
*
|
||||
* (N.B. after a retry, we don't check for found_new_pvs.)
|
||||
*/
|
||||
if (!dm_list_empty(&pvs_new)) {
|
||||
dm_list_init(&pvs_scan);
|
||||
dm_list_splice(&pvs_scan, &pvs_new);
|
||||
dm_list_init(&pvs_new);
|
||||
log_debug_lvmetad("Rescan VG %s found new PVs to scan.", vg->name);
|
||||
goto scan_more;
|
||||
}
|
||||
if (!save_vg || found_new_pvs) {
|
||||
if (!save_vg)
|
||||
log_debug_lvmetad("Rescan VG %s did not find VG on previous devs.", vg->name);
|
||||
if (found_new_pvs)
|
||||
log_debug_lvmetad("Rescan VG %s scanning all devs to find new PVs.", vg->name);
|
||||
|
||||
if (missing_devs) {
|
||||
if (vgmeta_ret)
|
||||
dm_config_destroy(vgmeta_ret);
|
||||
return_NULL;
|
||||
label_scan(cmd);
|
||||
|
||||
if (!(vginfo = lvmcache_vginfo_from_vgname(vg->name, NULL))) {
|
||||
log_error("VG %s vg info not found after rescanning devices.", vg->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set pvs_scan to devs that the label scan found
|
||||
* in the VG and retry the metadata reading loop.
|
||||
*/
|
||||
dm_list_init(&pvs_scan);
|
||||
|
||||
if (!lvmcache_get_vg_devs(cmd, vginfo, &pvs_scan)) {
|
||||
log_error("VG %s info devs not found after rescanning devices.", vg->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
log_debug_lvmetad("Rescan VG %s has %d PVs after label scan.",
|
||||
vg->name, dm_list_size(&pvs_scan));
|
||||
|
||||
if (save_vg)
|
||||
release_vg(save_vg);
|
||||
if (save_meta)
|
||||
dm_config_destroy(save_meta);
|
||||
save_vg = NULL;
|
||||
save_meta = NULL;
|
||||
save_dev = NULL;
|
||||
save_seqno = 0;
|
||||
found_new_pvs = 0;
|
||||
retried_reads = 1;
|
||||
goto retry_reads;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2024,52 +2187,50 @@ scan_more:
|
||||
dm_list_iterate_items(devl, &pvs_drop) {
|
||||
if (!devl->dev)
|
||||
continue;
|
||||
log_debug_lvmetad("Rescan VG %s dropping %s.", vg->name, dev_name(devl->dev));
|
||||
if (!lvmetad_pv_gone_by_dev(devl->dev))
|
||||
return_NULL;
|
||||
log_debug_lvmetad("Rescan VG %s removing %s from lvmetad.", vg->name, dev_name(devl->dev));
|
||||
if (!lvmetad_pv_gone_by_dev(devl->dev)) {
|
||||
/* FIXME: use an error path that disables lvmetad */
|
||||
log_error("Failed to remove %s from lvmetad.", dev_name(devl->dev));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the VG in lvmetad.
|
||||
* Update lvmetad with the newly read version of the VG.
|
||||
* When the seqno is unchanged the cached VG can be left.
|
||||
*/
|
||||
if (vgmeta_ret) {
|
||||
fid = lvmcache_fmt(info)->ops->create_instance(lvmcache_fmt(info), &fic);
|
||||
if (!(vg_ret = import_vg_from_config_tree(vgmeta_ret, fid))) {
|
||||
log_error("VG import from config tree failed");
|
||||
lvmcache_fmt(info)->ops->destroy_instance(fid);
|
||||
goto out;
|
||||
if (save_vg && (save_seqno != vg->seqno)) {
|
||||
dm_list_iterate_items(devl, &pvs_scan) {
|
||||
if (!devl->dev)
|
||||
continue;
|
||||
log_debug_lvmetad("Rescan VG %s removing %s from lvmetad to replace.",
|
||||
vg->name, dev_name(devl->dev));
|
||||
if (!lvmetad_pv_gone_by_dev(devl->dev)) {
|
||||
/* FIXME: use an error path that disables lvmetad */
|
||||
log_error("Failed to remove %s from lvmetad.", dev_name(devl->dev));
|
||||
}
|
||||
}
|
||||
|
||||
log_debug_lvmetad("Rescan VG %s updating lvmetad from seqno %u to seqno %u.",
|
||||
vg->name, vg->seqno, save_seqno);
|
||||
|
||||
/*
|
||||
* Update lvmetad with the newly read version of the VG.
|
||||
* When the seqno is unchanged the cached VG can be left.
|
||||
* If this vg_update fails the cached metadata in
|
||||
* lvmetad will remain invalid.
|
||||
*/
|
||||
if (save_seqno != vg->seqno) {
|
||||
dm_list_iterate_items(devl, &pvs_scan) {
|
||||
if (!devl->dev)
|
||||
continue;
|
||||
log_debug_lvmetad("Rescan VG %s dropping to replace %s.", vg->name, dev_name(devl->dev));
|
||||
if (!lvmetad_pv_gone_by_dev(devl->dev))
|
||||
return_NULL;
|
||||
}
|
||||
|
||||
log_debug_lvmetad("Rescan VG %s updating lvmetad from seqno %u to seqno %u.",
|
||||
vg->name, vg->seqno, save_seqno);
|
||||
|
||||
/*
|
||||
* If this vg_update fails the cached metadata in
|
||||
* lvmetad will remain invalid.
|
||||
*/
|
||||
vg_ret->lvmetad_update_pending = 1;
|
||||
if (!lvmetad_vg_update_finish(vg_ret))
|
||||
log_error("Failed to update lvmetad with new VG meta");
|
||||
save_vg->lvmetad_update_pending = 1;
|
||||
if (!lvmetad_vg_update_finish(save_vg)) {
|
||||
/* FIXME: use an error path that disables lvmetad */
|
||||
log_error("Failed to update lvmetad with new VG meta");
|
||||
}
|
||||
dm_config_destroy(vgmeta_ret);
|
||||
}
|
||||
out:
|
||||
if (vg_ret)
|
||||
log_debug_lvmetad("Rescan VG %s done (seqno %u).", vg_ret->name, vg_ret->seqno);
|
||||
return vg_ret;
|
||||
if (!save_vg && fid)
|
||||
fmt->ops->destroy_instance(fid);
|
||||
if (save_meta)
|
||||
dm_config_destroy(save_meta);
|
||||
if (save_vg)
|
||||
log_debug_lvmetad("Rescan VG %s done (new seqno %u).", save_vg->name, save_vg->seqno);
|
||||
return save_vg;
|
||||
}
|
||||
|
||||
int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
|
||||
@ -2079,9 +2240,12 @@ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
|
||||
struct label *label;
|
||||
struct lvmcache_info *info;
|
||||
struct _lvmetad_pvscan_baton baton;
|
||||
const struct format_type *fmt;
|
||||
/* Create a dummy instance. */
|
||||
struct format_instance_ctx fic = { .type = 0 };
|
||||
|
||||
log_debug_lvmetad("Scan metadata from dev %s", dev_name(dev));
|
||||
|
||||
if (!lvmetad_used()) {
|
||||
log_error("Cannot proceed since lvmetad is not active.");
|
||||
return 0;
|
||||
@ -2092,23 +2256,31 @@ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!label_read(dev, &label, 0)) {
|
||||
log_print_unless_silent("No PV label found on %s.", dev_name(dev));
|
||||
if (!(info = lvmcache_info_from_pvid(dev->pvid, dev, 0))) {
|
||||
log_print_unless_silent("No PV info found on %s for PVID %s.", dev_name(dev), dev->pvid);
|
||||
if (!lvmetad_pv_gone_by_dev(dev))
|
||||
goto_bad;
|
||||
return 1;
|
||||
}
|
||||
|
||||
info = (struct lvmcache_info *) label->info;
|
||||
if (!(label = lvmcache_get_label(info))) {
|
||||
log_print_unless_silent("No PV label found for %s.", dev_name(dev));
|
||||
if (!lvmetad_pv_gone_by_dev(dev))
|
||||
goto_bad;
|
||||
return 1;
|
||||
}
|
||||
|
||||
fmt = lvmcache_fmt(info);
|
||||
|
||||
baton.cmd = cmd;
|
||||
baton.vg = NULL;
|
||||
baton.fid = lvmcache_fmt(info)->ops->create_instance(lvmcache_fmt(info), &fic);
|
||||
baton.fid = fmt->ops->create_instance(fmt, &fic);
|
||||
|
||||
if (!baton.fid)
|
||||
goto_bad;
|
||||
|
||||
if (baton.fid->fmt->features & FMT_OBSOLETE) {
|
||||
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
|
||||
if (fmt->features & FMT_OBSOLETE) {
|
||||
fmt->ops->destroy_instance(baton.fid);
|
||||
log_warn("WARNING: Disabling lvmetad cache which does not support obsolete (lvm1) metadata.");
|
||||
lvmetad_set_disabled(cmd, LVMETAD_DISABLE_REASON_LVM1);
|
||||
_found_lvm1_metadata = 1;
|
||||
@ -2122,9 +2294,9 @@ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
|
||||
lvmcache_foreach_mda(info, _lvmetad_pvscan_single, &baton);
|
||||
|
||||
if (!baton.vg)
|
||||
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
|
||||
fmt->ops->destroy_instance(baton.fid);
|
||||
|
||||
if (!lvmetad_pv_found(cmd, (const struct id *) &dev->pvid, dev, lvmcache_fmt(info),
|
||||
if (!lvmetad_pv_found(cmd, (const struct id *) &dev->pvid, dev, fmt,
|
||||
label->sector, baton.vg, found_vgnames, changed_vgnames)) {
|
||||
release_vg(baton.vg);
|
||||
goto_bad;
|
||||
@ -2190,6 +2362,13 @@ int lvmetad_pvscan_all_devs(struct cmd_context *cmd, int do_wait)
|
||||
replacing_other_update = 1;
|
||||
}
|
||||
|
||||
label_scan(cmd);
|
||||
|
||||
if (lvmcache_found_duplicate_pvs()) {
|
||||
log_warn("WARNING: Scan found duplicate PVs.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_verbose("Scanning all devices to update lvmetad.");
|
||||
|
||||
if (!(iter = dev_iter_create(cmd->lvmetad_filter, 1))) {
|
||||
@ -2372,11 +2551,18 @@ static int _lvmetad_get_pv_cache_list(struct cmd_context *cmd, struct dm_list *p
|
||||
*/
|
||||
static void _update_pv_in_udev(struct cmd_context *cmd, dev_t devt)
|
||||
{
|
||||
struct device *dev;
|
||||
|
||||
log_debug_devs("device %d:%d open to update udev",
|
||||
/*
|
||||
* FIXME: this is diabled as part of removing dev_opens
|
||||
* to integrate bcache. If this is really needed, we
|
||||
* can do a separate open/close here.
|
||||
*/
|
||||
log_debug_devs("SKIP device %d:%d open to update udev",
|
||||
(int)MAJOR(devt), (int)MINOR(devt));
|
||||
|
||||
#if 0
|
||||
struct device *dev;
|
||||
|
||||
if (!(dev = dev_cache_get_by_devt(devt, cmd->lvmetad_filter))) {
|
||||
log_error("_update_pv_in_udev no dev found");
|
||||
return;
|
||||
@ -2389,6 +2575,7 @@ static void _update_pv_in_udev(struct cmd_context *cmd, dev_t devt)
|
||||
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2560,6 +2747,8 @@ void lvmetad_validate_global_cache(struct cmd_context *cmd, int force)
|
||||
*/
|
||||
_lvmetad_get_pv_cache_list(cmd, &pvc_before);
|
||||
|
||||
log_debug_lvmetad("Rescan all devices to validate global cache.");
|
||||
|
||||
/*
|
||||
* Update the local lvmetad cache so it correctly reflects any
|
||||
* changes made on remote hosts. (It's possible that this command
|
||||
@ -2628,7 +2817,7 @@ void lvmetad_validate_global_cache(struct cmd_context *cmd, int force)
|
||||
_update_changed_pvs_in_udev(cmd, &pvc_before, &pvc_after);
|
||||
}
|
||||
|
||||
log_debug_lvmetad("Validating global lvmetad cache finished");
|
||||
log_debug_lvmetad("Rescanned all devices");
|
||||
}
|
||||
|
||||
int lvmetad_vg_is_foreign(struct cmd_context *cmd, const char *vgname, const char *vgid)
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2018 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@ -23,6 +23,7 @@
|
||||
#include "toolcontext.h"
|
||||
#include "lvm-file.h"
|
||||
#include "memlock.h"
|
||||
#include "label.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
@ -279,7 +280,7 @@ struct dm_config_tree *config_file_open_and_read(const char *config_file,
|
||||
}
|
||||
|
||||
log_very_verbose("Loading config file: %s", config_file);
|
||||
if (!config_file_read(cmd->mem, cft)) {
|
||||
if (!config_file_read(cft)) {
|
||||
log_error("Failed to load config file %s", config_file);
|
||||
goto bad;
|
||||
}
|
||||
@ -489,102 +490,32 @@ int override_config_tree_from_profile(struct cmd_context *cmd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct process_config_file_params {
|
||||
struct dm_config_tree *cft;
|
||||
struct device *dev;
|
||||
off_t offset;
|
||||
size_t size;
|
||||
off_t offset2;
|
||||
size_t size2;
|
||||
checksum_fn_t checksum_fn;
|
||||
uint32_t checksum;
|
||||
int checksum_only;
|
||||
int no_dup_node_check;
|
||||
lvm_callback_fn_t config_file_read_fd_callback;
|
||||
void *config_file_read_fd_context;
|
||||
int ret;
|
||||
};
|
||||
|
||||
static void _process_config_file_buffer(int failed, unsigned ioflags, void *context, const void *data)
|
||||
{
|
||||
struct process_config_file_params *pcfp = context;
|
||||
const char *fb = data, *fe;
|
||||
|
||||
if (failed) {
|
||||
pcfp->ret = 0;
|
||||
goto_out;
|
||||
}
|
||||
|
||||
if (pcfp->checksum_fn && pcfp->checksum !=
|
||||
(pcfp->checksum_fn(pcfp->checksum_fn(INITIAL_CRC, (const uint8_t *)fb, pcfp->size),
|
||||
(const uint8_t *)(fb + pcfp->size), pcfp->size2))) {
|
||||
log_error("%s: Checksum error at offset %" PRIu64, dev_name(pcfp->dev), (uint64_t) pcfp->offset);
|
||||
pcfp->ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!pcfp->checksum_only) {
|
||||
fe = fb + pcfp->size + pcfp->size2;
|
||||
if (pcfp->no_dup_node_check) {
|
||||
if (!dm_config_parse_without_dup_node_check(pcfp->cft, fb, fe))
|
||||
pcfp->ret = 0;
|
||||
} else if (!dm_config_parse(pcfp->cft, fb, fe))
|
||||
pcfp->ret = 0;
|
||||
}
|
||||
|
||||
out:
|
||||
if (pcfp->config_file_read_fd_callback)
|
||||
pcfp->config_file_read_fd_callback(!pcfp->ret, ioflags, pcfp->config_file_read_fd_context, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* When checksum_only is set, the checksum of buffer is only matched
|
||||
* and function avoids parsing of mda into config tree which
|
||||
* remains unmodified and should not be used.
|
||||
*/
|
||||
int config_file_read_fd(struct dm_pool *mem, struct dm_config_tree *cft, struct device *dev, dev_io_reason_t reason,
|
||||
int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_reason_t reason,
|
||||
off_t offset, size_t size, off_t offset2, size_t size2,
|
||||
checksum_fn_t checksum_fn, uint32_t checksum,
|
||||
int checksum_only, int no_dup_node_check, unsigned ioflags,
|
||||
lvm_callback_fn_t config_file_read_fd_callback, void *config_file_read_fd_context)
|
||||
int checksum_only, int no_dup_node_check)
|
||||
{
|
||||
char *fb;
|
||||
char *fb, *fe;
|
||||
int r = 0;
|
||||
off_t mmap_offset = 0;
|
||||
int use_mmap = 1;
|
||||
const char *buf = NULL;
|
||||
unsigned circular = size2 ? 1 : 0; /* Wrapped around end of disk metadata buffer? */
|
||||
off_t mmap_offset = 0;
|
||||
char *buf = NULL;
|
||||
struct config_source *cs = dm_config_get_custom(cft);
|
||||
struct process_config_file_params *pcfp;
|
||||
|
||||
if (!_is_file_based_config_source(cs->type)) {
|
||||
log_error(INTERNAL_ERROR "config_file_read_fd: expected file, special file "
|
||||
"or profile config source, found %s config source.",
|
||||
_config_source_names[cs->type]);
|
||||
goto bad;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(pcfp = dm_pool_zalloc(mem, sizeof(*pcfp)))) {
|
||||
log_debug("config_file_read_fd: process_config_file_params struct allocation failed");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
pcfp->cft = cft;
|
||||
pcfp->dev = dev;
|
||||
pcfp->offset = offset;
|
||||
pcfp->size = size;
|
||||
pcfp->offset2 = offset2;
|
||||
pcfp->size2 = size2;
|
||||
pcfp->checksum_fn = checksum_fn;
|
||||
pcfp->checksum = checksum;
|
||||
pcfp->checksum_only = checksum_only;
|
||||
pcfp->no_dup_node_check = no_dup_node_check;
|
||||
pcfp->config_file_read_fd_callback = config_file_read_fd_callback;
|
||||
pcfp->config_file_read_fd_context = config_file_read_fd_context;
|
||||
pcfp->ret = 1;
|
||||
|
||||
/* Only use mmap with regular files */
|
||||
if (!(dev->flags & DEV_REGULAR) || circular)
|
||||
if (!(dev->flags & DEV_REGULAR) || size2)
|
||||
use_mmap = 0;
|
||||
|
||||
if (use_mmap) {
|
||||
@ -594,40 +525,67 @@ int config_file_read_fd(struct dm_pool *mem, struct dm_config_tree *cft, struct
|
||||
MAP_PRIVATE, dev_fd(dev), offset - mmap_offset);
|
||||
if (fb == (caddr_t) (-1)) {
|
||||
log_sys_error("mmap", dev_name(dev));
|
||||
goto bad;
|
||||
goto out;
|
||||
}
|
||||
_process_config_file_buffer(0, ioflags, pcfp, fb + mmap_offset);
|
||||
r = pcfp->ret;
|
||||
fb = fb + mmap_offset;
|
||||
} else {
|
||||
if (!(buf = dm_malloc(size + size2))) {
|
||||
log_error("Failed to allocate circular buffer.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dev_read_bytes(dev, offset, size, buf))
|
||||
goto out;
|
||||
|
||||
if (size2) {
|
||||
if (!dev_read_bytes(dev, offset2, size2, buf + size))
|
||||
goto out;
|
||||
}
|
||||
|
||||
fb = buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* The checksum passed in is the checksum from the mda_header
|
||||
* preceding this metadata. They should always match.
|
||||
* FIXME: handle case where mda_header checksum is bad,
|
||||
* but the checksum calculated here is correct.
|
||||
*/
|
||||
if (checksum_fn && checksum !=
|
||||
(checksum_fn(checksum_fn(INITIAL_CRC, (const uint8_t *)fb, size),
|
||||
(const uint8_t *)(fb + size), size2))) {
|
||||
log_error("%s: Checksum error at offset %" PRIu64, dev_name(dev), (uint64_t) offset);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!checksum_only) {
|
||||
fe = fb + size + size2;
|
||||
if (no_dup_node_check) {
|
||||
if (!dm_config_parse_without_dup_node_check(cft, fb, fe))
|
||||
goto_out;
|
||||
} else {
|
||||
if (!dm_config_parse(cft, fb, fe))
|
||||
goto_out;
|
||||
}
|
||||
}
|
||||
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
if (!use_mmap)
|
||||
dm_free(buf);
|
||||
else {
|
||||
/* unmap the file */
|
||||
if (munmap(fb, size + mmap_offset)) {
|
||||
if (munmap(fb - mmap_offset, size + mmap_offset)) {
|
||||
log_sys_error("munmap", dev_name(dev));
|
||||
r = 0;
|
||||
}
|
||||
} else {
|
||||
if (circular) {
|
||||
if (!(buf = dev_read_circular(dev, (uint64_t) offset, size, (uint64_t) offset2, size2, reason)))
|
||||
goto_out;
|
||||
_process_config_file_buffer(0, ioflags, pcfp, buf);
|
||||
dm_free((void *)buf);
|
||||
} else {
|
||||
dev_read_callback(dev, (uint64_t) offset, size, reason, ioflags, _process_config_file_buffer, pcfp);
|
||||
if (config_file_read_fd_callback)
|
||||
return 1;
|
||||
}
|
||||
r = pcfp->ret;
|
||||
}
|
||||
|
||||
out:
|
||||
return r;
|
||||
|
||||
bad:
|
||||
if (config_file_read_fd_callback)
|
||||
config_file_read_fd_callback(1, ioflags, config_file_read_fd_context, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_file_read(struct dm_pool *mem, struct dm_config_tree *cft)
|
||||
int config_file_read(struct dm_config_tree *cft)
|
||||
{
|
||||
const char *filename = NULL;
|
||||
struct config_source *cs = dm_config_get_custom(cft);
|
||||
@ -655,8 +613,8 @@ int config_file_read(struct dm_pool *mem, struct dm_config_tree *cft)
|
||||
}
|
||||
}
|
||||
|
||||
r = config_file_read_fd(mem, cft, cf->dev, DEV_IO_MDA_CONTENT, 0, (size_t) info.st_size, 0, 0,
|
||||
(checksum_fn_t) NULL, 0, 0, 0, 0, NULL, NULL);
|
||||
r = config_file_read_fd(cft, cf->dev, DEV_IO_MDA_CONTENT, 0, (size_t) info.st_size, 0, 0,
|
||||
(checksum_fn_t) NULL, 0, 0, 0);
|
||||
|
||||
if (!cf->keep_open) {
|
||||
if (!dev_close(cf->dev))
|
||||
|
@ -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,
|
||||
|
@ -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"
|
||||
|
@ -32,9 +32,6 @@
|
||||
#define DEFAULT_SYSTEM_ID_SOURCE "none"
|
||||
#define DEFAULT_OBTAIN_DEVICE_LIST_FROM_UDEV 1
|
||||
#define DEFAULT_EXTERNAL_DEVICE_INFO_SOURCE "none"
|
||||
#define DEFAULT_USE_AIO 1
|
||||
#define DEFAULT_AIO_MAX 128
|
||||
#define DEFAULT_AIO_MEMORY 10
|
||||
#define DEFAULT_SYSFS_SCAN 1
|
||||
#define DEFAULT_MD_COMPONENT_DETECTION 1
|
||||
#define DEFAULT_FW_RAID_COMPONENT_DETECTION 0
|
||||
@ -182,7 +179,6 @@
|
||||
#define DEFAULT_LOGLEVEL 0
|
||||
#define DEFAULT_INDENT 1
|
||||
#define DEFAULT_ABORT_ON_INTERNAL_ERRORS 0
|
||||
#define DEFAULT_DETECT_INTERNAL_VG_CACHE_CORRUPTION 0
|
||||
#define DEFAULT_UNITS "r"
|
||||
#define DEFAULT_SUFFIX 1
|
||||
#define DEFAULT_HOSTTAGS 0
|
||||
|
1182
lib/device/bcache.c
Normal file
1182
lib/device/bcache.c
Normal file
File diff suppressed because it is too large
Load Diff
164
lib/device/bcache.h
Normal file
164
lib/device/bcache.h
Normal file
@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef BCACHE_H
|
||||
#define BCACHE_H
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "libdevmapper.h"
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
// FIXME: move somewhere more sensible
|
||||
#define container_of(v, t, head) \
|
||||
((t *)((const char *)(v) - (const char *)&((t *) 0)->head))
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* bcache-specific error numbers
|
||||
* These supplement standard -EXXX error numbers and
|
||||
* should not overlap.
|
||||
*/
|
||||
#define BCACHE_NO_BLOCK 201
|
||||
|
||||
enum dir {
|
||||
DIR_READ,
|
||||
DIR_WRITE
|
||||
};
|
||||
|
||||
typedef uint64_t block_address;
|
||||
typedef uint64_t sector_t;
|
||||
|
||||
typedef void io_complete_fn(void *context, int io_error);
|
||||
|
||||
struct io_engine {
|
||||
void (*destroy)(struct io_engine *e);
|
||||
bool (*issue)(struct io_engine *e, enum dir d, int fd,
|
||||
sector_t sb, sector_t se, void *data, void *context);
|
||||
bool (*wait)(struct io_engine *e, io_complete_fn fn);
|
||||
unsigned (*max_io)(struct io_engine *e);
|
||||
};
|
||||
|
||||
struct io_engine *create_async_io_engine(void);
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
struct bcache;
|
||||
struct block {
|
||||
/* clients may only access these three fields */
|
||||
int fd;
|
||||
uint64_t index;
|
||||
void *data;
|
||||
|
||||
struct bcache *cache;
|
||||
struct dm_list list;
|
||||
struct dm_list hash;
|
||||
|
||||
unsigned flags;
|
||||
unsigned ref_count;
|
||||
int error;
|
||||
enum dir io_dir;
|
||||
};
|
||||
|
||||
/*
|
||||
* Ownership of engine passes. Engine will be destroyed even if this fails.
|
||||
*/
|
||||
struct bcache *bcache_create(sector_t block_size, unsigned nr_cache_blocks,
|
||||
struct io_engine *engine);
|
||||
void bcache_destroy(struct bcache *cache);
|
||||
|
||||
enum bcache_get_flags {
|
||||
/*
|
||||
* The block will be zeroed before get_block returns it. This
|
||||
* potentially avoids a read if the block is not already in the cache.
|
||||
* GF_DIRTY is implicit.
|
||||
*/
|
||||
GF_ZERO = (1 << 0),
|
||||
|
||||
/*
|
||||
* Indicates the caller is intending to change the data in the block, a
|
||||
* writeback will occur after the block is released.
|
||||
*/
|
||||
GF_DIRTY = (1 << 1)
|
||||
};
|
||||
|
||||
unsigned bcache_nr_cache_blocks(struct bcache *cache);
|
||||
unsigned bcache_max_prefetches(struct bcache *cache);
|
||||
|
||||
/*
|
||||
* Use the prefetch method to take advantage of asynchronous IO. For example,
|
||||
* if you wanted to read a block from many devices concurrently you'd do
|
||||
* something like this:
|
||||
*
|
||||
* dm_list_iterate_items (dev, &devices)
|
||||
* bcache_prefetch(cache, dev->fd, block);
|
||||
*
|
||||
* dm_list_iterate_items (dev, &devices) {
|
||||
* if (!bcache_get(cache, dev->fd, block, &b))
|
||||
* fail();
|
||||
*
|
||||
* process_block(b);
|
||||
* }
|
||||
*
|
||||
* It's slightly sub optimal, since you may not run the gets in the order that
|
||||
* they complete. But we're talking a very small difference, and it's worth it
|
||||
* to keep callbacks out of this interface.
|
||||
*/
|
||||
void bcache_prefetch(struct bcache *cache, int fd, block_address index);
|
||||
|
||||
/*
|
||||
* Returns true on success.
|
||||
*/
|
||||
bool bcache_get(struct bcache *cache, int fd, block_address index,
|
||||
unsigned flags, struct block **result, int *error);
|
||||
void bcache_put(struct block *b);
|
||||
|
||||
/*
|
||||
* flush() does not attempt to writeback locked blocks. flush will fail
|
||||
* (return false), if any unlocked dirty data cannot be written back.
|
||||
*/
|
||||
bool bcache_flush(struct bcache *cache);
|
||||
|
||||
/*
|
||||
* Removes a block from the cache. If the block is dirty it will be written
|
||||
* back first. If the block is currently held a warning will be issued, and it
|
||||
* will not be removed.
|
||||
*/
|
||||
void bcache_invalidate(struct bcache *cache, int fd, block_address index);
|
||||
|
||||
/*
|
||||
* Invalidates all blocks on the given descriptor. Call this before closing
|
||||
* the descriptor to make sure everything is written back.
|
||||
*/
|
||||
void bcache_invalidate_fd(struct bcache *cache, int fd);
|
||||
|
||||
/*
|
||||
* Prefetches the blocks neccessary to satisfy a byte range.
|
||||
*/
|
||||
void bcache_prefetch_bytes(struct bcache *cache, int fd, off_t start, size_t len);
|
||||
|
||||
/*
|
||||
* Reads and writes the bytes. Returns false if errors occur.
|
||||
*/
|
||||
bool bcache_read_bytes(struct bcache *cache, int fd, off_t start, size_t len, void *data);
|
||||
bool bcache_write_bytes(struct bcache *cache, int fd, off_t start, size_t len, void *data);
|
||||
bool bcache_write_zeros(struct bcache *cache, int fd, off_t start, size_t len);
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
#endif
|
@ -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)
|
||||
|
@ -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);
|
||||
|
||||
|
@ -53,12 +53,6 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Always read at least 8k from disk.
|
||||
* This seems to be a good compromise for the existing LVM2 metadata layout.
|
||||
*/
|
||||
#define MIN_READ_SIZE (8 * 1024)
|
||||
|
||||
static DM_LIST_INIT(_open_devices);
|
||||
static unsigned _dev_size_seqno = 1;
|
||||
|
||||
@ -80,319 +74,38 @@ static const char *_reason_text(dev_io_reason_t reason)
|
||||
return _reasons[(unsigned) reason];
|
||||
}
|
||||
|
||||
/*
|
||||
* Release the memory holding the last data we read
|
||||
*/
|
||||
static void _release_devbuf(struct device_buffer *devbuf)
|
||||
{
|
||||
dm_free(devbuf->malloc_address);
|
||||
devbuf->malloc_address = NULL;
|
||||
}
|
||||
|
||||
void devbufs_release(struct device *dev)
|
||||
{
|
||||
if ((dev->flags & DEV_REGULAR))
|
||||
return;
|
||||
|
||||
_release_devbuf(&dev->last_devbuf);
|
||||
_release_devbuf(&dev->last_extra_devbuf);
|
||||
}
|
||||
|
||||
#ifdef AIO_SUPPORT
|
||||
|
||||
# include <libaio.h>
|
||||
|
||||
static io_context_t _aio_ctx = 0;
|
||||
static struct io_event *_aio_events = NULL;
|
||||
static int _aio_max = 0;
|
||||
static int64_t _aio_memory_max = 0;
|
||||
static int _aio_must_queue = 0; /* Have we reached AIO capacity? */
|
||||
|
||||
static DM_LIST_INIT(_aio_queue);
|
||||
|
||||
#define DEFAULT_AIO_COLLECTION_EVENTS 32
|
||||
|
||||
int dev_async_setup(struct cmd_context *cmd)
|
||||
{
|
||||
int r;
|
||||
|
||||
_aio_max = find_config_tree_int(cmd, devices_aio_max_CFG, NULL);
|
||||
_aio_memory_max = find_config_tree_int(cmd, devices_aio_memory_CFG, NULL) * INT64_C(1024 * 1024);
|
||||
|
||||
/* Threshold is zero? */
|
||||
if (!_aio_max || !_aio_memory_max) {
|
||||
if (_aio_ctx)
|
||||
dev_async_exit();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Already set up? */
|
||||
if (_aio_ctx)
|
||||
return 1;
|
||||
|
||||
log_debug_io("Setting up aio context for up to %" PRId64 " MB across %d events.", _aio_memory_max, _aio_max);
|
||||
|
||||
if (!_aio_events && !(_aio_events = dm_zalloc(sizeof(*_aio_events) * DEFAULT_AIO_COLLECTION_EVENTS))) {
|
||||
log_error("Failed to allocate io_event array for asynchronous I/O.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((r = io_setup(_aio_max, &_aio_ctx)) < 0) {
|
||||
/*
|
||||
* Possible errors:
|
||||
* ENOSYS - aio not available in current kernel
|
||||
* EAGAIN - _aio_max is too big
|
||||
* EFAULT - invalid pointer
|
||||
* EINVAL - _aio_ctx != 0 or kernel aio limits exceeded
|
||||
* ENOMEM
|
||||
*/
|
||||
log_warn("WARNING: Asynchronous I/O setup for %d events failed: %s", _aio_max, strerror(-r));
|
||||
log_warn("WARNING: Using only synchronous I/O.");
|
||||
dm_free(_aio_events);
|
||||
_aio_events = NULL;
|
||||
_aio_ctx = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Reset aio context after fork */
|
||||
int dev_async_reset(struct cmd_context *cmd)
|
||||
{
|
||||
log_debug_io("Resetting asynchronous I/O context.");
|
||||
_aio_ctx = 0;
|
||||
dm_free(_aio_events);
|
||||
_aio_events = NULL;
|
||||
|
||||
return dev_async_setup(cmd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Track the amount of in-flight async I/O.
|
||||
* If it exceeds the defined threshold set _aio_must_queue.
|
||||
*/
|
||||
static void _update_aio_counters(int nr, ssize_t bytes)
|
||||
{
|
||||
static int64_t aio_bytes = 0;
|
||||
static int aio_count = 0;
|
||||
|
||||
aio_bytes += bytes;
|
||||
aio_count += nr;
|
||||
|
||||
if (aio_count >= _aio_max || aio_bytes > _aio_memory_max)
|
||||
_aio_must_queue = 1;
|
||||
else
|
||||
_aio_must_queue = 0;
|
||||
}
|
||||
|
||||
static int _io(struct device_buffer *devbuf, unsigned ioflags);
|
||||
|
||||
int dev_async_getevents(void)
|
||||
{
|
||||
struct device_buffer *devbuf, *tmp;
|
||||
lvm_callback_fn_t dev_read_callback_fn;
|
||||
void *dev_read_callback_context;
|
||||
int r, event_nr;
|
||||
|
||||
if (!_aio_ctx)
|
||||
return 1;
|
||||
|
||||
do {
|
||||
/* FIXME Add timeout - currently NULL - waits for ever for at least 1 item */
|
||||
r = io_getevents(_aio_ctx, 1, DEFAULT_AIO_COLLECTION_EVENTS, _aio_events, NULL);
|
||||
if (r > 0)
|
||||
break;
|
||||
if (!r)
|
||||
return 1; /* Timeout elapsed */
|
||||
if (r == -EINTR)
|
||||
continue;
|
||||
if (r == -EAGAIN) {
|
||||
usleep(100);
|
||||
return 1; /* Give the caller the opportunity to do other work before repeating */
|
||||
}
|
||||
/*
|
||||
* ENOSYS - not supported by kernel
|
||||
* EFAULT - memory invalid
|
||||
* EINVAL - _aio_ctx invalid or min_nr/nr/timeout out of range
|
||||
*/
|
||||
log_error("Asynchronous event collection failed: %s", strerror(-r));
|
||||
return 0;
|
||||
} while (1);
|
||||
|
||||
for (event_nr = 0; event_nr < r; event_nr++) {
|
||||
devbuf = _aio_events[event_nr].obj->data;
|
||||
dm_free(_aio_events[event_nr].obj);
|
||||
|
||||
_update_aio_counters(-1, -devbuf->where.size);
|
||||
|
||||
dev_read_callback_fn = devbuf->dev_read_callback_fn;
|
||||
dev_read_callback_context = devbuf->dev_read_callback_context;
|
||||
|
||||
/* Clear the callbacks as a precaution */
|
||||
devbuf->dev_read_callback_context = NULL;
|
||||
devbuf->dev_read_callback_fn = NULL;
|
||||
|
||||
if (_aio_events[event_nr].res == devbuf->where.size) {
|
||||
if (dev_read_callback_fn)
|
||||
dev_read_callback_fn(0, AIO_SUPPORTED_CODE_PATH, dev_read_callback_context, (char *)devbuf->buf + devbuf->data_offset);
|
||||
} else {
|
||||
/* FIXME If partial read is possible, resubmit remainder */
|
||||
log_error("%s: asynchronous read only I/O failed (" FMTd64 ") of " FMTu64 " bytes at " FMTu64 " (for %s): %s",
|
||||
dev_name(devbuf->where.dev), _aio_events[event_nr].res,
|
||||
(uint64_t) devbuf->where.size, (uint64_t) devbuf->where.start,
|
||||
_reason_text(devbuf->reason),
|
||||
(((int64_t)_aio_events[event_nr].res) < 0) ? strerror(-(int64_t)_aio_events[event_nr].res) : 0);
|
||||
_release_devbuf(devbuf);
|
||||
if (dev_read_callback_fn)
|
||||
dev_read_callback_fn(1, AIO_SUPPORTED_CODE_PATH, dev_read_callback_context, NULL);
|
||||
else
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Submit further queued events if we can */
|
||||
dm_list_iterate_items_gen_safe(devbuf, tmp, &_aio_queue, aio_queued) {
|
||||
if (_aio_must_queue)
|
||||
break;
|
||||
dm_list_del(&devbuf->aio_queued);
|
||||
_io(devbuf, 1);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _io_async(struct device_buffer *devbuf)
|
||||
{
|
||||
struct device_area *where = &devbuf->where;
|
||||
struct iocb *iocb;
|
||||
int r;
|
||||
|
||||
_update_aio_counters(1, devbuf->where.size);
|
||||
|
||||
if (!(iocb = dm_malloc(sizeof(*iocb)))) {
|
||||
log_error("Failed to allocate I/O control block array for asynchronous I/O.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
io_prep_pread(iocb, dev_fd(where->dev), devbuf->buf, where->size, where->start);
|
||||
iocb->data = devbuf;
|
||||
|
||||
do {
|
||||
r = io_submit(_aio_ctx, 1L, &iocb);
|
||||
if (r ==1)
|
||||
break; /* Success */
|
||||
if (r == -EAGAIN) {
|
||||
/* Try to release some resources then retry */
|
||||
usleep(100);
|
||||
if (dev_async_getevents())
|
||||
return_0;
|
||||
/* FIXME Add counter/timeout so we can't get stuck here for ever */
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Possible errors:
|
||||
* EFAULT - invalid data
|
||||
* ENOSYS - no aio support in kernel
|
||||
* EBADF - bad file descriptor in iocb
|
||||
* EINVAL - invalid _aio_ctx / iocb not initialised / invalid operation for this fd
|
||||
*/
|
||||
log_error("Asynchronous event submission failed: %s", strerror(-r));
|
||||
return 0;
|
||||
} while (1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void dev_async_exit(void)
|
||||
{
|
||||
struct device_buffer *devbuf, *tmp;
|
||||
lvm_callback_fn_t dev_read_callback_fn;
|
||||
void *dev_read_callback_context;
|
||||
int r;
|
||||
|
||||
if (!_aio_ctx)
|
||||
return;
|
||||
|
||||
/* Discard any queued requests */
|
||||
dm_list_iterate_items_gen_safe(devbuf, tmp, &_aio_queue, aio_queued) {
|
||||
dm_list_del(&devbuf->aio_queued);
|
||||
|
||||
_update_aio_counters(-1, -devbuf->where.size);
|
||||
|
||||
dev_read_callback_fn = devbuf->dev_read_callback_fn;
|
||||
dev_read_callback_context = devbuf->dev_read_callback_context;
|
||||
|
||||
_release_devbuf(devbuf);
|
||||
|
||||
if (dev_read_callback_fn)
|
||||
dev_read_callback_fn(1, AIO_SUPPORTED_CODE_PATH, dev_read_callback_context, NULL);
|
||||
}
|
||||
|
||||
log_debug_io("Destroying aio context.");
|
||||
if ((r = io_destroy(_aio_ctx)) < 0)
|
||||
/* Returns -ENOSYS if aio not in kernel or -EINVAL if _aio_ctx invalid */
|
||||
log_error("Failed to destroy asynchronous I/O context: %s", strerror(-r));
|
||||
|
||||
dm_free(_aio_events);
|
||||
_aio_events = NULL;
|
||||
|
||||
_aio_ctx = 0;
|
||||
}
|
||||
|
||||
static void _queue_aio(struct device_buffer *devbuf)
|
||||
{
|
||||
dm_list_add(&_aio_queue, &devbuf->aio_queued);
|
||||
log_debug_io("Queueing aio.");
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int _aio_ctx = 0;
|
||||
static int _aio_must_queue = 0;
|
||||
|
||||
int dev_async_setup(struct cmd_context *cmd)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dev_async_reset(struct cmd_context *cmd)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dev_async_getevents(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void dev_async_exit(void)
|
||||
{
|
||||
}
|
||||
|
||||
static int _io_async(struct device_buffer *devbuf)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _queue_aio(struct device_buffer *devbuf)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* AIO_SUPPORT */
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
* The standard io loop that keeps submitting an io until it's
|
||||
* all gone.
|
||||
*---------------------------------------------------------------*/
|
||||
static int _io_sync(struct device_buffer *devbuf)
|
||||
static int _io(struct device_area *where, char *buffer, int should_write, dev_io_reason_t reason)
|
||||
{
|
||||
struct device_area *where = &devbuf->where;
|
||||
int fd = dev_fd(where->dev);
|
||||
char *buffer = devbuf->buf;
|
||||
ssize_t n = 0;
|
||||
size_t total = 0;
|
||||
|
||||
if (fd < 0) {
|
||||
log_error("Attempt to read an unopened device (%s).",
|
||||
dev_name(where->dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug_io("%s %s:%8" PRIu64 " bytes (sync) at %" PRIu64 "%s (for %s)",
|
||||
should_write ? "Write" : "Read ", dev_name(where->dev),
|
||||
where->size, (uint64_t) where->start,
|
||||
(should_write && test_mode()) ? " (test mode - suppressed)" : "", _reason_text(reason));
|
||||
|
||||
/*
|
||||
* Skip all writes in test mode.
|
||||
*/
|
||||
if (should_write && test_mode())
|
||||
return 1;
|
||||
|
||||
if (where->size > SSIZE_MAX) {
|
||||
log_error("Read size too large: %" PRIu64, where->size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lseek(fd, (off_t) where->start, SEEK_SET) == (off_t) -1) {
|
||||
log_error("%s: lseek %" PRIu64 " failed: %s",
|
||||
dev_name(where->dev), (uint64_t) where->start,
|
||||
@ -402,19 +115,18 @@ static int _io_sync(struct device_buffer *devbuf)
|
||||
|
||||
while (total < (size_t) where->size) {
|
||||
do
|
||||
n = devbuf->write ?
|
||||
n = should_write ?
|
||||
write(fd, buffer, (size_t) where->size - total) :
|
||||
read(fd, buffer, (size_t) where->size - total);
|
||||
while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN)));
|
||||
|
||||
if (n < 0)
|
||||
log_error("%s: synchronous %s failed after %" PRIu64 " of %" PRIu64
|
||||
" at %" PRIu64 " (for %s): %s", dev_name(where->dev),
|
||||
devbuf->write ? "write" : "read",
|
||||
(uint64_t) total,
|
||||
(uint64_t) where->size, (uint64_t) where->start,
|
||||
_reason_text(devbuf->reason),
|
||||
strerror(errno));
|
||||
log_error_once("%s: %s failed after %" PRIu64 " of %" PRIu64
|
||||
" at %" PRIu64 ": %s", dev_name(where->dev),
|
||||
should_write ? "write" : "read",
|
||||
(uint64_t) total,
|
||||
(uint64_t) where->size,
|
||||
(uint64_t) where->start, strerror(errno));
|
||||
|
||||
if (n <= 0)
|
||||
break;
|
||||
@ -426,42 +138,6 @@ static int _io_sync(struct device_buffer *devbuf)
|
||||
return (total == (size_t) where->size);
|
||||
}
|
||||
|
||||
static int _io(struct device_buffer *devbuf, unsigned ioflags)
|
||||
{
|
||||
struct device_area *where = &devbuf->where;
|
||||
int fd = dev_fd(where->dev);
|
||||
int async = (!devbuf->write && _aio_ctx && aio_supported_code_path(ioflags) && devbuf->dev_read_callback_fn) ? 1 : 0;
|
||||
|
||||
if (fd < 0) {
|
||||
log_error("Attempt to read an unopened device (%s).",
|
||||
dev_name(where->dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!devbuf->buf && !(devbuf->malloc_address = devbuf->buf = dm_malloc_aligned((size_t) devbuf->where.size, 0))) {
|
||||
log_error("I/O buffer malloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug_io("%s %s(fd %d):%8" PRIu64 " bytes (%ssync) at %" PRIu64 "%s (for %s)",
|
||||
devbuf->write ? "Write" : "Read ", dev_name(where->dev), fd,
|
||||
where->size, async ? "a" : "", (uint64_t) where->start,
|
||||
(devbuf->write && test_mode()) ? " (test mode - suppressed)" : "", _reason_text(devbuf->reason));
|
||||
|
||||
/*
|
||||
* Skip all writes in test mode.
|
||||
*/
|
||||
if (devbuf->write && test_mode())
|
||||
return 1;
|
||||
|
||||
if (where->size > SSIZE_MAX) {
|
||||
log_error("Read size too large: %" PRIu64, where->size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return async ? _io_async(devbuf) : _io_sync(devbuf);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
* LVM2 uses O_DIRECT when performing metadata io, which requires
|
||||
* block size aligned accesses. If any io is not aligned we have
|
||||
@ -551,16 +227,15 @@ static void _widen_region(unsigned int block_size, struct device_area *region,
|
||||
result->size += block_size - delta;
|
||||
}
|
||||
|
||||
static int _aligned_io(struct device_area *where, char *write_buffer,
|
||||
int should_write, dev_io_reason_t reason,
|
||||
unsigned ioflags, lvm_callback_fn_t dev_read_callback_fn, void *dev_read_callback_context)
|
||||
static int _aligned_io(struct device_area *where, char *buffer,
|
||||
int should_write, dev_io_reason_t reason)
|
||||
{
|
||||
char *bounce, *bounce_buf;
|
||||
unsigned int physical_block_size = 0;
|
||||
unsigned int block_size = 0;
|
||||
unsigned buffer_was_widened = 0;
|
||||
uintptr_t mask;
|
||||
struct device_area widened;
|
||||
struct device_buffer *devbuf;
|
||||
int r = 0;
|
||||
|
||||
if (!(where->dev->flags & DEV_REGULAR) &&
|
||||
@ -569,11 +244,6 @@ static int _aligned_io(struct device_area *where, char *write_buffer,
|
||||
|
||||
if (!block_size)
|
||||
block_size = lvm_getpagesize();
|
||||
|
||||
/* Apply minimum read size */
|
||||
if (!should_write && block_size < MIN_READ_SIZE)
|
||||
block_size = MIN_READ_SIZE;
|
||||
|
||||
mask = block_size - 1;
|
||||
|
||||
_widen_region(block_size, where, &widened);
|
||||
@ -583,75 +253,50 @@ static int _aligned_io(struct device_area *where, char *write_buffer,
|
||||
buffer_was_widened = 1;
|
||||
log_debug_io("Widening request for %" PRIu64 " bytes at %" PRIu64 " to %" PRIu64 " bytes at %" PRIu64 " on %s (for %s)",
|
||||
where->size, (uint64_t) where->start, widened.size, (uint64_t) widened.start, dev_name(where->dev), _reason_text(reason));
|
||||
}
|
||||
|
||||
devbuf = DEV_DEVBUF(where->dev, reason);
|
||||
_release_devbuf(devbuf);
|
||||
devbuf->where.dev = where->dev;
|
||||
devbuf->where.start = widened.start;
|
||||
devbuf->where.size = widened.size;
|
||||
devbuf->write = should_write;
|
||||
devbuf->reason = reason;
|
||||
devbuf->dev_read_callback_fn = dev_read_callback_fn;
|
||||
devbuf->dev_read_callback_context = dev_read_callback_context;
|
||||
|
||||
/* Store location of requested data relative to start of buf */
|
||||
devbuf->data_offset = where->start - devbuf->where.start;
|
||||
|
||||
if (should_write && !buffer_was_widened && !((uintptr_t) write_buffer & mask))
|
||||
} else if (!((uintptr_t) buffer & mask))
|
||||
/* Perform the I/O directly. */
|
||||
devbuf->buf = write_buffer;
|
||||
else if (!should_write)
|
||||
/* Postpone buffer allocation until we're about to issue the I/O */
|
||||
devbuf->buf = NULL;
|
||||
else {
|
||||
/* Allocate a bounce buffer with an extra block */
|
||||
if (!(devbuf->malloc_address = devbuf->buf = dm_malloc((size_t) devbuf->where.size + block_size))) {
|
||||
log_error("Bounce buffer malloc failed");
|
||||
return 0;
|
||||
}
|
||||
return _io(where, buffer, should_write, reason);
|
||||
|
||||
/*
|
||||
* Realign start of bounce buffer (using the extra sector)
|
||||
*/
|
||||
if (((uintptr_t) devbuf->buf) & mask)
|
||||
devbuf->buf = (char *) ((((uintptr_t) devbuf->buf) + mask) & ~mask);
|
||||
/* Allocate a bounce buffer with an extra block */
|
||||
if (!(bounce_buf = bounce = dm_malloc((size_t) widened.size + block_size))) {
|
||||
log_error("Bounce buffer malloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If we've reached our concurrent AIO limit, add this request to the queue */
|
||||
if (!devbuf->write && _aio_ctx && aio_supported_code_path(ioflags) && dev_read_callback_fn && _aio_must_queue) {
|
||||
_queue_aio(devbuf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
devbuf->write = 0;
|
||||
/*
|
||||
* Realign start of bounce buffer (using the extra sector)
|
||||
*/
|
||||
if (((uintptr_t) bounce) & mask)
|
||||
bounce = (char *) ((((uintptr_t) bounce) + mask) & ~mask);
|
||||
|
||||
/* Do we need to read into the bounce buffer? */
|
||||
if ((!should_write || buffer_was_widened) && !_io(devbuf, ioflags)) {
|
||||
if ((!should_write || buffer_was_widened) &&
|
||||
!_io(&widened, bounce, 0, reason)) {
|
||||
if (!should_write)
|
||||
goto_bad;
|
||||
goto_out;
|
||||
/* FIXME Handle errors properly! */
|
||||
/* FIXME pre-extend the file */
|
||||
memset(devbuf->buf, '\n', devbuf->where.size);
|
||||
memset(bounce, '\n', widened.size);
|
||||
}
|
||||
|
||||
if (!should_write)
|
||||
return 1;
|
||||
if (should_write) {
|
||||
memcpy(bounce + (where->start - widened.start), buffer,
|
||||
(size_t) where->size);
|
||||
|
||||
/* writes */
|
||||
|
||||
if (devbuf->malloc_address) {
|
||||
memcpy((char *) devbuf->buf + devbuf->data_offset, write_buffer, (size_t) where->size);
|
||||
log_debug_io("Overwriting %" PRIu64 " bytes at %" PRIu64 " (for %s)", where->size,
|
||||
(uint64_t) where->start, _reason_text(devbuf->reason));
|
||||
/* ... then we write */
|
||||
if (!(r = _io(&widened, bounce, 1, reason)))
|
||||
stack;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* ... then we write */
|
||||
devbuf->write = 1;
|
||||
if (!(r = _io(devbuf, 0)))
|
||||
stack;
|
||||
bad:
|
||||
_release_devbuf(devbuf);
|
||||
memcpy(buffer, bounce + (where->start - widened.start),
|
||||
(size_t) where->size);
|
||||
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
dm_free(bounce_buf);
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -685,6 +330,8 @@ static int _dev_get_size_file(struct device *dev, uint64_t *size)
|
||||
static int _dev_get_size_dev(struct device *dev, uint64_t *size)
|
||||
{
|
||||
const char *name = dev_name(dev);
|
||||
int fd = dev->bcache_fd;
|
||||
int do_close = 0;
|
||||
|
||||
if (dev->size_seqno == _dev_size_seqno) {
|
||||
log_very_verbose("%s: using cached size %" PRIu64 " sectors",
|
||||
@ -693,12 +340,16 @@ static int _dev_get_size_dev(struct device *dev, uint64_t *size)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!dev_open_readonly(dev))
|
||||
return_0;
|
||||
if (fd <= 0) {
|
||||
if (!dev_open_readonly(dev))
|
||||
return_0;
|
||||
fd = dev_fd(dev);
|
||||
do_close = 1;
|
||||
}
|
||||
|
||||
if (ioctl(dev_fd(dev), BLKGETSIZE64, size) < 0) {
|
||||
if (ioctl(fd, BLKGETSIZE64, size) < 0) {
|
||||
log_sys_error("ioctl BLKGETSIZE64", name);
|
||||
if (!dev_close(dev))
|
||||
if (do_close && !dev_close(dev))
|
||||
log_sys_error("close", name);
|
||||
return 0;
|
||||
}
|
||||
@ -707,7 +358,7 @@ static int _dev_get_size_dev(struct device *dev, uint64_t *size)
|
||||
dev->size = *size;
|
||||
dev->size_seqno = _dev_size_seqno;
|
||||
|
||||
if (!dev_close(dev))
|
||||
if (do_close && !dev_close(dev))
|
||||
log_sys_error("close", name);
|
||||
|
||||
log_very_verbose("%s: size is %" PRIu64 " sectors", name, *size);
|
||||
@ -984,17 +635,12 @@ int dev_open_readonly_quiet(struct device *dev)
|
||||
|
||||
int dev_test_excl(struct device *dev)
|
||||
{
|
||||
int flags;
|
||||
int r;
|
||||
int flags = 0;
|
||||
|
||||
flags = vg_write_lock_held() ? O_RDWR : O_RDONLY;
|
||||
flags |= O_EXCL;
|
||||
flags |= O_RDWR;
|
||||
|
||||
r = dev_open_flags(dev, flags, 1, 1);
|
||||
if (r)
|
||||
dev_close_immediate(dev);
|
||||
|
||||
return r;
|
||||
return dev_open_flags(dev, flags, 1, 1);
|
||||
}
|
||||
|
||||
static void _close(struct device *dev)
|
||||
@ -1005,7 +651,6 @@ static void _close(struct device *dev)
|
||||
dev->phys_block_size = -1;
|
||||
dev->block_size = -1;
|
||||
dm_list_del(&dev->open_list);
|
||||
devbufs_release(dev);
|
||||
|
||||
log_debug_devs("Closed %s", dev_name(dev));
|
||||
|
||||
@ -1015,7 +660,6 @@ static void _close(struct device *dev)
|
||||
|
||||
static int _dev_close(struct device *dev, int immediate)
|
||||
{
|
||||
|
||||
if (dev->fd < 0) {
|
||||
log_error("Attempt to close device '%s' "
|
||||
"which is not open.", dev_name(dev));
|
||||
@ -1078,123 +722,57 @@ static void _dev_inc_error_count(struct device *dev)
|
||||
dev->max_error_count, dev_name(dev));
|
||||
}
|
||||
|
||||
/*
|
||||
* Data is returned (read-only) at DEV_DEVBUF_DATA(dev, reason).
|
||||
* If dev_read_callback_fn is supplied, we always return 1 and take
|
||||
* responsibility for calling it exactly once. This might happen before the
|
||||
* function returns (if there's an error or the I/O is synchronous) or after.
|
||||
* Any error is passed to that function, which must track it if required.
|
||||
*/
|
||||
static int _dev_read_callback(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t reason,
|
||||
unsigned ioflags, lvm_callback_fn_t dev_read_callback_fn, void *callback_context)
|
||||
int dev_read(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t reason, void *buffer)
|
||||
{
|
||||
struct device_area where;
|
||||
struct device_buffer *devbuf;
|
||||
uint64_t buf_end;
|
||||
int cached = 0;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
if (!dev->open_count) {
|
||||
log_error(INTERNAL_ERROR "Attempt to access device %s while closed.", dev_name(dev));
|
||||
goto out;
|
||||
}
|
||||
if (!dev->open_count)
|
||||
return_0;
|
||||
|
||||
if (!_dev_is_valid(dev))
|
||||
goto_out;
|
||||
|
||||
/*
|
||||
* Can we satisfy this from data we stored last time we read?
|
||||
*/
|
||||
if ((devbuf = DEV_DEVBUF(dev, reason)) && devbuf->malloc_address) {
|
||||
buf_end = devbuf->where.start + devbuf->where.size - 1;
|
||||
if (offset >= devbuf->where.start && offset <= buf_end && offset + len - 1 <= buf_end) {
|
||||
/* Reuse this buffer */
|
||||
cached = 1;
|
||||
devbuf->data_offset = offset - devbuf->where.start;
|
||||
log_debug_io("Cached read for %" PRIu64 " bytes at %" PRIu64 " on %s (for %s)",
|
||||
(uint64_t) len, (uint64_t) offset, dev_name(dev), _reason_text(reason));
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
where.dev = dev;
|
||||
where.start = offset;
|
||||
where.size = len;
|
||||
|
||||
ret = _aligned_io(&where, NULL, 0, reason, ioflags, dev_read_callback_fn, callback_context);
|
||||
if (!ret) {
|
||||
log_debug("Read from %s failed (for %s).", dev_name(dev), _reason_text(reason));
|
||||
ret = _aligned_io(&where, buffer, 0, reason);
|
||||
if (!ret)
|
||||
_dev_inc_error_count(dev);
|
||||
}
|
||||
|
||||
out:
|
||||
/* If we had an error or this was sync I/O, pass the result to any callback fn */
|
||||
if ((!ret || !_aio_ctx || !aio_supported_code_path(ioflags) || cached) && dev_read_callback_fn) {
|
||||
dev_read_callback_fn(!ret, ioflags, callback_context, DEV_DEVBUF_DATA(dev, reason));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dev_read_callback(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t reason,
|
||||
unsigned ioflags, lvm_callback_fn_t dev_read_callback_fn, void *callback_context)
|
||||
/*
|
||||
* Read from 'dev' into 'buf', possibly in 2 distinct regions, denoted
|
||||
* by (offset,len) and (offset2,len2). Thus, the total size of
|
||||
* 'buf' should be len+len2.
|
||||
*/
|
||||
int dev_read_circular(struct device *dev, uint64_t offset, size_t len,
|
||||
uint64_t offset2, size_t len2, dev_io_reason_t reason, char *buf)
|
||||
{
|
||||
/* Always returns 1 if callback fn is supplied */
|
||||
if (!_dev_read_callback(dev, offset, len, reason, ioflags, dev_read_callback_fn, callback_context))
|
||||
log_error(INTERNAL_ERROR "_dev_read_callback failed");
|
||||
}
|
||||
if (!dev_read(dev, offset, len, reason, buf)) {
|
||||
log_error("Read from %s failed", dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns pointer to read-only buffer. Caller does not free it. */
|
||||
const char *dev_read(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t reason)
|
||||
{
|
||||
if (!_dev_read_callback(dev, offset, len, reason, 0, NULL, NULL))
|
||||
return_NULL;
|
||||
/*
|
||||
* The second region is optional, and allows for
|
||||
* a circular buffer on the device.
|
||||
*/
|
||||
if (!len2)
|
||||
return 1;
|
||||
|
||||
return DEV_DEVBUF_DATA(dev, reason);
|
||||
}
|
||||
|
||||
/* Read into supplied retbuf owned by the caller. */
|
||||
int dev_read_buf(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t reason, void *retbuf)
|
||||
{
|
||||
if (!_dev_read_callback(dev, offset, len, reason, 0, NULL, NULL))
|
||||
return_0;
|
||||
|
||||
memcpy(retbuf, DEV_DEVBUF_DATA(dev, reason), len);
|
||||
if (!dev_read(dev, offset2, len2, reason, buf + len)) {
|
||||
log_error("Circular read from %s failed",
|
||||
dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read from 'dev' in 2 distinct regions, denoted by (offset,len) and (offset2,len2).
|
||||
* Caller is responsible for dm_free().
|
||||
*/
|
||||
const char *dev_read_circular(struct device *dev, uint64_t offset, size_t len,
|
||||
uint64_t offset2, size_t len2, dev_io_reason_t reason)
|
||||
{
|
||||
char *buf = NULL;
|
||||
|
||||
if (!(buf = dm_malloc(len + len2))) {
|
||||
log_error("Buffer allocation failed for split metadata.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!dev_read_buf(dev, offset, len, reason, buf)) {
|
||||
log_error("Read from %s failed.", dev_name(dev));
|
||||
dm_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!dev_read_buf(dev, offset2, len2, reason, buf + len)) {
|
||||
log_error("Circular read from %s failed.", dev_name(dev));
|
||||
dm_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* FIXME If O_DIRECT can't extend file, dev_extend first; dev_truncate after.
|
||||
* But fails if concurrent processes writing
|
||||
*/
|
||||
@ -1238,7 +816,7 @@ int dev_write(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t r
|
||||
|
||||
dev->flags |= DEV_ACCESSED_W;
|
||||
|
||||
ret = _aligned_io(&where, buffer, 1, reason, 0, NULL, NULL);
|
||||
ret = _aligned_io(&where, buffer, 1, reason);
|
||||
if (!ret)
|
||||
_dev_inc_error_count(dev);
|
||||
|
||||
@ -1248,7 +826,7 @@ int dev_write(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t r
|
||||
int dev_set(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t reason, int value)
|
||||
{
|
||||
size_t s;
|
||||
char buffer[4096] __attribute__((aligned(4096)));
|
||||
char buffer[4096] __attribute__((aligned(8)));
|
||||
|
||||
if (!dev_open(dev))
|
||||
return_0;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -31,18 +31,8 @@
|
||||
#define DEV_USED_FOR_LV 0x00000100 /* Is device used for an LV */
|
||||
#define DEV_ASSUMED_FOR_LV 0x00000200 /* Is device assumed for an LV */
|
||||
#define DEV_NOT_O_NOATIME 0x00000400 /* Don't use O_NOATIME */
|
||||
|
||||
/* ioflags */
|
||||
#define AIO_SUPPORTED_CODE_PATH 0x00000001 /* Set if the code path supports AIO */
|
||||
|
||||
#define aio_supported_code_path(ioflags) (((ioflags) & AIO_SUPPORTED_CODE_PATH) ? 1 : 0)
|
||||
|
||||
/*
|
||||
* Standard format for callback functions.
|
||||
* When provided, callback functions are called exactly once.
|
||||
* If failed is set, data cannot be accessed.
|
||||
*/
|
||||
typedef void (*lvm_callback_fn_t)(int failed, unsigned ioflags, void *context, const void *data);
|
||||
#define DEV_IN_BCACHE 0x00000800 /* dev fd is open and used in bcache */
|
||||
#define DEV_BCACHE_EXCL 0x00001000 /* bcache_fd should be open EXCL */
|
||||
|
||||
/*
|
||||
* Support for external device info.
|
||||
@ -61,48 +51,6 @@ struct dev_ext {
|
||||
void *handle;
|
||||
};
|
||||
|
||||
/*
|
||||
* All I/O is annotated with the reason it is performed.
|
||||
*/
|
||||
typedef enum dev_io_reason {
|
||||
DEV_IO_SIGNATURES = 0, /* Scanning device signatures */
|
||||
DEV_IO_LABEL, /* LVM PV disk label */
|
||||
DEV_IO_MDA_HEADER, /* Text format metadata area header */
|
||||
DEV_IO_MDA_CONTENT, /* Text format metadata area content */
|
||||
DEV_IO_MDA_EXTRA_HEADER, /* Header of any extra metadata areas on device */
|
||||
DEV_IO_MDA_EXTRA_CONTENT, /* Content of any extra metadata areas on device */
|
||||
DEV_IO_FMT1, /* Original LVM1 metadata format */
|
||||
DEV_IO_POOL, /* Pool metadata format */
|
||||
DEV_IO_LV, /* Content written to an LV */
|
||||
DEV_IO_LOG /* Logging messages */
|
||||
} dev_io_reason_t;
|
||||
|
||||
/*
|
||||
* Is this I/O for a device's extra metadata area?
|
||||
*/
|
||||
#define EXTRA_IO(reason) ((reason) == DEV_IO_MDA_EXTRA_HEADER || (reason) == DEV_IO_MDA_EXTRA_CONTENT)
|
||||
#define DEV_DEVBUF(dev, reason) (EXTRA_IO((reason)) ? &(dev)->last_extra_devbuf : &(dev)->last_devbuf)
|
||||
#define DEV_DEVBUF_DATA(dev, reason) ((char *) DEV_DEVBUF((dev), (reason))->buf + DEV_DEVBUF((dev), (reason))->data_offset)
|
||||
|
||||
struct device_area {
|
||||
struct device *dev;
|
||||
uint64_t start; /* Bytes */
|
||||
uint64_t size; /* Bytes */
|
||||
};
|
||||
|
||||
struct device_buffer {
|
||||
uint64_t data_offset; /* Offset to start of requested data within buf */
|
||||
void *malloc_address; /* Start of allocated memory */
|
||||
void *buf; /* Aligned buffer that contains data within it */
|
||||
struct device_area where; /* Location of buf */
|
||||
dev_io_reason_t reason;
|
||||
unsigned write:1; /* 1 if write; 0 if read */
|
||||
|
||||
lvm_callback_fn_t dev_read_callback_fn;
|
||||
void *dev_read_callback_context;
|
||||
struct dm_list aio_queued; /* Queue of async I/O waiting to be issued */
|
||||
};
|
||||
|
||||
/*
|
||||
* All devices in LVM will be represented by one of these.
|
||||
* pointer comparisons are valid.
|
||||
@ -119,14 +67,13 @@ struct device {
|
||||
int phys_block_size;
|
||||
int block_size;
|
||||
int read_ahead;
|
||||
int bcache_fd;
|
||||
uint32_t flags;
|
||||
unsigned size_seqno;
|
||||
uint64_t size;
|
||||
uint64_t end;
|
||||
struct dm_list open_list;
|
||||
struct dev_ext ext;
|
||||
struct device_buffer last_devbuf; /* Last data buffer read from the device */
|
||||
struct device_buffer last_extra_devbuf; /* Last data buffer read from the device for extra metadata area */
|
||||
|
||||
const char *vgid; /* if device is an LV */
|
||||
const char *lvid; /* if device is an LV */
|
||||
@ -135,11 +82,33 @@ struct device {
|
||||
char _padding[7];
|
||||
};
|
||||
|
||||
/*
|
||||
* All I/O is annotated with the reason it is performed.
|
||||
*/
|
||||
typedef enum dev_io_reason {
|
||||
DEV_IO_SIGNATURES = 0, /* Scanning device signatures */
|
||||
DEV_IO_LABEL, /* LVM PV disk label */
|
||||
DEV_IO_MDA_HEADER, /* Text format metadata area header */
|
||||
DEV_IO_MDA_CONTENT, /* Text format metadata area content */
|
||||
DEV_IO_MDA_EXTRA_HEADER, /* Header of any extra metadata areas on device */
|
||||
DEV_IO_MDA_EXTRA_CONTENT, /* Content of any extra metadata areas on device */
|
||||
DEV_IO_FMT1, /* Original LVM1 metadata format */
|
||||
DEV_IO_POOL, /* Pool metadata format */
|
||||
DEV_IO_LV, /* Content written to an LV */
|
||||
DEV_IO_LOG /* Logging messages */
|
||||
} dev_io_reason_t;
|
||||
|
||||
struct device_list {
|
||||
struct dm_list list;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
struct device_area {
|
||||
struct device *dev;
|
||||
uint64_t start; /* Bytes */
|
||||
uint64_t size; /* Bytes */
|
||||
};
|
||||
|
||||
/*
|
||||
* Support for external device info.
|
||||
*/
|
||||
@ -179,19 +148,9 @@ int dev_test_excl(struct device *dev);
|
||||
int dev_fd(struct device *dev);
|
||||
const char *dev_name(const struct device *dev);
|
||||
|
||||
/* Returns a read-only buffer */
|
||||
const char *dev_read(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t reason);
|
||||
const char *dev_read_circular(struct device *dev, uint64_t offset, size_t len,
|
||||
uint64_t offset2, size_t len2, dev_io_reason_t reason);
|
||||
|
||||
/* Passes the data (or error) to dev_read_callback_fn */
|
||||
void dev_read_callback(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t reason,
|
||||
unsigned ioflags, lvm_callback_fn_t dev_read_callback_fn, void *callback_context);
|
||||
|
||||
/* Read data and copy it into a supplied private buffer. */
|
||||
/* Only use for tiny reads or on unimportant code paths. */
|
||||
int dev_read_buf(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t reason, void *retbuf);
|
||||
|
||||
int dev_read(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t reason, void *buffer);
|
||||
int dev_read_circular(struct device *dev, uint64_t offset, size_t len,
|
||||
uint64_t offset2, size_t len2, dev_io_reason_t reason, char *buf);
|
||||
int dev_write(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t reason, void *buffer);
|
||||
int dev_append(struct device *dev, size_t len, dev_io_reason_t reason, char *buffer);
|
||||
int dev_set(struct device *dev, uint64_t offset, size_t len, dev_io_reason_t reason, int value);
|
||||
@ -201,15 +160,7 @@ struct device *dev_create_file(const char *filename, struct device *dev,
|
||||
struct dm_str_list *alias, int use_malloc);
|
||||
void dev_destroy_file(struct device *dev);
|
||||
|
||||
void devbufs_release(struct device *dev);
|
||||
|
||||
/* Return a valid device name from the alias list; NULL otherwise */
|
||||
const char *dev_name_confirmed(struct device *dev, int quiet);
|
||||
|
||||
struct cmd_context;
|
||||
int dev_async_getevents(void);
|
||||
int dev_async_setup(struct cmd_context *cmd);
|
||||
void dev_async_exit(void);
|
||||
int dev_async_reset(struct cmd_context *cmd);
|
||||
|
||||
#endif
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include "lvm-version.h"
|
||||
#include "toolcontext.h"
|
||||
#include "config-util.h"
|
||||
#include "layout.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
@ -124,12 +123,11 @@ static int _extend_buffer(struct formatter *f)
|
||||
|
||||
log_debug_metadata("Doubling metadata output buffer to " FMTu32,
|
||||
f->data.buf.size * 2);
|
||||
if (!(newbuf = dm_malloc_aligned(f->data.buf.size * 2, 0)))
|
||||
return_0;
|
||||
|
||||
memcpy(newbuf, f->data.buf.start, f->data.buf.size);
|
||||
free(f->data.buf.start);
|
||||
|
||||
if (!(newbuf = dm_realloc(f->data.buf.start,
|
||||
f->data.buf.size * 2))) {
|
||||
log_error("Buffer reallocation failed.");
|
||||
return 0;
|
||||
}
|
||||
f->data.buf.start = newbuf;
|
||||
f->data.buf.size *= 2;
|
||||
|
||||
@ -1066,7 +1064,7 @@ size_t text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf)
|
||||
return_0;
|
||||
|
||||
f->data.buf.size = 65536; /* Initial metadata limit */
|
||||
if (!(f->data.buf.start = dm_malloc_aligned(f->data.buf.size, 0))) {
|
||||
if (!(f->data.buf.start = dm_malloc(f->data.buf.size))) {
|
||||
log_error("text_export buffer allocation failed");
|
||||
goto out;
|
||||
}
|
||||
@ -1081,12 +1079,7 @@ size_t text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf)
|
||||
goto_out;
|
||||
}
|
||||
|
||||
f->data.buf.used += 1; /* Terminating NUL */
|
||||
|
||||
/* Zero fill up to next alignment boundary */
|
||||
memset(f->data.buf.start + f->data.buf.used, 0, MDA_ALIGNMENT - f->data.buf.used % MDA_ALIGNMENT);
|
||||
|
||||
r = f->data.buf.used;
|
||||
r = f->data.buf.used + 1;
|
||||
*buf = f->data.buf.start;
|
||||
|
||||
out:
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2018 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@ -16,7 +16,6 @@
|
||||
#include "lib.h"
|
||||
#include "metadata.h"
|
||||
#include "import-export.h"
|
||||
#include "toolcontext.h"
|
||||
|
||||
/* FIXME Use tidier inclusion method */
|
||||
static struct text_vg_version_ops *(_text_vsn_list[2]);
|
||||
@ -33,102 +32,70 @@ static void _init_text_import(void)
|
||||
_text_import_initialised = 1;
|
||||
}
|
||||
|
||||
struct import_vgsummary_params {
|
||||
const struct format_type *fmt;
|
||||
struct dm_config_tree *cft;
|
||||
int checksum_only;
|
||||
struct lvmcache_vgsummary *vgsummary;
|
||||
lvm_callback_fn_t process_vgsummary_fn;
|
||||
void *process_vgsummary_context;
|
||||
int ret;
|
||||
};
|
||||
|
||||
static void _import_vgsummary(int failed, unsigned ioflags, void *context, const void *data)
|
||||
/*
|
||||
* Find out vgname on a given device.
|
||||
*/
|
||||
int text_read_metadata_summary(const struct format_type *fmt,
|
||||
struct device *dev, dev_io_reason_t reason,
|
||||
off_t offset, uint32_t size,
|
||||
off_t offset2, uint32_t size2,
|
||||
checksum_fn_t checksum_fn,
|
||||
int checksum_only,
|
||||
struct lvmcache_vgsummary *vgsummary)
|
||||
{
|
||||
struct import_vgsummary_params *ivsp = context;
|
||||
struct dm_config_tree *cft;
|
||||
struct text_vg_version_ops **vsn;
|
||||
int r = 0;
|
||||
|
||||
if (failed) {
|
||||
ivsp->ret = 0;
|
||||
goto_out;
|
||||
_init_text_import();
|
||||
|
||||
if (!(cft = config_open(CONFIG_FILE_SPECIAL, NULL, 0)))
|
||||
return_0;
|
||||
|
||||
if (dev) {
|
||||
log_debug_metadata("Reading metadata summary from %s at %llu size %d (+%d)",
|
||||
dev_name(dev), (unsigned long long)offset,
|
||||
size, size2);
|
||||
|
||||
if (!config_file_read_fd(cft, dev, reason, offset, size,
|
||||
offset2, size2, checksum_fn,
|
||||
vgsummary->mda_checksum,
|
||||
checksum_only, 1)) {
|
||||
/* FIXME: handle errors */
|
||||
log_error("Couldn't read volume group metadata from %s.", dev_name(dev));
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
if (!config_file_read(cft)) {
|
||||
log_error("Couldn't read volume group metadata from file.");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (ivsp->checksum_only)
|
||||
if (checksum_only) {
|
||||
/* Checksum matches already-cached content - no need to reparse. */
|
||||
log_debug_metadata("Skipped parsing metadata on %s", dev_name(dev));
|
||||
r = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a set of version functions that can read this file
|
||||
*/
|
||||
for (vsn = &_text_vsn_list[0]; *vsn; vsn++) {
|
||||
if (!(*vsn)->check_version(ivsp->cft))
|
||||
if (!(*vsn)->check_version(cft))
|
||||
continue;
|
||||
|
||||
if (!(*vsn)->read_vgsummary(ivsp->fmt, ivsp->cft, ivsp->vgsummary)) {
|
||||
ivsp->ret = 0;
|
||||
if (!(*vsn)->read_vgsummary(fmt, cft, vgsummary))
|
||||
goto_out;
|
||||
}
|
||||
|
||||
goto out;
|
||||
r = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Nothing found */
|
||||
ivsp->ret = 0;
|
||||
|
||||
out:
|
||||
config_destroy(ivsp->cft);
|
||||
|
||||
if (ivsp->process_vgsummary_fn)
|
||||
ivsp->process_vgsummary_fn(!ivsp->ret, ioflags, ivsp->process_vgsummary_context, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find out vgname on a given device.
|
||||
*/
|
||||
int text_vgsummary_import(const struct format_type *fmt,
|
||||
struct device *dev, dev_io_reason_t reason,
|
||||
off_t offset, uint32_t size,
|
||||
off_t offset2, uint32_t size2,
|
||||
checksum_fn_t checksum_fn,
|
||||
int checksum_only, unsigned ioflags,
|
||||
struct lvmcache_vgsummary *vgsummary,
|
||||
lvm_callback_fn_t process_vgsummary_fn,
|
||||
void *process_vgsummary_context)
|
||||
{
|
||||
struct import_vgsummary_params *ivsp;
|
||||
|
||||
_init_text_import();
|
||||
|
||||
if (!(ivsp = dm_pool_zalloc(fmt->cmd->mem, sizeof(*ivsp)))) {
|
||||
log_error("Failed to allocate import_vgsummary_params struct.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(ivsp->cft = config_open(CONFIG_FILE_SPECIAL, NULL, 0)))
|
||||
return_0;
|
||||
|
||||
ivsp->fmt = fmt;
|
||||
ivsp->checksum_only = checksum_only;
|
||||
ivsp->vgsummary = vgsummary;
|
||||
ivsp->process_vgsummary_fn = process_vgsummary_fn;
|
||||
ivsp->process_vgsummary_context = process_vgsummary_context;
|
||||
ivsp->ret = 1;
|
||||
|
||||
if (!dev) {
|
||||
if (!config_file_read(fmt->cmd->mem, ivsp->cft)) {
|
||||
log_error("Couldn't read volume group metadata.");
|
||||
ivsp->ret = 0;
|
||||
}
|
||||
_import_vgsummary(!ivsp->ret, ioflags, ivsp, NULL);
|
||||
} else if (!config_file_read_fd(fmt->cmd->mem, ivsp->cft, dev, reason, offset, size,
|
||||
offset2, size2, checksum_fn,
|
||||
vgsummary->mda_checksum,
|
||||
checksum_only, 1, ioflags, &_import_vgsummary, ivsp)) {
|
||||
log_error("Couldn't read volume group metadata.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ivsp->ret;
|
||||
out:
|
||||
config_destroy(cft);
|
||||
return r;
|
||||
}
|
||||
|
||||
struct cached_vg_fmtdata {
|
||||
@ -136,30 +103,74 @@ struct cached_vg_fmtdata {
|
||||
size_t cached_mda_size;
|
||||
};
|
||||
|
||||
struct import_vg_params {
|
||||
struct format_instance *fid;
|
||||
struct dm_config_tree *cft;
|
||||
int single_device;
|
||||
int skip_parse;
|
||||
unsigned *use_previous_vg;
|
||||
struct volume_group *vg;
|
||||
uint32_t checksum;
|
||||
uint32_t total_size;
|
||||
time_t *when;
|
||||
struct cached_vg_fmtdata **vg_fmtdata;
|
||||
char **desc;
|
||||
};
|
||||
|
||||
static void _import_vg(int failed, unsigned ioflags, void *context, const void *data)
|
||||
struct volume_group *text_read_metadata(struct format_instance *fid,
|
||||
const char *file,
|
||||
struct cached_vg_fmtdata **vg_fmtdata,
|
||||
unsigned *use_previous_vg,
|
||||
struct device *dev, int primary_mda,
|
||||
off_t offset, uint32_t size,
|
||||
off_t offset2, uint32_t size2,
|
||||
checksum_fn_t checksum_fn,
|
||||
uint32_t checksum,
|
||||
time_t *when, char **desc)
|
||||
{
|
||||
struct import_vg_params *ivp = context;
|
||||
struct volume_group *vg = NULL;
|
||||
struct dm_config_tree *cft;
|
||||
struct text_vg_version_ops **vsn;
|
||||
int skip_parse;
|
||||
|
||||
ivp->vg = NULL;
|
||||
/*
|
||||
* This struct holds the checksum and size of the VG metadata
|
||||
* that was read from a previous device. When we read the VG
|
||||
* metadata from this device, we can skip parsing it into a
|
||||
* cft (saving time) if the checksum of the metadata buffer
|
||||
* we read from this device matches the size/checksum saved in
|
||||
* the mda_header/rlocn struct on this device, and matches the
|
||||
* size/checksum from the previous device.
|
||||
*/
|
||||
if (vg_fmtdata && !*vg_fmtdata &&
|
||||
!(*vg_fmtdata = dm_pool_zalloc(fid->mem, sizeof(**vg_fmtdata)))) {
|
||||
log_error("Failed to allocate VG fmtdata for text format.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ivp->skip_parse) {
|
||||
if (ivp->use_previous_vg)
|
||||
*ivp->use_previous_vg = 1;
|
||||
_init_text_import();
|
||||
|
||||
*desc = NULL;
|
||||
*when = 0;
|
||||
|
||||
if (!(cft = config_open(CONFIG_FILE_SPECIAL, file, 0)))
|
||||
return_NULL;
|
||||
|
||||
/* Does the metadata match the already-cached VG? */
|
||||
skip_parse = vg_fmtdata &&
|
||||
((*vg_fmtdata)->cached_mda_checksum == checksum) &&
|
||||
((*vg_fmtdata)->cached_mda_size == (size + size2));
|
||||
|
||||
|
||||
if (dev) {
|
||||
log_debug_metadata("Reading metadata from %s at %llu size %d (+%d)",
|
||||
dev_name(dev), (unsigned long long)offset,
|
||||
size, size2);
|
||||
|
||||
if (!config_file_read_fd(cft, dev, MDA_CONTENT_REASON(primary_mda), offset, size,
|
||||
offset2, size2, checksum_fn, checksum,
|
||||
skip_parse, 1)) {
|
||||
/* FIXME: handle errors */
|
||||
log_error("Couldn't read volume group metadata from %s.", dev_name(dev));
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
if (!config_file_read(cft)) {
|
||||
log_error("Couldn't read volume group metadata from file.");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (skip_parse) {
|
||||
if (use_previous_vg)
|
||||
*use_previous_vg = 1;
|
||||
log_debug_metadata("Skipped parsing metadata on %s", dev_name(dev));
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -167,98 +178,36 @@ static void _import_vg(int failed, unsigned ioflags, void *context, const void *
|
||||
* Find a set of version functions that can read this file
|
||||
*/
|
||||
for (vsn = &_text_vsn_list[0]; *vsn; vsn++) {
|
||||
if (!(*vsn)->check_version(ivp->cft))
|
||||
if (!(*vsn)->check_version(cft))
|
||||
continue;
|
||||
|
||||
if (!(ivp->vg = (*vsn)->read_vg(ivp->fid, ivp->cft, ivp->single_device, 0)))
|
||||
if (!(vg = (*vsn)->read_vg(fid, cft, 0)))
|
||||
goto_out;
|
||||
|
||||
(*vsn)->read_desc(ivp->vg->vgmem, ivp->cft, ivp->when, ivp->desc);
|
||||
(*vsn)->read_desc(vg->vgmem, cft, when, desc);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ivp->vg && ivp->vg_fmtdata && *ivp->vg_fmtdata) {
|
||||
(*ivp->vg_fmtdata)->cached_mda_size = ivp->total_size;
|
||||
(*ivp->vg_fmtdata)->cached_mda_checksum = ivp->checksum;
|
||||
if (vg && vg_fmtdata && *vg_fmtdata) {
|
||||
(*vg_fmtdata)->cached_mda_size = (size + size2);
|
||||
(*vg_fmtdata)->cached_mda_checksum = checksum;
|
||||
}
|
||||
|
||||
if (ivp->use_previous_vg)
|
||||
*ivp->use_previous_vg = 0;
|
||||
if (use_previous_vg)
|
||||
*use_previous_vg = 0;
|
||||
|
||||
out:
|
||||
config_destroy(ivp->cft);
|
||||
out:
|
||||
config_destroy(cft);
|
||||
return vg;
|
||||
}
|
||||
|
||||
struct volume_group *text_vg_import_fd(struct format_instance *fid,
|
||||
const char *file,
|
||||
struct cached_vg_fmtdata **vg_fmtdata,
|
||||
unsigned *use_previous_vg,
|
||||
int single_device,
|
||||
struct device *dev, int primary_mda,
|
||||
off_t offset, uint32_t size,
|
||||
off_t offset2, uint32_t size2,
|
||||
checksum_fn_t checksum_fn,
|
||||
uint32_t checksum, unsigned ioflags,
|
||||
time_t *when, char **desc)
|
||||
{
|
||||
struct import_vg_params *ivp;
|
||||
|
||||
if (vg_fmtdata && !*vg_fmtdata &&
|
||||
!(*vg_fmtdata = dm_pool_zalloc(fid->mem, sizeof(**vg_fmtdata)))) {
|
||||
log_error("Failed to allocate VG fmtdata for text format.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(ivp = dm_pool_zalloc(fid->fmt->cmd->mem, sizeof(*ivp)))) {
|
||||
log_error("Failed to allocate import_vgsummary_params struct.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_init_text_import();
|
||||
|
||||
ivp->fid = fid;
|
||||
ivp->when = when;
|
||||
*ivp->when = 0;
|
||||
ivp->desc = desc;
|
||||
*ivp->desc = NULL;
|
||||
ivp->single_device = single_device;
|
||||
ivp->use_previous_vg = use_previous_vg;
|
||||
ivp->checksum = checksum;
|
||||
ivp->total_size = size + size2;
|
||||
ivp->vg_fmtdata = vg_fmtdata;
|
||||
|
||||
if (!(ivp->cft = config_open(CONFIG_FILE_SPECIAL, file, 0)))
|
||||
return_NULL;
|
||||
|
||||
/* Does the metadata match the already-cached VG? */
|
||||
ivp->skip_parse = vg_fmtdata &&
|
||||
((*vg_fmtdata)->cached_mda_checksum == checksum) &&
|
||||
((*vg_fmtdata)->cached_mda_size == ivp->total_size);
|
||||
|
||||
if (!dev && !config_file_read(fid->mem, ivp->cft)) {
|
||||
config_destroy(ivp->cft);
|
||||
return_NULL;
|
||||
}
|
||||
|
||||
if (dev) {
|
||||
if (!config_file_read_fd(fid->mem, ivp->cft, dev, MDA_CONTENT_REASON(primary_mda), offset, size,
|
||||
offset2, size2, checksum_fn, checksum,
|
||||
ivp->skip_parse, 1, ioflags, &_import_vg, ivp)) {
|
||||
config_destroy(ivp->cft);
|
||||
return_NULL;
|
||||
}
|
||||
} else
|
||||
_import_vg(0, 0, ivp, NULL);
|
||||
|
||||
return ivp->vg;
|
||||
}
|
||||
|
||||
struct volume_group *text_vg_import_file(struct format_instance *fid,
|
||||
struct volume_group *text_read_metadata_file(struct format_instance *fid,
|
||||
const char *file,
|
||||
time_t *when, char **desc)
|
||||
{
|
||||
return text_vg_import_fd(fid, file, NULL, NULL, 0, NULL, 0, (off_t)0, 0, (off_t)0, 0, NULL, 0,
|
||||
0, when, desc);
|
||||
return text_read_metadata(fid, file, NULL, NULL, NULL, 0,
|
||||
(off_t)0, 0, (off_t)0, 0, NULL, 0,
|
||||
when, desc);
|
||||
}
|
||||
|
||||
static struct volume_group *_import_vg_from_config_tree(const struct dm_config_tree *cft,
|
||||
@ -278,7 +227,7 @@ static struct volume_group *_import_vg_from_config_tree(const struct dm_config_t
|
||||
* The only path to this point uses cached vgmetadata,
|
||||
* so it can use cached PV state too.
|
||||
*/
|
||||
if (!(vg = (*vsn)->read_vg(fid, cft, 1, allow_lvmetad_extensions)))
|
||||
if (!(vg = (*vsn)->read_vg(fid, cft, allow_lvmetad_extensions)))
|
||||
stack;
|
||||
else if ((vg_missing = vg_missing_pv_count(vg))) {
|
||||
log_verbose("There are %d physical volumes missing.",
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2018 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@ -19,7 +19,6 @@
|
||||
#include "label.h"
|
||||
#include "xlate.h"
|
||||
#include "lvmcache.h"
|
||||
#include "toolcontext.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
@ -36,14 +35,14 @@ static int _text_can_handle(struct labeller *l __attribute__((unused)),
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dl_setup_baton {
|
||||
struct _dl_setup_baton {
|
||||
struct disk_locn *pvh_dlocn_xl;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
static int _da_setup(struct disk_locn *da, void *baton)
|
||||
{
|
||||
struct dl_setup_baton *p = baton;
|
||||
struct _dl_setup_baton *p = baton;
|
||||
p->pvh_dlocn_xl->offset = xlate64(da->offset);
|
||||
p->pvh_dlocn_xl->size = xlate64(da->size);
|
||||
p->pvh_dlocn_xl++;
|
||||
@ -57,7 +56,7 @@ static int _ba_setup(struct disk_locn *ba, void *baton)
|
||||
|
||||
static int _mda_setup(struct metadata_area *mda, void *baton)
|
||||
{
|
||||
struct dl_setup_baton *p = baton;
|
||||
struct _dl_setup_baton *p = baton;
|
||||
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
||||
|
||||
if (mdac->area.dev != p->dev)
|
||||
@ -72,7 +71,7 @@ static int _mda_setup(struct metadata_area *mda, void *baton)
|
||||
|
||||
static int _dl_null_termination(void *baton)
|
||||
{
|
||||
struct dl_setup_baton *p = baton;
|
||||
struct _dl_setup_baton *p = baton;
|
||||
|
||||
p->pvh_dlocn_xl->offset = xlate64(UINT64_C(0));
|
||||
p->pvh_dlocn_xl->size = xlate64(UINT64_C(0));
|
||||
@ -87,7 +86,7 @@ static int _text_write(struct label *label, void *buf)
|
||||
struct pv_header *pvhdr;
|
||||
struct pv_header_extension *pvhdr_ext;
|
||||
struct lvmcache_info *info;
|
||||
struct dl_setup_baton baton;
|
||||
struct _dl_setup_baton baton;
|
||||
char buffer[64] __attribute__((aligned(8)));
|
||||
int ba1, da1, mda1, mda2;
|
||||
|
||||
@ -319,62 +318,23 @@ static int _text_initialise_label(struct labeller *l __attribute__((unused)),
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct update_mda_baton {
|
||||
struct _update_mda_baton {
|
||||
struct lvmcache_info *info;
|
||||
struct label *label;
|
||||
int nr_outstanding_mdas;
|
||||
unsigned ioflags;
|
||||
lvm_callback_fn_t read_label_callback_fn;
|
||||
void *read_label_callback_context;
|
||||
int ret;
|
||||
};
|
||||
|
||||
struct process_mda_header_params {
|
||||
struct update_mda_baton *umb;
|
||||
struct metadata_area *mda;
|
||||
struct device *dev;
|
||||
struct lvmcache_vgsummary vgsummary;
|
||||
int ret;
|
||||
};
|
||||
|
||||
static void _process_vgsummary(int failed, unsigned ioflags, void *context, const void *data)
|
||||
static int _read_mda_header_and_metadata(struct metadata_area *mda, void *baton)
|
||||
{
|
||||
struct process_mda_header_params *pmp = context;
|
||||
const struct lvmcache_vgsummary *vgsummary = data;
|
||||
|
||||
--pmp->umb->nr_outstanding_mdas;
|
||||
|
||||
/* FIXME Need to distinguish genuine errors here */
|
||||
if (failed)
|
||||
goto_out;
|
||||
|
||||
if (!lvmcache_update_vgname_and_id(pmp->umb->info, vgsummary)) {
|
||||
pmp->umb->ret = 0;
|
||||
pmp->ret = 0;
|
||||
}
|
||||
|
||||
out:
|
||||
if (!pmp->umb->nr_outstanding_mdas && pmp->umb->ret)
|
||||
lvmcache_make_valid(pmp->umb->info);
|
||||
|
||||
if (!dev_close(pmp->dev))
|
||||
stack;
|
||||
|
||||
if (!pmp->umb->nr_outstanding_mdas && pmp->umb->read_label_callback_fn)
|
||||
pmp->umb->read_label_callback_fn(!pmp->umb->ret, ioflags, pmp->umb->read_label_callback_context, pmp->umb->label);
|
||||
}
|
||||
|
||||
static void _process_mda_header(int failed, unsigned ioflags, void *context, const void *data)
|
||||
{
|
||||
struct process_mda_header_params *pmp = context;
|
||||
const struct mda_header *mdah = data;
|
||||
struct update_mda_baton *umb = pmp->umb;
|
||||
const struct format_type *fmt = umb->label->labeller->fmt;
|
||||
struct metadata_area *mda = pmp->mda;
|
||||
struct _update_mda_baton *p = baton;
|
||||
const struct format_type *fmt = p->label->labeller->fmt;
|
||||
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
||||
struct mda_header *mdah;
|
||||
struct lvmcache_vgsummary vgsummary = { 0 };
|
||||
|
||||
if (failed)
|
||||
goto_bad;
|
||||
if (!(mdah = raw_read_mda_header(fmt, &mdac->area, mda_is_primary(mda)))) {
|
||||
log_error("Failed to read mda header from %s", dev_name(mdac->area.dev));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
mda_set_ignored(mda, rlocn_is_ignored(mdah->raw_locns));
|
||||
|
||||
@ -382,102 +342,53 @@ static void _process_mda_header(int failed, unsigned ioflags, void *context, con
|
||||
log_debug_metadata("Ignoring mda on device %s at offset " FMTu64,
|
||||
dev_name(mdac->area.dev),
|
||||
mdac->area.start);
|
||||
goto bad;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!vgname_from_mda(fmt, mdah, mda_is_primary(mda), &mdac->area, &pmp->vgsummary, &mdac->free_sectors, ioflags, _process_vgsummary, pmp)) {
|
||||
/* FIXME Separate fatal and non-fatal error cases? */
|
||||
goto_bad;
|
||||
if (!read_metadata_location_summary(fmt, mdah, mda_is_primary(mda), &mdac->area,
|
||||
&vgsummary, &mdac->free_sectors)) {
|
||||
if (vgsummary.zero_offset)
|
||||
return 1;
|
||||
|
||||
log_error("Failed to read metadata summary from %s", dev_name(mdac->area.dev));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
bad:
|
||||
_process_vgsummary(1, ioflags, pmp, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
static int _count_mda(struct metadata_area *mda, void *baton)
|
||||
{
|
||||
struct update_mda_baton *umb = baton;
|
||||
|
||||
umb->nr_outstanding_mdas++;
|
||||
if (!lvmcache_update_vgname_and_id(p->info, &vgsummary)) {
|
||||
log_error("Failed to save lvm summary for %s", dev_name(mdac->area.dev));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
lvmcache_del(p->info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _update_mda(struct metadata_area *mda, void *baton)
|
||||
static int _text_read(struct labeller *l, struct device *dev, void *label_buf,
|
||||
struct label **label)
|
||||
{
|
||||
struct process_mda_header_params *pmp;
|
||||
struct update_mda_baton *umb = baton;
|
||||
const struct format_type *fmt = umb->label->labeller->fmt;
|
||||
struct dm_pool *mem = umb->label->labeller->fmt->cmd->mem;
|
||||
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
||||
unsigned ioflags = umb->ioflags;
|
||||
|
||||
if (!(pmp = dm_pool_zalloc(mem, sizeof(*pmp)))) {
|
||||
log_error("struct process_mda_header_params allocation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Using the labeller struct to preserve info about
|
||||
* the last parsed vgname, vgid, creation host
|
||||
*
|
||||
* TODO: make lvmcache smarter and move this cache logic there
|
||||
*/
|
||||
|
||||
pmp->dev = mdac->area.dev;
|
||||
pmp->umb = umb;
|
||||
pmp->mda = mda;
|
||||
|
||||
if (!dev_open_readonly(mdac->area.dev)) {
|
||||
mda_set_ignored(mda, 1);
|
||||
stack;
|
||||
if (!--umb->nr_outstanding_mdas && umb->read_label_callback_fn)
|
||||
umb->read_label_callback_fn(!umb->ret, ioflags, umb->read_label_callback_context, umb->label);
|
||||
return 1;
|
||||
}
|
||||
|
||||
pmp->ret = 1;
|
||||
|
||||
if (!raw_read_mda_header_callback(fmt->cmd->mem, &mdac->area, mda_is_primary(mda), ioflags, _process_mda_header, pmp)) {
|
||||
_process_vgsummary(1, ioflags, pmp, NULL);
|
||||
stack;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (umb->read_label_callback_fn)
|
||||
return 1;
|
||||
else
|
||||
return pmp->ret;
|
||||
}
|
||||
|
||||
static int _text_read(struct labeller *l, struct device *dev, void *buf, unsigned ioflags,
|
||||
lvm_callback_fn_t read_label_callback_fn, void *read_label_callback_context)
|
||||
{
|
||||
struct label_header *lh = (struct label_header *) buf;
|
||||
struct label_header *lh = (struct label_header *) label_buf;
|
||||
struct pv_header *pvhdr;
|
||||
struct pv_header_extension *pvhdr_ext;
|
||||
struct lvmcache_info *info;
|
||||
struct disk_locn *dlocn_xl;
|
||||
uint64_t offset;
|
||||
uint32_t ext_version;
|
||||
struct dm_pool *mem = l->fmt->cmd->mem;
|
||||
struct update_mda_baton *umb;
|
||||
struct label *label;
|
||||
struct _update_mda_baton baton;
|
||||
|
||||
/*
|
||||
* PV header base
|
||||
*/
|
||||
pvhdr = (struct pv_header *) ((char *) buf + xlate32(lh->offset_xl));
|
||||
pvhdr = (struct pv_header *) ((char *) label_buf + xlate32(lh->offset_xl));
|
||||
|
||||
if (!(info = lvmcache_add(l, (char *)pvhdr->pv_uuid, dev,
|
||||
FMT_TEXT_ORPHAN_VG_NAME,
|
||||
FMT_TEXT_ORPHAN_VG_NAME, 0)))
|
||||
goto_bad;
|
||||
return_0;
|
||||
|
||||
label = lvmcache_get_label(info);
|
||||
*label = lvmcache_get_label(info);
|
||||
|
||||
lvmcache_set_device_size(info, xlate64(pvhdr->device_size_xl));
|
||||
|
||||
@ -523,41 +434,23 @@ static int _text_read(struct labeller *l, struct device *dev, void *buf, unsigne
|
||||
lvmcache_add_ba(info, offset, xlate64(dlocn_xl->size));
|
||||
dlocn_xl++;
|
||||
}
|
||||
|
||||
out:
|
||||
if (!(umb = dm_pool_zalloc(mem, sizeof(*umb)))) {
|
||||
log_error("baton allocation failed");
|
||||
goto_bad;
|
||||
baton.info = info;
|
||||
baton.label = *label;
|
||||
|
||||
/*
|
||||
* In the vg_read phase, we compare all mdas and decide which to use
|
||||
* which are bad and need repair.
|
||||
*
|
||||
* FIXME: this quits if the first mda is bad, but we need something
|
||||
* smarter to be able to use the second mda if it's good.
|
||||
*/
|
||||
if (!lvmcache_foreach_mda(info, _read_mda_header_and_metadata, &baton)) {
|
||||
log_error("Failed to scan VG from %s", dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
umb->info = info;
|
||||
umb->label = label;
|
||||
umb->ioflags = ioflags;
|
||||
umb->read_label_callback_fn = read_label_callback_fn;
|
||||
umb->read_label_callback_context = read_label_callback_context;
|
||||
|
||||
umb->ret = 1;
|
||||
|
||||
if (!lvmcache_foreach_mda(info, _count_mda, umb))
|
||||
goto_bad;
|
||||
|
||||
if (!umb->nr_outstanding_mdas) {
|
||||
lvmcache_make_valid(info);
|
||||
if (read_label_callback_fn)
|
||||
read_label_callback_fn(0, ioflags, read_label_callback_context, label);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!lvmcache_foreach_mda(info, _update_mda, umb))
|
||||
goto_bad;
|
||||
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
if (read_label_callback_fn)
|
||||
read_label_callback_fn(1, ioflags, read_label_callback_context, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _text_destroy_label(struct labeller *l __attribute__((unused)),
|
||||
|
1038
lib/label/label.c
1038
lib/label/label.c
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -38,10 +38,9 @@
|
||||
#include <sys/param.h>
|
||||
|
||||
static struct physical_volume *_pv_read(struct cmd_context *cmd,
|
||||
struct dm_pool *pvmem,
|
||||
const char *pv_name,
|
||||
struct format_instance *fid,
|
||||
uint32_t warn_flags, int scan_label_only);
|
||||
const struct format_type *fmt,
|
||||
struct volume_group *vg,
|
||||
struct lvmcache_info *info);
|
||||
|
||||
static int _alignment_overrides_default(unsigned long data_alignment,
|
||||
unsigned long default_pe_align)
|
||||
@ -330,37 +329,6 @@ bad:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int get_pv_from_vg_by_id(const struct format_type *fmt, const char *vg_name,
|
||||
const char *vgid, const char *pvid,
|
||||
struct physical_volume *pv)
|
||||
{
|
||||
struct volume_group *vg;
|
||||
struct pv_list *pvl;
|
||||
uint32_t warn_flags = WARN_PV_READ | WARN_INCONSISTENT;
|
||||
int r = 0, consistent = 0;
|
||||
|
||||
if (!(vg = vg_read_internal(fmt->cmd, vg_name, vgid, warn_flags, &consistent))) {
|
||||
log_error("get_pv_from_vg_by_id: vg_read_internal failed to read VG %s",
|
||||
vg_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dm_list_iterate_items(pvl, &vg->pvs) {
|
||||
if (id_equal(&pvl->pv->id, (const struct id *) pvid)) {
|
||||
if (!_copy_pv(fmt->cmd->mem, pv, pvl->pv)) {
|
||||
log_error("internal PV duplication failed");
|
||||
r = 0;
|
||||
goto out;
|
||||
}
|
||||
r = 1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
out:
|
||||
release_vg(vg);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _move_pv(struct volume_group *vg_from, struct volume_group *vg_to,
|
||||
const char *pv_name, int enforce_pv_from_source)
|
||||
{
|
||||
@ -719,7 +687,12 @@ int check_pv_dev_sizes(struct volume_group *vg)
|
||||
* source file. All the following and more are only used by liblvm:
|
||||
*
|
||||
* . get_pvs()
|
||||
* . get_vgids()
|
||||
* . get_vgnames()
|
||||
* . lvmcache_get_vgids()
|
||||
* . lvmcache_get_vgnames()
|
||||
* . the vg->pvs_to_write list and pv_to_write struct
|
||||
* . _pvcreate_write()
|
||||
*/
|
||||
|
||||
int vg_extend_each_pv(struct volume_group *vg, struct pvcreate_params *pp)
|
||||
@ -1442,28 +1415,24 @@ static int _pvcreate_write(struct cmd_context *cmd, struct pv_to_write *pvw)
|
||||
struct device *dev = pv->dev;
|
||||
const char *pv_name = dev_name(dev);
|
||||
|
||||
if (!label_scan_open(dev)) {
|
||||
log_error("%s not opened: device not written", pv_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pvw->new_pv) {
|
||||
/* Wipe existing label first */
|
||||
if (!label_remove(pv_dev(pv))) {
|
||||
if (!label_remove(dev)) {
|
||||
log_error("Failed to wipe existing label on %s", pv_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pvw->pp->zero) {
|
||||
log_verbose("Zeroing start of device %s", pv_name);
|
||||
if (!dev_open_quiet(dev)) {
|
||||
log_error("%s not opened: device not zeroed", pv_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dev_set(dev, UINT64_C(0), (size_t) 2048, DEV_IO_LABEL, 0)) {
|
||||
if (!dev_write_zeros(dev, 0, 2048)) {
|
||||
log_error("%s not wiped: aborting", pv_name);
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3242,9 +3211,7 @@ static int _check_mda_in_use(struct metadata_area *mda, void *_in_use)
|
||||
struct _vg_read_orphan_baton {
|
||||
struct cmd_context *cmd;
|
||||
struct volume_group *vg;
|
||||
uint32_t warn_flags;
|
||||
int consistent;
|
||||
int repair;
|
||||
const struct format_type *fmt;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -3341,8 +3308,7 @@ static int _vg_read_orphan_pv(struct lvmcache_info *info, void *baton)
|
||||
uint32_t ext_version;
|
||||
uint32_t ext_flags;
|
||||
|
||||
if (!(pv = _pv_read(b->vg->cmd, b->vg->vgmem, dev_name(lvmcache_device(info)),
|
||||
b->vg->fid, b->warn_flags, 0))) {
|
||||
if (!(pv = _pv_read(b->cmd, b->fmt, b->vg, info))) {
|
||||
stack;
|
||||
return 1;
|
||||
}
|
||||
@ -3426,8 +3392,6 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd,
|
||||
struct pv_list head;
|
||||
|
||||
dm_list_init(&head.list);
|
||||
lvmcache_label_scan(cmd);
|
||||
lvmcache_seed_infos_from_lvmetad(cmd);
|
||||
|
||||
if (!(vginfo = lvmcache_vginfo_from_vgname(orphan_vgname, NULL)))
|
||||
return_NULL;
|
||||
@ -3449,10 +3413,22 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd,
|
||||
vg->free_count = 0;
|
||||
|
||||
baton.cmd = cmd;
|
||||
baton.warn_flags = warn_flags;
|
||||
baton.fmt = fmt;
|
||||
baton.vg = vg;
|
||||
baton.consistent = 1;
|
||||
baton.repair = *consistent;
|
||||
|
||||
/*
|
||||
* vg_read for a normal VG will rescan labels for all the devices
|
||||
* in the VG, in case something changed on disk between the initial
|
||||
* label scan and acquiring the VG lock. We don't rescan labels
|
||||
* here because this is only called in two ways:
|
||||
*
|
||||
* 1. for reporting, in which case it doesn't matter if something
|
||||
* changed between the label scan and printing the PVs here
|
||||
*
|
||||
* 2. pvcreate_each_device() for pvcreate//vgcreate/vgextend,
|
||||
* which already does the label rescan after taking the
|
||||
* orphan lock.
|
||||
*/
|
||||
|
||||
while ((pvl = (struct pv_list *) dm_list_first(&head.list))) {
|
||||
dm_list_del(&pvl->list);
|
||||
@ -3464,7 +3440,6 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd,
|
||||
if (!lvmcache_foreach_pv(vginfo, _vg_read_orphan_pv, &baton))
|
||||
return_NULL;
|
||||
|
||||
*consistent = baton.consistent;
|
||||
return vg;
|
||||
}
|
||||
|
||||
@ -3786,8 +3761,8 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
struct pv_list *pvl;
|
||||
struct dm_list all_pvs;
|
||||
char uuid[64] __attribute__((aligned(8)));
|
||||
int skipped_rescan = 0;
|
||||
|
||||
unsigned seqno = 0;
|
||||
int reappeared = 0;
|
||||
struct cached_vg_fmtdata *vg_fmtdata = NULL; /* Additional format-specific data about the vg */
|
||||
unsigned use_previous_vg;
|
||||
@ -3808,7 +3783,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
if (lvmetad_used() && !use_precommitted) {
|
||||
if ((correct_vg = lvmcache_get_vg(cmd, vgname, vgid, precommitted))) {
|
||||
if ((correct_vg = lvmetad_vg_lookup(cmd, vgname, vgid))) {
|
||||
dm_list_iterate_items(pvl, &correct_vg->pvs)
|
||||
reappeared += _check_reappeared_pv(correct_vg, pvl->pv, *consistent);
|
||||
if (reappeared && *consistent)
|
||||
@ -3833,42 +3808,73 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
release_vg(correct_vg);
|
||||
return_NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* When a command reads the vg from lvmetad, and then
|
||||
* writes the vg, the write path does some disk reads
|
||||
* of the devs.
|
||||
* FIXME: when a command is going to write the vg,
|
||||
* we should just read the vg from disk entirely
|
||||
* and skip reading it from lvmetad.
|
||||
*/
|
||||
dm_list_iterate_items(pvl, &correct_vg->pvs)
|
||||
label_scan_open(pvl->pv->dev);
|
||||
|
||||
}
|
||||
|
||||
return correct_vg;
|
||||
}
|
||||
|
||||
/*
|
||||
* If cached metadata was inconsistent and *consistent is set
|
||||
* then repair it now. Otherwise just return it.
|
||||
* Also return if use_precommitted is set due to the FIXME in
|
||||
* the missing PV logic below.
|
||||
* Rescan the devices that are associated with this vg in lvmcache.
|
||||
* This repeats what was done by the command's initial label scan,
|
||||
* but only the devices associated with this VG.
|
||||
*
|
||||
* The lvmcache info about these devs is from the initial label scan
|
||||
* performed by the command before the vg lock was held. Now the VG
|
||||
* lock is held, so we rescan all the info from the devs in case
|
||||
* something changed between the initial scan and now that the lock
|
||||
* is held.
|
||||
*
|
||||
* Some commands (e.g. reporting) are fine reporting data read by
|
||||
* the label scan. It doesn't matter if the devs changed between
|
||||
* the label scan and here, we can report what was seen in the
|
||||
* scan, even though it is the old state, since we will not be
|
||||
* making any modifications. If the VG was being modified during
|
||||
* the scan, and caused us to see inconsistent metadata on the
|
||||
* different PVs in the VG, then we do want to rescan the devs
|
||||
* here to get a consistent view of the VG. Note that we don't
|
||||
* know if the scan found all the PVs in the VG at this point.
|
||||
* We don't know that until vg_read looks at the list of PVs in
|
||||
* the metadata and compares that to the devices found by the scan.
|
||||
*
|
||||
* It's possible that a change made to the VG during scan was
|
||||
* adding or removing a PV from the VG. In this case, the list
|
||||
* of devices associated with the VG in lvmcache would change
|
||||
* due to the rescan.
|
||||
*
|
||||
* The devs in the VG may be persistently inconsistent due to some
|
||||
* previous problem. In this case, rescanning the labels here will
|
||||
* find the same inconsistency. The VG repair (mistakenly done by
|
||||
* vg_read below) is supposed to fix that.
|
||||
*
|
||||
* FIXME: sort out the usage of the global lock (which is mixed up
|
||||
* with the orphan lock), and when we can tell that the global
|
||||
* lock is taken prior to the label scan, and still held here,
|
||||
* we can also skip the rescan in that case.
|
||||
*/
|
||||
if ((correct_vg = lvmcache_get_vg(cmd, vgname, vgid, precommitted)) &&
|
||||
(use_precommitted || !*consistent)) {
|
||||
*consistent = 1;
|
||||
return correct_vg;
|
||||
if (!cmd->can_use_one_scan || lvmcache_scan_mismatch(cmd, vgname, vgid)) {
|
||||
skipped_rescan = 0;
|
||||
log_debug_metadata("Rescanning devices for for %s", vgname);
|
||||
lvmcache_label_rescan_vg(cmd, vgname, vgid);
|
||||
} else {
|
||||
if (correct_vg && correct_vg->seqno > seqno)
|
||||
seqno = correct_vg->seqno;
|
||||
release_vg(correct_vg);
|
||||
correct_vg = NULL;
|
||||
log_debug_metadata("Skipped rescanning devices for %s", vgname);
|
||||
skipped_rescan = 1;
|
||||
}
|
||||
|
||||
|
||||
/* Find the vgname in the cache */
|
||||
/* If it's not there we must do full scan to be completely sure */
|
||||
if (!(fmt = lvmcache_fmt_from_vgname(cmd, vgname, vgid, 1))) {
|
||||
lvmcache_label_scan(cmd);
|
||||
if (!(fmt = lvmcache_fmt_from_vgname(cmd, vgname, vgid, 1))) {
|
||||
/* Independent MDAs aren't supported under low memory */
|
||||
if (!cmd->independent_metadata_areas && prioritized_section())
|
||||
return_NULL;
|
||||
lvmcache_force_next_label_scan();
|
||||
lvmcache_label_scan(cmd);
|
||||
if (!(fmt = lvmcache_fmt_from_vgname(cmd, vgname, vgid, 0)))
|
||||
return_NULL;
|
||||
}
|
||||
if (!(fmt = lvmcache_fmt_from_vgname(cmd, vgname, vgid, 0))) {
|
||||
log_debug_metadata("Cache did not find fmt for vgname %s", vgname);
|
||||
return_NULL;
|
||||
}
|
||||
|
||||
/* Now determine the correct vgname if none was supplied */
|
||||
@ -3886,6 +3892,36 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
if (use_precommitted && !(fmt->features & FMT_PRECOMMIT))
|
||||
use_precommitted = 0;
|
||||
|
||||
/*
|
||||
* A "format instance" is an abstraction for a VG location,
|
||||
* i.e. where a VG's metadata exists on disk.
|
||||
*
|
||||
* An fic (format_instance_ctx) is a temporary struct used
|
||||
* to create an fid (format_instance). The fid hangs around
|
||||
* and is used to create a 'vg' to which it connected (vg->fid).
|
||||
*
|
||||
* The 'fic' describes a VG in terms of fmt/name/id.
|
||||
*
|
||||
* The 'fid' describes a VG in more detail than the fic,
|
||||
* holding information about where to find the VG metadata.
|
||||
*
|
||||
* The 'vg' describes the VG in the most detail representing
|
||||
* all the VG metadata.
|
||||
*
|
||||
* The fic and fid are set up by create_instance() to describe
|
||||
* the VG location. This happens before the VG metadata is
|
||||
* assembled into the more familiar struct volume_group "vg".
|
||||
*
|
||||
* The fid has one main purpose: to keep track of the metadata
|
||||
* locations for a given VG. It does this by putting 'mda'
|
||||
* structs on fid->metadata_areas_in_use, which specify where
|
||||
* metadata is located on disk. It gets this information
|
||||
* (metadata locations for a specific VG) from the command's
|
||||
* initial label scan. The info is passed indirectly via
|
||||
* lvmcache info/vginfo structs, which are created by the
|
||||
* label scan and then copied into fid by create_instance().
|
||||
*/
|
||||
|
||||
/* create format instance with appropriate metadata area */
|
||||
fic.type = FMT_INSTANCE_MDAS | FMT_INSTANCE_AUX_MDAS;
|
||||
fic.context.vg_ref.vg_name = vgname;
|
||||
@ -3909,12 +3945,16 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
/* Ensure contents of all metadata areas match - else do recovery */
|
||||
inconsistent_mda_count=0;
|
||||
dm_list_iterate_items(mda, &fid->metadata_areas_in_use) {
|
||||
struct device *mda_dev = mda_get_device(mda);
|
||||
|
||||
use_previous_vg = 0;
|
||||
|
||||
log_debug_metadata("Reading VG %s from %s", vgname, dev_name(mda_dev));
|
||||
|
||||
if ((use_precommitted &&
|
||||
!(vg = mda->ops->vg_read_precommit(fid, vgname, mda, &vg_fmtdata, &use_previous_vg, 0)) && !use_previous_vg) ||
|
||||
!(vg = mda->ops->vg_read_precommit(fid, vgname, mda, &vg_fmtdata, &use_previous_vg)) && !use_previous_vg) ||
|
||||
(!use_precommitted &&
|
||||
!(vg = mda->ops->vg_read(fid, vgname, mda, &vg_fmtdata, &use_previous_vg, 0, 0)) && !use_previous_vg)) {
|
||||
!(vg = mda->ops->vg_read(fid, vgname, mda, &vg_fmtdata, &use_previous_vg)) && !use_previous_vg)) {
|
||||
inconsistent = 1;
|
||||
vg_fmtdata = NULL;
|
||||
continue;
|
||||
@ -3933,10 +3973,8 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
|
||||
/* FIXME Also ensure contents same - checksum compare? */
|
||||
if (correct_vg->seqno != vg->seqno) {
|
||||
if (cmd->metadata_read_only)
|
||||
log_very_verbose("Not repairing VG %s metadata seqno (%d != %d) "
|
||||
"as global/metadata_read_only is set.",
|
||||
vgname, vg->seqno, correct_vg->seqno);
|
||||
if (cmd->metadata_read_only || skipped_rescan)
|
||||
log_warn("Not repairing metadata for VG %s.", vgname);
|
||||
else
|
||||
inconsistent = 1;
|
||||
|
||||
@ -3997,7 +4035,29 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
return_NULL;
|
||||
}
|
||||
|
||||
log_debug_metadata("Empty mda found for VG %s.", vgname);
|
||||
log_debug_metadata("Empty mda found for VG %s on %s.",
|
||||
vgname, dev_name(pvl->pv->dev));
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* If we are going to do any repair we have to be using
|
||||
* the latest metadata on disk, so we have to rescan devs
|
||||
* if we skipped that at the start of the vg_read. We'll
|
||||
* likely come back through here, but without having
|
||||
* skipped_rescan.
|
||||
*
|
||||
* FIXME: in some cases we don't want to do this.
|
||||
*/
|
||||
if (skipped_rescan && cmd->can_use_one_scan) {
|
||||
log_debug_metadata("Restarting read to rescan devs.");
|
||||
cmd->can_use_one_scan = 0;
|
||||
release_vg(correct_vg);
|
||||
correct_vg = NULL;
|
||||
lvmcache_del(info);
|
||||
label_read(pvl->pv->dev, NULL, 0);
|
||||
goto restart_scan;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (inconsistent_mdas)
|
||||
continue;
|
||||
@ -4076,8 +4136,6 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
/* Independent MDAs aren't supported under low memory */
|
||||
if (!cmd->independent_metadata_areas && prioritized_section())
|
||||
return_NULL;
|
||||
lvmcache_force_next_label_scan();
|
||||
lvmcache_label_scan(cmd);
|
||||
if (!(fmt = lvmcache_fmt_from_vgname(cmd, vgname, vgid, 0)))
|
||||
return_NULL;
|
||||
|
||||
@ -4104,9 +4162,9 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
use_previous_vg = 0;
|
||||
|
||||
if ((use_precommitted &&
|
||||
!(vg = mda->ops->vg_read_precommit(fid, vgname, mda, &vg_fmtdata, &use_previous_vg, 0)) && !use_previous_vg) ||
|
||||
!(vg = mda->ops->vg_read_precommit(fid, vgname, mda, &vg_fmtdata, &use_previous_vg)) && !use_previous_vg) ||
|
||||
(!use_precommitted &&
|
||||
!(vg = mda->ops->vg_read(fid, vgname, mda, &vg_fmtdata, &use_previous_vg, 0, 0)) && !use_previous_vg)) {
|
||||
!(vg = mda->ops->vg_read(fid, vgname, mda, &vg_fmtdata, &use_previous_vg)) && !use_previous_vg)) {
|
||||
inconsistent = 1;
|
||||
vg_fmtdata = NULL;
|
||||
continue;
|
||||
@ -4137,10 +4195,8 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
/* FIXME Also ensure contents same - checksums same? */
|
||||
if (correct_vg->seqno != vg->seqno) {
|
||||
/* Ignore inconsistent seqno if told to skip repair logic */
|
||||
if (cmd->metadata_read_only)
|
||||
log_very_verbose("Not repairing VG %s metadata seqno (%d != %d) "
|
||||
"as global/metadata_read_only is set.",
|
||||
vgname, vg->seqno, correct_vg->seqno);
|
||||
if (cmd->metadata_read_only || skipped_rescan)
|
||||
log_warn("Not repairing metadata for VG %s.", vgname);
|
||||
else
|
||||
inconsistent = 1;
|
||||
|
||||
@ -4220,6 +4276,13 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
return correct_vg;
|
||||
}
|
||||
|
||||
if (skipped_rescan) {
|
||||
log_warn("Not repairing metadata for VG %s.", vgname);
|
||||
_free_pv_list(&all_pvs);
|
||||
release_vg(correct_vg);
|
||||
return_NULL;
|
||||
}
|
||||
|
||||
/* Don't touch if vgids didn't match */
|
||||
if (inconsistent_vgid) {
|
||||
log_warn("WARNING: Inconsistent metadata UUIDs found for "
|
||||
@ -4266,14 +4329,16 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
/* We have the VG now finally, check if PV ext info is in sync with VG metadata. */
|
||||
if (!_check_or_repair_pv_ext(cmd, correct_vg, *consistent, &inconsistent_pvs)) {
|
||||
if (!_check_or_repair_pv_ext(cmd, correct_vg,
|
||||
skipped_rescan ? 0 : *consistent,
|
||||
&inconsistent_pvs)) {
|
||||
release_vg(correct_vg);
|
||||
return_NULL;
|
||||
}
|
||||
|
||||
*consistent = !inconsistent_pvs;
|
||||
|
||||
if (correct_vg && *consistent) {
|
||||
if (correct_vg && *consistent && !skipped_rescan) {
|
||||
if (update_old_pv_ext && !_vg_update_old_pv_ext_if_needed(correct_vg)) {
|
||||
release_vg(correct_vg);
|
||||
return_NULL;
|
||||
@ -4499,21 +4564,10 @@ static struct volume_group *_vg_read_by_vgid(struct cmd_context *cmd,
|
||||
unsigned precommitted)
|
||||
{
|
||||
const char *vgname;
|
||||
struct dm_list *vgnames;
|
||||
struct volume_group *vg;
|
||||
struct dm_str_list *strl;
|
||||
uint32_t warn_flags = WARN_PV_READ | WARN_INCONSISTENT;
|
||||
int consistent = 0;
|
||||
|
||||
/* Is corresponding vgname already cached? */
|
||||
if (lvmcache_vgid_is_cached(vgid)) {
|
||||
if ((vg = _vg_read(cmd, NULL, vgid, warn_flags, &consistent, precommitted)) &&
|
||||
id_equal(&vg->id, (const struct id *)vgid)) {
|
||||
return vg;
|
||||
}
|
||||
release_vg(vg);
|
||||
}
|
||||
|
||||
/*
|
||||
* When using lvmlockd we should never reach this point.
|
||||
* The VG is locked, then vg_read() is done, which gets
|
||||
@ -4526,36 +4580,52 @@ static struct volume_group *_vg_read_by_vgid(struct cmd_context *cmd,
|
||||
|
||||
/* Mustn't scan if memory locked: ensure cache gets pre-populated! */
|
||||
if (critical_section())
|
||||
return_NULL;
|
||||
log_debug_metadata("Reading VG by vgid in critical section pre %d vgid %.8s", precommitted, vgid);
|
||||
|
||||
/* FIXME Need a genuine read by ID here - don't vg_read_internal by name! */
|
||||
/* FIXME Disabled vgrenames while active for now because we aren't
|
||||
* allowed to do a full scan here any more. */
|
||||
if (!(vgname = lvmcache_vgname_from_vgid(cmd->mem, vgid))) {
|
||||
log_debug_metadata("Reading VG by vgid %.8s no VG name found, retrying.", vgid);
|
||||
lvmcache_destroy(cmd, 0, 0);
|
||||
label_scan_destroy(cmd);
|
||||
lvmcache_label_scan(cmd);
|
||||
}
|
||||
|
||||
// The slow way - full scan required to cope with vgrename
|
||||
lvmcache_force_next_label_scan();
|
||||
lvmcache_label_scan(cmd);
|
||||
if (!(vgnames = get_vgnames(cmd, 0))) {
|
||||
log_error("vg_read_by_vgid: get_vgnames failed");
|
||||
if (!(vgname = lvmcache_vgname_from_vgid(cmd->mem, vgid))) {
|
||||
log_debug_metadata("Reading VG by vgid %.8s no VG name found.", vgid);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dm_list_iterate_items(strl, vgnames) {
|
||||
vgname = strl->str;
|
||||
if (!vgname)
|
||||
continue; // FIXME Unnecessary?
|
||||
consistent = 0;
|
||||
if ((vg = _vg_read(cmd, vgname, vgid, warn_flags, &consistent, precommitted)) &&
|
||||
id_equal(&vg->id, (const struct id *)vgid)) {
|
||||
if (!consistent) {
|
||||
release_vg(vg);
|
||||
return NULL;
|
||||
}
|
||||
return vg;
|
||||
}
|
||||
release_vg(vg);
|
||||
consistent = 0;
|
||||
|
||||
label_scan_setup_bcache();
|
||||
|
||||
if (!(vg = _vg_read(cmd, vgname, vgid, warn_flags, &consistent, precommitted))) {
|
||||
log_error("Rescan devices to look for missing VG.");
|
||||
goto scan;
|
||||
}
|
||||
|
||||
if (vg_missing_pv_count(vg)) {
|
||||
log_error("Rescan devices to look for missing PVs.");
|
||||
release_vg(vg);
|
||||
goto scan;
|
||||
}
|
||||
|
||||
label_scan_destroy(cmd); /* drop bcache to close devs, keep lvmcache */
|
||||
return vg;
|
||||
|
||||
scan:
|
||||
lvmcache_destroy(cmd, 0, 0);
|
||||
label_scan_destroy(cmd);
|
||||
lvmcache_label_scan(cmd);
|
||||
|
||||
if (!(vg = _vg_read(cmd, vgname, vgid, warn_flags, &consistent, precommitted)))
|
||||
goto fail;
|
||||
|
||||
label_scan_destroy(cmd); /* drop bcache to close devs, keep lvmcache */
|
||||
return vg;
|
||||
|
||||
fail:
|
||||
label_scan_destroy(cmd); /* drop bache to close devs, keep lvmcache */
|
||||
log_debug_metadata("Reading VG by vgid %.8s not found.", vgid);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -4571,7 +4641,7 @@ struct logical_volume *lv_from_lvid(struct cmd_context *cmd, const char *lvid_s,
|
||||
|
||||
log_very_verbose("Finding %svolume group for uuid %s", precommitted ? "precommitted " : "", lvid_s);
|
||||
if (!(vg = _vg_read_by_vgid(cmd, (const char *)lvid->id[0].uuid, precommitted))) {
|
||||
log_error("Volume group for uuid not found: %s", lvid_s);
|
||||
log_error("Reading VG not found for LVID %s", lvid_s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -4640,86 +4710,40 @@ const char *find_vgname_from_pvname(struct cmd_context *cmd,
|
||||
return find_vgname_from_pvid(cmd, pvid);
|
||||
}
|
||||
|
||||
/* FIXME Use label functions instead of PV functions */
|
||||
static struct physical_volume *_pv_read(struct cmd_context *cmd,
|
||||
struct dm_pool *pvmem,
|
||||
const char *pv_name,
|
||||
struct format_instance *fid,
|
||||
uint32_t warn_flags, int scan_label_only)
|
||||
const struct format_type *fmt,
|
||||
struct volume_group *vg,
|
||||
struct lvmcache_info *info)
|
||||
{
|
||||
struct physical_volume *pv;
|
||||
struct label *label;
|
||||
struct lvmcache_info *info;
|
||||
struct device *dev;
|
||||
const struct format_type *fmt;
|
||||
int found;
|
||||
struct device *dev = lvmcache_device(info);
|
||||
|
||||
if (!(dev = dev_cache_get(pv_name, cmd->filter)))
|
||||
return_NULL;
|
||||
|
||||
if (lvmetad_used()) {
|
||||
info = lvmcache_info_from_pvid(dev->pvid, dev, 0);
|
||||
if (!info) {
|
||||
if (!lvmetad_pv_lookup_by_dev(cmd, dev, &found))
|
||||
return_NULL;
|
||||
if (!found) {
|
||||
if (warn_flags & WARN_PV_READ)
|
||||
log_error("No physical volume found in lvmetad cache for %s",
|
||||
pv_name);
|
||||
return NULL;
|
||||
}
|
||||
if (!(info = lvmcache_info_from_pvid(dev->pvid, dev, 0))) {
|
||||
if (warn_flags & WARN_PV_READ)
|
||||
log_error("No cache info in lvmetad cache for %s.",
|
||||
pv_name);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
label = lvmcache_get_label(info);
|
||||
} else {
|
||||
if (!(label_read(dev, &label, UINT64_C(0)))) {
|
||||
if (warn_flags & WARN_PV_READ)
|
||||
log_error("No physical volume label read from %s",
|
||||
pv_name);
|
||||
return NULL;
|
||||
}
|
||||
info = (struct lvmcache_info *) label->info;
|
||||
}
|
||||
|
||||
fmt = lvmcache_fmt(info);
|
||||
|
||||
pv = _alloc_pv(pvmem, dev);
|
||||
if (!pv) {
|
||||
log_error("pv allocation for '%s' failed", pv_name);
|
||||
if (!(pv = _alloc_pv(vg->vgmem, NULL))) {
|
||||
log_error("pv allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pv->label_sector = label->sector;
|
||||
|
||||
/* FIXME Move more common code up here */
|
||||
if (!(lvmcache_fmt(info)->ops->pv_read(lvmcache_fmt(info), pv_name, pv, scan_label_only))) {
|
||||
log_error("Failed to read existing physical volume '%s'",
|
||||
pv_name);
|
||||
goto bad;
|
||||
if (fmt->ops->pv_read) {
|
||||
/* format1 and pool */
|
||||
if (!(fmt->ops->pv_read(fmt, dev_name(dev), pv, 0))) {
|
||||
log_error("Failed to read existing physical volume '%s'", dev_name(dev));
|
||||
goto bad;
|
||||
}
|
||||
} else {
|
||||
/* format text */
|
||||
if (!lvmcache_populate_pv_fields(info, vg, pv))
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
if (!pv->size)
|
||||
goto bad;
|
||||
|
||||
if (!alloc_pv_segment_whole_pv(pvmem, pv))
|
||||
if (!alloc_pv_segment_whole_pv(vg->vgmem, pv))
|
||||
goto_bad;
|
||||
|
||||
if (fid)
|
||||
lvmcache_fid_add_mdas(info, fid, (const char *) &pv->id, ID_LEN);
|
||||
else {
|
||||
lvmcache_fid_add_mdas(info, fmt->orphan_vg->fid, (const char *) &pv->id, ID_LEN);
|
||||
pv_set_fid(pv, fmt->orphan_vg->fid);
|
||||
}
|
||||
|
||||
lvmcache_fid_add_mdas(info, vg->fid, (const char *) &pv->id, ID_LEN);
|
||||
pv_set_fid(pv, vg->fid);
|
||||
return pv;
|
||||
bad:
|
||||
free_pv_fid(pv);
|
||||
dm_pool_free(pvmem, pv);
|
||||
dm_pool_free(vg->vgmem, pv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -5621,7 +5645,6 @@ uint32_t vg_lock_newname(struct cmd_context *cmd, const char *vgname)
|
||||
unlock_vg(cmd, NULL, vgname);
|
||||
return FAILED_LOCKING;
|
||||
}
|
||||
lvmcache_force_next_label_scan();
|
||||
lvmcache_label_scan(cmd);
|
||||
if (!lvmcache_fmt_from_vgname(cmd, vgname, NULL, 0))
|
||||
return SUCCESS; /* vgname not found after scanning */
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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:
|
||||
;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
65
make.tmpl.in
65
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\
|
||||
|
@ -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
|
||||
|
||||
|
1
old-tests/config/.gitignore
vendored
1
old-tests/config/.gitignore
vendored
@ -1 +0,0 @@
|
||||
!Makefile
|
@ -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
|
@ -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;
|
||||
}
|
@ -1 +0,0 @@
|
||||
foo = []
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
@ -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)
|
||||
{
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
@ -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
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
}
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -1,2 +1 @@
|
||||
export LVM_TEST_LOCKING=3
|
||||
export LVM_TEST_LVM1=1
|
||||
|
@ -1,2 +1 @@
|
||||
export LVM_TEST_LOCKING=1
|
||||
export LVM_TEST_LVM1=1
|
||||
|
@ -1,3 +1,2 @@
|
||||
export LVM_TEST_LOCKING=3
|
||||
export LVM_TEST_DEVDIR=/dev
|
||||
export LVM_TEST_LVM1=1
|
||||
|
@ -1,3 +1,2 @@
|
||||
export LVM_TEST_LOCKING=1
|
||||
export LVM_TEST_DEVDIR=/dev
|
||||
export LVM_TEST_LVM1=1
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright (C) 2014 Red Hat, Inc. All rights reserved.
|
||||
# Copyright (C) 2018 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This copyrighted material is made available to anyone wishing to use,
|
||||
# modify, copy, or redistribute it subject to the terms and conditions
|
||||
@ -16,26 +16,27 @@ SKIP_WITH_LVMLOCKD=1
|
||||
|
||||
. lib/inittest
|
||||
|
||||
aux prepare_pvs 3
|
||||
aux prepare_pvs 3 100
|
||||
get_devs
|
||||
|
||||
vgcreate -s 64k "$vg" "${DEVICES[@]}"
|
||||
|
||||
lvcreate -aey -l10 --type mirror -m1 -n $lv1 $vg "$dev1" "$dev2"
|
||||
# Use zero devices for big mirror legs
|
||||
aux zero_dev "$dev2" $(get first_extent_sector "$dev2"):
|
||||
aux zero_dev "$dev3" $(get first_extent_sector "$dev3"):
|
||||
|
||||
# Slow down device so we are able to start next conversion in parallel
|
||||
aux delay_dev "$dev3" 0 200
|
||||
lvcreate -aey -L90 --type mirror --corelog --regionsize 16k -m1 -n $lv1 $vg "$dev1" "$dev2"
|
||||
|
||||
lvconvert -m+1 -b $vg/$lv1 "$dev3"
|
||||
|
||||
# To fix - wait helps here....
|
||||
#lvconvert $vg/$lv1
|
||||
|
||||
# We want here ongoing conversion
|
||||
|
||||
lvs -a -o+seg_pe_ranges $vg
|
||||
|
||||
# Now it should be able to drop 2nd. leg
|
||||
lvconvert -m-1 $vg/$lv1 "$dev2"
|
||||
|
||||
lvs -a $vg
|
||||
|
||||
#
|
||||
# It fails so use 'should' and -vvvv for now
|
||||
#
|
||||
should lvconvert -vvvv -m-1 $vg/$lv1 "$dev2"
|
||||
|
||||
vgremove -f $vg
|
||||
|
@ -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
|
||||
|
@ -25,6 +25,9 @@ vgextend $vg1 "$dev1"
|
||||
|
||||
dd if=badmda of="$dev1" bs=256K count=1
|
||||
|
||||
# the vg_read in vgck (and other commands) will repair the metadata
|
||||
vgck $vg1
|
||||
|
||||
# dev1 is part of vg1 (as witnessed by metadata on dev2 and dev3), but its mda
|
||||
# was corrupt (written over by a backup from time dev1 was an orphan)
|
||||
check pv_field "$dev1" vg_name $vg1
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user