mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
Some new features.
This commit is contained in:
parent
d1d9800ef1
commit
5a52dca9c2
21
INSTALL
21
INSTALL
@ -6,8 +6,8 @@ LVM2 installation
|
||||
Ensure the device-mapper has been installed on the machine.
|
||||
|
||||
The device-mapper should be in the kernel (look for 'device-mapper'
|
||||
messages in the kernel logs) and /usr/include/libdevmapper.h should
|
||||
be present.
|
||||
messages in the kernel logs) and /usr/include/libdevmapper.h
|
||||
and libdevmapper.so should be present.
|
||||
|
||||
The device-mapper is available from:
|
||||
ftp://ftp.sistina.com/pub/LVM2/device-mapper/
|
||||
@ -17,9 +17,15 @@ LVM2 installation
|
||||
|
||||
Run the 'configure' script from the top directory.
|
||||
|
||||
If you do not have GNU readline (http://www.gnu.org/directory/readline.html)
|
||||
installed use
|
||||
./configure --disable-readline
|
||||
If you wish to use the built-in LVM2 shell and have GNU readline
|
||||
installed (http://www.gnu.org/directory/readline.html) use:
|
||||
./configure --enable-readline
|
||||
|
||||
If you don't want to include the LVM1 backwards-compatibility code use:
|
||||
./configure --with-lvm1=none
|
||||
|
||||
To separate the LVM1 support into a shared library loaded by lvm.conf use:
|
||||
./configure --with-lvm1=shared
|
||||
|
||||
|
||||
3) Build and install LVM2.
|
||||
@ -31,6 +37,9 @@ LVM2 installation
|
||||
|
||||
The tools will work fine without a configuration file being
|
||||
present, but you ought to review the example file in doc/example.conf.
|
||||
For example, specifying the devices that LVM2 is to use should
|
||||
For example, specifying the devices that LVM2 is to use can
|
||||
make the tools run more efficiently - and avoid scanning /dev/cdrom!
|
||||
|
||||
Please also refer to the WHATS_NEW file and the manual pages for the
|
||||
individual commands.
|
||||
|
||||
|
18
INTRO
18
INTRO
@ -1,18 +0,0 @@
|
||||
An introduction to LVM2
|
||||
=======================
|
||||
|
||||
Background
|
||||
|
||||
|
||||
Compatibility with LVM1
|
||||
|
||||
|
||||
New features
|
||||
|
||||
|
||||
Missing features
|
||||
|
||||
|
||||
Future enhancements
|
||||
|
||||
|
@ -23,7 +23,8 @@ VPATH = @srcdir@
|
||||
SUBDIRS = include man lib tools
|
||||
|
||||
ifeq ($(MAKECMDGOALS),distclean)
|
||||
SUBDIRS += test/mm test/device test/format1 test/regex test/filters
|
||||
SUBDIRS += lib/format1 \
|
||||
test/mm test/device test/format1 test/regex test/filters
|
||||
endif
|
||||
|
||||
include make.tmpl
|
||||
|
4
README
4
README
@ -1,10 +1,10 @@
|
||||
This directory contains a beta release of LMV2, the new version of
|
||||
This directory contains a beta release of LVM2, the new version of
|
||||
the userland LVM tools designed for the new device-mapper for
|
||||
the Linux kernel.
|
||||
|
||||
The device-mapper needs to be installed before compiling these LVM2 tools.
|
||||
|
||||
For more information about LVM2 read the INTRO file.
|
||||
For more information about LVM2 read the WHATS_NEW file.
|
||||
Installation instructions are in INSTALL.
|
||||
|
||||
This is beta-quality software, released for testing purposes only.
|
||||
|
28
TODO
28
TODO
@ -1,28 +0,0 @@
|
||||
before 2.0
|
||||
-----------
|
||||
|
||||
vgexport
|
||||
vgimport
|
||||
snapshots
|
||||
pvmove
|
||||
device-mapper support for 2.5 kernel series
|
||||
review FIXMEs
|
||||
extra validation & full consistency checks in format1 with LVM1
|
||||
partial activation (aka VG quorum)
|
||||
error message review
|
||||
locking during metadata changes
|
||||
format2 with atomic transactions
|
||||
bidirectional format1/format2 migration tool
|
||||
persistent minors
|
||||
statistics target and tool support
|
||||
review tool exit codes for LVM1 compatibility
|
||||
|
||||
before 2.1
|
||||
----------
|
||||
|
||||
e2fsadm
|
||||
lvmsadc
|
||||
lvmsar
|
||||
pvdata
|
||||
vgsplit
|
||||
vgmknodes
|
86
WHATS_NEW
Normal file
86
WHATS_NEW
Normal file
@ -0,0 +1,86 @@
|
||||
Mondy 18th November 2002
|
||||
========================
|
||||
|
||||
The new format of LVM metadata is ready for you to test!
|
||||
We expect it to be more efficient and more robust than the original format.
|
||||
It's more compact and supports transactional changes and replication.
|
||||
Should things go wrong on a system, it's human-readable (and editable).
|
||||
|
||||
Please report any problems you find to the mailing list,
|
||||
linux-lvm@sistina.com. The software has NOT yet been thoroughly
|
||||
tested and so quite possibly there'll still be some bugs in it.
|
||||
Be aware of the disclaimer in the COPYING file.
|
||||
|
||||
While testing, we recommend turning logging on in the configuration file
|
||||
to provide us with diagnostic information:
|
||||
log {
|
||||
file="/tmp/lvm2.log"
|
||||
level=6
|
||||
}
|
||||
|
||||
You should schedule regular backups of your configuration file and
|
||||
metadata backups and archives (normally kept under /etc/lvm).
|
||||
|
||||
Please read docs/example.conf and "man lvm.conf" to find out more about
|
||||
the configuration file.
|
||||
|
||||
To convert an existing volume group called vg1 to the new format using
|
||||
the default settings, use "vgconvert -M2 vg1". See "man vgconvert".
|
||||
|
||||
-M (or --metadatatype in its long form) is a new flag to indicate which
|
||||
format of metadata the command should use for anything it creates.
|
||||
Currently, the valid types are "lvm1" and "lvm2" and they can be
|
||||
abbreviated to "1" and "2" respectively. The default value for this
|
||||
flag can be changed in the global section in the config file.
|
||||
|
||||
Backwards-compatible support for the original LVM1 metadata format is
|
||||
maintained, but it can be moved into a shared library or removed
|
||||
completely with configure's --with-lvm1 option.
|
||||
|
||||
Under LVM2, the basic unit of metadata is the volume group. Different
|
||||
volume groups can use different formats of metadata - vg1 could use
|
||||
the original LVM1 format while vg2 used the new format - but you can't
|
||||
mix formats within a volume group. So to add a PV to an LVM2-format
|
||||
volume group you must run "pvcreate -M2" on it, followed by "vgextend".
|
||||
|
||||
With LVM2-format metadata, lvextend will let you specify striping
|
||||
parameters. So an LV could consist of two or more "segments" - the
|
||||
first segment could have 3 stripes while the second segment has just 2.
|
||||
|
||||
LVM2 maintains a backup of the current metadata for each volume group
|
||||
in /etc/lvm/backup, and puts copies of previous versions in
|
||||
/etc/lvm/archive. "vgcfgbackup" and "vgcfgrestore" can be used to
|
||||
create and restore from these files. If you fully understand what
|
||||
you're doing, metadata can be changed by editing a copy of a current
|
||||
backup file and using vgcfgrestore to reload it.
|
||||
|
||||
Please read the pvcreate man page for more information on the new
|
||||
format for metadata.
|
||||
|
||||
All tools that can change things have a --test flag which can be used
|
||||
to check the effect of a set of cmdline args without really making the
|
||||
changes.
|
||||
|
||||
|
||||
What's not finished?
|
||||
====================
|
||||
The internal cache. If you turn on debugging output you'll see lots of
|
||||
repeated disk reads, many of which will eventually get optimised out.
|
||||
|
||||
--test sometimes causes a command to fail (e.g. vgconvert --test) even
|
||||
though the real command would work: again, fixing this is waiting for
|
||||
the work on the cache.
|
||||
|
||||
Several of the tools do not yet contain the logic to handle full
|
||||
recovery: combinations of pvcreate and vgcfgrestore may sometimes be
|
||||
needed to restore metadata if a tool gets interrupted or crashes or
|
||||
finds something unexpected. This applies particularly to tools that
|
||||
work on more than one volume group at once (e.g. vgsplit).
|
||||
|
||||
Display output. Some metadata information cannot yet be displayed.
|
||||
Work has started on new display tools.
|
||||
|
||||
Recovery tools to salvage "lost" metadata directly from the disks:
|
||||
but we hope the new format will mean such tools are hardly ever needed!
|
||||
|
||||
|
196
configure
vendored
196
configure
vendored
@ -16,13 +16,16 @@ ac_help="$ac_help
|
||||
--with-user=USER Set the owner of installed files "
|
||||
ac_help="$ac_help
|
||||
--with-group=GROUP Set the group owner of installed files "
|
||||
ac_help="$ac_help
|
||||
--with-lvm1=TYPE LVM1 metadata support: internal/shared/none
|
||||
[TYPE=internal] "
|
||||
ac_help="$ac_help
|
||||
--enable-jobs=NUM Number of jobs to run simultaneously"
|
||||
ac_help="$ac_help
|
||||
--enable-static_link Use this to link the tools to the liblvm library
|
||||
statically. Default is dynamic linking"
|
||||
ac_help="$ac_help
|
||||
--disable-readline Disable readline support"
|
||||
--enable-readline Enable readline support"
|
||||
|
||||
# Initialize some variables set by options.
|
||||
# The variables have the same names as the options, with
|
||||
@ -559,7 +562,7 @@ do
|
||||
# Extract the first word of "$ac_prog", so it can be a program name with args.
|
||||
set dummy $ac_prog; ac_word=$2
|
||||
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
|
||||
echo "configure:563: checking for $ac_word" >&5
|
||||
echo "configure:566: checking for $ac_word" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
@ -591,7 +594,7 @@ done
|
||||
# Extract the first word of "gcc", so it can be a program name with args.
|
||||
set dummy gcc; ac_word=$2
|
||||
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
|
||||
echo "configure:595: checking for $ac_word" >&5
|
||||
echo "configure:598: checking for $ac_word" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
@ -621,7 +624,7 @@ if test -z "$CC"; then
|
||||
# Extract the first word of "cc", so it can be a program name with args.
|
||||
set dummy cc; ac_word=$2
|
||||
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
|
||||
echo "configure:625: checking for $ac_word" >&5
|
||||
echo "configure:628: checking for $ac_word" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
@ -672,7 +675,7 @@ fi
|
||||
# Extract the first word of "cl", so it can be a program name with args.
|
||||
set dummy cl; ac_word=$2
|
||||
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
|
||||
echo "configure:676: checking for $ac_word" >&5
|
||||
echo "configure:679: checking for $ac_word" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
@ -704,7 +707,7 @@ fi
|
||||
fi
|
||||
|
||||
echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
|
||||
echo "configure:708: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
|
||||
echo "configure:711: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
|
||||
|
||||
ac_ext=c
|
||||
# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
|
||||
@ -715,12 +718,12 @@ cross_compiling=$ac_cv_prog_cc_cross
|
||||
|
||||
cat > conftest.$ac_ext << EOF
|
||||
|
||||
#line 719 "configure"
|
||||
#line 722 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
main(){return(0);}
|
||||
EOF
|
||||
if { (eval echo configure:724: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
if { (eval echo configure:727: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
ac_cv_prog_cc_works=yes
|
||||
# If we can't run a trivial program, we are probably using a cross compiler.
|
||||
if (./conftest; exit) 2>/dev/null; then
|
||||
@ -746,12 +749,12 @@ if test $ac_cv_prog_cc_works = no; then
|
||||
{ echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
|
||||
fi
|
||||
echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
|
||||
echo "configure:750: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
|
||||
echo "configure:753: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
|
||||
echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
|
||||
cross_compiling=$ac_cv_prog_cc_cross
|
||||
|
||||
echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
|
||||
echo "configure:755: checking whether we are using GNU C" >&5
|
||||
echo "configure:758: checking whether we are using GNU C" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
@ -760,7 +763,7 @@ else
|
||||
yes;
|
||||
#endif
|
||||
EOF
|
||||
if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:764: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
|
||||
if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:767: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
|
||||
ac_cv_prog_gcc=yes
|
||||
else
|
||||
ac_cv_prog_gcc=no
|
||||
@ -779,7 +782,7 @@ ac_test_CFLAGS="${CFLAGS+set}"
|
||||
ac_save_CFLAGS="$CFLAGS"
|
||||
CFLAGS=
|
||||
echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
|
||||
echo "configure:783: checking whether ${CC-cc} accepts -g" >&5
|
||||
echo "configure:786: checking whether ${CC-cc} accepts -g" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
@ -822,7 +825,7 @@ fi
|
||||
# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
|
||||
# ./install, which can be erroneously created by make from ./install.sh.
|
||||
echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
|
||||
echo "configure:826: checking for a BSD compatible install" >&5
|
||||
echo "configure:829: checking for a BSD compatible install" >&5
|
||||
if test -z "$INSTALL"; then
|
||||
if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
@ -875,7 +878,7 @@ test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
|
||||
test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
|
||||
|
||||
echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6
|
||||
echo "configure:879: checking whether ln -s works" >&5
|
||||
echo "configure:882: checking whether ln -s works" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
@ -896,7 +899,7 @@ else
|
||||
fi
|
||||
|
||||
echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
|
||||
echo "configure:900: checking whether ${MAKE-make} sets \${MAKE}" >&5
|
||||
echo "configure:903: checking whether ${MAKE-make} sets \${MAKE}" >&5
|
||||
set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
|
||||
if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
@ -925,7 +928,7 @@ fi
|
||||
# Extract the first word of "ranlib", so it can be a program name with args.
|
||||
set dummy ranlib; ac_word=$2
|
||||
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
|
||||
echo "configure:929: checking for $ac_word" >&5
|
||||
echo "configure:932: checking for $ac_word" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
@ -958,12 +961,12 @@ for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h
|
||||
do
|
||||
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
|
||||
echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6
|
||||
echo "configure:962: checking for $ac_hdr that defines DIR" >&5
|
||||
echo "configure:965: checking for $ac_hdr that defines DIR" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 967 "configure"
|
||||
#line 970 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <sys/types.h>
|
||||
#include <$ac_hdr>
|
||||
@ -971,7 +974,7 @@ int main() {
|
||||
DIR *dirp = 0;
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:975: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
|
||||
if { (eval echo configure:978: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
|
||||
rm -rf conftest*
|
||||
eval "ac_cv_header_dirent_$ac_safe=yes"
|
||||
else
|
||||
@ -996,7 +999,7 @@ done
|
||||
# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
|
||||
if test $ac_header_dirent = dirent.h; then
|
||||
echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6
|
||||
echo "configure:1000: checking for opendir in -ldir" >&5
|
||||
echo "configure:1003: checking for opendir in -ldir" >&5
|
||||
ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'`
|
||||
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
@ -1004,7 +1007,7 @@ else
|
||||
ac_save_LIBS="$LIBS"
|
||||
LIBS="-ldir $LIBS"
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1008 "configure"
|
||||
#line 1011 "configure"
|
||||
#include "confdefs.h"
|
||||
/* Override any gcc2 internal prototype to avoid an error. */
|
||||
/* We use char because int might match the return type of a gcc2
|
||||
@ -1015,7 +1018,7 @@ int main() {
|
||||
opendir()
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:1019: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
if { (eval echo configure:1022: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
rm -rf conftest*
|
||||
eval "ac_cv_lib_$ac_lib_var=yes"
|
||||
else
|
||||
@ -1037,7 +1040,7 @@ fi
|
||||
|
||||
else
|
||||
echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6
|
||||
echo "configure:1041: checking for opendir in -lx" >&5
|
||||
echo "configure:1044: checking for opendir in -lx" >&5
|
||||
ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'`
|
||||
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
@ -1045,7 +1048,7 @@ else
|
||||
ac_save_LIBS="$LIBS"
|
||||
LIBS="-lx $LIBS"
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1049 "configure"
|
||||
#line 1052 "configure"
|
||||
#include "confdefs.h"
|
||||
/* Override any gcc2 internal prototype to avoid an error. */
|
||||
/* We use char because int might match the return type of a gcc2
|
||||
@ -1056,7 +1059,7 @@ int main() {
|
||||
opendir()
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:1060: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
if { (eval echo configure:1063: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
rm -rf conftest*
|
||||
eval "ac_cv_lib_$ac_lib_var=yes"
|
||||
else
|
||||
@ -1079,7 +1082,7 @@ fi
|
||||
fi
|
||||
|
||||
echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
|
||||
echo "configure:1083: checking how to run the C preprocessor" >&5
|
||||
echo "configure:1086: checking how to run the C preprocessor" >&5
|
||||
# On Suns, sometimes $CPP names a directory.
|
||||
if test -n "$CPP" && test -d "$CPP"; then
|
||||
CPP=
|
||||
@ -1094,13 +1097,13 @@ else
|
||||
# On the NeXT, cc -E runs the code through the compiler's parser,
|
||||
# not just through cpp.
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1098 "configure"
|
||||
#line 1101 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <assert.h>
|
||||
Syntax Error
|
||||
EOF
|
||||
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
|
||||
{ (eval echo configure:1104: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
|
||||
{ (eval echo configure:1107: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
|
||||
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
|
||||
if test -z "$ac_err"; then
|
||||
:
|
||||
@ -1111,13 +1114,13 @@ else
|
||||
rm -rf conftest*
|
||||
CPP="${CC-cc} -E -traditional-cpp"
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1115 "configure"
|
||||
#line 1118 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <assert.h>
|
||||
Syntax Error
|
||||
EOF
|
||||
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
|
||||
{ (eval echo configure:1121: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
|
||||
{ (eval echo configure:1124: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
|
||||
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
|
||||
if test -z "$ac_err"; then
|
||||
:
|
||||
@ -1128,13 +1131,13 @@ else
|
||||
rm -rf conftest*
|
||||
CPP="${CC-cc} -nologo -E"
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1132 "configure"
|
||||
#line 1135 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <assert.h>
|
||||
Syntax Error
|
||||
EOF
|
||||
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
|
||||
{ (eval echo configure:1138: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
|
||||
{ (eval echo configure:1141: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
|
||||
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
|
||||
if test -z "$ac_err"; then
|
||||
:
|
||||
@ -1159,12 +1162,12 @@ fi
|
||||
echo "$ac_t""$CPP" 1>&6
|
||||
|
||||
echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
|
||||
echo "configure:1163: checking for ANSI C header files" >&5
|
||||
echo "configure:1166: checking for ANSI C header files" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1168 "configure"
|
||||
#line 1171 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
@ -1172,7 +1175,7 @@ else
|
||||
#include <float.h>
|
||||
EOF
|
||||
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
|
||||
{ (eval echo configure:1176: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
|
||||
{ (eval echo configure:1179: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
|
||||
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
|
||||
if test -z "$ac_err"; then
|
||||
rm -rf conftest*
|
||||
@ -1189,7 +1192,7 @@ rm -f conftest*
|
||||
if test $ac_cv_header_stdc = yes; then
|
||||
# SunOS 4.x string.h does not declare mem*, contrary to ANSI.
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1193 "configure"
|
||||
#line 1196 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <string.h>
|
||||
EOF
|
||||
@ -1207,7 +1210,7 @@ fi
|
||||
if test $ac_cv_header_stdc = yes; then
|
||||
# ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1211 "configure"
|
||||
#line 1214 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <stdlib.h>
|
||||
EOF
|
||||
@ -1228,7 +1231,7 @@ if test "$cross_compiling" = yes; then
|
||||
:
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1232 "configure"
|
||||
#line 1235 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <ctype.h>
|
||||
#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
|
||||
@ -1239,7 +1242,7 @@ if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
|
||||
exit (0); }
|
||||
|
||||
EOF
|
||||
if { (eval echo configure:1243: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
|
||||
if { (eval echo configure:1246: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
|
||||
then
|
||||
:
|
||||
else
|
||||
@ -1266,17 +1269,17 @@ for ac_hdr in fcntl.h malloc.h sys/ioctl.h unistd.h
|
||||
do
|
||||
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
|
||||
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
|
||||
echo "configure:1270: checking for $ac_hdr" >&5
|
||||
echo "configure:1273: checking for $ac_hdr" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1275 "configure"
|
||||
#line 1278 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <$ac_hdr>
|
||||
EOF
|
||||
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
|
||||
{ (eval echo configure:1280: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
|
||||
{ (eval echo configure:1283: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
|
||||
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
|
||||
if test -z "$ac_err"; then
|
||||
rm -rf conftest*
|
||||
@ -1304,12 +1307,12 @@ done
|
||||
|
||||
|
||||
echo $ac_n "checking for working const""... $ac_c" 1>&6
|
||||
echo "configure:1308: checking for working const" >&5
|
||||
echo "configure:1311: checking for working const" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1313 "configure"
|
||||
#line 1316 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
int main() {
|
||||
@ -1358,7 +1361,7 @@ ccp = (char const *const *) p;
|
||||
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:1362: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
|
||||
if { (eval echo configure:1365: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
|
||||
rm -rf conftest*
|
||||
ac_cv_c_const=yes
|
||||
else
|
||||
@ -1379,21 +1382,21 @@ EOF
|
||||
fi
|
||||
|
||||
echo $ac_n "checking for inline""... $ac_c" 1>&6
|
||||
echo "configure:1383: checking for inline" >&5
|
||||
echo "configure:1386: checking for inline" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
ac_cv_c_inline=no
|
||||
for ac_kw in inline __inline__ __inline; do
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1390 "configure"
|
||||
#line 1393 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
int main() {
|
||||
} int $ac_kw foo() {
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:1397: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
|
||||
if { (eval echo configure:1400: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
|
||||
rm -rf conftest*
|
||||
ac_cv_c_inline=$ac_kw; break
|
||||
else
|
||||
@ -1419,12 +1422,12 @@ EOF
|
||||
esac
|
||||
|
||||
echo $ac_n "checking for off_t""... $ac_c" 1>&6
|
||||
echo "configure:1423: checking for off_t" >&5
|
||||
echo "configure:1426: checking for off_t" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1428 "configure"
|
||||
#line 1431 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <sys/types.h>
|
||||
#if STDC_HEADERS
|
||||
@ -1452,12 +1455,12 @@ EOF
|
||||
fi
|
||||
|
||||
echo $ac_n "checking for pid_t""... $ac_c" 1>&6
|
||||
echo "configure:1456: checking for pid_t" >&5
|
||||
echo "configure:1459: checking for pid_t" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1461 "configure"
|
||||
#line 1464 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <sys/types.h>
|
||||
#if STDC_HEADERS
|
||||
@ -1485,12 +1488,12 @@ EOF
|
||||
fi
|
||||
|
||||
echo $ac_n "checking for size_t""... $ac_c" 1>&6
|
||||
echo "configure:1489: checking for size_t" >&5
|
||||
echo "configure:1492: checking for size_t" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1494 "configure"
|
||||
#line 1497 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <sys/types.h>
|
||||
#if STDC_HEADERS
|
||||
@ -1518,12 +1521,12 @@ EOF
|
||||
fi
|
||||
|
||||
echo $ac_n "checking for st_rdev in struct stat""... $ac_c" 1>&6
|
||||
echo "configure:1522: checking for st_rdev in struct stat" >&5
|
||||
echo "configure:1525: checking for st_rdev in struct stat" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_struct_st_rdev'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1527 "configure"
|
||||
#line 1530 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
@ -1531,7 +1534,7 @@ int main() {
|
||||
struct stat s; s.st_rdev;
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:1535: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
|
||||
if { (eval echo configure:1538: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
|
||||
rm -rf conftest*
|
||||
ac_cv_struct_st_rdev=yes
|
||||
else
|
||||
@ -1552,12 +1555,12 @@ EOF
|
||||
fi
|
||||
|
||||
echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
|
||||
echo "configure:1556: checking whether time.h and sys/time.h may both be included" >&5
|
||||
echo "configure:1559: checking whether time.h and sys/time.h may both be included" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1561 "configure"
|
||||
#line 1564 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
@ -1566,7 +1569,7 @@ int main() {
|
||||
struct tm *tp;
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:1570: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
|
||||
if { (eval echo configure:1573: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
|
||||
rm -rf conftest*
|
||||
ac_cv_header_time=yes
|
||||
else
|
||||
@ -1607,6 +1610,21 @@ else
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --with-lvm1 or --without-lvm1 was given.
|
||||
if test "${with_lvm1+set}" = set; then
|
||||
withval="$with_lvm1"
|
||||
LVM1="$withval"
|
||||
else
|
||||
LVM1="internal"
|
||||
fi
|
||||
|
||||
|
||||
if [ "x$LVM1" != xnone -a "x$LVM1" != xinternal -a "x$LVM1" != xshared ];
|
||||
then { echo "configure: error: --with-lvm1 parameter invalid
|
||||
" 1>&2; exit 1; }
|
||||
exit
|
||||
fi;
|
||||
|
||||
# Check whether --enable-jobs or --disable-jobs was given.
|
||||
if test "${enable_jobs+set}" = set; then
|
||||
enableval="$enable_jobs"
|
||||
@ -1631,7 +1649,7 @@ if test "${enable_readline+set}" = set; then
|
||||
\
|
||||
READLINE=$enableval
|
||||
else
|
||||
READLINE=yes
|
||||
READLINE=no
|
||||
fi
|
||||
|
||||
|
||||
@ -1641,13 +1659,13 @@ fi;
|
||||
|
||||
if test $ac_cv_prog_gcc = yes; then
|
||||
echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6
|
||||
echo "configure:1645: checking whether ${CC-cc} needs -traditional" >&5
|
||||
echo "configure:1663: checking whether ${CC-cc} needs -traditional" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
ac_pattern="Autoconf.*'x'"
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1651 "configure"
|
||||
#line 1669 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <sgtty.h>
|
||||
Autoconf TIOCGETP
|
||||
@ -1665,7 +1683,7 @@ rm -f conftest*
|
||||
|
||||
if test $ac_cv_prog_gcc_traditional = no; then
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1669 "configure"
|
||||
#line 1687 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <termio.h>
|
||||
Autoconf TCGETA
|
||||
@ -1687,12 +1705,12 @@ echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6
|
||||
fi
|
||||
|
||||
echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
|
||||
echo "configure:1691: checking return type of signal handlers" >&5
|
||||
echo "configure:1709: checking return type of signal handlers" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1696 "configure"
|
||||
#line 1714 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
@ -1709,7 +1727,7 @@ int main() {
|
||||
int i;
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:1713: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
|
||||
if { (eval echo configure:1731: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
|
||||
rm -rf conftest*
|
||||
ac_cv_type_signal=void
|
||||
else
|
||||
@ -1728,12 +1746,12 @@ EOF
|
||||
|
||||
|
||||
echo $ac_n "checking for vprintf""... $ac_c" 1>&6
|
||||
echo "configure:1732: checking for vprintf" >&5
|
||||
echo "configure:1750: checking for vprintf" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1737 "configure"
|
||||
#line 1755 "configure"
|
||||
#include "confdefs.h"
|
||||
/* System header to define __stub macros and hopefully few prototypes,
|
||||
which can conflict with char vprintf(); below. */
|
||||
@ -1756,7 +1774,7 @@ vprintf();
|
||||
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:1760: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
if { (eval echo configure:1778: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
rm -rf conftest*
|
||||
eval "ac_cv_func_vprintf=yes"
|
||||
else
|
||||
@ -1780,12 +1798,12 @@ fi
|
||||
|
||||
if test "$ac_cv_func_vprintf" != yes; then
|
||||
echo $ac_n "checking for _doprnt""... $ac_c" 1>&6
|
||||
echo "configure:1784: checking for _doprnt" >&5
|
||||
echo "configure:1802: checking for _doprnt" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1789 "configure"
|
||||
#line 1807 "configure"
|
||||
#include "confdefs.h"
|
||||
/* System header to define __stub macros and hopefully few prototypes,
|
||||
which can conflict with char _doprnt(); below. */
|
||||
@ -1808,7 +1826,7 @@ _doprnt();
|
||||
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:1812: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
if { (eval echo configure:1830: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
rm -rf conftest*
|
||||
eval "ac_cv_func__doprnt=yes"
|
||||
else
|
||||
@ -1835,12 +1853,12 @@ fi
|
||||
for ac_func in mkdir rmdir uname
|
||||
do
|
||||
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
|
||||
echo "configure:1839: checking for $ac_func" >&5
|
||||
echo "configure:1857: checking for $ac_func" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1844 "configure"
|
||||
#line 1862 "configure"
|
||||
#include "confdefs.h"
|
||||
/* System header to define __stub macros and hopefully few prototypes,
|
||||
which can conflict with char $ac_func(); below. */
|
||||
@ -1863,7 +1881,7 @@ $ac_func();
|
||||
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:1867: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
if { (eval echo configure:1885: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
rm -rf conftest*
|
||||
eval "ac_cv_func_$ac_func=yes"
|
||||
else
|
||||
@ -1891,14 +1909,14 @@ done
|
||||
if test x$READLINE = xyes; then
|
||||
|
||||
echo $ac_n "checking for library containing tgetent""... $ac_c" 1>&6
|
||||
echo "configure:1895: checking for library containing tgetent" >&5
|
||||
echo "configure:1913: checking for library containing tgetent" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_search_tgetent'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
ac_func_search_save_LIBS="$LIBS"
|
||||
ac_cv_search_tgetent="no"
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1902 "configure"
|
||||
#line 1920 "configure"
|
||||
#include "confdefs.h"
|
||||
/* Override any gcc2 internal prototype to avoid an error. */
|
||||
/* We use char because int might match the return type of a gcc2
|
||||
@ -1909,7 +1927,7 @@ int main() {
|
||||
tgetent()
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:1913: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
if { (eval echo configure:1931: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
rm -rf conftest*
|
||||
ac_cv_search_tgetent="none required"
|
||||
else
|
||||
@ -1920,7 +1938,7 @@ rm -f conftest*
|
||||
test "$ac_cv_search_tgetent" = "no" && for i in ncurses curses termcap termlib; do
|
||||
LIBS="-l$i $ac_func_search_save_LIBS"
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1924 "configure"
|
||||
#line 1942 "configure"
|
||||
#include "confdefs.h"
|
||||
/* Override any gcc2 internal prototype to avoid an error. */
|
||||
/* We use char because int might match the return type of a gcc2
|
||||
@ -1931,7 +1949,7 @@ int main() {
|
||||
tgetent()
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:1935: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
if { (eval echo configure:1953: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
rm -rf conftest*
|
||||
ac_cv_search_tgetent="-l$i"
|
||||
break
|
||||
@ -1965,7 +1983,7 @@ fi
|
||||
|
||||
if test x$READLINE = xyes; then
|
||||
echo $ac_n "checking for readline in -lreadline""... $ac_c" 1>&6
|
||||
echo "configure:1969: checking for readline in -lreadline" >&5
|
||||
echo "configure:1987: checking for readline in -lreadline" >&5
|
||||
ac_lib_var=`echo readline'_'readline | sed 'y%./+-%__p_%'`
|
||||
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
@ -1973,7 +1991,7 @@ else
|
||||
ac_save_LIBS="$LIBS"
|
||||
LIBS="-lreadline $LIBS"
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1977 "configure"
|
||||
#line 1995 "configure"
|
||||
#include "confdefs.h"
|
||||
/* Override any gcc2 internal prototype to avoid an error. */
|
||||
/* We use char because int might match the return type of a gcc2
|
||||
@ -1984,7 +2002,7 @@ int main() {
|
||||
readline()
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:1988: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
if { (eval echo configure:2006: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
rm -rf conftest*
|
||||
eval "ac_cv_lib_$ac_lib_var=yes"
|
||||
else
|
||||
@ -2021,12 +2039,12 @@ package as well (which may be called readline-devel or something similar).
|
||||
fi
|
||||
|
||||
echo $ac_n "checking for rl_completion_matches""... $ac_c" 1>&6
|
||||
echo "configure:2025: checking for rl_completion_matches" >&5
|
||||
echo "configure:2043: checking for rl_completion_matches" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_func_rl_completion_matches'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 2030 "configure"
|
||||
#line 2048 "configure"
|
||||
#include "confdefs.h"
|
||||
/* System header to define __stub macros and hopefully few prototypes,
|
||||
which can conflict with char rl_completion_matches(); below. */
|
||||
@ -2049,7 +2067,7 @@ rl_completion_matches();
|
||||
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:2053: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
if { (eval echo configure:2071: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
rm -rf conftest*
|
||||
eval "ac_cv_func_rl_completion_matches=yes"
|
||||
else
|
||||
@ -2085,6 +2103,7 @@ fi
|
||||
|
||||
|
||||
|
||||
|
||||
trap '' 1 2 15
|
||||
cat > confcache <<\EOF
|
||||
# This file is a shell script that caches the results of configure
|
||||
@ -2203,6 +2222,7 @@ Makefile \
|
||||
make.tmpl \
|
||||
include/Makefile \
|
||||
lib/Makefile \
|
||||
lib/format1/Makefile \
|
||||
man/Makefile \
|
||||
tools/Makefile \
|
||||
tools/version.h \
|
||||
@ -2255,6 +2275,7 @@ s%@CPP@%$CPP%g
|
||||
s%@JOBS@%$JOBS%g
|
||||
s%@STATIC_LINK@%$STATIC_LINK%g
|
||||
s%@READLINE@%$READLINE%g
|
||||
s%@LVM1@%$LVM1%g
|
||||
s%@HAVE_RL_COMPLETION_MATCHES@%$HAVE_RL_COMPLETION_MATCHES%g
|
||||
s%@OWNER@%$OWNER%g
|
||||
s%@GROUP@%$GROUP%g
|
||||
@ -2305,6 +2326,7 @@ Makefile \
|
||||
make.tmpl \
|
||||
include/Makefile \
|
||||
lib/Makefile \
|
||||
lib/format1/Makefile \
|
||||
man/Makefile \
|
||||
tools/Makefile \
|
||||
tools/version.h \
|
||||
|
22
configure.in
22
configure.in
@ -61,15 +61,29 @@ AC_ARG_WITH(group,
|
||||
[ GROUP="$withval" ],
|
||||
[ GROUP="root" ])
|
||||
|
||||
dnl -- format1 inclusion type
|
||||
AC_ARG_WITH(lvm1,
|
||||
[ --with-lvm1=TYPE LVM1 metadata support: internal/shared/none
|
||||
[TYPE=internal] ],
|
||||
[ LVM1="$withval" ],
|
||||
[ LVM1="internal" ])
|
||||
|
||||
if [[ "x$LVM1" != xnone -a "x$LVM1" != xinternal -a "x$LVM1" != xshared ]];
|
||||
then AC_MSG_ERROR(
|
||||
--with-lvm1 parameter invalid
|
||||
)
|
||||
exit
|
||||
fi;
|
||||
|
||||
AC_ARG_ENABLE(jobs, [ --enable-jobs=NUM Number of jobs to run simultaneously], JOBS=-j$enableval, JOBS=)
|
||||
|
||||
dnl Enables staticly linked tools
|
||||
AC_ARG_ENABLE(static_link, [ --enable-static_link Use this to link the tools to the liblvm library
|
||||
statically. Default is dynamic linking], STATIC_LINK=$enableval, STATIC_LINK=no)
|
||||
|
||||
dnl Disable readline
|
||||
AC_ARG_ENABLE(readline, [ --disable-readline Disable readline support], \
|
||||
READLINE=$enableval, READLINE=yes)
|
||||
dnl Enable readline
|
||||
AC_ARG_ENABLE(readline, [ --enable-readline Enable readline support], \
|
||||
READLINE=$enableval, READLINE=no)
|
||||
|
||||
dnl Mess with default exec_prefix
|
||||
if [[ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ]];
|
||||
@ -125,6 +139,7 @@ fi
|
||||
AC_SUBST(JOBS)
|
||||
AC_SUBST(STATIC_LINK)
|
||||
AC_SUBST(READLINE)
|
||||
AC_SUBST(LVM1)
|
||||
AC_SUBST(HAVE_RL_COMPLETION_MATCHES)
|
||||
AC_SUBST(OWNER)
|
||||
AC_SUBST(GROUP)
|
||||
@ -137,6 +152,7 @@ Makefile \
|
||||
make.tmpl \
|
||||
include/Makefile \
|
||||
lib/Makefile \
|
||||
lib/format1/Makefile \
|
||||
man/Makefile \
|
||||
tools/Makefile \
|
||||
tools/version.h \
|
||||
|
156
doc/example.conf
156
doc/example.conf
@ -1,24 +1,25 @@
|
||||
# This is an example configuration file for the LVM2 system. It
|
||||
# contains the default settings that would be used if there was no
|
||||
# This is an example configuration file for the LVM2 system.
|
||||
# It contains the default settings that would be used if there was no
|
||||
# /etc/lvm/lvm.conf file.
|
||||
# Refer to 'man lvm.conf' for further information.
|
||||
#
|
||||
# Refer to 'man lvm.conf' for further information including the file layout.
|
||||
#
|
||||
# To put this file in a different directory and override /etc/lvm set
|
||||
# the environment variable LVM_SYSTEM_DIR before running the tools.
|
||||
|
||||
|
||||
# This section allows the user to configure which block devices should
|
||||
# This section allows you to configure which block devices should
|
||||
# be used by the LVM system.
|
||||
devices {
|
||||
|
||||
# where do you want your volume groups to appear ?
|
||||
# Where do you want your volume groups to appear ?
|
||||
dir = "/dev"
|
||||
|
||||
# An array of directories that contain the device nodes you wish
|
||||
# to use with LVM2.
|
||||
scan = "/dev"
|
||||
|
||||
# A very important option, that allows you to tune the LVM2 system
|
||||
# to just look at a restricted set of devices that you're
|
||||
# interested in.
|
||||
scan = [ "/dev" ]
|
||||
|
||||
# A filter that tells LVM2 to only use a restricted set of devices.
|
||||
# The filter consists of an array of regular expressions. These
|
||||
# expressions can be delimited by a character of your choice, and
|
||||
# prefixed with either an 'a' (for accept) or 'r' (for reject).
|
||||
@ -26,51 +27,56 @@ devices {
|
||||
# Remember to run vgscan after you change this parameter.
|
||||
|
||||
# By default we accept every block device:
|
||||
filter = "a/.*/"
|
||||
filter = [ "a/.*/" ]
|
||||
|
||||
# Exclude the cdrom drive
|
||||
# filter = [ "r|/dev/cdrom|" ]
|
||||
|
||||
# When testing I like to work with just loopback devices:
|
||||
# filter = ["a/loop/", "r/.*/"]
|
||||
# filter = [ "a/loop/", "r/.*/" ]
|
||||
|
||||
# Or maybe all loops and ide drives except hdc:
|
||||
# filter =["a|loop|", "r|/dev/hdc|", "a|/dev/ide|", "r|.*|"]
|
||||
# filter =[ "a|loop|", "r|/dev/hdc|", "a|/dev/ide|", "r|.*|" ]
|
||||
|
||||
# Use anchors if you want to be really specific
|
||||
# filter = ["a|^/dev/hda8$|", "r/.*/"]
|
||||
# filter = [ "a|^/dev/hda8$|", "r/.*/" ]
|
||||
|
||||
# The results of all the filtering are cached on disk to avoid
|
||||
# The results of the filtering are cached on disk to avoid
|
||||
# rescanning dud devices (which can take a very long time). By
|
||||
# default this cache file is hidden in the /etc/lvm directory, it
|
||||
# is human readable to aid filter debugging.
|
||||
# default this cache file is hidden in the /etc/lvm directory.
|
||||
# It is safe to delete this file. vgscan regenerates it.
|
||||
cache = "/etc/lvm/.cache"
|
||||
|
||||
# You can turn off writing this cache file by setting this to 0.
|
||||
write_cache_state = 1
|
||||
}
|
||||
|
||||
# A section that allows the user to configure the nature of the
|
||||
# This section that allows you to configure the nature of the
|
||||
# information that LVM2 reports.
|
||||
log {
|
||||
|
||||
# Where should the log of error and debug messages go ? By
|
||||
# default there is no log.
|
||||
#file = "/var/log/lvm2.log"
|
||||
|
||||
# Should we overwrite the last log. By default we append.
|
||||
overwrite = 0
|
||||
|
||||
# There are 9 log levels, with 9 being the most verbose.
|
||||
level = 3
|
||||
|
||||
# Controls the messages sent to stdout or stderr while running
|
||||
# LVM2. There are three levels of verbosity, 3 being the most
|
||||
# verbose.
|
||||
# Controls the messages sent to stdout or stderr.
|
||||
# There are three levels of verbosity, 3 being the most verbose.
|
||||
verbose = 0
|
||||
|
||||
# Should we send log messages through syslog?
|
||||
# 1 is yes; 0 is no.
|
||||
syslog = 1
|
||||
|
||||
# Choose format of output messages
|
||||
# Should we log error and debug messages to a file?
|
||||
# By default there is no log file.
|
||||
#file = "/var/log/lvm2.log"
|
||||
|
||||
# Should we overwrite the log file each time the program is run?
|
||||
# By default we append.
|
||||
overwrite = 0
|
||||
|
||||
# What level of log messages should we send to the log file and/or syslog?
|
||||
# There are 6 syslog-like log levels currently in use - 2 to 7 inclusive.
|
||||
# 7 is the most verbose (LOG_DEBUG).
|
||||
level = 0
|
||||
|
||||
# Format of output messages
|
||||
# Whether or not (1 or 0) to indent messages according to their severity
|
||||
indent = 1
|
||||
|
||||
@ -78,10 +84,11 @@ log {
|
||||
command_names = 0
|
||||
|
||||
# A prefix to use before the message text (but after the command name,
|
||||
# if selected)
|
||||
# if selected). Default is two spaces, so you can see/grep the severity
|
||||
# of each message.
|
||||
prefix = " "
|
||||
|
||||
# To make the messages look similar to the original LVM use:
|
||||
# To make the messages look similar to the original LVM tools use:
|
||||
# indent = 0
|
||||
# command_names = 1
|
||||
# prefix = " -- "
|
||||
@ -95,19 +102,20 @@ backup {
|
||||
|
||||
# Should we maintain a backup of the current metadata configuration ?
|
||||
# Use 1 for Yes; 0 for No.
|
||||
# Think very hard before turning this off.
|
||||
# Think very hard before turning this off!
|
||||
backup = 1
|
||||
|
||||
# Where shall we keep it ?
|
||||
# Remember to back up this directory regularly!
|
||||
backup_dir = "/etc/lvm/backup"
|
||||
|
||||
|
||||
# Should we maintain an archive of old metadata configurations.
|
||||
# Use 1 for Yes; 0 for No.
|
||||
# On by default. Think very hard before turning this off.
|
||||
archive = 1
|
||||
|
||||
# Where should archived files go ?
|
||||
# Remember to back up this directory regularly!
|
||||
archive_dir = "/etc/lvm/archive"
|
||||
|
||||
# What is the minimum number of archive files you wish to keep ?
|
||||
@ -117,20 +125,15 @@ backup {
|
||||
retain_days = 30
|
||||
}
|
||||
|
||||
# Settings for the running LVM2 in shell mode.
|
||||
# Settings for the running LVM2 in shell (readline) mode.
|
||||
shell {
|
||||
|
||||
# Number of lines of history to store in ~/.lvm_history
|
||||
history_size = 100
|
||||
}
|
||||
|
||||
# Metadata settings
|
||||
metadata {
|
||||
# List of directories holding copies of text format metadata
|
||||
dirs = [ "/etc/lvm/metadata" ]
|
||||
}
|
||||
|
||||
# Miscellaneous global settings
|
||||
# Miscellaneous global LVM2 settings
|
||||
global {
|
||||
|
||||
# The file creation mask for any files and directories created.
|
||||
@ -145,10 +148,73 @@ global {
|
||||
# command. Defaults to off.
|
||||
test = 0
|
||||
|
||||
# Default metadata format commands use - "lvm1" (default) or "text"
|
||||
format = "lvm1"
|
||||
# Whether or not to communicate with the kernel device-mapper.
|
||||
# Set to 0 if you want to use the tools to manipulate LVM metadata
|
||||
# without activating any logical volumes.
|
||||
# If the device-mapper kernel driver is not present in your kernel
|
||||
# setting this to 0 should suppress the error messages.
|
||||
activation = 1
|
||||
|
||||
# The default metadata format that commands should use - "lvm1" or "lvm2".
|
||||
# The command line override is -M1 or -M2.
|
||||
# Defaults to "lvm1" if compiled in, else "lvm2".
|
||||
# format = "lvm1"
|
||||
|
||||
# Location of proc filesystem
|
||||
proc = "/proc"
|
||||
|
||||
# Type of locking to use. Defaults to file-based locking (1).
|
||||
# Turn locking off by setting to 0 (dangerous: risks metadata corruption
|
||||
# if LVM2 commands get run concurrently).
|
||||
locking_type = 1
|
||||
|
||||
# Local non-LV directory that holds file-based locks while commands are
|
||||
# in progress. A directory like /tmp that may get wiped on reboot is OK.
|
||||
locking_dir = "/var/lock/lvm"
|
||||
|
||||
# Other entries can go here to allow you to load shared libraries
|
||||
# e.g. if support for LVM1 metadata was compiled as a shared library use
|
||||
# format_libraries = "liblvm2format1.so"
|
||||
# Full pathnames can be given.
|
||||
|
||||
# Search this directory first for shared libraries.
|
||||
# library_dir = "/lib"
|
||||
}
|
||||
|
||||
|
||||
####################
|
||||
# Advanced section #
|
||||
####################
|
||||
|
||||
# Metadata settings
|
||||
#
|
||||
# metadata {
|
||||
# Default number of copies of metadata to hold on each PV. 0, 1 or 2.
|
||||
# It's best to leave this at 2.
|
||||
# You might want to override it from the command line with 0 or 1
|
||||
# when running pvcreate on new PVs which are to be added to large VGs.
|
||||
|
||||
# pvmetadatacopies = 2
|
||||
|
||||
# Approximate default size of on-disk metadata areas in sectors.
|
||||
# You should increase this if you have large volume groups or
|
||||
# you want to retain a large on-disk history of your metadata changes.
|
||||
|
||||
# pvmetadatasize = 255
|
||||
|
||||
# List of directories holding live copies of text format metadata.
|
||||
# These directories must not be on logical volumes!
|
||||
# It's possible to use LVM2 with a couple of directories here,
|
||||
# preferably on different (non-LV) filesystems, and with no other
|
||||
# on-disk metadata (pvmetadatacopies = 0). Or this can be in
|
||||
# addition to on-disk metadata areas.
|
||||
# The feature was originally added to simplify testing.
|
||||
#
|
||||
# Never edit any files in these directories by hand unless you
|
||||
# you are absolutely sure you know what you are doing! Use
|
||||
# the supplied toolset to make changes (e.g. vgcfgrestore).
|
||||
|
||||
# dirs = [ "/etc/lvm/metadata", "/mnt/disk2/lvm/metadata2" ]
|
||||
#}
|
||||
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
../lib/activate/activate.h
|
||||
../lib/cache/cache.h
|
||||
../lib/commands/errors.h
|
||||
../lib/commands/toolcontext.h
|
||||
../lib/config/config.h
|
||||
@ -11,23 +12,25 @@
|
||||
../lib/device/dev-cache.h
|
||||
../lib/device/device.h
|
||||
../lib/display/display.h
|
||||
../lib/display/display_formats.h
|
||||
../lib/filters/filter-composite.h
|
||||
../lib/filters/filter-persistent.h
|
||||
../lib/filters/filter-regex.h
|
||||
../lib/filters/filter.h
|
||||
../lib/format1/format1.h
|
||||
../lib/format1/lvm1_label.h
|
||||
../lib/format1/lvm1-label.h
|
||||
../lib/format_text/format-text.h
|
||||
../lib/label/label.h
|
||||
../lib/label/uuid-map.h
|
||||
../lib/locking/locking.h
|
||||
../lib/log/log.h
|
||||
../lib/metadata/metadata.h
|
||||
../lib/mm/dbg_malloc.h
|
||||
../lib/mm/pool.h
|
||||
../lib/mm/xlate.h
|
||||
../lib/misc/crc.h
|
||||
../lib/misc/lib.h
|
||||
../lib/misc/lvm-file.h
|
||||
../lib/misc/lvm-string.h
|
||||
../lib/misc/sharedlib.h
|
||||
../lib/regex/matcher.h
|
||||
../lib/uuid/uuid.h
|
||||
../lib/vgcache/vgcache.h
|
||||
|
@ -8,10 +8,16 @@ srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
ifeq ("@LVM1@", "shared")
|
||||
SUBDIRS = format1
|
||||
endif
|
||||
|
||||
SOURCES=\
|
||||
activate/activate.c \
|
||||
activate/dev_manager.c \
|
||||
activate/fs.c \
|
||||
cache/cache.c \
|
||||
commands/toolcontext.c \
|
||||
config/config.c \
|
||||
datastruct/bitset.c \
|
||||
datastruct/btree.c \
|
||||
@ -24,20 +30,14 @@ SOURCES=\
|
||||
filters/filter-persistent.c \
|
||||
filters/filter-regex.c \
|
||||
filters/filter.c \
|
||||
format1/disk-rep.c \
|
||||
format1/format1.c \
|
||||
format1/import-export.c \
|
||||
format1/import-extents.c \
|
||||
format1/layout.c \
|
||||
format1/lvm1_label.c \
|
||||
format1/vg_number.c \
|
||||
format_text/archive.c \
|
||||
format_text/export.c \
|
||||
format_text/flags.c \
|
||||
format_text/format-text.c \
|
||||
format_text/import.c \
|
||||
format_text/import_vsn1.c \
|
||||
format_text/text_label.c \
|
||||
label/label.c \
|
||||
label/uuid-map.c \
|
||||
locking/external_locking.c \
|
||||
locking/file_locking.c \
|
||||
locking/locking.c \
|
||||
@ -48,14 +48,26 @@ SOURCES=\
|
||||
metadata/metadata.c \
|
||||
metadata/pv_map.c \
|
||||
metadata/snapshot_manip.c \
|
||||
misc/crc.c \
|
||||
misc/lvm-file.c \
|
||||
misc/sharedlib.c \
|
||||
mm/dbg_malloc.c \
|
||||
mm/pool.c \
|
||||
regex/matcher.c \
|
||||
regex/parse_rx.c \
|
||||
regex/ttree.c \
|
||||
uuid/uuid.c \
|
||||
vgcache/vgcache.c
|
||||
uuid/uuid.c
|
||||
|
||||
ifeq ("@LVM1@", "internal")
|
||||
SOURCES+=\
|
||||
format1/disk-rep.c \
|
||||
format1/format1.c \
|
||||
format1/import-export.c \
|
||||
format1/import-extents.c \
|
||||
format1/layout.c \
|
||||
format1/lvm1-label.c \
|
||||
format1/vg_number.c
|
||||
endif
|
||||
|
||||
TARGETS=liblvm.a
|
||||
|
||||
|
@ -4,9 +4,9 @@
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "format-text.h"
|
||||
|
||||
#include "log.h"
|
||||
#include "pool.h"
|
||||
#include "config.h"
|
||||
#include "hash.h"
|
||||
@ -17,7 +17,6 @@
|
||||
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <fcntl.h>
|
||||
@ -52,7 +51,7 @@ struct archive_file {
|
||||
* Extract vg name and version number from a filename.
|
||||
*/
|
||||
static int _split_vg(const char *filename, char *vg, size_t vg_size,
|
||||
uint32_t * index)
|
||||
uint32_t *index)
|
||||
{
|
||||
int len, vg_len;
|
||||
char *dot, *underscore;
|
||||
@ -202,7 +201,7 @@ static void _remove_expired(struct list *archives, uint32_t archives_size,
|
||||
return;
|
||||
|
||||
/* Convert retain_days into the time after which we must retain */
|
||||
retain_time = time(NULL) - (time_t) retain_days * SECS_PER_DAY;
|
||||
retain_time = time(NULL) - (time_t) retain_days *SECS_PER_DAY;
|
||||
|
||||
/* Assume list is ordered oldest first (by index) */
|
||||
list_iterate(bh, archives) {
|
||||
@ -252,7 +251,7 @@ int archive_vg(struct volume_group *vg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!text_vg_export(fp, vg, desc)) {
|
||||
if (!text_vg_export_file(vg, desc, fp)) {
|
||||
stack;
|
||||
fclose(fp);
|
||||
return 0;
|
||||
@ -297,8 +296,7 @@ int archive_vg(struct volume_group *vg,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _display_archive(struct cmd_context *cmd, struct uuid_map *um,
|
||||
struct archive_file *af)
|
||||
static void _display_archive(struct cmd_context *cmd, struct archive_file *af)
|
||||
{
|
||||
struct volume_group *vg = NULL;
|
||||
struct format_instance *tf;
|
||||
@ -308,8 +306,9 @@ static void _display_archive(struct cmd_context *cmd, struct uuid_map *um,
|
||||
|
||||
log_print("path:\t\t%s", af->path);
|
||||
|
||||
if (!(context = create_text_context(cmd->fmtt, af->path, NULL)) ||
|
||||
!(tf = cmd->fmtt->ops->create_instance(cmd->fmtt, NULL, context))) {
|
||||
if (!(context = create_text_context(cmd, af->path, NULL)) ||
|
||||
!(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
|
||||
context))) {
|
||||
log_error("Couldn't create text instance object.");
|
||||
return;
|
||||
}
|
||||
@ -319,7 +318,7 @@ static void _display_archive(struct cmd_context *cmd, struct uuid_map *um,
|
||||
* retrieve the archive time and description.
|
||||
*/
|
||||
/* FIXME Use variation on _vg_read */
|
||||
if (!(vg = text_vg_import(tf, af->path, um, &when, &desc))) {
|
||||
if (!(vg = text_vg_import_file(tf, af->path, &when, &desc))) {
|
||||
log_print("Unable to read archive file.");
|
||||
tf->fmt->ops->destroy_instance(tf);
|
||||
return;
|
||||
@ -332,8 +331,7 @@ static void _display_archive(struct cmd_context *cmd, struct uuid_map *um,
|
||||
tf->fmt->ops->destroy_instance(tf);
|
||||
}
|
||||
|
||||
int archive_list(struct cmd_context *cmd, struct uuid_map *um,
|
||||
const char *dir, const char *vg)
|
||||
int archive_list(struct cmd_context *cmd, const char *dir, const char *vg)
|
||||
{
|
||||
struct list *archives, *ah;
|
||||
struct archive_file *af;
|
||||
@ -349,7 +347,7 @@ int archive_list(struct cmd_context *cmd, struct uuid_map *um,
|
||||
list_iterate(ah, archives) {
|
||||
af = list_item(ah, struct archive_file);
|
||||
|
||||
_display_archive(cmd, um, af);
|
||||
_display_archive(cmd, af);
|
||||
log_print(" ");
|
||||
}
|
||||
|
||||
|
@ -4,40 +4,74 @@
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "import-export.h"
|
||||
#include "metadata.h"
|
||||
#include "log.h"
|
||||
#include "hash.h"
|
||||
#include "pool.h"
|
||||
#include "dbg_malloc.h"
|
||||
#include "lvm-string.h"
|
||||
#include "display.h"
|
||||
#include "lvm-string.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
|
||||
struct formatter;
|
||||
typedef int (*out_with_comment_fn) (struct formatter * f, const char *comment,
|
||||
const char *fmt, va_list ap);
|
||||
typedef void (*nl_fn) (struct formatter * f);
|
||||
/*
|
||||
* The first half of this file deals with
|
||||
* exporting the vg, ie. writing it to a file.
|
||||
*/
|
||||
struct formatter {
|
||||
struct pool *mem; /* pv names allocated from here */
|
||||
struct hash_table *pv_names; /* dev_name -> pv_name (eg, pv1) */
|
||||
|
||||
FILE *fp; /* where we're writing to */
|
||||
int indent; /* current level of indentation */
|
||||
union {
|
||||
FILE *fp; /* where we're writing to */
|
||||
struct {
|
||||
char *buf;
|
||||
uint32_t size;
|
||||
uint32_t used;
|
||||
} buf;
|
||||
} data;
|
||||
|
||||
out_with_comment_fn out_with_comment;
|
||||
nl_fn nl;
|
||||
|
||||
int indent; /* current level of indentation */
|
||||
int error;
|
||||
int header; /* 1 => comments at start; 0 => end */
|
||||
};
|
||||
|
||||
static struct utsname _utsname;
|
||||
|
||||
static void _init(void)
|
||||
{
|
||||
static int _initialised = 0;
|
||||
|
||||
if (_initialised)
|
||||
return;
|
||||
|
||||
if (uname(&_utsname)) {
|
||||
log_error("uname failed: %s", strerror(errno));
|
||||
memset(&_utsname, 0, sizeof(_utsname));
|
||||
}
|
||||
|
||||
_initialised = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Formatting functions.
|
||||
*/
|
||||
static void _out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
|
||||
static int _out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
|
||||
__attribute__ ((format(printf, 3, 4)));
|
||||
|
||||
static void _out_hint(struct formatter *f, const char *fmt, ...)
|
||||
static int _out_hint(struct formatter *f, const char *fmt, ...)
|
||||
__attribute__ ((format(printf, 2, 3)));
|
||||
|
||||
static void _out(struct formatter *f, const char *fmt, ...)
|
||||
static int _out(struct formatter *f, const char *fmt, ...)
|
||||
__attribute__ ((format(printf, 2, 3)));
|
||||
|
||||
#define MAX_INDENT 5
|
||||
@ -58,26 +92,39 @@ static void _dec_indent(struct formatter *f)
|
||||
/*
|
||||
* Newline function for prettier layout.
|
||||
*/
|
||||
static void _nl(struct formatter *f)
|
||||
static void _nl_file(struct formatter *f)
|
||||
{
|
||||
fprintf(f->fp, "\n");
|
||||
fprintf(f->data.fp, "\n");
|
||||
}
|
||||
|
||||
static void _nl_raw(struct formatter *f)
|
||||
{
|
||||
if (f->data.buf.used >= f->data.buf.size - 1)
|
||||
return;
|
||||
|
||||
*f->data.buf.buf = '\n';
|
||||
f->data.buf.buf += 1;
|
||||
f->data.buf.used += 1;
|
||||
*f->data.buf.buf = '\0';
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#define COMMENT_TAB 6
|
||||
static void _out_with_comment(struct formatter *f, const char *comment,
|
||||
const char *fmt, va_list ap)
|
||||
static int _out_with_comment_file(struct formatter *f, const char *comment,
|
||||
const char *fmt, va_list ap)
|
||||
{
|
||||
int i;
|
||||
char white_space[MAX_INDENT + 1];
|
||||
|
||||
if (ferror(f->fp))
|
||||
return;
|
||||
if (ferror(f->data.fp))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < f->indent; i++)
|
||||
white_space[i] = '\t';
|
||||
white_space[i] = '\0';
|
||||
fprintf(f->fp, white_space);
|
||||
i = vfprintf(f->fp, fmt, ap);
|
||||
fprintf(f->data.fp, white_space);
|
||||
i = vfprintf(f->data.fp, fmt, ap);
|
||||
|
||||
if (comment) {
|
||||
/*
|
||||
@ -88,13 +135,34 @@ static void _out_with_comment(struct formatter *f, const char *comment,
|
||||
i++;
|
||||
|
||||
do
|
||||
fputc('\t', f->fp);
|
||||
fputc('\t', f->data.fp);
|
||||
|
||||
while (++i < COMMENT_TAB);
|
||||
|
||||
fprintf(f->fp, comment);
|
||||
fprintf(f->data.fp, comment);
|
||||
}
|
||||
fputc('\n', f->fp);
|
||||
fputc('\n', f->data.fp);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _out_with_comment_raw(struct formatter *f, const char *comment,
|
||||
const char *fmt, va_list ap)
|
||||
{
|
||||
int n;
|
||||
|
||||
n = vsnprintf(f->data.buf.buf, f->data.buf.size - f->data.buf.used,
|
||||
fmt, ap);
|
||||
|
||||
if (n < 0 || (n > f->data.buf.size - f->data.buf.used - 1))
|
||||
return 0;
|
||||
|
||||
f->data.buf.buf += n;
|
||||
f->data.buf.used += n;
|
||||
|
||||
f->nl(f);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -109,7 +177,7 @@ static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
|
||||
"Kilobytes",
|
||||
"Megabytes",
|
||||
"Gigabytes",
|
||||
"Terrabytes",
|
||||
"Terabytes",
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -129,43 +197,55 @@ static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
|
||||
* Appends a comment giving a size in more easily
|
||||
* readable form (eg, 4M instead of 8096).
|
||||
*/
|
||||
static void _out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
|
||||
static int _out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
|
||||
{
|
||||
char buffer[64];
|
||||
va_list ap;
|
||||
int r;
|
||||
|
||||
_sectors_to_units(size, buffer, sizeof(buffer));
|
||||
if (!_sectors_to_units(size, buffer, sizeof(buffer)))
|
||||
return 0;
|
||||
|
||||
va_start(ap, fmt);
|
||||
_out_with_comment(f, buffer, fmt, ap);
|
||||
r = f->out_with_comment(f, buffer, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Appends a comment indicating that the line is
|
||||
* only a hint.
|
||||
*/
|
||||
static void _out_hint(struct formatter *f, const char *fmt, ...)
|
||||
static int _out_hint(struct formatter *f, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int r;
|
||||
|
||||
va_start(ap, fmt);
|
||||
_out_with_comment(f, "# Hint only", fmt, ap);
|
||||
r = f->out_with_comment(f, "# Hint only", fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* The normal output function.
|
||||
*/
|
||||
static void _out(struct formatter *f, const char *fmt, ...)
|
||||
static int _out(struct formatter *f, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int r;
|
||||
|
||||
va_start(ap, fmt);
|
||||
_out_with_comment(f, NULL, fmt, ap);
|
||||
r = f->out_with_comment(f, NULL, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#define _outf(args...) do {if (!_out(args)) {stack; return 0;}} while (0)
|
||||
|
||||
static int _print_header(struct formatter *f,
|
||||
struct volume_group *vg, const char *desc)
|
||||
{
|
||||
@ -173,15 +253,17 @@ static int _print_header(struct formatter *f,
|
||||
|
||||
t = time(NULL);
|
||||
|
||||
_out(f,
|
||||
"# This file was originally generated by the LVM2 library\n"
|
||||
"# Generated: %s", ctime(&t));
|
||||
_outf(f, "# Generated by LVM2: %s", ctime(&t));
|
||||
_outf(f, CONTENTS_FIELD " = \"" CONTENTS_VALUE "\"");
|
||||
_outf(f, FORMAT_VERSION_FIELD " = %d", FORMAT_VERSION_VALUE);
|
||||
f->nl(f);
|
||||
|
||||
_out(f, CONTENTS_FIELD " = \"" CONTENTS_VALUE "\"");
|
||||
_out(f, FORMAT_VERSION_FIELD " = %d\n", FORMAT_VERSION_VALUE);
|
||||
|
||||
_out(f, "description = \"%s\"", desc);
|
||||
_out(f, "creation_time = %lu\n", t);
|
||||
_outf(f, "description = \"%s\"", desc);
|
||||
f->nl(f);
|
||||
_outf(f, "creation_host = \"%s\"\t# %s %s %s %s %s", _utsname.nodename,
|
||||
_utsname.sysname, _utsname.nodename, _utsname.release,
|
||||
_utsname.version, _utsname.machine);
|
||||
_outf(f, "creation_time = %lu\t# %s", t, ctime(&t));
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -195,20 +277,23 @@ static int _print_vg(struct formatter *f, struct volume_group *vg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
_out(f, "id = \"%s\"", buffer);
|
||||
_outf(f, "id = \"%s\"", buffer);
|
||||
|
||||
_out(f, "seqno = %u", vg->seqno);
|
||||
_outf(f, "seqno = %u", vg->seqno);
|
||||
if (!print_flags(vg->status, VG_FLAGS, buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_out(f, "status = %s", buffer);
|
||||
_outf(f, "status = %s", buffer);
|
||||
if (vg->system_id && *vg->system_id)
|
||||
_out(f, "system_id = \"%s\"", vg->system_id);
|
||||
_out_size(f, vg->extent_size, "extent_size = %u", vg->extent_size);
|
||||
_out(f, "max_lv = %u", vg->max_lv);
|
||||
_out(f, "max_pv = %u", vg->max_pv);
|
||||
_outf(f, "system_id = \"%s\"", vg->system_id);
|
||||
if (!_out_size(f, vg->extent_size, "extent_size = %u", vg->extent_size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
_outf(f, "max_lv = %u", vg->max_lv);
|
||||
_outf(f, "max_pv = %u", vg->max_pv);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -231,7 +316,7 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
|
||||
char buffer[256];
|
||||
const char *name;
|
||||
|
||||
_out(f, "physical_volumes {");
|
||||
_outf(f, "physical_volumes {");
|
||||
_inc_indent(f);
|
||||
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
@ -243,8 +328,8 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
_nl(f);
|
||||
_out(f, "%s {", name);
|
||||
f->nl(f);
|
||||
_outf(f, "%s {", name);
|
||||
_inc_indent(f);
|
||||
|
||||
if (!id_write_format(&pv->id, buffer, sizeof(buffer))) {
|
||||
@ -252,65 +337,93 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
_out(f, "id = \"%s\"", buffer);
|
||||
_out_hint(f, "device = \"%s\"", dev_name(pv->dev));
|
||||
_nl(f);
|
||||
_outf(f, "id = \"%s\"", buffer);
|
||||
if (!_out_hint(f, "device = \"%s\"", dev_name(pv->dev))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
f->nl(f);
|
||||
|
||||
if (!print_flags(pv->status, PV_FLAGS, buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_out(f, "status = %s", buffer);
|
||||
_out(f, "pe_start = %llu", pv->pe_start);
|
||||
_out_size(f, vg->extent_size * (uint64_t) pv->pe_count,
|
||||
"pe_count = %u", pv->pe_count);
|
||||
|
||||
_dec_indent(f);
|
||||
_out(f, "}");
|
||||
}
|
||||
|
||||
_dec_indent(f);
|
||||
_out(f, "}");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _print_segment(struct formatter *f, struct volume_group *vg,
|
||||
int count, struct stripe_segment *seg)
|
||||
{
|
||||
int s;
|
||||
const char *name;
|
||||
|
||||
_out(f, "segment%u {", count);
|
||||
_inc_indent(f);
|
||||
|
||||
_out(f, "start_extent = %u", seg->le);
|
||||
_out_size(f, seg->len * vg->extent_size, "extent_count = %u", seg->len);
|
||||
_out(f, "stripes = %u", seg->stripes);
|
||||
|
||||
if (seg->stripes > 1)
|
||||
_out_size(f, seg->stripe_size,
|
||||
"stripe_size = %u", seg->stripe_size);
|
||||
|
||||
_nl(f);
|
||||
_out(f, "areas = [");
|
||||
_inc_indent(f);
|
||||
|
||||
for (s = 0; s < seg->stripes; s++) {
|
||||
if (!(name = _get_pv_name(f, seg->area[s].pv))) {
|
||||
_outf(f, "status = %s", buffer);
|
||||
_outf(f, "pe_start = %" PRIu64, pv->pe_start);
|
||||
if (!_out_size(f, vg->extent_size * (uint64_t) pv->pe_count,
|
||||
"pe_count = %u", pv->pe_count)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_out(f, "\"%s\", %u%s", name, seg->area[s].pe,
|
||||
(s == seg->stripes - 1) ? "" : ",");
|
||||
_dec_indent(f);
|
||||
_outf(f, "}");
|
||||
}
|
||||
|
||||
_dec_indent(f);
|
||||
_out(f, "]");
|
||||
_outf(f, "}");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _print_segment(struct formatter *f, struct volume_group *vg,
|
||||
int count, struct lv_segment *seg)
|
||||
{
|
||||
int s;
|
||||
const char *name;
|
||||
|
||||
_outf(f, "segment%u {", count);
|
||||
_inc_indent(f);
|
||||
|
||||
_outf(f, "start_extent = %u", seg->le);
|
||||
if (!_out_size(f, seg->len * vg->extent_size, "extent_count = %u",
|
||||
seg->len)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
f->nl(f);
|
||||
_outf(f, "type = \"%s\"", get_segtype_string(seg->type));
|
||||
|
||||
switch (seg->type) {
|
||||
case SEG_STRIPED:
|
||||
_outf(f, "stripe_count = %u%s", seg->stripes,
|
||||
(seg->stripes == 1) ? "\t# linear" : "");
|
||||
|
||||
if (seg->stripes > 1)
|
||||
_out_size(f, seg->stripe_size,
|
||||
"stripe_size = %u", seg->stripe_size);
|
||||
|
||||
f->nl(f);
|
||||
_outf(f, "stripes = [");
|
||||
_inc_indent(f);
|
||||
|
||||
for (s = 0; s < seg->stripes; s++) {
|
||||
if (!(name = _get_pv_name(f, seg->area[s].pv))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_outf(f, "\"%s\", %u%s", name, seg->area[s].pe,
|
||||
(s == seg->stripes - 1) ? "" : ",");
|
||||
}
|
||||
|
||||
_dec_indent(f);
|
||||
_outf(f, "]");
|
||||
break;
|
||||
|
||||
case SEG_SNAPSHOT:
|
||||
_outf(f, "chunk_size = %u", seg->chunk_size);
|
||||
_outf(f, "origin = \"%s\"", seg->origin->name);
|
||||
_outf(f, "cow_store = \"%s\"", seg->cow->name);
|
||||
break;
|
||||
case SEG_MIRROR:
|
||||
/* mirrors = [ "lvol1", 10, ... ] */
|
||||
;
|
||||
}
|
||||
|
||||
_dec_indent(f);
|
||||
_out(f, "}");
|
||||
_outf(f, "}");
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -326,86 +439,48 @@ static int _count_segments(struct logical_volume *lv)
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _print_lvs(struct formatter *f, struct volume_group *vg)
|
||||
static int _print_snapshot(struct formatter *f, struct snapshot *snap,
|
||||
unsigned int count)
|
||||
{
|
||||
struct list *lvh, *segh;
|
||||
struct logical_volume *lv;
|
||||
struct stripe_segment *seg;
|
||||
char buffer[256];
|
||||
int seg_count;
|
||||
struct lv_segment seg;
|
||||
|
||||
/*
|
||||
* Don't bother with an lv section if there are no lvs.
|
||||
*/
|
||||
if (list_empty(&vg->lvs))
|
||||
return 1;
|
||||
f->nl(f);
|
||||
|
||||
_out(f, "logical_volumes {");
|
||||
_outf(f, "snapshot%u {", count);
|
||||
_inc_indent(f);
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
if (!id_write_format(&snap->id, buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_nl(f);
|
||||
_out(f, "%s {", lv->name);
|
||||
_inc_indent(f);
|
||||
_outf(f, "id = \"%s\"", buffer);
|
||||
if (!print_flags(LVM_READ | LVM_WRITE | VISIBLE_LV, LV_FLAGS,
|
||||
buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME: Write full lvid */
|
||||
if (!id_write_format(&lv->lvid.id[1], buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
_outf(f, "status = %s", buffer);
|
||||
_outf(f, "segment_count = 1");
|
||||
|
||||
_out(f, "id = \"%s\"", buffer);
|
||||
f->nl(f);
|
||||
|
||||
if (!print_flags(lv->status, LV_FLAGS,
|
||||
buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
seg.type = SEG_SNAPSHOT;
|
||||
seg.le = 0;
|
||||
seg.len = snap->origin->le_count;
|
||||
seg.origin = snap->origin;
|
||||
seg.cow = snap->cow;
|
||||
seg.chunk_size = snap->chunk_size;
|
||||
|
||||
_out(f, "status = %s", buffer);
|
||||
_out(f, "allocation_policy = \"%s\"",
|
||||
get_alloc_string(lv->alloc));
|
||||
_out(f, "read_ahead = %u", lv->read_ahead);
|
||||
if (lv->minor >= 0)
|
||||
_out(f, "minor = %d", lv->minor);
|
||||
_out(f, "segment_count = %u", _count_segments(lv));
|
||||
_nl(f);
|
||||
|
||||
seg_count = 1;
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct stripe_segment);
|
||||
|
||||
if (!_print_segment(f, vg, seg_count++, seg)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
_dec_indent(f);
|
||||
_out(f, "}");
|
||||
if (!_print_segment(f, snap->origin->vg, 1, &seg)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_dec_indent(f);
|
||||
_out(f, "}");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _print_snapshot(struct formatter *f, struct snapshot *s,
|
||||
unsigned int count)
|
||||
{
|
||||
_nl(f);
|
||||
_out(f, "snapshot%u {", count);
|
||||
_inc_indent(f);
|
||||
|
||||
_out(f, "chunk_size = %u", s->chunk_size);
|
||||
_out(f, "origin = \"%s\"", s->origin->name);
|
||||
_out(f, "cow_store = \"%s\"", s->cow->name);
|
||||
|
||||
_dec_indent(f);
|
||||
_out(f, "}");
|
||||
_outf(f, "}");
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -416,16 +491,6 @@ static int _print_snapshots(struct formatter *f, struct volume_group *vg)
|
||||
struct snapshot *s;
|
||||
unsigned int count = 0;
|
||||
|
||||
/*
|
||||
* Don't bother with a snapshot section if there are no
|
||||
* snapshots.
|
||||
*/
|
||||
if (list_empty(&vg->snapshots))
|
||||
return 1;
|
||||
|
||||
_out(f, "snapshots {");
|
||||
_inc_indent(f);
|
||||
|
||||
list_iterate(sh, &vg->snapshots) {
|
||||
s = list_item(sh, struct snapshot_list)->snapshot;
|
||||
|
||||
@ -435,8 +500,78 @@ static int _print_snapshots(struct formatter *f, struct volume_group *vg)
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _print_lvs(struct formatter *f, struct volume_group *vg)
|
||||
{
|
||||
struct list *lvh, *segh;
|
||||
struct logical_volume *lv;
|
||||
struct lv_segment *seg;
|
||||
char buffer[256];
|
||||
int seg_count;
|
||||
|
||||
/*
|
||||
* Don't bother with an lv section if there are no lvs.
|
||||
*/
|
||||
if (list_empty(&vg->lvs))
|
||||
return 1;
|
||||
|
||||
_outf(f, "logical_volumes {");
|
||||
_inc_indent(f);
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
|
||||
f->nl(f);
|
||||
_outf(f, "%s {", lv->name);
|
||||
_inc_indent(f);
|
||||
|
||||
/* FIXME: Write full lvid */
|
||||
if (!id_write_format(&lv->lvid.id[1], buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_outf(f, "id = \"%s\"", buffer);
|
||||
|
||||
if (!print_flags(lv->status, LV_FLAGS, buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_outf(f, "status = %s", buffer);
|
||||
if (lv->alloc != ALLOC_DEFAULT)
|
||||
_outf(f, "allocation_policy = \"%s\"",
|
||||
get_alloc_string(lv->alloc));
|
||||
if (lv->read_ahead)
|
||||
_outf(f, "read_ahead = %u", lv->read_ahead);
|
||||
if (lv->minor >= 0)
|
||||
_outf(f, "minor = %d", lv->minor);
|
||||
_outf(f, "segment_count = %u", _count_segments(lv));
|
||||
f->nl(f);
|
||||
|
||||
seg_count = 1;
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
|
||||
if (!_print_segment(f, vg, seg_count++, seg)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
_dec_indent(f);
|
||||
_outf(f, "}");
|
||||
}
|
||||
|
||||
if (!_print_snapshots(f, vg)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_dec_indent(f);
|
||||
_out(f, "}");
|
||||
_outf(f, "}");
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -494,19 +629,10 @@ static int _build_pv_names(struct formatter *f, struct volume_group *vg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int text_vg_export(FILE * fp, struct volume_group *vg, const char *desc)
|
||||
static int _text_vg_export(struct formatter *f,
|
||||
struct volume_group *vg, const char *desc)
|
||||
{
|
||||
int r = 0;
|
||||
struct formatter *f;
|
||||
|
||||
if (!(f = dbg_malloc(sizeof(*f)))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(f, 0, sizeof(*f));
|
||||
f->fp = fp;
|
||||
f->indent = 0;
|
||||
|
||||
if (!_build_pv_names(f, vg)) {
|
||||
stack;
|
||||
@ -514,32 +640,34 @@ int text_vg_export(FILE * fp, struct volume_group *vg, const char *desc)
|
||||
}
|
||||
#define fail do {stack; goto out;} while(0)
|
||||
|
||||
if (!_print_header(f, vg, desc))
|
||||
if (f->header && !_print_header(f, vg, desc))
|
||||
fail;
|
||||
|
||||
if (!_out(f, "%s {", vg->name))
|
||||
fail;
|
||||
|
||||
_out(f, "%s {", vg->name);
|
||||
_inc_indent(f);
|
||||
|
||||
if (!_print_vg(f, vg))
|
||||
fail;
|
||||
|
||||
_nl(f);
|
||||
f->nl(f);
|
||||
if (!_print_pvs(f, vg))
|
||||
fail;
|
||||
|
||||
_nl(f);
|
||||
f->nl(f);
|
||||
if (!_print_lvs(f, vg))
|
||||
fail;
|
||||
|
||||
_nl(f);
|
||||
if (!_print_snapshots(f, vg))
|
||||
_dec_indent(f);
|
||||
if (!_out(f, "}"))
|
||||
fail;
|
||||
|
||||
if (!f->header && !_print_header(f, vg, desc))
|
||||
fail;
|
||||
|
||||
#undef fail
|
||||
|
||||
_dec_indent(f);
|
||||
_out(f, "}");
|
||||
r = !ferror(f->fp);
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
if (f->mem)
|
||||
@ -548,6 +676,68 @@ int text_vg_export(FILE * fp, struct volume_group *vg, const char *desc)
|
||||
if (f->pv_names)
|
||||
hash_destroy(f->pv_names);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp)
|
||||
{
|
||||
struct formatter *f;
|
||||
int r;
|
||||
|
||||
_init();
|
||||
|
||||
if (!(f = dbg_malloc(sizeof(*f)))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(f, 0, sizeof(*f));
|
||||
f->data.fp = fp;
|
||||
f->indent = 0;
|
||||
f->header = 1;
|
||||
f->out_with_comment = &_out_with_comment_file;
|
||||
f->nl = &_nl_file;
|
||||
|
||||
r = _text_vg_export(f, vg, desc);
|
||||
if (r)
|
||||
r = !ferror(f->data.fp);
|
||||
dbg_free(f);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Returns amount of buffer used incl. terminating NUL */
|
||||
int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf,
|
||||
uint32_t size)
|
||||
{
|
||||
struct formatter *f;
|
||||
int r;
|
||||
|
||||
_init();
|
||||
|
||||
if (!(f = dbg_malloc(sizeof(*f)))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(f, 0, sizeof(*f));
|
||||
f->data.buf.buf = buf;
|
||||
f->data.buf.size = size;
|
||||
f->indent = 0;
|
||||
f->header = 0;
|
||||
f->out_with_comment = &_out_with_comment_raw;
|
||||
f->nl = &_nl_raw;
|
||||
|
||||
if (!_text_vg_export(f, vg, desc)) {
|
||||
stack;
|
||||
r = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = f->data.buf.used + 1;
|
||||
|
||||
out:
|
||||
dbg_free(f);
|
||||
return r;
|
||||
}
|
||||
|
||||
#undef _outf
|
||||
|
@ -4,7 +4,7 @@
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "log.h"
|
||||
#include "lib.h"
|
||||
#include "metadata.h"
|
||||
#include "import-export.h"
|
||||
#include "lvm-string.h"
|
||||
@ -60,7 +60,7 @@ static struct flag *_get_flags(int type)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _emit(char **buffer, size_t * size, const char *fmt, ...)
|
||||
static int _emit(char **buffer, size_t *size, const char *fmt, ...)
|
||||
{
|
||||
size_t n;
|
||||
va_list ap;
|
||||
@ -122,7 +122,7 @@ int print_flags(uint32_t status, int type, char *buffer, size_t size)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int read_flags(uint32_t * status, int type, struct config_value *cv)
|
||||
int read_flags(uint32_t *status, int type, struct config_value *cv)
|
||||
{
|
||||
int f;
|
||||
uint32_t s = 0;
|
||||
@ -133,31 +133,30 @@ int read_flags(uint32_t * status, int type, struct config_value *cv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only scan the flags if it wasn't an empty array.
|
||||
*/
|
||||
if (cv->type != CFG_EMPTY_ARRAY) {
|
||||
while (cv) {
|
||||
if (cv->type != CFG_STRING) {
|
||||
log_err("Status value is not a string.");
|
||||
return 0;
|
||||
}
|
||||
if (cv->type == CFG_EMPTY_ARRAY)
|
||||
goto out;
|
||||
|
||||
for (f = 0; flags[f].description; f++)
|
||||
if (!strcmp(flags[f].description, cv->v.str)) {
|
||||
s |= flags[f].mask;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!flags[f].description) {
|
||||
log_err("Unknown status flag '%s'.", cv->v.str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cv = cv->next;
|
||||
while (cv) {
|
||||
if (cv->type != CFG_STRING) {
|
||||
log_err("Status value is not a string.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (f = 0; flags[f].description; f++)
|
||||
if (!strcmp(flags[f].description, cv->v.str)) {
|
||||
s |= flags[f].mask;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!flags[f].description) {
|
||||
log_err("Unknown status flag '%s'.", cv->v.str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cv = cv->next;
|
||||
}
|
||||
|
||||
out:
|
||||
*status = s;
|
||||
return 1;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -9,7 +9,10 @@
|
||||
|
||||
#include "lvm-types.h"
|
||||
#include "metadata.h"
|
||||
#include "uuid-map.h"
|
||||
#include "pool.h"
|
||||
|
||||
#define FMT_TEXT_NAME "lvm2"
|
||||
#define FMT_TEXT_ALIAS "text"
|
||||
|
||||
/*
|
||||
* Archives a vg config. 'retain_days' is the minimum number of
|
||||
@ -19,21 +22,33 @@
|
||||
*/
|
||||
int archive_vg(struct volume_group *vg,
|
||||
const char *dir,
|
||||
const char *desc,
|
||||
uint32_t retain_days,
|
||||
uint32_t min_archive);
|
||||
const char *desc, uint32_t retain_days, uint32_t min_archive);
|
||||
|
||||
/*
|
||||
* Displays a list of vg backups in a particular archive directory.
|
||||
*/
|
||||
int archive_list(struct cmd_context *cmd, struct uuid_map *um,
|
||||
const char *dir, const char *vg);
|
||||
int archive_list(struct cmd_context *cmd, const char *dir, const char *vg);
|
||||
|
||||
/*
|
||||
* The text format can read and write a volume_group to a file.
|
||||
*/
|
||||
struct format_type *create_text_format(struct cmd_context *cmd);
|
||||
void *create_text_context(struct format_type *fmt, const char *path,
|
||||
void *create_text_context(struct cmd_context *cmd, const char *path,
|
||||
const char *desc);
|
||||
|
||||
struct labeller *text_labeller_create(struct format_type *fmt);
|
||||
|
||||
int pvhdr_read(struct device *dev, char *buf);
|
||||
|
||||
int add_da(struct format_type *fmt, struct pool *mem, struct list *das,
|
||||
uint64_t start, uint64_t size);
|
||||
void del_das(struct list *das);
|
||||
|
||||
int add_mda(struct format_type *fmt, struct pool *mem, struct list *mdas,
|
||||
struct device *dev, uint64_t start, uint64_t size);
|
||||
void del_mdas(struct list *mdas);
|
||||
|
||||
int vgname_from_mda(struct format_type *fmt, struct device_area *dev_area,
|
||||
char *buf, uint32_t size);
|
||||
|
||||
#endif
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include "config.h"
|
||||
#include "lvm-types.h"
|
||||
#include "metadata.h"
|
||||
#include "uuid-map.h"
|
||||
#include "pool.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
@ -33,14 +33,32 @@ enum {
|
||||
LV_FLAGS
|
||||
};
|
||||
|
||||
struct text_vg_version_ops {
|
||||
int (*check_version) (struct config_tree * cf);
|
||||
struct volume_group *(*read_vg) (struct format_instance * fid,
|
||||
struct config_tree * cf);
|
||||
void (*read_desc) (struct pool * mem, struct config_tree * cf,
|
||||
time_t *when, char **desc);
|
||||
};
|
||||
|
||||
struct text_vg_version_ops *text_vg_vsn1_init(void);
|
||||
|
||||
int print_flags(uint32_t status, int type, char *buffer, size_t size);
|
||||
int read_flags(uint32_t *status, int type, struct config_value *cv);
|
||||
|
||||
|
||||
int text_vg_export(FILE *fp, struct volume_group *vg, const char *desc);
|
||||
struct volume_group *text_vg_import(struct format_instance *fid,
|
||||
const char *file,
|
||||
struct uuid_map *um,
|
||||
time_t *when, char **desc);
|
||||
int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp);
|
||||
int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf,
|
||||
uint32_t size);
|
||||
struct volume_group *text_vg_import_file(struct format_instance *fid,
|
||||
const char *file,
|
||||
time_t *when, char **desc);
|
||||
struct volume_group *text_vg_import_fd(struct format_instance *fid,
|
||||
const char *file,
|
||||
int fd,
|
||||
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);
|
||||
|
||||
#endif
|
||||
|
@ -4,743 +4,80 @@
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "metadata.h"
|
||||
#include "import-export.h"
|
||||
#include "pool.h"
|
||||
#include "log.h"
|
||||
#include "uuid.h"
|
||||
#include "display.h"
|
||||
#include "hash.h"
|
||||
#include "toolcontext.h"
|
||||
#include "display.h"
|
||||
|
||||
typedef int (*section_fn) (struct format_instance * fid, struct pool * mem,
|
||||
struct volume_group * vg, struct config_node * pvn,
|
||||
struct config_node * vgn,
|
||||
struct hash_table * pv_hash, struct uuid_map * um);
|
||||
|
||||
#define _read_int32(root, path, result) \
|
||||
get_config_uint32(root, path, '/', result)
|
||||
|
||||
#define _read_uint32(root, path, result) \
|
||||
get_config_uint32(root, path, '/', result)
|
||||
|
||||
#define _read_int64(root, path, result) \
|
||||
get_config_uint64(root, path, '/', result)
|
||||
|
||||
/*
|
||||
* Logs an attempt to read an invalid format file.
|
||||
*/
|
||||
static void _invalid_format(const char *str)
|
||||
{
|
||||
log_error("Can't process text format file (%s)", str);
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks that the config file contains vg metadata, and that it
|
||||
* we recognise the version number,
|
||||
*/
|
||||
static int _check_version(struct config_file *cf)
|
||||
{
|
||||
struct config_node *cn;
|
||||
struct config_value *cv;
|
||||
|
||||
/*
|
||||
* Check the contents field.
|
||||
*/
|
||||
if (!(cn = find_config_node(cf->root, CONTENTS_FIELD, '/'))) {
|
||||
_invalid_format("missing contents field");
|
||||
return 0;
|
||||
}
|
||||
|
||||
cv = cn->v;
|
||||
if (!cv || cv->type != CFG_STRING || strcmp(cv->v.str, CONTENTS_VALUE))
|
||||
{
|
||||
_invalid_format("unrecognised contents field");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the version number.
|
||||
*/
|
||||
if (!(cn = find_config_node(cf->root, FORMAT_VERSION_FIELD, '/'))) {
|
||||
_invalid_format("missing version number");
|
||||
return 0;
|
||||
}
|
||||
|
||||
cv = cn->v;
|
||||
if (!cv || cv->type != CFG_INT || cv->v.i != FORMAT_VERSION_VALUE) {
|
||||
_invalid_format("unrecognised version number");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read_id(struct id *id, struct config_node *cn, const char *path)
|
||||
{
|
||||
struct config_value *cv;
|
||||
|
||||
if (!(cn = find_config_node(cn, path, '/'))) {
|
||||
log_error("Couldn't find uuid.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
cv = cn->v;
|
||||
if (!cv || !cv->v.str) {
|
||||
log_error("uuid must be a string.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!id_read_format(id, cv->v.str)) {
|
||||
log_error("Invalid uuid.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read_pv(struct format_instance *fid, struct pool *mem,
|
||||
struct volume_group *vg, struct config_node *pvn,
|
||||
struct config_node *vgn,
|
||||
struct hash_table *pv_hash, struct uuid_map *um)
|
||||
{
|
||||
struct physical_volume *pv;
|
||||
struct pv_list *pvl;
|
||||
struct config_node *cn;
|
||||
|
||||
if (!(pvl = pool_zalloc(mem, sizeof(*pvl))) ||
|
||||
!(pvl->pv = pool_zalloc(mem, sizeof(*pvl->pv)))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
pv = pvl->pv;
|
||||
|
||||
/*
|
||||
* Add the pv to the pv hash for quick lookup when we read
|
||||
* the lv segments.
|
||||
*/
|
||||
if (!hash_insert(pv_hash, pvn->key, pv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(pvn = pvn->child)) {
|
||||
log_error("Empty pv section.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_read_id(&pv->id, pvn, "id")) {
|
||||
log_error("Couldn't read uuid for volume group.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use the uuid map to convert the uuid into a device.
|
||||
*/
|
||||
if (!(pv->dev = uuid_map_lookup(um, &pv->id))) {
|
||||
char buffer[64];
|
||||
|
||||
if (!id_write_format(&pv->id, buffer, sizeof(buffer)))
|
||||
log_error("Couldn't find device.");
|
||||
else
|
||||
log_error("Couldn't find device with uuid '%s'.", buffer);
|
||||
|
||||
if (partial_mode())
|
||||
vg->status |= PARTIAL_VG;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(pv->vg_name = pool_strdup(mem, vg->name))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(cn = find_config_node(pvn, "status", '/'))) {
|
||||
log_error("Couldn't find status flags for physical volume.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(read_flags(&pv->status, PV_FLAGS, cn->v))) {
|
||||
log_error("Couldn't read status flags for physical volume.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_read_int64(pvn, "pe_start", &pv->pe_start)) {
|
||||
log_error("Couldn't read extent size for volume group.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_read_int32(pvn, "pe_count", &pv->pe_count)) {
|
||||
log_error("Couldn't find extent count (pe_count) for "
|
||||
"physical volume.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* adjust the volume group. */
|
||||
vg->extent_count += pv->pe_count;
|
||||
vg->free_count += pv->pe_count;
|
||||
|
||||
pv->pe_size = vg->extent_size;
|
||||
pv->size = pv->pe_size * (uint64_t) pv->pe_count;
|
||||
pv->pe_alloc_count = 0;
|
||||
pv->fid = fid;
|
||||
|
||||
vg->pv_count++;
|
||||
list_add(&vg->pvs, &pvl->list);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _insert_segment(struct logical_volume *lv,
|
||||
struct stripe_segment *seg)
|
||||
{
|
||||
struct list *segh;
|
||||
struct stripe_segment *comp;
|
||||
|
||||
list_iterate(segh, &lv->segments) {
|
||||
comp = list_item(segh, struct stripe_segment);
|
||||
|
||||
if (comp->le > seg->le) {
|
||||
list_add(&comp->list, &seg->list);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
lv->le_count += seg->len;
|
||||
list_add(&lv->segments, &seg->list);
|
||||
}
|
||||
|
||||
static int _read_segment(struct pool *mem, struct volume_group *vg,
|
||||
struct logical_volume *lv, struct config_node *sn,
|
||||
struct hash_table *pv_hash)
|
||||
{
|
||||
int s;
|
||||
uint32_t stripes;
|
||||
struct stripe_segment *seg;
|
||||
struct config_node *cn;
|
||||
struct config_value *cv;
|
||||
const char *seg_name = sn->key;
|
||||
|
||||
if (!(sn = sn->child)) {
|
||||
log_error("Empty segment section.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_read_int32(sn, "stripes", &stripes)) {
|
||||
log_error("Couldn't read 'stripes' for segment '%s'.", sn->key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(seg = pool_zalloc(mem, sizeof(*seg) +
|
||||
(sizeof(seg->area[0]) * stripes)))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
seg->stripes = stripes;
|
||||
seg->lv = lv;
|
||||
|
||||
if (!_read_int32(sn, "start_extent", &seg->le)) {
|
||||
log_error("Couldn't read 'start_extent' for segment '%s'.",
|
||||
sn->key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_read_int32(sn, "extent_count", &seg->len)) {
|
||||
log_error("Couldn't read 'extent_count' for segment '%s'.",
|
||||
sn->key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (seg->stripes == 0) {
|
||||
log_error("Zero stripes is *not* allowed for segment '%s'.",
|
||||
sn->key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((seg->stripes != 1) &&
|
||||
!_read_int32(sn, "stripe_size", &seg->stripe_size)) {
|
||||
log_error("Couldn't read 'stripe_size' for segment '%s'.",
|
||||
sn->key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(cn = find_config_node(sn, "areas", '/'))) {
|
||||
log_error("Couldn't find 'areas' array for segment '%s'.",
|
||||
sn->key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the stripes from the 'areas' array.
|
||||
* FIXME: we could move this to a separate function.
|
||||
*/
|
||||
for (cv = cn->v, s = 0; cv && s < seg->stripes; s++, cv = cv->next) {
|
||||
|
||||
/* first we read the pv */
|
||||
const char *bad = "Badly formed areas array for segment '%s'.";
|
||||
struct physical_volume *pv;
|
||||
uint32_t allocated;
|
||||
|
||||
if (cv->type != CFG_STRING) {
|
||||
log_error(bad, sn->key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(pv = hash_lookup(pv_hash, cv->v.str))) {
|
||||
log_error("Couldn't find physical volume '%s' for "
|
||||
"segment '%s'.",
|
||||
cv->v.str ? cv->v.str : "NULL", seg_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
seg->area[s].pv = pv;
|
||||
|
||||
if (!(cv = cv->next)) {
|
||||
log_error(bad, sn->key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cv->type != CFG_INT) {
|
||||
log_error(bad, sn->key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
seg->area[s].pe = cv->v.i;
|
||||
|
||||
/*
|
||||
* Adjust the extent counts in the pv and vg.
|
||||
*/
|
||||
allocated = seg->len / seg->stripes;
|
||||
pv->pe_alloc_count += allocated;
|
||||
vg->free_count -= allocated;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check we read the correct number of stripes.
|
||||
*/
|
||||
if (cv || (s < seg->stripes)) {
|
||||
log_error("Incorrect number of stripes in 'area' array "
|
||||
"for segment '%s'.", seg_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert into correct part of segment list.
|
||||
*/
|
||||
_insert_segment(lv, seg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read_segments(struct pool *mem, struct volume_group *vg,
|
||||
struct logical_volume *lv, struct config_node *lvn,
|
||||
struct hash_table *pv_hash)
|
||||
{
|
||||
struct config_node *sn;
|
||||
int count = 0, seg_count;
|
||||
|
||||
for (sn = lvn; sn; sn = sn->sib) {
|
||||
|
||||
/*
|
||||
* All sub-sections are assumed to be segments.
|
||||
*/
|
||||
if (!sn->v) {
|
||||
if (!_read_segment(mem, vg, lv, sn, pv_hash)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_read_int32(lvn, "segment_count", &seg_count)) {
|
||||
log_error("Couldn't read segment count for logical volume.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (seg_count != count) {
|
||||
log_error("segment_count and actual number of segments "
|
||||
"disagree.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check there are no gaps or overlaps in the lv.
|
||||
*/
|
||||
if (!lv_check_segments(lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Merge segments in case someones been editing things by hand.
|
||||
*/
|
||||
if (!lv_merge_segments(lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read_lv(struct format_instance *fid, struct pool *mem,
|
||||
struct volume_group *vg, struct config_node *lvn,
|
||||
struct config_node *vgn, struct hash_table *pv_hash,
|
||||
struct uuid_map *um)
|
||||
{
|
||||
struct logical_volume *lv;
|
||||
struct lv_list *lvl;
|
||||
struct config_node *cn;
|
||||
|
||||
if (!(lvl = pool_zalloc(mem, sizeof(*lvl))) ||
|
||||
!(lvl->lv = pool_zalloc(mem, sizeof(*lvl->lv)))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
lv = lvl->lv;
|
||||
|
||||
if (!(lv->name = pool_strdup(mem, lvn->key))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(lvn = lvn->child)) {
|
||||
log_error("Empty logical volume section.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
lv->vg = vg;
|
||||
|
||||
/* FIXME: read full lvid */
|
||||
if (!_read_id(&lv->lvid.id[1], lvn, "id")) {
|
||||
log_error("Couldn't read uuid for logical volume %s.", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(&lv->lvid.id[0], &lv->vg->id, sizeof(lv->lvid.id[0]));
|
||||
|
||||
if (!(cn = find_config_node(lvn, "status", '/'))) {
|
||||
log_error("Couldn't find status flags for logical volume.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(read_flags(&lv->status, LV_FLAGS, cn->v))) {
|
||||
log_error("Couldn't read status flags for logical volume.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
lv->minor = -1;
|
||||
if ((lv->status & FIXED_MINOR) &&
|
||||
!_read_int32(lvn, "minor", &lv->minor)) {
|
||||
log_error("Couldn't read 'minor' value for logical volume.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* allocation_policy is optional since it is meaning less
|
||||
* for things like mirrors and snapshots. Where it isn't
|
||||
* specified we default to the next free policy.
|
||||
*/
|
||||
lv->alloc = ALLOC_NEXT_FREE;
|
||||
if ((cn = find_config_node(lvn, "allocation_policy", '/'))) {
|
||||
struct config_value *cv = cn->v;
|
||||
if (!cv || !cv->v.str) {
|
||||
log_err("allocation_policy must be a string.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
lv->alloc = get_alloc_from_string(cv->v.str);
|
||||
}
|
||||
|
||||
if (!_read_int32(lvn, "read_ahead", &lv->read_ahead)) {
|
||||
log_error("Couldn't read 'read_ahead' value for "
|
||||
"logical volume.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_init(&lv->segments);
|
||||
if (!_read_segments(mem, vg, lv, lvn, pv_hash)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
lv->size = (uint64_t) lv->le_count * (uint64_t) vg->extent_size;
|
||||
|
||||
vg->lv_count++;
|
||||
list_add(&vg->lvs, &lvl->list);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read_snapshot(struct format_instance *fid, struct pool *mem,
|
||||
struct volume_group *vg, struct config_node *sn,
|
||||
struct config_node *vgn, struct hash_table *pv_hash,
|
||||
struct uuid_map *um)
|
||||
{
|
||||
uint32_t chunk_size;
|
||||
const char *org_name, *cow_name;
|
||||
struct logical_volume *org, *cow;
|
||||
|
||||
if (!(sn = sn->child)) {
|
||||
log_error("Empty snapshot section.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_read_uint32(sn, "chunk_size", &chunk_size)) {
|
||||
log_error("Couldn't read chunk size for snapshot.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(cow_name = find_config_str(sn, "cow_store", '/', NULL))) {
|
||||
log_error("Snapshot cow storage not specified.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(org_name = find_config_str(sn, "origin", '/', NULL))) {
|
||||
log_error("Snapshot origin not specified.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(cow = find_lv(vg, cow_name))) {
|
||||
log_error("Unknown logical volume specified for "
|
||||
"snapshot cow store.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(org = find_lv(vg, org_name))) {
|
||||
log_error("Unknown logical volume specified for "
|
||||
"snapshot origin.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!vg_add_snapshot(org, cow, 1, chunk_size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read_sections(struct format_instance *fid,
|
||||
const char *section, section_fn fn,
|
||||
struct pool *mem,
|
||||
struct volume_group *vg, struct config_node *vgn,
|
||||
struct hash_table *pv_hash,
|
||||
struct uuid_map *um, int optional)
|
||||
{
|
||||
struct config_node *n;
|
||||
|
||||
if (!(n = find_config_node(vgn, section, '/'))) {
|
||||
if (!optional) {
|
||||
log_error("Couldn't find section '%s'.", section);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (n = n->child; n; n = n->sib) {
|
||||
if (!fn(fid, mem, vg, n, vgn, pv_hash, um)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct volume_group *_read_vg(struct format_instance *fid,
|
||||
struct config_file *cf,
|
||||
struct uuid_map *um)
|
||||
{
|
||||
struct config_node *vgn, *cn;
|
||||
struct volume_group *vg;
|
||||
struct hash_table *pv_hash = NULL;
|
||||
struct pool *mem = fid->fmt->cmd->mem;
|
||||
|
||||
/* skip any top-level values */
|
||||
for (vgn = cf->root; (vgn && vgn->v); vgn = vgn->sib) ;
|
||||
|
||||
if (!vgn) {
|
||||
log_error("Couldn't find volume group in file.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(vg = pool_zalloc(mem, sizeof(*vg)))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
vg->cmd = fid->fmt->cmd;
|
||||
|
||||
/* FIXME Determine format type from file contents */
|
||||
/* eg Set to instance of fmt1 here if reading a format1 backup? */
|
||||
vg->fid = fid;
|
||||
|
||||
if (!(vg->name = pool_strdup(mem, vgn->key))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!(vg->system_id = pool_zalloc(mem, NAME_LEN))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
vgn = vgn->child;
|
||||
|
||||
if ((cn = find_config_node(vgn, "system_id", '/')) && cn->v) {
|
||||
if (!cn->v->v.str) {
|
||||
log_error("system_id must be a string");
|
||||
goto bad;
|
||||
}
|
||||
strncpy(vg->system_id, cn->v->v.str, NAME_LEN);
|
||||
}
|
||||
|
||||
if (!_read_id(&vg->id, vgn, "id")) {
|
||||
log_error("Couldn't read uuid for volume group %s.", vg->name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!_read_int32(vgn, "seqno", &vg->seqno)) {
|
||||
log_error("Couldn't read 'seqno' for volume group %s.", vg->name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!(cn = find_config_node(vgn, "status", '/'))) {
|
||||
log_error("Couldn't find status flags for volume group %s.",
|
||||
vg->name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!(read_flags(&vg->status, VG_FLAGS, cn->v))) {
|
||||
log_error("Couldn't read status flags for volume group %s.",
|
||||
vg->name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!_read_int32(vgn, "extent_size", &vg->extent_size)) {
|
||||
log_error("Couldn't read extent size for volume group %s.",
|
||||
vg->name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* 'extent_count' and 'free_count' get filled in
|
||||
* implicitly when reading in the pv's and lv's.
|
||||
*/
|
||||
|
||||
if (!_read_int32(vgn, "max_lv", &vg->max_lv)) {
|
||||
log_error("Couldn't read 'max_lv' for volume group %s.",
|
||||
vg->name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!_read_int32(vgn, "max_pv", &vg->max_pv)) {
|
||||
log_error("Couldn't read 'max_pv' for volume group %s.",
|
||||
vg->name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* The pv hash memoises the pv section names -> pv
|
||||
* structures.
|
||||
*/
|
||||
if (!(pv_hash = hash_create(32))) {
|
||||
log_error("Couldn't create hash table.");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
list_init(&vg->pvs);
|
||||
if (!_read_sections(fid, "physical_volumes", _read_pv, mem, vg,
|
||||
vgn, pv_hash, um, 0)) {
|
||||
log_error("Couldn't find all physical volumes for volume "
|
||||
"group %s.", vg->name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
list_init(&vg->lvs);
|
||||
if (!_read_sections(fid, "logical_volumes", _read_lv, mem, vg,
|
||||
vgn, pv_hash, um, 1)) {
|
||||
log_error("Couldn't read all logical volumes for volume "
|
||||
"group %s.", vg->name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
list_init(&vg->snapshots);
|
||||
if (!_read_sections(fid, "snapshots", _read_snapshot, mem, vg,
|
||||
vgn, pv_hash, um, 1)) {
|
||||
log_error("Couldn't read all snapshots for volume group %s.",
|
||||
vg->name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
hash_destroy(pv_hash);
|
||||
|
||||
if (vg->status & PARTIAL_VG) {
|
||||
vg->status &= ~LVM_WRITE;
|
||||
vg->status |= LVM_READ;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finished.
|
||||
*/
|
||||
return vg;
|
||||
|
||||
bad:
|
||||
if (pv_hash)
|
||||
hash_destroy(pv_hash);
|
||||
|
||||
pool_free(mem, vg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void _read_desc(struct pool *mem,
|
||||
struct config_file *cf, time_t * when, char **desc)
|
||||
{
|
||||
const char *d;
|
||||
unsigned int u = 0u;
|
||||
|
||||
d = find_config_str(cf->root, "description", '/', "");
|
||||
*desc = pool_strdup(mem, d);
|
||||
|
||||
get_config_uint32(cf->root, "creation_time", '/', &u);
|
||||
*when = u;
|
||||
}
|
||||
|
||||
struct volume_group *text_vg_import(struct format_instance *fid,
|
||||
const char *file,
|
||||
struct uuid_map *um,
|
||||
time_t * when, char **desc)
|
||||
#include "cache.h"
|
||||
|
||||
/* FIXME Use tidier inclusion method */
|
||||
static struct text_vg_version_ops *(_text_vsn_list[2]);
|
||||
|
||||
struct volume_group *text_vg_import_fd(struct format_instance *fid,
|
||||
const char *file,
|
||||
int fd,
|
||||
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 volume_group *vg = NULL;
|
||||
struct config_file *cf;
|
||||
struct config_tree *cf;
|
||||
struct text_vg_version_ops **vsn;
|
||||
|
||||
static int _initialised = 0;
|
||||
|
||||
if (!_initialised) {
|
||||
_text_vsn_list[0] = text_vg_vsn1_init();
|
||||
_text_vsn_list[1] = NULL;
|
||||
_initialised = 1;
|
||||
}
|
||||
|
||||
*desc = NULL;
|
||||
*when = 0;
|
||||
|
||||
if (!(cf = create_config_file())) {
|
||||
if (!(cf = create_config_tree())) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!read_config(cf, file)) {
|
||||
log_error("Couldn't read volume group file.");
|
||||
if ((fd == -1 && !read_config_file(cf, file)) ||
|
||||
(fd != -1 && !read_config_fd(cf, fd, file, offset, size,
|
||||
offset2, size2, checksum_fn,
|
||||
checksum))) {
|
||||
log_error("Couldn't read volume group metadata.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!_check_version(cf))
|
||||
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(cf))
|
||||
continue;
|
||||
|
||||
if (!(vg = _read_vg(fid, cf, um))) {
|
||||
stack;
|
||||
goto out;
|
||||
if (!(vg = (*vsn)->read_vg(fid, cf))) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
(*vsn)->read_desc(fid->fmt->cmd->mem, cf, when, desc);
|
||||
break;
|
||||
}
|
||||
|
||||
_read_desc(fid->fmt->cmd->mem, cf, when, desc);
|
||||
|
||||
out:
|
||||
destroy_config_file(cf);
|
||||
destroy_config_tree(cf);
|
||||
return vg;
|
||||
}
|
||||
|
||||
struct volume_group *text_vg_import_file(struct format_instance *fid,
|
||||
const char *file,
|
||||
time_t *when, char **desc)
|
||||
{
|
||||
return text_vg_import_fd(fid, file, -1, 0, 0, 0, 0, NULL, 0,
|
||||
when, desc);
|
||||
}
|
||||
|
735
lib/format_text/import_vsn1.c
Normal file
735
lib/format_text/import_vsn1.c
Normal file
@ -0,0 +1,735 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "metadata.h"
|
||||
#include "import-export.h"
|
||||
#include "pool.h"
|
||||
#include "display.h"
|
||||
#include "hash.h"
|
||||
#include "toolcontext.h"
|
||||
#include "cache.h"
|
||||
|
||||
typedef int (*section_fn) (struct format_instance * fid, struct pool * mem,
|
||||
struct volume_group * vg, struct config_node * pvn,
|
||||
struct config_node * vgn,
|
||||
struct hash_table * pv_hash);
|
||||
|
||||
#define _read_int32(root, path, result) \
|
||||
get_config_uint32(root, path, '/', result)
|
||||
|
||||
#define _read_uint32(root, path, result) \
|
||||
get_config_uint32(root, path, '/', result)
|
||||
|
||||
#define _read_int64(root, path, result) \
|
||||
get_config_uint64(root, path, '/', result)
|
||||
|
||||
/*
|
||||
* Logs an attempt to read an invalid format file.
|
||||
*/
|
||||
static void _invalid_format(const char *str)
|
||||
{
|
||||
log_error("Can't process text format file - %s.", str);
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks that the config file contains vg metadata, and that it
|
||||
* we recognise the version number,
|
||||
*/
|
||||
static int _check_version(struct config_tree *cf)
|
||||
{
|
||||
struct config_node *cn;
|
||||
struct config_value *cv;
|
||||
|
||||
/*
|
||||
* Check the contents field.
|
||||
*/
|
||||
if (!(cn = find_config_node(cf->root, CONTENTS_FIELD, '/'))) {
|
||||
_invalid_format("missing contents field");
|
||||
return 0;
|
||||
}
|
||||
|
||||
cv = cn->v;
|
||||
if (!cv || cv->type != CFG_STRING || strcmp(cv->v.str, CONTENTS_VALUE)) {
|
||||
_invalid_format("unrecognised contents field");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the version number.
|
||||
*/
|
||||
if (!(cn = find_config_node(cf->root, FORMAT_VERSION_FIELD, '/'))) {
|
||||
_invalid_format("missing version number");
|
||||
return 0;
|
||||
}
|
||||
|
||||
cv = cn->v;
|
||||
if (!cv || cv->type != CFG_INT || cv->v.i != FORMAT_VERSION_VALUE) {
|
||||
_invalid_format("unrecognised version number");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read_id(struct id *id, struct config_node *cn, const char *path)
|
||||
{
|
||||
struct config_value *cv;
|
||||
|
||||
if (!(cn = find_config_node(cn, path, '/'))) {
|
||||
log_error("Couldn't find uuid.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
cv = cn->v;
|
||||
if (!cv || !cv->v.str) {
|
||||
log_error("uuid must be a string.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!id_read_format(id, cv->v.str)) {
|
||||
log_error("Invalid uuid.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read_pv(struct format_instance *fid, struct pool *mem,
|
||||
struct volume_group *vg, struct config_node *pvn,
|
||||
struct config_node *vgn, struct hash_table *pv_hash)
|
||||
{
|
||||
struct physical_volume *pv;
|
||||
struct pv_list *pvl;
|
||||
struct config_node *cn;
|
||||
|
||||
if (!(pvl = pool_zalloc(mem, sizeof(*pvl))) ||
|
||||
!(pvl->pv = pool_zalloc(mem, sizeof(*pvl->pv)))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
pv = pvl->pv;
|
||||
|
||||
/*
|
||||
* Add the pv to the pv hash for quick lookup when we read
|
||||
* the lv segments.
|
||||
*/
|
||||
if (!hash_insert(pv_hash, pvn->key, pv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(pvn = pvn->child)) {
|
||||
log_error("Empty pv section.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_read_id(&pv->id, pvn, "id")) {
|
||||
log_error("Couldn't read uuid for volume group.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert the uuid into a device.
|
||||
*/
|
||||
if (!(pv->dev = device_from_pvid(fid->fmt->cmd, &pv->id))) {
|
||||
char buffer[64];
|
||||
|
||||
if (!id_write_format(&pv->id, buffer, sizeof(buffer)))
|
||||
log_error("Couldn't find device.");
|
||||
else
|
||||
log_error("Couldn't find device with uuid '%s'.",
|
||||
buffer);
|
||||
|
||||
if (partial_mode())
|
||||
vg->status |= PARTIAL_VG;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(pv->vg_name = pool_strdup(mem, vg->name))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(cn = find_config_node(pvn, "status", '/'))) {
|
||||
log_error("Couldn't find status flags for physical volume.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(read_flags(&pv->status, PV_FLAGS, cn->v))) {
|
||||
log_error("Couldn't read status flags for physical volume.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_read_int64(pvn, "pe_start", &pv->pe_start)) {
|
||||
log_error("Couldn't read extent size for volume group.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_read_int32(pvn, "pe_count", &pv->pe_count)) {
|
||||
log_error("Couldn't find extent count (pe_count) for "
|
||||
"physical volume.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* adjust the volume group. */
|
||||
vg->extent_count += pv->pe_count;
|
||||
vg->free_count += pv->pe_count;
|
||||
|
||||
pv->pe_size = vg->extent_size;
|
||||
pv->size = vg->extent_size * (uint64_t) pv->pe_count;
|
||||
pv->pe_alloc_count = 0;
|
||||
pv->fmt = fid->fmt;
|
||||
|
||||
vg->pv_count++;
|
||||
list_add(&vg->pvs, &pvl->list);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _insert_segment(struct logical_volume *lv, struct lv_segment *seg)
|
||||
{
|
||||
struct list *segh;
|
||||
struct lv_segment *comp;
|
||||
|
||||
list_iterate(segh, &lv->segments) {
|
||||
comp = list_item(segh, struct lv_segment);
|
||||
|
||||
if (comp->le > seg->le) {
|
||||
list_add(&comp->list, &seg->list);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
lv->le_count += seg->len;
|
||||
list_add(&lv->segments, &seg->list);
|
||||
}
|
||||
|
||||
static int _read_segment(struct pool *mem, struct volume_group *vg,
|
||||
struct logical_volume *lv, struct config_node *sn,
|
||||
struct hash_table *pv_hash)
|
||||
{
|
||||
int s;
|
||||
uint32_t stripes = 0;
|
||||
struct lv_segment *seg;
|
||||
struct config_node *cn;
|
||||
struct config_value *cv;
|
||||
const char *seg_name = sn->key;
|
||||
uint32_t start_extent, extent_count;
|
||||
uint32_t chunk_size;
|
||||
const char *org_name, *cow_name;
|
||||
struct logical_volume *org, *cow;
|
||||
segment_type_t segtype;
|
||||
|
||||
if (!(sn = sn->child)) {
|
||||
log_error("Empty segment section.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_read_int32(sn, "start_extent", &start_extent)) {
|
||||
log_error("Couldn't read 'start_extent' for segment '%s'.",
|
||||
sn->key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_read_int32(sn, "extent_count", &extent_count)) {
|
||||
log_error("Couldn't read 'extent_count' for segment '%s'.",
|
||||
sn->key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
segtype = SEG_STRIPED; /* Default */
|
||||
if ((cn = find_config_node(sn, "type", '/'))) {
|
||||
cv = cn->v;
|
||||
if (!cv || !cv->v.str) {
|
||||
log_error("Segment type must be a string.");
|
||||
return 0;
|
||||
}
|
||||
segtype = get_segtype_from_string(cv->v.str);
|
||||
}
|
||||
|
||||
if (segtype == SEG_STRIPED) {
|
||||
if (!_read_int32(sn, "stripe_count", &stripes)) {
|
||||
log_error("Couldn't read 'stripe_count' for "
|
||||
"segment '%s'.", sn->key);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(seg = pool_zalloc(mem, sizeof(*seg) +
|
||||
(sizeof(seg->area[0]) * stripes)))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
seg->lv = lv;
|
||||
seg->le = start_extent;
|
||||
seg->len = extent_count;
|
||||
|
||||
switch (segtype) {
|
||||
case SEG_MIRROR:
|
||||
case SEG_SNAPSHOT:
|
||||
lv->status |= SNAPSHOT;
|
||||
|
||||
if (!_read_uint32(sn, "chunk_size", &chunk_size)) {
|
||||
log_error("Couldn't read chunk size for snapshot.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_suppress(1);
|
||||
|
||||
if (!(cow_name = find_config_str(sn, "cow_store", '/', NULL))) {
|
||||
log_suppress(0);
|
||||
log_error("Snapshot cow storage not specified.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(org_name = find_config_str(sn, "origin", '/', NULL))) {
|
||||
log_suppress(0);
|
||||
log_error("Snapshot origin not specified.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_suppress(0);
|
||||
|
||||
if (!(cow = find_lv(vg, cow_name))) {
|
||||
log_error("Unknown logical volume specified for "
|
||||
"snapshot cow store.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(org = find_lv(vg, org_name))) {
|
||||
log_error("Unknown logical volume specified for "
|
||||
"snapshot origin.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!vg_add_snapshot(org, cow, 1, &lv->lvid.id[1], chunk_size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case SEG_STRIPED:
|
||||
seg->stripes = stripes;
|
||||
|
||||
if (!seg->stripes) {
|
||||
log_error("Zero stripes *not* allowed for segment '%s'",
|
||||
sn->key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((seg->stripes != 1) &&
|
||||
!_read_int32(sn, "stripe_size", &seg->stripe_size)) {
|
||||
log_error("Couldn't read stripe_size for segment '%s'.",
|
||||
sn->key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(cn = find_config_node(sn, "stripes", '/'))) {
|
||||
log_error("Couldn't find stripes array for segment "
|
||||
"'%s'.", sn->key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (cv = cn->v, s = 0; cv && s < seg->stripes;
|
||||
s++, cv = cv->next) {
|
||||
|
||||
/* first we read the pv */
|
||||
const char *bad = "Badly formed areas array for "
|
||||
"segment '%s'.";
|
||||
struct physical_volume *pv;
|
||||
uint32_t allocated;
|
||||
|
||||
if (cv->type != CFG_STRING) {
|
||||
log_error(bad, sn->key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(pv = hash_lookup(pv_hash, cv->v.str))) {
|
||||
log_error("Couldn't find physical volume '%s' "
|
||||
"for segment '%s'.",
|
||||
cv->v.str ? cv->v.str : "NULL",
|
||||
seg_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
seg->area[s].pv = pv;
|
||||
|
||||
if (!(cv = cv->next)) {
|
||||
log_error(bad, sn->key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cv->type != CFG_INT) {
|
||||
log_error(bad, sn->key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
seg->area[s].pe = cv->v.i;
|
||||
|
||||
/*
|
||||
* Adjust the extent counts in the pv and vg.
|
||||
*/
|
||||
allocated = seg->len / seg->stripes;
|
||||
pv->pe_alloc_count += allocated;
|
||||
vg->free_count -= allocated;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check we read the correct number of stripes.
|
||||
*/
|
||||
if (cv || (s < seg->stripes)) {
|
||||
log_error("Incorrect number of stripes in 'area' array "
|
||||
"for segment '%s'.", seg_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert into correct part of segment list.
|
||||
*/
|
||||
_insert_segment(lv, seg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read_segments(struct pool *mem, struct volume_group *vg,
|
||||
struct logical_volume *lv, struct config_node *lvn,
|
||||
struct hash_table *pv_hash)
|
||||
{
|
||||
struct config_node *sn;
|
||||
int count = 0, seg_count;
|
||||
|
||||
for (sn = lvn; sn; sn = sn->sib) {
|
||||
|
||||
/*
|
||||
* All sub-sections are assumed to be segments.
|
||||
*/
|
||||
if (!sn->v) {
|
||||
if (!_read_segment(mem, vg, lv, sn, pv_hash)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
/* FIXME Remove this restriction */
|
||||
if ((lv->status & SNAPSHOT) && count > 1) {
|
||||
log_error("Only one segment permitted for snapshot");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_read_int32(lvn, "segment_count", &seg_count)) {
|
||||
log_error("Couldn't read segment count for logical volume.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (seg_count != count) {
|
||||
log_error("segment_count and actual number of segments "
|
||||
"disagree.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check there are no gaps or overlaps in the lv.
|
||||
*/
|
||||
if (!lv_check_segments(lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Merge segments in case someones been editing things by hand.
|
||||
*/
|
||||
if (!lv_merge_segments(lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read_lv(struct format_instance *fid, struct pool *mem,
|
||||
struct volume_group *vg, struct config_node *lvn,
|
||||
struct config_node *vgn, struct hash_table *pv_hash)
|
||||
{
|
||||
struct logical_volume *lv;
|
||||
struct lv_list *lvl;
|
||||
struct config_node *cn;
|
||||
|
||||
if (!(lvl = pool_zalloc(mem, sizeof(*lvl))) ||
|
||||
!(lvl->lv = pool_zalloc(mem, sizeof(*lvl->lv)))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
lv = lvl->lv;
|
||||
|
||||
if (!(lv->name = pool_strdup(mem, lvn->key))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(lvn = lvn->child)) {
|
||||
log_error("Empty logical volume section.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
lv->vg = vg;
|
||||
|
||||
/* FIXME: read full lvid */
|
||||
if (!_read_id(&lv->lvid.id[1], lvn, "id")) {
|
||||
log_error("Couldn't read uuid for logical volume %s.",
|
||||
lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(&lv->lvid.id[0], &lv->vg->id, sizeof(lv->lvid.id[0]));
|
||||
|
||||
if (!(cn = find_config_node(lvn, "status", '/'))) {
|
||||
log_error("Couldn't find status flags for logical volume.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(read_flags(&lv->status, LV_FLAGS, cn->v))) {
|
||||
log_error("Couldn't read status flags for logical volume.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_init(&lv->segments);
|
||||
if (!_read_segments(mem, vg, lv, lvn, pv_hash)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
lv->alloc = ALLOC_DEFAULT;
|
||||
if ((cn = find_config_node(lvn, "allocation_policy", '/'))) {
|
||||
struct config_value *cv = cn->v;
|
||||
if (!cv || !cv->v.str) {
|
||||
log_error("allocation_policy must be a string.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
lv->alloc = get_alloc_from_string(cv->v.str);
|
||||
}
|
||||
|
||||
/* read_ahead defaults to 0 */
|
||||
if (!_read_int32(lvn, "read_ahead", &lv->read_ahead))
|
||||
lv->read_ahead = 0;
|
||||
|
||||
lv->size = (uint64_t) lv->le_count * (uint64_t) vg->extent_size;
|
||||
|
||||
/* Skip this for now for snapshots */
|
||||
if (!(lv->status & SNAPSHOT)) {
|
||||
lv->minor = -1;
|
||||
if ((lv->status & FIXED_MINOR) &&
|
||||
!_read_int32(lvn, "minor", &lv->minor)) {
|
||||
log_error("Couldn't read minor number for logical "
|
||||
"volume.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
vg->lv_count++;
|
||||
list_add(&vg->lvs, &lvl->list);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read_sections(struct format_instance *fid,
|
||||
const char *section, section_fn fn,
|
||||
struct pool *mem,
|
||||
struct volume_group *vg, struct config_node *vgn,
|
||||
struct hash_table *pv_hash, int optional)
|
||||
{
|
||||
struct config_node *n;
|
||||
|
||||
if (!(n = find_config_node(vgn, section, '/'))) {
|
||||
if (!optional) {
|
||||
log_error("Couldn't find section '%s'.", section);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (n = n->child; n; n = n->sib) {
|
||||
if (!fn(fid, mem, vg, n, vgn, pv_hash)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct volume_group *_read_vg(struct format_instance *fid,
|
||||
struct config_tree *cf)
|
||||
{
|
||||
struct config_node *vgn, *cn;
|
||||
struct volume_group *vg;
|
||||
struct hash_table *pv_hash = NULL;
|
||||
struct pool *mem = fid->fmt->cmd->mem;
|
||||
|
||||
/* skip any top-level values */
|
||||
for (vgn = cf->root; (vgn && vgn->v); vgn = vgn->sib) ;
|
||||
|
||||
if (!vgn) {
|
||||
log_error("Couldn't find volume group in file.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(vg = pool_zalloc(mem, sizeof(*vg)))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
vg->cmd = fid->fmt->cmd;
|
||||
|
||||
/* FIXME Determine format type from file contents */
|
||||
/* eg Set to instance of fmt1 here if reading a format1 backup? */
|
||||
vg->fid = fid;
|
||||
|
||||
if (!(vg->name = pool_strdup(mem, vgn->key))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!(vg->system_id = pool_zalloc(mem, NAME_LEN))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
vgn = vgn->child;
|
||||
|
||||
if ((cn = find_config_node(vgn, "system_id", '/')) && cn->v) {
|
||||
if (!cn->v->v.str) {
|
||||
log_error("system_id must be a string");
|
||||
goto bad;
|
||||
}
|
||||
strncpy(vg->system_id, cn->v->v.str, NAME_LEN);
|
||||
}
|
||||
|
||||
if (!_read_id(&vg->id, vgn, "id")) {
|
||||
log_error("Couldn't read uuid for volume group %s.", vg->name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!_read_int32(vgn, "seqno", &vg->seqno)) {
|
||||
log_error("Couldn't read 'seqno' for volume group %s.",
|
||||
vg->name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!(cn = find_config_node(vgn, "status", '/'))) {
|
||||
log_error("Couldn't find status flags for volume group %s.",
|
||||
vg->name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!(read_flags(&vg->status, VG_FLAGS, cn->v))) {
|
||||
log_error("Couldn't read status flags for volume group %s.",
|
||||
vg->name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!_read_int32(vgn, "extent_size", &vg->extent_size)) {
|
||||
log_error("Couldn't read extent size for volume group %s.",
|
||||
vg->name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* 'extent_count' and 'free_count' get filled in
|
||||
* implicitly when reading in the pv's and lv's.
|
||||
*/
|
||||
|
||||
if (!_read_int32(vgn, "max_lv", &vg->max_lv)) {
|
||||
log_error("Couldn't read 'max_lv' for volume group %s.",
|
||||
vg->name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!_read_int32(vgn, "max_pv", &vg->max_pv)) {
|
||||
log_error("Couldn't read 'max_pv' for volume group %s.",
|
||||
vg->name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* The pv hash memoises the pv section names -> pv
|
||||
* structures.
|
||||
*/
|
||||
if (!(pv_hash = hash_create(32))) {
|
||||
log_error("Couldn't create hash table.");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
list_init(&vg->pvs);
|
||||
if (!_read_sections(fid, "physical_volumes", _read_pv, mem, vg,
|
||||
vgn, pv_hash, 0)) {
|
||||
log_error("Couldn't find all physical volumes for volume "
|
||||
"group %s.", vg->name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
list_init(&vg->lvs);
|
||||
list_init(&vg->snapshots);
|
||||
if (!_read_sections(fid, "logical_volumes", _read_lv, mem, vg,
|
||||
vgn, pv_hash, 1)) {
|
||||
log_error("Couldn't read all logical volumes for volume "
|
||||
"group %s.", vg->name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
hash_destroy(pv_hash);
|
||||
|
||||
if (vg->status & PARTIAL_VG) {
|
||||
vg->status &= ~LVM_WRITE;
|
||||
vg->status |= LVM_READ;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finished.
|
||||
*/
|
||||
return vg;
|
||||
|
||||
bad:
|
||||
if (pv_hash)
|
||||
hash_destroy(pv_hash);
|
||||
|
||||
pool_free(mem, vg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void _read_desc(struct pool *mem,
|
||||
struct config_tree *cf, time_t *when, char **desc)
|
||||
{
|
||||
const char *d;
|
||||
unsigned int u = 0u;
|
||||
|
||||
log_suppress(1);
|
||||
d = find_config_str(cf->root, "description", '/', "");
|
||||
log_suppress(0);
|
||||
*desc = pool_strdup(mem, d);
|
||||
|
||||
get_config_uint32(cf->root, "creation_time", '/', &u);
|
||||
*when = u;
|
||||
}
|
||||
|
||||
static struct text_vg_version_ops _vsn1_ops = {
|
||||
check_version:_check_version,
|
||||
read_vg:_read_vg,
|
||||
read_desc:_read_desc
|
||||
};
|
||||
|
||||
struct text_vg_version_ops *text_vg_vsn1_init(void)
|
||||
{
|
||||
return &_vsn1_ops;
|
||||
};
|
76
lib/format_text/layout.h
Normal file
76
lib/format_text/layout.h
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#ifndef _LVM_TEXT_LAYOUT_H
|
||||
#define _LVM_TEXT_LAYOUT_H
|
||||
|
||||
#include "config.h"
|
||||
#include "lvm-types.h"
|
||||
#include "metadata.h"
|
||||
#include "uuid.h"
|
||||
|
||||
/* On disk */
|
||||
struct disk_locn {
|
||||
uint64_t offset; /* Offset in bytes to start sector */
|
||||
uint64_t size; /* Bytes */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Data areas (holding PEs) */
|
||||
struct data_area_list {
|
||||
struct list list;
|
||||
struct disk_locn disk_locn;
|
||||
};
|
||||
|
||||
/* Fields with the suffix _xl should be xlate'd wherever they appear */
|
||||
/* On disk */
|
||||
struct pv_header {
|
||||
uint8_t pv_uuid[ID_LEN];
|
||||
uint64_t device_size_xl; /* Bytes */
|
||||
|
||||
/* NULL-terminated list of data areas followed by */
|
||||
/* NULL-terminated list of metadata area headers */
|
||||
struct disk_locn disk_areas_xl[0]; /* Two lists */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* On disk */
|
||||
struct raw_locn {
|
||||
uint64_t offset; /* Offset in bytes to start sector */
|
||||
uint64_t size; /* Bytes */
|
||||
uint32_t checksum;
|
||||
uint32_t filler;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* On disk */
|
||||
/* Structure size limited to one sector */
|
||||
struct mda_header {
|
||||
uint32_t checksum_xl; /* Checksum of rest of mda_header */
|
||||
uint8_t magic[16]; /* To aid scans for metadata */
|
||||
uint32_t version;
|
||||
uint64_t start; /* Absolute start byte of mda_header */
|
||||
uint64_t size; /* Size of metadata area */
|
||||
|
||||
struct raw_locn raw_locns[0]; /* NULL-terminated list */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct mda_lists {
|
||||
struct list dirs;
|
||||
struct list raws;
|
||||
struct metadata_area_ops *file_ops;
|
||||
struct metadata_area_ops *raw_ops;
|
||||
};
|
||||
|
||||
struct mda_context {
|
||||
struct device_area area;
|
||||
struct raw_locn rlocn; /* Store inbetween write and commit */
|
||||
};
|
||||
|
||||
/* FIXME Convert this at runtime */
|
||||
#define FMTT_MAGIC "\040\114\126\115\062\040\170\133\065\101\045\162\060\116\052\076"
|
||||
#define FMTT_VERSION 1
|
||||
#define MDA_HEADER_SIZE 512
|
||||
#define LVM2_LABEL "LVM2 001"
|
||||
|
||||
#endif
|
@ -1,67 +0,0 @@
|
||||
# An example volume group
|
||||
|
||||
# YYYY-MM-DD HH:MM:SS
|
||||
output_date = "2001-12-11 11:35:12"
|
||||
|
||||
sample_volume_group {
|
||||
|
||||
id = "ksjdlfksjldskjlsk"
|
||||
status = ["ACTIVE"]
|
||||
|
||||
extent_size = 8192 # 4 Megabytes
|
||||
|
||||
max_lv = 99
|
||||
max_pv = 255
|
||||
|
||||
physical_volumes {
|
||||
|
||||
pv1 {
|
||||
id = "lksjdflksdlsk"
|
||||
device = "/dev/hda1" # Hint only
|
||||
|
||||
status = ["ALLOCATABLE"]
|
||||
pe_start = 8192
|
||||
pe_count = 2048 # 8 Gigabytes
|
||||
}
|
||||
|
||||
pv2 {
|
||||
id = "lksjdflksdlsk"
|
||||
device = "/dev/hda2" # Hint only
|
||||
|
||||
status = ["ALLOCATABLE"]
|
||||
pe_start = 8192
|
||||
pe_count = 1024 # 4 Gigabytes
|
||||
}
|
||||
}
|
||||
|
||||
logical_volumes {
|
||||
|
||||
music {
|
||||
status = ["ACTIVE"]
|
||||
read_ahead = 1024
|
||||
|
||||
segment_count = 2
|
||||
|
||||
segment1 {
|
||||
start_extent = 0
|
||||
extent_count = 1024 # 4 Gigabytes
|
||||
stripes = 1
|
||||
|
||||
areas = [
|
||||
"pv1", 0
|
||||
]
|
||||
}
|
||||
|
||||
segment2 {
|
||||
start_extent = 1024
|
||||
extent_count = 2048 # 8 Gigabytes
|
||||
stripes = 2
|
||||
stripe_size = 32 # 16 Kilobytes
|
||||
|
||||
areas = [
|
||||
"pv1", 1024,
|
||||
"pv2", 0
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
280
lib/format_text/text_label.c
Normal file
280
lib/format_text/text_label.c
Normal file
@ -0,0 +1,280 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "format-text.h"
|
||||
#include "layout.h"
|
||||
#include "label.h"
|
||||
#include "xlate.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
static int _can_handle(struct labeller *l, char *buf, uint64_t sector)
|
||||
{
|
||||
struct label_header *lh = (struct label_header *) buf;
|
||||
|
||||
if (!strncmp(lh->type, LVM2_LABEL, sizeof(lh->type)))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _write(struct label *label, char *buf)
|
||||
{
|
||||
struct label_header *lh = (struct label_header *) buf;
|
||||
struct pv_header *pvhdr;
|
||||
struct cache_info *info;
|
||||
struct disk_locn *pvh_dlocn_xl;
|
||||
struct list *mdash, *dash;
|
||||
struct metadata_area *mda;
|
||||
struct mda_context *mdac;
|
||||
struct data_area_list *da;
|
||||
|
||||
/* FIXME Move to where label is created */
|
||||
strncpy(label->type, LVM2_LABEL, sizeof(label->type));
|
||||
|
||||
strncpy(lh->type, label->type, sizeof(label->type));
|
||||
|
||||
pvhdr = (struct pv_header *) ((void *) buf + xlate32(lh->offset_xl));
|
||||
info = (struct cache_info *) label->info;
|
||||
pvhdr->device_size_xl = xlate64(info->device_size);
|
||||
memcpy(pvhdr->pv_uuid, &info->dev->pvid, sizeof(struct id));
|
||||
|
||||
pvh_dlocn_xl = &pvhdr->disk_areas_xl[0];
|
||||
|
||||
/* List of data areas (holding PEs) */
|
||||
list_iterate(dash, &info->das) {
|
||||
da = list_item(dash, struct data_area_list);
|
||||
|
||||
pvh_dlocn_xl->offset = xlate64(da->disk_locn.offset);
|
||||
pvh_dlocn_xl->size = xlate64(da->disk_locn.size);
|
||||
pvh_dlocn_xl++;
|
||||
}
|
||||
|
||||
/* NULL-termination */
|
||||
pvh_dlocn_xl->offset = xlate64(0);
|
||||
pvh_dlocn_xl->size = xlate64(0);
|
||||
pvh_dlocn_xl++;
|
||||
|
||||
/* List of metadata area header locations */
|
||||
list_iterate(mdash, &info->mdas) {
|
||||
mda = list_item(mdash, struct metadata_area);
|
||||
mdac = (struct mda_context *) mda->metadata_locn;
|
||||
|
||||
if (mdac->area.dev != info->dev)
|
||||
continue;
|
||||
|
||||
pvh_dlocn_xl->offset = xlate64(mdac->area.start);
|
||||
pvh_dlocn_xl->size = xlate64(mdac->area.size);
|
||||
pvh_dlocn_xl++;
|
||||
}
|
||||
|
||||
/* NULL-termination */
|
||||
pvh_dlocn_xl->offset = xlate64(0);
|
||||
pvh_dlocn_xl->size = xlate64(0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int add_da(struct format_type *fmt, struct pool *mem, struct list *das,
|
||||
uint64_t start, uint64_t size)
|
||||
{
|
||||
struct data_area_list *dal;
|
||||
|
||||
if (!mem) {
|
||||
if (!(dal = dbg_malloc(sizeof(*dal)))) {
|
||||
log_error("struct data_area_list allocation failed");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (!(dal = pool_alloc(mem, sizeof(*dal)))) {
|
||||
log_error("struct data_area_list allocation failed");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
dal->disk_locn.offset = start;
|
||||
dal->disk_locn.size = size;
|
||||
|
||||
list_add(das, &dal->list);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void del_das(struct list *das)
|
||||
{
|
||||
struct list *dah, *tmp;
|
||||
struct data_area_list *da;
|
||||
|
||||
list_iterate_safe(dah, tmp, das) {
|
||||
da = list_item(dah, struct data_area_list);
|
||||
list_del(&da->list);
|
||||
dbg_free(da);
|
||||
}
|
||||
}
|
||||
|
||||
int add_mda(struct format_type *fmt, struct pool *mem, struct list *mdas,
|
||||
struct device *dev, uint64_t start, uint64_t size)
|
||||
{
|
||||
/* FIXME List size restricted by pv_header SECTOR_SIZE */
|
||||
struct metadata_area *mdal;
|
||||
struct mda_lists *mda_lists = (struct mda_lists *) fmt->private;
|
||||
struct mda_context *mdac;
|
||||
|
||||
if (!mem) {
|
||||
if (!(mdal = dbg_malloc(sizeof(struct metadata_area)))) {
|
||||
log_error("struct mda_list allocation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(mdac = dbg_malloc(sizeof(struct mda_context)))) {
|
||||
log_error("struct mda_context allocation failed");
|
||||
dbg_free(mdal);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (!(mdal = pool_alloc(mem, sizeof(struct metadata_area)))) {
|
||||
log_error("struct mda_list allocation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(mdac = pool_alloc(mem, sizeof(struct mda_context)))) {
|
||||
log_error("struct mda_context allocation failed");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
mdal->ops = mda_lists->raw_ops;
|
||||
mdal->metadata_locn = mdac;
|
||||
|
||||
mdac->area.dev = dev;
|
||||
mdac->area.start = start;
|
||||
mdac->area.size = size;
|
||||
memset(&mdac->rlocn, 0, sizeof(mdac->rlocn));
|
||||
|
||||
list_add(mdas, &mdal->list);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void del_mdas(struct list *mdas)
|
||||
{
|
||||
struct list *mdah, *tmp;
|
||||
struct metadata_area *mda;
|
||||
|
||||
list_iterate_safe(mdah, tmp, mdas) {
|
||||
mda = list_item(mdah, struct metadata_area);
|
||||
dbg_free(mda->metadata_locn);
|
||||
list_del(&mda->list);
|
||||
dbg_free(mda);
|
||||
}
|
||||
}
|
||||
|
||||
static int _initialise_label(struct labeller *l, struct label *label)
|
||||
{
|
||||
strncpy(label->type, LVM2_LABEL, sizeof(label->type));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read(struct labeller *l, struct device *dev, char *buf,
|
||||
struct label **label)
|
||||
{
|
||||
struct label_header *lh = (struct label_header *) buf;
|
||||
struct pv_header *pvhdr;
|
||||
struct cache_info *info;
|
||||
struct disk_locn *dlocn_xl;
|
||||
uint64_t offset;
|
||||
struct list *mdah;
|
||||
struct metadata_area *mda;
|
||||
char vgnamebuf[NAME_LEN + 2];
|
||||
struct mda_context *mdac;
|
||||
|
||||
pvhdr = (struct pv_header *) ((void *) buf + xlate32(lh->offset_xl));
|
||||
|
||||
if (!(info = cache_add(l, pvhdr->pv_uuid, dev, NULL, NULL)))
|
||||
return 0;
|
||||
*label = info->label;
|
||||
|
||||
info->device_size = xlate64(pvhdr->device_size_xl);
|
||||
|
||||
if (info->das.n)
|
||||
del_das(&info->das);
|
||||
list_init(&info->das);
|
||||
|
||||
if (info->mdas.n)
|
||||
del_mdas(&info->mdas);
|
||||
list_init(&info->mdas);
|
||||
|
||||
/* Data areas holding the PEs */
|
||||
dlocn_xl = pvhdr->disk_areas_xl;
|
||||
while ((offset = xlate64(dlocn_xl->offset))) {
|
||||
add_da(info->fmt, NULL, &info->das, offset,
|
||||
xlate64(dlocn_xl->size));
|
||||
dlocn_xl++;
|
||||
}
|
||||
|
||||
/* Metadata area headers */
|
||||
dlocn_xl++;
|
||||
while ((offset = xlate64(dlocn_xl->offset))) {
|
||||
add_mda(info->fmt, NULL, &info->mdas, dev, offset,
|
||||
xlate64(dlocn_xl->size));
|
||||
dlocn_xl++;
|
||||
}
|
||||
|
||||
list_iterate(mdah, &info->mdas) {
|
||||
mda = list_item(mdah, struct metadata_area);
|
||||
mdac = (struct mda_context *) mda->metadata_locn;
|
||||
if (vgname_from_mda(info->fmt, &mdac->area, vgnamebuf,
|
||||
sizeof(vgnamebuf))) {
|
||||
cache_update_vgname(info, vgnamebuf);
|
||||
}
|
||||
}
|
||||
|
||||
info->status &= ~CACHE_INVALID;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _destroy_label(struct labeller *l, struct label *label)
|
||||
{
|
||||
struct cache_info *info = (struct cache_info *) label->info;
|
||||
|
||||
if (info->mdas.n)
|
||||
del_mdas(&info->mdas);
|
||||
if (info->das.n)
|
||||
del_das(&info->das);
|
||||
}
|
||||
|
||||
static void _destroy(struct labeller *l)
|
||||
{
|
||||
dbg_free(l);
|
||||
}
|
||||
|
||||
struct label_ops _text_ops = {
|
||||
can_handle:_can_handle,
|
||||
write:_write,
|
||||
read:_read,
|
||||
verify:_can_handle,
|
||||
initialise_label:_initialise_label,
|
||||
destroy_label:_destroy_label,
|
||||
destroy:_destroy
|
||||
};
|
||||
|
||||
struct labeller *text_labeller_create(struct format_type *fmt)
|
||||
{
|
||||
struct labeller *l;
|
||||
|
||||
if (!(l = dbg_malloc(sizeof(*l)))) {
|
||||
log_err("Couldn't allocate labeller object.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
l->ops = &_text_ops;
|
||||
l->private = (void *) fmt;
|
||||
|
||||
return l;
|
||||
}
|
@ -4,10 +4,18 @@
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "label.h"
|
||||
#include "list.h"
|
||||
#include "dbg_malloc.h"
|
||||
#include "log.h"
|
||||
#include "crc.h"
|
||||
#include "xlate.h"
|
||||
#include "cache.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* FIXME Allow for larger labels? Restricted to single sector currently */
|
||||
|
||||
/*
|
||||
* Internal labeller struct.
|
||||
@ -58,6 +66,7 @@ void label_exit(void)
|
||||
for (c = _labellers.n; c != &_labellers; c = n) {
|
||||
n = c->n;
|
||||
li = list_item(c, struct labeller_i);
|
||||
li->l->ops->destroy(li->l);
|
||||
_free_li(li);
|
||||
}
|
||||
}
|
||||
@ -89,64 +98,257 @@ struct labeller *label_get_handler(const char *name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct labeller *_find_labeller(struct device *dev)
|
||||
static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
uint64_t *label_sector)
|
||||
{
|
||||
struct list *lih;
|
||||
struct labeller_i *li;
|
||||
struct labeller *r = NULL;
|
||||
int already_open;
|
||||
struct label_header *lh;
|
||||
uint64_t sector;
|
||||
int found = 0;
|
||||
char readbuf[LABEL_SCAN_SIZE];
|
||||
|
||||
list_iterate(lih, &_labellers) {
|
||||
li = list_item(lih, struct labeller_i);
|
||||
if (li->l->ops->can_handle(li->l, dev))
|
||||
return li->l;
|
||||
already_open = dev_is_open(dev);
|
||||
|
||||
if (!already_open && !dev_open(dev, O_RDONLY)) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
log_debug("No label on device '%s'.", dev_name(dev));
|
||||
return NULL;
|
||||
if (dev_read(dev, 0, LABEL_SCAN_SIZE, readbuf) != LABEL_SCAN_SIZE) {
|
||||
log_debug("%s: Failed to read label area", dev_name(dev));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Scan first few sectors for a valid label */
|
||||
for (sector = 0; sector < LABEL_SCAN_SECTORS;
|
||||
sector += LABEL_SIZE >> SECTOR_SHIFT) {
|
||||
lh = (struct label_header *) (readbuf +
|
||||
(sector << SECTOR_SHIFT));
|
||||
|
||||
if (!strncmp(lh->id, LABEL_ID, sizeof(lh->id))) {
|
||||
if (found) {
|
||||
log_error("Ignoring additional label on %s at "
|
||||
"sector %" PRIu64, dev_name(dev),
|
||||
sector);
|
||||
}
|
||||
if (xlate64(lh->sector_xl) != sector) {
|
||||
log_info("%s: Label for sector %" PRIu64
|
||||
" found at sector %" PRIu64
|
||||
" - ignoring", dev_name(dev),
|
||||
xlate64(lh->sector_xl), sector);
|
||||
continue;
|
||||
}
|
||||
if (calc_crc(INITIAL_CRC, &lh->offset_xl, LABEL_SIZE -
|
||||
((void *) &lh->offset_xl - (void *) lh)) !=
|
||||
xlate32(lh->crc_xl)) {
|
||||
log_info("Label checksum incorrect on %s - "
|
||||
"ignoring", dev_name(dev));
|
||||
continue;
|
||||
}
|
||||
if (found)
|
||||
continue;
|
||||
}
|
||||
|
||||
list_iterate(lih, &_labellers) {
|
||||
li = list_item(lih, struct labeller_i);
|
||||
if (li->l->ops->can_handle(li->l, (char *) lh, sector)) {
|
||||
log_very_verbose("%s: %s label detected",
|
||||
dev_name(dev), li->name);
|
||||
if (found) {
|
||||
log_error("Ignoring additional label "
|
||||
"on %s at sector %" PRIu64,
|
||||
dev_name(dev), sector);
|
||||
continue;
|
||||
}
|
||||
r = li->l;
|
||||
memcpy(buf, lh, LABEL_SIZE);
|
||||
if (label_sector)
|
||||
*label_sector = sector;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
log_very_verbose("%s: No label detected", dev_name(dev));
|
||||
|
||||
out:
|
||||
if (!already_open && !dev_close(dev))
|
||||
stack;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* FIXME Also wipe associated metadata area headers? */
|
||||
int label_remove(struct device *dev)
|
||||
{
|
||||
struct labeller *l;
|
||||
char buf[LABEL_SIZE];
|
||||
char readbuf[LABEL_SCAN_SIZE];
|
||||
int r = 1;
|
||||
uint64_t sector;
|
||||
int wipe;
|
||||
struct list *lih;
|
||||
struct labeller_i *li;
|
||||
struct label_header *lh;
|
||||
|
||||
if (!(l = _find_labeller(dev))) {
|
||||
memset(buf, 0, LABEL_SIZE);
|
||||
|
||||
log_very_verbose("Scanning for labels to wipe from %s", dev_name(dev));
|
||||
|
||||
if (!dev_open(dev, O_RDWR)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return l->ops->remove(l, dev);
|
||||
}
|
||||
if (dev_read(dev, 0, LABEL_SCAN_SIZE, readbuf) != LABEL_SCAN_SIZE) {
|
||||
log_debug("%s: Failed to read label area", dev_name(dev));
|
||||
goto out;
|
||||
}
|
||||
|
||||
int label_read(struct device *dev, struct label **result)
|
||||
{
|
||||
int r;
|
||||
struct list *lih;
|
||||
struct labeller_i *li;
|
||||
/* Scan first few sectors for anything looking like a label */
|
||||
for (sector = 0; sector < LABEL_SCAN_SECTORS;
|
||||
sector += LABEL_SIZE >> SECTOR_SHIFT) {
|
||||
lh = (struct label_header *) (readbuf +
|
||||
(sector << SECTOR_SHIFT));
|
||||
|
||||
list_iterate(lih, &_labellers) {
|
||||
li = list_item(lih, struct labeller_i);
|
||||
if ((r = li->l->ops->read(li->l, dev, result))) {
|
||||
(*result)->labeller = li->l;
|
||||
return r;
|
||||
wipe = 0;
|
||||
|
||||
if (!strncmp(lh->id, LABEL_ID, sizeof(lh->id))) {
|
||||
if (xlate64(lh->sector_xl) == sector)
|
||||
wipe = 1;
|
||||
} else {
|
||||
list_iterate(lih, &_labellers) {
|
||||
li = list_item(lih, struct labeller_i);
|
||||
if (li->l->ops->can_handle(li->l, (char *) lh,
|
||||
sector)) {
|
||||
wipe = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (wipe) {
|
||||
log_info("%s: Wiping label at sector %" PRIu64,
|
||||
dev_name(dev), sector);
|
||||
if (dev_write(dev, sector << SECTOR_SHIFT, LABEL_SIZE,
|
||||
buf) != LABEL_SIZE) {
|
||||
log_error("Failed to remove label from %s at "
|
||||
"sector %" PRIu64, dev_name(dev),
|
||||
sector);
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log_debug("No label on device '%s'.", dev_name(dev));
|
||||
return 0;
|
||||
out:
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* FIXME Avoid repeated re-reading if cache lock held */
|
||||
int label_read(struct device *dev, struct label **result)
|
||||
{
|
||||
char buf[LABEL_SIZE];
|
||||
struct labeller *l;
|
||||
uint64_t sector;
|
||||
int r;
|
||||
|
||||
if (!(l = _find_labeller(dev, buf, §or))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((r = l->ops->read(l, dev, buf, result)) && result && *result)
|
||||
(*result)->sector = sector;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Caller may need to use label_get_handler to create label struct! */
|
||||
int label_write(struct device *dev, struct label *label)
|
||||
{
|
||||
char buf[LABEL_SIZE];
|
||||
struct label_header *lh = (struct label_header *) buf;
|
||||
int r = 1;
|
||||
int already_open;
|
||||
|
||||
if ((LABEL_SIZE + (label->sector << SECTOR_SHIFT)) > LABEL_SCAN_SIZE) {
|
||||
log_error("Label sector %" PRIu64 " beyond range (%ld)",
|
||||
label->sector, LABEL_SCAN_SECTORS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(buf, 0, LABEL_SIZE);
|
||||
|
||||
strncpy(lh->id, LABEL_ID, sizeof(lh->id));
|
||||
lh->sector_xl = xlate64(label->sector);
|
||||
lh->offset_xl = xlate32(sizeof(*lh));
|
||||
|
||||
if (!label->labeller->ops->write(label, buf))
|
||||
return 0;
|
||||
|
||||
lh->crc_xl = xlate32(calc_crc(INITIAL_CRC, &lh->offset_xl, LABEL_SIZE -
|
||||
((void *) &lh->offset_xl - (void *) lh)));
|
||||
|
||||
already_open = dev_is_open(dev);
|
||||
if (!already_open && dev_open(dev, O_RDWR)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_info("%s: Writing label to sector %" PRIu64, dev_name(dev),
|
||||
label->sector);
|
||||
if (dev_write(dev, label->sector << SECTOR_SHIFT, LABEL_SIZE, buf) !=
|
||||
LABEL_SIZE) {
|
||||
log_debug("Failed to write label to %s", dev_name(dev));
|
||||
r = 0;
|
||||
}
|
||||
|
||||
if (!already_open && dev_close(dev))
|
||||
stack;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int label_verify(struct device *dev)
|
||||
{
|
||||
struct labeller *l;
|
||||
char buf[LABEL_SIZE];
|
||||
uint64_t sector;
|
||||
|
||||
if (!(l = _find_labeller(dev))) {
|
||||
if (!(l = _find_labeller(dev, buf, §or))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return l->ops->verify(l, dev);
|
||||
return l->ops->verify(l, buf, sector);
|
||||
}
|
||||
|
||||
void label_destroy(struct label *lab)
|
||||
void label_destroy(struct label *label)
|
||||
{
|
||||
lab->labeller->ops->destroy_label(lab->labeller, lab);
|
||||
label->labeller->ops->destroy_label(label->labeller, label);
|
||||
dbg_free(label);
|
||||
}
|
||||
|
||||
struct label *label_create(struct labeller *labeller)
|
||||
{
|
||||
struct label *label;
|
||||
|
||||
if (!(label = dbg_malloc(sizeof(*label)))) {
|
||||
log_error("label allocaction failed");
|
||||
return NULL;
|
||||
}
|
||||
memset(label, 0, sizeof(*label));
|
||||
|
||||
label->labeller = labeller;
|
||||
|
||||
labeller->ops->initialise_label(labeller, label);
|
||||
|
||||
return label;
|
||||
}
|
||||
|
@ -7,18 +7,31 @@
|
||||
#ifndef _LVM_LABEL_H
|
||||
#define _LVM_LABEL_H
|
||||
|
||||
#include "cache.h"
|
||||
#include "lvm-types.h"
|
||||
#include "uuid.h"
|
||||
#include "device.h"
|
||||
|
||||
#define LABEL_ID "LABELONE"
|
||||
#define LABEL_SIZE SECTOR_SIZE /* Think very carefully before changing this */
|
||||
#define LABEL_SCAN_SECTORS 4L
|
||||
#define LABEL_SCAN_SIZE (LABEL_SCAN_SECTORS << SECTOR_SHIFT)
|
||||
|
||||
/* On disk - 32 bytes */
|
||||
struct label_header {
|
||||
uint8_t id[8]; /* LABELONE */
|
||||
uint64_t sector_xl; /* Sector number of this label */
|
||||
uint32_t crc_xl; /* From next field to end of sector */
|
||||
uint32_t offset_xl; /* Offset from start of struct to contents */
|
||||
uint8_t type[8]; /* LVM2 001 */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* In core */
|
||||
struct label {
|
||||
struct id id;
|
||||
|
||||
char volume_type[32];
|
||||
uint32_t version[3];
|
||||
|
||||
void *extra_info;
|
||||
|
||||
char type[8];
|
||||
uint64_t sector;
|
||||
struct labeller *labeller;
|
||||
void *info;
|
||||
};
|
||||
|
||||
struct labeller;
|
||||
@ -27,39 +40,38 @@ struct label_ops {
|
||||
/*
|
||||
* Is the device labelled with this format ?
|
||||
*/
|
||||
int (*can_handle)(struct labeller *l, struct device *dev);
|
||||
int (*can_handle) (struct labeller * l, char *buf, uint64_t sector);
|
||||
|
||||
/*
|
||||
* Write a label to a volume.
|
||||
*/
|
||||
int (*write)(struct labeller *l,
|
||||
struct device *dev, struct label *label);
|
||||
|
||||
/*
|
||||
* Remove a label from a device.
|
||||
*/
|
||||
int (*remove)(struct labeller *l, struct device *dev);
|
||||
int (*write) (struct label * label, char *buf);
|
||||
|
||||
/*
|
||||
* Read a label from a volume.
|
||||
*/
|
||||
int (*read)(struct labeller *l,
|
||||
struct device *dev, struct label **label);
|
||||
int (*read) (struct labeller * l, struct device * dev,
|
||||
char *buf, struct label ** label);
|
||||
|
||||
/*
|
||||
* Additional consistency checks for the paranoid.
|
||||
*/
|
||||
int (*verify)(struct labeller *l, struct device *dev);
|
||||
int (*verify) (struct labeller * l, char *buf, uint64_t sector);
|
||||
|
||||
/*
|
||||
* Populate label_type etc.
|
||||
*/
|
||||
int (*initialise_label) (struct labeller * l, struct label * label);
|
||||
|
||||
/*
|
||||
* Destroy a previously read label.
|
||||
*/
|
||||
void (*destroy_label)(struct labeller *l, struct label *label);
|
||||
void (*destroy_label) (struct labeller * l, struct label * label);
|
||||
|
||||
/*
|
||||
* Destructor.
|
||||
*/
|
||||
void (*destroy)(struct labeller *l);
|
||||
void (*destroy) (struct labeller * l);
|
||||
};
|
||||
|
||||
struct labeller {
|
||||
@ -67,7 +79,6 @@ struct labeller {
|
||||
void *private;
|
||||
};
|
||||
|
||||
|
||||
int label_init(void);
|
||||
void label_exit(void);
|
||||
|
||||
@ -77,14 +88,9 @@ struct labeller *label_get_handler(const char *name);
|
||||
|
||||
int label_remove(struct device *dev);
|
||||
int label_read(struct device *dev, struct label **result);
|
||||
int label_write(struct device *dev, struct label *label);
|
||||
int label_verify(struct device *dev);
|
||||
void label_destroy(struct label *lab);
|
||||
|
||||
/*
|
||||
* We'll support two label types: the 'pretend the
|
||||
* LVM1 pv structure at the begining of the disk
|
||||
* is a label' hack, and pjc's 1 sector labels at
|
||||
* the front and back of the device.
|
||||
*/
|
||||
struct label *label_create(struct labeller *labeller);
|
||||
void label_destroy(struct label *label);
|
||||
|
||||
#endif
|
||||
|
@ -1,569 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2002 Sistina Software
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "device.h"
|
||||
#include "dev-cache.h"
|
||||
#include "log.h"
|
||||
#include "pool.h"
|
||||
#include "dbg_malloc.h"
|
||||
#include "filter.h"
|
||||
#include "label.h"
|
||||
#include "lvm2_label.h"
|
||||
#include "xlate.h"
|
||||
|
||||
/* Label Magic is "LnXl" - error: imagination failure */
|
||||
#define LABEL_MAGIC 0x6c586e4c
|
||||
|
||||
/* Size of blocks that dev_get_size() returns the number of */
|
||||
#define BLOCK_SIZE 512
|
||||
|
||||
/* This is just the "struct lvm2_label" with the data pointer removed */
|
||||
struct label_ondisk {
|
||||
uint32_t magic;
|
||||
uint32_t crc;
|
||||
uint64_t label1_loc;
|
||||
uint64_t label2_loc;
|
||||
uint16_t datalen;
|
||||
uint16_t pad;
|
||||
|
||||
uint32_t version[3];
|
||||
char disk_type[32];
|
||||
};
|
||||
|
||||
struct filter_private {
|
||||
void *mem;
|
||||
char disk_type[32];
|
||||
uint32_t version[3];
|
||||
int version_match;
|
||||
};
|
||||
|
||||
/* Calculate CRC32 of a buffer */
|
||||
static uint32_t crc32(uint32_t initial, const unsigned char *databuf,
|
||||
size_t datalen)
|
||||
{
|
||||
static const u_int crctab[] = {
|
||||
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
|
||||
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
|
||||
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
|
||||
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
|
||||
};
|
||||
uint32_t idx, crc = initial;
|
||||
|
||||
for (idx = 0; idx < datalen; idx++) {
|
||||
crc ^= *databuf++;
|
||||
crc = (crc >> 4) ^ crctab[crc & 0xf];
|
||||
crc = (crc >> 4) ^ crctab[crc & 0xf];
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
/* Calculate crc */
|
||||
static uint32_t calc_crc(struct label_ondisk *label, char *data)
|
||||
{
|
||||
uint32_t crcval = 0xffffffff;
|
||||
|
||||
crcval = crc32(crcval, (char *) &label->magic, sizeof(label->magic));
|
||||
crcval =
|
||||
crc32(crcval, (char *) &label->label1_loc,
|
||||
sizeof(label->label1_loc));
|
||||
crcval =
|
||||
crc32(crcval, (char *) &label->label2_loc,
|
||||
sizeof(label->label2_loc));
|
||||
crcval =
|
||||
crc32(crcval, (char *) &label->datalen, sizeof(label->datalen));
|
||||
crcval =
|
||||
crc32(crcval, (char *) &label->version, sizeof(label->version));
|
||||
crcval =
|
||||
crc32(crcval, (char *) label->disk_type, strlen(label->disk_type));
|
||||
crcval = crc32(crcval, (char *) data, label->datalen);
|
||||
|
||||
return crcval;
|
||||
}
|
||||
|
||||
/* Calculate the locations we should find the labels in */
|
||||
static inline void get_label_locations(uint64_t size, uint32_t sectsize,
|
||||
long *first, long *second)
|
||||
{
|
||||
*first = sectsize;
|
||||
*second = size * BLOCK_SIZE - sectsize;
|
||||
}
|
||||
|
||||
/* Read a label off disk */
|
||||
static int lvm2_label_read(struct labeller *l, struct device *dev,
|
||||
struct label **label)
|
||||
{
|
||||
uint64_t size;
|
||||
uint32_t sectsize;
|
||||
char *block;
|
||||
struct label_ondisk *ondisk;
|
||||
int status;
|
||||
int iter;
|
||||
long offset[2];
|
||||
|
||||
if (!dev_get_size(dev, &size))
|
||||
return 0;
|
||||
|
||||
if (!dev_get_sectsize(dev, §size))
|
||||
return 0;
|
||||
|
||||
if (!dev_open(dev, O_RDONLY))
|
||||
return 0;
|
||||
|
||||
block = dbg_malloc(sectsize);
|
||||
if (!block) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
ondisk = (struct label_ondisk *) block;
|
||||
get_label_locations(size, sectsize, &offset[0], &offset[1]);
|
||||
|
||||
/* If the first label is bad then use the second */
|
||||
for (iter = 0; iter <= 1; iter++) {
|
||||
status = dev_read(dev, offset[iter], sectsize, block);
|
||||
if (status) {
|
||||
struct label *incore;
|
||||
int i;
|
||||
int found_nul;
|
||||
|
||||
/* If the MAGIC doesn't match there's no point in
|
||||
carrying on */
|
||||
if (xlate32(ondisk->magic) != LABEL_MAGIC)
|
||||
continue;
|
||||
|
||||
/* Look for a NUL in the disk_type string so we don't
|
||||
SEGV is something has gone horribly wrong */
|
||||
found_nul = 0;
|
||||
for (i = 0; i < sizeof(ondisk->disk_type); i++)
|
||||
if (ondisk->disk_type[i] == '\0')
|
||||
found_nul = 1;
|
||||
|
||||
if (!found_nul)
|
||||
continue;
|
||||
|
||||
incore = dbg_malloc(sizeof(struct label));
|
||||
if (incore == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copy and convert endianness */
|
||||
strncpy(incore->volume_type, ondisk->disk_type,
|
||||
sizeof(incore->volume_type));
|
||||
incore->version[0] = xlate32(ondisk->version[0]);
|
||||
incore->version[1] = xlate32(ondisk->version[1]);
|
||||
incore->version[2] = xlate32(ondisk->version[2]);
|
||||
incore->extra_len = xlate16(ondisk->datalen);
|
||||
incore->extra_info =
|
||||
block + sizeof(struct label_ondisk);
|
||||
|
||||
/* Make sure datalen is a sensible size too */
|
||||
if (incore->extra_len > sectsize)
|
||||
continue;
|
||||
|
||||
/* Check Crc */
|
||||
if (xlate32(ondisk->crc) !=
|
||||
calc_crc(ondisk, incore->extra_info)) {
|
||||
log_error
|
||||
("Crc %d on device %s does not match. got %x, expected %x",
|
||||
iter, dev_name(dev), xlate32(ondisk->crc),
|
||||
calc_crc(ondisk, incore->extra_info));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check label locations match our view of the device */
|
||||
if (xlate64(ondisk->label1_loc) != offset[0])
|
||||
log_error
|
||||
("Label 1 location is wrong in label %d - check block size of the device\n",
|
||||
iter);
|
||||
if (xlate64(ondisk->label2_loc) != offset[1])
|
||||
log_error
|
||||
("Label 2 location is wrong in label %d - the size of the device must have changed\n",
|
||||
iter);
|
||||
|
||||
/* Copy to user's data area */
|
||||
*label = incore;
|
||||
incore->extra_info = dbg_malloc(incore->extra_len);
|
||||
if (!incore->extra_info) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
memcpy(incore->extra_info,
|
||||
block + sizeof(struct label_ondisk),
|
||||
incore->extra_len);
|
||||
|
||||
dbg_free(block);
|
||||
dev_close(dev);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
dbg_free(block);
|
||||
dev_close(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Write a label to a device */
|
||||
static int lvm2_label_write(struct labeller *l, struct device *dev,
|
||||
struct label *label)
|
||||
{
|
||||
uint64_t size;
|
||||
uint32_t sectsize;
|
||||
char *block;
|
||||
struct label_ondisk *ondisk;
|
||||
int status1, status2;
|
||||
long offset[2];
|
||||
|
||||
if (!dev_get_size(dev, &size))
|
||||
return 0;
|
||||
|
||||
if (!dev_get_sectsize(dev, §size))
|
||||
return 0;
|
||||
|
||||
/* Can the metata fit in the remaining space ? */
|
||||
if (label->extra_len > sectsize - sizeof(struct label_ondisk))
|
||||
return 0;
|
||||
|
||||
block = dbg_malloc(sizeof(struct label_ondisk) + label->extra_len);
|
||||
if (!block) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
ondisk = (struct label_ondisk *) block;
|
||||
|
||||
get_label_locations(size, sectsize, &offset[0], &offset[1]);
|
||||
|
||||
/* Make into ondisk format */
|
||||
ondisk->magic = xlate32(LABEL_MAGIC);
|
||||
ondisk->version[0] = xlate32(label->version[0]);
|
||||
ondisk->version[1] = xlate32(label->version[1]);
|
||||
ondisk->version[2] = xlate32(label->version[2]);
|
||||
ondisk->label1_loc = xlate64(offset[0]);
|
||||
ondisk->label2_loc = xlate64(offset[1]);
|
||||
ondisk->datalen = xlate16(label->extra_len);
|
||||
strncpy(ondisk->disk_type, label->volume_type,
|
||||
sizeof(ondisk->disk_type));
|
||||
memcpy(block + sizeof(struct label_ondisk), label->extra_info,
|
||||
label->extra_len);
|
||||
ondisk->crc = xlate32(calc_crc(ondisk, label->extra_info));
|
||||
|
||||
/* Write metadata to disk */
|
||||
if (!dev_open(dev, O_RDWR)) {
|
||||
dbg_free(block);
|
||||
return 0;
|
||||
}
|
||||
|
||||
status1 =
|
||||
dev_write(dev, offset[0],
|
||||
sizeof(struct label_ondisk) + label->extra_len, block);
|
||||
if (!status1)
|
||||
log_error("Error writing label 1\n");
|
||||
|
||||
/* Write another at the end of the device */
|
||||
status2 =
|
||||
dev_write(dev, offset[1],
|
||||
sizeof(struct label_ondisk) + label->extra_len, block);
|
||||
if (!status2) {
|
||||
char zerobuf[sizeof(struct label_ondisk)];
|
||||
log_error("Error writing label 2\n");
|
||||
|
||||
/* Wipe the first label so it doesn't get confusing */
|
||||
memset(zerobuf, 0, sizeof(struct label_ondisk));
|
||||
if (!dev_write
|
||||
(dev, offset[0], sizeof(struct label_ondisk),
|
||||
zerobuf)) log_error("Error erasing label 1\n");
|
||||
}
|
||||
|
||||
dbg_free(block);
|
||||
dev_close(dev);
|
||||
|
||||
return ((status1 != 0) && (status2 != 0));
|
||||
}
|
||||
|
||||
/* Return 1 for Yes, 0 for No */
|
||||
static int lvm2_is_labelled(struct labeller *l, struct device *dev)
|
||||
{
|
||||
struct label *label;
|
||||
int status;
|
||||
|
||||
status = lvm2_label_read(l, dev, &label);
|
||||
if (status)
|
||||
label_free(label);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Check the device is labelled and has the right format_type */
|
||||
static int _accept_format(struct dev_filter *f, struct device *dev)
|
||||
{
|
||||
struct label *l;
|
||||
int status;
|
||||
struct filter_private *fp = (struct filter_private *) f->private;
|
||||
|
||||
status = lvm2_label_read(NULL, dev, &l);
|
||||
|
||||
if (status) {
|
||||
if (strcmp(l->volume_type, fp->disk_type) == 0) {
|
||||
switch (fp->version_match) {
|
||||
case VERSION_MATCH_EQUAL:
|
||||
if (l->version[0] == fp->version[0] &&
|
||||
l->version[1] == fp->version[1] &&
|
||||
l->version[2] == fp->version[2])
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case VERSION_MATCH_LESSTHAN:
|
||||
if (l->version[0] == fp->version[0] &&
|
||||
l->version[1] < fp->version[1])
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case VERSION_MATCH_LESSEQUAL:
|
||||
if (l->version[0] == fp->version[0] &&
|
||||
l->version[1] <= fp->version[1])
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case VERSION_MATCH_ANY:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
label_free(l);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We just want to know if it's labelled or not */
|
||||
static int _accept_label(struct dev_filter *f, struct device *dev)
|
||||
{
|
||||
return lvm2_is_labelled(NULL, dev);
|
||||
}
|
||||
|
||||
static void _destroy(struct dev_filter *f)
|
||||
{
|
||||
struct filter_private *fp = (struct filter_private *) f->private;
|
||||
}
|
||||
|
||||
/* A filter to find devices with a particular label type on them */
|
||||
struct dev_filter *lvm2_label_format_filter_create(char *disk_type,
|
||||
uint32_t version[3],
|
||||
int match_type)
|
||||
{
|
||||
struct pool *mem;
|
||||
struct filter_private *fp;
|
||||
struct dev_filter *f;
|
||||
|
||||
/* Validate the match type */
|
||||
if (match_type != VERSION_MATCH_EQUAL &&
|
||||
match_type != VERSION_MATCH_LESSTHAN &&
|
||||
match_type != VERSION_MATCH_LESSEQUAL &&
|
||||
match_type != VERSION_MATCH_ANY)
|
||||
return 0;
|
||||
|
||||
mem = pool_create(10 * 1024);
|
||||
if (!mem) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(f = pool_zalloc(mem, sizeof(*f)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!(fp = pool_zalloc(mem, sizeof(*fp)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
fp->mem = mem;
|
||||
strcpy(fp->disk_type, disk_type);
|
||||
fp->version[0] = version[0];
|
||||
fp->version[1] = version[1];
|
||||
fp->version[2] = version[2];
|
||||
fp->version_match = match_type;
|
||||
f->passes_filter = _accept_format;
|
||||
f->destroy = _destroy;
|
||||
f->private = fp;
|
||||
|
||||
return f;
|
||||
|
||||
bad:
|
||||
pool_destroy(mem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* A filter to find devices with any label on them */
|
||||
struct dev_filter *lvm2_label_filter_create()
|
||||
{
|
||||
struct pool *mem = pool_create(10 * 1024);
|
||||
struct filter_private *fp;
|
||||
struct dev_filter *f;
|
||||
|
||||
if (!mem) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(f = pool_zalloc(mem, sizeof(*f)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!(fp = pool_zalloc(mem, sizeof(*fp)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
fp->mem = mem;
|
||||
f->passes_filter = _accept_label;
|
||||
f->destroy = _destroy;
|
||||
f->private = fp;
|
||||
|
||||
return f;
|
||||
|
||||
bad:
|
||||
pool_destroy(mem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Return 1 if both labels are identical, 0 if not or there was an error */
|
||||
static int lvm2_labels_match(struct labeller *l, struct device *dev)
|
||||
{
|
||||
uint64_t size;
|
||||
uint32_t sectsize;
|
||||
char *block1;
|
||||
char *block2;
|
||||
struct label_ondisk *ondisk1;
|
||||
struct label_ondisk *ondisk2;
|
||||
int status = 0;
|
||||
long offset[2];
|
||||
|
||||
if (!dev_get_size(dev, &size))
|
||||
return 0;
|
||||
|
||||
if (!dev_get_sectsize(dev, §size))
|
||||
return 0;
|
||||
|
||||
/* Allocate some space for the blocks we are going to read in */
|
||||
block1 = dbg_malloc(sectsize);
|
||||
if (!block1) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
block2 = dbg_malloc(sectsize);
|
||||
if (!block2) {
|
||||
stack;
|
||||
dbg_free(block1);
|
||||
return 0;
|
||||
}
|
||||
ondisk1 = (struct label_ondisk *) block1;
|
||||
ondisk2 = (struct label_ondisk *) block2;
|
||||
|
||||
get_label_locations(size, sectsize, &offset[0], &offset[1]);
|
||||
|
||||
/* Fetch em */
|
||||
if (!dev_open(dev, O_RDONLY))
|
||||
goto finish;
|
||||
|
||||
if (!dev_read(dev, offset[0], sectsize, block1))
|
||||
goto finish;
|
||||
|
||||
if (!dev_read(dev, offset[1], sectsize, block2))
|
||||
goto finish;
|
||||
|
||||
dev_close(dev);
|
||||
|
||||
/* Is it labelled? */
|
||||
if (xlate32(ondisk1->magic) != LABEL_MAGIC)
|
||||
goto finish;
|
||||
|
||||
/* Compare the whole structs */
|
||||
if (memcmp(ondisk1, ondisk2, sizeof(struct label_ondisk)) != 0)
|
||||
goto finish;
|
||||
|
||||
/* OK, check the data area */
|
||||
if (memcmp(block1 + sizeof(struct label_ondisk),
|
||||
block2 + sizeof(struct label_ondisk),
|
||||
xlate16(ondisk1->datalen)) != 0)
|
||||
goto finish;
|
||||
|
||||
/* They match !! */
|
||||
status = 1;
|
||||
|
||||
finish:
|
||||
dbg_free(block2);
|
||||
dbg_free(block1);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int lvm2_label_remove(struct labeller *l, struct device *dev)
|
||||
{
|
||||
uint64_t size;
|
||||
uint32_t sectsize;
|
||||
char block[BLOCK_SIZE];
|
||||
int status1, status2;
|
||||
long offset[2];
|
||||
|
||||
if (!dev_get_size(dev, &size))
|
||||
return 0;
|
||||
|
||||
if (!dev_get_sectsize(dev, §size))
|
||||
return 0;
|
||||
|
||||
if (!dev_open(dev, O_RDWR)) {
|
||||
dbg_free(block);
|
||||
return 0;
|
||||
}
|
||||
|
||||
get_label_locations(size, sectsize, &offset[0], &offset[1]);
|
||||
memset(block, 0, BLOCK_SIZE);
|
||||
|
||||
/* Blank out the first label */
|
||||
status1 = dev_write(dev, offset[0], BLOCK_SIZE, block);
|
||||
if (!status1)
|
||||
log_error("Error erasing label 1\n");
|
||||
|
||||
/* ...and the other at the end of the device */
|
||||
status2 = dev_write(dev, offset[1], BLOCK_SIZE, block);
|
||||
if (!status2)
|
||||
log_error("Error erasing label 2\n");
|
||||
|
||||
dev_close(dev);
|
||||
|
||||
return ((status1 != 0) && (status2 != 0));
|
||||
}
|
||||
|
||||
static void lvm2_label_destroy(struct labeller *l)
|
||||
{
|
||||
}
|
||||
|
||||
static struct label_ops handler_ops = {
|
||||
can_handle: lvm2_is_labelled,
|
||||
write: lvm2_label_write,
|
||||
remove: lvm2_label_remove,
|
||||
read: lvm2_label_read,
|
||||
verify: lvm2_labels_match,
|
||||
destroy: lvm2_label_destroy,
|
||||
};
|
||||
|
||||
static struct labeller this_labeller = {
|
||||
private: NULL,
|
||||
ops: &handler_ops,
|
||||
};
|
||||
|
||||
/* Don't know how this gets called... */
|
||||
void lvm2_label_init()
|
||||
{
|
||||
label_register_handler("LVM2", &this_labeller);
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the GPL.
|
||||
*/
|
||||
|
||||
struct lvm2_label
|
||||
{
|
||||
uint32_t magic;
|
||||
uint32_t crc;
|
||||
uint64_t label1_loc;
|
||||
uint64_t label2_loc;
|
||||
uint16_t datalen;
|
||||
|
||||
char disk_type[32];
|
||||
uint32_t version[3];
|
||||
|
||||
char *data;
|
||||
};
|
||||
|
||||
#define VERSION_MATCH_EQUAL 1
|
||||
#define VERSION_MATCH_LESSTHAN 2
|
||||
#define VERSION_MATCH_LESSEQUAL 3
|
||||
#define VERSION_MATCH_ANY 4
|
||||
|
||||
extern struct dev_filter *lvm2_label_filter_create();
|
||||
extern struct dev_filter *lvm2_label_format_filter_create(char *disk_type, uint32_t version[3], int match_type);
|
@ -1,99 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#ifndef _LVM_UUID_MAP_H
|
||||
#define _LVM_UUID_MAP_H
|
||||
|
||||
#include "uuid-map.h"
|
||||
#include "dev-cache.h"
|
||||
#include "dbg_malloc.h"
|
||||
#include "log.h"
|
||||
#include "label.h"
|
||||
#include "pool.h"
|
||||
|
||||
struct uuid_map {
|
||||
struct dev_filter *filter;
|
||||
};
|
||||
|
||||
struct uuid_map *uuid_map_create(struct dev_filter *devices)
|
||||
{
|
||||
struct uuid_map *um;
|
||||
|
||||
if (!(um = dbg_malloc(sizeof(*um)))) {
|
||||
log_err("Couldn't allocate uuid_map object.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
um->filter = devices;
|
||||
return um;
|
||||
}
|
||||
|
||||
void uuid_map_destroy(struct uuid_map *um)
|
||||
{
|
||||
dbg_free(um);
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple, non-caching implementation to start with.
|
||||
*/
|
||||
struct device *uuid_map_lookup(struct uuid_map *um, struct id *id)
|
||||
{
|
||||
struct dev_iter *iter;
|
||||
struct device *dev;
|
||||
struct label *lab;
|
||||
|
||||
if (!(iter = dev_iter_create(um->filter))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while ((dev = dev_iter_get(iter))) {
|
||||
|
||||
if (!label_read(dev, &lab))
|
||||
continue;
|
||||
|
||||
if (id_equal(id, &lab->id)) {
|
||||
label_destroy(lab);
|
||||
break;
|
||||
}
|
||||
|
||||
label_destroy(lab);
|
||||
}
|
||||
|
||||
dev_iter_destroy(iter);
|
||||
return dev;
|
||||
}
|
||||
|
||||
struct id *uuid_map_lookup_label(struct pool *mem, struct uuid_map *um,
|
||||
const char *name)
|
||||
{
|
||||
struct device *dev;
|
||||
struct label *lab;
|
||||
struct id *id;
|
||||
|
||||
if (!(dev = dev_cache_get(name, um->filter))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!label_read(dev, &lab)) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(id = pool_alloc(mem, sizeof(*id)))) {
|
||||
stack;
|
||||
label_destroy(lab);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(id, &lab->id, sizeof(*id));
|
||||
|
||||
label_destroy(lab);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
#endif
|
@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#ifndef _LVM_UUID_MAP_H
|
||||
#define _LVM_UUID_MAP_H
|
||||
|
||||
#include "uuid.h"
|
||||
#include "dev-cache.h"
|
||||
#include "pool.h"
|
||||
|
||||
/*
|
||||
* Holds a mapping from uuid -> device.
|
||||
*/
|
||||
struct uuid_map;
|
||||
|
||||
struct uuid_map *uuid_map_create(struct dev_filter *devices);
|
||||
void uuid_map_destroy(struct uuid_map *um);
|
||||
|
||||
/*
|
||||
* Find the device with a particular uuid.
|
||||
*/
|
||||
struct device *uuid_map_lookup(struct uuid_map *um, struct id *id);
|
||||
struct id *uuid_map_lookup_label(struct pool *mem, struct uuid_map *um,
|
||||
const char *name);
|
||||
|
||||
#endif
|
@ -4,10 +4,9 @@
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "metadata.h"
|
||||
#include "pv_map.h"
|
||||
#include "log.h"
|
||||
#include "dbg_malloc.h"
|
||||
#include "lvm-string.h"
|
||||
#include "toolcontext.h"
|
||||
|
||||
@ -17,7 +16,7 @@
|
||||
* These functions adjust the pe counts in pv's
|
||||
* after we've added or removed segments.
|
||||
*/
|
||||
static void _get_extents(struct stripe_segment *seg)
|
||||
static void _get_extents(struct lv_segment *seg)
|
||||
{
|
||||
int s, count;
|
||||
struct physical_volume *pv;
|
||||
@ -29,7 +28,7 @@ static void _get_extents(struct stripe_segment *seg)
|
||||
}
|
||||
}
|
||||
|
||||
static void _put_extents(struct stripe_segment *seg)
|
||||
static void _put_extents(struct lv_segment *seg)
|
||||
{
|
||||
int s, count;
|
||||
struct physical_volume *pv;
|
||||
@ -43,9 +42,9 @@ static void _put_extents(struct stripe_segment *seg)
|
||||
}
|
||||
}
|
||||
|
||||
static struct stripe_segment *_alloc_segment(struct pool *mem, int stripes)
|
||||
static struct lv_segment *_alloc_segment(struct pool *mem, int stripes)
|
||||
{
|
||||
struct stripe_segment *seg;
|
||||
struct lv_segment *seg;
|
||||
uint32_t len = sizeof(*seg) + (stripes * sizeof(seg->area[0]));
|
||||
|
||||
if (!(seg = pool_zalloc(mem, len))) {
|
||||
@ -58,13 +57,13 @@ static struct stripe_segment *_alloc_segment(struct pool *mem, int stripes)
|
||||
|
||||
static int _alloc_stripe_area(struct logical_volume *lv, uint32_t stripes,
|
||||
uint32_t stripe_size,
|
||||
struct pv_area **areas, uint32_t * index)
|
||||
struct pv_area **areas, uint32_t *index)
|
||||
{
|
||||
uint32_t count = lv->le_count - *index;
|
||||
uint32_t per_area = count / stripes;
|
||||
uint32_t smallest = areas[stripes - 1]->count;
|
||||
uint32_t s;
|
||||
struct stripe_segment *seg;
|
||||
struct lv_segment *seg;
|
||||
|
||||
if (smallest < per_area)
|
||||
per_area = smallest;
|
||||
@ -75,6 +74,7 @@ static int _alloc_stripe_area(struct logical_volume *lv, uint32_t stripes,
|
||||
}
|
||||
|
||||
seg->lv = lv;
|
||||
seg->type = SEG_STRIPED;
|
||||
seg->le = *index;
|
||||
seg->len = per_area * stripes;
|
||||
seg->stripes = stripes;
|
||||
@ -169,11 +169,11 @@ static int _alloc_striped(struct logical_volume *lv,
|
||||
* the complete area then the area is split, otherwise the area
|
||||
* is unlinked from the pv_map.
|
||||
*/
|
||||
static int _alloc_linear_area(struct logical_volume *lv, uint32_t * index,
|
||||
static int _alloc_linear_area(struct logical_volume *lv, uint32_t *index,
|
||||
struct pv_map *map, struct pv_area *pva)
|
||||
{
|
||||
uint32_t count, remaining;
|
||||
struct stripe_segment *seg;
|
||||
struct lv_segment *seg;
|
||||
|
||||
count = pva->count;
|
||||
remaining = lv->le_count - *index;
|
||||
@ -186,6 +186,7 @@ static int _alloc_linear_area(struct logical_volume *lv, uint32_t * index,
|
||||
}
|
||||
|
||||
seg->lv = lv;
|
||||
seg->type = SEG_STRIPED;
|
||||
seg->le = *index;
|
||||
seg->len = count;
|
||||
seg->stripe_size = 0;
|
||||
@ -248,8 +249,8 @@ static int _alloc_contiguous(struct logical_volume *lv,
|
||||
* Areas just get allocated in order until the lv
|
||||
* is full.
|
||||
*/
|
||||
static int _alloc_simple(struct logical_volume *lv,
|
||||
struct list *pvms, uint32_t allocated)
|
||||
static int _alloc_next_free(struct logical_volume *lv,
|
||||
struct list *pvms, uint32_t allocated)
|
||||
{
|
||||
struct list *tmp1, *tmp2;
|
||||
struct pv_map *pvm;
|
||||
@ -305,8 +306,8 @@ static int _allocate(struct volume_group *vg, struct logical_volume *lv,
|
||||
else if (lv->alloc == ALLOC_CONTIGUOUS)
|
||||
r = _alloc_contiguous(lv, pvms, allocated);
|
||||
|
||||
else if (lv->alloc == ALLOC_NEXT_FREE)
|
||||
r = _alloc_simple(lv, pvms, allocated);
|
||||
else if (lv->alloc == ALLOC_NEXT_FREE || lv->alloc == ALLOC_DEFAULT)
|
||||
r = _alloc_next_free(lv, pvms, allocated);
|
||||
|
||||
else {
|
||||
log_error("Unknown allocation policy: "
|
||||
@ -322,7 +323,7 @@ static int _allocate(struct volume_group *vg, struct logical_volume *lv,
|
||||
* counts in pv's.
|
||||
*/
|
||||
for (segh = lv->segments.p; segh != old_tail; segh = segh->p)
|
||||
_get_extents(list_item(segh, struct stripe_segment));
|
||||
_get_extents(list_item(segh, struct lv_segment));
|
||||
} else {
|
||||
/*
|
||||
* Put the segment list back how we found it.
|
||||
@ -456,12 +457,12 @@ int lv_reduce(struct format_instance *fi,
|
||||
struct logical_volume *lv, uint32_t extents)
|
||||
{
|
||||
struct list *segh;
|
||||
struct stripe_segment *seg;
|
||||
struct lv_segment *seg;
|
||||
uint32_t count = extents;
|
||||
|
||||
for (segh = lv->segments.p;
|
||||
(segh != &lv->segments) && count; segh = segh->p) {
|
||||
seg = list_item(segh, struct stripe_segment);
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
|
||||
if (seg->len <= count) {
|
||||
/* remove this segment completely */
|
||||
@ -534,7 +535,7 @@ int lv_remove(struct volume_group *vg, struct logical_volume *lv)
|
||||
|
||||
/* iterate through the lv's segments freeing off the pe's */
|
||||
list_iterate(segh, &lv->segments)
|
||||
_put_extents(list_item(segh, struct stripe_segment));
|
||||
_put_extents(list_item(segh, struct lv_segment));
|
||||
|
||||
vg->lv_count--;
|
||||
vg->free_count += lv->le_count;
|
||||
|
@ -4,7 +4,7 @@
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "log.h"
|
||||
#include "lib.h"
|
||||
#include "metadata.h"
|
||||
|
||||
/*
|
||||
@ -12,12 +12,14 @@
|
||||
* successfully merged. If the do merge, 'first'
|
||||
* will be adjusted to contain both areas.
|
||||
*/
|
||||
static int _merge(struct stripe_segment *first, struct stripe_segment *second)
|
||||
static int _merge(struct lv_segment *first, struct lv_segment *second)
|
||||
{
|
||||
int s;
|
||||
uint32_t width;
|
||||
|
||||
if (!first ||
|
||||
(first->type != SEG_STRIPED) ||
|
||||
(first->type != second->type) ||
|
||||
(first->stripes != second->stripes) ||
|
||||
(first->stripe_size != second->stripe_size))
|
||||
return 0;
|
||||
@ -39,10 +41,10 @@ static int _merge(struct stripe_segment *first, struct stripe_segment *second)
|
||||
int lv_merge_segments(struct logical_volume *lv)
|
||||
{
|
||||
struct list *segh;
|
||||
struct stripe_segment *current, *prev = NULL;
|
||||
struct lv_segment *current, *prev = NULL;
|
||||
|
||||
list_iterate(segh, &lv->segments) {
|
||||
current = list_item(segh, struct stripe_segment);
|
||||
current = list_item(segh, struct lv_segment);
|
||||
|
||||
if (_merge(prev, current))
|
||||
list_del(¤t->list);
|
||||
|
@ -4,24 +4,21 @@
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "log.h"
|
||||
#include "lib.h"
|
||||
#include "pool.h"
|
||||
#include "device.h"
|
||||
#include "dev-cache.h"
|
||||
#include "metadata.h"
|
||||
#include "toolcontext.h"
|
||||
#include "lvm-string.h"
|
||||
#include "uuid.h"
|
||||
#include "vgcache.h"
|
||||
#include "cache.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
int _add_pv_to_vg(struct format_instance *fi, struct volume_group *vg,
|
||||
int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg,
|
||||
const char *pv_name)
|
||||
{
|
||||
struct pv_list *pvl;
|
||||
struct physical_volume *pv;
|
||||
struct pool *mem = fi->fmt->cmd->mem;
|
||||
struct pool *mem = fid->fmt->cmd->mem;
|
||||
struct list mdas;
|
||||
|
||||
log_verbose("Adding physical volume '%s' to volume group '%s'",
|
||||
pv_name, vg->name);
|
||||
@ -31,7 +28,8 @@ int _add_pv_to_vg(struct format_instance *fi, struct volume_group *vg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(pv = pv_read(fi->fmt->cmd, pv_name))) {
|
||||
list_init(&mdas);
|
||||
if (!(pv = pv_read(fid->fmt->cmd, pv_name, &mdas, NULL))) {
|
||||
log_error("Failed to read existing physical volume '%s'",
|
||||
pv_name);
|
||||
return 0;
|
||||
@ -43,6 +41,12 @@ int _add_pv_to_vg(struct format_instance *fi, struct volume_group *vg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pv->fmt != fid->fmt) {
|
||||
log_error("Physical volume %s is of different format type (%s)",
|
||||
pv_name, pv->fmt->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(pv->vg_name = pool_strdup(mem, vg->name))) {
|
||||
log_error("vg->name allocation failed for '%s'", pv_name);
|
||||
return 0;
|
||||
@ -58,13 +62,14 @@ int _add_pv_to_vg(struct format_instance *fi, struct volume_group *vg,
|
||||
|
||||
/*
|
||||
* The next two fields should be corrected
|
||||
* by fi->pv_setup.
|
||||
* by fid->pv_setup.
|
||||
*/
|
||||
pv->pe_count = (pv->size - pv->pe_start) / pv->pe_size;
|
||||
pv->pe_count = (pv->size - pv->pe_start) / vg->extent_size;
|
||||
|
||||
pv->pe_alloc_count = 0;
|
||||
|
||||
if (!fi->fmt->ops->pv_setup(fi, pv, vg)) {
|
||||
if (!fid->fmt->ops->pv_setup(fid->fmt, 0, 0, vg->extent_size, 0, 0,
|
||||
&fid->metadata_areas, pv, vg)) {
|
||||
log_error("Format-specific setup of physical volume '%s' "
|
||||
"failed.", pv_name);
|
||||
return 0;
|
||||
@ -93,19 +98,21 @@ int _add_pv_to_vg(struct format_instance *fi, struct volume_group *vg,
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vg_extend(struct format_instance *fi,
|
||||
int vg_extend(struct format_instance *fid,
|
||||
struct volume_group *vg, int pv_count, char **pv_names)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* attach each pv */
|
||||
for (i = 0; i < pv_count; i++)
|
||||
if (!_add_pv_to_vg(fi, vg, pv_names[i])) {
|
||||
if (!_add_pv_to_vg(fid, vg, pv_names[i])) {
|
||||
log_error("Unable to add physical volume '%s' to "
|
||||
"volume group '%s'.", pv_names[i], vg->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME Decide whether to initialise and add new mdahs to format instance */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -124,6 +131,7 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
|
||||
{
|
||||
struct volume_group *vg;
|
||||
struct pool *mem = cmd->mem;
|
||||
int consistent = 0;
|
||||
|
||||
if (!(vg = pool_zalloc(mem, sizeof(*vg)))) {
|
||||
stack;
|
||||
@ -132,7 +140,7 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
|
||||
|
||||
/* is this vg name already in use ? */
|
||||
init_partial(1);
|
||||
if (vg_read(cmd, vg_name)) {
|
||||
if (vg_read(cmd, vg_name, &consistent)) {
|
||||
log_err("A volume group called '%s' already exists.", vg_name);
|
||||
goto bad;
|
||||
}
|
||||
@ -198,11 +206,17 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct physical_volume *pv_create(struct format_instance *fid,
|
||||
const char *name,
|
||||
struct id *id, uint64_t size)
|
||||
/* Sizes in sectors */
|
||||
struct physical_volume *pv_create(struct format_type *fmt,
|
||||
struct device *dev,
|
||||
struct id *id, uint64_t size,
|
||||
uint64_t pe_start,
|
||||
uint32_t existing_extent_count,
|
||||
uint32_t existing_extent_size,
|
||||
int pvmetadatacopies,
|
||||
uint64_t pvmetadatasize, struct list *mdas)
|
||||
{
|
||||
struct pool *mem = fid->fmt->cmd->mem;
|
||||
struct pool *mem = fmt->cmd->mem;
|
||||
struct physical_volume *pv = pool_alloc(mem, sizeof(*pv));
|
||||
|
||||
if (!pv) {
|
||||
@ -215,10 +229,7 @@ struct physical_volume *pv_create(struct format_instance *fid,
|
||||
else
|
||||
memcpy(&pv->id, id, sizeof(*id));
|
||||
|
||||
if (!(pv->dev = dev_cache_get(name, fid->fmt->cmd->filter))) {
|
||||
log_error("%s: Couldn't find device.", name);
|
||||
goto bad;
|
||||
}
|
||||
pv->dev = dev;
|
||||
|
||||
if (!(pv->vg_name = pool_alloc(mem, NAME_LEN))) {
|
||||
stack;
|
||||
@ -229,22 +240,22 @@ struct physical_volume *pv_create(struct format_instance *fid,
|
||||
pv->status = ALLOCATABLE_PV;
|
||||
|
||||
if (!dev_get_size(pv->dev, &pv->size)) {
|
||||
log_error("%s: Couldn't get size.", name);
|
||||
log_error("%s: Couldn't get size.", dev_name(pv->dev));
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (size) {
|
||||
if (size > pv->size)
|
||||
log_print("WARNING: %s: Overriding real size. "
|
||||
"You could lose data.", name);
|
||||
"You could lose data.", dev_name(pv->dev));
|
||||
log_verbose("%s: Pretending size is %" PRIu64 " sectors.",
|
||||
name, size);
|
||||
dev_name(pv->dev), size);
|
||||
pv->size = size;
|
||||
}
|
||||
|
||||
if (pv->size < PV_MIN_SIZE) {
|
||||
log_error("%s: Size must exceed minimum of %lu sectors.",
|
||||
name, PV_MIN_SIZE);
|
||||
log_error("%s: Size must exceed minimum of %ld sectors.",
|
||||
dev_name(pv->dev), PV_MIN_SIZE);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
@ -252,11 +263,14 @@ struct physical_volume *pv_create(struct format_instance *fid,
|
||||
pv->pe_start = 0;
|
||||
pv->pe_count = 0;
|
||||
pv->pe_alloc_count = 0;
|
||||
pv->fid = fid;
|
||||
pv->fmt = fmt;
|
||||
|
||||
if (!fid->fmt->ops->pv_setup(fid, pv, NULL)) {
|
||||
if (!fmt->ops->pv_setup(fmt, pe_start, existing_extent_count,
|
||||
existing_extent_size,
|
||||
pvmetadatacopies, pvmetadatasize, mdas,
|
||||
pv, NULL)) {
|
||||
log_error("%s: Format-specific setup of physical volume "
|
||||
"failed.", name);
|
||||
"failed.", dev_name(pv->dev));
|
||||
goto bad;
|
||||
}
|
||||
return pv;
|
||||
@ -278,7 +292,21 @@ struct pv_list *find_pv_in_vg(struct volume_group *vg, const char *pv_name)
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct physical_volume *find_pv_in_vg_by_uuid(struct volume_group *vg,
|
||||
struct id *id)
|
||||
{
|
||||
struct list *pvh;
|
||||
struct pv_list *pvl;
|
||||
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pvl = list_item(pvh, struct pv_list);
|
||||
if (id_equal(&pvl->pv->id, id))
|
||||
return pvl->pv;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct lv_list *find_lv_in_vg(struct volume_group *vg, const char *lv_name)
|
||||
@ -339,16 +367,14 @@ struct physical_volume *find_pv(struct volume_group *vg, struct device *dev)
|
||||
int vg_remove(struct volume_group *vg)
|
||||
{
|
||||
struct list *mdah;
|
||||
void *mdl;
|
||||
|
||||
if (!vg->fid->fmt->ops->vg_remove)
|
||||
return 1;
|
||||
struct metadata_area *mda;
|
||||
|
||||
/* FIXME Improve recovery situation? */
|
||||
/* Remove each copy of the metadata */
|
||||
list_iterate(mdah, &vg->fid->metadata_areas) {
|
||||
mdl = list_item(mdah, struct metadata_area)->metadata_locn;
|
||||
if (!vg->fid->fmt->ops->vg_remove(vg->fid, vg, mdl)) {
|
||||
mda = list_item(mdah, struct metadata_area);
|
||||
if (mda->ops->vg_remove &&
|
||||
!mda->ops->vg_remove(vg->fid, vg, mda)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@ -360,7 +386,8 @@ int vg_remove(struct volume_group *vg)
|
||||
int vg_write(struct volume_group *vg)
|
||||
{
|
||||
struct list *mdah;
|
||||
void *mdl;
|
||||
struct metadata_area *mda;
|
||||
int cache_updated = 0;
|
||||
|
||||
if (vg->status & PARTIAL_VG) {
|
||||
log_error("Cannot change metadata for partial volume group %s",
|
||||
@ -368,24 +395,31 @@ int vg_write(struct volume_group *vg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (list_empty(&vg->fid->metadata_areas)) {
|
||||
log_error("Aborting vg_write: No metadata areas to write to!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
vg->seqno++;
|
||||
|
||||
/* Write to each copy of the metadata area */
|
||||
list_iterate(mdah, &vg->fid->metadata_areas) {
|
||||
mdl = list_item(mdah, struct metadata_area)->metadata_locn;
|
||||
if (!vg->fid->fmt->ops->vg_write(vg->fid, vg, mdl)) {
|
||||
mda = list_item(mdah, struct metadata_area);
|
||||
if (!mda->ops->vg_write(vg->fid, vg, mda)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!vg->fid->fmt->ops->vg_commit)
|
||||
return 1;
|
||||
|
||||
/* Commit to each copy of the metadata area */
|
||||
list_iterate(mdah, &vg->fid->metadata_areas) {
|
||||
mdl = list_item(mdah, struct metadata_area)->metadata_locn;
|
||||
if (!vg->fid->fmt->ops->vg_commit(vg->fid, vg, mdl)) {
|
||||
mda = list_item(mdah, struct metadata_area);
|
||||
if (!cache_updated) {
|
||||
cache_update_vg(vg);
|
||||
cache_updated = 1;
|
||||
}
|
||||
if (mda->ops->vg_commit &&
|
||||
!mda->ops->vg_commit(vg->fid, vg, mda)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@ -394,46 +428,105 @@ int vg_write(struct volume_group *vg)
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name)
|
||||
/* Make orphan PVs look like a VG */
|
||||
struct volume_group *_vg_read_orphans(struct cmd_context *cmd)
|
||||
{
|
||||
struct cache_vginfo *vginfo;
|
||||
struct list *ih;
|
||||
struct device *dev;
|
||||
struct pv_list *pvl;
|
||||
struct volume_group *vg;
|
||||
struct physical_volume *pv;
|
||||
|
||||
if (!(vginfo = vginfo_from_vgname(ORPHAN))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(vg = pool_zalloc(cmd->mem, sizeof(*vg)))) {
|
||||
log_error("vg allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
list_init(&vg->pvs);
|
||||
list_init(&vg->lvs);
|
||||
list_init(&vg->snapshots);
|
||||
vg->cmd = cmd;
|
||||
if (!(vg->name = pool_strdup(cmd->mem, ORPHAN))) {
|
||||
log_error("vg name allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_iterate(ih, &vginfo->infos) {
|
||||
dev = list_item(ih, struct cache_info)->dev;
|
||||
if (!(pv = pv_read(cmd, dev_name(dev), NULL, NULL))) {
|
||||
continue;
|
||||
}
|
||||
if (!(pvl = pool_zalloc(cmd->mem, sizeof(*pvl)))) {
|
||||
log_error("pv_list allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
pvl->pv = pv;
|
||||
list_add(&vg->pvs, &pvl->list);
|
||||
vg->pv_count++;
|
||||
}
|
||||
|
||||
return vg;
|
||||
}
|
||||
|
||||
/* Caller sets consistent to 1 if it's safe for vg_read to correct
|
||||
* inconsistent metadata on disk (i.e. the VG write lock is held).
|
||||
* This guarantees only consistent metadata is returned unless PARTIAL_VG.
|
||||
* If consistent is 0, caller must check whether consistent == 1 on return
|
||||
* and take appropriate action if it isn't (e.g. abort; get write lock
|
||||
* and call vg_read again).
|
||||
*/
|
||||
struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
|
||||
int *consistent)
|
||||
{
|
||||
struct format_instance *fid;
|
||||
struct format_type *fmt;
|
||||
struct volume_group *vg, *correct_vg;
|
||||
struct list *mdah, *names;
|
||||
void *mdl;
|
||||
struct list *mdah;
|
||||
struct metadata_area *mda;
|
||||
int inconsistent = 0, first_time = 1;
|
||||
|
||||
/* create format instance with appropriate metadata area */
|
||||
if (!(fmt = vgcache_find_format(vg_name))) {
|
||||
/* Do full scan */
|
||||
if (!(names = get_vgs(cmd))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
pool_free(cmd->mem, names);
|
||||
if (!(fmt = vgcache_find_format(vg_name))) {
|
||||
stack;
|
||||
return NULL;
|
||||
if (!*vgname) {
|
||||
*consistent = 1;
|
||||
return _vg_read_orphans(cmd);
|
||||
}
|
||||
|
||||
/* Find the vgname in the cache */
|
||||
/* If it's not there we must do full scan to be completely sure */
|
||||
if (!(fmt = fmt_from_vgname(vgname))) {
|
||||
cache_label_scan(cmd, 0);
|
||||
if (!(fmt = fmt_from_vgname(vgname))) {
|
||||
cache_label_scan(cmd, 1);
|
||||
if (!(fmt = fmt_from_vgname(vgname))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(fid = fmt->ops->create_instance(fmt, vg_name, NULL))) {
|
||||
/* create format instance with appropriate metadata area */
|
||||
if (!(fid = fmt->ops->create_instance(fmt, vgname, NULL))) {
|
||||
log_error("Failed to create format instance");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Ensure contents of all metadata areas match - else do recovery */
|
||||
list_iterate(mdah, &fid->metadata_areas) {
|
||||
mdl = list_item(mdah, struct metadata_area)->metadata_locn;
|
||||
if (!(vg = fid->fmt->ops->vg_read(fid, vg_name, mdl))) {
|
||||
inconsistent = 1;
|
||||
continue;
|
||||
mda = list_item(mdah, struct metadata_area);
|
||||
if (!(vg = mda->ops->vg_read(fid, vgname, mda))) {
|
||||
inconsistent = 1;
|
||||
continue;
|
||||
}
|
||||
if (first_time) {
|
||||
correct_vg = vg;
|
||||
first_time = 0;
|
||||
continue;
|
||||
}
|
||||
/* FIXME Also ensure contents same - checksum compare? */
|
||||
if (correct_vg->seqno != vg->seqno) {
|
||||
inconsistent = 1;
|
||||
if (vg->seqno > correct_vg->seqno)
|
||||
@ -447,7 +540,21 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cache_update_vg(correct_vg);
|
||||
|
||||
if (inconsistent) {
|
||||
if (!*consistent)
|
||||
return correct_vg;
|
||||
|
||||
/* Don't touch partial volume group metadata */
|
||||
/* Should be fixed manually with vgcfgbackup/restore etc. */
|
||||
if ((correct_vg->status & PARTIAL_VG)) {
|
||||
log_error("Inconsistent metadata copies found for "
|
||||
"partial volume group %s", vgname);
|
||||
*consistent = 0;
|
||||
return correct_vg;
|
||||
}
|
||||
|
||||
log_print("Inconsistent metadata copies found - updating "
|
||||
"to use version %u", correct_vg->seqno);
|
||||
if (!vg_write(correct_vg)) {
|
||||
@ -456,51 +563,121 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name)
|
||||
}
|
||||
}
|
||||
|
||||
vgcache_add(vg_name, correct_vg->id.uuid, NULL, fmt);
|
||||
*consistent = 1;
|
||||
|
||||
return correct_vg;
|
||||
}
|
||||
|
||||
/* This is only called by lv_from_lvid, which is only called from
|
||||
* activate.c so we know the appropriate VG lock is already held and
|
||||
* the vg_read is therefore safe.
|
||||
*/
|
||||
struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid)
|
||||
{
|
||||
char *vgname;
|
||||
struct list *vgs, *vgh;
|
||||
struct list *vgnames, *slh;
|
||||
struct volume_group *vg;
|
||||
struct cache_vginfo *vginfo;
|
||||
int consistent = 0;
|
||||
|
||||
if (!(vgs = get_vgs(cmd))) {
|
||||
/* Is corresponding vgname already cached? */
|
||||
if ((vginfo = vginfo_from_vgid(vgid)) &&
|
||||
vginfo->vgname && *vginfo->vgname) {
|
||||
if ((vg = vg_read(cmd, vginfo->vgname, &consistent)) &&
|
||||
!strncmp(vg->id.uuid, vgid, ID_LEN)) {
|
||||
if (!consistent) {
|
||||
log_error("Volume group %s metadata is "
|
||||
"inconsistent", vginfo->vgname);
|
||||
return NULL;
|
||||
}
|
||||
return vg;
|
||||
}
|
||||
}
|
||||
|
||||
/* The slow way - full scan required to cope with vgrename */
|
||||
if (!(vgnames = get_vgs(cmd, 1))) {
|
||||
log_error("vg_read_by_vgid: get_vgs failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_iterate(vgh, vgs) {
|
||||
vgname = list_item(vgh, struct name_list)->name;
|
||||
if ((vg = vg_read(cmd, vgname)) &&
|
||||
!strncmp(vg->id.uuid, vgid, ID_LEN)) return vg;
|
||||
list_iterate(slh, vgnames) {
|
||||
vgname = list_item(slh, struct str_list)->str;
|
||||
if (!vgname || !*vgname)
|
||||
continue; /* FIXME Unnecessary? */
|
||||
consistent = 0;
|
||||
if ((vg = vg_read(cmd, vgname, &consistent)) &&
|
||||
!strncmp(vg->id.uuid, vgid, ID_LEN)) {
|
||||
if (!consistent) {
|
||||
log_error("Volume group %s metadata is "
|
||||
"inconsistent", vgname);
|
||||
return NULL;
|
||||
}
|
||||
return vg;
|
||||
}
|
||||
}
|
||||
|
||||
pool_free(cmd->mem, vgs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* FIXME Use label functions instead of PV functions? */
|
||||
struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name)
|
||||
/* Only called by activate.c */
|
||||
struct logical_volume *lv_from_lvid(struct cmd_context *cmd, const char *lvid_s)
|
||||
{
|
||||
struct lv_list *lvl;
|
||||
struct volume_group *vg;
|
||||
union lvid *lvid;
|
||||
|
||||
lvid = (union lvid *) lvid_s;
|
||||
|
||||
log_very_verbose("Finding volume group for uuid %s", lvid_s);
|
||||
if (!(vg = vg_read_by_vgid(cmd, lvid->id[0].uuid))) {
|
||||
log_error("Volume group for uuid not found: %s", lvid_s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
log_verbose("Found volume group \"%s\"", vg->name);
|
||||
if (vg->status & EXPORTED_VG) {
|
||||
log_error("Volume group \"%s\" is exported", vg->name);
|
||||
return NULL;
|
||||
}
|
||||
if (!(lvl = find_lv_in_vg_by_lvid(vg, lvid))) {
|
||||
log_very_verbose("Can't find logical volume id %s", lvid_s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return lvl->lv;
|
||||
}
|
||||
|
||||
/* FIXME Use label functions instead of PV functions */
|
||||
struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
|
||||
struct list *mdas, uint64_t *label_sector)
|
||||
{
|
||||
struct physical_volume *pv;
|
||||
struct label *label;
|
||||
struct cache_info *info;
|
||||
struct device *dev;
|
||||
|
||||
if (!(dev = dev_cache_get(pv_name, cmd->filter))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(label_read(dev, &label))) {
|
||||
log_error("Failed to read label on physical volume %s",
|
||||
pv_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
info = (struct cache_info *) label->info;
|
||||
if (label_sector && *label_sector)
|
||||
*label_sector = label->sector;
|
||||
|
||||
if (!(pv = pool_zalloc(cmd->mem, sizeof(*pv)))) {
|
||||
log_error("pv_list allocation for '%s' failed", pv_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Member of a format1 VG? */
|
||||
if (!(cmd->fmt1->ops->pv_read(cmd->fmt1, pv_name, pv))) {
|
||||
log_error("Failed to read existing physical volume '%s'",
|
||||
pv_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Member of a format_text VG? */
|
||||
if (!(cmd->fmtt->ops->pv_read(cmd->fmtt, pv_name, pv))) {
|
||||
/* FIXME Move more common code up here */
|
||||
if (!(info->fmt->ops->pv_read(info->fmt, pv_name, pv, mdas))) {
|
||||
log_error("Failed to read existing physical volume '%s'",
|
||||
pv_name);
|
||||
return 0;
|
||||
@ -512,30 +689,22 @@ struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name)
|
||||
return pv;
|
||||
}
|
||||
|
||||
struct list *get_vgs(struct cmd_context *cmd)
|
||||
/* May return empty list */
|
||||
struct list *get_vgs(struct cmd_context *cmd, int full_scan)
|
||||
{
|
||||
struct list *names;
|
||||
|
||||
if (!(names = pool_alloc(cmd->mem, sizeof(*names)))) {
|
||||
log_error("VG name list allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_init(names);
|
||||
|
||||
if (!cmd->fmt1->ops->get_vgs(cmd->fmt1, names) ||
|
||||
!cmd->fmtt->ops->get_vgs(cmd->fmtt, names) ||
|
||||
list_empty(names)) {
|
||||
pool_free(cmd->mem, names);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return names;
|
||||
return cache_get_vgnames(cmd, full_scan);
|
||||
}
|
||||
|
||||
struct list *get_pvs(struct cmd_context *cmd)
|
||||
{
|
||||
struct list *results;
|
||||
char *vgname;
|
||||
struct list *pvh, *tmp;
|
||||
struct list *vgnames, *slh;
|
||||
struct volume_group *vg;
|
||||
int consistent = 0;
|
||||
|
||||
cache_label_scan(cmd, 0);
|
||||
|
||||
if (!(results = pool_alloc(cmd->mem, sizeof(*results)))) {
|
||||
log_error("PV list allocation failed");
|
||||
@ -544,40 +713,50 @@ struct list *get_pvs(struct cmd_context *cmd)
|
||||
|
||||
list_init(results);
|
||||
|
||||
/* fmtt modifies fmt1 output */
|
||||
if (!cmd->fmt1->ops->get_pvs(cmd->fmt1, results) ||
|
||||
!cmd->fmtt->ops->get_pvs(cmd->fmtt, results)) {
|
||||
pool_free(cmd->mem, results);
|
||||
/* Get list of VGs */
|
||||
if (!(vgnames = get_vgs(cmd, 0))) {
|
||||
log_error("get_pvs: get_vgs failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Read every VG to ensure cache consistency */
|
||||
/* Orphan VG is last on list */
|
||||
init_partial(1);
|
||||
list_iterate(slh, vgnames) {
|
||||
vgname = list_item(slh, struct str_list)->str;
|
||||
if (!vgname)
|
||||
continue; /* FIXME Unnecessary? */
|
||||
consistent = 0;
|
||||
if (!(vg = vg_read(cmd, vgname, &consistent))) {
|
||||
stack;
|
||||
continue;
|
||||
}
|
||||
if (!consistent)
|
||||
log_print("Warning: Volume Group %s is not consistent",
|
||||
vgname);
|
||||
|
||||
/* Move PVs onto results list */
|
||||
list_iterate_safe(pvh, tmp, &vg->pvs) {
|
||||
list_add(results, pvh);
|
||||
}
|
||||
}
|
||||
init_partial(0);
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
int pv_write(struct cmd_context *cmd, struct physical_volume *pv)
|
||||
int pv_write(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
struct list *mdas, int64_t label_sector)
|
||||
{
|
||||
struct list *mdah;
|
||||
void *mdl;
|
||||
|
||||
/* Write to each copy of the metadata area */
|
||||
list_iterate(mdah, &pv->fid->metadata_areas) {
|
||||
mdl = list_item(mdah, struct metadata_area)->metadata_locn;
|
||||
if (!pv->fid->fmt->ops->pv_write(pv->fid, pv, mdl)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
if (*pv->vg_name || pv->pe_alloc_count) {
|
||||
log_error("Assertion failed: can't _pv_write non-orphan PV "
|
||||
"(in VG %s)", pv->vg_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!pv->fid->fmt->ops->pv_commit)
|
||||
return 1;
|
||||
|
||||
/* Commit to each copy of the metadata area */
|
||||
list_iterate(mdah, &pv->fid->metadata_areas) {
|
||||
mdl = list_item(mdah, struct metadata_area)->metadata_locn;
|
||||
if (!pv->fid->fmt->ops->pv_commit(pv->fid, pv, mdl)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
if (!pv->fmt->ops->pv_write(pv->fmt, pv, mdas, label_sector)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
@ -10,90 +10,126 @@
|
||||
#ifndef _LVM_METADATA_H
|
||||
#define _LVM_METADATA_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <asm/page.h>
|
||||
#include "ctype.h"
|
||||
#include "dev-cache.h"
|
||||
#include "list.h"
|
||||
#include "uuid.h"
|
||||
#include <sys/types.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
#define NAME_LEN 128
|
||||
#define MAX_STRIPES 128
|
||||
#define SECTOR_SIZE 512
|
||||
#define STRIPE_SIZE_DEFAULT 16 /* 16KB */
|
||||
#define STRIPE_SIZE_MIN ( PAGE_SIZE/SECTOR_SIZE) /* PAGESIZE in sectors */
|
||||
#define STRIPE_SIZE_MAX ( 512L * 1024 / SECTOR_SIZE) /* 512 KB in sectors */
|
||||
#define PV_MIN_SIZE ( 512L * 1024 / SECTOR_SIZE) /* 512 KB in sectors */
|
||||
#define PE_ALIGN (65536UL / SECTOR_SIZE) /* PE alignment */
|
||||
|
||||
#define SECTOR_SHIFT 9L
|
||||
#define SECTOR_SIZE ( 1L << SECTOR_SHIFT )
|
||||
#define STRIPE_SIZE_DEFAULT 16 /* 16KB */
|
||||
#define STRIPE_SIZE_MIN ( PAGE_SIZE >> SECTOR_SHIFT) /* PAGESIZE in sectors */
|
||||
#define STRIPE_SIZE_MAX ( 512L * 1024L >> SECTOR_SHIFT) /* 512 KB in sectors */
|
||||
#define PV_MIN_SIZE ( 512L * 1024L >> SECTOR_SHIFT) /* 512 KB in sectors */
|
||||
#define PE_ALIGN (65536UL >> SECTOR_SHIFT) /* PE alignment */
|
||||
|
||||
/* Various flags */
|
||||
/* Note that the bits no longer necessarily correspond to LVM1 disk format */
|
||||
|
||||
#define BIT(x) (1 << x)
|
||||
#define EXPORTED_VG BIT(0) /* VG PV */
|
||||
#define RESIZEABLE_VG BIT(1) /* VG */
|
||||
#define PARTIAL_VG BIT(2) /* VG */
|
||||
#define PARTIAL_VG 0x00000001 /* VG */
|
||||
#define EXPORTED_VG 0x00000002 /* VG PV */
|
||||
#define RESIZEABLE_VG 0x00000004 /* VG */
|
||||
|
||||
/*
|
||||
* May any free extents on this PV be used or must they be left
|
||||
* free?
|
||||
*/
|
||||
#define ALLOCATABLE_PV BIT(3) /* PV */
|
||||
/* May any free extents on this PV be used or must they be left free? */
|
||||
#define ALLOCATABLE_PV 0x00000008 /* PV */
|
||||
|
||||
#define SPINDOWN_LV BIT(4) /* LV */
|
||||
#define BADBLOCK_ON BIT(5) /* LV */
|
||||
#define FIXED_MINOR BIT(6) /* LV */
|
||||
#define VISIBLE_LV BIT(7) /* LV */
|
||||
#define SPINDOWN_LV 0x00000010 /* LV */
|
||||
#define BADBLOCK_ON 0x00000020 /* LV */
|
||||
#define VISIBLE_LV 0x00000040 /* LV */
|
||||
#define FIXED_MINOR 0x00000080 /* LV */
|
||||
/* FIXME Remove when metadata restructuring is completed */
|
||||
#define SNAPSHOT 0x00001000 /* LV - temp internal use only */
|
||||
|
||||
/*
|
||||
* FIXME: do we really set read/write for a whole vg ?
|
||||
*/
|
||||
#define LVM_READ BIT(8) /* LV VG */
|
||||
#define LVM_WRITE BIT(9) /* LV VG */
|
||||
#define CLUSTERED BIT(10) /* VG */
|
||||
#define SHARED BIT(11) /* VG */
|
||||
|
||||
#define FMT_SEGMENTS 0x00000001 /* Arbitrary segment parameters? */
|
||||
|
||||
#define FMT_TEXT_NAME "text"
|
||||
#define FMT_LVM1_NAME "lvm1"
|
||||
#define LVM_READ 0x00000100 /* LV VG */
|
||||
#define LVM_WRITE 0x00000200 /* LV VG */
|
||||
#define CLUSTERED 0x00000400 /* VG */
|
||||
#define SHARED 0x00000800 /* VG */
|
||||
|
||||
/* Format features flags */
|
||||
#define FMT_SEGMENTS 0x00000001 /* Arbitrary segment params? */
|
||||
#define FMT_MDAS 0x00000002 /* Proper metadata areas? */
|
||||
|
||||
typedef enum {
|
||||
ALLOC_DEFAULT,
|
||||
ALLOC_NEXT_FREE,
|
||||
ALLOC_STRICT,
|
||||
ALLOC_CONTIGUOUS
|
||||
|
||||
} alloc_policy_t;
|
||||
|
||||
struct physical_volume {
|
||||
struct id id;
|
||||
struct device *dev;
|
||||
struct format_instance *fid;
|
||||
char *vg_name;
|
||||
|
||||
uint32_t status;
|
||||
uint64_t size;
|
||||
|
||||
/* physical extents */
|
||||
uint64_t pe_size;
|
||||
uint64_t pe_start;
|
||||
uint32_t pe_count;
|
||||
uint32_t pe_alloc_count;
|
||||
};
|
||||
typedef enum {
|
||||
SEG_STRIPED,
|
||||
SEG_SNAPSHOT,
|
||||
SEG_MIRROR
|
||||
} segment_type_t;
|
||||
|
||||
struct cmd_context;
|
||||
struct format_handler;
|
||||
struct labeller;
|
||||
|
||||
struct format_type {
|
||||
struct list list;
|
||||
struct cmd_context *cmd;
|
||||
struct format_handler *ops;
|
||||
struct labeller *labeller;
|
||||
const char *name;
|
||||
const char *alias;
|
||||
uint32_t features;
|
||||
void *library;
|
||||
void *private;
|
||||
};
|
||||
|
||||
struct physical_volume {
|
||||
struct id id;
|
||||
struct device *dev;
|
||||
struct format_type *fmt;
|
||||
char *vg_name;
|
||||
|
||||
uint32_t status;
|
||||
uint64_t size;
|
||||
|
||||
/* physical extents */
|
||||
uint64_t pe_size;
|
||||
uint64_t pe_start;
|
||||
uint32_t pe_count;
|
||||
uint32_t pe_alloc_count;
|
||||
};
|
||||
|
||||
struct metadata_area;
|
||||
struct format_instance;
|
||||
|
||||
/* Per-format per-metadata area operations */
|
||||
struct metadata_area_ops {
|
||||
struct volume_group *(*vg_read) (struct format_instance * fi,
|
||||
const char *vg_name,
|
||||
struct metadata_area * mda);
|
||||
/*
|
||||
* Write out complete VG metadata. You must ensure internal
|
||||
* consistency before calling. eg. PEs can't refer to PVs not
|
||||
* part of the VG.
|
||||
*
|
||||
* It is also the responsibility of the caller to ensure external
|
||||
* consistency, eg by calling pv_write() if removing PVs from
|
||||
* a VG or calling vg_write() a second time if splitting a VG
|
||||
* into two.
|
||||
*
|
||||
* vg_write() should not read or write from any PVs not included
|
||||
* in the volume_group structure it is handed.
|
||||
* (format1 currently breaks this rule.)
|
||||
*/
|
||||
int (*vg_write) (struct format_instance * fid, struct volume_group * vg,
|
||||
struct metadata_area * mda);
|
||||
int (*vg_commit) (struct format_instance * fid,
|
||||
struct volume_group * vg, struct metadata_area * mda);
|
||||
int (*vg_remove) (struct format_instance * fi, struct volume_group * vg,
|
||||
struct metadata_area * mda);
|
||||
};
|
||||
|
||||
struct metadata_area {
|
||||
struct list list;
|
||||
struct metadata_area_ops *ops;
|
||||
void *metadata_locn;
|
||||
};
|
||||
|
||||
@ -105,27 +141,27 @@ struct format_instance {
|
||||
struct volume_group {
|
||||
struct cmd_context *cmd;
|
||||
struct format_instance *fid;
|
||||
uint32_t seqno; /* Metadata sequence number */
|
||||
uint32_t seqno; /* Metadata sequence number */
|
||||
|
||||
struct id id;
|
||||
char *name;
|
||||
char *system_id;
|
||||
|
||||
uint32_t status;
|
||||
uint32_t status;
|
||||
|
||||
uint32_t extent_size;
|
||||
uint32_t extent_count;
|
||||
uint32_t free_count;
|
||||
uint32_t extent_size;
|
||||
uint32_t extent_count;
|
||||
uint32_t free_count;
|
||||
|
||||
uint32_t max_lv;
|
||||
uint32_t max_pv;
|
||||
uint32_t max_lv;
|
||||
uint32_t max_pv;
|
||||
|
||||
/* physical volumes */
|
||||
uint32_t pv_count;
|
||||
/* physical volumes */
|
||||
uint32_t pv_count;
|
||||
struct list pvs;
|
||||
|
||||
/* logical volumes */
|
||||
uint32_t lv_count;
|
||||
/* logical volumes */
|
||||
uint32_t lv_count;
|
||||
struct list lvs;
|
||||
|
||||
/* snapshots */
|
||||
@ -133,17 +169,23 @@ struct volume_group {
|
||||
struct list snapshots;
|
||||
};
|
||||
|
||||
struct stripe_segment {
|
||||
struct lv_segment {
|
||||
struct list list;
|
||||
|
||||
struct logical_volume *lv;
|
||||
|
||||
segment_type_t type;
|
||||
uint32_t le;
|
||||
uint32_t len;
|
||||
|
||||
/* FIXME Fields depend on segment type */
|
||||
uint32_t stripe_size;
|
||||
uint32_t stripes;
|
||||
struct logical_volume *origin;
|
||||
struct logical_volume *cow;
|
||||
uint32_t chunk_size;
|
||||
|
||||
/* There will be one area for each stripe */
|
||||
struct {
|
||||
struct {
|
||||
struct physical_volume *pv;
|
||||
uint32_t pe;
|
||||
} area[0];
|
||||
@ -151,22 +193,24 @@ struct stripe_segment {
|
||||
|
||||
struct logical_volume {
|
||||
union lvid lvid;
|
||||
char *name;
|
||||
char *name;
|
||||
|
||||
struct volume_group *vg;
|
||||
|
||||
uint32_t status;
|
||||
uint32_t status;
|
||||
alloc_policy_t alloc;
|
||||
uint32_t read_ahead;
|
||||
int32_t minor;
|
||||
|
||||
uint64_t size;
|
||||
uint32_t le_count;
|
||||
uint64_t size;
|
||||
uint32_t le_count;
|
||||
|
||||
struct list segments;
|
||||
};
|
||||
|
||||
struct snapshot {
|
||||
struct id id;
|
||||
|
||||
int persistent; /* boolean */
|
||||
uint32_t chunk_size; /* in 512 byte sectors */
|
||||
|
||||
@ -182,6 +226,7 @@ struct name_list {
|
||||
struct pv_list {
|
||||
struct list list;
|
||||
struct physical_volume *pv;
|
||||
struct list *mdas;
|
||||
};
|
||||
|
||||
struct lv_list {
|
||||
@ -195,133 +240,111 @@ struct snapshot_list {
|
||||
struct snapshot *snapshot;
|
||||
};
|
||||
|
||||
|
||||
struct mda_list {
|
||||
struct list list;
|
||||
struct device_area mda;
|
||||
};
|
||||
|
||||
/*
|
||||
* Ownership of objects passes to caller.
|
||||
*/
|
||||
struct format_handler {
|
||||
/*
|
||||
* Returns a name_list of vg's.
|
||||
* Scan any metadata areas that aren't referenced in PV labels
|
||||
*/
|
||||
struct list *(*get_vgs)(struct format_type *fmt, struct list *names);
|
||||
|
||||
/*
|
||||
* Returns pv_list of fully-populated pv structures.
|
||||
*/
|
||||
struct list *(*get_pvs)(struct format_type *fmt, struct list *results);
|
||||
int (*scan) (struct format_type * fmt);
|
||||
|
||||
/*
|
||||
* Return PV with given path.
|
||||
*/
|
||||
int (*pv_read)(struct format_type *fmt,
|
||||
const char *pv_name,
|
||||
struct physical_volume *pv);
|
||||
int (*pv_read) (struct format_type * fmt, const char *pv_name,
|
||||
struct physical_volume * pv, struct list * mdas);
|
||||
|
||||
/*
|
||||
* Tweak an already filled out a pv ready for importing into a
|
||||
* vg. eg. pe_count is format specific.
|
||||
*/
|
||||
int (*pv_setup)(struct format_instance *fi, struct physical_volume *pv,
|
||||
struct volume_group *vg);
|
||||
int (*pv_setup) (struct format_type * fmt,
|
||||
uint64_t pe_start, uint32_t extent_count,
|
||||
uint32_t extent_size,
|
||||
int pvmetadatacopies,
|
||||
uint64_t pvmetadatasize, struct list * mdas,
|
||||
struct physical_volume * pv, struct volume_group * vg);
|
||||
|
||||
/*
|
||||
* Write a PV structure to disk. Fails if the PV is in a VG ie
|
||||
* pv->vg_name must be null.
|
||||
*/
|
||||
int (*pv_write)(struct format_instance *fi, struct physical_volume *pv,
|
||||
void *mdl);
|
||||
int (*pv_commit)(struct format_instance *fid,
|
||||
struct physical_volume *pv, void *mdl);
|
||||
int (*pv_write) (struct format_type * fmt, struct physical_volume * pv,
|
||||
struct list * mdas, int64_t label_sector);
|
||||
|
||||
/*
|
||||
* Tweak an already filled out a lv eg, check there
|
||||
* aren't too many extents.
|
||||
*/
|
||||
int (*lv_setup)(struct format_instance *fi, struct logical_volume *lv);
|
||||
int (*lv_setup) (struct format_instance * fi,
|
||||
struct logical_volume * lv);
|
||||
|
||||
/*
|
||||
* Tweak an already filled out vg. eg, max_pv is format
|
||||
* specific.
|
||||
*/
|
||||
int (*vg_setup)(struct format_instance *fi, struct volume_group *vg);
|
||||
int (*vg_remove)(struct format_instance *fi, struct volume_group *vg,
|
||||
void *mdl);
|
||||
int (*vg_setup) (struct format_instance * fi, struct volume_group * vg);
|
||||
|
||||
/*
|
||||
* The name may be prefixed with the dev_dir from the
|
||||
* job_context.
|
||||
* mdl is the metadata location to use
|
||||
*/
|
||||
struct volume_group *(*vg_read)(struct format_instance *fi,
|
||||
const char *vg_name, void *mdl);
|
||||
|
||||
/*
|
||||
* Write out complete VG metadata. You must ensure internal
|
||||
* consistency before calling. eg. PEs can't refer to PVs not
|
||||
* part of the VG.
|
||||
*
|
||||
* It is also the responsibility of the caller to ensure external
|
||||
* consistency, eg by calling pv_write() if removing PVs from
|
||||
* a VG or calling vg_write() a second time if splitting a VG
|
||||
* into two.
|
||||
*
|
||||
* vg_write() must not read or write from any PVs not included
|
||||
* in the volume_group structure it is handed. Note: format1
|
||||
* does read all pv's currently.
|
||||
*/
|
||||
int (*vg_write)(struct format_instance *fid, struct volume_group *vg,
|
||||
void *mdl);
|
||||
|
||||
int (*vg_commit)(struct format_instance *fid, struct volume_group *vg,
|
||||
void *mdl);
|
||||
/*
|
||||
* Create format instance with a particular metadata area
|
||||
*/
|
||||
struct format_instance *(*create_instance)(struct format_type *fmt,
|
||||
const char *vgname,
|
||||
void *context);
|
||||
struct format_instance *(*create_instance) (struct format_type * fmt,
|
||||
const char *vgname,
|
||||
void *context);
|
||||
|
||||
/*
|
||||
* Destructor for format instance
|
||||
*/
|
||||
void (*destroy_instance)(struct format_instance *fid);
|
||||
void (*destroy_instance) (struct format_instance * fid);
|
||||
|
||||
/*
|
||||
* Destructor for format type
|
||||
*/
|
||||
void (*destroy)(struct format_type *fmt);
|
||||
void (*destroy) (struct format_type * fmt);
|
||||
};
|
||||
|
||||
/*
|
||||
* Utility functions
|
||||
*/
|
||||
int vg_write(struct volume_group *vg);
|
||||
struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name);
|
||||
struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name,
|
||||
int *consistent);
|
||||
struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid);
|
||||
struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name);
|
||||
struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
|
||||
struct list *mdas, uint64_t *label_sector);
|
||||
struct list *get_pvs(struct cmd_context *cmd);
|
||||
struct list *get_vgs(struct cmd_context *cmd);
|
||||
int pv_write(struct cmd_context *cmd, struct physical_volume *pv);
|
||||
|
||||
/* Set full_scan to 1 to re-read every (filtered) device label */
|
||||
struct list *get_vgs(struct cmd_context *cmd, int full_scan);
|
||||
|
||||
struct physical_volume *pv_create(struct format_instance *fi,
|
||||
const char *name,
|
||||
int pv_write(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
struct list *mdas, int64_t label_sector);
|
||||
|
||||
/* pe_start and pe_end relate to any existing data so that new metadata
|
||||
* areas can avoid overlap */
|
||||
struct physical_volume *pv_create(struct format_type *fmt,
|
||||
struct device *dev,
|
||||
struct id *id,
|
||||
uint64_t size);
|
||||
uint64_t size,
|
||||
uint64_t pe_start,
|
||||
uint32_t existing_extent_count,
|
||||
uint32_t existing_extent_size,
|
||||
int pvmetadatacopies,
|
||||
uint64_t pvmetadatasize, struct list *mdas);
|
||||
|
||||
struct volume_group *vg_create(struct cmd_context *cmd, const char *name,
|
||||
uint32_t extent_size, int max_pv, int max_lv,
|
||||
int pv_count, char **pv_names);
|
||||
int vg_remove(struct volume_group *vg);
|
||||
|
||||
/*
|
||||
* This needs the format instance to check the
|
||||
* pv's are orphaned.
|
||||
*/
|
||||
int vg_extend(struct format_instance *fi,
|
||||
struct volume_group *vg, int pv_count, char **pv_names);
|
||||
|
||||
int vg_extend(struct format_instance *fi, struct volume_group *vg,
|
||||
int pv_count, char **pv_names);
|
||||
|
||||
/*
|
||||
* Create a new LV within a given volume group.
|
||||
@ -344,35 +367,33 @@ int lv_extend(struct format_instance *fi,
|
||||
struct logical_volume *lv,
|
||||
uint32_t stripes,
|
||||
uint32_t stripe_size,
|
||||
uint32_t extents,
|
||||
struct list *allocatable_pvs);
|
||||
uint32_t extents, struct list *allocatable_pvs);
|
||||
|
||||
/* lv must be part of vg->lvs */
|
||||
int lv_remove(struct volume_group *vg, struct logical_volume *lv);
|
||||
|
||||
|
||||
/* FIXME: Move to other files */
|
||||
int id_eq(struct id *op1, struct id *op2);
|
||||
|
||||
/* Manipulate PV structures */
|
||||
int pv_add(struct volume_group *vg, struct physical_volume *pv);
|
||||
int pv_remove(struct volume_group *vg, struct physical_volume *pv);
|
||||
struct physical_volume *pv_find(struct volume_group *vg,
|
||||
const char *pv_name);
|
||||
|
||||
struct physical_volume *pv_find(struct volume_group *vg, const char *pv_name);
|
||||
|
||||
/* Find a PV within a given VG */
|
||||
struct pv_list *find_pv_in_vg(struct volume_group *vg, const char *pv_name);
|
||||
struct physical_volume *find_pv_in_vg_by_uuid(struct volume_group *vg,
|
||||
struct id *id);
|
||||
|
||||
/* Find an LV within a given VG */
|
||||
struct lv_list *find_lv_in_vg(struct volume_group *vg, const char *lv_name);
|
||||
struct lv_list *find_lv_in_vg_by_lvid(struct volume_group *vg,
|
||||
struct lv_list *find_lv_in_vg_by_lvid(struct volume_group *vg,
|
||||
union lvid *lvid);
|
||||
|
||||
/* Return the VG that contains a given LV (based on path given in lv_name) */
|
||||
/* or environment var */
|
||||
struct volume_group *find_vg_with_lv(const char *lv_name);
|
||||
|
||||
/* Find LV with given lvid (used during activation) */
|
||||
struct logical_volume *lv_from_lvid(struct cmd_context *cmd,
|
||||
const char *lvid_s);
|
||||
|
||||
/* FIXME Merge these functions with ones above */
|
||||
struct physical_volume *find_pv(struct volume_group *vg, struct device *dev);
|
||||
@ -388,7 +409,6 @@ const char *strip_dir(const char *vg_name, const char *dir);
|
||||
*/
|
||||
int lv_check_segments(struct logical_volume *lv);
|
||||
|
||||
|
||||
/*
|
||||
* Sometimes (eg, after an lvextend), it is possible to merge two
|
||||
* adjacent segments into a single segment. This function trys
|
||||
@ -396,7 +416,6 @@ int lv_check_segments(struct logical_volume *lv);
|
||||
*/
|
||||
int lv_merge_segments(struct logical_volume *lv);
|
||||
|
||||
|
||||
/*
|
||||
* Useful functions for managing snapshots.
|
||||
*/
|
||||
@ -409,10 +428,30 @@ struct list *find_snapshots(struct logical_volume *lv);
|
||||
|
||||
int vg_add_snapshot(struct logical_volume *origin,
|
||||
struct logical_volume *cow,
|
||||
int persistent,
|
||||
uint32_t chunk_size);
|
||||
int persistent, struct id *id, uint32_t chunk_size);
|
||||
|
||||
int vg_remove_snapshot(struct volume_group *vg, struct logical_volume *cow);
|
||||
|
||||
static inline int validate_vgname(const char *n)
|
||||
{
|
||||
register char c;
|
||||
register int len = 0;
|
||||
|
||||
if (!n || !*n)
|
||||
return 0;
|
||||
|
||||
/* Hyphen used as VG-LV separator - ambiguity if LV starts with it */
|
||||
if (*n == '-')
|
||||
return 0;
|
||||
|
||||
while ((len++, c = *n++))
|
||||
if (!isalnum(c) && c != '.' && c != '_' && c != '-' && c != '+')
|
||||
return 0;
|
||||
|
||||
if (len > NAME_LEN)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -4,8 +4,8 @@
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "pv_map.h"
|
||||
#include "log.h"
|
||||
#include "hash.h"
|
||||
|
||||
#include <assert.h>
|
||||
@ -73,7 +73,7 @@ static int _fill_bitsets(struct volume_group *vg, struct list *maps)
|
||||
struct pv_map *pvm;
|
||||
uint32_t s, pe;
|
||||
struct hash_table *hash;
|
||||
struct stripe_segment *seg;
|
||||
struct lv_segment *seg;
|
||||
int r = 0;
|
||||
|
||||
if (!(hash = hash_create(128))) {
|
||||
@ -95,7 +95,7 @@ static int _fill_bitsets(struct volume_group *vg, struct list *maps)
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct stripe_segment);
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
|
||||
for (s = 0; s < seg->stripes; s++) {
|
||||
for (pe = 0; pe < (seg->len / seg->stripes);
|
||||
@ -142,7 +142,7 @@ static void _insert_area(struct list *head, struct pv_area *a)
|
||||
}
|
||||
|
||||
static int _create_single_area(struct pool *mem, struct pv_map *pvm,
|
||||
uint32_t * extent)
|
||||
uint32_t *extent)
|
||||
{
|
||||
uint32_t e = *extent, b, count = pvm->pv->pe_count;
|
||||
struct pv_area *pva;
|
||||
|
@ -4,7 +4,7 @@
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "log.h"
|
||||
#include "lib.h"
|
||||
#include "metadata.h"
|
||||
#include "toolcontext.h"
|
||||
|
||||
@ -97,7 +97,7 @@ struct list *find_snapshots(struct logical_volume *lv)
|
||||
|
||||
int vg_add_snapshot(struct logical_volume *origin,
|
||||
struct logical_volume *cow,
|
||||
int persistent, uint32_t chunk_size)
|
||||
int persistent, struct id *id, uint32_t chunk_size)
|
||||
{
|
||||
struct snapshot *s;
|
||||
struct snapshot_list *sl;
|
||||
@ -121,12 +121,20 @@ int vg_add_snapshot(struct logical_volume *origin,
|
||||
s->origin = origin;
|
||||
s->cow = cow;
|
||||
|
||||
if (id)
|
||||
s->id = *id;
|
||||
else if (!id_create(&s->id)) {
|
||||
log_error("Snapshot UUID creation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(sl = pool_alloc(mem, sizeof(*sl)))) {
|
||||
stack;
|
||||
pool_free(mem, s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cow->status &= ~VISIBLE_LV;
|
||||
sl->snapshot = s;
|
||||
list_add(&origin->vg->snapshots, &sl->list);
|
||||
|
||||
|
22
make.tmpl.in
22
make.tmpl.in
@ -48,7 +48,7 @@ MAKEFLAGS = @JOBS@
|
||||
endif
|
||||
|
||||
SUFFIXES=
|
||||
SUFFIXES=.c .d .o
|
||||
SUFFIXES=.c .d .o .so
|
||||
|
||||
CFLAGS+=-Wall
|
||||
#CFLAGS+=-O2
|
||||
@ -57,10 +57,13 @@ CFLAGS+=-g -fno-omit-frame-pointer
|
||||
#CFLAGS+=-pg
|
||||
#LD_FLAGS=-pg
|
||||
|
||||
CFLAGS+=-D_REENTRANT -DDEBUG_MEM -DDEBUG -D_GNU_SOURCE
|
||||
CFLAGS+=-DDEBUG_MEM -DDEBUG
|
||||
#CFLAGS+=-DDEBUG_POOL
|
||||
#CFLAGS+=-DBOUNDS_CHECK
|
||||
|
||||
LIB_VERSION := $(shell cat $(top_srcdir)/VERSION | \
|
||||
awk -F '.' '{printf "%s.%s",$$1,$$2}')
|
||||
|
||||
INCLUDES+=-I. -I$(top_srcdir)/include
|
||||
INC_LNS=$(top_srcdir)/include/.symlinks_created
|
||||
|
||||
@ -81,6 +84,10 @@ ifeq ("@HAVE_RL_COMPLETION_MATCHES@", "yes")
|
||||
CFLAGS += -DHAVE_RL_COMPLETION_MATCHES
|
||||
endif
|
||||
|
||||
ifeq ("@LVM1@", "internal")
|
||||
CFLAGS += -DLVM1_INTERNAL
|
||||
endif
|
||||
|
||||
OBJECTS=$(SOURCES:%.c=%.o)
|
||||
|
||||
SUBDIRS.install := $(SUBDIRS:=.install)
|
||||
@ -101,14 +108,21 @@ $(SUBDIRS.install):
|
||||
$(MAKE) -C $(@:.install=) install
|
||||
|
||||
$(SUBDIRS.clean):
|
||||
$(MAKE) -C $(@:.clean=) clean
|
||||
-$(MAKE) -C $(@:.clean=) clean
|
||||
|
||||
$(SUBDIRS.distclean):
|
||||
$(MAKE) -C $(@:.distclean=) distclean
|
||||
-$(MAKE) -C $(@:.distclean=) distclean
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(INCLUDES) $(CFLAGS) $< -o $@
|
||||
|
||||
%.so: %.o
|
||||
$(CC) -c $(INCLUDES) $(CFLAGS) %< -o $@
|
||||
|
||||
%.so: $(OBJECTS)
|
||||
$(CC) -shared -Wl,-soname,$(notdir $@).$(LIB_VERSION) \
|
||||
-Wl,--version-script,.export.sym $(OBJECTS) -o $@
|
||||
|
||||
%.d: %.c
|
||||
set -e; FILE=`echo $@ | sed 's/\\//\\\\\\//g;s/\\.d//g'`; \
|
||||
DEPS=`echo $(DEPS) | sed -e 's/\\//\\\\\\//g'`; \
|
||||
|
@ -23,8 +23,9 @@ VPATH = @srcdir@
|
||||
MAN5=lvm.conf.5
|
||||
MAN8=lvchange.8 lvcreate.8 lvdisplay.8 lvextend.8 lvm.8 lvmchange.8 \
|
||||
lvreduce.8 lvremove.8 lvrename.8 lvscan.8 pvchange.8 \
|
||||
pvcreate.8 pvdisplay.8 pvscan.8 vgcfgbackup.8 vgchange.8 vgck.8 \
|
||||
vgcreate.8 vgdisplay.8 vgextend.8 vgmerge.8 vgreduce.8 vgremove.8 \
|
||||
pvcreate.8 pvdisplay.8 pvremove.8 pvscan.8 vgcfgbackup.8 \
|
||||
vgcfgrestore.8 vgchange.8 vgck.8 vgcreate.8 \
|
||||
vgconvert.8 vgdisplay.8 vgextend.8 vgmerge.8 vgreduce.8 vgremove.8 \
|
||||
vgrename.8 vgscan.8
|
||||
MAN5DIR=${mandir}/man5
|
||||
MAN8DIR=${mandir}/man8
|
||||
|
@ -5,18 +5,17 @@ lvchange \- change attributes of a logical volume
|
||||
.B lvchange
|
||||
[\-A/\-\-autobackup y/n] [\-a/\-\-available y/n]
|
||||
[\-C/\-\-contiguous y/n] [\-d/\-\-debug] [\-h/\-?/\-\-help]
|
||||
[\-\-ignorelockingfailure]
|
||||
[\-M/\-\-persistent y/n] [\-\-minor minor]
|
||||
[\-P/\-\-partial y/n]
|
||||
[\-p/\-\-permission r/w] [\-r/\-\-readahead ReadAheadSectors]
|
||||
[\-t/\-\-test]
|
||||
[\-v/\-\-verbose] LogicalVolumePath [LogicalVolumePath...]
|
||||
.SH DESCRIPTION
|
||||
lvchange allows you to change the attributes of a logical volume.
|
||||
.SH OPTIONS
|
||||
See \fBlvm\fP for common options.
|
||||
.TP
|
||||
.I \-A, \-\-autobackup y/n
|
||||
Controls automatic backup of VG metadata after the change ( see
|
||||
.B vgcfgbackup(8)
|
||||
). Default is yes.
|
||||
.TP
|
||||
.I \-a, \-\-available y/n
|
||||
Controls the availability of the logical volumes for use.
|
||||
This is (among others) useful for changing the logical volume's name
|
||||
@ -25,18 +24,25 @@ This is (among others) useful for changing the logical volume's name
|
||||
) safely.
|
||||
.TP
|
||||
.I \-C, \-\-contiguous y/n
|
||||
Tries to set or resets the contiguous allocation policy for
|
||||
Tries to set or reset the contiguous allocation policy for
|
||||
logical volumes. It's only possible to change a non-contiguous
|
||||
logical volume's allocation policy to contiguous, if all of the
|
||||
allocated physical extents are already contiguous.
|
||||
.TP
|
||||
.I \-\-minor minor
|
||||
Set the minor number.
|
||||
.TP
|
||||
.I \-M, \-\-persistent y/n
|
||||
Set to y to make the minor number specified persistent.
|
||||
.TP
|
||||
.I \-p, \-\-permission r/w
|
||||
Change access permission to read-only or read/write.
|
||||
.TP
|
||||
.I \-r, \-\-readahead ReadAheadSectors
|
||||
Change read ahead sector count per logical between 2 and 120.
|
||||
Not used by device-mapper.
|
||||
.SH Examples
|
||||
"lvchange -x n /dev/vg00/lvol1" prevents the allocation of any physical
|
||||
"lvchange -x n vg00/lvol1" prevents the allocation of any physical
|
||||
extents on logical volume lvol1 in volume group vg00.
|
||||
.SH SEE ALSO
|
||||
.BR lvm (8),
|
||||
|
@ -8,8 +8,10 @@ lvcreate \- create a logical volume in an existing volume group
|
||||
[\-i/\-\-stripes Stripes [\-I/\-\-stripesize StripeSize]]
|
||||
{\-l/\-\-extents LogicalExtentsNumber |
|
||||
\-L/\-\-size LogicalVolumeSize[kKmMgGtT]}
|
||||
[\-M/\-\-persistent y/n] [\-\-minor minor]
|
||||
[\-n/\-\-name LogicalVolumeName]
|
||||
[\-p/\-\-permission r/rw] [\-r/\-\-readahead ReadAheadSectors]
|
||||
[\-t/\-\-test]
|
||||
[\-v/\-\-verbose] [\-Z/\-\-zero y/n]
|
||||
VolumeGroupName [PhysicalVolumePath...]
|
||||
.br
|
||||
@ -37,13 +39,6 @@ keep the contents of the original logical volume for backup purposes.
|
||||
.SH OPTIONS
|
||||
See \fBlvm\fP for common options.
|
||||
.TP
|
||||
.I \-A, \-\-autobackup y/n
|
||||
Controls automatic backup of VG metadata after the change ( see
|
||||
.B vgcfgbackup(8)
|
||||
).
|
||||
.br
|
||||
Default is yes.
|
||||
.TP
|
||||
.I \-c, \-\-chunksize ChunkSize
|
||||
Power of 2 chunk size for the snapshot logical volume between 4k and 1024k.
|
||||
.TP
|
||||
@ -73,6 +68,12 @@ G for gigabytes or T for terabytes is optional.
|
||||
.br
|
||||
Default unit is megabytes.
|
||||
.TP
|
||||
.I \-\-minor minor
|
||||
Set the minor number.
|
||||
.TP
|
||||
.I \-M, \-\-persistent y/n
|
||||
Set to y to make the minor number specified persistent.
|
||||
.TP
|
||||
.I \-n, \-\-name LogicalVolumeName
|
||||
The name for the new logical volume.
|
||||
.br
|
||||
@ -86,6 +87,7 @@ Default is read and write.
|
||||
.TP
|
||||
.I \-r, \-\-readahead ReadAheadSectors
|
||||
Set read ahead sector count of this logical volume to a value between 2 and 120.
|
||||
Ignored by device-mapper.
|
||||
.TP
|
||||
.I \-s, \-\-snapshot
|
||||
Create a snapshot logical volume (or snapshot) for an existing, so called
|
||||
@ -122,7 +124,7 @@ contents of the original logical volume named /dev/vg00/lvol1
|
||||
at snapshot logical volume creation time. If the original logical volume
|
||||
contains a file system, you can mount the snapshot logical volume on an
|
||||
arbitrary directory in order to access the contents of the filesystem to run
|
||||
a backup while the original filesystem is updated.
|
||||
a backup while the original filesystem continues to get updated.
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR lvm (8),
|
||||
|
@ -3,8 +3,10 @@
|
||||
lvdisplay \- display attributes of a logical volume
|
||||
.SH SYNOPSIS
|
||||
.B lvdisplay
|
||||
[\-c/\-\-colon] [\-d/\-\-debug] [\-D/\-\-disk] [\-h/\-?/\-\-help]
|
||||
[\-v[v]/\-\-verbose] LogicalVolumePath [LogicalVolumePath...]
|
||||
[\-c/\-\-colon] [\-d/\-\-debug] [\-h/\-?/\-\-help]
|
||||
[\-\-ignorelockingfailure]
|
||||
[\-\-maps] [\-P/\-\-partial]
|
||||
[\-v/\-\-verbose] LogicalVolumePath [LogicalVolumePath...]
|
||||
.SH DESCRIPTION
|
||||
lvdisplay allows you to see the attributes of a logical volume
|
||||
like size, read/write status, snapshot information etc.
|
||||
@ -12,7 +14,8 @@ like size, read/write status, snapshot information etc.
|
||||
See \fBlvm\fP for common options.
|
||||
.TP
|
||||
.I \-c, \-\-colon
|
||||
Generate colon seperated output for easier parsing in scripts or programs.
|
||||
Deprecated. To be replaced with a more-powerful reporting tool.
|
||||
Generate colon separated output for easier parsing in scripts or programs.
|
||||
.nf
|
||||
|
||||
The values are:
|
||||
@ -33,11 +36,6 @@ The values are:
|
||||
|
||||
.fi
|
||||
.TP
|
||||
.I \-D, \-\-disk
|
||||
Show attributes of the volume group descriptor array on disk(s).
|
||||
Without this switch they are derived from kernel space.
|
||||
Useful, if the volume group isn't active.
|
||||
.TP
|
||||
.I \-m, \-\-maps
|
||||
Display the mapping of logical extents to physical volumes and
|
||||
physical extents.
|
||||
|
@ -4,8 +4,10 @@ lvextend \- extend the size of a logical volume
|
||||
.SH SYNOPSIS
|
||||
.B lvextend
|
||||
[\-A/\-\-autobackup y/n] [\-d/\-\-debug] [\-h/\-?/\-\-help]
|
||||
[\-i/\-\-stripes Stripes [\-I/\-\-stripesize StripeSize]]
|
||||
{\-l/\-\-extents [+]LogicalExtentsNumber |
|
||||
\-L/\-\-size [+]LogicalVolumeSize[kKmMgGtT]}
|
||||
[\-t/\-\-test]
|
||||
[\-v/\-\-verbose] LogicalVolumePath [PhysicalVolumePath...]
|
||||
.SH DESCRIPTION
|
||||
lvextend allows you to extend the size of a logical volume.
|
||||
@ -15,11 +17,6 @@ for information to create snapshots) is supprted as well.
|
||||
.SH OPTIONS
|
||||
See \fBlvm\fP for common options.
|
||||
.TP
|
||||
.I \-A, \-\-autobackup y/n
|
||||
Controls automatic backup of VG metadata after the change ( see
|
||||
.B vgcfgbackup(8)
|
||||
). Default is yes.
|
||||
.TP
|
||||
.I \-l, \-\-extents [+]LogicalExtentsNumber
|
||||
Extend or set the logical volume size in units of logical extents.
|
||||
With the + sign the value is added to the actual size
|
||||
@ -30,6 +27,18 @@ Extend or set the logical volume size in units in units of megabytes.
|
||||
A size suffix of M for megabytes, G for gigabytes or T for terabytes is
|
||||
optional. With the + sign the value is added to the actual size
|
||||
of the logical volume and without it, the value is taken as an absolute one.
|
||||
.TP
|
||||
.I \-i, \-\-stripes Stripes
|
||||
Gives the number of stripes for the extension.
|
||||
Not applicable to PVs using the original metadata LVM format.
|
||||
This is equal to the number of physical volumes to scatter
|
||||
the logical volume.
|
||||
.TP
|
||||
.I \-I, \-\-stripesize StripeSize
|
||||
Gives the number of kilobytes for the granularity of the stripes.
|
||||
Not applicable to PVs using the original metadata LVM format.
|
||||
.br
|
||||
StripeSize must be 2^n (n = 2 to 9)
|
||||
.SH Examples
|
||||
"lvextend -L +54 /dev/vg01/lvol10 /dev/sdk3" tries to extend the size of
|
||||
that logical volume by 54MB on physical volume /dev/sdk3.
|
||||
|
54
man/lvm.8
54
man/lvm.8
@ -25,26 +25,61 @@ A file containing a simple script with one command per line
|
||||
can also be given on the command line. The script can also be
|
||||
executed directly if the first line is #! followed by the absolute
|
||||
path of \fBlvm\fP.
|
||||
.LP
|
||||
Where commands take VG or LV names as arguments, the full path name is
|
||||
optional. An LV called "lvol0" in a VG called "vg0" can be specified
|
||||
as "vg0/lvol0". If a list of VGs is required but is left empty, a list of
|
||||
all VGs will be substituted. If a list of LVs is required
|
||||
but a VG is given, a list of all the LVs in that VG will be substituted.
|
||||
So "lvdisplay vg0" will display all the LVs in "vg0".
|
||||
.SH OPTIONS
|
||||
The following options can be used with every command and are not documented
|
||||
on individual manual pages.
|
||||
The following options are available for many of the commands and are
|
||||
not documented on individual manual pages.
|
||||
.TP
|
||||
\fB-h | --help\fP \(em Display the help text.
|
||||
.TP
|
||||
\fB--version\fP \(em Display the version.
|
||||
Not implemented yet.
|
||||
\fB--version\fP \(em Display version information.
|
||||
.TP
|
||||
\fB-v | --verbose\fP \(em Set verbose level.
|
||||
Repeat from 1 to 3 times to determine the detail of messages
|
||||
Repeat from 1 to 3 times to increase the detail of messages
|
||||
sent to stdout and stderr. Overrides config file setting.
|
||||
.TP
|
||||
\fB-d | --debug\fP \(em Set debug level.
|
||||
Repeat from 1 to 6 times to determine the detail of messages sent
|
||||
Repeat from 1 to 6 times to increase the detail of messages sent
|
||||
to the log file and/or syslog (if configured).
|
||||
Overrides config file setting.
|
||||
.TP
|
||||
\fB--quiet\fP \(em Suppress output and log messages.
|
||||
Overrides -d and -v.
|
||||
.TP
|
||||
\fB-t | --test\fP \(em Run in test mode.
|
||||
Commands will not update metadata.
|
||||
.TP
|
||||
\fB--driverloaded\fP { \fBy\fP | \fBn\fP }
|
||||
Whether or not the device-mapper kernel driver is loaded.
|
||||
If you set this to \fBn\fP, no attempt will be made to contact the driver.
|
||||
.TP
|
||||
\fB-A | --autobackup\fP { \fBy\fP | \fBn\fP }
|
||||
Whether or not to metadata should be backed up automatically after a change.
|
||||
You are strongly advised not to disable this!
|
||||
See
|
||||
.B vgcfgbackup (8).
|
||||
.TP
|
||||
\fB-P | --partial\fP
|
||||
When set, the tools will do their best to provide access to volume groups
|
||||
that are only partially available. Where part of a logical volume is
|
||||
missing, \fB/dev/ioerror\fP will be substituted, and you could use
|
||||
\fBdmsetup (8)\fP to set this up to return I/O errors when accessed,
|
||||
or create it as a large block device of nulls. Metadata may not be
|
||||
changed with this option. To insert a replacement physical volume
|
||||
of the same or large size use \fBpvcreate -u\fP to set the uuid to
|
||||
match the original followed by \fBvgcfgrestore (8)\fP.
|
||||
.TP
|
||||
\fB--ignorelockingfailure\fP
|
||||
This lets you proceed with read-only metadata operations such as
|
||||
\fBlvchange -ay\fP and \fBvgchange -ay\fP even if the locking module fails.
|
||||
One use for this is in a system init script if the lock directory
|
||||
is mounted read-only when the script runs.
|
||||
.SH ENVIRONMENT VARIABLES
|
||||
.TP
|
||||
\fBLVM_SYSTEM_DIR\fP
|
||||
@ -53,14 +88,9 @@ system files.
|
||||
Defaults to "/etc/lvm".
|
||||
.TP
|
||||
\fBHOME\fP
|
||||
Directory containing .lvm_history if the internal shell
|
||||
Directory containing .lvm_history if the internal readline shell
|
||||
is invoked.
|
||||
.TP
|
||||
\fBLVM_AUTOBACKUP\fP
|
||||
Set to "no" to disable automatic metadata
|
||||
backups and archiving. Not recommended.
|
||||
Defaults to "yes".
|
||||
.TP
|
||||
\fBLVM_VG_NAME\fP
|
||||
The volume group name that is assumed for
|
||||
any reference to a logical volume that doesn't specify a path.
|
||||
|
@ -4,6 +4,7 @@ lvmchange \- change attributes of the logical volume manager
|
||||
.SH SYNOPSIS
|
||||
.B lvmchange
|
||||
.SH DESCRIPTION
|
||||
lvmchange is not currently supported under LVM2
|
||||
lvmchange is not currently supported under LVM2, although
|
||||
\fBdmsetup (8)\fP has a \fBremove_all\fP command.
|
||||
.SH SEE ALSO
|
||||
.BR dmsetup (8)
|
||||
|
@ -6,7 +6,8 @@ lvreduce \- reduce the size of a logical volume
|
||||
[\-A/\-\-autobackup y/n] [\-d/\-\-debug] [\-f/\-\-force]
|
||||
[\-h/\-?/\-\-help] {\-l/\-\-extents [\-]LogicalExtentsNumber |
|
||||
\-L/\-\-size [\-]LogicalVolumeSize[kKmMgGtT]}
|
||||
[\-v/\-\-verbose] LogicalVolumePath
|
||||
[\-t/\-\-test]
|
||||
[\-v/\-\-verbose] LogicalVolume[Path]
|
||||
.SH DESCRIPTION
|
||||
lvreduce allows you to reduce the size of a logical volume.
|
||||
Be careful when reducing a logical volume's size, because data in the
|
||||
@ -26,11 +27,6 @@ for information to create snapshots) is supported as well.
|
||||
.SH OPTIONS
|
||||
See \fBlvm\fP for common options.
|
||||
.TP
|
||||
.I \-A, \-\-autobackup y/n
|
||||
Controls automatic backup of VG metadata after the change ( see
|
||||
.B vgcfgbackup(8)
|
||||
). Default is yes.
|
||||
.TP
|
||||
.I \-f, \-\-force
|
||||
Force size reduction without any question.
|
||||
.TP
|
||||
|
@ -4,17 +4,14 @@ lvremove \- remove a logical volume
|
||||
.SH SYNOPSIS
|
||||
.B lvremove
|
||||
[\-A/\-\-autobackup y/n] [\-d/\-\-debug] [\-f/\-\-force]
|
||||
[\-h/\-?/\-\-help] [\-v/\-\-verbose] LogicalVolumePath [LogicalVolumePath...]
|
||||
[\-h/\-?/\-\-help]
|
||||
[\-t/\-\-test]
|
||||
[\-v/\-\-verbose] LogicalVolumePath [LogicalVolumePath...]
|
||||
.SH DESCRIPTION
|
||||
lvremove allows you to remove one or more inactive logical volumes.
|
||||
.SH OPTIONS
|
||||
See \fBlvm\fP for common options.
|
||||
.TP
|
||||
.I \-A, \-\-autobackup y/n
|
||||
Controls automatic backup of VG metadata after the change ( see
|
||||
.B vgcfgbackup(8)
|
||||
). Default is yes.
|
||||
.TP
|
||||
.I \-f, \-\-force
|
||||
Force remove without confirmation.
|
||||
.SH Example
|
||||
|
@ -5,7 +5,9 @@ lvrename \- rename a logical volume
|
||||
.B lvrename
|
||||
.RB [ \-A | \-\-autobackup " {" y | n }]
|
||||
.RB [ \-d | \-\-debug ]
|
||||
.RB [ \-f | \-\-force ]
|
||||
.RB [ \-h | \-\-help ]
|
||||
.RB [ \-t | \-\-test ]
|
||||
.RB [ \-v | \-\-verbose ]
|
||||
.RB [ \-\-version ]
|
||||
.TP
|
||||
@ -20,11 +22,6 @@ to
|
||||
.IR NewLogicalVolume { Name | Path }.
|
||||
.SH OPTIONS
|
||||
See \fBlvm\fP for common options.
|
||||
.TP
|
||||
.BR \-A ", " \-\-autobackup " {" y | n }
|
||||
Controls automatic backup of VG metadata after the change (see
|
||||
.BR vgcfgbackup (8)).
|
||||
Default is yes.
|
||||
.SH EXAMPLE
|
||||
To rename
|
||||
.B lvold
|
||||
|
@ -5,8 +5,9 @@ lvscan \- scan (all disks) for logical volumes
|
||||
.B lvscan
|
||||
.RB [ \-b | \-\-blockdevice ]
|
||||
.RB [ \-d | \-\-debug ]
|
||||
.RB [ \-D | \-\-disk ]
|
||||
.RB [ \-h | \-\-help ]
|
||||
.RB [ \-\-ignorelockingfailure ]
|
||||
.RB [ \-P | \-\-partial ]
|
||||
.RB [ \-v | \-\-verbose ]
|
||||
.SH DESCRIPTION
|
||||
.B lvscan
|
||||
@ -18,10 +19,6 @@ See \fBlvm\fP for common options.
|
||||
.BR \-b ", " \-\-blockdevice
|
||||
Adds the device major and minor numbers to the display
|
||||
of each logical volume.
|
||||
.TP
|
||||
.BR \-D ", " \-\-disk
|
||||
Scan for logical volumes on disk(s) instead of getting the information
|
||||
from the kernel.
|
||||
.SH SEE ALSO
|
||||
.BR lvm (8),
|
||||
.BR lvcreate (8),
|
||||
|
@ -4,6 +4,7 @@ pvchange \- change attributes of a physical volume
|
||||
.SH SYNOPSIS
|
||||
.B pvchange
|
||||
[\-A/\-\-autobackup y/n] [\-d/\-\-debug] [\-h/\-?/\-\-help]
|
||||
[\-t/\-\-test]
|
||||
[\-v/\-\-verbose] [\-a/\-\-all] [\-x/\-\-allocatable y/n] [PhysicalVolumePath...]
|
||||
.SH DESCRIPTION
|
||||
pvchange allows you to change the allocation permissions of one or
|
||||
@ -11,11 +12,6 @@ more physical volumes.
|
||||
.SH OPTIONS
|
||||
See \fBlvm\fP for common options.
|
||||
.TP
|
||||
.I \-A, \-\-autobackup y/n
|
||||
Controls automatic backup of VG metadata after the change ( see
|
||||
.B vgcfgbackup(8)
|
||||
). Default is yes.
|
||||
.TP
|
||||
.I \-a, \-\-all
|
||||
If PhysicalVolumePath is not specified on the command line all
|
||||
physical volumes are searched for and used.
|
||||
|
@ -7,8 +7,15 @@ pvcreate \- initialize a disk or partition for use by LVM
|
||||
.RB [ \-f [ f ]| \-\-force " [" \-\-force ]]
|
||||
.RB [ \-y | \-\-yes ]
|
||||
.RB [ \-h | \-\-help ]
|
||||
.RB [ \-t | \-\-test ]
|
||||
.RB [ \-v | \-\-verbose ]
|
||||
.RB [ \-V | \-\-version ]
|
||||
.RB [ \-\-labelsector ]
|
||||
.RB [ \-M | \-\-metadatatype type ]
|
||||
.RB [ \-\-metadatacopies #copies ]
|
||||
.RB [ \-\-metadatasize size ]
|
||||
.RB [ \-\-restorefile file ]
|
||||
.RB [ \-\-setphysicalvolumesize size ]
|
||||
.RB [ \-\-version ]
|
||||
.IR PhysicalVolume " [" PhysicalVolume ...]
|
||||
.SH DESCRIPTION
|
||||
.B pvcreate
|
||||
@ -17,7 +24,7 @@ initializes
|
||||
for later use by the Logical Volume Manager (LVM). Each
|
||||
.I PhysicalVolume
|
||||
can be a disk partition, whole disk, meta device, or loopback file.
|
||||
For DOS disk partitions, the partition id must be set to 0x8e using
|
||||
For DOS disk partitions, the partition id should be set to 0x8e using
|
||||
.BR fdisk "(8), " cfdisk "(8), "
|
||||
or a equivalent. For
|
||||
.B whole disk devices only
|
||||
@ -47,11 +54,61 @@ In an emergency you can override this behaviour with -ff.
|
||||
Specify the uuid for the device.
|
||||
Without this option, \fBpvcreate\fP generates a random uuid.
|
||||
All of your physical volumes must have unique uuids.
|
||||
You need to use this option to restore a backup of LVM metadata onto
|
||||
a replacement device - see \fBvgcfgrestore\fP(8).
|
||||
You need to use this option before restoring a backup of LVM metadata
|
||||
onto a replacement device - see \fBvgcfgrestore\fP(8).
|
||||
.TP
|
||||
.BR \-y ", " \-\-yes
|
||||
Answer yes to all questions.
|
||||
.SH NEW METADATA OPTIONS
|
||||
LVM2 introduces a new format for storing metadata on disk.
|
||||
This new format is more efficient and resilient than the format the
|
||||
original version of LVM used and offers the advanced user greater
|
||||
flexibility and control.
|
||||
.sp
|
||||
The new format may be selected on the command line with \fB-M2\fP or by
|
||||
setting \fBformat = "lvm2"\fP in the \fBglobal\fP section of \fBlvm.conf\fP.
|
||||
Each physical volume in the same volume group must use the same format, but
|
||||
different volume groups on a machine may use different formats
|
||||
simultaneously: the tools can handle both formats.
|
||||
Additional formats can be added as shared libraries.
|
||||
.sp
|
||||
Additional tools for manipulating the locations and sizes of metadata areas
|
||||
will be written in due course. Use the verbose/debug options on the tools
|
||||
to see where the metadata areas are placed.
|
||||
.TP
|
||||
.BR \-\-metadatasize " size"
|
||||
The approximate amount of space to be set aside for each metadata area.
|
||||
(The size you specify may get rounded.)
|
||||
.TP
|
||||
.BR \-\-metadatacopies " copies"
|
||||
The number of metadata areas to set aside on each PV. Currently
|
||||
this can be 0, 1 or 2.
|
||||
If set to 2 (the default), two copies of the volume group metadata
|
||||
are held on the PV, one at the front of the PV and one at the end.
|
||||
If set to 1, one copy is kept at the front of the PV (starting in the
|
||||
5th sector).
|
||||
If set to 0, no copies are kept on this PV - you might wish to use this
|
||||
with VGs containing large numbers of PVs. But if you do this and
|
||||
then later use \fBvgsplit\fP you must ensure that each VG is still going
|
||||
to have a suitable number of copies of the metadata after the split!
|
||||
.TP
|
||||
.BR \-\-restorefile " file"
|
||||
In conjunction with \fB--uuid\fP, this extracts the location and size
|
||||
of the data on the PV from the file (produced by \fBvgcfgbackup\fP)
|
||||
and ensures that the metadata that the program produces is consistent
|
||||
with the contents of the file i.e. the physical extents will be in
|
||||
the same place and not get overwritten by new metadata. This provides
|
||||
a mechanism to upgrade the metadata format or to add/remove metadata
|
||||
areas. Use with care. See also \fBvgconvert\fP(8).
|
||||
.TP
|
||||
.BR \-\-labelsector " sector"
|
||||
By default the PV is labelled with an LVM2 identifier in its second
|
||||
sector (sector 1). This lets you use a different sector near the
|
||||
start of the disk (between 0 and 3 inclusive - see LABEL_SCAN_SECTORS
|
||||
in the source). Use with care.
|
||||
.TP
|
||||
.BR \-\-setphysicalvolumesize " size"
|
||||
Overrides the automatically-detected size of the PV. Use with care.
|
||||
.SH Example
|
||||
Initialize partition #4 on the third SCSI disk and the entire fifth
|
||||
SCSI disk for later use by LVM:
|
||||
@ -61,4 +118,4 @@ SCSI disk for later use by LVM:
|
||||
.SH SEE ALSO
|
||||
.BR lvm "(8), " vgcreate "(8), " vgextend "(8), " lvcreate "(8), "
|
||||
.BR cfdisk "(8), " fdisk "(8), " losetup "(8), " mdadd "(8), "
|
||||
.BR vgcfgrestore "(8)"
|
||||
.BR vgcfgrestore "(8), " vgconvert "(8)"
|
||||
|
@ -22,7 +22,7 @@ The values are:
|
||||
* physical volume device name
|
||||
* volume group name
|
||||
* physical volume size in kilobytes
|
||||
* internal physical volume number
|
||||
* internal physical volume number (obsolete)
|
||||
* physical volume status
|
||||
* physical volume (not) allocatable
|
||||
* current number of logical volumes on this physical volume
|
||||
|
22
man/pvremove.8
Normal file
22
man/pvremove.8
Normal file
@ -0,0 +1,22 @@
|
||||
.TH PVREMOVE 8 "LVM TOOLS" "Sistina Software UK" \" -*- nroff -*-
|
||||
.SH NAME
|
||||
pvremove \- remove a physical volume
|
||||
.SH SYNOPSIS
|
||||
.B pvremove
|
||||
.RB [ \-d | \-\-debug]
|
||||
.RB [ \-f [ f ]| \-\-force " [" \-\-force ]]
|
||||
.RB [\-h | \-\-help]
|
||||
.RB [ \-t | \-\-test ]
|
||||
.RB [ \-v [ v ]| \-\-verbose " [" \-\-verbose ]]
|
||||
.RB [ \-y | \-\-yes ]
|
||||
.IR PhysicalVolume " [" PhysicalVolume ...]
|
||||
.SH DESCRIPTION
|
||||
.B pvremove
|
||||
wipes the label on a device so that LVM will no longer recognise it
|
||||
as a physical volume.
|
||||
.SH OPTIONS
|
||||
See \fBlvm\fP for common options.
|
||||
.SH SEE ALSO
|
||||
.BR lvm (8),
|
||||
.BR pvcreate (8),
|
||||
.BR pvdisplay (8)
|
@ -6,6 +6,7 @@ pvscan \- scan all disks for physical volumes
|
||||
.RB [ \-d | \-\-debug]
|
||||
.RB [\-e | \-\-exported]
|
||||
.RB [\-h | \-\-help]
|
||||
.RB [\-\-ignorelockingfailure]
|
||||
.RB [ \-n | \-\-novolumegroup]
|
||||
.RB [\-s | \-\-short]
|
||||
.RB [\-u | \-\-uuid]
|
||||
@ -26,7 +27,7 @@ Only show physical volumes not belonging to any volume group.
|
||||
Short listing format.
|
||||
.TP
|
||||
.BR \-u ", " \-\-uuid
|
||||
Show UUIDs (Unifrom Unique Identifiers) in addition to device special names.
|
||||
Show UUIDs (Uniform Unique Identifiers) in addition to device special names.
|
||||
.SH SEE ALSO
|
||||
.BR lvm (8),
|
||||
.BR pvcreate (8),
|
||||
|
@ -4,17 +4,19 @@ vgcfgbackup \- backup volume group descriptor area
|
||||
.SH SYNOPSIS
|
||||
.B vgcfgbackup
|
||||
.RB [ \-d | \-\-debug ]
|
||||
.RB [ \-f | \-\-file " filename" ]
|
||||
.RB [ \-h | \-\-help ]
|
||||
.RB [ \-\-ignorelockingfailure ]
|
||||
.RB [ \-P | \-\-partial ]
|
||||
.RB [ \-v | \-\-verbose ]
|
||||
.RI [ VolumeGroupName ...]
|
||||
.SH DESCRIPTION
|
||||
.B vgcfgbackup
|
||||
allows you to backup the metadata
|
||||
of one to all volume groups to files in
|
||||
.IR /etc/lvm .
|
||||
If you don't give any volume groups in the command line, all of them
|
||||
of your volume groups.
|
||||
If you don't name any volume groups pn the command line, all of them
|
||||
will be backed up. This DOESN'T backup user/system data in logical
|
||||
volume(s)!
|
||||
volume(s)! Backup /etc/lvm regularly too.
|
||||
.SH OPTIONS
|
||||
See \fBlvm\fP for common options.
|
||||
.SH SEE ALSO
|
||||
|
23
man/vgcfgrestore.8
Normal file
23
man/vgcfgrestore.8
Normal file
@ -0,0 +1,23 @@
|
||||
.TH VGCFGRESTORE 8 "LVM TOOLS" "Sistina Software UK" \" -*- nroff -*-
|
||||
.SH NAME
|
||||
vgcfgrestore \- restore volume group descriptor area
|
||||
.SH SYNOPSIS
|
||||
.B vgcfgrestore
|
||||
.RB [ \-d | \-\-debug ]
|
||||
.RB [ \-f | \-\-file " filename" ]
|
||||
.RB [ \-l[l] | \-\-list [--list] ]
|
||||
.RB [ \-h | \-\-help ]
|
||||
.RB [ \-M | \-\-Metadatatype 1|2]
|
||||
.RB [ \-n | \-\-name " VolumeGroupName" ]
|
||||
.RB [ \-t | \-\-test ]
|
||||
.RB [ \-v | \-\-verbose ]
|
||||
.RI [ VolumeGroupName ...]
|
||||
.SH DESCRIPTION
|
||||
.B vgcfgrestore
|
||||
allows you to restore the metadata
|
||||
of your volume groups from a text backup file produced by \fBvgcfgbackup\fP.
|
||||
.SH OPTIONS
|
||||
See \fBlvm\fP for common options.
|
||||
.SH SEE ALSO
|
||||
.BR lvm (8),
|
||||
.BR vgcreate (8)
|
@ -3,14 +3,17 @@
|
||||
vgchange \- change attributes of a volume group
|
||||
.SH SYNOPSIS
|
||||
.B vgchange
|
||||
.RB [ \-A | \-\-autobackup " {" y | n }]
|
||||
.RB [\-A | \-\-autobackup " {" y | n }]
|
||||
.RB [\-a | \-\-available " {" y | n }]
|
||||
.RB [\-d | \-\-debug]
|
||||
.RB [ \-h | \-\-help]
|
||||
.RB [\-h | \-\-help]
|
||||
.RB [\-\-ignorelockingfailure]
|
||||
.RB [\-l | \-\-logicalvolume
|
||||
.IR MaxLogicalVolumes ]
|
||||
.RB [ \-v | \-\-verbose ]
|
||||
.RB [ \-\-version ]
|
||||
.RB [\-P | \-\-partial]
|
||||
.RB [-t | \-\-test]
|
||||
.RB [\-v | \-\-verbose]
|
||||
.RB [\-\-version ]
|
||||
.RB [\-x | \-\-resizeable " {" y | n }]
|
||||
.RI [ VolumeGroupName ...]
|
||||
.SH DESCRIPTION
|
||||
@ -20,12 +23,13 @@ Its main purpose is to activate and deactivate
|
||||
.IR VolumeGroupName ,
|
||||
or all volume groups if none is specified. Only active volume groups
|
||||
are subject to changes and allow access to their logical volumes.
|
||||
During volume group activation, if
|
||||
[Not yet implemented: During volume group activation, if
|
||||
.B vgchange
|
||||
recognizes snapshot logical volumes which were dropped because they ran
|
||||
out of space, it displays a message informing the administrator that such
|
||||
snapshots should be removed (see
|
||||
.BR lvremove (8)).
|
||||
]
|
||||
.SH OPTIONS
|
||||
See \fBlvm\fP for common options.
|
||||
.TP
|
||||
|
38
man/vgconvert.8
Normal file
38
man/vgconvert.8
Normal file
@ -0,0 +1,38 @@
|
||||
.TH VGCONVERT 8 "LVM TOOLS" "Sistina Software UK" \" -*- nroff -*-
|
||||
.SH NAME
|
||||
vgconvert \- convert volume group metadata format
|
||||
.SH SYNOPSIS
|
||||
.B vgconvert
|
||||
.RB [ \-d | \-\-debug ]
|
||||
.RB [ \-h | \-\-help ]
|
||||
.RB [ \-t | \-\-test ]
|
||||
.RB [ \-v | \-\-verbose ]
|
||||
.RB [ \-\-labelsector ]
|
||||
.RB [ \-M | \-\-metadatatype type ]
|
||||
.RB [ \-\-metadatacopies #copies ]
|
||||
.RB [ \-\-metadatasize size ]
|
||||
.RB [ \-\-version ]
|
||||
.IR VolumeGroupName " [" VolumeGroupName ...]
|
||||
.SH DESCRIPTION
|
||||
.B vgconvert
|
||||
converts
|
||||
.I VolumeGroupName
|
||||
metadata from one format to another provided that the metadata
|
||||
fits into the same space.
|
||||
.SH OPTIONS
|
||||
See \fBlvm\fP(8) and \fBpvcreate\fP(8) for options.
|
||||
.SH EXAMPLE
|
||||
Convert volume group vg1 from LVM1 metadata format to the new LVM2
|
||||
metadata format.
|
||||
.sp
|
||||
.B vgconvert -M2 vg1
|
||||
.SH RECOVERY
|
||||
Use \fBpvscan\fP(8) to see which PVs lost their metadata.
|
||||
Run \fBpvcreate\fP(8) with the --uuid and --restorefile options on each
|
||||
such PV to reformat it as it was, using the archive file that
|
||||
\fBvgconvert\fP(8) created at the start of the procedure.
|
||||
Finally run \fBvgcfgrestore\fP(8) with that archive file to restore
|
||||
the original metadata.
|
||||
.SH SEE ALSO
|
||||
.BR lvm "(8), " pvcreate "(8),"
|
||||
.BR vgcfgrestore "(8)"
|
@ -8,10 +8,12 @@ vgcreate \- create a volume group
|
||||
.RB [ \-h | \-\-help ]
|
||||
.RB [ \-l | \-\-maxlogicalvolumes
|
||||
.IR MaxLogicalVolumes ]
|
||||
.RB [ -M | \-\-metadatatype type]
|
||||
.RB [ -p | \-\-maxphysicalvolumes
|
||||
.IR MaxPhysicalVolumes ]
|
||||
.RB [ \-s | \-\-physicalextentsize
|
||||
.IR PhysicalExtentSize [ \fBkKmMgGtT\fR ]]
|
||||
.RB [ \-t | \-\-test ]
|
||||
.RB [ \-v | \-\-verbose ]
|
||||
.RB [ \-\-version ]
|
||||
.I VolumeGroupName PhysicalVolumePath
|
||||
|
@ -6,8 +6,9 @@ vgdisplay \- display attributes of volume groups
|
||||
.RB [ \-A | \-\-activevolumegroups ]
|
||||
.RB [ \-c | \-\-colon ]
|
||||
.RB [ \-d | \-\-debug ]
|
||||
.RB [ \-D | \-\-disk ]
|
||||
.RB [ \-h | \-\-help ]
|
||||
.RB [ \-\-ignorelockingfailure ]
|
||||
.RB [ \-P | \-\-partial ]
|
||||
.RB [ \-s | \-\-short ]
|
||||
.RB [ \-v [ v ]| \-\-verbose " [" \-\-verbose ]]
|
||||
.RB [ \-\-version ]
|
||||
@ -50,11 +51,6 @@ The values are:
|
||||
|
||||
.fi
|
||||
.TP
|
||||
.BR \-D ", " \-\-disk
|
||||
Show attributes from the volume group descriptor area on disk(s).
|
||||
Without this switch they are shown from the kernel.
|
||||
Useful if the volume group isn't activated.
|
||||
.TP
|
||||
.BR \-s ", " \-\-short
|
||||
Give a short listing showing the existence of volume groups.
|
||||
.TP
|
||||
|
@ -3,7 +3,9 @@
|
||||
vgextend \- add physical volumes to a volume group
|
||||
.SH SYNOPSIS
|
||||
.B vgextend
|
||||
[\-A/\-\-autobackup y/n] [\-d/\-\-debug] [\-h/\-?/\-\-help] [\-v/\-\-verbose]
|
||||
[\-A/\-\-autobackup y/n] [\-d/\-\-debug] [\-h/\-?/\-\-help]
|
||||
[\-t/\-\-test]
|
||||
[\-v/\-\-verbose]
|
||||
VolumeGroupName PhysicalDevicePath [PhysicalDevicePath...]
|
||||
.SH DESCRIPTION
|
||||
vgextend allows you to add one or more initialized physical volumes ( see
|
||||
@ -11,11 +13,6 @@ vgextend allows you to add one or more initialized physical volumes ( see
|
||||
) to an existing volume group to extend it in size.
|
||||
.SH OPTIONS
|
||||
See \fBlvm\fP for common options.
|
||||
.TP
|
||||
.I \-A, \-\-autobackup y/n
|
||||
Controls automatic backup of VG metadata after the change ( see
|
||||
.B vgcfgbackup(8)
|
||||
). Default is yes.
|
||||
.SH Examples
|
||||
"vgextend vg00 /dev/sda4 /dev/sdn1" tries to extend the existing volume
|
||||
group "vg00" by the new physical volumes (see
|
||||
|
@ -13,11 +13,6 @@ are equal and physical and logical volume summaries of both volume groups
|
||||
fit into DestinationVolumeGroupName's limits.
|
||||
.SH OPTIONS
|
||||
See \fBlvm\fP for common options.
|
||||
.TP
|
||||
.I \-A, \-\-autobackup y/n
|
||||
Controls automatic backup of VG metadata after the merge ( see
|
||||
.B vgcfgbackup(8)
|
||||
). Default is yes.
|
||||
.I \-l, \-\-list
|
||||
Display merged DestinationVolumeGroupName like "vgdisplay -v".
|
||||
.TP
|
||||
|
@ -4,6 +4,7 @@ vgreduce \- reduce a volume group
|
||||
.SH SYNOPSIS
|
||||
.B vgreduce
|
||||
[\-a/\-\-all] [\-A/\-\-autobackup y/n] [\-d/\-\-debug] [\-h/\-?/\-\-help]
|
||||
[\-t/\-\-test]
|
||||
[\-v/\-\-verbose] VolumeGroupName
|
||||
[PhysicalVolumePath...]
|
||||
.SH DESCRIPTION
|
||||
@ -14,11 +15,6 @@ See \fBlvm\fP for common options.
|
||||
.TP
|
||||
.I \-a, \-\-all
|
||||
Removes all empty physical volumes if none are given on command line.
|
||||
.TP
|
||||
.I \-A, \-\-autobackup y/n
|
||||
Controls automatic backup of VG metadata after the change ( see
|
||||
.B vgcfgbackup(8)
|
||||
). Default is yes.
|
||||
.SH SEE ALSO
|
||||
.BR lvm (8),
|
||||
.BR vgextend (8)
|
||||
|
@ -3,7 +3,7 @@
|
||||
vgremove \- remove a volume group
|
||||
.SH SYNOPSIS
|
||||
.B vgremove
|
||||
[\-d/\-\-debug] [\-h/\-?/\-\-help] [\-v/\-\-verbose]
|
||||
[\-d/\-\-debug] [\-h/\-?/\-\-help] [\-t/\-\-test] [\-v/\-\-verbose]
|
||||
VolumeGroupName [VolumeGroupName...]
|
||||
.SH DESCRIPTION
|
||||
vgremove allows you to remove one or more volume groups.
|
||||
|
@ -6,6 +6,7 @@ vgrename \- rename a volume group
|
||||
[\-A/\-\-autobackup y/n]
|
||||
[\-d/\-\-debug]
|
||||
[\-h/\-?/\-\-help]
|
||||
[\-t/\-\-test]
|
||||
[\-v/\-\-verbose]
|
||||
OldVolumeGroupPath/\-Name NewVolumeGroupPath/\-Name
|
||||
.SH DESCRIPTION
|
||||
@ -14,11 +15,6 @@ vgrename renames an existing (see
|
||||
) volume group.
|
||||
.SH OPTIONS
|
||||
See \fBlvm\fP for common options.
|
||||
.TP
|
||||
.I \-A, \-\-autobackup y/n
|
||||
Controls automatic backup of VG metadata after the change ( see
|
||||
.B vgcfgbackup(8)
|
||||
). Default is yes.
|
||||
.SH Examples
|
||||
"vgrename /dev/vg02 /dev/my_volume_group" renames existing
|
||||
volume group "vg02" to "my_volume_group".
|
||||
|
@ -3,7 +3,10 @@
|
||||
vgscan \- scan all disks for volume groups and rebuild caches
|
||||
.SH SYNOPSIS
|
||||
.B vgscan
|
||||
[\-d/\-\-debug] [\-h/\-?/\-\-help] [\-v/\-\-verbose]
|
||||
[\-d/\-\-debug] [\-h/\-?/\-\-help]
|
||||
[\-\-ignorelockingfailure]
|
||||
[\-P/\-\-partial]
|
||||
[\-v/\-\-verbose]
|
||||
.SH DESCRIPTION
|
||||
vgscan scans all SCSI, (E)IDE disks, multiple devices and a bunch
|
||||
of other disk devices in the system looking for LVM physical volumes
|
||||
|
19
scripts/vg_convert
Executable file
19
scripts/vg_convert
Executable file
@ -0,0 +1,19 @@
|
||||
#!/bin/sh -x
|
||||
|
||||
# Original script used to convert a VG from LVM1 to LVM2 metadata format.
|
||||
# Superceded by 'vgconvert', but left here to show how to do it step-by-step.
|
||||
|
||||
# Takes vgname as parameter. No error checking. Uses temp file 'lvmbackup'.
|
||||
|
||||
echo "Please use the 'vgconvert' tool instead"
|
||||
exit 1
|
||||
|
||||
./vgcfgbackup $1 || exit 1
|
||||
./vgcfgbackup --file lvmbackup $1 || exit 1
|
||||
|
||||
CMDS=`./pvscan -u | sed -ne "s/.*PV \(.*\) with UUID \(.*\) VG $1 .*/.\/pvcreate -ff -y -M lvm2 --restorefile lvmbackup -u \2 \1 ; /p"`
|
||||
|
||||
sh -x -c "$CMDS" || exit 1
|
||||
|
||||
./vgcfgrestore --file lvmbackup -M lvm2 $1 || exit 1
|
||||
|
@ -37,6 +37,7 @@ SOURCES=\
|
||||
pvchange.c \
|
||||
pvcreate.c \
|
||||
pvdisplay.c \
|
||||
pvremove.c \
|
||||
pvscan.c \
|
||||
toollib.c \
|
||||
vgcfgbackup.c \
|
||||
@ -44,6 +45,7 @@ SOURCES=\
|
||||
vgchange.c \
|
||||
vgck.c \
|
||||
vgcreate.c \
|
||||
vgconvert.c \
|
||||
vgdisplay.c \
|
||||
vgexport.c \
|
||||
vgextend.c \
|
||||
|
160
tools/archive.c
160
tools/archive.c
@ -4,18 +4,8 @@
|
||||
* This file is released under the GPL.
|
||||
*/
|
||||
|
||||
#include "log.h"
|
||||
#include "archive.h"
|
||||
#include "dbg_malloc.h"
|
||||
#include "format-text.h"
|
||||
#include "lvm-string.h"
|
||||
#include "toollib.h"
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
|
||||
static struct {
|
||||
int enabled;
|
||||
char *dir;
|
||||
@ -97,7 +87,7 @@ int archive(struct volume_group *vg)
|
||||
return 1;
|
||||
|
||||
if (test_mode()) {
|
||||
log_print("Test mode: Skipping archiving of volume group.");
|
||||
log_verbose("Test mode: Skipping archiving of volume group.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -113,7 +103,7 @@ int archive(struct volume_group *vg)
|
||||
|
||||
int archive_display(struct cmd_context *cmd, const char *vg_name)
|
||||
{
|
||||
return archive_list(cmd, cmd->um, _archive_params.dir, vg_name);
|
||||
return archive_list(cmd, _archive_params.dir, vg_name);
|
||||
}
|
||||
|
||||
static struct {
|
||||
@ -153,11 +143,8 @@ void backup_enable(int flag)
|
||||
|
||||
static int __backup(struct volume_group *vg)
|
||||
{
|
||||
int r;
|
||||
struct format_instance *tf;
|
||||
char name[PATH_MAX];
|
||||
char *desc;
|
||||
void *context;
|
||||
|
||||
if (!(desc = _build_desc(vg->cmd->mem, vg->cmd->cmd_line, 0))) {
|
||||
stack;
|
||||
@ -173,20 +160,7 @@ static int __backup(struct volume_group *vg)
|
||||
|
||||
log_verbose("Creating volume group backup \"%s\"", name);
|
||||
|
||||
if (!(context = create_text_context(vg->cmd->fmtt, name, desc)) ||
|
||||
!(tf = vg->cmd->fmtt->ops->create_instance(vg->cmd->fmtt, NULL,
|
||||
context))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(r = tf->fmt->ops->vg_write(tf, vg, context)) ||
|
||||
!(r = tf->fmt->ops->vg_commit(tf, vg, context)))
|
||||
stack;
|
||||
|
||||
tf->fmt->ops->destroy_instance(tf);
|
||||
|
||||
return r;
|
||||
return backup_to_file(name, desc, vg);
|
||||
}
|
||||
|
||||
int backup(struct volume_group *vg)
|
||||
@ -197,7 +171,7 @@ int backup(struct volume_group *vg)
|
||||
}
|
||||
|
||||
if (test_mode()) {
|
||||
log_print("Test mode: Skipping volume group backup.");
|
||||
log_verbose("Test mode: Skipping volume group backup.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -227,57 +201,73 @@ int backup_remove(const char *vg_name)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct volume_group *_read_vg(struct cmd_context *cmd,
|
||||
const char *vg_name, const char *file)
|
||||
struct volume_group *backup_read_vg(struct cmd_context *cmd,
|
||||
const char *vg_name, const char *file)
|
||||
{
|
||||
struct volume_group *vg;
|
||||
struct format_instance *tf;
|
||||
struct list *mdah;
|
||||
struct metadata_area *mda;
|
||||
void *context;
|
||||
|
||||
if (!(context = create_text_context(cmd->fmtt, file,
|
||||
if (!(context = create_text_context(cmd, file,
|
||||
cmd->cmd_line)) ||
|
||||
!(tf = cmd->fmtt->ops->create_instance(cmd->fmtt, NULL, context))) {
|
||||
!(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
|
||||
context))) {
|
||||
log_error("Couldn't create text format object.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(vg = tf->fmt->ops->vg_read(tf, vg_name, context)))
|
||||
stack;
|
||||
list_iterate(mdah, &tf->metadata_areas) {
|
||||
mda = list_item(mdah, struct metadata_area);
|
||||
if (!(vg = mda->ops->vg_read(tf, vg_name, mda)))
|
||||
stack;
|
||||
break;
|
||||
}
|
||||
|
||||
tf->fmt->ops->destroy_instance(tf);
|
||||
return vg;
|
||||
}
|
||||
|
||||
int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name,
|
||||
const char *file)
|
||||
/* ORPHAN and VG locks held before calling this */
|
||||
int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg)
|
||||
{
|
||||
struct volume_group *vg;
|
||||
struct list *pvh;
|
||||
struct physical_volume *pv;
|
||||
struct cache_info *info;
|
||||
|
||||
/*
|
||||
* Read in the volume group.
|
||||
* FIXME: Check that the PVs referenced in the backup are
|
||||
* not members of other existing VGs.
|
||||
*/
|
||||
if (!(vg = _read_vg(cmd, vg_name, file))) {
|
||||
stack;
|
||||
|
||||
/* Attempt to write out using currently active format */
|
||||
if (!(vg->fid = cmd->fmt->ops->create_instance(cmd->fmt, vg->name,
|
||||
NULL))) {
|
||||
log_error("Failed to allocate format instance");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that those pv's referenced in the backup are
|
||||
* currently orphans or members of the vg.s
|
||||
*/
|
||||
/*
|
||||
* FIXME: waiting for label code.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Write the vg.
|
||||
*/
|
||||
|
||||
/* FIXME How do I find what format to write out the VG in? */
|
||||
/* Must store the format type inside the backup? */
|
||||
if (!(vg->fid = cmd->fmt1->ops->create_instance(cmd->fmt1, NULL, NULL))) {
|
||||
log_error("Failed to allocate format1 instance");
|
||||
return 0;
|
||||
/* Add any metadata areas on the PVs */
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pv = list_item(pvh, struct pv_list)->pv;
|
||||
if (!(info = info_from_pvid(pv->dev->pvid))) {
|
||||
log_error("PV %s missing from cache",
|
||||
dev_name(pv->dev));
|
||||
return 0;
|
||||
}
|
||||
if (cmd->fmt != info->fmt) {
|
||||
log_error("PV %s is a different format (%s)",
|
||||
dev_name(pv->dev), info->fmt->name);
|
||||
return 0;
|
||||
}
|
||||
if (!vg->fid->fmt->ops->
|
||||
pv_setup(vg->fid->fmt, 0, 0, 0, 0, 0,
|
||||
&vg->fid->metadata_areas, pv, vg)) {
|
||||
log_error("Format-specific setup for %s failed",
|
||||
dev_name(pv->dev));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!vg_write(vg)) {
|
||||
@ -288,6 +278,23 @@ int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ORPHAN and VG locks held before calling this */
|
||||
int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name,
|
||||
const char *file)
|
||||
{
|
||||
struct volume_group *vg;
|
||||
|
||||
/*
|
||||
* Read in the volume group from the text file.
|
||||
*/
|
||||
if (!(vg = backup_read_vg(cmd, vg_name, file))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return backup_restore_vg(cmd, vg);
|
||||
}
|
||||
|
||||
int backup_restore(struct cmd_context *cmd, const char *vg_name)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
@ -300,3 +307,38 @@ int backup_restore(struct cmd_context *cmd, const char *vg_name)
|
||||
|
||||
return backup_restore_from_file(cmd, vg_name, path);
|
||||
}
|
||||
|
||||
int backup_to_file(const char *file, const char *desc, struct volume_group *vg)
|
||||
{
|
||||
int r;
|
||||
struct format_instance *tf;
|
||||
struct list *mdah;
|
||||
struct metadata_area *mda;
|
||||
void *context;
|
||||
struct cmd_context *cmd;
|
||||
|
||||
cmd = vg->cmd;
|
||||
|
||||
if (!(context = create_text_context(cmd, file, desc)) ||
|
||||
!(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
|
||||
context))) {
|
||||
log_error("Couldn't create backup object.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Write and commit the metadata area */
|
||||
list_iterate(mdah, &tf->metadata_areas) {
|
||||
mda = list_item(mdah, struct metadata_area);
|
||||
if (!(r = mda->ops->vg_write(tf, vg, mda))) {
|
||||
stack;
|
||||
continue;
|
||||
}
|
||||
if (mda->ops->vg_commit &&
|
||||
!(r = mda->ops->vg_commit(tf, vg, mda))) {
|
||||
stack;
|
||||
}
|
||||
}
|
||||
|
||||
tf->fmt->ops->destroy_instance(tf);
|
||||
return r;
|
||||
}
|
||||
|
@ -42,8 +42,13 @@ void backup_enable(int flag);
|
||||
int backup(struct volume_group *vg);
|
||||
int backup_remove(const char *vg_name);
|
||||
|
||||
struct volume_group *backup_read_vg(struct cmd_context *cmd,
|
||||
const char *vg_name, const char *file);
|
||||
int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg);
|
||||
int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name,
|
||||
const char *file);
|
||||
int backup_restore(struct cmd_context *cmd, const char *vg_name);
|
||||
|
||||
int backup_to_file(const char *file, const char *desc, struct volume_group *vg);
|
||||
|
||||
#endif
|
||||
|
@ -12,6 +12,11 @@ arg(version_ARG, '\0', "version", NULL)
|
||||
arg(quiet_ARG, '\0', "quiet", NULL)
|
||||
arg(physicalvolumesize_ARG, '\0', "setphysicalvolumesize", size_arg)
|
||||
arg(ignorelockingfailure_ARG, '\0', "ignorelockingfailure", NULL)
|
||||
arg(metadatacopies_ARG, '\0', "metadatacopies", int_arg)
|
||||
arg(metadatasize_ARG, '\0', "metadatasize", size_arg)
|
||||
arg(restorefile_ARG, '\0', "restorefile", string_arg)
|
||||
arg(labelsector_ARG, '\0', "labelsector", int_arg)
|
||||
arg(driverloaded_ARG, '\0', "driverloaded", yes_no_arg)
|
||||
|
||||
/* Allow some variations */
|
||||
arg(resizable_ARG, '\0', "resizable", yes_no_arg)
|
||||
@ -77,4 +82,3 @@ arg(zero_ARG, 'Z', "zero", yes_no_arg)
|
||||
|
||||
/* this should always be last */
|
||||
arg(ARG_COUNT, '-', "", NULL)
|
||||
|
||||
|
@ -18,6 +18,21 @@
|
||||
*
|
||||
*/
|
||||
|
||||
/*********** Replace with script?
|
||||
xx(e2fsadm,
|
||||
"Resize logical volume and ext2 filesystem",
|
||||
"e2fsadm "
|
||||
"[-d|--debug] " "[-h|--help] " "[-n|--nofsck]" "\n"
|
||||
"\t{[-l|--extents] [+|-]LogicalExtentsNumber |" "\n"
|
||||
"\t [-L|--size] [+|-]LogicalVolumeSize[kKmMgGtT]}" "\n"
|
||||
"\t[-t|--test] " "\n"
|
||||
"\t[-v|--verbose] " "\n"
|
||||
"\t[--version] " "\n"
|
||||
"\tLogicalVolumePath" "\n",
|
||||
|
||||
extents_ARG, size_ARG, nofsck_ARG, test_ARG)
|
||||
*********/
|
||||
|
||||
xx(help,
|
||||
"Display help for commands",
|
||||
"help <command>" "\n")
|
||||
@ -40,6 +55,7 @@ xx(lvchange,
|
||||
"\t[-C/--contiguous y/n]\n"
|
||||
"\t[-d/--debug]\n"
|
||||
"\t[-h/-?/--help]\n"
|
||||
"\t[--ignorelockingfailure]\n"
|
||||
"\t[-M/--persistent y/n] [--minor minor]\n"
|
||||
"\t[-P/--partial] " "\n"
|
||||
"\t[-p/--permission r/rw]\n"
|
||||
@ -84,14 +100,14 @@ xx(lvdisplay,
|
||||
"lvdisplay\n"
|
||||
"\t[-c/--colon]\n"
|
||||
"\t[-d/--debug]\n"
|
||||
"\t[-D/--disk]\n"
|
||||
"\t[-h/-?/--help]\n"
|
||||
"\t[-m/--maps]\n"
|
||||
"\t[-P/--partial] " "\n"
|
||||
"\t[-v/--verbose]\n"
|
||||
"\tLogicalVolume[Path] [LogicalVolume[Path]...]\n",
|
||||
|
||||
colon_ARG, disk_ARG, maps_ARG, partial_ARG, ignorelockingfailure_ARG)
|
||||
colon_ARG, disk_ARG, maps_ARG, partial_ARG,
|
||||
ignorelockingfailure_ARG)
|
||||
|
||||
xx(lvextend,
|
||||
"Add space to a logical volume",
|
||||
@ -106,8 +122,8 @@ xx(lvextend,
|
||||
"\t[-v/--verbose]\n"
|
||||
"\tLogicalVolume[Path] [ PhysicalVolumePath... ]\n",
|
||||
|
||||
autobackup_ARG, extents_ARG, size_ARG, stripes_ARG, stripesize_ARG,
|
||||
test_ARG)
|
||||
autobackup_ARG, extents_ARG, size_ARG, stripes_ARG,
|
||||
stripesize_ARG, test_ARG)
|
||||
|
||||
xx(lvmchange,
|
||||
"With the device mapper, this is obsolete and does nothing.",
|
||||
@ -212,7 +228,6 @@ xx(lvscan,
|
||||
"lvscan " "\n"
|
||||
"\t[-b|--blockdevice] " "\n"
|
||||
"\t[-d|--debug] " "\n"
|
||||
"\t[-D|--disk]" "\n"
|
||||
"\t[-h|--help] " "\n"
|
||||
"\t[-P|--partial] " "\n"
|
||||
"\t[-v|--verbose] " "\n"
|
||||
@ -237,18 +252,25 @@ xx(pvchange,
|
||||
xx(pvcreate,
|
||||
"Initialize physical volume(s) for use by LVM",
|
||||
"pvcreate " "\n"
|
||||
"\t[--restorefile file]\n"
|
||||
"\t[-d|--debug]" "\n"
|
||||
"\t[-f[f]|--force [--force]] " "\n"
|
||||
"\t[-h|--help] " "\n"
|
||||
"\t[-y|--yes]" "\n"
|
||||
"\t[-s|--size PhysicalVolumeSize[kKmMgGtT]" "\n"
|
||||
"\t[--labelsector sector] " "\n"
|
||||
"\t[-M|--metadatatype 1|2]" "\n"
|
||||
"\t[--metadatacopies #copies]" "\n"
|
||||
"\t[--metadatasize MetadataSize[kKmMgGtT]]" "\n"
|
||||
"\t[--setphysicalvolumesize PhysicalVolumeSize[kKmMgGtT]" "\n"
|
||||
"\t[-t|--test] " "\n"
|
||||
"\t[-u|--uuid uuid] " "\n"
|
||||
"\t[-v|--verbose] " "\n"
|
||||
"\t[-y|--yes]" "\n"
|
||||
"\t[--version] " "\n"
|
||||
"\tPhysicalVolume [PhysicalVolume...]\n",
|
||||
|
||||
force_ARG, test_ARG, physicalvolumesize_ARG, uuidstr_ARG, yes_ARG)
|
||||
force_ARG, test_ARG, labelsector_ARG, metadatatype_ARG, metadatacopies_ARG,
|
||||
metadatasize_ARG, physicalvolumesize_ARG, restorefile_ARG, uuidstr_ARG,
|
||||
yes_ARG)
|
||||
|
||||
xx(pvdata,
|
||||
"Display the on-disk metadata for physical volume(s)",
|
||||
@ -297,9 +319,26 @@ xx(pvmove,
|
||||
|
||||
autobackup_ARG, force_ARG, name_ARG, test_ARG)
|
||||
|
||||
xx(pvremove,
|
||||
"Remove LVM label(s) from physical volume(s)",
|
||||
"pvremove " "\n"
|
||||
"\t[-d|--debug]" "\n"
|
||||
"\t[-f[f]|--force [--force]] " "\n"
|
||||
"\t[-h|--help] " "\n"
|
||||
"\t[-y|--yes]" "\n"
|
||||
"\t[-t|--test] " "\n"
|
||||
"\t[-v|--verbose] " "\n"
|
||||
"\t[-y|--yes]" "\n"
|
||||
"\t[--version] " "\n"
|
||||
"\tPhysicalVolume [PhysicalVolume...]\n",
|
||||
|
||||
force_ARG, test_ARG, yes_ARG)
|
||||
|
||||
xx(pvresize,
|
||||
"Resize a physical volume in use by a volume group",
|
||||
"pvmove "
|
||||
"Not implemented. Use pvcreate options.",
|
||||
/***
|
||||
"pvresize "
|
||||
"[-A|--autobackup {y|n}] "
|
||||
"[-d|--debug] "
|
||||
"[-h|--help]\n\t"
|
||||
@ -307,7 +346,7 @@ xx(pvresize,
|
||||
"[-v|--verbose] "
|
||||
"[--version]\n\t"
|
||||
"\tPhysicalVolumePath [PhysicalVolumePath...]\n",
|
||||
|
||||
***/
|
||||
autobackup_ARG, physicalvolumesize_ARG)
|
||||
|
||||
xx(pvscan,
|
||||
@ -343,6 +382,7 @@ xx(vgcfgrestore,
|
||||
"\t[-d|--debug] " "\n"
|
||||
"\t[-f|--file filename] " "\n"
|
||||
"\t[-l[l]|--list [--list]]" "\n"
|
||||
"\t[-M|--metadatatype 1|2]" "\n"
|
||||
"\t[-n|--name VolumeGroupName] " "\n"
|
||||
"\t[-h|--help]" "\n"
|
||||
"\t[-t|--test] " "\n"
|
||||
@ -350,7 +390,7 @@ xx(vgcfgrestore,
|
||||
"\t[--version] " "\n"
|
||||
"\tVolumeGroupName",
|
||||
|
||||
file_ARG, list_ARG, name_ARG, test_ARG)
|
||||
file_ARG, list_ARG, metadatatype_ARG, name_ARG, test_ARG)
|
||||
|
||||
xx(vgchange,
|
||||
"Change volume group attributes",
|
||||
@ -379,6 +419,23 @@ xx(vgck,
|
||||
"\t[-v/--verbose]\n"
|
||||
"\t[VolumeGroupName...]\n" )
|
||||
|
||||
xx(vgconvert,
|
||||
"Change volume group metadata format",
|
||||
"vgconvert " "\n"
|
||||
"\t[-d|--debug]" "\n"
|
||||
"\t[-h|--help] " "\n"
|
||||
"\t[--labelsector sector] " "\n"
|
||||
"\t[-M|--metadatatype 1|2]" "\n"
|
||||
"\t[--metadatacopies #copies]" "\n"
|
||||
"\t[--metadatasize MetadataSize[kKmMgGtT]]" "\n"
|
||||
"\t[-t|--test] " "\n"
|
||||
"\t[-v|--verbose] " "\n"
|
||||
"\t[--version] " "\n"
|
||||
"\tVolumeGroupName [VolumeGroupName...]\n",
|
||||
|
||||
force_ARG, test_ARG, labelsector_ARG, metadatatype_ARG, metadatacopies_ARG,
|
||||
metadatasize_ARG )
|
||||
|
||||
xx(vgcreate,
|
||||
"Create a volume group",
|
||||
"vgcreate" "\n"
|
||||
@ -386,7 +443,7 @@ xx(vgcreate,
|
||||
"\t[-d|--debug]" "\n"
|
||||
"\t[-h|--help]" "\n"
|
||||
"\t[-l|--maxlogicalvolumes MaxLogicalVolumes]" "\n"
|
||||
"\t[-M|--metadatatype lvm1/text] " "\n"
|
||||
"\t[-M|--metadatatype 1|2] " "\n"
|
||||
"\t[-p|--maxphysicalvolumes MaxPhysicalVolumes] " "\n"
|
||||
"\t[-s|--physicalextentsize PhysicalExtentSize[kKmMgGtT]] " "\n"
|
||||
"\t[-t|--test] " "\n"
|
||||
@ -403,6 +460,7 @@ xx(vgdisplay,
|
||||
"\t[-c|--colon | -s|--short | -v|--verbose]" "\n"
|
||||
"\t[-d|--debug] " "\n"
|
||||
"\t[-h|--help] " "\n"
|
||||
"\t[--ignorelockingfailure]" "\n"
|
||||
"\t[-P|--partial] " "\n"
|
||||
"\t[-A|--activevolumegroups | [-D|--disk]" "\n"
|
||||
"\t[--version]" "\n"
|
||||
@ -499,7 +557,6 @@ xx(vgrename,
|
||||
"vgrename\n"
|
||||
"\t[-A/--autobackup y/n]\n"
|
||||
"\t[-d/--debug]\n"
|
||||
"\t[-f/--force]\n"
|
||||
"\t[-h/-?/--help]\n"
|
||||
"\t[-t/--test]\n"
|
||||
"\t[-v/--verbose]\n"
|
||||
@ -524,7 +581,7 @@ xx(vgsplit,
|
||||
"\t[-d|--debug] " "\n"
|
||||
"\t[-h|--help] " "\n"
|
||||
"\t[-l|--list]" "\n"
|
||||
"\t[-M|--metadatatype lvm1/text] " "\n"
|
||||
"\t[-M|--metadatatype 1|2] " "\n"
|
||||
"\t[-t|--test] " "\n"
|
||||
"\t[-v|--verbose] " "\n"
|
||||
"\t[--version]" "\n"
|
||||
|
221
tools/lvchange.c
221
tools/lvchange.c
@ -20,120 +20,6 @@
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv);
|
||||
static int lvchange_permission(struct cmd_context *cmd,
|
||||
struct logical_volume *lv);
|
||||
static int lvchange_availability(struct cmd_context *cmd,
|
||||
struct logical_volume *lv);
|
||||
static int lvchange_contiguous(struct cmd_context *cmd,
|
||||
struct logical_volume *lv);
|
||||
static int lvchange_readahead(struct cmd_context *cmd,
|
||||
struct logical_volume *lv);
|
||||
static int lvchange_persistent(struct cmd_context *cmd,
|
||||
struct logical_volume *lv);
|
||||
|
||||
int lvchange(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
if (!arg_count(cmd, available_ARG) && !arg_count(cmd, contiguous_ARG)
|
||||
&& !arg_count(cmd, permission_ARG) && !arg_count(cmd, readahead_ARG)
|
||||
&& !arg_count(cmd, minor_ARG) && !arg_count(cmd, persistent_ARG)) {
|
||||
log_error("One or more of -a, -C, -m, -M, -p or -r required");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, ignorelockingfailure_ARG) &&
|
||||
(arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) ||
|
||||
arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG))) {
|
||||
log_error("Only -a permitted with --ignorelockingfailure");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (!argc) {
|
||||
log_error("Please give logical volume path(s)");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, minor_ARG) && argc != 1) {
|
||||
log_error("Only give one logical volume when specifying minor");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (!driver_is_loaded())
|
||||
return ECMD_FAILED;
|
||||
|
||||
return process_each_lv(cmd, argc, argv, LCK_VG_WRITE, &lvchange_single);
|
||||
}
|
||||
|
||||
static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
{
|
||||
int doit = 0;
|
||||
int archived = 0;
|
||||
|
||||
if (!(lv->vg->status & LVM_WRITE) &&
|
||||
(arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) ||
|
||||
arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG))) {
|
||||
log_error("Only -a permitted with read-only volume "
|
||||
"group \"%s\"", lv->vg->name);
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (lv_is_origin(lv) &&
|
||||
(arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) ||
|
||||
arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG))) {
|
||||
log_error("Can't change logical volume \"%s\" under snapshot",
|
||||
lv->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (lv_is_cow(lv)) {
|
||||
log_error("Can't change snapshot logical volume \"%s\"",
|
||||
lv->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
/* access permission change */
|
||||
if (arg_count(cmd, permission_ARG)) {
|
||||
if (!archive(lv->vg))
|
||||
return ECMD_FAILED;
|
||||
archived = 1;
|
||||
doit += lvchange_permission(cmd, lv);
|
||||
}
|
||||
|
||||
/* allocation policy change */
|
||||
if (arg_count(cmd, contiguous_ARG)) {
|
||||
if (!archived && !archive(lv->vg))
|
||||
return ECMD_FAILED;
|
||||
archived = 1;
|
||||
doit += lvchange_contiguous(cmd, lv);
|
||||
}
|
||||
|
||||
/* read ahead sector change */
|
||||
if (arg_count(cmd, readahead_ARG)) {
|
||||
if (!archived && !archive(lv->vg))
|
||||
return ECMD_FAILED;
|
||||
archived = 1;
|
||||
doit += lvchange_readahead(cmd, lv);
|
||||
}
|
||||
|
||||
/* read ahead sector change */
|
||||
if (arg_count(cmd, persistent_ARG)) {
|
||||
if (!archived && !archive(lv->vg))
|
||||
return ECMD_FAILED;
|
||||
archived = 1;
|
||||
doit += lvchange_persistent(cmd, lv);
|
||||
}
|
||||
|
||||
if (doit)
|
||||
log_print("Logical volume \"%s\" changed", lv->name);
|
||||
|
||||
/* availability change */
|
||||
if (arg_count(cmd, available_ARG))
|
||||
if (!lvchange_availability(cmd, lv))
|
||||
return ECMD_FAILED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lvchange_permission(struct cmd_context *cmd,
|
||||
struct logical_volume *lv)
|
||||
{
|
||||
@ -234,7 +120,7 @@ static int lvchange_contiguous(struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
/******** FIXME lv_check_contiguous?
|
||||
if ((lv_allocation & ALLOC_CONTIGUOUS)
|
||||
if (want_contiguous)
|
||||
&& (ret = lv_check_contiguous(vg, lv_index + 1)) == FALSE) {
|
||||
log_error("No contiguous logical volume \"%s\"", lv->name);
|
||||
return 0;
|
||||
@ -245,8 +131,8 @@ static int lvchange_contiguous(struct cmd_context *cmd,
|
||||
log_verbose("Setting contiguous allocation policy for \"%s\"",
|
||||
lv->name);
|
||||
} else {
|
||||
lv->alloc = ALLOC_NEXT_FREE;
|
||||
log_verbose("Removing contiguous allocation policy for \"%s\"",
|
||||
lv->alloc = ALLOC_DEFAULT;
|
||||
log_verbose("Reverting to default allocation policy for \"%s\"",
|
||||
lv->name);
|
||||
}
|
||||
|
||||
@ -371,3 +257,104 @@ static int lvchange_persistent(struct cmd_context *cmd,
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
void *handle)
|
||||
{
|
||||
int doit = 0;
|
||||
int archived = 0;
|
||||
|
||||
if (!(lv->vg->status & LVM_WRITE) &&
|
||||
(arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) ||
|
||||
arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG))) {
|
||||
log_error("Only -a permitted with read-only volume "
|
||||
"group \"%s\"", lv->vg->name);
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (lv_is_origin(lv) &&
|
||||
(arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) ||
|
||||
arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG))) {
|
||||
log_error("Can't change logical volume \"%s\" under snapshot",
|
||||
lv->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (lv_is_cow(lv)) {
|
||||
log_error("Can't change snapshot logical volume \"%s\"",
|
||||
lv->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
/* access permission change */
|
||||
if (arg_count(cmd, permission_ARG)) {
|
||||
if (!archive(lv->vg))
|
||||
return ECMD_FAILED;
|
||||
archived = 1;
|
||||
doit += lvchange_permission(cmd, lv);
|
||||
}
|
||||
|
||||
/* allocation policy change */
|
||||
if (arg_count(cmd, contiguous_ARG)) {
|
||||
if (!archived && !archive(lv->vg))
|
||||
return ECMD_FAILED;
|
||||
archived = 1;
|
||||
doit += lvchange_contiguous(cmd, lv);
|
||||
}
|
||||
|
||||
/* read ahead sector change */
|
||||
if (arg_count(cmd, readahead_ARG)) {
|
||||
if (!archived && !archive(lv->vg))
|
||||
return ECMD_FAILED;
|
||||
archived = 1;
|
||||
doit += lvchange_readahead(cmd, lv);
|
||||
}
|
||||
|
||||
/* read ahead sector change */
|
||||
if (arg_count(cmd, persistent_ARG)) {
|
||||
if (!archived && !archive(lv->vg))
|
||||
return ECMD_FAILED;
|
||||
archived = 1;
|
||||
doit += lvchange_persistent(cmd, lv);
|
||||
}
|
||||
|
||||
if (doit)
|
||||
log_print("Logical volume \"%s\" changed", lv->name);
|
||||
|
||||
/* availability change */
|
||||
if (arg_count(cmd, available_ARG))
|
||||
if (!lvchange_availability(cmd, lv))
|
||||
return ECMD_FAILED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lvchange(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
if (!arg_count(cmd, available_ARG) && !arg_count(cmd, contiguous_ARG)
|
||||
&& !arg_count(cmd, permission_ARG) && !arg_count(cmd, readahead_ARG)
|
||||
&& !arg_count(cmd, minor_ARG) && !arg_count(cmd, persistent_ARG)) {
|
||||
log_error("One or more of -a, -C, -m, -M, -p or -r required");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, ignorelockingfailure_ARG) &&
|
||||
(arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) ||
|
||||
arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG))) {
|
||||
log_error("Only -a permitted with --ignorelockingfailure");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (!argc) {
|
||||
log_error("Please give logical volume path(s)");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, minor_ARG) && argc != 1) {
|
||||
log_error("Only give one logical volume when specifying minor");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
return process_each_lv(cmd, argc, argv, LCK_VG_WRITE, NULL,
|
||||
&lvchange_single);
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ static int _read_name_params(struct lvcreate_params *lp,
|
||||
if (lp->lv_name && strchr(lp->lv_name, '/')) {
|
||||
if (!(lp->vg_name =
|
||||
extract_vgname(cmd, lp->lv_name)))
|
||||
return 0;
|
||||
return 0;
|
||||
|
||||
if (strcmp(lp->vg_name, argv[0])) {
|
||||
log_error("Inconsistent volume group "
|
||||
@ -109,6 +109,13 @@ static int _read_name_params(struct lvcreate_params *lp,
|
||||
if (lp->lv_name && (ptr = strrchr(lp->lv_name, '/')))
|
||||
lp->lv_name = ptr + 1;
|
||||
|
||||
/* FIXME Remove this restriction eventually */
|
||||
if (lp->lv_name && !strncmp(lp->lv_name, "snapshot", 8)) {
|
||||
log_error("Names starting \"snapshot\" are reserved. "
|
||||
"Please choose a different LV name.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -312,20 +319,21 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
|
||||
{
|
||||
uint32_t size_rest;
|
||||
uint32_t status = 0;
|
||||
alloc_policy_t alloc = ALLOC_NEXT_FREE;
|
||||
alloc_policy_t alloc = ALLOC_DEFAULT;
|
||||
struct volume_group *vg;
|
||||
struct logical_volume *lv, *org;
|
||||
struct list *pvh;
|
||||
int consistent = 1;
|
||||
|
||||
if (lp->contiguous)
|
||||
alloc = ALLOC_CONTIGUOUS;
|
||||
|
||||
status |= lp->permission;
|
||||
status |= lp->permission | VISIBLE_LV;
|
||||
|
||||
/* does VG exist? */
|
||||
log_verbose("Finding volume group \"%s\"", lp->vg_name);
|
||||
|
||||
if (!(vg = vg_read(cmd, lp->vg_name))) {
|
||||
if (!(vg = vg_read(cmd, lp->vg_name, &consistent))) {
|
||||
log_error("Volume group \"%s\" doesn't exist", lp->vg_name);
|
||||
return 0;
|
||||
}
|
||||
@ -391,20 +399,30 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
|
||||
lp->extents = lp->extents - size_rest + lp->stripes;
|
||||
}
|
||||
|
||||
if (lp->snapshot && !(org = find_lv(vg, lp->origin))) {
|
||||
log_err("Couldn't find origin volume '%s'.", lp->origin);
|
||||
if (!activation()) {
|
||||
if (lp->snapshot)
|
||||
log_error("Can't create snapshot without using "
|
||||
"device-mapper kernel driver");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* For now all logical volumes are visible.
|
||||
*/
|
||||
status |= VISIBLE_LV;
|
||||
|
||||
if (lp->snapshot) {
|
||||
if (!(org = find_lv(vg, lp->origin))) {
|
||||
log_err("Couldn't find origin volume '%s'.",
|
||||
lp->origin);
|
||||
return 0;
|
||||
}
|
||||
if (lv_is_cow(org)) {
|
||||
log_error("Snapshots of snapshots are not supported "
|
||||
"yet.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(lv = lv_create(vg->fid, lp->lv_name, status, alloc,
|
||||
lp->stripes, lp->stripe_size, lp->extents,
|
||||
vg, pvh))) return 0;
|
||||
vg, pvh)))
|
||||
return 0;
|
||||
|
||||
if (lp->read_ahead) {
|
||||
log_verbose("Setting read ahead sectors");
|
||||
@ -421,16 +439,28 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
|
||||
return 0;
|
||||
|
||||
/* store vg on disk(s) */
|
||||
if (!vg_write(vg))
|
||||
if (!vg_write(vg)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lock_vol(cmd, lv->lvid.s, LCK_LV_ACTIVATE))
|
||||
if (!lock_vol(cmd, lv->lvid.s, LCK_LV_ACTIVATE)) {
|
||||
/* FIXME Remove the failed lv we just added */
|
||||
log_error("Aborting. Failed to wipe snapshot "
|
||||
"exception store. Remove new LV and retry.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lp->zero || lp->snapshot)
|
||||
_zero_lv(cmd, lv);
|
||||
else
|
||||
log_print("WARNING: \"%s\" not zeroed", lv->name);
|
||||
if ((lp->zero || lp->snapshot) && activation()) {
|
||||
if (!_zero_lv(cmd, lv) && lp->snapshot) {
|
||||
/* FIXME Remove the failed lv we just added */
|
||||
log_error("Aborting. Failed to wipe snapshot "
|
||||
"exception store. Remove new LV and retry.");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
log_error("WARNING: \"%s\" not zeroed", lv->name);
|
||||
/* FIXME Remove the failed lv we just added */
|
||||
}
|
||||
|
||||
if (lp->snapshot) {
|
||||
if (!lock_vol(cmd, lv->lvid.s, LCK_LV_DEACTIVATE)) {
|
||||
@ -443,7 +473,7 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!vg_add_snapshot(org, lv, 1, lp->chunk_size)) {
|
||||
if (!vg_add_snapshot(org, lv, 1, NULL, lp->chunk_size)) {
|
||||
log_err("Couldn't create snapshot.");
|
||||
return 0;
|
||||
}
|
||||
@ -480,9 +510,6 @@ int lvcreate(struct cmd_context *cmd, int argc, char **argv)
|
||||
if (!_read_params(&lp, cmd, argc, argv))
|
||||
return -EINVALID_CMD_LINE;
|
||||
|
||||
if (!driver_is_loaded())
|
||||
return ECMD_FAILED;
|
||||
|
||||
if (!lock_vol(cmd, lp.vg_name, LCK_VG_WRITE)) {
|
||||
log_error("Can't get lock for %s", lp.vg_name);
|
||||
return 0;
|
||||
|
@ -20,12 +20,13 @@
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
int lvdisplay_single(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
int lvdisplay_single(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
void *handle)
|
||||
{
|
||||
if (arg_count(cmd, colon_ARG))
|
||||
lvdisplay_colons(lv);
|
||||
else {
|
||||
lvdisplay_full(cmd, lv);
|
||||
lvdisplay_full(cmd, lv, handle);
|
||||
if (arg_count(cmd, maps_ARG))
|
||||
lvdisplay_segments(lv);
|
||||
}
|
||||
@ -42,8 +43,6 @@ int lvdisplay(struct cmd_context *cmd, int argc, char **argv)
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (!driver_is_loaded())
|
||||
return ECMD_FAILED;
|
||||
|
||||
return process_each_lv(cmd, argc, argv, LCK_VG_READ, &lvdisplay_single);
|
||||
return process_each_lv(cmd, argc, argv, LCK_VG_READ, NULL,
|
||||
&lvdisplay_single);
|
||||
}
|
||||
|
969
tools/lvm.c
969
tools/lvm.c
File diff suppressed because it is too large
Load Diff
@ -29,7 +29,7 @@ int lvmdiskscan(struct cmd_context *cmd, int argc, char **argv)
|
||||
uint64_t size;
|
||||
struct dev_iter *iter;
|
||||
struct device *dev;
|
||||
struct physical_volume *pv;
|
||||
struct label *label;
|
||||
|
||||
if (arg_count(cmd, lvmpartition_ARG))
|
||||
log_print("WARNING: only considering LVM devices");
|
||||
@ -44,7 +44,7 @@ int lvmdiskscan(struct cmd_context *cmd, int argc, char **argv)
|
||||
/* Do scan */
|
||||
for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter)) {
|
||||
/* Try if it is a PV first */
|
||||
if ((pv = pv_read(cmd, dev_name(dev)))) {
|
||||
if ((label_read(dev, &label))) {
|
||||
if (!dev_get_size(dev, &size)) {
|
||||
log_error("Couldn't get size of \"%s\"",
|
||||
dev_name(dev));
|
||||
|
@ -20,22 +20,8 @@
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv);
|
||||
|
||||
int lvremove(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
if (!argc) {
|
||||
log_error("Please enter one or more logical volume paths");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (!driver_is_loaded())
|
||||
return ECMD_FAILED;
|
||||
|
||||
return process_each_lv(cmd, argc, argv, LCK_VG_READ, &lvremove_single);
|
||||
}
|
||||
|
||||
static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
void *handle)
|
||||
{
|
||||
struct volume_group *vg;
|
||||
struct dm_info info;
|
||||
@ -95,7 +81,7 @@ static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
}
|
||||
|
||||
/* store it on disks */
|
||||
if (vg_write(vg))
|
||||
if (!vg_write(vg))
|
||||
return ECMD_FAILED;
|
||||
|
||||
backup(vg);
|
||||
@ -103,3 +89,14 @@ static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
log_print("Logical volume \"%s\" successfully removed", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lvremove(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
if (!argc) {
|
||||
log_error("Please enter one or more logical volume paths");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
return process_each_lv(cmd, argc, argv, LCK_VG_READ, NULL,
|
||||
&lvremove_single);
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ int lvrename(struct cmd_context *cmd, int argc, char **argv)
|
||||
char *lv_name_old, *lv_name_new;
|
||||
char *vg_name, *vg_name_new, *vg_name_old;
|
||||
char *st;
|
||||
int consistent = 1;
|
||||
|
||||
struct volume_group *vg;
|
||||
struct logical_volume *lv;
|
||||
@ -53,7 +54,7 @@ int lvrename(struct cmd_context *cmd, int argc, char **argv)
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (!is_valid_chars(vg_name)) {
|
||||
if (!validate_vgname(vg_name)) {
|
||||
log_error("Please provide a valid volume group name");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
@ -86,7 +87,14 @@ int lvrename(struct cmd_context *cmd, int argc, char **argv)
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!is_valid_chars(lv_name_new)) {
|
||||
/* FIXME Remove this restriction eventually */
|
||||
if (!strncmp(lv_name_new, "snapshot", 8)) {
|
||||
log_error("Names starting \"snapshot\" are reserved. "
|
||||
"Please choose a different LV name.");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!validate_vgname(lv_name_new)) {
|
||||
log_error
|
||||
("New logical volume name \"%s\" has invalid characters",
|
||||
lv_name_new);
|
||||
@ -98,9 +106,6 @@ int lvrename(struct cmd_context *cmd, int argc, char **argv)
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (!driver_is_loaded())
|
||||
return ECMD_FAILED;
|
||||
|
||||
log_verbose("Checking for existing volume group \"%s\"", vg_name);
|
||||
|
||||
if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) {
|
||||
@ -108,7 +113,7 @@ int lvrename(struct cmd_context *cmd, int argc, char **argv)
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!(vg = vg_read(cmd, vg_name))) {
|
||||
if (!(vg = vg_read(cmd, vg_name, &consistent))) {
|
||||
log_error("Volume group \"%s\" doesn't exist", vg_name);
|
||||
goto error;
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv)
|
||||
struct list *pvh, *segh;
|
||||
struct lv_list *lvl;
|
||||
int opt = 0;
|
||||
int consistent = 1;
|
||||
|
||||
enum {
|
||||
LV_ANY = 0,
|
||||
@ -94,9 +95,6 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv)
|
||||
if ((st = strrchr(lv_name, '/')))
|
||||
lv_name = st + 1;
|
||||
|
||||
if (!driver_is_loaded())
|
||||
return ECMD_FAILED;
|
||||
|
||||
/* does VG exist? */
|
||||
log_verbose("Finding volume group %s", vg_name);
|
||||
if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) {
|
||||
@ -104,7 +102,7 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv)
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!(vg = vg_read(cmd, vg_name))) {
|
||||
if (!(vg = vg_read(cmd, vg_name, &consistent))) {
|
||||
log_error("Volume group %s doesn't exist", vg_name);
|
||||
goto error;
|
||||
}
|
||||
@ -193,10 +191,10 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv)
|
||||
if (extents > lv->le_count &&
|
||||
!(stripes == 1 || (stripes > 1 && stripesize))) {
|
||||
list_iterate(segh, &lv->segments) {
|
||||
struct stripe_segment *seg;
|
||||
struct lv_segment *seg;
|
||||
uint32_t sz, str;
|
||||
|
||||
seg = list_item(segh, struct stripe_segment);
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
sz = seg->stripe_size;
|
||||
str = seg->stripes;
|
||||
|
||||
@ -237,10 +235,10 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv)
|
||||
"when reducing");
|
||||
|
||||
list_iterate(segh, &lv->segments) {
|
||||
struct stripe_segment *seg;
|
||||
struct lv_segment *seg;
|
||||
uint32_t seg_extents;
|
||||
|
||||
seg = list_item(segh, struct stripe_segment);
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
seg_extents = seg->len;
|
||||
|
||||
seg_stripesize = seg->stripe_size;
|
||||
@ -261,7 +259,7 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv)
|
||||
log_error("Stripesize for striped segment should not be 0!");
|
||||
goto error_cmdline;
|
||||
}
|
||||
|
||||
|
||||
if ((stripes > 1)) {
|
||||
if (!(stripesize_extents = stripesize / vg->extent_size))
|
||||
stripesize_extents = 1;
|
||||
|
@ -20,41 +20,8 @@
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
static int lvscan_single(struct cmd_context *cmd, struct logical_volume *lv);
|
||||
|
||||
int lvscan(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
if (argc) {
|
||||
log_error("No additional command line arguments allowed");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
return process_each_lv(cmd, argc, argv, LCK_VG_READ, &lvscan_single);
|
||||
|
||||
/*********** FIXME Count! Add private struct to process_each*
|
||||
* if (!lv_total)
|
||||
* log_print("no logical volumes found");
|
||||
* else {
|
||||
* log_print
|
||||
* ("%d logical volumes with %s total in %d volume group%s",
|
||||
* lv_total, (dummy =
|
||||
* display_size(lv_capacity_total / 2, SIZE_SHORT)),
|
||||
* vg_total, vg_total == 1 ? "" : "s");
|
||||
* dbg_free(dummy);
|
||||
* dummy = NULL;
|
||||
* if (lv_active > 0)
|
||||
* printf("%d active", lv_active);
|
||||
* if (lv_active > 0 && lv_total - lv_active > 0)
|
||||
* printf(" / ");
|
||||
* if (lv_total - lv_active > 0)
|
||||
* printf("%d inactive", lv_total - lv_active);
|
||||
* printf(" logical volumes\n");
|
||||
* }
|
||||
*************/
|
||||
|
||||
}
|
||||
|
||||
static int lvscan_single(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
static int lvscan_single(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
void *handle)
|
||||
{
|
||||
struct dm_info info;
|
||||
int lv_total = 0;
|
||||
@ -63,7 +30,6 @@ static int lvscan_single(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
char *dummy;
|
||||
const char *active_str, *snapshot_str;
|
||||
|
||||
/* FIXME Add -D arg to skip this! */
|
||||
if (lv_info(lv, &info) && info.exists)
|
||||
active_str = "ACTIVE ";
|
||||
else
|
||||
@ -76,48 +42,28 @@ static int lvscan_single(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
else
|
||||
snapshot_str = " ";
|
||||
|
||||
/********** FIXME Snapshot
|
||||
if (lv->status & SNAPSHOT)
|
||||
dummy =
|
||||
display_size(lv->lv_remap_end *
|
||||
lv->lv_chunk_size / 2,
|
||||
SIZE_SHORT);
|
||||
else
|
||||
***********/
|
||||
dummy = display_size(lv->size / 2, SIZE_SHORT);
|
||||
|
||||
log_print("%s%s '%s%s/%s' [%s]%s", active_str, snapshot_str,
|
||||
log_print("%s%s '%s%s/%s' [%s] %s", active_str, snapshot_str,
|
||||
cmd->dev_dir, lv->vg->name, lv->name, dummy,
|
||||
get_alloc_string(lv->alloc));
|
||||
|
||||
dbg_free(dummy);
|
||||
|
||||
/* FIXME sprintf? */
|
||||
|
||||
/*********** FIXME Handle segments?
|
||||
if (lv->segments[0]->stripes > 1 && !(lv->status & SNAPSHOT))
|
||||
log_print(" striped[%u]", lv->segments[0]->stripes);
|
||||
****************/
|
||||
|
||||
/******** FIXME Device number display & Snapshot
|
||||
if (arg_count(cmd,blockdevice_ARG))
|
||||
printf(" %d:%d",
|
||||
MAJOR(lv->lv_dev),
|
||||
MINOR(lv->lv_dev));
|
||||
else
|
||||
if (lv->status & SNAPSHOT)
|
||||
printf(" of %s", lv->lv_snapshot_org->name);
|
||||
*****************/
|
||||
|
||||
lv_total++;
|
||||
|
||||
/******** FIXME Snapshot
|
||||
if (lv->status & SNAPSHOT)
|
||||
lv_capacity_total +=
|
||||
lv->lv_remap_end * lv->lv_chunk_size
|
||||
else
|
||||
********/
|
||||
lv_capacity_total += lv->size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lvscan(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
if (argc) {
|
||||
log_error("No additional command line arguments allowed");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
return process_each_lv(cmd, argc, argv, LCK_VG_READ, NULL,
|
||||
&lvscan_single);
|
||||
}
|
||||
|
157
tools/pvchange.c
157
tools/pvchange.c
@ -20,76 +20,19 @@
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
int pvchange_single(struct cmd_context *cmd, struct physical_volume *pv);
|
||||
/* FIXME Locking. PVs in VG. */
|
||||
|
||||
int pvchange(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
int opt = 0;
|
||||
int done = 0;
|
||||
int total = 0;
|
||||
|
||||
struct physical_volume *pv;
|
||||
char *pv_name;
|
||||
|
||||
struct list *pvh, *pvs;
|
||||
|
||||
if (arg_count(cmd, allocatable_ARG) == 0) {
|
||||
log_error("Please give the x option");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (!(arg_count(cmd, all_ARG)) && !argc) {
|
||||
log_error("Please give a physical volume path");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, all_ARG) && argc) {
|
||||
log_error("Option a and PhysicalVolumePath are exclusive");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (argc) {
|
||||
log_verbose("Using physical volume(s) on command line");
|
||||
for (; opt < argc; opt++) {
|
||||
pv_name = argv[opt];
|
||||
if (!(pv = pv_read(cmd, pv_name))) {
|
||||
log_error
|
||||
("Failed to read physical volume \"%s\"",
|
||||
pv_name);
|
||||
continue;
|
||||
}
|
||||
total++;
|
||||
done += pvchange_single(cmd, pv);
|
||||
}
|
||||
} else {
|
||||
log_verbose("Scanning for physical volume names");
|
||||
if (!(pvs = get_pvs(cmd))) {
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
list_iterate(pvh, pvs) {
|
||||
total++;
|
||||
done += pvchange_single(cmd,
|
||||
list_item(pvh,
|
||||
struct pv_list)->pv);
|
||||
}
|
||||
}
|
||||
|
||||
log_print("%d physical volume%s changed / %d physical volume%s "
|
||||
"not changed",
|
||||
done, done > 1 ? "s" : "",
|
||||
total - done, total - done > 1 ? "s" : "");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pvchange_single(struct cmd_context *cmd, struct physical_volume *pv)
|
||||
int pvchange_single(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
void *handle)
|
||||
{
|
||||
struct volume_group *vg = NULL;
|
||||
struct pv_list *pvl;
|
||||
struct list mdas;
|
||||
uint64_t sector;
|
||||
|
||||
const char *pv_name = dev_name(pv->dev);
|
||||
|
||||
int consistent = 1;
|
||||
int allocatable =
|
||||
!strcmp(arg_str_value(cmd, allocatable_ARG, "n"), "y");
|
||||
|
||||
@ -103,7 +46,7 @@ int pvchange_single(struct cmd_context *cmd, struct physical_volume *pv)
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!(vg = vg_read(cmd, pv->vg_name))) {
|
||||
if (!(vg = vg_read(cmd, pv->vg_name, &consistent))) {
|
||||
unlock_vg(cmd, pv->vg_name);
|
||||
log_error("Unable to find volume group of \"%s\"",
|
||||
pv_name);
|
||||
@ -132,6 +75,18 @@ int pvchange_single(struct cmd_context *cmd, struct physical_volume *pv)
|
||||
pv = pvl->pv;
|
||||
if (!archive(vg))
|
||||
return 0;
|
||||
} else {
|
||||
if (!lock_vol(cmd, ORPHAN, LCK_VG_WRITE)) {
|
||||
log_error("Can't get lock for orphans");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!(pv = pv_read(cmd, pv_name, &mdas, §or))) {
|
||||
unlock_vg(cmd, ORPHAN);
|
||||
log_error("Unable to read PV \"%s\"", pv_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* change allocatability for a PV */
|
||||
@ -140,6 +95,8 @@ int pvchange_single(struct cmd_context *cmd, struct physical_volume *pv)
|
||||
pv_name);
|
||||
if (*pv->vg_name)
|
||||
unlock_vg(cmd, pv->vg_name);
|
||||
else
|
||||
unlock_vg(cmd, ORPHAN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -148,6 +105,8 @@ int pvchange_single(struct cmd_context *cmd, struct physical_volume *pv)
|
||||
pv_name);
|
||||
if (*pv->vg_name)
|
||||
unlock_vg(cmd, pv->vg_name);
|
||||
else
|
||||
unlock_vg(cmd, ORPHAN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -172,14 +131,82 @@ int pvchange_single(struct cmd_context *cmd, struct physical_volume *pv)
|
||||
backup(vg);
|
||||
unlock_vg(cmd, pv->vg_name);
|
||||
} else {
|
||||
if (!(pv_write(cmd, pv))) {
|
||||
if (!(pv_write(cmd, pv, &mdas, sector))) {
|
||||
unlock_vg(cmd, ORPHAN);
|
||||
log_error("Failed to store physical volume \"%s\"",
|
||||
pv_name);
|
||||
return 0;
|
||||
}
|
||||
unlock_vg(cmd, ORPHAN);
|
||||
}
|
||||
|
||||
log_print("Physical volume \"%s\" changed", pv_name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int pvchange(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
int opt = 0;
|
||||
int done = 0;
|
||||
int total = 0;
|
||||
|
||||
struct physical_volume *pv;
|
||||
char *pv_name;
|
||||
|
||||
struct list *pvh, *pvs;
|
||||
struct list mdas;
|
||||
|
||||
list_init(&mdas);
|
||||
|
||||
if (arg_count(cmd, allocatable_ARG) == 0) {
|
||||
log_error("Please give the x option");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (!(arg_count(cmd, all_ARG)) && !argc) {
|
||||
log_error("Please give a physical volume path");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, all_ARG) && argc) {
|
||||
log_error("Option a and PhysicalVolumePath are exclusive");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (argc) {
|
||||
log_verbose("Using physical volume(s) on command line");
|
||||
for (; opt < argc; opt++) {
|
||||
pv_name = argv[opt];
|
||||
/* FIXME Read VG instead - pv_read will fail */
|
||||
if (!(pv = pv_read(cmd, pv_name, &mdas, NULL))) {
|
||||
log_error
|
||||
("Failed to read physical volume \"%s\"",
|
||||
pv_name);
|
||||
continue;
|
||||
}
|
||||
total++;
|
||||
done += pvchange_single(cmd, pv, NULL);
|
||||
}
|
||||
} else {
|
||||
log_verbose("Scanning for physical volume names");
|
||||
if (!(pvs = get_pvs(cmd))) {
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
list_iterate(pvh, pvs) {
|
||||
total++;
|
||||
done += pvchange_single(cmd,
|
||||
list_item(pvh,
|
||||
struct pv_list)->pv,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
log_print("%d physical volume%s changed / %d physical volume%s "
|
||||
"not changed",
|
||||
done, done > 1 ? "s" : "",
|
||||
total - done, total - done > 1 ? "s" : "");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
117
tools/pvcreate.c
117
tools/pvcreate.c
@ -19,6 +19,7 @@
|
||||
*/
|
||||
|
||||
#include "tools.h"
|
||||
#include "defaults.h"
|
||||
|
||||
const char _really_init[] =
|
||||
"Really INITIALIZE physical volume \"%s\" of volume group \"%s\" [y/n]? ";
|
||||
@ -39,7 +40,7 @@ static int pvcreate_check(struct cmd_context *cmd, const char *name)
|
||||
}
|
||||
|
||||
/* is there a pv here already */
|
||||
if (!(pv = pv_read(cmd, name)))
|
||||
if (!(pv = pv_read(cmd, name, NULL, NULL)))
|
||||
return 1;
|
||||
|
||||
/* orphan ? */
|
||||
@ -72,20 +73,28 @@ static int pvcreate_check(struct cmd_context *cmd, const char *name)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void pvcreate_single(struct cmd_context *cmd, const char *pv_name)
|
||||
static void pvcreate_single(struct cmd_context *cmd, const char *pv_name,
|
||||
void *handle)
|
||||
{
|
||||
struct physical_volume *pv;
|
||||
struct format_instance *fid;
|
||||
struct physical_volume *pv, *existing_pv;
|
||||
struct id id, *idp = NULL;
|
||||
char *uuid;
|
||||
uint64_t size = 0;
|
||||
struct device *dev;
|
||||
struct list mdas;
|
||||
int pvmetadatacopies;
|
||||
uint64_t pvmetadatasize;
|
||||
struct volume_group *vg;
|
||||
char *restorefile;
|
||||
uint64_t pe_start = 0;
|
||||
uint32_t extent_count = 0, extent_size = 0;
|
||||
|
||||
if (arg_count(cmd, uuidstr_ARG)) {
|
||||
uuid = arg_str_value(cmd, uuidstr_ARG, "");
|
||||
if (!id_read_format(&id, uuid))
|
||||
return;
|
||||
if ((dev = uuid_map_lookup(cmd->um, &id))) {
|
||||
if ((dev = device_from_pvid(cmd, &id)) &&
|
||||
(dev != dev_cache_get(pv_name, cmd->filter))) {
|
||||
log_error("uuid %s already in use on \"%s\"", uuid,
|
||||
dev_name(dev));
|
||||
return;
|
||||
@ -93,32 +102,84 @@ static void pvcreate_single(struct cmd_context *cmd, const char *pv_name)
|
||||
idp = &id;
|
||||
}
|
||||
|
||||
if (!pvcreate_check(cmd, pv_name))
|
||||
if (arg_count(cmd, restorefile_ARG)) {
|
||||
restorefile = arg_str_value(cmd, restorefile_ARG, "");
|
||||
/* The uuid won't already exist */
|
||||
init_partial(1);
|
||||
if (!(vg = backup_read_vg(cmd, NULL, restorefile))) {
|
||||
log_error("Unable to read volume group from %s",
|
||||
restorefile);
|
||||
return;
|
||||
}
|
||||
init_partial(0);
|
||||
if (!(existing_pv = find_pv_in_vg_by_uuid(vg, idp))) {
|
||||
log_error("Can't find uuid %s in backup file %s",
|
||||
uuid, restorefile);
|
||||
return;
|
||||
}
|
||||
pe_start = existing_pv->pe_start;
|
||||
extent_size = existing_pv->pe_size;
|
||||
extent_count = existing_pv->pe_count;
|
||||
}
|
||||
|
||||
if (!lock_vol(cmd, "", LCK_VG_WRITE)) {
|
||||
log_error("Can't get lock for orphan PVs");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pvcreate_check(cmd, pv_name))
|
||||
goto error;
|
||||
|
||||
size = arg_int64_value(cmd, physicalvolumesize_ARG, 0) * 2;
|
||||
|
||||
/* FIXME Use config file/cmd line to specify format */
|
||||
if (!(fid = cmd->fmt1->ops->create_instance(cmd->fmt1, NULL, NULL))) {
|
||||
log_error("Failed to create format1 instance");
|
||||
return;
|
||||
pvmetadatasize = arg_int64_value(cmd, metadatasize_ARG, 0) * 2;
|
||||
if (!pvmetadatasize)
|
||||
pvmetadatasize = find_config_int(cmd->cf->root,
|
||||
"metadata/pvmetadatasize",
|
||||
'/', DEFAULT_PVMETADATASIZE);
|
||||
|
||||
pvmetadatacopies = arg_int_value(cmd, metadatacopies_ARG, -1);
|
||||
if (pvmetadatacopies < 0)
|
||||
pvmetadatacopies = find_config_int(cmd->cf->root,
|
||||
"metadata/pvmetadatacopies",
|
||||
'/',
|
||||
DEFAULT_PVMETADATACOPIES);
|
||||
|
||||
if (!(dev = dev_cache_get(pv_name, cmd->filter))) {
|
||||
log_error("%s: Couldn't find device.", pv_name);
|
||||
goto error;
|
||||
}
|
||||
if (!(pv = pv_create(fid, pv_name, idp, size))) {
|
||||
|
||||
list_init(&mdas);
|
||||
if (!(pv = pv_create(cmd->fmt, dev, idp, size, pe_start,
|
||||
extent_count, extent_size,
|
||||
pvmetadatacopies, pvmetadatasize, &mdas))) {
|
||||
log_error("Failed to setup physical volume \"%s\"", pv_name);
|
||||
return;
|
||||
goto error;
|
||||
}
|
||||
|
||||
log_verbose("Set up physical volume for \"%s\" with %" PRIu64
|
||||
" sectors", pv_name, pv->size);
|
||||
" available sectors", pv_name, pv->size);
|
||||
|
||||
/* Wipe existing label first */
|
||||
if (!label_remove(pv->dev)) {
|
||||
log_error("Failed to wipe existing label on %s", pv_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
log_very_verbose("Writing physical volume data to disk \"%s\"",
|
||||
pv_name);
|
||||
if (!(pv_write(cmd, pv))) {
|
||||
if (!(pv_write(cmd, pv, &mdas, arg_int_value(cmd, labelsector_ARG,
|
||||
DEFAULT_LABELSECTOR)))) {
|
||||
log_error("Failed to write physical volume \"%s\"", pv_name);
|
||||
return;
|
||||
goto error;
|
||||
}
|
||||
|
||||
log_print("Physical volume \"%s\" successfully created", pv_name);
|
||||
|
||||
error:
|
||||
unlock_vg(cmd, "");
|
||||
return;
|
||||
}
|
||||
|
||||
int pvcreate(struct cmd_context *cmd, int argc, char **argv)
|
||||
@ -130,6 +191,11 @@ int pvcreate(struct cmd_context *cmd, int argc, char **argv)
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, restorefile_ARG) && !arg_count(cmd, uuidstr_ARG)) {
|
||||
log_error("--uuid is required with --restorefile");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, uuidstr_ARG) && argc != 1) {
|
||||
log_error("Can only set uuid on one volume at once");
|
||||
return EINVALID_CMD_LINE;
|
||||
@ -140,8 +206,27 @@ int pvcreate(struct cmd_context *cmd, int argc, char **argv)
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (arg_int_value(cmd, labelsector_ARG, 0) >= LABEL_SCAN_SECTORS) {
|
||||
log_error("labelsector must be less than %lu",
|
||||
LABEL_SCAN_SECTORS);
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (!(cmd->fmt->features & FMT_MDAS) &&
|
||||
(arg_count(cmd, metadatacopies_ARG) ||
|
||||
arg_count(cmd, metadatasize_ARG))) {
|
||||
log_error("Metadata parameters only apply to text format");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, metadatacopies_ARG) &&
|
||||
arg_int_value(cmd, metadatacopies_ARG, -1) > 2) {
|
||||
log_error("Metadatacopies may only be 0, 1 or 2");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
pvcreate_single(cmd, argv[i]);
|
||||
pvcreate_single(cmd, argv[i], NULL);
|
||||
pool_empty(cmd->mem);
|
||||
}
|
||||
|
||||
|
@ -20,44 +20,8 @@
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
void pvdisplay_single(struct cmd_context *cmd, struct physical_volume *pv);
|
||||
|
||||
int pvdisplay(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
int opt = 0;
|
||||
|
||||
struct list *pvh, *pvs;
|
||||
struct physical_volume *pv;
|
||||
|
||||
if (arg_count(cmd, colon_ARG) && arg_count(cmd, maps_ARG)) {
|
||||
log_error("Option -v not allowed with option -c");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (argc) {
|
||||
log_very_verbose("Using physical volume(s) on command line");
|
||||
|
||||
for (; opt < argc; opt++) {
|
||||
if (!(pv = pv_read(cmd, argv[opt]))) {
|
||||
log_error("Failed to read physical "
|
||||
"volume \"%s\"", argv[opt]);
|
||||
continue;
|
||||
}
|
||||
pvdisplay_single(cmd, pv);
|
||||
}
|
||||
} else {
|
||||
log_verbose("Scanning for physical volume names");
|
||||
if (!(pvs = get_pvs(cmd)))
|
||||
return ECMD_FAILED;
|
||||
|
||||
list_iterate(pvh, pvs)
|
||||
pvdisplay_single(cmd, list_item(pvh, struct pv_list)->pv);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pvdisplay_single(struct cmd_context *cmd, struct physical_volume *pv)
|
||||
void pvdisplay_single(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
void *handle)
|
||||
{
|
||||
char *sz;
|
||||
uint64_t size;
|
||||
@ -80,50 +44,57 @@ void pvdisplay_single(struct cmd_context *cmd, struct physical_volume *pv)
|
||||
log_print("Physical volume \"%s\" of volume group \"%s\" "
|
||||
"is exported", pv_name, pv->vg_name);
|
||||
|
||||
/********* FIXME
|
||||
log_error("no physical volume identifier on \"%s\"" , pv_name);
|
||||
*********/
|
||||
|
||||
if (!pv->vg_name) {
|
||||
log_print("\"%s\" is a new physical volume of \"%s\"",
|
||||
pv_name, (sz = display_size(size / 2, SIZE_SHORT)));
|
||||
dbg_free(sz);
|
||||
}
|
||||
|
||||
/* FIXME: Check active - no point?
|
||||
log_very_verbose("checking physical volume activity" );
|
||||
pv_check_active ( pv->vg_name, pv->pv_name)
|
||||
pv_status ( pv->vg_name, pv->pv_name, &pv)
|
||||
*/
|
||||
|
||||
/* FIXME: Check consistency - do this when reading metadata BUT trigger mesgs
|
||||
log_very_verbose("checking physical volume consistency" );
|
||||
ret = pv_check_consistency (pv)
|
||||
*/
|
||||
|
||||
if (arg_count(cmd, colon_ARG)) {
|
||||
pvdisplay_colons(pv);
|
||||
return;
|
||||
}
|
||||
|
||||
pvdisplay_full(pv);
|
||||
pvdisplay_full(pv, handle);
|
||||
|
||||
if (!arg_count(cmd, maps_ARG))
|
||||
return;
|
||||
|
||||
/******* FIXME
|
||||
if (pv->pe_alloc_count) {
|
||||
if (!(pv->pe = pv_read_pe(pv_name, pv)))
|
||||
goto pvdisplay_device_out;
|
||||
if (!(lvs = pv_read_lvs(pv))) {
|
||||
log_error("Failed to read LVs on \"%s\"", pv->pv_name);
|
||||
goto pvdisplay_device_out;
|
||||
}
|
||||
pv_display_pe_text(pv, pv->pe, lvs);
|
||||
} else
|
||||
log_print("no logical volume on physical volume \"%s\"",
|
||||
pv_name);
|
||||
**********/
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int pvdisplay(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
int opt = 0;
|
||||
|
||||
struct list *pvh, *pvs;
|
||||
struct physical_volume *pv;
|
||||
|
||||
if (arg_count(cmd, colon_ARG) && arg_count(cmd, maps_ARG)) {
|
||||
log_error("Option -v not allowed with option -c");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (argc) {
|
||||
log_very_verbose("Using physical volume(s) on command line");
|
||||
|
||||
for (; opt < argc; opt++) {
|
||||
if (!(pv = pv_read(cmd, argv[opt], NULL, NULL))) {
|
||||
log_error("Failed to read physical "
|
||||
"volume \"%s\"", argv[opt]);
|
||||
continue;
|
||||
}
|
||||
pvdisplay_single(cmd, pv, NULL);
|
||||
}
|
||||
} else {
|
||||
log_verbose("Scanning for physical volume names");
|
||||
if (!(pvs = get_pvs(cmd)))
|
||||
return ECMD_FAILED;
|
||||
|
||||
list_iterate(pvh, pvs)
|
||||
pvdisplay_single(cmd, list_item(pvh, struct pv_list)->pv,
|
||||
NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
128
tools/pvremove.c
Normal file
128
tools/pvremove.c
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Sistina Software
|
||||
*
|
||||
* pvcreate 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, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* pvcreate 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 LVM; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "tools.h"
|
||||
#include "defaults.h"
|
||||
|
||||
const char _really_wipe[] =
|
||||
"Really WIPE LABELS from physical volume \"%s\" of volume group \"%s\" [y/n]? ";
|
||||
|
||||
/*
|
||||
* Decide whether it is "safe" to wipe the labels on this device.
|
||||
* 0 indicates we may not.
|
||||
*/
|
||||
static int pvremove_check(struct cmd_context *cmd, const char *name)
|
||||
{
|
||||
struct physical_volume *pv;
|
||||
|
||||
/* is the partition type set correctly ? */
|
||||
if ((arg_count(cmd, force_ARG) < 1) && !is_lvm_partition(name)) {
|
||||
log_error("%s: Not LVM partition type: use -f to override",
|
||||
name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* is there a pv here already */
|
||||
if (!(pv = pv_read(cmd, name, NULL, NULL)))
|
||||
return 1;
|
||||
|
||||
/* orphan ? */
|
||||
if (!pv->vg_name[0])
|
||||
return 1;
|
||||
|
||||
/* Allow partial & exported VGs to be destroyed. */
|
||||
/* we must have -ff to overwrite a non orphan */
|
||||
if (arg_count(cmd, force_ARG) < 2) {
|
||||
log_error("Can't pvremove physical volume \"%s\" of "
|
||||
"volume group \"%s\" without -ff", name, pv->vg_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* prompt */
|
||||
if (!arg_count(cmd, yes_ARG) &&
|
||||
yes_no_prompt(_really_wipe, name, pv->vg_name) == 'n') {
|
||||
log_print("%s: physical volume label not removed", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, force_ARG)) {
|
||||
log_print("WARNING: Wiping physical volume label from "
|
||||
"%s%s%s%s", name,
|
||||
pv->vg_name[0] ? " of volume group \"" : "",
|
||||
pv->vg_name[0] ? pv->vg_name : "",
|
||||
pv->vg_name[0] ? "\"" : "");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void pvremove_single(struct cmd_context *cmd, const char *pv_name,
|
||||
void *handle)
|
||||
{
|
||||
struct device *dev;
|
||||
|
||||
if (!lock_vol(cmd, "", LCK_VG_WRITE)) {
|
||||
log_error("Can't get lock for orphan PVs");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pvremove_check(cmd, pv_name))
|
||||
goto error;
|
||||
|
||||
if (!(dev = dev_cache_get(pv_name, cmd->filter))) {
|
||||
log_error("%s: Couldn't find device.", pv_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Wipe existing label(s) */
|
||||
if (!label_remove(dev)) {
|
||||
log_error("Failed to wipe existing label(s) on %s", pv_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
log_print("Labels on physical volume \"%s\" successfully wiped",
|
||||
pv_name);
|
||||
|
||||
error:
|
||||
unlock_vg(cmd, "");
|
||||
return;
|
||||
}
|
||||
|
||||
int pvremove(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!argc) {
|
||||
log_error("Please enter a physical volume path");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, yes_ARG) && !arg_count(cmd, force_ARG)) {
|
||||
log_error("Option y can only be given with option f");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
pvremove_single(cmd, argv[i], NULL);
|
||||
pool_empty(cmd->mem);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
178
tools/pvscan.c
178
tools/pvscan.c
@ -20,11 +20,95 @@
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
void pvscan_display_single(struct cmd_context *cmd, struct physical_volume *pv);
|
||||
|
||||
int pv_max_name_len = 0;
|
||||
int vg_max_name_len = 0;
|
||||
|
||||
void pvscan_display_single(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
void *handle)
|
||||
{
|
||||
char uuid[64];
|
||||
int vg_name_len = 0;
|
||||
|
||||
char *s1, *s2;
|
||||
|
||||
char pv_tmp_name[NAME_LEN] = { 0, };
|
||||
char vg_tmp_name[NAME_LEN] = { 0, };
|
||||
char vg_name_this[NAME_LEN] = { 0, };
|
||||
|
||||
/* short listing? */
|
||||
if (arg_count(cmd, short_ARG) > 0) {
|
||||
log_print("%s", dev_name(pv->dev));
|
||||
return;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, verbose_ARG) > 1) {
|
||||
/* FIXME As per pv_display! Drop through for now. */
|
||||
/* pv_show(pv); */
|
||||
|
||||
/* FIXME - Moved to Volume Group structure */
|
||||
/* log_print("System Id %s", pv->vg->system_id); */
|
||||
|
||||
/* log_print(" "); */
|
||||
/* return; */
|
||||
}
|
||||
|
||||
memset(pv_tmp_name, 0, sizeof(pv_tmp_name));
|
||||
|
||||
vg_name_len = strlen(pv->vg_name) + 1;
|
||||
|
||||
if (arg_count(cmd, uuid_ARG)) {
|
||||
if (!id_write_format(&pv->id, uuid, sizeof(uuid))) {
|
||||
stack;
|
||||
return;
|
||||
}
|
||||
|
||||
sprintf(pv_tmp_name, "%-*s with UUID %s",
|
||||
pv_max_name_len - 2, dev_name(pv->dev), uuid);
|
||||
} else {
|
||||
sprintf(pv_tmp_name, "%s", dev_name(pv->dev));
|
||||
}
|
||||
|
||||
if (!*pv->vg_name) {
|
||||
log_print("PV %-*s %-*s %s [%s]",
|
||||
pv_max_name_len, pv_tmp_name,
|
||||
vg_max_name_len, " ",
|
||||
pv->fmt ? pv->fmt->name : " ",
|
||||
(s1 = display_size(pv->size / 2, SIZE_SHORT)));
|
||||
dbg_free(s1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pv->status & EXPORTED_VG) {
|
||||
strncpy(vg_name_this, pv->vg_name, vg_name_len);
|
||||
log_print("PV %-*s is in exported VG %s "
|
||||
"[%s / %s free]",
|
||||
pv_max_name_len, pv_tmp_name,
|
||||
vg_name_this, (s1 =
|
||||
display_size(pv->pe_count *
|
||||
pv->pe_size / 2,
|
||||
SIZE_SHORT)),
|
||||
(s2 = display_size((pv->pe_count - pv->pe_alloc_count)
|
||||
* pv->pe_size / 2, SIZE_SHORT)));
|
||||
dbg_free(s1);
|
||||
dbg_free(s2);
|
||||
return;
|
||||
}
|
||||
|
||||
sprintf(vg_tmp_name, "%s", pv->vg_name);
|
||||
log_print
|
||||
("PV %-*s VG %-*s %s [%s / %s free]", pv_max_name_len,
|
||||
pv_tmp_name, vg_max_name_len, vg_tmp_name,
|
||||
pv->fmt ? pv->fmt->name : " ",
|
||||
(s1 = display_size(pv->pe_count * pv->pe_size / 2, SIZE_SHORT)),
|
||||
(s2 =
|
||||
display_size((pv->pe_count - pv->pe_alloc_count) * pv->pe_size /
|
||||
2, SIZE_SHORT)));
|
||||
dbg_free(s1);
|
||||
dbg_free(s2);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int pvscan(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
int new_pvs_found = 0;
|
||||
@ -56,6 +140,9 @@ int pvscan(struct cmd_context *cmd, int argc, char **argv)
|
||||
log_verbose("Wiping cache of LVM-capable devices");
|
||||
persistent_filter_wipe(cmd->filter);
|
||||
|
||||
log_verbose("Wiping internal cache");
|
||||
cache_destroy();
|
||||
|
||||
log_verbose("Walking through all physical volumes");
|
||||
if (!(pvs = get_pvs(cmd)))
|
||||
return ECMD_FAILED;
|
||||
@ -108,7 +195,8 @@ int pvscan(struct cmd_context *cmd, int argc, char **argv)
|
||||
vg_max_name_len += 2;
|
||||
|
||||
list_iterate(pvh, pvs)
|
||||
pvscan_display_single(cmd, list_item(pvh, struct pv_list)->pv);
|
||||
pvscan_display_single(cmd, list_item(pvh, struct pv_list)->pv,
|
||||
NULL);
|
||||
|
||||
if (!pvs_found) {
|
||||
log_print("No matching physical volumes found");
|
||||
@ -128,87 +216,3 @@ int pvscan(struct cmd_context *cmd, int argc, char **argv)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pvscan_display_single(struct cmd_context *cmd, struct physical_volume *pv)
|
||||
{
|
||||
char uuid[64];
|
||||
int vg_name_len = 0;
|
||||
|
||||
char *s1, *s2;
|
||||
|
||||
char pv_tmp_name[NAME_LEN] = { 0, };
|
||||
char vg_tmp_name[NAME_LEN] = { 0, };
|
||||
char vg_name_this[NAME_LEN] = { 0, };
|
||||
|
||||
/* short listing? */
|
||||
if (arg_count(cmd, short_ARG) > 0) {
|
||||
log_print("%s", dev_name(pv->dev));
|
||||
return;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, verbose_ARG) > 1) {
|
||||
/* FIXME As per pv_display! Drop through for now. */
|
||||
/* pv_show(pv); */
|
||||
|
||||
/* FIXME - Moved to Volume Group structure */
|
||||
/* log_print("System Id %s", pv->vg->system_id); */
|
||||
|
||||
/* log_print(" "); */
|
||||
/* return; */
|
||||
}
|
||||
|
||||
memset(pv_tmp_name, 0, sizeof(pv_tmp_name));
|
||||
|
||||
vg_name_len = strlen(pv->vg_name) + 1;
|
||||
|
||||
if (arg_count(cmd, uuid_ARG)) {
|
||||
if (!id_write_format(&pv->id, uuid, sizeof(uuid))) {
|
||||
stack;
|
||||
return;
|
||||
}
|
||||
|
||||
sprintf(pv_tmp_name, "%-*s with UUID %s",
|
||||
pv_max_name_len - 2, dev_name(pv->dev), uuid);
|
||||
} else {
|
||||
sprintf(pv_tmp_name, "%s", dev_name(pv->dev));
|
||||
}
|
||||
|
||||
if (!*pv->vg_name) {
|
||||
log_print("PV %-*s %-*s [%s]",
|
||||
pv_max_name_len, pv_tmp_name,
|
||||
vg_max_name_len, " ",
|
||||
(s1 = display_size(pv->size / 2, SIZE_SHORT)));
|
||||
dbg_free(s1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pv->status & EXPORTED_VG) {
|
||||
strncpy(vg_name_this, pv->vg_name, vg_name_len);
|
||||
log_print("PV %-*s is in exported VG %s "
|
||||
"[%s / %s free]",
|
||||
pv_max_name_len, pv_tmp_name,
|
||||
vg_name_this, (s1 =
|
||||
display_size(pv->pe_count *
|
||||
pv->pe_size / 2,
|
||||
SIZE_SHORT)),
|
||||
(s2 = display_size((pv->pe_count - pv->pe_alloc_count)
|
||||
* pv->pe_size / 2, SIZE_SHORT)));
|
||||
dbg_free(s1);
|
||||
dbg_free(s2);
|
||||
return;
|
||||
}
|
||||
|
||||
sprintf(vg_tmp_name, "%s", pv->vg_name);
|
||||
log_print
|
||||
("PV %-*s VG %-*s %s [%s / %s free]", pv_max_name_len,
|
||||
pv_tmp_name, vg_max_name_len, vg_tmp_name,
|
||||
pv->fid ? pv->fid->fmt->name : " ",
|
||||
(s1 = display_size(pv->pe_count * pv->pe_size / 2, SIZE_SHORT)),
|
||||
(s2 =
|
||||
display_size((pv->pe_count - pv->pe_alloc_count) * pv->pe_size /
|
||||
2, SIZE_SHORT)));
|
||||
dbg_free(s1);
|
||||
dbg_free(s2);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -6,10 +6,10 @@
|
||||
|
||||
#define unimplemented \
|
||||
{ log_error("Command not implemented yet."); return ECMD_FAILED;}
|
||||
/*int e2fsadm(struct cmd_context *cmd, int argc, char **argv) unimplemented*/
|
||||
int lvmsadc(struct cmd_context *cmd, int argc, char **argv) unimplemented
|
||||
int lvmsar(struct cmd_context *cmd, int argc, char **argv) unimplemented
|
||||
int pvdata(struct cmd_context *cmd, int argc, char **argv) unimplemented
|
||||
int pvmove(struct cmd_context *cmd, int argc, char **argv) unimplemented
|
||||
int pvresize(struct cmd_context *cmd, int argc, char **argv) unimplemented
|
||||
int vgmknodes(struct cmd_context *cmd, int argc, char **argv) unimplemented
|
||||
|
||||
|
210
tools/toollib.c
210
tools/toollib.c
@ -9,8 +9,10 @@
|
||||
#include <sys/stat.h>
|
||||
|
||||
int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
void *handle,
|
||||
int (*process_single) (struct cmd_context * cmd,
|
||||
struct logical_volume * lv))
|
||||
struct logical_volume * lv,
|
||||
void *handle))
|
||||
{
|
||||
int ret_max = 0;
|
||||
int ret = 0;
|
||||
@ -25,7 +27,7 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
ret = process_single(cmd, lv);
|
||||
ret = process_single(cmd, lv, handle);
|
||||
if (ret > ret_max)
|
||||
ret_max = ret;
|
||||
}
|
||||
@ -34,94 +36,163 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
|
||||
}
|
||||
|
||||
struct volume_group *recover_vg(struct cmd_context *cmd, const char *vgname,
|
||||
int lock_type)
|
||||
{
|
||||
int consistent = 1;
|
||||
|
||||
lock_type &= ~LCK_TYPE_MASK;
|
||||
lock_type |= LCK_WRITE;
|
||||
|
||||
if (!lock_vol(cmd, vgname, lock_type)) {
|
||||
log_error("Can't lock %s for metadata recovery: skipping",
|
||||
vgname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return vg_read(cmd, vgname, &consistent);
|
||||
}
|
||||
|
||||
int process_each_lv(struct cmd_context *cmd, int argc, char **argv,
|
||||
int lock_type,
|
||||
int lock_type, void *handle,
|
||||
int (*process_single) (struct cmd_context * cmd,
|
||||
struct logical_volume * lv))
|
||||
struct logical_volume * lv,
|
||||
void *handle))
|
||||
{
|
||||
int opt = 0;
|
||||
int ret_max = 0;
|
||||
int ret = 0;
|
||||
int vg_count = 0;
|
||||
int consistent;
|
||||
|
||||
struct list *vgh, *vgs;
|
||||
struct list *slh, *vgnames;
|
||||
struct volume_group *vg;
|
||||
struct logical_volume *lv;
|
||||
struct lv_list *lvl;
|
||||
|
||||
char *vg_name;
|
||||
char *vgname;
|
||||
|
||||
if (argc) {
|
||||
log_verbose("Using logical volume(s) on command line");
|
||||
for (; opt < argc; opt++) {
|
||||
char *lv_name = argv[opt];
|
||||
int vgname_provided = 1;
|
||||
|
||||
/* does VG exist? */
|
||||
if (!(vg_name = extract_vgname(cmd, lv_name))) {
|
||||
if (ret_max < ECMD_FAILED)
|
||||
ret_max = ECMD_FAILED;
|
||||
continue;
|
||||
/* Do we have a vgname or lvname? */
|
||||
vgname = lv_name;
|
||||
if (!strncmp(vgname, cmd->dev_dir,
|
||||
strlen(cmd->dev_dir)))
|
||||
vgname += strlen(cmd->dev_dir);
|
||||
if (strchr(vgname, '/')) {
|
||||
/* Must be an LV */
|
||||
vgname_provided = 0;
|
||||
if (!(vgname = extract_vgname(cmd, lv_name))) {
|
||||
if (ret_max < ECMD_FAILED)
|
||||
ret_max = ECMD_FAILED;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
log_verbose("Finding volume group \"%s\"", vg_name);
|
||||
if (!lock_vol(cmd, vg_name, lock_type)) {
|
||||
log_error("Can't lock %s: skipping", vg_name);
|
||||
log_verbose("Finding volume group \"%s\"", vgname);
|
||||
if (!lock_vol(cmd, vgname, lock_type)) {
|
||||
log_error("Can't lock %s: skipping", vgname);
|
||||
continue;
|
||||
}
|
||||
if (!(vg = vg_read(cmd, vg_name))) {
|
||||
log_error("Volume group \"%s\" doesn't exist",
|
||||
vg_name);
|
||||
if (ret_max < ECMD_FAILED)
|
||||
ret_max = ECMD_FAILED;
|
||||
unlock_vg(cmd, vg_name);
|
||||
continue;
|
||||
if (lock_type & LCK_WRITE)
|
||||
consistent = 1;
|
||||
else
|
||||
consistent = 0;
|
||||
if (!(vg = vg_read(cmd, vgname, &consistent)) ||
|
||||
!consistent) {
|
||||
unlock_vg(cmd, vgname);
|
||||
if (!vg)
|
||||
log_error("Volume group \"%s\" "
|
||||
"not found", vgname);
|
||||
else
|
||||
log_error("Volume group \"%s\" "
|
||||
"inconsistent", vgname);
|
||||
if (!vg || !(vg =
|
||||
recover_vg(cmd, vgname,
|
||||
lock_type))) {
|
||||
unlock_vg(cmd, vgname);
|
||||
if (ret_max < ECMD_FAILED)
|
||||
ret_max = ECMD_FAILED;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (vg->status & EXPORTED_VG) {
|
||||
log_error("Volume group \"%s\" is exported",
|
||||
vg->name);
|
||||
unlock_vg(cmd, vg_name);
|
||||
unlock_vg(cmd, vgname);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (vgname_provided) {
|
||||
if ((ret =
|
||||
process_each_lv_in_vg(cmd, vg, handle,
|
||||
process_single)) >
|
||||
ret_max)
|
||||
ret_max = ret;
|
||||
unlock_vg(cmd, vgname);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(lvl = find_lv_in_vg(vg, lv_name))) {
|
||||
log_error("Can't find logical volume \"%s\" "
|
||||
"in volume group \"%s\"",
|
||||
lv_name, vg_name);
|
||||
lv_name, vgname);
|
||||
if (ret_max < ECMD_FAILED)
|
||||
ret_max = ECMD_FAILED;
|
||||
unlock_vg(cmd, vg_name);
|
||||
unlock_vg(cmd, vgname);
|
||||
continue;
|
||||
}
|
||||
|
||||
lv = lvl->lv;
|
||||
|
||||
if ((ret = process_single(cmd, lv)) > ret_max)
|
||||
if ((ret = process_single(cmd, lv, handle)) > ret_max)
|
||||
ret_max = ret;
|
||||
unlock_vg(cmd, vg_name);
|
||||
unlock_vg(cmd, vgname);
|
||||
}
|
||||
} else {
|
||||
log_verbose("Finding all logical volumes");
|
||||
if (!(vgs = get_vgs(cmd))) {
|
||||
if (!(vgnames = get_vgs(cmd, 0))) {
|
||||
log_error("No volume groups found");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
list_iterate(vgh, vgs) {
|
||||
vg_name = list_item(vgh, struct name_list)->name;
|
||||
if (!lock_vol(cmd, vg_name, lock_type)) {
|
||||
log_error("Can't lock %s: skipping", vg_name);
|
||||
list_iterate(slh, vgnames) {
|
||||
vgname = list_item(slh, struct str_list)->str;
|
||||
if (!vgname || !*vgname)
|
||||
continue; /* FIXME Unnecessary? */
|
||||
if (!lock_vol(cmd, vgname, lock_type)) {
|
||||
log_error("Can't lock %s: skipping", vgname);
|
||||
continue;
|
||||
}
|
||||
if (!(vg = vg_read(cmd, vg_name))) {
|
||||
log_error("Volume group \"%s\" not found",
|
||||
vg_name);
|
||||
if (ret_max < ECMD_FAILED)
|
||||
ret_max = ECMD_FAILED;
|
||||
unlock_vg(cmd, vg_name);
|
||||
continue;
|
||||
if (lock_type & LCK_WRITE)
|
||||
consistent = 1;
|
||||
else
|
||||
consistent = 0;
|
||||
if (!(vg = vg_read(cmd, vgname, &consistent)) ||
|
||||
!consistent) {
|
||||
unlock_vg(cmd, vgname);
|
||||
if (!vg)
|
||||
log_error("Volume group \"%s\" "
|
||||
"not found", vgname);
|
||||
else
|
||||
log_error("Volume group \"%s\" "
|
||||
"inconsistent", vgname);
|
||||
if (!vg || !(vg =
|
||||
recover_vg(cmd, vgname,
|
||||
lock_type))) {
|
||||
unlock_vg(cmd, vgname);
|
||||
if (ret_max < ECMD_FAILED)
|
||||
ret_max = ECMD_FAILED;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
ret = process_each_lv_in_vg(cmd, vg, process_single);
|
||||
unlock_vg(cmd, vg_name);
|
||||
ret = process_each_lv_in_vg(cmd, vg, handle,
|
||||
process_single);
|
||||
unlock_vg(cmd, vgname);
|
||||
if (ret > ret_max)
|
||||
ret_max = ret;
|
||||
vg_count++;
|
||||
@ -132,16 +203,18 @@ int process_each_lv(struct cmd_context *cmd, int argc, char **argv,
|
||||
}
|
||||
|
||||
int process_each_vg(struct cmd_context *cmd, int argc, char **argv,
|
||||
int lock_type,
|
||||
int lock_type, int consistent, void *handle,
|
||||
int (*process_single) (struct cmd_context * cmd,
|
||||
const char *vg_name))
|
||||
const char *vg_name,
|
||||
struct volume_group * vg,
|
||||
int consistent, void *handle))
|
||||
{
|
||||
int opt = 0;
|
||||
int ret_max = 0;
|
||||
int ret = 0;
|
||||
|
||||
struct list *vgh;
|
||||
struct list *vgs;
|
||||
struct list *slh, *vgnames;
|
||||
struct volume_group *vg;
|
||||
|
||||
char *vg_name;
|
||||
char *dev_dir = cmd->dev_dir;
|
||||
@ -161,24 +234,32 @@ int process_each_vg(struct cmd_context *cmd, int argc, char **argv,
|
||||
log_error("Can't lock %s: skipping", vg_name);
|
||||
continue;
|
||||
}
|
||||
if ((ret = process_single(cmd, vg_name)) > ret_max)
|
||||
log_verbose("Finding volume group \"%s\"", vg_name);
|
||||
vg = vg_read(cmd, vg_name, &consistent);
|
||||
if ((ret = process_single(cmd, vg_name, vg, consistent,
|
||||
handle))
|
||||
> ret_max)
|
||||
ret_max = ret;
|
||||
unlock_vg(cmd, vg_name);
|
||||
}
|
||||
} else {
|
||||
log_verbose("Finding all volume groups");
|
||||
if (!(vgs = get_vgs(cmd))) {
|
||||
if (!(vgnames = get_vgs(cmd, 0)) || list_empty(vgnames)) {
|
||||
log_error("No volume groups found");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
list_iterate(vgh, vgs) {
|
||||
vg_name = list_item(vgh, struct name_list)->name;
|
||||
list_iterate(slh, vgnames) {
|
||||
vg_name = list_item(slh, struct str_list)->str;
|
||||
if (!vg_name || !*vg_name)
|
||||
continue; /* FIXME Unnecessary? */
|
||||
if (!lock_vol(cmd, vg_name, lock_type)) {
|
||||
log_error("Can't lock %s: skipping", vg_name);
|
||||
continue;
|
||||
}
|
||||
ret = process_single(cmd, vg_name);
|
||||
|
||||
log_verbose("Finding volume group \"%s\"", vg_name);
|
||||
vg = vg_read(cmd, vg_name, &consistent);
|
||||
ret = process_single(cmd, vg_name, vg, consistent,
|
||||
handle);
|
||||
if (ret > ret_max)
|
||||
ret_max = ret;
|
||||
unlock_vg(cmd, vg_name);
|
||||
@ -189,9 +270,11 @@ int process_each_vg(struct cmd_context *cmd, int argc, char **argv,
|
||||
}
|
||||
|
||||
int process_each_pv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
void *handle,
|
||||
int (*process_single) (struct cmd_context * cmd,
|
||||
struct volume_group * vg,
|
||||
struct physical_volume * pv))
|
||||
struct physical_volume * pv,
|
||||
void *handle))
|
||||
{
|
||||
int ret_max = 0;
|
||||
int ret = 0;
|
||||
@ -201,7 +284,7 @@ int process_each_pv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pv = list_item(pvh, struct pv_list)->pv;
|
||||
|
||||
if ((ret = process_single(cmd, vg, pv)) > ret_max)
|
||||
if ((ret = process_single(cmd, vg, pv, handle)) > ret_max)
|
||||
ret_max = ret;
|
||||
}
|
||||
|
||||
@ -209,10 +292,11 @@ int process_each_pv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
}
|
||||
|
||||
int process_each_pv(struct cmd_context *cmd, int argc, char **argv,
|
||||
struct volume_group *vg,
|
||||
struct volume_group *vg, void *handle,
|
||||
int (*process_single) (struct cmd_context * cmd,
|
||||
struct volume_group * vg,
|
||||
struct physical_volume * pv))
|
||||
struct physical_volume * pv,
|
||||
void *handle))
|
||||
{
|
||||
int opt = 0;
|
||||
int ret_max = 0;
|
||||
@ -229,32 +313,18 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv,
|
||||
vg->name);
|
||||
continue;
|
||||
}
|
||||
ret = process_single(cmd, vg, pvl->pv);
|
||||
ret = process_single(cmd, vg, pvl->pv, handle);
|
||||
if (ret > ret_max)
|
||||
ret_max = ret;
|
||||
}
|
||||
} else {
|
||||
log_verbose("Using all physical volume(s) in volume group");
|
||||
process_each_pv_in_vg(cmd, vg, process_single);
|
||||
process_each_pv_in_vg(cmd, vg, handle, process_single);
|
||||
}
|
||||
|
||||
return ret_max;
|
||||
}
|
||||
|
||||
int is_valid_chars(char *n)
|
||||
{
|
||||
register char c;
|
||||
|
||||
/* Hyphen used as VG-LV separator - ambiguity if LV starts with it */
|
||||
if (*n == '-')
|
||||
return 0;
|
||||
|
||||
while ((c = *n++))
|
||||
if (!isalnum(c) && c != '.' && c != '_' && c != '-' && c != '+')
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *extract_vgname(struct cmd_context *cmd, char *lv_name)
|
||||
{
|
||||
char *vg_name = lv_name;
|
||||
|
@ -29,30 +29,42 @@ int autobackup_init(const char *backup_dir, int keep_days, int keep_number,
|
||||
int autobackup);
|
||||
int autobackup(struct volume_group *vg);
|
||||
|
||||
struct volume_group *recover_vg(struct cmd_context *cmd, const char *vgname,
|
||||
int lock_type);
|
||||
|
||||
int process_each_vg(struct cmd_context *cmd, int argc, char **argv,
|
||||
int lock_type,
|
||||
int lock_type, int consistent, void *handle,
|
||||
int (*process_single) (struct cmd_context * cmd,
|
||||
const char *vg_name));
|
||||
const char *vg_name,
|
||||
struct volume_group *vg,
|
||||
int consistent,
|
||||
void *handle));
|
||||
|
||||
int process_each_pv(struct cmd_context *cmd, int argc, char **argv,
|
||||
struct volume_group *vg,
|
||||
struct volume_group *vg, void *handle,
|
||||
int (*process_single) (struct cmd_context * cmd,
|
||||
struct volume_group * vg,
|
||||
struct physical_volume * pv));
|
||||
struct physical_volume * pv,
|
||||
void *handle));
|
||||
|
||||
int process_each_lv(struct cmd_context *cmd, int argc, char **argv,
|
||||
int lock_type,
|
||||
int lock_type, void *handle,
|
||||
int (*process_single) (struct cmd_context * cmd,
|
||||
struct logical_volume * lv));
|
||||
struct logical_volume * lv,
|
||||
void *handle));
|
||||
|
||||
int process_each_pv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
void *handle,
|
||||
int (*process_single) (struct cmd_context * cmd,
|
||||
struct volume_group * vg,
|
||||
struct physical_volume * pv));
|
||||
int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
int (*process_single) (struct cmd_context * cmd,
|
||||
struct logical_volume * lv));
|
||||
struct physical_volume * pv,
|
||||
void *handle));
|
||||
|
||||
int is_valid_chars(char *n);
|
||||
int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
void *handle,
|
||||
int (*process_single) (struct cmd_context * cmd,
|
||||
struct logical_volume * lv,
|
||||
void *handle));
|
||||
|
||||
char *default_vgname(struct cmd_context *cmd);
|
||||
char *extract_vgname(struct cmd_context *cmd, char *lv_name);
|
||||
|
@ -7,39 +7,40 @@
|
||||
#ifndef _LVM_TOOLS_H
|
||||
#define _LVM_TOOLS_H
|
||||
|
||||
#include "pool.h"
|
||||
#include "dbg_malloc.h"
|
||||
#include "list.h"
|
||||
#include "log.h"
|
||||
#include "lvm-string.h"
|
||||
#include "lvm-file.h"
|
||||
#include "metadata.h"
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "activate.h"
|
||||
#include "archive.h"
|
||||
#include "cache.h"
|
||||
#include "config.h"
|
||||
#include "dbg_malloc.h"
|
||||
#include "dev-cache.h"
|
||||
#include "device.h"
|
||||
#include "vgcache.h"
|
||||
#include "display.h"
|
||||
#include "errors.h"
|
||||
#include "filter.h"
|
||||
#include "filter-persistent.h"
|
||||
#include "filter-composite.h"
|
||||
#include "filter-persistent.h"
|
||||
#include "filter-regex.h"
|
||||
#include "format1.h"
|
||||
#include "format-text.h"
|
||||
#include "toollib.h"
|
||||
#include "activate.h"
|
||||
#include "archive.h"
|
||||
#include "metadata.h"
|
||||
#include "list.h"
|
||||
#include "locking.h"
|
||||
#include "log.h"
|
||||
#include "lvm-file.h"
|
||||
#include "lvm-string.h"
|
||||
#include "pool.h"
|
||||
#include "toolcontext.h"
|
||||
#include "toollib.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define CMD_LEN 256
|
||||
#define MAX_ARGS 64
|
||||
@ -68,7 +69,7 @@ typedef enum {
|
||||
struct arg {
|
||||
char short_arg;
|
||||
char *long_arg;
|
||||
int (*fn) (struct arg * a);
|
||||
int (*fn) (struct cmd_context * cmd, struct arg * a);
|
||||
|
||||
int count;
|
||||
char *value;
|
||||
@ -92,14 +93,14 @@ struct command {
|
||||
void usage(const char *name);
|
||||
|
||||
/* the argument verify/normalise functions */
|
||||
int yes_no_arg(struct arg *a);
|
||||
int size_arg(struct arg *a);
|
||||
int int_arg(struct arg *a);
|
||||
int int_arg_with_sign(struct arg *a);
|
||||
int minor_arg(struct arg *a);
|
||||
int string_arg(struct arg *a);
|
||||
int permission_arg(struct arg *a);
|
||||
int metadatatype_arg(struct arg *a);
|
||||
int yes_no_arg(struct cmd_context *cmd, struct arg *a);
|
||||
int size_arg(struct cmd_context *cmd, struct arg *a);
|
||||
int int_arg(struct cmd_context *cmd, struct arg *a);
|
||||
int int_arg_with_sign(struct cmd_context *cmd, struct arg *a);
|
||||
int minor_arg(struct cmd_context *cmd, struct arg *a);
|
||||
int string_arg(struct cmd_context *cmd, struct arg *a);
|
||||
int permission_arg(struct cmd_context *cmd, struct arg *a);
|
||||
int metadatatype_arg(struct cmd_context *cmd, struct arg *a);
|
||||
|
||||
char yes_no_prompt(const char *prompt, ...);
|
||||
|
||||
@ -151,13 +152,4 @@ static inline const char *command_name(struct cmd_context *cmd)
|
||||
return cmd->command->name;
|
||||
}
|
||||
|
||||
static inline int driver_is_loaded(void)
|
||||
{
|
||||
int i = driver_version(NULL, 0);
|
||||
|
||||
if (!i)
|
||||
log_error("device-mapper driver/module not loaded?");
|
||||
return i;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -6,44 +6,29 @@
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static int _backup_to_file(const char *file, struct volume_group *vg)
|
||||
static int vg_backup_single(struct cmd_context *cmd, const char *vg_name,
|
||||
struct volume_group *vg, int consistent,
|
||||
void *handle)
|
||||
{
|
||||
int r;
|
||||
struct format_instance *tf;
|
||||
void *context;
|
||||
|
||||
if (!(context = create_text_context(vg->cmd->fmtt, file,
|
||||
vg->cmd->cmd_line)) ||
|
||||
!(tf = vg->cmd->fmtt->ops->create_instance(vg->cmd->fmtt, NULL,
|
||||
context))) {
|
||||
log_error("Couldn't create backup object.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(r = tf->fmt->ops->vg_write(tf, vg, context)) ||
|
||||
!(r = tf->fmt->ops->vg_commit(tf, vg, context)))
|
||||
stack;
|
||||
|
||||
tf->fmt->ops->destroy_instance(tf);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int vg_backup_single(struct cmd_context *cmd, const char *vg_name)
|
||||
{
|
||||
struct volume_group *vg;
|
||||
|
||||
log_verbose("Checking for volume group \"%s\"", vg_name);
|
||||
if (!(vg = vg_read(cmd, vg_name))) {
|
||||
if (!vg) {
|
||||
log_error("Volume group \"%s\" not found", vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!consistent)
|
||||
log_error("Warning: Volume group \"%s\" inconsistent", vg_name);
|
||||
|
||||
if (arg_count(cmd, file_ARG)) {
|
||||
_backup_to_file(arg_value(cmd, file_ARG), vg);
|
||||
backup_to_file(arg_value(cmd, file_ARG), vg->cmd->cmd_line, vg);
|
||||
|
||||
} else {
|
||||
if (!consistent) {
|
||||
log_error("No backup taken: specify filename with -f "
|
||||
"to backup an inconsistent VG");
|
||||
stack;
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
/* just use the normal backup code */
|
||||
backup_enable(1); /* force a backup */
|
||||
if (!backup(vg)) {
|
||||
@ -58,8 +43,6 @@ static int vg_backup_single(struct cmd_context *cmd, const char *vg_name)
|
||||
|
||||
int vgcfgbackup(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
if (!driver_is_loaded())
|
||||
return ECMD_FAILED;
|
||||
|
||||
return process_each_vg(cmd, argc, argv, LCK_VG_READ, &vg_backup_single);
|
||||
return process_each_vg(cmd, argc, argv, LCK_VG_READ, 0, NULL,
|
||||
&vg_backup_single);
|
||||
}
|
||||
|
@ -13,9 +13,6 @@ int vgcfgrestore(struct cmd_context *cmd, int argc, char **argv)
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!driver_is_loaded())
|
||||
return ECMD_FAILED;
|
||||
|
||||
/*
|
||||
* FIXME: overloading the -l arg for now to display a
|
||||
* list of archive files for a particular vg
|
||||
@ -27,13 +24,28 @@ int vgcfgrestore(struct cmd_context *cmd, int argc, char **argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lock_vol(cmd, ORPHAN, LCK_VG_WRITE)) {
|
||||
log_error("Unable to lock orphans");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!lock_vol(cmd, argv[0], LCK_VG_WRITE | LCK_NONBLOCK)) {
|
||||
log_error("Unable to lock volume group %s", argv[0]);
|
||||
unlock_vg(cmd, ORPHAN);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!(arg_count(cmd, file_ARG) ?
|
||||
backup_restore_from_file(cmd, argv[0],
|
||||
arg_str_value(cmd, file_ARG, "")) :
|
||||
backup_restore(cmd, argv[0]))) {
|
||||
unlock_vg(cmd, argv[0]);
|
||||
unlock_vg(cmd, ORPHAN);
|
||||
log_err("Restore failed.");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
unlock_vg(cmd, argv[0]);
|
||||
unlock_vg(cmd, ORPHAN);
|
||||
return 0;
|
||||
}
|
||||
|
142
tools/vgchange.c
142
tools/vgchange.c
@ -20,11 +20,6 @@
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
static int vgchange_single(struct cmd_context *cmd, const char *vg_name);
|
||||
void vgchange_available(struct cmd_context *cmd, struct volume_group *vg);
|
||||
void vgchange_resizeable(struct cmd_context *cmd, struct volume_group *vg);
|
||||
void vgchange_logicalvolume(struct cmd_context *cmd, struct volume_group *vg);
|
||||
|
||||
static int _activate_lvs_in_vg(struct cmd_context *cmd,
|
||||
struct volume_group *vg, int lock)
|
||||
{
|
||||
@ -48,72 +43,6 @@ static int _activate_lvs_in_vg(struct cmd_context *cmd,
|
||||
return count;
|
||||
}
|
||||
|
||||
int vgchange(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
if (!
|
||||
(arg_count(cmd, available_ARG) + arg_count(cmd, logicalvolume_ARG) +
|
||||
arg_count(cmd, resizeable_ARG))) {
|
||||
log_error("One of -a, -l or -x options required");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, available_ARG) + arg_count(cmd, logicalvolume_ARG) +
|
||||
arg_count(cmd, resizeable_ARG) > 1) {
|
||||
log_error("Only one of -a, -l or -x options allowed");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, ignorelockingfailure_ARG) &&
|
||||
!arg_count(cmd, available_ARG)) {
|
||||
log_error("--ignorelockingfailure only available with -a");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, available_ARG) == 1
|
||||
&& arg_count(cmd, autobackup_ARG)) {
|
||||
log_error("-A option not necessary with -a option");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (!driver_is_loaded())
|
||||
return ECMD_FAILED;
|
||||
|
||||
return process_each_vg(cmd, argc, argv,
|
||||
(arg_count(cmd, available_ARG)) ?
|
||||
LCK_VG_READ : LCK_VG_WRITE, &vgchange_single);
|
||||
}
|
||||
|
||||
static int vgchange_single(struct cmd_context *cmd, const char *vg_name)
|
||||
{
|
||||
struct volume_group *vg;
|
||||
|
||||
if (!(vg = vg_read(cmd, vg_name))) {
|
||||
log_error("Unable to find volume group \"%s\"", vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!(vg->status & LVM_WRITE) && !arg_count(cmd, available_ARG)) {
|
||||
log_error("Volume group \"%s\" is read-only", vg->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (vg->status & EXPORTED_VG) {
|
||||
log_error("Volume group \"%s\" is exported", vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, available_ARG))
|
||||
vgchange_available(cmd, vg);
|
||||
|
||||
if (arg_count(cmd, resizeable_ARG))
|
||||
vgchange_resizeable(cmd, vg);
|
||||
|
||||
if (arg_count(cmd, logicalvolume_ARG))
|
||||
vgchange_logicalvolume(cmd, vg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vgchange_available(struct cmd_context *cmd, struct volume_group *vg)
|
||||
{
|
||||
int lv_open, active;
|
||||
@ -208,3 +137,74 @@ void vgchange_logicalvolume(struct cmd_context *cmd, struct volume_group *vg)
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int vgchange_single(struct cmd_context *cmd, const char *vg_name,
|
||||
struct volume_group *vg, int consistent,
|
||||
void *handle)
|
||||
{
|
||||
if (!vg) {
|
||||
log_error("Unable to find volume group \"%s\"", vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!consistent) {
|
||||
unlock_vg(cmd, vg_name);
|
||||
log_error("Volume group \"%s\" inconsistent", vg_name);
|
||||
if (!(vg = recover_vg(cmd, vg_name, LCK_VG_WRITE)))
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!(vg->status & LVM_WRITE) && !arg_count(cmd, available_ARG)) {
|
||||
log_error("Volume group \"%s\" is read-only", vg->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (vg->status & EXPORTED_VG) {
|
||||
log_error("Volume group \"%s\" is exported", vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, available_ARG))
|
||||
vgchange_available(cmd, vg);
|
||||
|
||||
if (arg_count(cmd, resizeable_ARG))
|
||||
vgchange_resizeable(cmd, vg);
|
||||
|
||||
if (arg_count(cmd, logicalvolume_ARG))
|
||||
vgchange_logicalvolume(cmd, vg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vgchange(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
if (!
|
||||
(arg_count(cmd, available_ARG) + arg_count(cmd, logicalvolume_ARG) +
|
||||
arg_count(cmd, resizeable_ARG))) {
|
||||
log_error("One of -a, -l or -x options required");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, available_ARG) + arg_count(cmd, logicalvolume_ARG) +
|
||||
arg_count(cmd, resizeable_ARG) > 1) {
|
||||
log_error("Only one of -a, -l or -x options allowed");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, ignorelockingfailure_ARG) &&
|
||||
!arg_count(cmd, available_ARG)) {
|
||||
log_error("--ignorelockingfailure only available with -a");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, available_ARG) == 1
|
||||
&& arg_count(cmd, autobackup_ARG)) {
|
||||
log_error("-A option not necessary with -a option");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
return process_each_vg(cmd, argc, argv,
|
||||
(arg_count(cmd, available_ARG)) ?
|
||||
LCK_VG_READ : LCK_VG_WRITE, 0, NULL,
|
||||
&vgchange_single);
|
||||
}
|
||||
|
31
tools/vgck.c
31
tools/vgck.c
@ -20,20 +20,15 @@
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
static int vgck_single(struct cmd_context *cmd, const char *vg_name);
|
||||
|
||||
int vgck(struct cmd_context *cmd, int argc, char **argv)
|
||||
static int vgck_single(struct cmd_context *cmd, const char *vg_name,
|
||||
struct volume_group *vg, int consistent, void *handle)
|
||||
{
|
||||
return process_each_vg(cmd, argc, argv, LCK_VG_READ, &vgck_single);
|
||||
}
|
||||
if (!consistent) {
|
||||
log_error("Volume group \"%s\" inconsistent", vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
static int vgck_single(struct cmd_context *cmd, const char *vg_name)
|
||||
{
|
||||
struct volume_group *vg;
|
||||
|
||||
log_verbose("Checking volume group \"%s\"", vg_name);
|
||||
|
||||
if (!(vg = vg_read(cmd, vg_name))) {
|
||||
if (!vg) {
|
||||
log_error("Volume group \"%s\" not found", vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
@ -43,12 +38,12 @@ static int vgck_single(struct cmd_context *cmd, const char *vg_name)
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
/******* FIXME Must be caught and logged by vg_read
|
||||
log_error("not all physical volumes of volume group \"%s\" online",
|
||||
log_error("volume group \"%s\" has physical volumes with ",
|
||||
"invalid version",
|
||||
********/
|
||||
|
||||
/* FIXME: free */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vgck(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
return process_each_vg(cmd, argc, argv, LCK_VG_READ, 0, NULL,
|
||||
&vgck_single);
|
||||
}
|
||||
|
185
tools/vgconvert.c
Normal file
185
tools/vgconvert.c
Normal file
@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software
|
||||
*
|
||||
* pvcreate 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, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* pvcreate 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 LVM; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "tools.h"
|
||||
#include "defaults.h"
|
||||
|
||||
static int vgconvert_single(struct cmd_context *cmd, const char *vg_name,
|
||||
struct volume_group *vg, int consistent,
|
||||
void *handle)
|
||||
{
|
||||
struct physical_volume *pv, *existing_pv;
|
||||
uint64_t size = 0;
|
||||
struct list mdas;
|
||||
int pvmetadatacopies = 0;
|
||||
uint64_t pvmetadatasize = 0;
|
||||
uint64_t pe_end = 0, pe_start = 0;
|
||||
struct list *pvh;
|
||||
|
||||
if (!vg) {
|
||||
log_error("Unable to find volume group \"%s\"", vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!consistent) {
|
||||
unlock_vg(cmd, vg_name);
|
||||
log_error("Volume group \"%s\" inconsistent", vg_name);
|
||||
if (!(vg = recover_vg(cmd, vg_name, LCK_VG_WRITE)))
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!(vg->status & LVM_WRITE)) {
|
||||
log_error("Volume group \"%s\" is read-only", vg->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (vg->status & EXPORTED_VG) {
|
||||
log_error("Volume group \"%s\" is exported", vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (vg->fid->fmt == cmd->fmt) {
|
||||
log_error("Volume group \"%s\" already uses format %s",
|
||||
vg_name, cmd->fmt->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (cmd->fmt->features & FMT_MDAS) {
|
||||
pvmetadatasize = arg_int64_value(cmd, metadatasize_ARG, 0) * 2;
|
||||
if (!pvmetadatasize)
|
||||
pvmetadatasize =
|
||||
find_config_int(cmd->cf->root,
|
||||
"metadata/pvmetadatasize",
|
||||
'/', DEFAULT_PVMETADATASIZE);
|
||||
|
||||
pvmetadatacopies = arg_int_value(cmd, metadatacopies_ARG, -1);
|
||||
if (pvmetadatacopies < 0)
|
||||
pvmetadatacopies =
|
||||
find_config_int(cmd->cf->root,
|
||||
"metadata/pvmetadatacopies",
|
||||
'/', DEFAULT_PVMETADATACOPIES);
|
||||
}
|
||||
|
||||
if (!archive(vg)) {
|
||||
log_error("Archive of \"%s\" metadata failed.", vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
existing_pv = list_item(pvh, struct pv_list)->pv;
|
||||
|
||||
pe_start = existing_pv->pe_start;
|
||||
pe_end = existing_pv->pe_count * existing_pv->pe_size
|
||||
+ pe_start - 1;
|
||||
|
||||
list_init(&mdas);
|
||||
if (!(pv = pv_create(cmd->fmt, existing_pv->dev,
|
||||
&existing_pv->id, size,
|
||||
pe_start, existing_pv->pe_count,
|
||||
existing_pv->pe_size, pvmetadatacopies,
|
||||
pvmetadatasize, &mdas))) {
|
||||
log_error("Failed to setup physical volume \"%s\"",
|
||||
dev_name(existing_pv->dev));
|
||||
log_error("Use pvcreate and vgcfgrestore to repair "
|
||||
"from archived metadata.");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
log_verbose("Set up physical volume for \"%s\" with %" PRIu64
|
||||
" available sectors", dev_name(pv->dev), pv->size);
|
||||
|
||||
/* Wipe existing label first */
|
||||
if (!label_remove(pv->dev)) {
|
||||
log_error("Failed to wipe existing label on %s",
|
||||
dev_name(pv->dev));
|
||||
log_error("Use pvcreate and vgcfgrestore to repair "
|
||||
"from archived metadata.");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
log_very_verbose("Writing physical volume data to disk \"%s\"",
|
||||
dev_name(pv->dev));
|
||||
if (!(pv_write(cmd, pv, &mdas,
|
||||
arg_int_value(cmd, labelsector_ARG,
|
||||
DEFAULT_LABELSECTOR)))) {
|
||||
log_error("Failed to write physical volume \"%s\"",
|
||||
dev_name(pv->dev));
|
||||
log_error("Use pvcreate and vgcfgrestore to repair "
|
||||
"from archived metadata.");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
log_verbose("Physical volume \"%s\" successfully created",
|
||||
dev_name(pv->dev));
|
||||
|
||||
}
|
||||
|
||||
log_verbose("Deleting existing metadata for VG %s", vg_name);
|
||||
if (!vg_remove(vg)) {
|
||||
log_error("Removal of existing metadata for %s failed.",
|
||||
vg_name);
|
||||
log_error("Use pvcreate and vgcfgrestore to repair "
|
||||
"from archived metadata.");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
log_verbose("Writing metadata for VG %s using format %s", vg_name,
|
||||
cmd->fmt->name);
|
||||
if (!backup_restore_vg(cmd, vg)) {
|
||||
log_error("Conversion failed for volume group %s.", vg_name);
|
||||
log_error("Use pvcreate and vgcfgrestore to repair from "
|
||||
"archived metadata.");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
log_print("Volume group %s successfully converted", vg_name);
|
||||
|
||||
backup(vg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vgconvert(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
if (!argc) {
|
||||
log_error("Please enter volume group(s)");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (arg_int_value(cmd, labelsector_ARG, 0) >= LABEL_SCAN_SECTORS) {
|
||||
log_error("labelsector must be less than %lu",
|
||||
LABEL_SCAN_SECTORS);
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (!(cmd->fmt->features & FMT_MDAS) &&
|
||||
(arg_count(cmd, metadatacopies_ARG) ||
|
||||
arg_count(cmd, metadatasize_ARG))) {
|
||||
log_error("Metadata parameters only apply to text format");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, metadatacopies_ARG) &&
|
||||
arg_int_value(cmd, metadatacopies_ARG, -1) > 2) {
|
||||
log_error("Metadatacopies may only be 0, 1 or 2");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
return process_each_vg(cmd, argc, argv, LCK_VG_WRITE, 0, NULL,
|
||||
&vgconvert_single);
|
||||
}
|
@ -73,15 +73,12 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!is_valid_chars(vg_name)) {
|
||||
if (!validate_vgname(vg_name)) {
|
||||
log_error("New volume group name \"%s\" has invalid characters",
|
||||
vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!driver_is_loaded())
|
||||
return ECMD_FAILED;
|
||||
|
||||
/* Create the new VG */
|
||||
if (!(vg = vg_create(cmd, vg_name, extent_size, max_pv, max_lv,
|
||||
argc - 1, argv + 1)))
|
||||
|
@ -20,64 +20,19 @@
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
static int vgdisplay_single(struct cmd_context *cmd, const char *vg_name);
|
||||
|
||||
int vgdisplay(struct cmd_context *cmd, int argc, char **argv)
|
||||
static int vgdisplay_single(struct cmd_context *cmd, const char *vg_name,
|
||||
struct volume_group *vg, int consistent,
|
||||
void *handle)
|
||||
{
|
||||
if (arg_count(cmd, colon_ARG) && arg_count(cmd, short_ARG)) {
|
||||
log_error("Option -c is not allowed with option -s");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (argc && arg_count(cmd, activevolumegroups_ARG)) {
|
||||
log_error("Option -A is not allowed with volume group names");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (!driver_is_loaded())
|
||||
return ECMD_FAILED;
|
||||
|
||||
/* FIXME -D disk_ARG is now redundant */
|
||||
|
||||
/********* FIXME: Do without this - or else 2(+) passes!
|
||||
Figure out longest volume group name
|
||||
for (c = opt; opt < argc; opt++) {
|
||||
len = strlen(argv[opt]);
|
||||
if (len > max_len)
|
||||
max_len = len;
|
||||
}
|
||||
**********/
|
||||
|
||||
process_each_vg(cmd, argc, argv, LCK_VG_READ, &vgdisplay_single);
|
||||
|
||||
/******** FIXME Need to count number processed
|
||||
Add this to process_each_vg if arg_count(cmd,activevolumegroups_ARG) ?
|
||||
|
||||
if (opt == argc) {
|
||||
log_print("no ");
|
||||
if (arg_count(cmd,activevolumegroups_ARG))
|
||||
printf("active ");
|
||||
printf("volume groups found\n\n");
|
||||
return LVM_E_NO_VG;
|
||||
}
|
||||
************/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vgdisplay_single(struct cmd_context *cmd, const char *vg_name)
|
||||
{
|
||||
|
||||
struct volume_group *vg;
|
||||
|
||||
/* FIXME Do the active check here if activevolumegroups_ARG ? */
|
||||
|
||||
log_very_verbose("Finding volume group \"%s\"", vg_name);
|
||||
if (!(vg = vg_read(cmd, vg_name))) {
|
||||
if (!vg) {
|
||||
log_error("Volume group \"%s\" doesn't exist", vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!consistent)
|
||||
log_error("WARNING: Volume group \"%s\" inconsistent", vg_name);
|
||||
|
||||
if (vg->status & EXPORTED_VG)
|
||||
log_print("WARNING: volume group \"%s\" is exported", vg_name);
|
||||
|
||||
@ -96,11 +51,50 @@ static int vgdisplay_single(struct cmd_context *cmd, const char *vg_name)
|
||||
if (arg_count(cmd, verbose_ARG)) {
|
||||
vgdisplay_extents(vg);
|
||||
|
||||
process_each_lv_in_vg(cmd, vg, &lvdisplay_full);
|
||||
process_each_lv_in_vg(cmd, vg, NULL, &lvdisplay_full);
|
||||
|
||||
log_print("--- Physical volumes ---");
|
||||
process_each_pv_in_vg(cmd, vg, &pvdisplay_short);
|
||||
process_each_pv_in_vg(cmd, vg, NULL, &pvdisplay_short);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vgdisplay(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
if (arg_count(cmd, colon_ARG) && arg_count(cmd, short_ARG)) {
|
||||
log_error("Option -c is not allowed with option -s");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (argc && arg_count(cmd, activevolumegroups_ARG)) {
|
||||
log_error("Option -A is not allowed with volume group names");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
/********* FIXME: Do without this - or else 2(+) passes!
|
||||
Figure out longest volume group name
|
||||
for (c = opt; opt < argc; opt++) {
|
||||
len = strlen(argv[opt]);
|
||||
if (len > max_len)
|
||||
max_len = len;
|
||||
}
|
||||
**********/
|
||||
|
||||
process_each_vg(cmd, argc, argv, LCK_VG_READ, 0, NULL,
|
||||
&vgdisplay_single);
|
||||
|
||||
/******** FIXME Need to count number processed
|
||||
Add this to process_each_vg if arg_count(cmd,activevolumegroups_ARG) ?
|
||||
|
||||
if (opt == argc) {
|
||||
log_print("no ");
|
||||
if (arg_count(cmd,activevolumegroups_ARG))
|
||||
printf("active ");
|
||||
printf("volume groups found\n\n");
|
||||
return LVM_E_NO_VG;
|
||||
}
|
||||
************/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -20,35 +20,20 @@
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
static int vgexport_single(struct cmd_context *cmd, const char *vg_name);
|
||||
|
||||
int vgexport(struct cmd_context *cmd, int argc, char **argv)
|
||||
static int vgexport_single(struct cmd_context *cmd, const char *vg_name,
|
||||
struct volume_group *vg, int consistent,
|
||||
void *handle)
|
||||
{
|
||||
if (!argc && !arg_count(cmd, all_ARG)) {
|
||||
log_error("Please supply volume groups or use -a for all.");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (argc && arg_count(cmd, all_ARG)) {
|
||||
log_error("No arguments permitted when using -a for all.");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!driver_is_loaded())
|
||||
return ECMD_FAILED;
|
||||
|
||||
return process_each_vg(cmd, argc, argv, LCK_VG_READ, &vgexport_single);
|
||||
}
|
||||
|
||||
static int vgexport_single(struct cmd_context *cmd, const char *vg_name)
|
||||
{
|
||||
struct volume_group *vg;
|
||||
|
||||
if (!(vg = vg_read(cmd, vg_name))) {
|
||||
if (!vg) {
|
||||
log_error("Unable to find volume group \"%s\"", vg_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!consistent) {
|
||||
log_error("Volume group %s inconsistent", vg_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (vg->status & EXPORTED_VG) {
|
||||
log_error("Volume group \"%s\" is already exported", vg_name);
|
||||
goto error;
|
||||
@ -82,3 +67,19 @@ static int vgexport_single(struct cmd_context *cmd, const char *vg_name)
|
||||
error:
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
int vgexport(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
if (!argc && !arg_count(cmd, all_ARG)) {
|
||||
log_error("Please supply volume groups or use -a for all.");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (argc && arg_count(cmd, all_ARG)) {
|
||||
log_error("No arguments permitted when using -a for all.");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
return process_each_vg(cmd, argc, argv, LCK_VG_WRITE, 1, NULL,
|
||||
&vgexport_single);
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ int vgextend(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
char *vg_name;
|
||||
struct volume_group *vg = NULL;
|
||||
int consistent = 1;
|
||||
|
||||
if (!argc) {
|
||||
log_error("Please enter volume group name and "
|
||||
@ -36,9 +37,6 @@ int vgextend(struct cmd_context *cmd, int argc, char **argv)
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (!driver_is_loaded())
|
||||
return ECMD_FAILED;
|
||||
|
||||
vg_name = argv[0];
|
||||
argc--;
|
||||
argv++;
|
||||
@ -55,7 +53,7 @@ int vgextend(struct cmd_context *cmd, int argc, char **argv)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!(vg = vg_read(cmd, vg_name))) {
|
||||
if (!(vg = vg_read(cmd, vg_name, &consistent)) || !consistent) {
|
||||
log_error("Volume group \"%s\" not found.", vg_name);
|
||||
goto error;
|
||||
}
|
||||
|
@ -20,31 +20,11 @@
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
static int vgimport_single(struct cmd_context *cmd, const char *vg_name);
|
||||
|
||||
int vgimport(struct cmd_context *cmd, int argc, char **argv)
|
||||
static int vgimport_single(struct cmd_context *cmd, const char *vg_name,
|
||||
struct volume_group *vg, int consistent,
|
||||
void *handle)
|
||||
{
|
||||
if (!argc && !arg_count(cmd, all_ARG)) {
|
||||
log_error("Please supply volume groups or use -a for all.");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (argc && arg_count(cmd, all_ARG)) {
|
||||
log_error("No arguments permitted when using -a for all.");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!driver_is_loaded())
|
||||
return ECMD_FAILED;
|
||||
|
||||
return process_each_vg(cmd, argc, argv, LCK_VG_WRITE, &vgimport_single);
|
||||
}
|
||||
|
||||
static int vgimport_single(struct cmd_context *cmd, const char *vg_name)
|
||||
{
|
||||
struct volume_group *vg;
|
||||
|
||||
if (!(vg = vg_read(cmd, vg_name))) {
|
||||
if (!vg || !consistent) {
|
||||
log_error("Unable to find exported volume group \"%s\"",
|
||||
vg_name);
|
||||
goto error;
|
||||
@ -77,3 +57,19 @@ static int vgimport_single(struct cmd_context *cmd, const char *vg_name)
|
||||
error:
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
int vgimport(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
if (!argc && !arg_count(cmd, all_ARG)) {
|
||||
log_error("Please supply volume groups or use -a for all.");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (argc && arg_count(cmd, all_ARG)) {
|
||||
log_error("No arguments permitted when using -a for all.");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
return process_each_vg(cmd, argc, argv, LCK_VG_WRITE, 1, NULL,
|
||||
&vgimport_single);
|
||||
}
|
||||
|
@ -20,42 +20,13 @@
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
int vgmerge_single(struct cmd_context *cmd, const char *vg_name_to,
|
||||
const char *vg_name_from);
|
||||
|
||||
int vgmerge(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
char *vg_name_to;
|
||||
int opt = 0;
|
||||
int ret = 0, ret_max = 0;
|
||||
|
||||
if (argc < 2) {
|
||||
log_error("Please enter 2 or more volume groups to merge");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (!driver_is_loaded())
|
||||
return ECMD_FAILED;
|
||||
|
||||
vg_name_to = argv[0];
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
for (; opt < argc; opt++) {
|
||||
ret = vgmerge_single(cmd, vg_name_to, argv[opt]);
|
||||
if (ret > ret_max)
|
||||
ret_max = ret;
|
||||
}
|
||||
|
||||
return ret_max;
|
||||
}
|
||||
|
||||
int vgmerge_single(struct cmd_context *cmd, const char *vg_name_to,
|
||||
const char *vg_name_from)
|
||||
{
|
||||
struct volume_group *vg_to, *vg_from;
|
||||
struct list *lvh1, *lvh2;
|
||||
int active;
|
||||
int consistent = 1;
|
||||
|
||||
if (!strcmp(vg_name_to, vg_name_from)) {
|
||||
log_error("Duplicate volume group name \"%s\"", vg_name_from);
|
||||
@ -68,7 +39,7 @@ int vgmerge_single(struct cmd_context *cmd, const char *vg_name_to,
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!(vg_to = vg_read(cmd, vg_name_to))) {
|
||||
if (!(vg_to = vg_read(cmd, vg_name_to, &consistent)) || !consistent) {
|
||||
log_error("Volume group \"%s\" doesn't exist", vg_name_to);
|
||||
unlock_vg(cmd, vg_name_to);
|
||||
return ECMD_FAILED;
|
||||
@ -93,7 +64,8 @@ int vgmerge_single(struct cmd_context *cmd, const char *vg_name_to,
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!(vg_from = vg_read(cmd, vg_name_from))) {
|
||||
consistent = 1;
|
||||
if (!(vg_from = vg_read(cmd, vg_name_from, &consistent)) || !consistent) {
|
||||
log_error("Volume group \"%s\" doesn't exist", vg_name_from);
|
||||
goto error;
|
||||
}
|
||||
@ -178,6 +150,14 @@ int vgmerge_single(struct cmd_context *cmd, const char *vg_name_to,
|
||||
list_del(lvh);
|
||||
list_add(&vg_to->lvs, lvh);
|
||||
}
|
||||
|
||||
while (!list_empty(&vg_from->fid->metadata_areas)) {
|
||||
struct list *mdah = vg_from->fid->metadata_areas.n;
|
||||
|
||||
list_del(mdah);
|
||||
list_add(&vg_to->fid->metadata_areas, mdah);
|
||||
}
|
||||
|
||||
vg_to->lv_count += vg_from->lv_count;
|
||||
|
||||
vg_to->extent_count += vg_from->extent_count;
|
||||
@ -205,3 +185,27 @@ int vgmerge_single(struct cmd_context *cmd, const char *vg_name_to,
|
||||
unlock_vg(cmd, vg_name_to);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
int vgmerge(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
char *vg_name_to;
|
||||
int opt = 0;
|
||||
int ret = 0, ret_max = 0;
|
||||
|
||||
if (argc < 2) {
|
||||
log_error("Please enter 2 or more volume groups to merge");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
vg_name_to = argv[0];
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
for (; opt < argc; opt++) {
|
||||
ret = vgmerge_single(cmd, vg_name_to, argv[opt]);
|
||||
if (ret > ret_max)
|
||||
ret_max = ret;
|
||||
}
|
||||
|
||||
return ret_max;
|
||||
}
|
||||
|
180
tools/vgreduce.c
180
tools/vgreduce.c
@ -20,97 +20,9 @@
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
static int vgreduce_single(struct cmd_context *cmd, struct volume_group *vg,
|
||||
struct physical_volume *pv);
|
||||
|
||||
int vgreduce(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
struct volume_group *vg;
|
||||
char *vg_name;
|
||||
int ret;
|
||||
|
||||
if (!argc) {
|
||||
log_error("Please give volume group name and "
|
||||
"physical volume paths");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (argc == 1 && !arg_count(cmd, all_ARG)) {
|
||||
log_error("Please enter physical volume paths or option -a");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (argc > 1 && arg_count(cmd, all_ARG)) {
|
||||
log_error("Option -a and physical volume paths mutually "
|
||||
"exclusive");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (!driver_is_loaded())
|
||||
return ECMD_FAILED;
|
||||
|
||||
vg_name = argv[0];
|
||||
argv++;
|
||||
argc--;
|
||||
|
||||
log_verbose("Finding volume group \"%s\"", vg_name);
|
||||
if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) {
|
||||
log_error("Can't get lock for %s", vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!(vg = vg_read(cmd, vg_name))) {
|
||||
log_error("Volume group \"%s\" doesn't exist", vg_name);
|
||||
unlock_vg(cmd, vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (vg->status & EXPORTED_VG) {
|
||||
log_error("Volume group \"%s\" is exported", vg->name);
|
||||
unlock_vg(cmd, vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!(vg->status & LVM_WRITE)) {
|
||||
log_error("Volume group \"%s\" is read-only", vg_name);
|
||||
unlock_vg(cmd, vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!(vg->status & RESIZEABLE_VG)) {
|
||||
log_error("Volume group \"%s\" is not reducable", vg_name);
|
||||
unlock_vg(cmd, vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
/* FIXME: Pass private structure through to all these functions */
|
||||
/* and update in batch here? */
|
||||
ret = process_each_pv(cmd, argc, argv, vg, vgreduce_single);
|
||||
|
||||
unlock_vg(cmd, vg_name);
|
||||
|
||||
return ret;
|
||||
|
||||
/******* FIXME
|
||||
log_error ("no empty physical volumes found in volume group \"%s\"", vg_name);
|
||||
|
||||
log_verbose
|
||||
("volume group \"%s\" will be reduced by %d physical volume%s",
|
||||
vg_name, np, np > 1 ? "s" : "");
|
||||
log_verbose ("reducing volume group \"%s\" by physical volume \"%s\"",
|
||||
vg_name, pv_names[p]);
|
||||
|
||||
log_print
|
||||
("volume group \"%s\" %ssuccessfully reduced by physical volume%s:",
|
||||
vg_name, error > 0 ? "NOT " : "", p > 1 ? "s" : "");
|
||||
log_print("%s", pv_this[p]->pv_name);
|
||||
********/
|
||||
|
||||
}
|
||||
|
||||
/* Or take pv_name instead? */
|
||||
static int vgreduce_single(struct cmd_context *cmd, struct volume_group *vg,
|
||||
struct physical_volume *pv)
|
||||
struct physical_volume *pv, void *handle)
|
||||
{
|
||||
struct pv_list *pvl;
|
||||
const char *name = dev_name(pv->dev);
|
||||
@ -120,12 +32,6 @@ static int vgreduce_single(struct cmd_context *cmd, struct volume_group *vg,
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
/********* FIXME: Is this unnecessary after checking pe_alloc_count?
|
||||
if (pv->lv_cur > 0) {
|
||||
log_error ("can't reduce volume group \"%s\" by used physical volume \"%s\"", vg_name, error_pv_name);
|
||||
}
|
||||
*********/
|
||||
|
||||
if (vg->pv_count == 1) {
|
||||
log_error("Can't remove final physical volume \"%s\" from "
|
||||
"volume group \"%s\"", name, vg->name);
|
||||
@ -153,7 +59,7 @@ static int vgreduce_single(struct cmd_context *cmd, struct volume_group *vg,
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!pv_write(cmd, pv)) {
|
||||
if (!pv_write(cmd, pv, NULL, -1)) {
|
||||
log_error("Failed to clear metadata from physical "
|
||||
"volume \"%s\" "
|
||||
"after removal from \"%s\"", name, vg->name);
|
||||
@ -166,3 +72,85 @@ static int vgreduce_single(struct cmd_context *cmd, struct volume_group *vg,
|
||||
|
||||
return 0;
|
||||
}
|
||||
int vgreduce(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
struct volume_group *vg;
|
||||
char *vg_name;
|
||||
int ret;
|
||||
int consistent = 1;
|
||||
|
||||
if (!argc) {
|
||||
log_error("Please give volume group name and "
|
||||
"physical volume paths");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (argc == 1 && !arg_count(cmd, all_ARG)) {
|
||||
log_error("Please enter physical volume paths or option -a");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (argc > 1 && arg_count(cmd, all_ARG)) {
|
||||
log_error("Option -a and physical volume paths mutually "
|
||||
"exclusive");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
vg_name = argv[0];
|
||||
argv++;
|
||||
argc--;
|
||||
|
||||
log_verbose("Finding volume group \"%s\"", vg_name);
|
||||
if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) {
|
||||
log_error("Can't get lock for %s", vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!(vg = vg_read(cmd, vg_name, &consistent)) || !consistent) {
|
||||
log_error("Volume group \"%s\" doesn't exist", vg_name);
|
||||
unlock_vg(cmd, vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (vg->status & EXPORTED_VG) {
|
||||
log_error("Volume group \"%s\" is exported", vg->name);
|
||||
unlock_vg(cmd, vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!(vg->status & LVM_WRITE)) {
|
||||
log_error("Volume group \"%s\" is read-only", vg_name);
|
||||
unlock_vg(cmd, vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!(vg->status & RESIZEABLE_VG)) {
|
||||
log_error("Volume group \"%s\" is not reducable", vg_name);
|
||||
unlock_vg(cmd, vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
/* FIXME: Pass private structure through to all these functions */
|
||||
/* and update in batch here? */
|
||||
ret = process_each_pv(cmd, argc, argv, vg, NULL, vgreduce_single);
|
||||
|
||||
unlock_vg(cmd, vg_name);
|
||||
|
||||
return ret;
|
||||
|
||||
/******* FIXME
|
||||
log_error ("no empty physical volumes found in volume group \"%s\"", vg_name);
|
||||
|
||||
log_verbose
|
||||
("volume group \"%s\" will be reduced by %d physical volume%s",
|
||||
vg_name, np, np > 1 ? "s" : "");
|
||||
log_verbose ("reducing volume group \"%s\" by physical volume \"%s\"",
|
||||
vg_name, pv_names[p]);
|
||||
|
||||
log_print
|
||||
("volume group \"%s\" %ssuccessfully reduced by physical volume%s:",
|
||||
vg_name, error > 0 ? "NOT " : "", p > 1 ? "s" : "");
|
||||
log_print("%s", pv_this[p]->pv_name);
|
||||
********/
|
||||
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user