1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-22 17:35:59 +03:00

Some new features.

This commit is contained in:
Alasdair Kergon 2002-11-18 14:04:08 +00:00
parent 81c44790d5
commit 34dd8d0a91
104 changed files with 6297 additions and 4468 deletions

21
INSTALL
View File

@ -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
View File

@ -1,18 +0,0 @@
An introduction to LVM2
=======================
Background
Compatibility with LVM1
New features
Missing features
Future enhancements

View File

@ -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
View File

@ -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
View File

@ -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

View File

@ -1 +1 @@
1.95.10-cvs (2002-05-31)
1.95.11-cvs (2002-11-18)

86
WHATS_NEW Normal file
View 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
View File

@ -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 \

View File

@ -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 \

View File

@ -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" ]
#}

View File

@ -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

View File

@ -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

View File

@ -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(" ");
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}

View 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
View 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

View File

@ -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
]
}
}
}

View 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;
}

View File

@ -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, &sector))) {
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, &sector))) {
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;
}

View File

@ -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

View File

@ -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, &sectsize))
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, &sectsize))
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, &sectsize))
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, &sectsize))
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);
}

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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(&current->list);

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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'`; \

View File

@ -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

View File

@ -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),

View File

@ -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),

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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),

View File

@ -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.

View File

@ -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)"

View File

@ -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
View 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)

View File

@ -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),

View File

@ -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
View 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)

View File

@ -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
View 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)"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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.

View File

@ -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".

View File

@ -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
View 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

View File

@ -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 \

View File

@ -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;
}

View File

@ -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

View File

@ -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)

View File

@ -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"

View File

@ -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);
}

View File

@ -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;

View File

@ -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);
}

File diff suppressed because it is too large Load Diff

View File

@ -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));

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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, &sector))) {
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;
}

View File

@ -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);
}

View File

@ -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
View 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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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
View 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);
}

View File

@ -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)))

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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