summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--INSTALL21
-rw-r--r--INTRO18
-rw-r--r--Makefile.in3
-rw-r--r--README4
-rw-r--r--TODO28
-rw-r--r--VERSION2
-rw-r--r--WHATS_NEW86
-rwxr-xr-xconfigure196
-rw-r--r--configure.in22
-rw-r--r--doc/example.conf156
-rw-r--r--include/.symlinks9
-rw-r--r--lib/Makefile.in32
-rw-r--r--lib/format_text/archive.c24
-rw-r--r--lib/format_text/export.c512
-rw-r--r--lib/format_text/flags.c41
-rw-r--r--lib/format_text/format-text.c1484
-rw-r--r--lib/format_text/format-text.h29
-rw-r--r--lib/format_text/import-export.h32
-rw-r--r--lib/format_text/import.c761
-rw-r--r--lib/format_text/import_vsn1.c735
-rw-r--r--lib/format_text/layout.h76
-rw-r--r--lib/format_text/sample.vg67
-rw-r--r--lib/format_text/text_label.c280
-rw-r--r--lib/label/label.c254
-rw-r--r--lib/label/label.h62
-rw-r--r--lib/label/lvm2_label.c569
-rw-r--r--lib/label/lvm2_label.h27
-rw-r--r--lib/label/uuid-map.c99
-rw-r--r--lib/label/uuid-map.h29
-rw-r--r--lib/metadata/lv_manip.c37
-rw-r--r--lib/metadata/merge.c10
-rw-r--r--lib/metadata/metadata.c427
-rw-r--r--lib/metadata/metadata.h339
-rw-r--r--lib/metadata/pv_map.c8
-rw-r--r--lib/metadata/snapshot_manip.c12
-rw-r--r--make.tmpl.in22
-rw-r--r--man/Makefile.in5
-rw-r--r--man/lvchange.820
-rw-r--r--man/lvcreate.818
-rw-r--r--man/lvdisplay.814
-rw-r--r--man/lvextend.819
-rw-r--r--man/lvm.854
-rw-r--r--man/lvmchange.83
-rw-r--r--man/lvreduce.88
-rw-r--r--man/lvremove.89
-rw-r--r--man/lvrename.87
-rw-r--r--man/lvscan.87
-rw-r--r--man/pvchange.86
-rw-r--r--man/pvcreate.867
-rw-r--r--man/pvdisplay.82
-rw-r--r--man/pvremove.822
-rw-r--r--man/pvscan.83
-rw-r--r--man/vgcfgbackup.810
-rw-r--r--man/vgcfgrestore.823
-rw-r--r--man/vgchange.814
-rw-r--r--man/vgconvert.838
-rw-r--r--man/vgcreate.82
-rw-r--r--man/vgdisplay.88
-rw-r--r--man/vgextend.89
-rw-r--r--man/vgmerge.85
-rw-r--r--man/vgreduce.86
-rw-r--r--man/vgremove.82
-rw-r--r--man/vgrename.86
-rw-r--r--man/vgscan.85
-rwxr-xr-xscripts/vg_convert19
-rw-r--r--tools/Makefile.in2
-rw-r--r--tools/archive.c160
-rw-r--r--tools/archive.h5
-rw-r--r--tools/args.h6
-rw-r--r--tools/commands.h85
-rw-r--r--tools/lvchange.c221
-rw-r--r--tools/lvcreate.c71
-rw-r--r--tools/lvdisplay.c11
-rw-r--r--tools/lvm.c889
-rw-r--r--tools/lvmdiskscan.c4
-rw-r--r--tools/lvremove.c31
-rw-r--r--tools/lvrename.c17
-rw-r--r--tools/lvresize.c16
-rw-r--r--tools/lvscan.c82
-rw-r--r--tools/pvchange.c157
-rw-r--r--tools/pvcreate.c117
-rw-r--r--tools/pvdisplay.c105
-rw-r--r--tools/pvremove.c128
-rw-r--r--tools/pvscan.c178
-rw-r--r--tools/stub.h2
-rw-r--r--tools/toollib.c212
-rw-r--r--tools/toollib.h32
-rw-r--r--tools/tools.h62
-rw-r--r--tools/vgcfgbackup.c51
-rw-r--r--tools/vgcfgrestore.c18
-rw-r--r--tools/vgchange.c142
-rw-r--r--tools/vgck.c31
-rw-r--r--tools/vgconvert.c185
-rw-r--r--tools/vgcreate.c5
-rw-r--r--tools/vgdisplay.c88
-rw-r--r--tools/vgexport.c47
-rw-r--r--tools/vgextend.c6
-rw-r--r--tools/vgimport.c44
-rw-r--r--tools/vgmerge.c68
-rw-r--r--tools/vgreduce.c118
-rw-r--r--tools/vgremove.c52
-rw-r--r--tools/vgrename.c37
-rw-r--r--tools/vgscan.c48
-rw-r--r--tools/vgsplit.c26
104 files changed, 6156 insertions, 4327 deletions
diff --git a/INSTALL b/INSTALL
index 8c9e33bb..93259a06 100644
--- a/INSTALL
+++ b/INSTALL
@@ -6,8 +6,8 @@ LVM2 installation
Ensure the device-mapper has been installed on the machine.
The device-mapper should be in the kernel (look for 'device-mapper'
- messages in the kernel logs) and /usr/include/libdevmapper.h should
- be present.
+ messages in the kernel logs) and /usr/include/libdevmapper.h
+ and libdevmapper.so should be present.
The device-mapper is available from:
ftp://ftp.sistina.com/pub/LVM2/device-mapper/
@@ -17,9 +17,15 @@ LVM2 installation
Run the 'configure' script from the top directory.
- If you do not have GNU readline (http://www.gnu.org/directory/readline.html)
- installed use
- ./configure --disable-readline
+ If you wish to use the built-in LVM2 shell and have GNU readline
+ installed (http://www.gnu.org/directory/readline.html) use:
+ ./configure --enable-readline
+
+ If you don't want to include the LVM1 backwards-compatibility code use:
+ ./configure --with-lvm1=none
+
+ To separate the LVM1 support into a shared library loaded by lvm.conf use:
+ ./configure --with-lvm1=shared
3) Build and install LVM2.
@@ -31,6 +37,9 @@ LVM2 installation
The tools will work fine without a configuration file being
present, but you ought to review the example file in doc/example.conf.
- For example, specifying the devices that LVM2 is to use should
+ For example, specifying the devices that LVM2 is to use can
make the tools run more efficiently - and avoid scanning /dev/cdrom!
+Please also refer to the WHATS_NEW file and the manual pages for the
+individual commands.
+
diff --git a/INTRO b/INTRO
deleted file mode 100644
index bc54a164..00000000
--- a/INTRO
+++ /dev/null
@@ -1,18 +0,0 @@
-An introduction to LVM2
-=======================
-
-Background
-
-
-Compatibility with LVM1
-
-
-New features
-
-
-Missing features
-
-
-Future enhancements
-
-
diff --git a/Makefile.in b/Makefile.in
index ef815a4e..ed1fd7ca 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -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
diff --git a/README b/README
index 9cf704d0..c66c11f1 100644
--- a/README
+++ b/README
@@ -1,10 +1,10 @@
-This directory contains a beta release of LMV2, the new version of
+This directory contains a beta release of LVM2, the new version of
the userland LVM tools designed for the new device-mapper for
the Linux kernel.
The device-mapper needs to be installed before compiling these LVM2 tools.
-For more information about LVM2 read the INTRO file.
+For more information about LVM2 read the WHATS_NEW file.
Installation instructions are in INSTALL.
This is beta-quality software, released for testing purposes only.
diff --git a/TODO b/TODO
deleted file mode 100644
index c3862f2a..00000000
--- a/TODO
+++ /dev/null
@@ -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
diff --git a/VERSION b/VERSION
index 25c80ade..146b0f6a 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.95.10-cvs (2002-05-31)
+1.95.11-cvs (2002-11-18)
diff --git a/WHATS_NEW b/WHATS_NEW
new file mode 100644
index 00000000..26c8fd34
--- /dev/null
+++ b/WHATS_NEW
@@ -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!
+
+
diff --git a/configure b/configure
index 8b891dee..31c584d5 100755
--- a/configure
+++ b/configure
@@ -17,12 +17,15 @@ ac_help="$ac_help
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 \
diff --git a/configure.in b/configure.in
index c95e8c6f..28f87b80 100644
--- a/configure.in
+++ b/configure.in
@@ -61,15 +61,29 @@ AC_ARG_WITH(group,
[ GROUP="$withval" ],
[ GROUP="root" ])
+dnl -- format1 inclusion type
+AC_ARG_WITH(lvm1,
+ [ --with-lvm1=TYPE LVM1 metadata support: internal/shared/none
+ [TYPE=internal] ],
+ [ LVM1="$withval" ],
+ [ LVM1="internal" ])
+
+if [[ "x$LVM1" != xnone -a "x$LVM1" != xinternal -a "x$LVM1" != xshared ]];
+ then AC_MSG_ERROR(
+--with-lvm1 parameter invalid
+)
+ exit
+fi;
+
AC_ARG_ENABLE(jobs, [ --enable-jobs=NUM Number of jobs to run simultaneously], JOBS=-j$enableval, JOBS=)
dnl Enables staticly linked tools
AC_ARG_ENABLE(static_link, [ --enable-static_link Use this to link the tools to the liblvm library
statically. Default is dynamic linking], STATIC_LINK=$enableval, STATIC_LINK=no)
-dnl Disable readline
-AC_ARG_ENABLE(readline, [ --disable-readline Disable readline support], \
-READLINE=$enableval, READLINE=yes)
+dnl Enable readline
+AC_ARG_ENABLE(readline, [ --enable-readline Enable readline support], \
+READLINE=$enableval, READLINE=no)
dnl Mess with default exec_prefix
if [[ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ]];
@@ -125,6 +139,7 @@ fi
AC_SUBST(JOBS)
AC_SUBST(STATIC_LINK)
AC_SUBST(READLINE)
+AC_SUBST(LVM1)
AC_SUBST(HAVE_RL_COMPLETION_MATCHES)
AC_SUBST(OWNER)
AC_SUBST(GROUP)
@@ -137,6 +152,7 @@ Makefile \
make.tmpl \
include/Makefile \
lib/Makefile \
+lib/format1/Makefile \
man/Makefile \
tools/Makefile \
tools/version.h \
diff --git a/doc/example.conf b/doc/example.conf
index 60554a83..df97131b 100644
--- a/doc/example.conf
+++ b/doc/example.conf
@@ -1,24 +1,25 @@
-# This is an example configuration file for the LVM2 system. It
-# contains the default settings that would be used if there was no
+# This is an example configuration file for the LVM2 system.
+# It contains the default settings that would be used if there was no
# /etc/lvm/lvm.conf file.
-# Refer to 'man lvm.conf' for further information.
+#
+# Refer to 'man lvm.conf' for further information including the file layout.
+#
+# To put this file in a different directory and override /etc/lvm set
+# the environment variable LVM_SYSTEM_DIR before running the tools.
-# This section allows the user to configure which block devices should
+# This section allows you to configure which block devices should
# be used by the LVM system.
devices {
- # where do you want your volume groups to appear ?
+ # Where do you want your volume groups to appear ?
dir = "/dev"
# An array of directories that contain the device nodes you wish
# to use with LVM2.
- scan = "/dev"
-
- # A very important option, that allows you to tune the LVM2 system
- # to just look at a restricted set of devices that you're
- # interested in.
+ scan = [ "/dev" ]
+ # A filter that tells LVM2 to only use a restricted set of devices.
# The filter consists of an array of regular expressions. These
# expressions can be delimited by a character of your choice, and
# prefixed with either an 'a' (for accept) or 'r' (for reject).
@@ -26,51 +27,56 @@ devices {
# Remember to run vgscan after you change this parameter.
# By default we accept every block device:
- filter = "a/.*/"
+ filter = [ "a/.*/" ]
+
+ # Exclude the cdrom drive
+ # filter = [ "r|/dev/cdrom|" ]
# When testing I like to work with just loopback devices:
- # filter = ["a/loop/", "r/.*/"]
+ # filter = [ "a/loop/", "r/.*/" ]
# Or maybe all loops and ide drives except hdc:
- # filter =["a|loop|", "r|/dev/hdc|", "a|/dev/ide|", "r|.*|"]
+ # filter =[ "a|loop|", "r|/dev/hdc|", "a|/dev/ide|", "r|.*|" ]
# Use anchors if you want to be really specific
- # filter = ["a|^/dev/hda8$|", "r/.*/"]
+ # filter = [ "a|^/dev/hda8$|", "r/.*/" ]
- # The results of all the filtering are cached on disk to avoid
+ # The results of the filtering are cached on disk to avoid
# rescanning dud devices (which can take a very long time). By
- # default this cache file is hidden in the /etc/lvm directory, it
- # is human readable to aid filter debugging.
+ # default this cache file is hidden in the /etc/lvm directory.
+ # It is safe to delete this file. vgscan regenerates it.
cache = "/etc/lvm/.cache"
# You can turn off writing this cache file by setting this to 0.
write_cache_state = 1
}
-# A section that allows the user to configure the nature of the
+# This section that allows you to configure the nature of the
# information that LVM2 reports.
log {
- # Where should the log of error and debug messages go ? By
- # default there is no log.
- #file = "/var/log/lvm2.log"
-
- # Should we overwrite the last log. By default we append.
- overwrite = 0
-
- # There are 9 log levels, with 9 being the most verbose.
- level = 3
-
- # Controls the messages sent to stdout or stderr while running
- # LVM2. There are three levels of verbosity, 3 being the most
- # verbose.
+ # Controls the messages sent to stdout or stderr.
+ # There are three levels of verbosity, 3 being the most verbose.
verbose = 0
# Should we send log messages through syslog?
# 1 is yes; 0 is no.
syslog = 1
- # Choose format of output messages
+ # Should we log error and debug messages to a file?
+ # By default there is no log file.
+ #file = "/var/log/lvm2.log"
+
+ # Should we overwrite the log file each time the program is run?
+ # By default we append.
+ overwrite = 0
+
+ # What level of log messages should we send to the log file and/or syslog?
+ # There are 6 syslog-like log levels currently in use - 2 to 7 inclusive.
+ # 7 is the most verbose (LOG_DEBUG).
+ level = 0
+
+ # Format of output messages
# Whether or not (1 or 0) to indent messages according to their severity
indent = 1
@@ -78,10 +84,11 @@ log {
command_names = 0
# A prefix to use before the message text (but after the command name,
- # if selected)
+ # if selected). Default is two spaces, so you can see/grep the severity
+ # of each message.
prefix = " "
- # To make the messages look similar to the original LVM use:
+ # To make the messages look similar to the original LVM tools use:
# indent = 0
# command_names = 1
# prefix = " -- "
@@ -95,19 +102,20 @@ backup {
# Should we maintain a backup of the current metadata configuration ?
# Use 1 for Yes; 0 for No.
- # Think very hard before turning this off.
+ # Think very hard before turning this off!
backup = 1
# Where shall we keep it ?
+ # Remember to back up this directory regularly!
backup_dir = "/etc/lvm/backup"
-
# Should we maintain an archive of old metadata configurations.
# Use 1 for Yes; 0 for No.
# On by default. Think very hard before turning this off.
archive = 1
# Where should archived files go ?
+ # Remember to back up this directory regularly!
archive_dir = "/etc/lvm/archive"
# What is the minimum number of archive files you wish to keep ?
@@ -117,20 +125,15 @@ backup {
retain_days = 30
}
-# Settings for the running LVM2 in shell mode.
+# Settings for the running LVM2 in shell (readline) mode.
shell {
# Number of lines of history to store in ~/.lvm_history
history_size = 100
}
-# Metadata settings
-metadata {
- # List of directories holding copies of text format metadata
- dirs = [ "/etc/lvm/metadata" ]
-}
-# Miscellaneous global settings
+# Miscellaneous global LVM2 settings
global {
# The file creation mask for any files and directories created.
@@ -145,10 +148,73 @@ global {
# command. Defaults to off.
test = 0
- # Default metadata format commands use - "lvm1" (default) or "text"
- format = "lvm1"
+ # Whether or not to communicate with the kernel device-mapper.
+ # Set to 0 if you want to use the tools to manipulate LVM metadata
+ # without activating any logical volumes.
+ # If the device-mapper kernel driver is not present in your kernel
+ # setting this to 0 should suppress the error messages.
+ activation = 1
+
+ # The default metadata format that commands should use - "lvm1" or "lvm2".
+ # The command line override is -M1 or -M2.
+ # Defaults to "lvm1" if compiled in, else "lvm2".
+ # format = "lvm1"
# Location of proc filesystem
proc = "/proc"
+
+ # Type of locking to use. Defaults to file-based locking (1).
+ # Turn locking off by setting to 0 (dangerous: risks metadata corruption
+ # if LVM2 commands get run concurrently).
+ locking_type = 1
+
+ # Local non-LV directory that holds file-based locks while commands are
+ # in progress. A directory like /tmp that may get wiped on reboot is OK.
+ locking_dir = "/var/lock/lvm"
+
+ # Other entries can go here to allow you to load shared libraries
+ # e.g. if support for LVM1 metadata was compiled as a shared library use
+ # format_libraries = "liblvm2format1.so"
+ # Full pathnames can be given.
+
+ # Search this directory first for shared libraries.
+ # library_dir = "/lib"
}
+
+####################
+# Advanced section #
+####################
+
+# Metadata settings
+#
+# metadata {
+ # Default number of copies of metadata to hold on each PV. 0, 1 or 2.
+ # It's best to leave this at 2.
+ # You might want to override it from the command line with 0 or 1
+ # when running pvcreate on new PVs which are to be added to large VGs.
+
+ # pvmetadatacopies = 2
+
+ # Approximate default size of on-disk metadata areas in sectors.
+ # You should increase this if you have large volume groups or
+ # you want to retain a large on-disk history of your metadata changes.
+
+ # pvmetadatasize = 255
+
+ # List of directories holding live copies of text format metadata.
+ # These directories must not be on logical volumes!
+ # It's possible to use LVM2 with a couple of directories here,
+ # preferably on different (non-LV) filesystems, and with no other
+ # on-disk metadata (pvmetadatacopies = 0). Or this can be in
+ # addition to on-disk metadata areas.
+ # The feature was originally added to simplify testing.
+ #
+ # Never edit any files in these directories by hand unless you
+ # you are absolutely sure you know what you are doing! Use
+ # the supplied toolset to make changes (e.g. vgcfgrestore).
+
+ # dirs = [ "/etc/lvm/metadata", "/mnt/disk2/lvm/metadata2" ]
+#}
+
+
diff --git a/include/.symlinks b/include/.symlinks
index 681709e9..dc1449c4 100644
--- a/include/.symlinks
+++ b/include/.symlinks
@@ -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
diff --git a/lib/Makefile.in b/lib/Makefile.in
index f3842ca5..d208a2e7 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -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
diff --git a/lib/format_text/archive.c b/lib/format_text/archive.c
index 100ff9a9..f2397d26 100644
--- a/lib/format_text/archive.c
+++ b/lib/format_text/archive.c
@@ -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(" ");
}
diff --git a/lib/format_text/export.c b/lib/format_text/export.c
index a9554068..8c7e5457 100644
--- a/lib/format_text/export.c
+++ b/lib/format_text/export.c
@@ -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));
-
- _out(f, CONTENTS_FIELD " = \"" CONTENTS_VALUE "\"");
- _out(f, FORMAT_VERSION_FIELD " = %d\n", FORMAT_VERSION_VALUE);
+ _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, "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);
+ _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;
+ }
_dec_indent(f);
- _out(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 stripe_segment *seg)
+ int count, struct lv_segment *seg)
{
int s;
const char *name;
- _out(f, "segment%u {", count);
+ _outf(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);
+ _outf(f, "start_extent = %u", seg->le);
+ if (!_out_size(f, seg->len * vg->extent_size, "extent_count = %u",
+ seg->len)) {
+ stack;
+ return 0;
+ }
- if (seg->stripes > 1)
- _out_size(f, seg->stripe_size,
- "stripe_size = %u", seg->stripe_size);
+ f->nl(f);
+ _outf(f, "type = \"%s\"", get_segtype_string(seg->type));
- _nl(f);
- _out(f, "areas = [");
- _inc_indent(f);
+ switch (seg->type) {
+ case SEG_STRIPED:
+ _outf(f, "stripe_count = %u%s", seg->stripes,
+ (seg->stripes == 1) ? "\t# linear" : "");
- for (s = 0; s < seg->stripes; s++) {
- if (!(name = _get_pv_name(f, seg->area[s].pv))) {
- stack;
- return 0;
+ 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) ? "" : ",");
}
- _out(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, "]");
-
- _dec_indent(f);
- _out(f, "}");
+ _outf(f, "}");
return 1;
}
@@ -326,11 +439,75 @@ static int _count_segments(struct logical_volume *lv)
return r;
}
+static int _print_snapshot(struct formatter *f, struct snapshot *snap,
+ unsigned int count)
+{
+ char buffer[256];
+ struct lv_segment seg;
+
+ f->nl(f);
+
+ _outf(f, "snapshot%u {", count);
+ _inc_indent(f);
+
+ if (!id_write_format(&snap->id, buffer, sizeof(buffer))) {
+ stack;
+ return 0;
+ }
+
+ _outf(f, "id = \"%s\"", buffer);
+ if (!print_flags(LVM_READ | LVM_WRITE | VISIBLE_LV, LV_FLAGS,
+ buffer, sizeof(buffer))) {
+ stack;
+ return 0;
+ }
+
+ _outf(f, "status = %s", buffer);
+ _outf(f, "segment_count = 1");
+
+ f->nl(f);
+
+ 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;
+
+ if (!_print_segment(f, snap->origin->vg, 1, &seg)) {
+ stack;
+ return 0;
+ }
+
+ _dec_indent(f);
+ _outf(f, "}");
+
+ return 1;
+}
+
+static int _print_snapshots(struct formatter *f, struct volume_group *vg)
+{
+ struct list *sh;
+ struct snapshot *s;
+ unsigned int count = 0;
+
+ list_iterate(sh, &vg->snapshots) {
+ s = list_item(sh, struct snapshot_list)->snapshot;
+
+ if (!_print_snapshot(f, s, count++)) {
+ stack;
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
static int _print_lvs(struct formatter *f, struct volume_group *vg)
{
struct list *lvh, *segh;
struct logical_volume *lv;
- struct stripe_segment *seg;
+ struct lv_segment *seg;
char buffer[256];
int seg_count;
@@ -340,14 +517,14 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
if (list_empty(&vg->lvs))
return 1;
- _out(f, "logical_volumes {");
+ _outf(f, "logical_volumes {");
_inc_indent(f);
list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
- _nl(f);
- _out(f, "%s {", lv->name);
+ f->nl(f);
+ _outf(f, "%s {", lv->name);
_inc_indent(f);
/* FIXME: Write full lvid */
@@ -356,26 +533,27 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
return 0;
}
- _out(f, "id = \"%s\"", buffer);
+ _outf(f, "id = \"%s\"", buffer);
- if (!print_flags(lv->status, LV_FLAGS,
- buffer, sizeof(buffer))) {
+ if (!print_flags(lv->status, LV_FLAGS, buffer, sizeof(buffer))) {
stack;
return 0;
}
- _out(f, "status = %s", buffer);
- _out(f, "allocation_policy = \"%s\"",
- get_alloc_string(lv->alloc));
- _out(f, "read_ahead = %u", lv->read_ahead);
+ _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)
- _out(f, "minor = %d", lv->minor);
- _out(f, "segment_count = %u", _count_segments(lv));
- _nl(f);
+ _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 stripe_segment);
+ seg = list_item(segh, struct lv_segment);
if (!_print_segment(f, vg, seg_count++, seg)) {
stack;
@@ -384,59 +562,16 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
}
_dec_indent(f);
- _out(f, "}");
+ _outf(f, "}");
}
- _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, "}");
-
- return 1;
-}
-
-static int _print_snapshots(struct formatter *f, struct volume_group *vg)
-{
- struct list *sh;
- 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;
-
- if (!_print_snapshot(f, s, count++)) {
- stack;
- return 0;
- }
+ 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;
-#undef fail
+ if (!f->header && !_print_header(f, vg, desc))
+ fail;
- _dec_indent(f);
- _out(f, "}");
- r = !ferror(f->fp);
+#undef fail
+ 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
diff --git a/lib/format_text/flags.c b/lib/format_text/flags.c
index 080e507d..63f8a479 100644
--- a/lib/format_text/flags.c
+++ b/lib/format_text/flags.c
@@ -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;
- }
+ while (cv) {
+ if (cv->type != CFG_STRING) {
+ log_err("Status value is not a string.");
+ return 0;
+ }
- if (!flags[f].description) {
- log_err("Unknown status flag '%s'.", cv->v.str);
- return 0;
+ for (f = 0; flags[f].description; f++)
+ if (!strcmp(flags[f].description, cv->v.str)) {
+ s |= flags[f].mask;
+ break;
}
- cv = cv->next;
+ if (!flags[f].description) {
+ log_err("Unknown status flag '%s'.", cv->v.str);
+ return 0;
}
+
+ cv = cv->next;
}
+ out:
*status = s;
return 1;
}
diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c
index 076e228e..6f493e5a 100644
--- a/lib/format_text/format-text.c
+++ b/lib/format_text/format-text.c
@@ -4,37 +4,43 @@
* This file is released under the LGPL.
*/
+#include "lib.h"
#include "format-text.h"
#include "import-export.h"
-
+#include "device.h"
#include "lvm-file.h"
-#include "log.h"
#include "pool.h"
#include "config.h"
#include "hash.h"
#include "display.h"
-#include "dbg_malloc.h"
#include "toolcontext.h"
-#include "vgcache.h"
#include "lvm-string.h"
+#include "uuid.h"
+#include "layout.h"
+#include "crc.h"
+#include "xlate.h"
+#include "label.h"
#include <unistd.h>
-#include <sys/types.h>
#include <sys/file.h>
#include <limits.h>
#include <dirent.h>
+#include <ctype.h>
-/* Arbitrary limits copied from format1/disk_rep.h */
-#define MAX_PV 256
-#define MAX_LV 256
-#define MAX_VG 99
-#define MAX_PV_SIZE ((uint32_t) -1) /* 2TB in sectors - 1 */
+static struct format_instance *_create_text_instance(struct format_type *fmt,
+ const char *vgname,
+ void *context);
struct dir_list {
struct list list;
char dir[0];
};
+struct raw_list {
+ struct list list;
+ struct device_area dev_area;
+};
+
struct text_context {
char *path_live; /* Path to file holding live metadata */
char *path_edit; /* Path to file holding edited metadata */
@@ -42,33 +48,13 @@ struct text_context {
};
/*
- * NOTE: Currently there can be only one vg per file.
+ * NOTE: Currently there can be only one vg per text file, and locking
+ * assumes VG's metadata is only held in metadata areas on PVs
+ * inside the VG.
*/
-static int _pv_setup(struct format_instance *fi, struct physical_volume *pv,
- struct volume_group *vg)
+static int _vg_setup(struct format_instance *fid, struct volume_group *vg)
{
- /* setup operations for the PV structure */
- if (pv->size > MAX_PV_SIZE)
- pv->size--;
- if (pv->size > MAX_PV_SIZE) {
- /* FIXME Limit hardcoded */
- log_error("Physical volumes cannot be bigger than 2TB");
- return 0;
- }
-
- return 1;
-}
-
-static int _vg_setup(struct format_instance *fi, struct volume_group *vg)
-{
- /* just check max_pv and max_lv */
- if (vg->max_lv >= MAX_LV)
- vg->max_lv = MAX_LV - 1;
-
- if (vg->max_pv >= MAX_PV)
- vg->max_pv = MAX_PV - 1;
-
if (vg->extent_size & (vg->extent_size - 1)) {
log_error("Extent size must be power of 2");
return 0;
@@ -77,7 +63,7 @@ static int _vg_setup(struct format_instance *fi, struct volume_group *vg)
return 1;
}
-static int _lv_setup(struct format_instance *fi, struct logical_volume *lv)
+static int _lv_setup(struct format_instance *fid, struct logical_volume *lv)
{
uint64_t max_size = UINT_MAX;
@@ -94,16 +80,440 @@ static int _lv_setup(struct format_instance *fi, struct logical_volume *lv)
return 1;
}
-static struct volume_group *_vg_read(struct format_instance *fi,
- const char *vgname, void *mdl)
+static void _xlate_mdah(struct mda_header *mdah)
+{
+ struct raw_locn *rl;
+
+ mdah->version = xlate32(mdah->version);
+ mdah->start = xlate64(mdah->start);
+ mdah->size = xlate64(mdah->size);
+
+ rl = &mdah->raw_locns[0];
+ while (rl->offset) {
+ rl->checksum = xlate32(rl->checksum);
+ rl->offset = xlate64(rl->offset);
+ rl->size = xlate64(rl->size);
+ rl++;
+ }
+}
+
+static struct mda_header *_raw_read_mda_header(struct format_type *fmt,
+ struct device_area *dev_area)
+{
+ struct mda_header *mdah;
+
+ if (!(mdah = pool_alloc(fmt->cmd->mem, MDA_HEADER_SIZE))) {
+ log_error("struct mda_header allocation failed");
+ return NULL;
+ }
+
+ if (dev_read(dev_area->dev, dev_area->start, MDA_HEADER_SIZE, mdah) !=
+ MDA_HEADER_SIZE) {
+ stack;
+ pool_free(fmt->cmd->mem, mdah);
+ return NULL;
+ }
+
+ if (mdah->checksum_xl != xlate32(calc_crc(INITIAL_CRC, mdah->magic,
+ MDA_HEADER_SIZE -
+ sizeof(mdah->checksum_xl)))) {
+ log_error("Incorrect metadata area header checksum");
+ return NULL;
+ }
+
+ _xlate_mdah(mdah);
+
+ if (strncmp(mdah->magic, FMTT_MAGIC, sizeof(mdah->magic))) {
+ log_error("Wrong magic number in metadata area header");
+ return NULL;
+ }
+
+ if (mdah->version != FMTT_VERSION) {
+ log_error("Incompatible metadata area header version: %d",
+ mdah->version);
+ return NULL;
+ }
+
+ if (mdah->start != dev_area->start) {
+ log_error("Incorrect start sector in metadata area header: %"
+ PRIu64, mdah->start);
+ return NULL;
+ }
+
+ return mdah;
+}
+
+static int _raw_write_mda_header(struct format_type *fmt,
+ struct device *dev,
+ uint64_t start_byte, struct mda_header *mdah)
+{
+ strncpy(mdah->magic, FMTT_MAGIC, sizeof(mdah->magic));
+ mdah->version = FMTT_VERSION;
+ mdah->start = start_byte;
+
+ _xlate_mdah(mdah);
+ mdah->checksum_xl = xlate32(calc_crc(INITIAL_CRC, mdah->magic,
+ MDA_HEADER_SIZE -
+ sizeof(mdah->checksum_xl)));
+
+ if (dev_write(dev, start_byte, MDA_HEADER_SIZE, mdah)
+ != MDA_HEADER_SIZE) {
+ stack;
+ pool_free(fmt->cmd->mem, mdah);
+ return 0;
+ }
+
+ return 1;
+}
+
+static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area,
+ struct mda_header *mdah,
+ const char *vgname)
+{
+ int len;
+ char vgnamebuf[NAME_LEN + 2];
+ struct raw_locn *rlocn;
+
+ rlocn = mdah->raw_locns;
+
+ /* FIXME Ignore if checksum incorrect!!! */
+ while (rlocn->offset) {
+ if (dev_read(dev_area->dev, dev_area->start + rlocn->offset,
+ sizeof(vgnamebuf), vgnamebuf)
+ != sizeof(vgnamebuf)) {
+ stack;
+ return NULL;
+ }
+ if (!strncmp(vgnamebuf, vgname, len = strlen(vgname)) &&
+ (isspace(vgnamebuf[len]) || vgnamebuf[len] == '{')) {
+ return rlocn;
+ }
+ rlocn++;
+ }
+
+ return NULL;
+}
+
+static struct raw_locn *_vg_posn(struct format_instance *fid,
+ struct device_area *dev_area,
+ const char *vgname)
+{
+
+ struct mda_header *mdah;
+
+ if (!(mdah = _raw_read_mda_header(fid->fmt, dev_area))) {
+ stack;
+ return NULL;
+ }
+
+ return _find_vg_rlocn(dev_area, mdah, vgname);
+}
+
+static int _raw_holds_vgname(struct format_instance *fid,
+ struct device_area *dev_area, const char *vgname)
+{
+ int r = 0;
+
+ if (!dev_open(dev_area->dev, O_RDONLY)) {
+ stack;
+ return 0;
+ }
+
+ if (_vg_posn(fid, dev_area, vgname))
+ r = 1;
+
+ if (!dev_close(dev_area->dev))
+ stack;
+
+ return r;
+}
+
+static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
+ const char *vgname,
+ struct device_area *area)
+{
+ struct volume_group *vg = NULL;
+ struct raw_locn *rlocn;
+ struct mda_header *mdah;
+ time_t when;
+ char *desc;
+ uint64_t wrap = 0;
+
+ if (!dev_open(area->dev, O_RDONLY)) {
+ stack;
+ return NULL;
+ }
+
+ if (!(mdah = _raw_read_mda_header(fid->fmt, area))) {
+ stack;
+ goto out;
+ }
+
+ if (!(rlocn = _vg_posn(fid, area, vgname))) {
+ stack;
+ goto out;
+ }
+
+ if (rlocn->offset + rlocn->size > mdah->size)
+ wrap = (rlocn->offset + rlocn->size) - mdah->size;
+
+ if (wrap > rlocn->offset) {
+ log_error("VG %s metadata too large for circular buffer",
+ vg->name);
+ goto out;
+ }
+
+ if (!(vg = text_vg_import_fd(fid, dev_name(area->dev),
+ dev_fd(area->dev),
+ area->start + rlocn->offset,
+ rlocn->size - wrap,
+ area->start + MDA_HEADER_SIZE, wrap,
+ calc_crc, rlocn->checksum, &when,
+ &desc))) {
+ stack;
+ goto out;
+ }
+
+ out:
+ if (!dev_close(area->dev))
+ stack;
+
+ return vg;
+}
+
+static struct volume_group *_vg_read_raw(struct format_instance *fid,
+ const char *vgname,
+ struct metadata_area *mda)
+{
+ struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
+
+ return _vg_read_raw_area(fid, vgname, &mdac->area);
+}
+
+static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
+ struct metadata_area *mda)
+{
+ struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
+ struct raw_locn *rlocn;
+ struct mda_header *mdah;
+ struct physical_volume *pv;
+ struct list *pvh;
+ int r = 0;
+ uint64_t new_wrap = 0, old_wrap = 0;
+
+ /* FIXME Essential fix! Make dynamic (realloc? pool?) */
+ char buf[65536];
+ int found = 0;
+
+ /* Ignore any mda on a PV outside the VG. vgsplit relies on this */
+ list_iterate(pvh, &vg->pvs) {
+ pv = list_item(pvh, struct pv_list)->pv;
+ if (pv->dev == mdac->area.dev) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ return 1;
+
+ if (!dev_open(mdac->area.dev, O_RDWR)) {
+ stack;
+ return 0;
+ }
+
+ if (!(mdah = _raw_read_mda_header(fid->fmt, &mdac->area))) {
+ stack;
+ goto out;
+ }
+
+ if ((rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name))) {
+ /* Start of free space - round up to next sector; circular */
+ mdac->rlocn.offset =
+ ((rlocn->offset + rlocn->size +
+ (SECTOR_SIZE - rlocn->size % SECTOR_SIZE) -
+ MDA_HEADER_SIZE) % (mdah->size - MDA_HEADER_SIZE))
+ + MDA_HEADER_SIZE;
+ } else {
+ /* Find an empty slot */
+ /* FIXME Assume only one VG per mdah for now */
+ mdac->rlocn.offset = MDA_HEADER_SIZE;
+ }
+
+ if (!(mdac->rlocn.size = text_vg_export_raw(vg, "", buf, sizeof(buf)))) {
+ log_error("VG %s metadata writing failed", vg->name);
+ goto out;
+ }
+
+ if (mdac->rlocn.offset + mdac->rlocn.size > mdah->size)
+ new_wrap = (mdac->rlocn.offset + mdac->rlocn.size) - mdah->size;
+
+ if (rlocn && (rlocn->offset + rlocn->size > mdah->size))
+ old_wrap = (rlocn->offset + rlocn->size) - mdah->size;
+
+ if ((new_wrap && old_wrap) ||
+ (rlocn && ((new_wrap > rlocn->offset) ||
+ (old_wrap && (mdac->rlocn.offset + mdac->rlocn.size >
+ rlocn->offset)))) ||
+ (mdac->rlocn.size >= mdah->size)) {
+ log_error("VG %s metadata too large for circular buffer",
+ vg->name);
+ goto out;
+ }
+
+ log_debug("Writing %s metadata to %s at %" PRIu64 " len %" PRIu64,
+ vg->name, dev_name(mdac->area.dev), mdac->area.start +
+ mdac->rlocn.offset, mdac->rlocn.size - new_wrap);
+
+ /* Write text out, circularly */
+ if (dev_write(mdac->area.dev, mdac->area.start + mdac->rlocn.offset,
+ mdac->rlocn.size - new_wrap,
+ buf) != mdac->rlocn.size - new_wrap) {
+ stack;
+ goto out;
+ }
+
+ if (new_wrap) {
+ log_debug("Writing metadata to %s at %" PRIu64 " len %" PRIu64,
+ dev_name(mdac->area.dev), mdac->area.start +
+ MDA_HEADER_SIZE, new_wrap);
+
+ if (dev_write(mdac->area.dev,
+ mdac->area.start + MDA_HEADER_SIZE,
+ new_wrap, buf + mdac->rlocn.size - new_wrap)
+ != new_wrap) {
+ stack;
+ goto out;
+ }
+ }
+
+ mdac->rlocn.checksum = calc_crc(INITIAL_CRC, buf,
+ mdac->rlocn.size - new_wrap);
+ if (new_wrap)
+ mdac->rlocn.checksum = calc_crc(mdac->rlocn.checksum,
+ buf + mdac->rlocn.size -
+ new_wrap, new_wrap);
+
+ r = 1;
+
+ out:
+ if (!dev_close(mdac->area.dev))
+ stack;
+
+ return r;
+}
+
+static int _vg_commit_raw(struct format_instance *fid, struct volume_group *vg,
+ struct metadata_area *mda)
+{
+ struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
+ struct mda_header *mdah;
+ struct raw_locn *rlocn;
+ struct physical_volume *pv;
+ struct list *pvh;
+ int r = 0;
+ int found = 0;
+
+ /* Ignore any mda on a PV outside the VG. vgsplit relies on this */
+ list_iterate(pvh, &vg->pvs) {
+ pv = list_item(pvh, struct pv_list)->pv;
+ if (pv->dev == mdac->area.dev) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ return 1;
+
+ if (!dev_open(mdac->area.dev, O_RDWR)) {
+ stack;
+ return 0;
+ }
+
+ if (!(mdah = _raw_read_mda_header(fid->fmt, &mdac->area))) {
+ stack;
+ goto out;
+ }
+
+ if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name))) {
+ rlocn = &mdah->raw_locns[0];
+ mdah->raw_locns[1].offset = 0;
+ }
+
+ rlocn->offset = mdac->rlocn.offset;
+ rlocn->size = mdac->rlocn.size;
+ rlocn->checksum = mdac->rlocn.checksum;
+
+ log_debug("Committing %s metadata (%u) to %s header at %" PRIu64,
+ vg->name, vg->seqno, dev_name(mdac->area.dev),
+ mdac->area.start);
+ if (!_raw_write_mda_header(fid->fmt, mdac->area.dev, mdac->area.start,
+ mdah)) {
+ log_error("Failed to write metadata area header");
+ goto out;
+ }
+
+ r = 1;
+
+ out:
+ if (!dev_close(mdac->area.dev))
+ stack;
+
+ return r;
+}
+
+static int _vg_remove_raw(struct format_instance *fid, struct volume_group *vg,
+ struct metadata_area *mda)
+{
+ struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
+ struct mda_header *mdah;
+ struct raw_locn *rlocn;
+ int r = 0;
+
+ if (!dev_open(mdac->area.dev, O_RDWR)) {
+ stack;
+ return 0;
+ }
+
+ if (!(mdah = _raw_read_mda_header(fid->fmt, &mdac->area))) {
+ stack;
+ goto out;
+ }
+
+ if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name))) {
+ rlocn = &mdah->raw_locns[0];
+ mdah->raw_locns[1].offset = 0;
+ }
+
+ rlocn->offset = 0;
+ rlocn->size = 0;
+ rlocn->checksum = 0;
+
+ if (!_raw_write_mda_header(fid->fmt, mdac->area.dev, mdac->area.start,
+ mdah)) {
+ log_error("Failed to write metadata area header");
+ goto out;
+ }
+
+ r = 1;
+
+ out:
+ if (!dev_close(mdac->area.dev))
+ stack;
+
+ return r;
+}
+
+static struct volume_group *_vg_read_file_name(struct format_instance *fid,
+ const char *vgname,
+ const char *path_live)
{
- struct text_context *tc = (struct text_context *) mdl;
struct volume_group *vg;
time_t when;
char *desc;
- if (!(vg = text_vg_import(fi, tc->path_live, fi->fmt->cmd->um, &when,
- &desc))) {
+ if (!(vg = text_vg_import_file(fid, path_live, &when, &desc))) {
stack;
return NULL;
}
@@ -113,20 +523,30 @@ static struct volume_group *_vg_read(struct format_instance *fi,
* text file (this restriction may remain). We need to
* check that it contains the correct volume group.
*/
- if (strcmp(vgname, vg->name)) {
- pool_free(fi->fmt->cmd->mem, vg);
+ if (vgname && strcmp(vgname, vg->name)) {
+ pool_free(fid->fmt->cmd->mem, vg);
log_err("'%s' does not contain volume group '%s'.",
- tc->path_live, vgname);
+ path_live, vgname);
return NULL;
- }
+ } else
+ log_debug("Read volume group %s from %s", vg->name, path_live);
return vg;
}
-static int _vg_write(struct format_instance *fi, struct volume_group *vg,
- void *mdl)
+static struct volume_group *_vg_read_file(struct format_instance *fid,
+ const char *vgname,
+ struct metadata_area *mda)
+{
+ struct text_context *tc = (struct text_context *) mda->metadata_locn;
+
+ return _vg_read_file_name(fid, vgname, tc->path_live);
+}
+
+static int _vg_write_file(struct format_instance *fid, struct volume_group *vg,
+ struct metadata_area *mda)
{
- struct text_context *tc = (struct text_context *) mdl;
+ struct text_context *tc = (struct text_context *) mda->metadata_locn;
FILE *fp;
int fd;
@@ -157,7 +577,9 @@ static int _vg_write(struct format_instance *fi, struct volume_group *vg,
return 0;
}
- if (!text_vg_export(fp, vg, tc->desc)) {
+ log_debug("Writing %s metadata to %s", vg->name, temp_file);
+
+ if (!text_vg_export_file(vg, tc->desc, fp)) {
log_error("Failed to write metadata to %s.", temp_file);
fclose(fp);
return 0;
@@ -175,6 +597,7 @@ static int _vg_write(struct format_instance *fi, struct volume_group *vg,
}
if (rename(temp_file, tc->path_edit)) {
+ log_debug("Renaming %s to %s", temp_file, tc->path_edit);
log_error("%s: rename to %s failed: %s", temp_file,
tc->path_edit, strerror(errno));
return 0;
@@ -183,34 +606,77 @@ static int _vg_write(struct format_instance *fi, struct volume_group *vg,
return 1;
}
-static int _pv_commit(struct format_instance *fi, struct physical_volume *pv,
- void *mdl)
+static int _vg_commit_file_backup(struct format_instance *fid,
+ struct volume_group *vg,
+ struct metadata_area *mda)
{
- // struct text_context *tc = (struct text_context *) mdl;
+ struct text_context *tc = (struct text_context *) mda->metadata_locn;
+
+ if (test_mode()) {
+ log_verbose("Test mode: Skipping committing %s metadata (%u)",
+ vg->name, vg->seqno);
+ if (unlink(tc->path_edit)) {
+ log_debug("Unlinking %s", tc->path_edit);
+ log_sys_error("unlink", tc->path_edit);
+ return 0;
+ }
+ } else {
+ log_debug("Committing %s metadata (%u)", vg->name, vg->seqno);
+ log_debug("Renaming %s to %s", tc->path_edit, tc->path_live);
+ if (rename(tc->path_edit, tc->path_live)) {
+ log_error("%s: rename to %s failed: %s", tc->path_edit,
+ tc->path_edit, strerror(errno));
+ return 0;
+ }
+ }
+
+ sync();
return 1;
}
-static int _vg_commit(struct format_instance *fi, struct volume_group *vg,
- void *mdl)
+static int _vg_commit_file(struct format_instance *fid, struct volume_group *vg,
+ struct metadata_area *mda)
{
- struct text_context *tc = (struct text_context *) mdl;
+ struct text_context *tc = (struct text_context *) mda->metadata_locn;
+ char *slash;
+ char newname[PATH_MAX];
+ int len;
- if (rename(tc->path_edit, tc->path_live)) {
- log_error("%s: rename to %s failed: %s", tc->path_edit,
- tc->path_edit, strerror(errno));
+ if (!_vg_commit_file_backup(fid, vg, mda))
return 0;
- }
- sync();
+ /* vgrename? */
+ if ((slash = rindex(tc->path_live, '/')))
+ slash = slash + 1;
+ else
+ slash = tc->path_live;
+
+ if (strcmp(slash, vg->name)) {
+ len = slash - tc->path_live;
+ strncpy(newname, tc->path_live, len);
+ strcpy(newname + len, vg->name);
+ log_debug("Renaming %s to %s", tc->path_live, newname);
+ if (test_mode())
+ log_verbose("Test mode: Skipping rename");
+ else {
+ if (rename(tc->path_live, newname)) {
+ log_error("%s: rename to %s failed: %s",
+ tc->path_live, newname,
+ strerror(errno));
+ sync();
+ return 0;
+ }
+ }
+ }
return 1;
}
-static int _vg_remove(struct format_instance *fi, struct volume_group *vg,
- void *mdl)
+static int _vg_remove_file(struct format_instance *fid, struct volume_group *vg,
+ struct metadata_area *mda)
{
- struct text_context *tc = (struct text_context *) mdl;
+ struct text_context *tc = (struct text_context *) mda->metadata_locn;
if (path_exists(tc->path_edit) && unlink(tc->path_edit)) {
log_sys_error("unlink", tc->path_edit);
@@ -227,44 +693,19 @@ static int _vg_remove(struct format_instance *fi, struct volume_group *vg,
return 1;
}
-/* Add vgname to list if it's not already there */
-static int _add_vgname(struct format_type *fmt, struct list *names,
- char *vgname)
-{
- struct list *nlh;
- struct name_list *nl;
-
- list_iterate(nlh, names) {
- nl = list_item(nlh, struct name_list);
- if (!strcmp(vgname, nl->name))
- return 1;
- }
-
- vgcache_add(vgname, NULL, NULL, fmt);
-
- if (!(nl = pool_alloc(fmt->cmd->mem, sizeof(*nl)))) {
- stack;
- return 0;
- }
-
- if (!(nl->name = pool_strdup(fmt->cmd->mem, vgname))) {
- log_error("strdup %s failed", vgname);
- return 0;
- }
-
- list_add(names, &nl->list);
- return 1;
-}
-
-static struct list *_get_vgs(struct format_type *fmt, struct list *names)
+static int _scan_file(struct format_type *fmt)
{
struct dirent *dirent;
struct dir_list *dl;
struct list *dlh, *dir_list;
char *tmp;
DIR *d;
+ struct volume_group *vg;
+ struct format_instance *fid;
+ char path[PATH_MAX];
+ char *vgname;
- dir_list = (struct list *) fmt->private;
+ dir_list = &((struct mda_lists *) fmt->private)->dirs;
list_iterate(dlh, dir_list) {
dl = list_item(dlh, struct dir_list);
@@ -277,151 +718,468 @@ static struct list *_get_vgs(struct format_type *fmt, struct list *names)
strcmp(dirent->d_name, "..") &&
(!(tmp = strstr(dirent->d_name, ".tmp")) ||
tmp != dirent->d_name + strlen(dirent->d_name)
- - 4))
- if (!_add_vgname(fmt, names, dirent->d_name))
- return NULL;
+ - 4)) {
+ vgname = dirent->d_name;
+ if (lvm_snprintf(path, PATH_MAX, "%s/%s",
+ dl->dir, vgname) < 0) {
+ log_error("Name too long %s/%s",
+ dl->dir, vgname);
+ break;
+ }
+
+ /* FIXME stat file to see if it's changed */
+ fid = _create_text_instance(fmt, NULL, NULL);
+ if ((vg = _vg_read_file_name(fid, vgname,
+ path)))
+ cache_update_vg(vg);
+ }
if (closedir(d))
log_sys_error("closedir", dl->dir);
}
- return names;
+ return 1;
}
-static struct list *_get_pvs(struct format_type *fmt, struct list *results)
+int vgname_from_mda(struct format_type *fmt, struct device_area *dev_area,
+ char *buf, uint32_t size)
{
- struct pv_list *pvl, *rhl;
- struct list *vgh;
- struct list *pvh;
- struct list *names = pool_alloc(fmt->cmd->mem, sizeof(*names));
- struct list *rh;
- struct name_list *nl;
- struct volume_group *vg;
+ struct raw_locn *rlocn;
+ struct mda_header *mdah;
+ int already_open;
+ int len;
+ int r = 0;
+
+ already_open = dev_is_open(dev_area->dev);
- list_init(names);
- if (!_get_vgs(fmt, names)) {
+ if (!already_open && !dev_open(dev_area->dev, O_RDONLY)) {
stack;
- return NULL;
+ return 0;
}
- list_iterate(vgh, names) {
+ if (!(mdah = _raw_read_mda_header(fmt, dev_area))) {
+ stack;
+ goto out;
+ }
- nl = list_item(vgh, struct name_list);
- if (!(vg = vg_read(fmt->cmd, nl->name))) {
- log_error("format_text: _get_pvs failed to read VG %s",
- nl->name);
- continue;
+ rlocn = mdah->raw_locns;
+
+ while (rlocn->offset) {
+ if (dev_read(dev_area->dev, dev_area->start + rlocn->offset,
+ size, buf) != size) {
+ stack;
+ goto out;
}
- /* FIXME Use temp hash! */
- list_iterate(pvh, &vg->pvs) {
- pvl = list_item(pvh, struct pv_list);
-
- /* If in use, remove from list of orphans */
- list_iterate(rh, results) {
- rhl = list_item(rh, struct pv_list);
- if (id_equal(&rhl->pv->id, &pvl->pv->id)) {
- if (*rhl->pv->vg_name)
- log_err("PV %s in two VGs "
- "%s and %s",
- dev_name(rhl->pv->dev),
- rhl->pv->vg_name,
- vg->name);
- else
- memcpy(&rhl->pv, &pvl->pv,
- sizeof(struct
- physical_volume));
- }
- }
+ len = 0;
+ while (buf[len] && !isspace(buf[len]) && buf[len] != '{' &&
+ len < size - 1)
+ len++;
+ buf[len] = '\0';
+
+ /* Ignore this entry if the characters aren't permissible */
+ if (!validate_vgname(buf)) {
+ stack;
+ goto out;
}
+
+ r = 1;
+ break;
+
+ /* FIXME Cope with returning a list */
+ rlocn++;
}
- pool_free(fmt->cmd->mem, names);
- return results;
+ out:
+ if (!already_open && dev_close(dev_area->dev))
+ stack;
+
+ return r;
}
-static int _pv_write(struct format_instance *fi, struct physical_volume *pv,
- void *mdl)
+static int _scan_raw(struct format_type *fmt)
{
- /* No on-disk PV structure change required! */
- /* FIXME vgcache could be wrong */
+ struct raw_list *rl;
+ struct list *rlh, *raw_list;
+ char vgnamebuf[NAME_LEN + 2];
+ struct volume_group *vg;
+ struct format_instance fid;
+
+ raw_list = &((struct mda_lists *) fmt->private)->raws;
+
+ fid.fmt = fmt;
+ list_init(&fid.metadata_areas);
+
+ list_iterate(rlh, raw_list) {
+ rl = list_item(rlh, struct raw_list);
+
+ /* FIXME We're reading mdah twice here... */
+ if (vgname_from_mda(fmt, &rl->dev_area, vgnamebuf,
+ sizeof(vgnamebuf))) {
+ if ((vg = _vg_read_raw_area(&fid, vgnamebuf,
+ &rl->dev_area)))
+ cache_update_vg(vg);
+ }
+ }
+
return 1;
- //return (fi->fmt->cmd->fmt1->ops->pv_write(fi, pv, NULL));
-/*** FIXME Not required?
+}
+
+static int _scan(struct format_type *fmt)
+{
+ return (_scan_file(fmt) & _scan_raw(fmt));
+}
+
+/* For orphan, creates new mdas according to policy.
+ Always have an mda between end-of-label and PE_ALIGN boundary */
+static int _mda_setup(struct format_type *fmt,
+ uint64_t pe_start, uint64_t pe_end,
+ int pvmetadatacopies,
+ uint64_t pvmetadatasize, struct list *mdas,
+ struct physical_volume *pv, struct volume_group *vg)
+{
+ uint64_t mda_adjustment, disk_size, alignment;
+ uint64_t start1, mda_size1; /* First area - start of disk */
+ uint64_t start2, mda_size2; /* Second area - end of disk */
+ uint64_t wipe_size = 8 << SECTOR_SHIFT;
+
+ if (!pvmetadatacopies) {
+ /* Space available for PEs */
+ pv->size -= PE_ALIGN;
+ return 1;
+ }
+
+ alignment = PE_ALIGN << SECTOR_SHIFT;
+ disk_size = pv->size << SECTOR_SHIFT;
+ pe_start <<= SECTOR_SHIFT;
+ pe_end <<= SECTOR_SHIFT;
+
+ if (pe_end > disk_size) {
+ log_error("Physical extents end beyond end of device %s!",
+ dev_name(pv->dev));
+ return 0;
+ }
+
+ /* Requested metadatasize */
+ mda_size1 = pvmetadatasize << SECTOR_SHIFT;
+
+ /* Space available for PEs (before any mdas created) */
+ pv->size -= LABEL_SCAN_SECTORS;
+
+ /* Place mda straight after label area at start of disk */
+ start1 = LABEL_SCAN_SIZE;
+
+ /* Round up to PE_ALIGN boundary */
+ mda_adjustment = (mda_size1 + start1) % alignment;
+ if (mda_adjustment)
+ mda_size1 += (alignment - mda_adjustment);
+
+ /* If we already have PEs, avoid overlap */
+ if (pe_start || pe_end) {
+ if (pe_start <= start1)
+ mda_size1 = 0;
+ else if (start1 + mda_size1 > pe_start)
+ mda_size1 = pe_start - start1;
+ }
+
+ /* FIXME If creating new mdas, wipe them! */
+ if (mda_size1) {
+ if (!add_mda(fmt, fmt->cmd->mem, mdas, pv->dev, start1,
+ mda_size1))
+ return 0;
+
+ if (!dev_zero(pv->dev, start1,
+ mda_size1 > wipe_size ? wipe_size : mda_size1)) {
+ log_error("Failed to wipe new metadata area");
+ return 0;
+ }
+
+ pv->size -= mda_size1 >> SECTOR_SHIFT;
+ if (pvmetadatacopies == 1)
+ return 1;
+ } else
+ start1 = 0;
+
+ /* A second copy at end of disk */
+ mda_size2 = pvmetadatasize << SECTOR_SHIFT;
+
+ /* Ensure it's not going to be bigger than the disk! */
+ if (mda_size2 > disk_size)
+ mda_size2 = disk_size - start1 - mda_size1;
+
+ mda_adjustment = (disk_size - mda_size2) % alignment;
+ if (mda_adjustment)
+ mda_size2 += mda_adjustment;
+
+ start2 = disk_size - mda_size2;
+
+ /* If we already have PEs, avoid overlap */
+ if (pe_start || pe_end) {
+ if (start2 < pe_end) {
+ mda_size2 -= (pe_end - start2);
+ start2 = pe_end;
+ }
+ }
+
+ /* If we already have a first mda, avoid overlap */
+ if (mda_size1) {
+ if (start2 < start1 + mda_size1) {
+ mda_size2 -= (start1 + mda_size1 - start2);
+ start2 = start1 + mda_size1;
+ }
+ /* No room for any PEs here now! */
+ }
+
+ if (mda_size2) {
+ if (!add_mda(fmt, fmt->cmd->mem, mdas, pv->dev, start2,
+ mda_size2))
+ return 0;
+ if (!dev_zero(pv->dev, start2,
+ mda_size1 > wipe_size ? wipe_size : mda_size1)) {
+ log_error("Failed to wipe new metadata area");
+ return 0;
+ }
+ pv->size -= mda_size2 >> SECTOR_SHIFT;
+ } else
+ return 0;
+
+ return 1;
+}
+
+/* Only for orphans */
+/* Set label_sector to -1 if rewriting existing label into same sector */
+static int _pv_write(struct format_type *fmt, struct physical_volume *pv,
+ struct list *mdas, int64_t label_sector)
+{
+ struct label *label;
+ struct cache_info *info;
+ struct mda_context *mdac;
+ struct list *mdash;
+ struct metadata_area *mda;
+ char buf[MDA_HEADER_SIZE];
+ struct mda_header *mdah = (struct mda_header *) buf;
+ uint64_t adjustment;
+
+ if (!(info = cache_add(fmt->labeller, (char *) &pv->id, pv->dev,
+ ORPHAN, NULL))) {
+ stack;
+ return 0;
+ }
+ label = info->label;
+
+ if (label_sector != -1)
+ label->sector = label_sector;
+
+ info->device_size = pv->size << SECTOR_SHIFT;
+ info->fmt = fmt;
+
+ /* If mdas supplied, use them regardless of existing ones, */
+ /* otherwise retain existing ones */
+ if (mdas) {
+ if (info->mdas.n)
+ del_mdas(&info->mdas);
+ else
+ list_init(&info->mdas);
+ list_iterate(mdash, mdas) {
+ mda = list_item(mdash, struct metadata_area);
+ mdac = mda->metadata_locn;
+ log_debug("Creating metadata area on %s at sector %"
+ PRIu64 " size %" PRIu64 " sectors",
+ dev_name(mdac->area.dev),
+ mdac->area.start >> SECTOR_SHIFT,
+ mdac->area.size >> SECTOR_SHIFT);
+ add_mda(fmt, NULL, &info->mdas, mdac->area.dev,
+ mdac->area.start, mdac->area.size);
+ }
+ /* FIXME Temporary until mda creation supported by tools */
+ } else if (!info->mdas.n) {
+ list_init(&info->mdas);
+ }
+
+ if (info->das.n)
+ del_das(&info->das);
+ else
+ list_init(&info->das);
+
+ /* Set pe_start to first aligned sector after any metadata
+ * areas that begin before pe_start */
+ pv->pe_start = PE_ALIGN;
+ list_iterate(mdash, &info->mdas) {
+ mda = list_item(mdash, struct metadata_area);
+ mdac = (struct mda_context *) mda->metadata_locn;
+ if (pv->dev == mdac->area.dev &&
+ (mdac->area.start < (pv->pe_start << SECTOR_SHIFT)) &&
+ (mdac->area.start + mdac->area.size >
+ (pv->pe_start << SECTOR_SHIFT))) {
+ pv->pe_start = (mdac->area.start + mdac->area.size)
+ >> SECTOR_SHIFT;
+ adjustment = pv->pe_start % PE_ALIGN;
+ if (adjustment)
+ pv->pe_start += (PE_ALIGN - adjustment);
+ }
+ }
+ if (!add_da(fmt, NULL, &info->das, pv->pe_start << SECTOR_SHIFT, 0)) {
+ stack;
+ return 0;
+ }
+
+ if (!dev_open(pv->dev, O_RDWR)) {
+ stack;
+ return 0;
+ }
+
+ list_iterate(mdash, &info->mdas) {
+ mda = list_item(mdash, struct metadata_area);
+ mdac = mda->metadata_locn;
+ memset(&buf, 0, sizeof(buf));
+ mdah->size = mdac->area.size;
+ if (!_raw_write_mda_header(fmt, mdac->area.dev,
+ mdac->area.start, mdah)) {
+ stack;
+ if (!dev_close(pv->dev))
+ stack;
+ return 0;
+ }
+ }
+
+ label_write(pv->dev, label);
+
+ if (!dev_close(pv->dev)) {
+ stack;
+ return 0;
+ }
+
+ return 1;
+}
+
+static int _get_pv_from_vg(struct format_type *fmt, const char *vg_name,
+ const char *id, struct physical_volume *pv)
+{
struct volume_group *vg;
struct list *pvh;
+ struct pv_list *pvl;
+ int consistent = 0;
- vg = _vg_read(fi, pv->vg_name);
+ if (!(vg = vg_read(fmt->cmd, vg_name, &consistent))) {
+ log_error("format_text: _vg_read failed to read VG %s",
+ vg_name);
+ return 0;
+ }
- // Find the PV in this VG
- if (vg) {
- list_iterate(pvh, &vg->pvs) {
- struct pv_list *vgpv = list_item(pvh, struct pv_list);
-
- if (id_equal(&pv->id, &vgpv->pv->id)) {
- vgpv->pv->status = pv->status;
- vgpv->pv->size = pv->size;
-
- // Not sure if it's worth doing these
- vgpv->pv->pe_size = pv->pe_size;
- vgpv->pv->pe_count = pv->pe_count;
- vgpv->pv->pe_start = pv->pe_start;
- vgpv->pv->pe_alloc_count = pv->pe_alloc_count;
-
- // Write it back
- _vg_write(fi, vg);
- pool_free(fi->fmt->cmd->mem, vg);
- return 1;
- }
+ if (!consistent)
+ log_error("Warning: Volume group %s is not consistent",
+ vg_name);
+
+ list_iterate(pvh, &vg->pvs) {
+ pvl = list_item(pvh, struct pv_list);
+ if (id_equal(&pvl->pv->id, (struct id *) id)) {
+ memcpy(pv, pvl->pv, sizeof(*pv));
+ return 1;
}
- pool_free(fi->fmt->cmd->mem, vg);
}
-
- // Can't handle PVs not in a VG
return 0;
-***/
}
-static int _pv_read(struct format_type *fmt, const char *pv_name,
- struct physical_volume *pv)
+static int _add_raw(struct list *raw_list, struct device_area *dev_area)
{
- struct pv_list *pvl;
- struct list *vgh;
- struct list *pvh;
- struct list *names = pool_alloc(fmt->cmd->mem, sizeof(*names));
- struct name_list *nl;
- struct volume_group *vg;
- struct id *id;
+ struct raw_list *rl;
+ struct list *rlh;
+
+ /* Already present? */
+ list_iterate(rlh, raw_list) {
+ rl = list_item(rlh, struct raw_list);
+ /* FIXME Check size/overlap consistency too */
+ if (rl->dev_area.dev == dev_area->dev &&
+ rl->dev_area.start == dev_area->start)
+ return 1;
+ }
- /* FIXME Push up to pv_read */
- if (!(id = uuid_map_lookup_label(fmt->cmd->mem, fmt->cmd->um, pv_name))) {
+ if (!(rl = dbg_malloc(sizeof(struct raw_list)))) {
+ log_error("_add_raw allocation failed");
+ return 0;
+ }
+ memcpy(&rl->dev_area, dev_area, sizeof(*dev_area));
+ list_add(raw_list, &rl->list);
+
+ return 1;
+}
+
+static int _pv_read(struct format_type *fmt, const char *pv_name,
+ struct physical_volume *pv, struct list *mdas)
+{
+ struct label *label;
+ struct device *dev;
+ struct cache_info *info;
+ struct metadata_area *mda, *mda_new;
+ struct mda_context *mdac, *mdac_new;
+ struct list *mdah, *dah;
+ struct data_area_list *da;
+
+ if (!(dev = dev_cache_get(pv_name, fmt->cmd->filter))) {
stack;
return 0;
}
- list_init(names);
- if (!_get_vgs(fmt, names)) {
+ if (!(label_read(dev, &label))) {
stack;
return 0;
}
+ info = (struct cache_info *) label->info;
+
+ /* Have we already cached vgname? */
+ if (info->vginfo && info->vginfo->vgname && *info->vginfo->vgname &&
+ _get_pv_from_vg(info->fmt, info->vginfo->vgname, info->dev->pvid,
+ pv)) {
+ return 1;
+ }
+
+ /* Perform full scan and try again */
+ cache_label_scan(fmt->cmd, 0);
+
+ if (info->vginfo && info->vginfo->vgname && *info->vginfo->vgname &&
+ _get_pv_from_vg(info->fmt, info->vginfo->vgname, info->dev->pvid,
+ pv)) {
+ return 1;
+ }
+
+ /* Orphan */
+ pv->dev = info->dev;
+ pv->fmt = info->fmt;
+ pv->size = info->device_size >> SECTOR_SHIFT;
+ pv->vg_name = ORPHAN;
+ memcpy(&pv->id, &info->dev->pvid, sizeof(pv->id));
+
+ /* Currently only support exactly one data area */
+ if (list_size(&info->das) != 1) {
+ log_error("Must be exactly one data area (found %d) on PV %s",
+ list_size(&info->das), dev_name(dev));
+ return 0;
+ }
+ list_iterate(dah, &info->das) {
+ da = list_item(dah, struct data_area_list);
+ pv->pe_start = da->disk_locn.offset >> SECTOR_SHIFT;
+ }
- list_iterate(vgh, names) {
+ if (!mdas)
+ return 1;
- nl = list_item(vgh, struct name_list);
- if (!(vg = vg_read(fmt->cmd, nl->name))) {
- log_error("format_text: _pv_read failed to read VG %s",
- nl->name);
+ /* Add copy of mdas to supplied list */
+ list_iterate(mdah, &info->mdas) {
+ mda = list_item(mdah, struct metadata_area);
+ mdac = (struct mda_context *) mda->metadata_locn;
+ if (!(mda_new = pool_alloc(fmt->cmd->mem, sizeof(*mda_new)))) {
+ log_error("metadata_area allocation failed");
return 0;
}
- list_iterate(pvh, &vg->pvs) {
- pvl = list_item(pvh, struct pv_list);
- if (id_equal(&pvl->pv->id, id)) {
- memcpy(pv, pvl->pv, sizeof(*pv));
- break;
- }
+ if (!(mdac_new = pool_alloc(fmt->cmd->mem, sizeof(*mdac_new)))) {
+ log_error("metadata_area allocation failed");
+ return 0;
}
+ memcpy(mda_new, mda, sizeof(*mda));
+ memcpy(mdac_new, mdac, sizeof(*mdac));
+ mda_new->metadata_locn = mdac_new;
+ list_add(mdas, &mda_new->list);
}
- pool_free(fmt->cmd->mem, names);
return 1;
}
@@ -440,25 +1198,152 @@ static void _free_dirs(struct list *dir_list)
}
}
+static void _free_raws(struct list *raw_list)
+{
+ struct list *rl, *tmp;
+
+ list_iterate_safe(rl, tmp, raw_list) {
+ list_del(rl);
+ dbg_free(rl);
+ }
+}
+
static void _destroy(struct format_type *fmt)
{
if (fmt->private) {
- _free_dirs((struct list *) fmt->private);
+ _free_dirs(&((struct mda_lists *) fmt->private)->dirs);
+ _free_raws(&((struct mda_lists *) fmt->private)->raws);
dbg_free(fmt->private);
}
dbg_free(fmt);
}
+static struct metadata_area_ops _metadata_text_file_ops = {
+ vg_read:_vg_read_file,
+ vg_write:_vg_write_file,
+ vg_remove:_vg_remove_file,
+ vg_commit:_vg_commit_file
+};
+
+static struct metadata_area_ops _metadata_text_file_backup_ops = {
+ vg_read:_vg_read_file,
+ vg_write:_vg_write_file,
+ vg_remove:_vg_remove_file,
+ vg_commit:_vg_commit_file_backup
+};
+
+static struct metadata_area_ops _metadata_text_raw_ops = {
+ vg_read:_vg_read_raw,
+ vg_write:_vg_write_raw,
+ vg_remove:_vg_remove_raw,
+ vg_commit:_vg_commit_raw
+};
+
+/* pvmetadatasize in sectors */
+static 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)
+{
+ struct metadata_area *mda, *mda_new, *mda2;
+ struct mda_context *mdac, *mdac_new, *mdac2;
+ struct list *pvmdas, *pvmdash, *mdash;
+ struct cache_info *info;
+ int found;
+ uint64_t pe_end = 0;
+
+ /* FIXME if vg, adjust start/end of pe area to avoid mdas! */
+
+ /* FIXME Cope with pvchange */
+ /* FIXME Merge code with _create_text_instance */
+
+ /* If new vg, add any further mdas on this PV to the fid's mda list */
+ if (vg) {
+ /* Iterate through all mdas on this PV */
+ if ((info = info_from_pvid(pv->dev->pvid))) {
+ pvmdas = &info->mdas;
+ list_iterate(pvmdash, pvmdas) {
+ mda = list_item(pvmdash, struct metadata_area);
+ mdac =
+ (struct mda_context *) mda->metadata_locn;
+
+ /* FIXME Check it isn't already in use */
+
+ /* Ensure it isn't already on list */
+ found = 0;
+ list_iterate(mdash, mdas) {
+ mda2 =
+ list_item(mdash,
+ struct metadata_area);
+ if (mda2->ops !=
+ &_metadata_text_raw_ops)
+ continue;
+ mdac2 =
+ (struct mda_context *) mda2->
+ metadata_locn;
+ if (!memcmp
+ (&mdac2->area, &mdac->area,
+ sizeof(mdac->area))) {
+ found = 1;
+ break;
+ }
+ }
+ if (found)
+ continue;
+
+ if (!(mda_new = pool_alloc(fmt->cmd->mem,
+ sizeof(*mda_new)))) {
+ stack;
+ return 0;
+ }
+
+ if (!(mdac_new = pool_alloc(fmt->cmd->mem,
+ sizeof(*mdac_new))))
+ {
+ stack;
+ return 0;
+ }
+ /* FIXME multiple dev_areas inside area */
+ memcpy(mda_new, mda, sizeof(*mda));
+ memcpy(mdac_new, mdac, sizeof(*mdac));
+ mda_new->metadata_locn = mdac_new;
+ list_add(mdas, &mda_new->list);
+ }
+ }
+
+ /* Unlike LVM1, we don't store this outside a VG */
+ /* FIXME Default from config file? vgextend cmdline flag? */
+ pv->status |= ALLOCATABLE_PV;
+ } else {
+ if (extent_count)
+ pe_end = pe_start + extent_count * extent_size - 1;
+ if (!_mda_setup(fmt, pe_start, pe_end, pvmetadatacopies,
+ pvmetadatasize, mdas, pv, vg)) {
+ stack;
+ return 0;
+ }
+
+ }
+
+ return 1;
+}
+
+/* NULL vgname means use only the supplied context e.g. an archive file */
static struct format_instance *_create_text_instance(struct format_type *fmt,
const char *vgname,
void *context)
{
struct format_instance *fid;
- struct metadata_area *mda;
+ struct metadata_area *mda, *mda_new;
+ struct mda_context *mdac, *mdac_new;
struct dir_list *dl;
- struct list *dlh, *dir_list;
+ struct raw_list *rl;
+ struct list *dlh, *dir_list, *rlh, *raw_list, *mdas, *mdash, *infoh;
char path[PATH_MAX];
+ struct cache_vginfo *vginfo;
if (!(fid = pool_alloc(fmt->cmd->mem, sizeof(*fid)))) {
log_error("Couldn't allocate format instance object.");
@@ -474,10 +1359,11 @@ static struct format_instance *_create_text_instance(struct format_type *fmt,
stack;
return NULL;
}
+ mda->ops = &_metadata_text_file_backup_ops;
mda->metadata_locn = context;
list_add(&fid->metadata_areas, &mda->list);
} else {
- dir_list = (struct list *) fmt->private;
+ dir_list = &((struct mda_lists *) fmt->private)->dirs;
list_iterate(dlh, dir_list) {
dl = list_item(dlh, struct dir_list);
@@ -488,21 +1374,83 @@ static struct format_instance *_create_text_instance(struct format_type *fmt,
return NULL;
}
- context = create_text_context(fmt, path, NULL);
+ context = create_text_context(fmt->cmd, path, NULL);
if (!(mda = pool_alloc(fmt->cmd->mem, sizeof(*mda)))) {
stack;
return NULL;
}
+ mda->ops = &_metadata_text_file_ops;
mda->metadata_locn = context;
list_add(&fid->metadata_areas, &mda->list);
}
+
+ raw_list = &((struct mda_lists *) fmt->private)->raws;
+
+ list_iterate(rlh, raw_list) {
+ rl = list_item(rlh, struct raw_list);
+
+ /* FIXME Cache this; rescan below if some missing */
+ if (!_raw_holds_vgname(fid, &rl->dev_area, vgname))
+ continue;
+
+ if (!(mda = pool_alloc(fmt->cmd->mem, sizeof(*mda)))) {
+ stack;
+ return NULL;
+ }
+
+ if (!(mdac = pool_alloc(fmt->cmd->mem, sizeof(*mdac)))) {
+ stack;
+ return NULL;
+ }
+ mda->metadata_locn = mdac;
+ /* FIXME Allow multiple dev_areas inside area */
+ memcpy(&mdac->area, &rl->dev_area, sizeof(mdac->area));
+ mda->ops = &_metadata_text_raw_ops;
+ list_add(&fid->metadata_areas, &mda->list);
+ }
+
+ /* Scan PVs in VG for any further MDAs */
+ cache_label_scan(fmt->cmd, 0);
+ if (!(vginfo = vginfo_from_vgname(vgname))) {
+ stack;
+ goto out;
+ }
+ list_iterate(infoh, &vginfo->infos) {
+ mdas = &(list_item(infoh, struct cache_info)->mdas);
+ list_iterate(mdash, mdas) {
+ mda = list_item(mdash, struct metadata_area);
+ mdac =
+ (struct mda_context *) mda->metadata_locn;
+
+ /* FIXME Check it holds this VG */
+ if (!(mda_new = pool_alloc(fmt->cmd->mem,
+ sizeof(*mda_new)))) {
+ stack;
+ return NULL;
+ }
+
+ if (!(mdac_new = pool_alloc(fmt->cmd->mem,
+ sizeof(*mdac_new))))
+ {
+ stack;
+ return NULL;
+ }
+ /* FIXME multiple dev_areas inside area */
+ memcpy(mda_new, mda, sizeof(*mda));
+ memcpy(mdac_new, mdac, sizeof(*mdac));
+ mda_new->metadata_locn = mdac_new;
+ list_add(&fid->metadata_areas, &mda_new->list);
+ }
+ }
+ /* FIXME Check raw metadata area count - rescan if required */
}
+ out:
return fid;
}
-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 text_context *tc;
@@ -514,17 +1462,17 @@ void *create_text_context(struct format_type *fmt, const char *path,
return NULL;
}
- if (!(tc = pool_alloc(fmt->cmd->mem, sizeof(*tc)))) {
+ if (!(tc = pool_alloc(cmd->mem, sizeof(*tc)))) {
stack;
return NULL;
}
- if (!(tc->path_live = pool_strdup(fmt->cmd->mem, path))) {
+ if (!(tc->path_live = pool_strdup(cmd->mem, path))) {
stack;
goto no_mem;
}
- if (!(tc->path_edit = pool_alloc(fmt->cmd->mem, strlen(path) + 5))) {
+ if (!(tc->path_edit = pool_alloc(cmd->mem, strlen(path) + 5))) {
stack;
goto no_mem;
}
@@ -533,7 +1481,7 @@ void *create_text_context(struct format_type *fmt, const char *path,
if (!desc)
desc = "";
- if (!(tc->desc = pool_strdup(fmt->cmd->mem, desc))) {
+ if (!(tc->desc = pool_strdup(cmd->mem, desc))) {
stack;
goto no_mem;
}
@@ -541,28 +1489,22 @@ void *create_text_context(struct format_type *fmt, const char *path,
return (void *) tc;
no_mem:
- pool_free(fmt->cmd->mem, tc);
+ pool_free(cmd->mem, tc);
log_err("Couldn't allocate text format context object.");
return NULL;
}
static struct format_handler _text_handler = {
- get_vgs: _get_vgs,
- get_pvs: _get_pvs,
- pv_read: _pv_read,
- pv_setup: _pv_setup,
- pv_write: _pv_write,
- pv_commit: _pv_commit,
- vg_setup: _vg_setup,
- lv_setup: _lv_setup,
- vg_read: _vg_read,
- vg_write: _vg_write,
- vg_remove: _vg_remove,
- vg_commit: _vg_commit,
+ scan:_scan,
+ pv_read:_pv_read,
+ pv_setup:_pv_setup,
+ pv_write:_pv_write,
+ vg_setup:_vg_setup,
+ lv_setup:_lv_setup,
create_instance:_create_text_instance,
destroy_instance:_destroy_instance,
- destroy: _destroy
+ destroy:_destroy
};
static int _add_dir(const char *dir, struct list *dir_list)
@@ -574,6 +1516,7 @@ static int _add_dir(const char *dir, struct list *dir_list)
log_error("_add_dir allocation failed");
return 0;
}
+ log_very_verbose("Adding text format metadata dir: %s", dir);
strcpy(dl->dir, dir);
list_add(dir_list, &dl->list);
return 1;
@@ -582,12 +1525,64 @@ static int _add_dir(const char *dir, struct list *dir_list)
return 0;
}
+static int _get_config_disk_area(struct cmd_context *cmd,
+ struct config_node *cn, struct list *raw_list)
+{
+ struct device_area dev_area;
+ char *id_str;
+ struct id id;
+
+ if (!(cn = cn->child)) {
+ log_error("Empty metadata disk_area section of config file");
+ return 0;
+ }
+
+ if (!get_config_uint64(cn, "start_sector", '/', &dev_area.start)) {
+ log_error("Missing start_sector in metadata disk_area section "
+ "of config file");
+ return 0;
+ }
+ dev_area.start <<= SECTOR_SHIFT;
+
+ if (!get_config_uint64(cn, "size", '/', &dev_area.size)) {
+ log_error("Missing size in metadata disk_area section "
+ "of config file");
+ return 0;
+ }
+ dev_area.size <<= SECTOR_SHIFT;
+
+ if (!get_config_str(cn, "id", '/', &id_str)) {
+ log_error("Missing uuid in metadata disk_area section "
+ "of config file");
+ return 0;
+ }
+
+ if (!id_read_format(&id, id_str)) {
+ log_error("Invalid uuid in metadata disk_area section "
+ "of config file: %s", id_str);
+ return 0;
+ }
+
+ if (!(dev_area.dev = device_from_pvid(cmd, &id))) {
+ char buffer[64];
+
+ if (!id_write_format(&id, buffer, sizeof(buffer)))
+ log_err("Couldn't find device.");
+ else
+ log_err("Couldn't find device with uuid '%s'.", buffer);
+
+ return 0;
+ }
+
+ return _add_raw(raw_list, &dev_area);
+}
+
struct format_type *create_text_format(struct cmd_context *cmd)
{
struct format_type *fmt;
struct config_node *cn;
struct config_value *cv;
- struct list *dir_list;
+ struct mda_lists *mda_lists;
if (!(fmt = dbg_malloc(sizeof(*fmt)))) {
stack;
@@ -597,41 +1592,58 @@ struct format_type *create_text_format(struct cmd_context *cmd)
fmt->cmd = cmd;
fmt->ops = &_text_handler;
fmt->name = FMT_TEXT_NAME;
- fmt->features = FMT_SEGMENTS;
+ fmt->alias = FMT_TEXT_ALIAS;
+ fmt->features = FMT_SEGMENTS | FMT_MDAS;
- if (!(dir_list = dbg_malloc(sizeof(struct list)))) {
+ if (!(mda_lists = dbg_malloc(sizeof(struct mda_lists)))) {
log_error("Failed to allocate dir_list");
return NULL;
}
- list_init(dir_list);
- fmt->private = (void *) dir_list;
+ list_init(&mda_lists->dirs);
+ list_init(&mda_lists->raws);
+ mda_lists->file_ops = &_metadata_text_file_ops;
+ mda_lists->raw_ops = &_metadata_text_raw_ops;
+ fmt->private = (void *) mda_lists;
- if (!(cn = find_config_node(cmd->cf->root, "metadata/dirs", '/'))) {
- log_verbose("metadata/dirs not in config file: Defaulting "
- "to /etc/lvm/metadata");
- _add_dir("/etc/lvm/metadata", dir_list);
- return fmt;
+ if (!(fmt->labeller = text_labeller_create(fmt))) {
+ log_error("Couldn't create text label handler.");
+ return NULL;
}
- for (cv = cn->v; cv; cv = cv->next) {
- if (cv->type != CFG_STRING) {
- log_error("Invalid string in config file: "
- "metadata/dirs");
- goto err;
+ if (!(label_register_handler(FMT_TEXT_NAME, fmt->labeller))) {
+ log_error("Couldn't register text label handler.");
+ return NULL;
+ }
+
+ if ((cn = find_config_node(cmd->cf->root, "metadata/dirs", '/'))) {
+ for (cv = cn->v; cv; cv = cv->next) {
+ if (cv->type != CFG_STRING) {
+ log_error("Invalid string in config file: "
+ "metadata/dirs");
+ goto err;
+ }
+
+ if (!_add_dir(cv->v.str, &mda_lists->dirs)) {
+ log_error("Failed to add %s to internal device "
+ "cache", cv->v.str);
+ goto err;
+ }
}
+ }
- if (!_add_dir(cv->v.str, dir_list)) {
- log_error("Failed to add %s to internal device cache",
- cv->v.str);
+ if (!(cn = find_config_node(cmd->cf->root, "metadata/disk_areas", '/')))
+ return fmt;
+
+ for (cn = cn->child; cn; cn = cn->sib) {
+ if (!_get_config_disk_area(cmd, cn, &mda_lists->raws))
goto err;
- }
}
return fmt;
err:
- _free_dirs(dir_list);
+ _free_dirs(&mda_lists->dirs);
dbg_free(fmt);
return NULL;
diff --git a/lib/format_text/format-text.h b/lib/format_text/format-text.h
index d5c77c71..f14c0adf 100644
--- a/lib/format_text/format-text.h
+++ b/lib/format_text/format-text.h
@@ -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
diff --git a/lib/format_text/import-export.h b/lib/format_text/import-export.h
index f86249a9..f630285c 100644
--- a/lib/format_text/import-export.h
+++ b/lib/format_text/import-export.h
@@ -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
diff --git a/lib/format_text/import.c b/lib/format_text/import.c
index 4028d71e..8d8acd1e 100644
--- a/lib/format_text/import.c
+++ b/lib/format_text/import.c
@@ -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)
+#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 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;
- }
+ struct volume_group *vg = NULL;
+ struct config_tree *cf;
+ struct text_vg_version_ops **vsn;
- return 1;
-}
+ static int _initialised = 0;
-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;
+ if (!_initialised) {
+ _text_vsn_list[0] = text_vg_vsn1_init();
+ _text_vsn_list[1] = NULL;
+ _initialised = 1;
}
- lv = lvl->lv;
+ *desc = NULL;
+ *when = 0;
- if (!(lv->name = pool_strdup(mem, lvn->key))) {
+ if (!(cf = create_config_tree())) {
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;
+ goto out;
}
- 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;
+ 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;
}
- /*
- * 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.
+ /*
+ * Find a set of version functions that can read this file
*/
- 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;
+ for (vsn = &_text_vsn_list[0]; *vsn; vsn++) {
+ if (!(*vsn)->check_version(cf))
+ continue;
- 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)) {
+ if (!(vg = (*vsn)->read_vg(fid, cf))) {
stack;
- return 0;
+ goto out;
}
- }
-
- 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;
+ (*vsn)->read_desc(fid->fmt->cmd->mem, cf, when, desc);
+ break;
}
- 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.
- */
+ out:
+ destroy_config_tree(cf);
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)
+struct volume_group *text_vg_import_file(struct format_instance *fid,
+ const char *file,
+ 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)
-{
- struct volume_group *vg = NULL;
- struct config_file *cf;
-
- *desc = NULL;
- *when = 0;
-
- if (!(cf = create_config_file())) {
- stack;
- goto out;
- }
-
- if (!read_config(cf, file)) {
- log_error("Couldn't read volume group file.");
- goto out;
- }
-
- if (!_check_version(cf))
- goto out;
-
- if (!(vg = _read_vg(fid, cf, um))) {
- stack;
- goto out;
- }
-
- _read_desc(fid->fmt->cmd->mem, cf, when, desc);
-
- out:
- destroy_config_file(cf);
- return vg;
+ return text_vg_import_fd(fid, file, -1, 0, 0, 0, 0, NULL, 0,
+ when, desc);
}
diff --git a/lib/format_text/import_vsn1.c b/lib/format_text/import_vsn1.c
new file mode 100644
index 00000000..cb944f7c
--- /dev/null
+++ b/lib/format_text/import_vsn1.c
@@ -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;
+};
diff --git a/lib/format_text/layout.h b/lib/format_text/layout.h
new file mode 100644
index 00000000..92ba02bb
--- /dev/null
+++ b/lib/format_text/layout.h
@@ -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
diff --git a/lib/format_text/sample.vg b/lib/format_text/sample.vg
deleted file mode 100644
index f4c28e4a..00000000
--- a/lib/format_text/sample.vg
+++ /dev/null
@@ -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
- ]
- }
- }
-} \ No newline at end of file
diff --git a/lib/format_text/text_label.c b/lib/format_text/text_label.c
new file mode 100644
index 00000000..b39d61ef
--- /dev/null
+++ b/lib/format_text/text_label.c
@@ -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;
+}
diff --git a/lib/label/label.c b/lib/label/label.c
index dcc523ec..d1618b70 100644
--- a/lib/label/label.c
+++ b/lib/label/label.c
@@ -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;
+
+ memset(buf, 0, LABEL_SIZE);
- if (!(l = _find_labeller(dev))) {
+ 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;
+ }
+
+ /* 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));
+
+ 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;
+ }
+ }
+ }
+
+ 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;
- struct list *lih;
- struct labeller_i *li;
- 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;
- }
+ if (!(l = _find_labeller(dev, buf, &sector))) {
+ stack;
+ return 0;
}
- log_debug("No label on device '%s'.", dev_name(dev));
- 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;
}
diff --git a/lib/label/label.h b/lib/label/label.h
index ec652c84..bd9549bb 100644
--- a/lib/label/label.h
+++ b/lib/label/label.h
@@ -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);
+ int (*write) (struct label * label, char *buf);
/*
- * Remove a label from a device.
+ * Read a label from a volume.
*/
- int (*remove)(struct labeller *l, struct device *dev);
+ int (*read) (struct labeller * l, struct device * dev,
+ char *buf, struct label ** label);
/*
- * Read a label from a volume.
+ * Additional consistency checks for the paranoid.
*/
- int (*read)(struct labeller *l,
- struct device *dev, struct label **label);
+ int (*verify) (struct labeller * l, char *buf, uint64_t sector);
/*
- * Additional consistency checks for the paranoid.
+ * Populate label_type etc.
*/
- int (*verify)(struct labeller *l, struct device *dev);
+ 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
diff --git a/lib/label/lvm2_label.c b/lib/label/lvm2_label.c
deleted file mode 100644
index d02675c0..00000000
--- a/lib/label/lvm2_label.c
+++ /dev/null
@@ -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);
-}
diff --git a/lib/label/lvm2_label.h b/lib/label/lvm2_label.h
deleted file mode 100644
index e9811846..00000000
--- a/lib/label/lvm2_label.h
+++ /dev/null
@@ -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);
diff --git a/lib/label/uuid-map.c b/lib/label/uuid-map.c
deleted file mode 100644
index 0e31021c..00000000
--- a/lib/label/uuid-map.c
+++ /dev/null
@@ -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
diff --git a/lib/label/uuid-map.h b/lib/label/uuid-map.h
deleted file mode 100644
index aff7a02f..00000000
--- a/lib/label/uuid-map.h
+++ /dev/null
@@ -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
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index 5a2136c6..569abfc3 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -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;
diff --git a/lib/metadata/merge.c b/lib/metadata/merge.c
index 86220046..67413a95 100644
--- a/lib/metadata/merge.c
+++ b/lib/metadata/merge.c
@@ -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);
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index 66850232..8941f826 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -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;
+
+ /* 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;
+ }
+ }
- if (!(vgs = get_vgs(cmd))) {
+ /* 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 (!(pv = pool_zalloc(cmd->mem, sizeof(*pv)))) {
- log_error("pv_list allocation for '%s' failed", pv_name);
+ if (!(dev = dev_cache_get(pv_name, cmd->filter))) {
+ stack;
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'",
+ if (!(label_read(dev, &label))) {
+ log_error("Failed to read label on physical volume %s",
pv_name);
return 0;
}
- /* Member of a format_text VG? */
- if (!(cmd->fmtt->ops->pv_read(cmd->fmtt, pv_name, pv))) {
+ 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;
+ }
+
+ /* 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;
diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h
index 9908470f..2c101048 100644
--- a/lib/metadata/metadata.h
+++ b/lib/metadata/metadata.h
@@ -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 */
-
-#define SPINDOWN_LV BIT(4) /* LV */
-#define BADBLOCK_ON BIT(5) /* LV */
-#define FIXED_MINOR BIT(6) /* LV */
-#define VISIBLE_LV BIT(7) /* LV */
-
-/*
- * 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 */
+/* May any free extents on this PV be used or must they be left free? */
+#define ALLOCATABLE_PV 0x00000008 /* PV */
-#define FMT_SEGMENTS 0x00000001 /* Arbitrary segment parameters? */
+#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 */
-#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);
-
- /*
- * 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);
+ int (*vg_setup) (struct format_instance * fi, struct volume_group * vg);
/*
- * 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);
+
+int pv_write(struct cmd_context *cmd, struct physical_volume *pv,
+ struct list *mdas, int64_t label_sector);
-struct physical_volume *pv_create(struct format_instance *fi,
- const char *name,
+/* 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
diff --git a/lib/metadata/pv_map.c b/lib/metadata/pv_map.c
index a30019e8..efde0848 100644
--- a/lib/metadata/pv_map.c
+++ b/lib/metadata/pv_map.c
@@ -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;
diff --git a/lib/metadata/snapshot_manip.c b/lib/metadata/snapshot_manip.c
index 06384ce8..23aeb18d 100644
--- a/lib/metadata/snapshot_manip.c
+++ b/lib/metadata/snapshot_manip.c
@@ -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);
diff --git a/make.tmpl.in b/make.tmpl.in
index 21988cba..e388b698 100644
--- a/make.tmpl.in
+++ b/make.tmpl.in
@@ -48,7 +48,7 @@ MAKEFLAGS = @JOBS@
endif
SUFFIXES=
-SUFFIXES=.c .d .o
+SUFFIXES=.c .d .o .so
CFLAGS+=-Wall
#CFLAGS+=-O2
@@ -57,10 +57,13 @@ CFLAGS+=-g -fno-omit-frame-pointer
#CFLAGS+=-pg
#LD_FLAGS=-pg
-CFLAGS+=-D_REENTRANT -DDEBUG_MEM -DDEBUG -D_GNU_SOURCE
+CFLAGS+=-DDEBUG_MEM -DDEBUG
#CFLAGS+=-DDEBUG_POOL
#CFLAGS+=-DBOUNDS_CHECK
+LIB_VERSION := $(shell cat $(top_srcdir)/VERSION | \
+ awk -F '.' '{printf "%s.%s",$$1,$$2}')
+
INCLUDES+=-I. -I$(top_srcdir)/include
INC_LNS=$(top_srcdir)/include/.symlinks_created
@@ -81,6 +84,10 @@ ifeq ("@HAVE_RL_COMPLETION_MATCHES@", "yes")
CFLAGS += -DHAVE_RL_COMPLETION_MATCHES
endif
+ifeq ("@LVM1@", "internal")
+ CFLAGS += -DLVM1_INTERNAL
+endif
+
OBJECTS=$(SOURCES:%.c=%.o)
SUBDIRS.install := $(SUBDIRS:=.install)
@@ -101,14 +108,21 @@ $(SUBDIRS.install):
$(MAKE) -C $(@:.install=) install
$(SUBDIRS.clean):
- $(MAKE) -C $(@:.clean=) clean
+ -$(MAKE) -C $(@:.clean=) clean
$(SUBDIRS.distclean):
- $(MAKE) -C $(@:.distclean=) distclean
+ -$(MAKE) -C $(@:.distclean=) distclean
%.o: %.c
$(CC) -c $(INCLUDES) $(CFLAGS) $< -o $@
+%.so: %.o
+ $(CC) -c $(INCLUDES) $(CFLAGS) %< -o $@
+
+%.so: $(OBJECTS)
+ $(CC) -shared -Wl,-soname,$(notdir $@).$(LIB_VERSION) \
+ -Wl,--version-script,.export.sym $(OBJECTS) -o $@
+
%.d: %.c
set -e; FILE=`echo $@ | sed 's/\\//\\\\\\//g;s/\\.d//g'`; \
DEPS=`echo $(DEPS) | sed -e 's/\\//\\\\\\//g'`; \
diff --git a/man/Makefile.in b/man/Makefile.in
index bd114b1c..0b688cb4 100644
--- a/man/Makefile.in
+++ b/man/Makefile.in
@@ -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
diff --git a/man/lvchange.8 b/man/lvchange.8
index 0b5fe2c1..f5fa1a42 100644
--- a/man/lvchange.8
+++ b/man/lvchange.8
@@ -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),
diff --git a/man/lvcreate.8 b/man/lvcreate.8
index da16d170..ed4ab82c 100644
--- a/man/lvcreate.8
+++ b/man/lvcreate.8
@@ -8,8 +8,10 @@ lvcreate \- create a logical volume in an existing volume group
[\-i/\-\-stripes Stripes [\-I/\-\-stripesize StripeSize]]
{\-l/\-\-extents LogicalExtentsNumber |
\-L/\-\-size LogicalVolumeSize[kKmMgGtT]}
+[\-M/\-\-persistent y/n] [\-\-minor minor]
[\-n/\-\-name LogicalVolumeName]
[\-p/\-\-permission r/rw] [\-r/\-\-readahead ReadAheadSectors]
+[\-t/\-\-test]
[\-v/\-\-verbose] [\-Z/\-\-zero y/n]
VolumeGroupName [PhysicalVolumePath...]
.br
@@ -37,13 +39,6 @@ keep the contents of the original logical volume for backup purposes.
.SH OPTIONS
See \fBlvm\fP for common options.
.TP
-.I \-A, \-\-autobackup y/n
-Controls automatic backup of VG metadata after the change ( see
-.B vgcfgbackup(8)
-).
-.br
-Default is yes.
-.TP
.I \-c, \-\-chunksize ChunkSize
Power of 2 chunk size for the snapshot logical volume between 4k and 1024k.
.TP
@@ -73,6 +68,12 @@ G for gigabytes or T for terabytes is optional.
.br
Default unit is megabytes.
.TP
+.I \-\-minor minor
+Set the minor number.
+.TP
+.I \-M, \-\-persistent y/n
+Set to y to make the minor number specified persistent.
+.TP
.I \-n, \-\-name LogicalVolumeName
The name for the new logical volume.
.br
@@ -86,6 +87,7 @@ Default is read and write.
.TP
.I \-r, \-\-readahead ReadAheadSectors
Set read ahead sector count of this logical volume to a value between 2 and 120.
+Ignored by device-mapper.
.TP
.I \-s, \-\-snapshot
Create a snapshot logical volume (or snapshot) for an existing, so called
@@ -122,7 +124,7 @@ contents of the original logical volume named /dev/vg00/lvol1
at snapshot logical volume creation time. If the original logical volume
contains a file system, you can mount the snapshot logical volume on an
arbitrary directory in order to access the contents of the filesystem to run
-a backup while the original filesystem is updated.
+a backup while the original filesystem continues to get updated.
.SH SEE ALSO
.BR lvm (8),
diff --git a/man/lvdisplay.8 b/man/lvdisplay.8
index 0a9f68af..401d3de1 100644
--- a/man/lvdisplay.8
+++ b/man/lvdisplay.8
@@ -3,8 +3,10 @@
lvdisplay \- display attributes of a logical volume
.SH SYNOPSIS
.B lvdisplay
-[\-c/\-\-colon] [\-d/\-\-debug] [\-D/\-\-disk] [\-h/\-?/\-\-help]
-[\-v[v]/\-\-verbose] LogicalVolumePath [LogicalVolumePath...]
+[\-c/\-\-colon] [\-d/\-\-debug] [\-h/\-?/\-\-help]
+[\-\-ignorelockingfailure]
+[\-\-maps] [\-P/\-\-partial]
+[\-v/\-\-verbose] LogicalVolumePath [LogicalVolumePath...]
.SH DESCRIPTION
lvdisplay allows you to see the attributes of a logical volume
like size, read/write status, snapshot information etc.
@@ -12,7 +14,8 @@ like size, read/write status, snapshot information etc.
See \fBlvm\fP for common options.
.TP
.I \-c, \-\-colon
-Generate colon seperated output for easier parsing in scripts or programs.
+Deprecated. To be replaced with a more-powerful reporting tool.
+Generate colon separated output for easier parsing in scripts or programs.
.nf
The values are:
@@ -33,11 +36,6 @@ The values are:
.fi
.TP
-.I \-D, \-\-disk
-Show attributes of the volume group descriptor array on disk(s).
-Without this switch they are derived from kernel space.
-Useful, if the volume group isn't active.
-.TP
.I \-m, \-\-maps
Display the mapping of logical extents to physical volumes and
physical extents.
diff --git a/man/lvextend.8 b/man/lvextend.8
index 98c379be..f9bb73aa 100644
--- a/man/lvextend.8
+++ b/man/lvextend.8
@@ -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.
diff --git a/man/lvm.8 b/man/lvm.8
index 055b73a1..e9882567 100644
--- a/man/lvm.8
+++ b/man/lvm.8
@@ -25,26 +25,61 @@ A file containing a simple script with one command per line
can also be given on the command line. The script can also be
executed directly if the first line is #! followed by the absolute
path of \fBlvm\fP.
+.LP
+Where commands take VG or LV names as arguments, the full path name is
+optional. An LV called "lvol0" in a VG called "vg0" can be specified
+as "vg0/lvol0". If a list of VGs is required but is left empty, a list of
+all VGs will be substituted. If a list of LVs is required
+but a VG is given, a list of all the LVs in that VG will be substituted.
+So "lvdisplay vg0" will display all the LVs in "vg0".
.SH OPTIONS
-The following options can be used with every command and are not documented
-on individual manual pages.
+The following options are available for many of the commands and are
+not documented on individual manual pages.
.TP
\fB-h | --help\fP \(em Display the help text.
.TP
-\fB--version\fP \(em Display the version.
-Not implemented yet.
+\fB--version\fP \(em Display version information.
.TP
\fB-v | --verbose\fP \(em Set verbose level.
-Repeat from 1 to 3 times to determine the detail of messages
+Repeat from 1 to 3 times to increase the detail of messages
sent to stdout and stderr. Overrides config file setting.
.TP
\fB-d | --debug\fP \(em Set debug level.
-Repeat from 1 to 6 times to determine the detail of messages sent
+Repeat from 1 to 6 times to increase the detail of messages sent
to the log file and/or syslog (if configured).
Overrides config file setting.
.TP
\fB--quiet\fP \(em Suppress output and log messages.
Overrides -d and -v.
+.TP
+\fB-t | --test\fP \(em Run in test mode.
+Commands will not update metadata.
+.TP
+\fB--driverloaded\fP { \fBy\fP | \fBn\fP }
+Whether or not the device-mapper kernel driver is loaded.
+If you set this to \fBn\fP, no attempt will be made to contact the driver.
+.TP
+\fB-A | --autobackup\fP { \fBy\fP | \fBn\fP }
+Whether or not to metadata should be backed up automatically after a change.
+You are strongly advised not to disable this!
+See
+.B vgcfgbackup (8).
+.TP
+\fB-P | --partial\fP
+When set, the tools will do their best to provide access to volume groups
+that are only partially available. Where part of a logical volume is
+missing, \fB/dev/ioerror\fP will be substituted, and you could use
+\fBdmsetup (8)\fP to set this up to return I/O errors when accessed,
+or create it as a large block device of nulls. Metadata may not be
+changed with this option. To insert a replacement physical volume
+of the same or large size use \fBpvcreate -u\fP to set the uuid to
+match the original followed by \fBvgcfgrestore (8)\fP.
+.TP
+\fB--ignorelockingfailure\fP
+This lets you proceed with read-only metadata operations such as
+\fBlvchange -ay\fP and \fBvgchange -ay\fP even if the locking module fails.
+One use for this is in a system init script if the lock directory
+is mounted read-only when the script runs.
.SH ENVIRONMENT VARIABLES
.TP
\fBLVM_SYSTEM_DIR\fP
@@ -53,14 +88,9 @@ system files.
Defaults to "/etc/lvm".
.TP
\fBHOME\fP
-Directory containing .lvm_history if the internal shell
+Directory containing .lvm_history if the internal readline shell
is invoked.
.TP
-\fBLVM_AUTOBACKUP\fP
-Set to "no" to disable automatic metadata
-backups and archiving. Not recommended.
-Defaults to "yes".
-.TP
\fBLVM_VG_NAME\fP
The volume group name that is assumed for
any reference to a logical volume that doesn't specify a path.
diff --git a/man/lvmchange.8 b/man/lvmchange.8
index 3bc3a72a..ef18c6b8 100644
--- a/man/lvmchange.8
+++ b/man/lvmchange.8
@@ -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)
diff --git a/man/lvreduce.8 b/man/lvreduce.8
index cc288f37..d9ce55e5 100644
--- a/man/lvreduce.8
+++ b/man/lvreduce.8
@@ -6,7 +6,8 @@ lvreduce \- reduce the size of a logical volume
[\-A/\-\-autobackup y/n] [\-d/\-\-debug] [\-f/\-\-force]
[\-h/\-?/\-\-help] {\-l/\-\-extents [\-]LogicalExtentsNumber |
\-L/\-\-size [\-]LogicalVolumeSize[kKmMgGtT]}
-[\-v/\-\-verbose] LogicalVolumePath
+[\-t/\-\-test]
+[\-v/\-\-verbose] LogicalVolume[Path]
.SH DESCRIPTION
lvreduce allows you to reduce the size of a logical volume.
Be careful when reducing a logical volume's size, because data in the
@@ -26,11 +27,6 @@ for information to create snapshots) is supported as well.
.SH OPTIONS
See \fBlvm\fP for common options.
.TP
-.I \-A, \-\-autobackup y/n
-Controls automatic backup of VG metadata after the change ( see
-.B vgcfgbackup(8)
-). Default is yes.
-.TP
.I \-f, \-\-force
Force size reduction without any question.
.TP
diff --git a/man/lvremove.8 b/man/lvremove.8
index 9e89c92b..69f693b8 100644
--- a/man/lvremove.8
+++ b/man/lvremove.8
@@ -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
diff --git a/man/lvrename.8 b/man/lvrename.8
index 47041413..11b4f24f 100644
--- a/man/lvrename.8
+++ b/man/lvrename.8
@@ -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
diff --git a/man/lvscan.8 b/man/lvscan.8
index 39859551..04b2b873 100644
--- a/man/lvscan.8
+++ b/man/lvscan.8
@@ -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),
diff --git a/man/pvchange.8 b/man/pvchange.8
index 41224d6e..e18cb890 100644
--- a/man/pvchange.8
+++ b/man/pvchange.8
@@ -4,6 +4,7 @@ pvchange \- change attributes of a physical volume
.SH SYNOPSIS
.B pvchange
[\-A/\-\-autobackup y/n] [\-d/\-\-debug] [\-h/\-?/\-\-help]
+[\-t/\-\-test]
[\-v/\-\-verbose] [\-a/\-\-all] [\-x/\-\-allocatable y/n] [PhysicalVolumePath...]
.SH DESCRIPTION
pvchange allows you to change the allocation permissions of one or
@@ -11,11 +12,6 @@ more physical volumes.
.SH OPTIONS
See \fBlvm\fP for common options.
.TP
-.I \-A, \-\-autobackup y/n
-Controls automatic backup of VG metadata after the change ( see
-.B vgcfgbackup(8)
-). Default is yes.
-.TP
.I \-a, \-\-all
If PhysicalVolumePath is not specified on the command line all
physical volumes are searched for and used.
diff --git a/man/pvcreate.8 b/man/pvcreate.8
index 681e3978..5bec86fd 100644
--- a/man/pvcreate.8
+++ b/man/pvcreate.8
@@ -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)"
diff --git a/man/pvdisplay.8 b/man/pvdisplay.8
index 840a4f9a..b1d0a089 100644
--- a/man/pvdisplay.8
+++ b/man/pvdisplay.8
@@ -22,7 +22,7 @@ The values are:
* physical volume device name
* volume group name
* physical volume size in kilobytes
-* internal physical volume number
+* internal physical volume number (obsolete)
* physical volume status
* physical volume (not) allocatable
* current number of logical volumes on this physical volume
diff --git a/man/pvremove.8 b/man/pvremove.8
new file mode 100644
index 00000000..7dcf4234
--- /dev/null
+++ b/man/pvremove.8
@@ -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)
diff --git a/man/pvscan.8 b/man/pvscan.8
index 74736857..b8440c8f 100644
--- a/man/pvscan.8
+++ b/man/pvscan.8
@@ -6,6 +6,7 @@ pvscan \- scan all disks for physical volumes
.RB [ \-d | \-\-debug]
.RB [\-e | \-\-exported]
.RB [\-h | \-\-help]
+.RB [\-\-ignorelockingfailure]
.RB [ \-n | \-\-novolumegroup]
.RB [\-s | \-\-short]
.RB [\-u | \-\-uuid]
@@ -26,7 +27,7 @@ Only show physical volumes not belonging to any volume group.
Short listing format.
.TP
.BR \-u ", " \-\-uuid
-Show UUIDs (Unifrom Unique Identifiers) in addition to device special names.
+Show UUIDs (Uniform Unique Identifiers) in addition to device special names.
.SH SEE ALSO
.BR lvm (8),
.BR pvcreate (8),
diff --git a/man/vgcfgbackup.8 b/man/vgcfgbackup.8
index f6b340fe..85f47395 100644
--- a/man/vgcfgbackup.8
+++ b/man/vgcfgbackup.8
@@ -4,17 +4,19 @@ vgcfgbackup \- backup volume group descriptor area
.SH SYNOPSIS
.B vgcfgbackup
.RB [ \-d | \-\-debug ]
+.RB [ \-f | \-\-file " filename" ]
.RB [ \-h | \-\-help ]
+.RB [ \-\-ignorelockingfailure ]
+.RB [ \-P | \-\-partial ]
.RB [ \-v | \-\-verbose ]
.RI [ VolumeGroupName ...]
.SH DESCRIPTION
.B vgcfgbackup
allows you to backup the metadata
-of one to all volume groups to files in
-.IR /etc/lvm .
-If you don't give any volume groups in the command line, all of them
+of your volume groups.
+If you don't name any volume groups pn the command line, all of them
will be backed up. This DOESN'T backup user/system data in logical
-volume(s)!
+volume(s)! Backup /etc/lvm regularly too.
.SH OPTIONS
See \fBlvm\fP for common options.
.SH SEE ALSO
diff --git a/man/vgcfgrestore.8 b/man/vgcfgrestore.8
new file mode 100644
index 00000000..6ce8e6cf
--- /dev/null
+++ b/man/vgcfgrestore.8
@@ -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)
diff --git a/man/vgchange.8 b/man/vgchange.8
index 54f6b5c1..e48efd21 100644
--- a/man/vgchange.8
+++ b/man/vgchange.8
@@ -3,14 +3,17 @@
vgchange \- change attributes of a volume group
.SH SYNOPSIS
.B vgchange
-.RB [ \-A | \-\-autobackup " {" y | n }]
+.RB [\-A | \-\-autobackup " {" y | n }]
.RB [\-a | \-\-available " {" y | n }]
.RB [\-d | \-\-debug]
-.RB [ \-h | \-\-help]
+.RB [\-h | \-\-help]
+.RB [\-\-ignorelockingfailure]
.RB [\-l | \-\-logicalvolume
.IR MaxLogicalVolumes ]
-.RB [ \-v | \-\-verbose ]
-.RB [ \-\-version ]
+.RB [\-P | \-\-partial]
+.RB [-t | \-\-test]
+.RB [\-v | \-\-verbose]
+.RB [\-\-version ]
.RB [\-x | \-\-resizeable " {" y | n }]
.RI [ VolumeGroupName ...]
.SH DESCRIPTION
@@ -20,12 +23,13 @@ Its main purpose is to activate and deactivate
.IR VolumeGroupName ,
or all volume groups if none is specified. Only active volume groups
are subject to changes and allow access to their logical volumes.
-During volume group activation, if
+[Not yet implemented: During volume group activation, if
.B vgchange
recognizes snapshot logical volumes which were dropped because they ran
out of space, it displays a message informing the administrator that such
snapshots should be removed (see
.BR lvremove (8)).
+]
.SH OPTIONS
See \fBlvm\fP for common options.
.TP
diff --git a/man/vgconvert.8 b/man/vgconvert.8
new file mode 100644
index 00000000..4de0da43
--- /dev/null
+++ b/man/vgconvert.8
@@ -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)"
diff --git a/man/vgcreate.8 b/man/vgcreate.8
index 01241ea7..6916bebf 100644
--- a/man/vgcreate.8
+++ b/man/vgcreate.8
@@ -8,10 +8,12 @@ vgcreate \- create a volume group
.RB [ \-h | \-\-help ]
.RB [ \-l | \-\-maxlogicalvolumes
.IR MaxLogicalVolumes ]
+.RB [ -M | \-\-metadatatype type]
.RB [ -p | \-\-maxphysicalvolumes
.IR MaxPhysicalVolumes ]
.RB [ \-s | \-\-physicalextentsize
.IR PhysicalExtentSize [ \fBkKmMgGtT\fR ]]
+.RB [ \-t | \-\-test ]
.RB [ \-v | \-\-verbose ]
.RB [ \-\-version ]
.I VolumeGroupName PhysicalVolumePath
diff --git a/man/vgdisplay.8 b/man/vgdisplay.8
index a4849408..4f958bb9 100644
--- a/man/vgdisplay.8
+++ b/man/vgdisplay.8
@@ -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
diff --git a/man/vgextend.8 b/man/vgextend.8
index cd81503c..1e8d84aa 100644
--- a/man/vgextend.8
+++ b/man/vgextend.8
@@ -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
diff --git a/man/vgmerge.8 b/man/vgmerge.8
index 12c27934..172d9484 100644
--- a/man/vgmerge.8
+++ b/man/vgmerge.8
@@ -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
diff --git a/man/vgreduce.8 b/man/vgreduce.8
index d81ea988..55ab1c24 100644
--- a/man/vgreduce.8
+++ b/man/vgreduce.8
@@ -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)
diff --git a/man/vgremove.8 b/man/vgremove.8
index 7a193102..7096fe2f 100644
--- a/man/vgremove.8
+++ b/man/vgremove.8
@@ -3,7 +3,7 @@
vgremove \- remove a volume group
.SH SYNOPSIS
.B vgremove
-[\-d/\-\-debug] [\-h/\-?/\-\-help] [\-v/\-\-verbose]
+[\-d/\-\-debug] [\-h/\-?/\-\-help] [\-t/\-\-test] [\-v/\-\-verbose]
VolumeGroupName [VolumeGroupName...]
.SH DESCRIPTION
vgremove allows you to remove one or more volume groups.
diff --git a/man/vgrename.8 b/man/vgrename.8
index 32870304..b0f570cd 100644
--- a/man/vgrename.8
+++ b/man/vgrename.8
@@ -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".
diff --git a/man/vgscan.8 b/man/vgscan.8
index 1715c0d0..2f596583 100644
--- a/man/vgscan.8
+++ b/man/vgscan.8
@@ -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
diff --git a/scripts/vg_convert b/scripts/vg_convert
new file mode 100755
index 00000000..0fa7e710
--- /dev/null
+++ b/scripts/vg_convert
@@ -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
+
diff --git a/tools/Makefile.in b/tools/Makefile.in
index 800b43eb..42ae8aef 100644
--- a/tools/Makefile.in
+++ b/tools/Makefile.in
@@ -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 \
diff --git a/tools/archive.c b/tools/archive.c
index 15251b51..8fdafc26 100644
--- a/tools/archive.c
+++ b/tools/archive.c
@@ -4,18 +4,8 @@
* This file is released under the GPL.
*/
-#include "log.h"
-#include "archive.h"
-#include "dbg_malloc.h"
-#include "format-text.h"
-#include "lvm-string.h"
-#include "toollib.h"
-
#include "tools.h"
-#include <unistd.h>
-#include <limits.h>
-
static struct {
int enabled;
char *dir;
@@ -97,7 +87,7 @@ int archive(struct volume_group *vg)
return 1;
if (test_mode()) {
- log_print("Test mode: Skipping archiving of volume group.");
+ log_verbose("Test mode: Skipping archiving of volume group.");
return 1;
}
@@ -113,7 +103,7 @@ int archive(struct volume_group *vg)
int archive_display(struct cmd_context *cmd, const char *vg_name)
{
- return archive_list(cmd, cmd->um, _archive_params.dir, vg_name);
+ return archive_list(cmd, _archive_params.dir, vg_name);
}
static struct {
@@ -153,11 +143,8 @@ void backup_enable(int flag)
static int __backup(struct volume_group *vg)
{
- int r;
- struct format_instance *tf;
char name[PATH_MAX];
char *desc;
- void *context;
if (!(desc = _build_desc(vg->cmd->mem, vg->cmd->cmd_line, 0))) {
stack;
@@ -173,20 +160,7 @@ static int __backup(struct volume_group *vg)
log_verbose("Creating volume group backup \"%s\"", name);
- if (!(context = create_text_context(vg->cmd->fmtt, name, desc)) ||
- !(tf = vg->cmd->fmtt->ops->create_instance(vg->cmd->fmtt, NULL,
- context))) {
- stack;
- return 0;
- }
-
- if (!(r = tf->fmt->ops->vg_write(tf, vg, context)) ||
- !(r = tf->fmt->ops->vg_commit(tf, vg, context)))
- stack;
-
- tf->fmt->ops->destroy_instance(tf);
-
- return r;
+ return backup_to_file(name, desc, vg);
}
int backup(struct volume_group *vg)
@@ -197,7 +171,7 @@ int backup(struct volume_group *vg)
}
if (test_mode()) {
- log_print("Test mode: Skipping volume group backup.");
+ log_verbose("Test mode: Skipping volume group backup.");
return 1;
}
@@ -227,57 +201,73 @@ int backup_remove(const char *vg_name)
return 1;
}
-static struct volume_group *_read_vg(struct cmd_context *cmd,
- const char *vg_name, const char *file)
+struct volume_group *backup_read_vg(struct cmd_context *cmd,
+ const char *vg_name, const char *file)
{
struct volume_group *vg;
struct format_instance *tf;
+ struct list *mdah;
+ struct metadata_area *mda;
void *context;
- if (!(context = create_text_context(cmd->fmtt, file,
+ if (!(context = create_text_context(cmd, file,
cmd->cmd_line)) ||
- !(tf = cmd->fmtt->ops->create_instance(cmd->fmtt, NULL, context))) {
+ !(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
+ context))) {
log_error("Couldn't create text format object.");
return NULL;
}
- if (!(vg = tf->fmt->ops->vg_read(tf, vg_name, context)))
- stack;
+ list_iterate(mdah, &tf->metadata_areas) {
+ mda = list_item(mdah, struct metadata_area);
+ if (!(vg = mda->ops->vg_read(tf, vg_name, mda)))
+ stack;
+ break;
+ }
tf->fmt->ops->destroy_instance(tf);
return vg;
}
-int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name,
- const char *file)
+/* ORPHAN and VG locks held before calling this */
+int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg)
{
- struct volume_group *vg;
+ struct list *pvh;
+ struct physical_volume *pv;
+ struct cache_info *info;
/*
- * Read in the volume group.
+ * FIXME: Check that the PVs referenced in the backup are
+ * not members of other existing VGs.
*/
- if (!(vg = _read_vg(cmd, vg_name, file))) {
- stack;
+
+ /* Attempt to write out using currently active format */
+ if (!(vg->fid = cmd->fmt->ops->create_instance(cmd->fmt, vg->name,
+ NULL))) {
+ log_error("Failed to allocate format instance");
return 0;
}
- /*
- * Check that those pv's referenced in the backup are
- * currently orphans or members of the vg.s
- */
- /*
- * FIXME: waiting for label code.
- */
-
- /*
- * Write the vg.
- */
-
- /* FIXME How do I find what format to write out the VG in? */
- /* Must store the format type inside the backup? */
- if (!(vg->fid = cmd->fmt1->ops->create_instance(cmd->fmt1, NULL, NULL))) {
- log_error("Failed to allocate format1 instance");
- return 0;
+ /* Add any metadata areas on the PVs */
+ list_iterate(pvh, &vg->pvs) {
+ pv = list_item(pvh, struct pv_list)->pv;
+ if (!(info = info_from_pvid(pv->dev->pvid))) {
+ log_error("PV %s missing from cache",
+ dev_name(pv->dev));
+ return 0;
+ }
+ if (cmd->fmt != info->fmt) {
+ log_error("PV %s is a different format (%s)",
+ dev_name(pv->dev), info->fmt->name);
+ return 0;
+ }
+ if (!vg->fid->fmt->ops->
+ pv_setup(vg->fid->fmt, 0, 0, 0, 0, 0,
+ &vg->fid->metadata_areas, pv, vg)) {
+ log_error("Format-specific setup for %s failed",
+ dev_name(pv->dev));
+ return 0;
+ }
}
if (!vg_write(vg)) {
@@ -288,6 +278,23 @@ int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name,
return 1;
}
+/* ORPHAN and VG locks held before calling this */
+int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name,
+ const char *file)
+{
+ struct volume_group *vg;
+
+ /*
+ * Read in the volume group from the text file.
+ */
+ if (!(vg = backup_read_vg(cmd, vg_name, file))) {
+ stack;
+ return 0;
+ }
+
+ return backup_restore_vg(cmd, vg);
+}
+
int backup_restore(struct cmd_context *cmd, const char *vg_name)
{
char path[PATH_MAX];
@@ -300,3 +307,38 @@ int backup_restore(struct cmd_context *cmd, const char *vg_name)
return backup_restore_from_file(cmd, vg_name, path);
}
+
+int backup_to_file(const char *file, const char *desc, struct volume_group *vg)
+{
+ int r;
+ struct format_instance *tf;
+ struct list *mdah;
+ struct metadata_area *mda;
+ void *context;
+ struct cmd_context *cmd;
+
+ cmd = vg->cmd;
+
+ if (!(context = create_text_context(cmd, file, desc)) ||
+ !(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
+ context))) {
+ log_error("Couldn't create backup object.");
+ return 0;
+ }
+
+ /* Write and commit the metadata area */
+ list_iterate(mdah, &tf->metadata_areas) {
+ mda = list_item(mdah, struct metadata_area);
+ if (!(r = mda->ops->vg_write(tf, vg, mda))) {
+ stack;
+ continue;
+ }
+ if (mda->ops->vg_commit &&
+ !(r = mda->ops->vg_commit(tf, vg, mda))) {
+ stack;
+ }
+ }
+
+ tf->fmt->ops->destroy_instance(tf);
+ return r;
+}
diff --git a/tools/archive.h b/tools/archive.h
index f0f34eb2..157ae805 100644
--- a/tools/archive.h
+++ b/tools/archive.h
@@ -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
diff --git a/tools/args.h b/tools/args.h
index ecfb1d12..15d47349 100644
--- a/tools/args.h
+++ b/tools/args.h
@@ -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)
-
diff --git a/tools/commands.h b/tools/commands.h
index 672cb2f2..b2e4868c 100644
--- a/tools/commands.h
+++ b/tools/commands.h
@@ -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"
diff --git a/tools/lvchange.c b/tools/lvchange.c
index 59d5901c..24cc73d0 100644
--- a/tools/lvchange.c
+++ b/tools/lvchange.c
@@ -20,120 +20,6 @@
#include "tools.h"
-static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv);
-static int lvchange_permission(struct cmd_context *cmd,
- struct logical_volume *lv);
-static int lvchange_availability(struct cmd_context *cmd,
- struct logical_volume *lv);
-static int lvchange_contiguous(struct cmd_context *cmd,
- struct logical_volume *lv);
-static int lvchange_readahead(struct cmd_context *cmd,
- struct logical_volume *lv);
-static int lvchange_persistent(struct cmd_context *cmd,
- struct logical_volume *lv);
-
-int lvchange(struct cmd_context *cmd, int argc, char **argv)
-{
- if (!arg_count(cmd, available_ARG) && !arg_count(cmd, contiguous_ARG)
- && !arg_count(cmd, permission_ARG) && !arg_count(cmd, readahead_ARG)
- && !arg_count(cmd, minor_ARG) && !arg_count(cmd, persistent_ARG)) {
- log_error("One or more of -a, -C, -m, -M, -p or -r required");
- return EINVALID_CMD_LINE;
- }
-
- if (arg_count(cmd, ignorelockingfailure_ARG) &&
- (arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) ||
- arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG))) {
- log_error("Only -a permitted with --ignorelockingfailure");
- return EINVALID_CMD_LINE;
- }
-
- if (!argc) {
- log_error("Please give logical volume path(s)");
- return EINVALID_CMD_LINE;
- }
-
- if (arg_count(cmd, minor_ARG) && argc != 1) {
- log_error("Only give one logical volume when specifying minor");
- return EINVALID_CMD_LINE;
- }
-
- if (!driver_is_loaded())
- return ECMD_FAILED;
-
- return process_each_lv(cmd, argc, argv, LCK_VG_WRITE, &lvchange_single);
-}
-
-static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv)
-{
- int doit = 0;
- int archived = 0;
-
- if (!(lv->vg->status & LVM_WRITE) &&
- (arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) ||
- arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG))) {
- log_error("Only -a permitted with read-only volume "
- "group \"%s\"", lv->vg->name);
- return EINVALID_CMD_LINE;
- }
-
- if (lv_is_origin(lv) &&
- (arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) ||
- arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG))) {
- log_error("Can't change logical volume \"%s\" under snapshot",
- lv->name);
- return ECMD_FAILED;
- }
-
- if (lv_is_cow(lv)) {
- log_error("Can't change snapshot logical volume \"%s\"",
- lv->name);
- return ECMD_FAILED;
- }
-
- /* access permission change */
- if (arg_count(cmd, permission_ARG)) {
- if (!archive(lv->vg))
- return ECMD_FAILED;
- archived = 1;
- doit += lvchange_permission(cmd, lv);
- }
-
- /* allocation policy change */
- if (arg_count(cmd, contiguous_ARG)) {
- if (!archived && !archive(lv->vg))
- return ECMD_FAILED;
- archived = 1;
- doit += lvchange_contiguous(cmd, lv);
- }
-
- /* read ahead sector change */
- if (arg_count(cmd, readahead_ARG)) {
- if (!archived && !archive(lv->vg))
- return ECMD_FAILED;
- archived = 1;
- doit += lvchange_readahead(cmd, lv);
- }
-
- /* read ahead sector change */
- if (arg_count(cmd, persistent_ARG)) {
- if (!archived && !archive(lv->vg))
- return ECMD_FAILED;
- archived = 1;
- doit += lvchange_persistent(cmd, lv);
- }
-
- if (doit)
- log_print("Logical volume \"%s\" changed", lv->name);
-
- /* availability change */
- if (arg_count(cmd, available_ARG))
- if (!lvchange_availability(cmd, lv))
- return ECMD_FAILED;
-
- return 0;
-}
-
static int lvchange_permission(struct cmd_context *cmd,
struct logical_volume *lv)
{
@@ -234,7 +120,7 @@ static int lvchange_contiguous(struct cmd_context *cmd,
}
/******** FIXME lv_check_contiguous?
- if ((lv_allocation & ALLOC_CONTIGUOUS)
+ if (want_contiguous)
&& (ret = lv_check_contiguous(vg, lv_index + 1)) == FALSE) {
log_error("No contiguous logical volume \"%s\"", lv->name);
return 0;
@@ -245,8 +131,8 @@ static int lvchange_contiguous(struct cmd_context *cmd,
log_verbose("Setting contiguous allocation policy for \"%s\"",
lv->name);
} else {
- lv->alloc = ALLOC_NEXT_FREE;
- log_verbose("Removing contiguous allocation policy for \"%s\"",
+ lv->alloc = ALLOC_DEFAULT;
+ log_verbose("Reverting to default allocation policy for \"%s\"",
lv->name);
}
@@ -371,3 +257,104 @@ static int lvchange_persistent(struct cmd_context *cmd,
return 1;
}
+
+static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
+ void *handle)
+{
+ int doit = 0;
+ int archived = 0;
+
+ if (!(lv->vg->status & LVM_WRITE) &&
+ (arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) ||
+ arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG))) {
+ log_error("Only -a permitted with read-only volume "
+ "group \"%s\"", lv->vg->name);
+ return EINVALID_CMD_LINE;
+ }
+
+ if (lv_is_origin(lv) &&
+ (arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) ||
+ arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG))) {
+ log_error("Can't change logical volume \"%s\" under snapshot",
+ lv->name);
+ return ECMD_FAILED;
+ }
+
+ if (lv_is_cow(lv)) {
+ log_error("Can't change snapshot logical volume \"%s\"",
+ lv->name);
+ return ECMD_FAILED;
+ }
+
+ /* access permission change */
+ if (arg_count(cmd, permission_ARG)) {
+ if (!archive(lv->vg))
+ return ECMD_FAILED;
+ archived = 1;
+ doit += lvchange_permission(cmd, lv);
+ }
+
+ /* allocation policy change */
+ if (arg_count(cmd, contiguous_ARG)) {
+ if (!archived && !archive(lv->vg))
+ return ECMD_FAILED;
+ archived = 1;
+ doit += lvchange_contiguous(cmd, lv);
+ }
+
+ /* read ahead sector change */
+ if (arg_count(cmd, readahead_ARG)) {
+ if (!archived && !archive(lv->vg))
+ return ECMD_FAILED;
+ archived = 1;
+ doit += lvchange_readahead(cmd, lv);
+ }
+
+ /* read ahead sector change */
+ if (arg_count(cmd, persistent_ARG)) {
+ if (!archived && !archive(lv->vg))
+ return ECMD_FAILED;
+ archived = 1;
+ doit += lvchange_persistent(cmd, lv);
+ }
+
+ if (doit)
+ log_print("Logical volume \"%s\" changed", lv->name);
+
+ /* availability change */
+ if (arg_count(cmd, available_ARG))
+ if (!lvchange_availability(cmd, lv))
+ return ECMD_FAILED;
+
+ return 0;
+}
+
+int lvchange(struct cmd_context *cmd, int argc, char **argv)
+{
+ if (!arg_count(cmd, available_ARG) && !arg_count(cmd, contiguous_ARG)
+ && !arg_count(cmd, permission_ARG) && !arg_count(cmd, readahead_ARG)
+ && !arg_count(cmd, minor_ARG) && !arg_count(cmd, persistent_ARG)) {
+ log_error("One or more of -a, -C, -m, -M, -p or -r required");
+ return EINVALID_CMD_LINE;
+ }
+
+ if (arg_count(cmd, ignorelockingfailure_ARG) &&
+ (arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) ||
+ arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG))) {
+ log_error("Only -a permitted with --ignorelockingfailure");
+ return EINVALID_CMD_LINE;
+ }
+
+ if (!argc) {
+ log_error("Please give logical volume path(s)");
+ return EINVALID_CMD_LINE;
+ }
+
+ if (arg_count(cmd, minor_ARG) && argc != 1) {
+ log_error("Only give one logical volume when specifying minor");
+ return EINVALID_CMD_LINE;
+ }
+
+ return process_each_lv(cmd, argc, argv, LCK_VG_WRITE, NULL,
+ &lvchange_single);
+}
diff --git a/tools/lvcreate.c b/tools/lvcreate.c
index 3065806c..59e9ed0a 100644
--- a/tools/lvcreate.c
+++ b/tools/lvcreate.c
@@ -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;
diff --git a/tools/lvdisplay.c b/tools/lvdisplay.c
index d421327c..69971b1b 100644
--- a/tools/lvdisplay.c
+++ b/tools/lvdisplay.c
@@ -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);
}
diff --git a/tools/lvm.c b/tools/lvm.c
index 366b906b..526c1847 100644
--- a/tools/lvm.c
+++ b/tools/lvm.c
@@ -5,9 +5,7 @@
*/
#include "tools.h"
-#include "archive.h"
#include "defaults.h"
-#include "lvm1_label.h"
#include "label.h"
#include "version.h"
@@ -19,10 +17,7 @@
#include <syslog.h>
#include <libgen.h>
#include <sys/stat.h>
-#include <ctype.h>
#include <time.h>
-#include <stdlib.h>
-#include <locale.h>
#ifdef READLINE_SUPPORT
#include <readline/readline.h>
@@ -46,136 +41,10 @@ struct arg the_args[ARG_COUNT + 1] = {
static int _array_size;
static int _num_commands;
static struct command *_commands;
-struct cmd_context *cmd;
-
-/* Whether or not to dump persistent filter state */
-static int _dump_filter;
static int _interactive;
-static FILE *_log;
-
-/* lvm1 label handler */
-static struct labeller *_lvm1_label;
-
-/*
- * This structure only contains those options that
- * can have a default and per command setting.
- */
-struct config_info {
- int debug;
- int verbose;
- int test;
- int syslog;
- const char *msg_prefix;
- int cmd_name; /* Show command name? */
-
- int archive; /* should we archive ? */
- int backup; /* should we backup ? */
-
- struct format_type *fmt;
-
- mode_t umask;
-};
-
-static struct config_info _default_settings;
-static struct config_info _current_settings;
-
-/*
- * The lvm_sys_dir contains:
- *
- * o The lvm configuration (lvm.conf)
- * o The persistent filter cache (.cache)
- * o Volume group backups (/backup)
- * o Archive of old vg configurations (/archive)
- */
-static char _sys_dir[PATH_MAX] = "/etc/lvm";
-static char _dev_dir[PATH_MAX];
-static char _proc_dir[PATH_MAX];
-
-/* static functions */
-static void register_commands(void);
-static struct command *find_command(const char *name);
-static void register_command(const char *name, command_fn fn,
- const char *desc, const char *usage, ...);
-static void create_new_command(const char *name, command_fn command,
- const char *desc, const char *usage,
- int nargs, int *args);
-
-static void alloc_command(void);
-static void add_getopt_arg(int arg, char **ptr, struct option **o);
-static int process_command_line(struct command *com, int *argc, char ***argv);
-static struct arg *find_arg(struct command *com, int a);
-static int process_common_commands(struct command *com);
-static int run_command(int argc, char **argv);
-static int init(void);
-static void fin(void);
-static int run_script(int argc, char **argv);
-
-#ifdef READLINE_SUPPORT
-static int shell(void);
-#endif
-
-static void display_help(void);
-
-int main(int argc, char **argv)
-{
- char *namebase, *base;
- int ret, alias = 0;
-
- if (!init())
- return -1;
-
- namebase = strdup(argv[0]);
- base = basename(namebase);
- while (*base == '/')
- base++;
- if (strcmp(base, "lvm"))
- alias = 1;
- free(namebase);
-
- register_commands();
-
-#ifdef READLINE_SUPPORT
- if (!alias && argc == 1) {
- ret = shell();
- goto out;
- }
-#endif
-
- if (!alias) {
- if (argc < 2) {
- log_fatal("Please supply an LVM command.");
- display_help();
- ret = EINVALID_CMD_LINE;
- goto out;
- }
-
- argc--;
- argv++;
- }
- ret = run_command(argc, argv);
- if ((ret == ENO_SUCH_CMD) && (!alias))
- ret = run_script(argc, argv);
- if (ret == ENO_SUCH_CMD)
- log_error("No such command. Try 'help'.");
-
- out:
- fin();
- return ret;
-}
-
-void usage(const char *name)
-{
- struct command *com = find_command(name);
-
- if (!com)
- return;
-
- log_error("%s: %s\n\n%s", com->name, com->desc, com->usage);
-}
-
-int yes_no_arg(struct arg *a)
+int yes_no_arg(struct cmd_context *cmd, struct arg *a)
{
a->sign = SIGN_NONE;
@@ -191,18 +60,26 @@ int yes_no_arg(struct arg *a)
return 1;
}
-int metadatatype_arg(struct arg *a)
+int metadatatype_arg(struct cmd_context *cmd, struct arg *a)
{
- if (!strcasecmp(a->value, cmd->fmtt->name))
- a->ptr = cmd->fmtt;
+ struct format_type *fmt;
+ struct list *fmth;
- else if (!strcasecmp(a->value, cmd->fmt1->name))
- a->ptr = cmd->fmt1;
+ char *format;
- else
- return 0;
+ format = a->value;
- return 1;
+ list_iterate(fmth, &cmd->formats) {
+ fmt = list_item(fmth, struct format_type);
+ if (!strcasecmp(fmt->name, format) ||
+ !strcasecmp(fmt->name + 3, format) ||
+ (fmt->alias && !strcasecmp(fmt->alias, format))) {
+ a->ptr = fmt;
+ return 1;
+ }
+ }
+
+ return 0;
}
int _get_int_arg(struct arg *a, char **ptr)
@@ -236,7 +113,7 @@ int _get_int_arg(struct arg *a, char **ptr)
return 1;
}
-int size_arg(struct arg *a)
+int size_arg(struct cmd_context *cmd, struct arg *a)
{
char *ptr;
int i;
@@ -283,7 +160,7 @@ int size_arg(struct arg *a)
return 1;
}
-int int_arg(struct arg *a)
+int int_arg(struct cmd_context *cmd, struct arg *a)
{
char *ptr;
@@ -293,7 +170,7 @@ int int_arg(struct arg *a)
return 1;
}
-int int_arg_with_sign(struct arg *a)
+int int_arg_with_sign(struct cmd_context *cmd, struct arg *a)
{
char *ptr;
@@ -303,7 +180,7 @@ int int_arg_with_sign(struct arg *a)
return 1;
}
-int minor_arg(struct arg *a)
+int minor_arg(struct cmd_context *cmd, struct arg *a)
{
char *ptr;
@@ -318,12 +195,12 @@ int minor_arg(struct arg *a)
return 1;
}
-int string_arg(struct arg *a)
+int string_arg(struct cmd_context *cmd, struct arg *a)
{
return 1;
}
-int permission_arg(struct arg *a)
+int permission_arg(struct cmd_context *cmd, struct arg *a)
{
a->sign = SIGN_NONE;
@@ -358,18 +235,45 @@ char yes_no_prompt(const char *prompt, ...)
return c;
}
-static void register_commands()
+static void __alloc(int size)
+{
+ if (!(_commands = dbg_realloc(_commands, sizeof(*_commands) * size))) {
+ log_fatal("Couldn't allocate memory.");
+ exit(ECMD_FAILED);
+ }
+
+ _array_size = size;
+}
+
+static void _alloc_command(void)
{
-#define xx(a, b, c...) register_command(# a, a, b, ## c, \
- debug_ARG, help_ARG, \
- version_ARG, verbose_ARG, \
- quiet_ARG, -1);
-#include "commands.h"
-#undef xx
+ if (!_array_size)
+ __alloc(32);
+
+ if (_array_size <= _num_commands)
+ __alloc(2 * _array_size);
}
-static void register_command(const char *name, command_fn fn,
- const char *desc, const char *usage, ...)
+static void _create_new_command(const char *name, command_fn command,
+ const char *desc, const char *usage,
+ int nargs, int *args)
+{
+ struct command *nc;
+
+ _alloc_command();
+
+ nc = _commands + _num_commands++;
+
+ nc->name = name;
+ nc->desc = desc;
+ nc->usage = usage;
+ nc->fn = command;
+ nc->num_args = nargs;
+ nc->valid_args = args;
+}
+
+static void _register_command(const char *name, command_fn fn,
+ const char *desc, const char *usage, ...)
{
int nargs = 0, i;
int *args;
@@ -394,10 +298,21 @@ static void register_command(const char *name, command_fn fn,
va_end(ap);
/* enter the command in the register */
- create_new_command(name, fn, desc, usage, nargs, args);
+ _create_new_command(name, fn, desc, usage, nargs, args);
+}
+
+static void _register_commands()
+{
+#define xx(a, b, c...) _register_command(# a, a, b, ## c, \
+ driverloaded_ARG, \
+ debug_ARG, help_ARG, \
+ version_ARG, verbose_ARG, \
+ quiet_ARG, -1);
+#include "commands.h"
+#undef xx
}
-static struct command *find_command(const char *name)
+static struct command *_find_command(const char *name)
{
int i;
char *namebase, *base;
@@ -418,41 +333,14 @@ static struct command *find_command(const char *name)
return _commands + i;
}
-static void create_new_command(const char *name, command_fn command,
- const char *desc, const char *usage,
- int nargs, int *args)
-{
- struct command *nc;
-
- alloc_command();
-
- nc = _commands + _num_commands++;
-
- nc->name = name;
- nc->desc = desc;
- nc->usage = usage;
- nc->fn = command;
- nc->num_args = nargs;
- nc->valid_args = args;
-}
-
-static void __alloc(int size)
+void usage(const char *name)
{
- if (!(_commands = dbg_realloc(_commands, sizeof(*_commands) * size))) {
- log_fatal("Couldn't allocate memory.");
- exit(ECMD_FAILED);
- }
-
- _array_size = size;
-}
+ struct command *com = _find_command(name);
-static void alloc_command(void)
-{
- if (!_array_size)
- __alloc(32);
+ if (!com)
+ return;
- if (_array_size <= _num_commands)
- __alloc(2 * _array_size);
+ log_error("%s: %s\n\n%s", com->name, com->desc, com->usage);
}
/*
@@ -464,7 +352,7 @@ static void alloc_command(void)
* we have only 1 ATM (--version) I think we can
* live with this restriction.
*/
-static void add_getopt_arg(int arg, char **ptr, struct option **o)
+static void _add_getopt_arg(int arg, char **ptr, struct option **o)
{
struct arg *a = the_args + arg;
@@ -484,7 +372,29 @@ static void add_getopt_arg(int arg, char **ptr, struct option **o)
}
}
-static int process_command_line(struct command *com, int *argc, char ***argv)
+static struct arg *_find_arg(struct command *com, int opt)
+{
+ struct arg *a;
+ int i, arg;
+
+ for (i = 0; i < com->num_args; i++) {
+ arg = com->valid_args[i];
+ a = the_args + arg;
+
+ /*
+ * opt should equal either the
+ * short arg, or the index into
+ * 'the_args'.
+ */
+ if ((a->short_arg && (opt == a->short_arg)) || (opt == arg))
+ return a;
+ }
+
+ return 0;
+}
+
+static int _process_command_line(struct cmd_context *cmd, int *argc,
+ char ***argv)
{
int i, opt;
char str[((ARG_COUNT + 1) * 2) + 1], *ptr = str;
@@ -501,8 +411,8 @@ static int process_command_line(struct command *com, int *argc, char ***argv)
}
/* fill in the short and long opts */
- for (i = 0; i < com->num_args; i++)
- add_getopt_arg(com->valid_args[i], &ptr, &o);
+ for (i = 0; i < cmd->command->num_args; i++)
+ _add_getopt_arg(cmd->command->valid_args[i], &ptr, &o);
*ptr = '\0';
memset(o, 0, sizeof(*o));
@@ -512,7 +422,7 @@ static int process_command_line(struct command *com, int *argc, char ***argv)
optind = 0;
while ((opt = getopt_long(*argc, *argv, str, opts, NULL)) >= 0) {
- a = find_arg(com, opt);
+ a = _find_arg(cmd->command, opt);
if (!a) {
log_fatal("Unrecognised option.");
@@ -528,7 +438,7 @@ static int process_command_line(struct command *com, int *argc, char ***argv)
a->value = optarg;
- if (!a->fn(a)) {
+ if (!a->fn(cmd, a)) {
log_error("Invalid argument %s", optarg);
return 0;
}
@@ -542,28 +452,7 @@ static int process_command_line(struct command *com, int *argc, char ***argv)
return 1;
}
-static struct arg *find_arg(struct command *com, int opt)
-{
- struct arg *a;
- int i, arg;
-
- for (i = 0; i < com->num_args; i++) {
- arg = com->valid_args[i];
- a = the_args + arg;
-
- /*
- * opt should equal either the
- * short arg, or the index into
- * 'the_args'.
- */
- if ((a->short_arg && (opt == a->short_arg)) || (opt == arg))
- return a;
- }
-
- return 0;
-}
-
-static int merge_synonym(int oldarg, int newarg)
+static int _merge_synonym(struct cmd_context *cmd, int oldarg, int newarg)
{
struct arg *old, *new;
@@ -600,37 +489,34 @@ int version(struct cmd_context *cmd, int argc, char **argv)
return ECMD_PROCESSED;
}
-static int process_common_commands(struct command *com)
+static int _get_settings(struct cmd_context *cmd)
{
- _current_settings = _default_settings;
+ cmd->current_settings = cmd->default_settings;
if (arg_count(cmd, debug_ARG))
- _current_settings.debug = _LOG_FATAL +
+ cmd->current_settings.debug = _LOG_FATAL +
(arg_count(cmd, debug_ARG) - 1);
if (arg_count(cmd, verbose_ARG))
- _current_settings.verbose = arg_count(cmd, verbose_ARG);
+ cmd->current_settings.verbose = arg_count(cmd, verbose_ARG);
if (arg_count(cmd, quiet_ARG)) {
- _current_settings.debug = 0;
- _current_settings.verbose = 0;
+ cmd->current_settings.debug = 0;
+ cmd->current_settings.verbose = 0;
}
if (arg_count(cmd, test_ARG))
- _current_settings.test = arg_count(cmd, test_ARG);
+ cmd->current_settings.test = arg_count(cmd, test_ARG);
- if (arg_count(cmd, help_ARG)) {
- usage(com->name);
- return ECMD_PROCESSED;
- }
-
- if (arg_count(cmd, version_ARG)) {
- return version(cmd, 0, (char **) NULL);
+ if (arg_count(cmd, driverloaded_ARG)) {
+ cmd->current_settings.activation =
+ arg_int_value(cmd, driverloaded_ARG,
+ cmd->default_settings.activation);
}
if (arg_count(cmd, autobackup_ARG)) {
- _current_settings.archive = 1;
- _current_settings.backup = 1;
+ cmd->current_settings.archive = 1;
+ cmd->current_settings.backup = 1;
}
if (arg_count(cmd, partial_ARG)) {
@@ -646,29 +532,31 @@ static int process_common_commands(struct command *com)
init_ignorelockingfailure(0);
/* Handle synonyms */
- if (!merge_synonym(resizable_ARG, resizeable_ARG) ||
- !merge_synonym(allocation_ARG, allocatable_ARG) ||
- !merge_synonym(allocation_ARG, resizeable_ARG))
- return ECMD_FAILED;
+ if (!_merge_synonym(cmd, resizable_ARG, resizeable_ARG) ||
+ !_merge_synonym(cmd, allocation_ARG, allocatable_ARG) ||
+ !_merge_synonym(cmd, allocation_ARG, resizeable_ARG))
+ return EINVALID_CMD_LINE;
- /* Zero indicates it's OK to continue processing this command */
+ /* Zero indicates success */
return 0;
}
-int help(struct cmd_context *cmd, int argc, char **argv)
+static int _process_common_commands(struct cmd_context *cmd)
{
- if (!argc)
- display_help();
- else {
- int i;
- for (i = 0; i < argc; i++)
- usage(argv[i]);
+ if (arg_count(cmd, help_ARG)) {
+ usage(cmd->command->name);
+ return ECMD_PROCESSED;
}
+ if (arg_count(cmd, version_ARG)) {
+ return version(cmd, 0, (char **) NULL);
+ }
+
+ /* Zero indicates it's OK to continue processing this command */
return 0;
}
-static void display_help(void)
+static void _display_help(void)
{
int i;
@@ -683,22 +571,38 @@ static void display_help(void)
}
}
-static void _use_settings(struct config_info *settings)
+int help(struct cmd_context *cmd, int argc, char **argv)
+{
+ if (!argc)
+ _display_help();
+ else {
+ int i;
+ for (i = 0; i < argc; i++)
+ usage(argv[i]);
+ }
+
+ return 0;
+}
+
+static void _apply_settings(struct cmd_context *cmd)
{
- init_debug(settings->debug);
- init_verbose(settings->verbose);
- init_test(settings->test);
+ init_debug(cmd->current_settings.debug);
+ init_verbose(cmd->current_settings.verbose);
+ init_test(cmd->current_settings.test);
+
+ init_msg_prefix(cmd->default_settings.msg_prefix);
+ init_cmd_name(cmd->default_settings.cmd_name);
- init_msg_prefix(_default_settings.msg_prefix);
- init_cmd_name(_default_settings.cmd_name);
+ archive_enable(cmd->current_settings.archive);
+ backup_enable(cmd->current_settings.backup);
- archive_enable(settings->archive);
- backup_enable(settings->backup);
+ set_activation(cmd->current_settings.activation);
- cmd->fmt = arg_ptr_value(cmd, metadatatype_ARG, settings->fmt);
+ cmd->fmt = arg_ptr_value(cmd, metadatatype_ARG,
+ cmd->current_settings.fmt);
}
-static char *_copy_command_line(struct pool *mem, int argc, char **argv)
+static char *_copy_command_line(struct cmd_context *cmd, int argc, char **argv)
{
int i;
@@ -720,59 +624,68 @@ static char *_copy_command_line(struct pool *mem, int argc, char **argv)
/*
* Terminate.
*/
- if (!pool_grow_object(mem, "\0", 1))
+ if (!pool_grow_object(cmd->mem, "\0", 1))
goto bad;
- return pool_end_object(mem);
+ return pool_end_object(cmd->mem);
bad:
log_err("Couldn't copy command line.");
- pool_abandon_object(mem);
+ pool_abandon_object(cmd->mem);
return NULL;
}
-static int run_command(int argc, char **argv)
+static int _run_command(struct cmd_context *cmd, int argc, char **argv)
{
int ret = 0;
int locking_type;
- if (!(cmd->cmd_line = _copy_command_line(cmd->mem, argc, argv)))
+ if (!(cmd->cmd_line = _copy_command_line(cmd, argc, argv)))
return ECMD_FAILED;
- if (!(cmd->command = find_command(argv[0])))
+ if (!(cmd->command = _find_command(argv[0])))
return ENO_SUCH_CMD;
- if (!process_command_line(cmd->command, &argc, &argv)) {
+ if (!_process_command_line(cmd, &argc, &argv)) {
log_error("Error during parsing of command line.");
return EINVALID_CMD_LINE;
}
set_cmd_name(cmd->command->name);
- if ((ret = process_common_commands(cmd->command)))
- return ret;
+ if (reload_config_file(&cmd->cf)) {
+ ;
+ /* FIXME Reinitialise various settings inc. logging, filters */
+ }
- _use_settings(&_current_settings);
+ if ((ret = _get_settings(cmd)))
+ goto out;
+ _apply_settings(cmd);
+
+ if ((ret = _process_common_commands(cmd)))
+ goto out;
locking_type = find_config_int(cmd->cf->root, "global/locking_type",
'/', 1);
if (!init_locking(locking_type, cmd->cf)) {
log_error("Locking type %d initialisation failed.",
locking_type);
- return 0;
+ ret = ECMD_FAILED;
+ goto out;
}
ret = cmd->command->fn(cmd, argc, argv);
fin_locking();
- /*
- * set the debug and verbose levels back
- * to the global default. We have to do
- * this so the logging levels get set
- * correctly for program exit.
- */
- _use_settings(&_default_settings);
+ out:
+ if (test_mode()) {
+ log_verbose("Test mode: Wiping internal cache");
+ cache_destroy();
+ }
+
+ cmd->current_settings = cmd->default_settings;
+ _apply_settings(cmd);
/*
* free off any memory the command used.
@@ -785,7 +698,7 @@ static int run_command(int argc, char **argv)
return ret;
}
-static int split(char *str, int *argc, char **argv, int max)
+static int _split(char *str, int *argc, char **argv, int max)
{
char *b = str, *e;
*argc = 0;
@@ -818,62 +731,13 @@ static void _init_rand(void)
srand((unsigned int) time(NULL) + (unsigned int) getpid());
}
-static void __init_log(struct config_file *cf)
-{
- char *open_mode = "a";
-
- const char *log_file;
-
- _default_settings.syslog =
- find_config_int(cf->root, "log/syslog", '/', 1);
- if (_default_settings.syslog != 1)
- fin_syslog();
-
- if (_default_settings.syslog > 1)
- init_syslog(_default_settings.syslog);
-
- _default_settings.debug =
- find_config_int(cf->root, "log/level", '/', 0);
- init_debug(_default_settings.debug);
-
- _default_settings.verbose =
- find_config_int(cf->root, "log/verbose", '/', 0);
- init_verbose(_default_settings.verbose);
-
- init_indent(find_config_int(cf->root, "log/indent", '/', 1));
-
- _default_settings.msg_prefix = find_config_str(cf->root, "log/prefix",
- '/', DEFAULT_MSG_PREFIX);
- init_msg_prefix(_default_settings.msg_prefix);
-
- _default_settings.cmd_name = find_config_int(cf->root,
- "log/command_names", '/',
- DEFAULT_CMD_NAME);
- init_cmd_name(_default_settings.cmd_name);
-
- _default_settings.test = find_config_int(cf->root, "global/test",
- '/', 0);
- if (find_config_int(cf->root, "log/overwrite", '/', 0))
- open_mode = "w";
-
- log_file = find_config_str(cf->root, "log/file", '/', 0);
- if (log_file) {
- /* set up the logging */
- if (!(_log = fopen(log_file, open_mode)))
- log_error("Couldn't open log file %s", log_file);
- else
- init_log(_log);
- }
-
-}
-
-static int _init_backup(struct config_file *cf)
+static int _init_backup(struct cmd_context *cmd, struct config_tree *cf)
{
int days, min;
char default_dir[PATH_MAX];
const char *dir;
- if (!_sys_dir) {
+ if (!cmd->sys_dir) {
log_warn("WARNING: Metadata changes will NOT be backed up");
backup_init("");
archive_init("", 0, 0);
@@ -881,7 +745,7 @@ static int _init_backup(struct config_file *cf)
}
/* set up archiving */
- _default_settings.archive =
+ cmd->default_settings.archive =
find_config_bool(cmd->cf->root, "backup/archive", '/',
DEFAULT_ARCHIVE_ENABLED);
@@ -891,10 +755,11 @@ static int _init_backup(struct config_file *cf)
min = find_config_int(cmd->cf->root, "backup/retain_min", '/',
DEFAULT_ARCHIVE_NUMBER);
- if (lvm_snprintf(default_dir, sizeof(default_dir), "%s/%s", _sys_dir,
- DEFAULT_ARCHIVE_SUBDIR) == -1) {
+ if (lvm_snprintf
+ (default_dir, sizeof(default_dir), "%s/%s", cmd->sys_dir,
+ DEFAULT_ARCHIVE_SUBDIR) == -1) {
log_err("Couldn't create default archive path '%s/%s'.",
- _sys_dir, DEFAULT_ARCHIVE_SUBDIR);
+ cmd->sys_dir, DEFAULT_ARCHIVE_SUBDIR);
return 0;
}
@@ -907,14 +772,15 @@ static int _init_backup(struct config_file *cf)
}
/* set up the backup */
- _default_settings.backup =
+ cmd->default_settings.backup =
find_config_bool(cmd->cf->root, "backup/backup", '/',
DEFAULT_BACKUP_ENABLED);
- if (lvm_snprintf(default_dir, sizeof(default_dir), "%s/%s", _sys_dir,
- DEFAULT_BACKUP_SUBDIR) == -1) {
+ if (lvm_snprintf
+ (default_dir, sizeof(default_dir), "%s/%s", cmd->sys_dir,
+ DEFAULT_BACKUP_SUBDIR) == -1) {
log_err("Couldn't create default backup path '%s/%s'.",
- _sys_dir, DEFAULT_BACKUP_SUBDIR);
+ cmd->sys_dir, DEFAULT_BACKUP_SUBDIR);
return 0;
}
@@ -929,269 +795,26 @@ static int _init_backup(struct config_file *cf)
return 1;
}
-static int dev_cache_setup(struct config_file *cf)
-{
- struct config_node *cn;
- struct config_value *cv;
-
- if (!dev_cache_init()) {
- stack;
- return 0;
- }
-
- if (!(cn = find_config_node(cf->root, "devices/scan", '/'))) {
- if (!dev_cache_add_dir("/dev")) {
- log_error("Failed to add /dev to internal "
- "device cache");
- return 0;
- }
- log_verbose
- ("device/scan not in config file: Defaulting to /dev");
- return 1;
- }
-
- for (cv = cn->v; cv; cv = cv->next) {
- if (cv->type != CFG_STRING) {
- log_error("Invalid string in config file: "
- "devices/scan");
- return 0;
- }
-
- if (!dev_cache_add_dir(cv->v.str)) {
- log_error("Failed to add %s to internal device cache",
- cv->v.str);
- return 0;
- }
- }
-
- return 1;
-}
-
-static struct dev_filter *filter_components_setup(struct config_file *cf)
-{
- struct config_node *cn;
- struct dev_filter *f1, *f2, *f3;
-
- if (!(f2 = lvm_type_filter_create(_proc_dir)))
- return 0;
-
- if (!(cn = find_config_node(cf->root, "devices/filter", '/'))) {
- log_debug("devices/filter not found in config file: no regex "
- "filter installed");
- return f2;
- }
-
- if (!(f1 = regex_filter_create(cn->v))) {
- log_error("Failed to create regex device filter");
- return f2;
- }
-
- if (!(f3 = composite_filter_create(2, f1, f2))) {
- log_error("Failed to create composite device filter");
- return f2;
- }
-
- return f3;
-}
-
-static struct dev_filter *filter_setup(struct config_file *cf)
-{
- const char *lvm_cache;
- struct dev_filter *f3, *f4;
- struct stat st;
- char cache_file[PATH_MAX];
-
- _dump_filter = 0;
-
- if (!(f3 = filter_components_setup(cmd->cf)))
- return 0;
-
- if (lvm_snprintf(cache_file, sizeof(cache_file),
- "%s/.cache", _sys_dir) < 0) {
- log_error("Persistent cache filename too long ('%s/.cache').",
- _sys_dir);
- return 0;
- }
-
- lvm_cache = find_config_str(cf->root, "devices/cache", '/', cache_file);
-
- if (!(f4 = persistent_filter_create(f3, lvm_cache))) {
- log_error("Failed to create persistent device filter");
- return 0;
- }
-
- /* Should we ever dump persistent filter state? */
- if (find_config_int(cf->root, "devices/write_cache_state", '/', 1))
- _dump_filter = 1;
-
- if (!*_sys_dir)
- _dump_filter = 0;
-
- if (!stat(lvm_cache, &st) && !persistent_filter_load(f4))
- log_verbose("Failed to load existing device cache from %s",
- lvm_cache);
-
- return f4;
-}
-
-static struct uuid_map *_init_uuid_map(struct dev_filter *filter)
-{
- label_init();
-
- /* add in the lvm1 labeller */
- if (!(_lvm1_label = lvm1_labeller_create())) {
- log_err("Couldn't create lvm1 label handler.");
- return 0;
- }
-
- if (!(label_register_handler("lvm1", _lvm1_label))) {
- log_err("Couldn't register lvm1 label handler.");
- return 0;
- }
-
- return uuid_map_create(filter);
-}
-
-static void _exit_uuid_map(void)
-{
- uuid_map_destroy(cmd->um);
- label_exit();
- _lvm1_label->ops->destroy(_lvm1_label);
- _lvm1_label = NULL;
-}
-
-static int _get_env_vars(void)
-{
- const char *e;
-
- /* Set to "" to avoid using any system directory */
- if ((e = getenv("LVM_SYSTEM_DIR"))) {
- if (lvm_snprintf(_sys_dir, sizeof(_sys_dir), "%s", e) < 0) {
- log_error("LVM_SYSTEM_DIR environment variable "
- "is too long.");
- return 0;
- }
- }
-
- return 1;
-}
-
-static int init(void)
+static struct cmd_context *_init(void)
{
- struct stat info;
- char config_file[PATH_MAX] = "";
- const char *format;
- mode_t old_umask;
-
- if (!setlocale(LC_ALL, ""))
- log_error("setlocale failed");
-
- if (!_get_env_vars())
- return 0;
+ struct cmd_context *cmd;
- /* Create system directory if it doesn't already exist */
- if (!create_dir(_sys_dir))
- return 0;
-
- if (!(cmd = dbg_malloc(sizeof(*cmd)))) {
- log_error("Failed to allocate command context");
- return 0;
- }
-
- cmd->args = &the_args[0];
-
- if (!(cmd->cf = create_config_file())) {
+ if (!(cmd = create_toolcontext(&the_args[0]))) {
stack;
- return 0;
+ return NULL;
}
- /* Use LOG_USER for syslog messages by default */
- init_syslog(LOG_USER);
-
_init_rand();
- if (*_sys_dir && lvm_snprintf(config_file, sizeof(config_file),
- "%s/lvm.conf", _sys_dir) < 0) {
- log_error("lvm_sys_dir was too long");
- return 0;
- }
-
- if (stat(config_file, &info) != -1 &&
- !read_config(cmd->cf, config_file)) {
- log_error("Failed to load config file %s", config_file);
- return 0;
- }
-
- __init_log(cmd->cf);
-
- _default_settings.umask = find_config_int(cmd->cf->root,
- "global/umask", '/',
- DEFAULT_UMASK);
-
- if ((old_umask = umask((mode_t) _default_settings.umask)) !=
- (mode_t) _default_settings.umask)
- log_verbose("Set umask to %04o", _default_settings.umask);
-
- if (lvm_snprintf(_dev_dir, sizeof(_dev_dir), "%s/",
- find_config_str(cmd->cf->root, "devices/dir",
- '/', DEFAULT_DEV_DIR)) < 0) {
- log_error("Device directory given in config file too long");
- return 0;
- }
-
- cmd->dev_dir = _dev_dir;
- dm_set_dev_dir(cmd->dev_dir);
-
- dm_log_init(print_log);
-
- if (lvm_snprintf(_proc_dir, sizeof(_proc_dir), "%s",
- find_config_str(cmd->cf->root, "global/proc",
- '/', DEFAULT_PROC_DIR)) < 0) {
- log_error("Device directory given in config file too long");
- return 0;
- }
+ if (!_init_backup(cmd, cmd->cf))
+ return NULL;
- if (!_init_backup(cmd->cf))
- return 0;
+ _apply_settings(cmd);
- if (!dev_cache_setup(cmd->cf))
- return 0;
-
- if (!(cmd->filter = filter_setup(cmd->cf))) {
- log_error("Failed to set up internal device filters");
- return 0;
- }
-
- /* the uuid map uses the filter */
- if (!(cmd->um = _init_uuid_map(cmd->filter))) {
- log_err("Failed to set up the uuid map.");
- return 0;
- }
-
- if (!(cmd->mem = pool_create(4 * 1024))) {
- log_error("Command pool creation failed");
- return 0;
- }
-
- /* FIXME Replace with list, dynamic libs etc. */
- if (!(cmd->fmt1 = create_lvm1_format(cmd)))
- return 0;
-
- if (!(cmd->fmtt = create_text_format(cmd)))
- return 0;
-
- format = find_config_str(cmd->cf->root, "global/format", '/',
- DEFAULT_FORMAT);
- if (!strcasecmp(format, "text"))
- _default_settings.fmt = cmd->fmtt;
- else /* "lvm1" */
- _default_settings.fmt = cmd->fmt1;
-
- _use_settings(&_default_settings);
- return 1;
+ return cmd;
}
-static void __fin_commands(void)
+static void _fin_commands(struct cmd_context *cmd)
{
int i;
@@ -1201,33 +824,16 @@ static void __fin_commands(void)
dbg_free(_commands);
}
-static void fin(void)
+static void _fin(struct cmd_context *cmd)
{
- if (_dump_filter)
- persistent_filter_dump(cmd->filter);
-
- cmd->fmt1->ops->destroy(cmd->fmt1);
- cmd->fmtt->ops->destroy(cmd->fmtt);
- cmd->filter->destroy(cmd->filter);
- pool_destroy(cmd->mem);
- vgcache_destroy();
- dev_cache_exit();
- destroy_config_file(cmd->cf);
archive_exit();
backup_exit();
- _exit_uuid_map();
- dbg_free(cmd);
- __fin_commands();
+ _fin_commands(cmd);
- dump_memory();
- fin_log();
- fin_syslog();
-
- if (_log)
- fclose(_log);
+ destroy_toolcontext(cmd);
}
-static int run_script(int argc, char **argv)
+static int _run_script(struct cmd_context *cmd, int argc, char **argv)
{
FILE *script;
@@ -1253,7 +859,7 @@ static int run_script(int argc, char **argv)
ret = EINVALID_CMD_LINE;
break;
}
- if (split(buffer, &argc, argv, MAX_ARGS) == MAX_ARGS) {
+ if (_split(buffer, &argc, argv, MAX_ARGS) == MAX_ARGS) {
buffer[50] = '\0';
log_error("Too many arguments: %s", buffer);
ret = EINVALID_CMD_LINE;
@@ -1263,7 +869,7 @@ static int run_script(int argc, char **argv)
continue;
if (!strcmp(argv[0], "quit") || !strcmp(argv[0], "exit"))
break;
- run_command(argc, argv);
+ _run_command(cmd, argc, argv);
}
fclose(script);
@@ -1337,7 +943,7 @@ static char *_list_args(const char *text, int state)
char c;
if (!(c = (the_args +
com->valid_args[match_no++])->short_arg))
- continue;
+ continue;
sprintf(s, "-%c", c);
if (!strncmp(text, s, len))
@@ -1394,7 +1000,7 @@ static int _hist_file(char *buffer, size_t size)
return 1;
}
-static void _read_history(void)
+static void _read_history(struct cmd_context *cmd)
{
char hist_file[PATH_MAX];
@@ -1420,7 +1026,7 @@ static void _write_history(void)
log_very_verbose("Couldn't write history to %s.", hist_file);
}
-static int shell(void)
+static int _shell(struct cmd_context *cmd)
{
int argc, ret;
char *input = NULL, *args[MAX_ARGS], **argv;
@@ -1428,7 +1034,7 @@ static int shell(void)
rl_readline_name = "lvm";
rl_attempted_completion_function = (CPPFunction *) _completion;
- _read_history();
+ _read_history(cmd);
_interactive = 1;
while (1) {
@@ -1449,7 +1055,7 @@ static int shell(void)
argv = args;
- if (split(input, &argc, argv, MAX_ARGS) == MAX_ARGS) {
+ if (_split(input, &argc, argv, MAX_ARGS) == MAX_ARGS) {
log_error("Too many arguments, sorry.");
continue;
}
@@ -1468,14 +1074,65 @@ static int shell(void)
break;
}
- ret = run_command(argc, argv);
+ ret = _run_command(cmd, argc, argv);
if (ret == ENO_SUCH_CMD)
log_error("No such command '%s'. Try 'help'.",
argv[0]);
+
+ _write_history();
}
- _write_history();
free(input);
return 0;
}
+
#endif
+
+int main(int argc, char **argv)
+{
+ char *namebase, *base;
+ int ret, alias = 0;
+ struct cmd_context *cmd;
+
+ if (!(cmd = _init()))
+ return -1;
+
+ namebase = strdup(argv[0]);
+ base = basename(namebase);
+ while (*base == '/')
+ base++;
+ if (strcmp(base, "lvm"))
+ alias = 1;
+ free(namebase);
+
+ _register_commands();
+
+#ifdef READLINE_SUPPORT
+ if (!alias && argc == 1) {
+ ret = _shell(cmd);
+ goto out;
+ }
+#endif
+
+ if (!alias) {
+ if (argc < 2) {
+ log_fatal("Please supply an LVM command.");
+ _display_help();
+ ret = EINVALID_CMD_LINE;
+ goto out;
+ }
+
+ argc--;
+ argv++;
+ }
+
+ ret = _run_command(cmd, argc, argv);
+ if ((ret == ENO_SUCH_CMD) && (!alias))
+ ret = _run_script(cmd, argc, argv);
+ if (ret == ENO_SUCH_CMD)
+ log_error("No such command. Try 'help'.");
+
+ out:
+ _fin(cmd);
+ return ret;
+}
diff --git a/tools/lvmdiskscan.c b/tools/lvmdiskscan.c
index c573517a..e65f80af 100644
--- a/tools/lvmdiskscan.c
+++ b/tools/lvmdiskscan.c
@@ -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));
diff --git a/tools/lvremove.c b/tools/lvremove.c
index 0e93866e..a41c1e59 100644
--- a/tools/lvremove.c
+++ b/tools/lvremove.c
@@ -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);
+}
diff --git a/tools/lvrename.c b/tools/lvrename.c
index e84e3c91..b061abd8 100644
--- a/tools/lvrename.c
+++ b/tools/lvrename.c
@@ -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;
}
diff --git a/tools/lvresize.c b/tools/lvresize.c
index 974c29b8..b058d8f5 100644
--- a/tools/lvresize.c
+++ b/tools/lvresize.c
@@ -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;
diff --git a/tools/lvscan.c b/tools/lvscan.c
index 044e2e6b..d0449288 100644
--- a/tools/lvscan.c
+++ b/tools/lvscan.c
@@ -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);
+}
diff --git a/tools/pvchange.c b/tools/pvchange.c
index b509f007..189c94d3 100644
--- a/tools/pvchange.c
+++ b/tools/pvchange.c
@@ -20,76 +20,19 @@
#include "tools.h"
-int pvchange_single(struct cmd_context *cmd, struct physical_volume *pv);
+/* FIXME Locking. PVs in VG. */
-int pvchange(struct cmd_context *cmd, int argc, char **argv)
-{
- int opt = 0;
- int done = 0;
- int total = 0;
-
- struct physical_volume *pv;
- char *pv_name;
-
- struct list *pvh, *pvs;
-
- if (arg_count(cmd, allocatable_ARG) == 0) {
- log_error("Please give the x option");
- return EINVALID_CMD_LINE;
- }
-
- if (!(arg_count(cmd, all_ARG)) && !argc) {
- log_error("Please give a physical volume path");
- return EINVALID_CMD_LINE;
- }
-
- if (arg_count(cmd, all_ARG) && argc) {
- log_error("Option a and PhysicalVolumePath are exclusive");
- return EINVALID_CMD_LINE;
- }
-
- if (argc) {
- log_verbose("Using physical volume(s) on command line");
- for (; opt < argc; opt++) {
- pv_name = argv[opt];
- if (!(pv = pv_read(cmd, pv_name))) {
- log_error
- ("Failed to read physical volume \"%s\"",
- pv_name);
- continue;
- }
- total++;
- done += pvchange_single(cmd, pv);
- }
- } else {
- log_verbose("Scanning for physical volume names");
- if (!(pvs = get_pvs(cmd))) {
- return ECMD_FAILED;
- }
-
- list_iterate(pvh, pvs) {
- total++;
- done += pvchange_single(cmd,
- list_item(pvh,
- struct pv_list)->pv);
- }
- }
-
- log_print("%d physical volume%s changed / %d physical volume%s "
- "not changed",
- done, done > 1 ? "s" : "",
- total - done, total - done > 1 ? "s" : "");
-
- return 0;
-}
-
-int pvchange_single(struct cmd_context *cmd, struct physical_volume *pv)
+int pvchange_single(struct cmd_context *cmd, struct physical_volume *pv,
+ void *handle)
{
struct volume_group *vg = NULL;
struct pv_list *pvl;
+ struct list mdas;
+ uint64_t sector;
const char *pv_name = dev_name(pv->dev);
+ int consistent = 1;
int allocatable =
!strcmp(arg_str_value(cmd, allocatable_ARG, "n"), "y");
@@ -103,7 +46,7 @@ int pvchange_single(struct cmd_context *cmd, struct physical_volume *pv)
return ECMD_FAILED;
}
- if (!(vg = vg_read(cmd, pv->vg_name))) {
+ if (!(vg = vg_read(cmd, pv->vg_name, &consistent))) {
unlock_vg(cmd, pv->vg_name);
log_error("Unable to find volume group of \"%s\"",
pv_name);
@@ -132,6 +75,18 @@ int pvchange_single(struct cmd_context *cmd, struct physical_volume *pv)
pv = pvl->pv;
if (!archive(vg))
return 0;
+ } else {
+ if (!lock_vol(cmd, ORPHAN, LCK_VG_WRITE)) {
+ log_error("Can't get lock for orphans");
+ return ECMD_FAILED;
+ }
+
+ if (!(pv = pv_read(cmd, pv_name, &mdas, &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;
+}
diff --git a/tools/pvcreate.c b/tools/pvcreate.c
index 0cc1d95f..7ca11ede 100644
--- a/tools/pvcreate.c
+++ b/tools/pvcreate.c
@@ -19,6 +19,7 @@
*/
#include "tools.h"
+#include "defaults.h"
const char _really_init[] =
"Really INITIALIZE physical volume \"%s\" of volume group \"%s\" [y/n]? ";
@@ -39,7 +40,7 @@ static int pvcreate_check(struct cmd_context *cmd, const char *name)
}
/* is there a pv here already */
- if (!(pv = pv_read(cmd, name)))
+ if (!(pv = pv_read(cmd, name, NULL, NULL)))
return 1;
/* orphan ? */
@@ -72,20 +73,28 @@ static int pvcreate_check(struct cmd_context *cmd, const char *name)
return 1;
}
-static void pvcreate_single(struct cmd_context *cmd, const char *pv_name)
+static void pvcreate_single(struct cmd_context *cmd, const char *pv_name,
+ void *handle)
{
- struct physical_volume *pv;
- struct format_instance *fid;
+ struct physical_volume *pv, *existing_pv;
struct id id, *idp = NULL;
char *uuid;
uint64_t size = 0;
struct device *dev;
+ struct list mdas;
+ int pvmetadatacopies;
+ uint64_t pvmetadatasize;
+ struct volume_group *vg;
+ char *restorefile;
+ uint64_t pe_start = 0;
+ uint32_t extent_count = 0, extent_size = 0;
if (arg_count(cmd, uuidstr_ARG)) {
uuid = arg_str_value(cmd, uuidstr_ARG, "");
if (!id_read_format(&id, uuid))
return;
- if ((dev = uuid_map_lookup(cmd->um, &id))) {
+ if ((dev = device_from_pvid(cmd, &id)) &&
+ (dev != dev_cache_get(pv_name, cmd->filter))) {
log_error("uuid %s already in use on \"%s\"", uuid,
dev_name(dev));
return;
@@ -93,32 +102,84 @@ static void pvcreate_single(struct cmd_context *cmd, const char *pv_name)
idp = &id;
}
- if (!pvcreate_check(cmd, pv_name))
+ if (arg_count(cmd, restorefile_ARG)) {
+ restorefile = arg_str_value(cmd, restorefile_ARG, "");
+ /* The uuid won't already exist */
+ init_partial(1);
+ if (!(vg = backup_read_vg(cmd, NULL, restorefile))) {
+ log_error("Unable to read volume group from %s",
+ restorefile);
+ return;
+ }
+ init_partial(0);
+ if (!(existing_pv = find_pv_in_vg_by_uuid(vg, idp))) {
+ log_error("Can't find uuid %s in backup file %s",
+ uuid, restorefile);
+ return;
+ }
+ pe_start = existing_pv->pe_start;
+ extent_size = existing_pv->pe_size;
+ extent_count = existing_pv->pe_count;
+ }
+
+ if (!lock_vol(cmd, "", LCK_VG_WRITE)) {
+ log_error("Can't get lock for orphan PVs");
return;
+ }
+
+ if (!pvcreate_check(cmd, pv_name))
+ goto error;
size = arg_int64_value(cmd, physicalvolumesize_ARG, 0) * 2;
- /* FIXME Use config file/cmd line to specify format */
- if (!(fid = cmd->fmt1->ops->create_instance(cmd->fmt1, NULL, NULL))) {
- log_error("Failed to create format1 instance");
- return;
+ pvmetadatasize = arg_int64_value(cmd, metadatasize_ARG, 0) * 2;
+ if (!pvmetadatasize)
+ pvmetadatasize = find_config_int(cmd->cf->root,
+ "metadata/pvmetadatasize",
+ '/', DEFAULT_PVMETADATASIZE);
+
+ pvmetadatacopies = arg_int_value(cmd, metadatacopies_ARG, -1);
+ if (pvmetadatacopies < 0)
+ pvmetadatacopies = find_config_int(cmd->cf->root,
+ "metadata/pvmetadatacopies",
+ '/',
+ DEFAULT_PVMETADATACOPIES);
+
+ if (!(dev = dev_cache_get(pv_name, cmd->filter))) {
+ log_error("%s: Couldn't find device.", pv_name);
+ goto error;
}
- if (!(pv = pv_create(fid, pv_name, idp, size))) {
+
+ list_init(&mdas);
+ if (!(pv = pv_create(cmd->fmt, dev, idp, size, pe_start,
+ extent_count, extent_size,
+ pvmetadatacopies, pvmetadatasize, &mdas))) {
log_error("Failed to setup physical volume \"%s\"", pv_name);
- return;
+ goto error;
}
log_verbose("Set up physical volume for \"%s\" with %" PRIu64
- " sectors", pv_name, pv->size);
+ " available sectors", pv_name, pv->size);
+
+ /* Wipe existing label first */
+ if (!label_remove(pv->dev)) {
+ log_error("Failed to wipe existing label on %s", pv_name);
+ goto error;
+ }
log_very_verbose("Writing physical volume data to disk \"%s\"",
pv_name);
- if (!(pv_write(cmd, pv))) {
+ if (!(pv_write(cmd, pv, &mdas, arg_int_value(cmd, labelsector_ARG,
+ DEFAULT_LABELSECTOR)))) {
log_error("Failed to write physical volume \"%s\"", pv_name);
- return;
+ goto error;
}
log_print("Physical volume \"%s\" successfully created", pv_name);
+
+ error:
+ unlock_vg(cmd, "");
+ return;
}
int pvcreate(struct cmd_context *cmd, int argc, char **argv)
@@ -130,6 +191,11 @@ int pvcreate(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
+ if (arg_count(cmd, restorefile_ARG) && !arg_count(cmd, uuidstr_ARG)) {
+ log_error("--uuid is required with --restorefile");
+ return EINVALID_CMD_LINE;
+ }
+
if (arg_count(cmd, uuidstr_ARG) && argc != 1) {
log_error("Can only set uuid on one volume at once");
return EINVALID_CMD_LINE;
@@ -140,8 +206,27 @@ int pvcreate(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
+ if (arg_int_value(cmd, labelsector_ARG, 0) >= LABEL_SCAN_SECTORS) {
+ log_error("labelsector must be less than %lu",
+ LABEL_SCAN_SECTORS);
+ return EINVALID_CMD_LINE;
+ }
+
+ if (!(cmd->fmt->features & FMT_MDAS) &&
+ (arg_count(cmd, metadatacopies_ARG) ||
+ arg_count(cmd, metadatasize_ARG))) {
+ log_error("Metadata parameters only apply to text format");
+ return EINVALID_CMD_LINE;
+ }
+
+ if (arg_count(cmd, metadatacopies_ARG) &&
+ arg_int_value(cmd, metadatacopies_ARG, -1) > 2) {
+ log_error("Metadatacopies may only be 0, 1 or 2");
+ return EINVALID_CMD_LINE;
+ }
+
for (i = 0; i < argc; i++) {
- pvcreate_single(cmd, argv[i]);
+ pvcreate_single(cmd, argv[i], NULL);
pool_empty(cmd->mem);
}
diff --git a/tools/pvdisplay.c b/tools/pvdisplay.c
index b526cc9b..ff4d121a 100644
--- a/tools/pvdisplay.c
+++ b/tools/pvdisplay.c
@@ -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;
+ 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);
}
- pv_display_pe_text(pv, pv->pe, lvs);
- } else
- log_print("no logical volume on physical volume \"%s\"",
- pv_name);
-**********/
+ } else {
+ log_verbose("Scanning for physical volume names");
+ if (!(pvs = get_pvs(cmd)))
+ return ECMD_FAILED;
- return;
+ list_iterate(pvh, pvs)
+ pvdisplay_single(cmd, list_item(pvh, struct pv_list)->pv,
+ NULL);
+ }
+
+ return 0;
}
diff --git a/tools/pvremove.c b/tools/pvremove.c
new file mode 100644
index 00000000..3410378f
--- /dev/null
+++ b/tools/pvremove.c
@@ -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;
+}
diff --git a/tools/pvscan.c b/tools/pvscan.c
index 868dea47..3f3b2f1b 100644
--- a/tools/pvscan.c
+++ b/tools/pvscan.c
@@ -20,11 +20,95 @@
#include "tools.h"
-void pvscan_display_single(struct cmd_context *cmd, struct physical_volume *pv);
-
int pv_max_name_len = 0;
int vg_max_name_len = 0;
+void pvscan_display_single(struct cmd_context *cmd, struct physical_volume *pv,
+ void *handle)
+{
+ char uuid[64];
+ int vg_name_len = 0;
+
+ char *s1, *s2;
+
+ char pv_tmp_name[NAME_LEN] = { 0, };
+ char vg_tmp_name[NAME_LEN] = { 0, };
+ char vg_name_this[NAME_LEN] = { 0, };
+
+ /* short listing? */
+ if (arg_count(cmd, short_ARG) > 0) {
+ log_print("%s", dev_name(pv->dev));
+ return;
+ }
+
+ if (arg_count(cmd, verbose_ARG) > 1) {
+ /* FIXME As per pv_display! Drop through for now. */
+ /* pv_show(pv); */
+
+ /* FIXME - Moved to Volume Group structure */
+ /* log_print("System Id %s", pv->vg->system_id); */
+
+ /* log_print(" "); */
+ /* return; */
+ }
+
+ memset(pv_tmp_name, 0, sizeof(pv_tmp_name));
+
+ vg_name_len = strlen(pv->vg_name) + 1;
+
+ if (arg_count(cmd, uuid_ARG)) {
+ if (!id_write_format(&pv->id, uuid, sizeof(uuid))) {
+ stack;
+ return;
+ }
+
+ sprintf(pv_tmp_name, "%-*s with UUID %s",
+ pv_max_name_len - 2, dev_name(pv->dev), uuid);
+ } else {
+ sprintf(pv_tmp_name, "%s", dev_name(pv->dev));
+ }
+
+ if (!*pv->vg_name) {
+ log_print("PV %-*s %-*s %s [%s]",
+ pv_max_name_len, pv_tmp_name,
+ vg_max_name_len, " ",
+ pv->fmt ? pv->fmt->name : " ",
+ (s1 = display_size(pv->size / 2, SIZE_SHORT)));
+ dbg_free(s1);
+ return;
+ }
+
+ if (pv->status & EXPORTED_VG) {
+ strncpy(vg_name_this, pv->vg_name, vg_name_len);
+ log_print("PV %-*s is in exported VG %s "
+ "[%s / %s free]",
+ pv_max_name_len, pv_tmp_name,
+ vg_name_this, (s1 =
+ display_size(pv->pe_count *
+ pv->pe_size / 2,
+ SIZE_SHORT)),
+ (s2 = display_size((pv->pe_count - pv->pe_alloc_count)
+ * pv->pe_size / 2, SIZE_SHORT)));
+ dbg_free(s1);
+ dbg_free(s2);
+ return;
+ }
+
+ sprintf(vg_tmp_name, "%s", pv->vg_name);
+ log_print
+ ("PV %-*s VG %-*s %s [%s / %s free]", pv_max_name_len,
+ pv_tmp_name, vg_max_name_len, vg_tmp_name,
+ pv->fmt ? pv->fmt->name : " ",
+ (s1 = display_size(pv->pe_count * pv->pe_size / 2, SIZE_SHORT)),
+ (s2 =
+ display_size((pv->pe_count - pv->pe_alloc_count) * pv->pe_size /
+ 2, SIZE_SHORT)));
+ dbg_free(s1);
+ dbg_free(s2);
+
+ return;
+}
+
int pvscan(struct cmd_context *cmd, int argc, char **argv)
{
int new_pvs_found = 0;
@@ -56,6 +140,9 @@ int pvscan(struct cmd_context *cmd, int argc, char **argv)
log_verbose("Wiping cache of LVM-capable devices");
persistent_filter_wipe(cmd->filter);
+ log_verbose("Wiping internal cache");
+ cache_destroy();
+
log_verbose("Walking through all physical volumes");
if (!(pvs = get_pvs(cmd)))
return ECMD_FAILED;
@@ -108,7 +195,8 @@ int pvscan(struct cmd_context *cmd, int argc, char **argv)
vg_max_name_len += 2;
list_iterate(pvh, pvs)
- pvscan_display_single(cmd, list_item(pvh, struct pv_list)->pv);
+ pvscan_display_single(cmd, list_item(pvh, struct pv_list)->pv,
+ NULL);
if (!pvs_found) {
log_print("No matching physical volumes found");
@@ -128,87 +216,3 @@ int pvscan(struct cmd_context *cmd, int argc, char **argv)
return 0;
}
-
-void pvscan_display_single(struct cmd_context *cmd, struct physical_volume *pv)
-{
- char uuid[64];
- int vg_name_len = 0;
-
- char *s1, *s2;
-
- char pv_tmp_name[NAME_LEN] = { 0, };
- char vg_tmp_name[NAME_LEN] = { 0, };
- char vg_name_this[NAME_LEN] = { 0, };
-
- /* short listing? */
- if (arg_count(cmd, short_ARG) > 0) {
- log_print("%s", dev_name(pv->dev));
- return;
- }
-
- if (arg_count(cmd, verbose_ARG) > 1) {
- /* FIXME As per pv_display! Drop through for now. */
- /* pv_show(pv); */
-
- /* FIXME - Moved to Volume Group structure */
- /* log_print("System Id %s", pv->vg->system_id); */
-
- /* log_print(" "); */
- /* return; */
- }
-
- memset(pv_tmp_name, 0, sizeof(pv_tmp_name));
-
- vg_name_len = strlen(pv->vg_name) + 1;
-
- if (arg_count(cmd, uuid_ARG)) {
- if (!id_write_format(&pv->id, uuid, sizeof(uuid))) {
- stack;
- return;
- }
-
- sprintf(pv_tmp_name, "%-*s with UUID %s",
- pv_max_name_len - 2, dev_name(pv->dev), uuid);
- } else {
- sprintf(pv_tmp_name, "%s", dev_name(pv->dev));
- }
-
- if (!*pv->vg_name) {
- log_print("PV %-*s %-*s [%s]",
- pv_max_name_len, pv_tmp_name,
- vg_max_name_len, " ",
- (s1 = display_size(pv->size / 2, SIZE_SHORT)));
- dbg_free(s1);
- return;
- }
-
- if (pv->status & EXPORTED_VG) {
- strncpy(vg_name_this, pv->vg_name, vg_name_len);
- log_print("PV %-*s is in exported VG %s "
- "[%s / %s free]",
- pv_max_name_len, pv_tmp_name,
- vg_name_this, (s1 =
- display_size(pv->pe_count *
- pv->pe_size / 2,
- SIZE_SHORT)),
- (s2 = display_size((pv->pe_count - pv->pe_alloc_count)
- * pv->pe_size / 2, SIZE_SHORT)));
- dbg_free(s1);
- dbg_free(s2);
- return;
- }
-
- sprintf(vg_tmp_name, "%s", pv->vg_name);
- log_print
- ("PV %-*s VG %-*s %s [%s / %s free]", pv_max_name_len,
- pv_tmp_name, vg_max_name_len, vg_tmp_name,
- pv->fid ? pv->fid->fmt->name : " ",
- (s1 = display_size(pv->pe_count * pv->pe_size / 2, SIZE_SHORT)),
- (s2 =
- display_size((pv->pe_count - pv->pe_alloc_count) * pv->pe_size /
- 2, SIZE_SHORT)));
- dbg_free(s1);
- dbg_free(s2);
-
- return;
-}
diff --git a/tools/stub.h b/tools/stub.h
index 185535c0..8ffefe13 100644
--- a/tools/stub.h
+++ b/tools/stub.h
@@ -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
-
diff --git a/tools/toollib.c b/tools/toollib.c
index 9b628ab0..917b4ff0 100644
--- a/tools/toollib.c
+++ b/tools/toollib.c
@@ -9,8 +9,10 @@
#include <sys/stat.h>
int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
+ void *handle,
int (*process_single) (struct cmd_context * cmd,
- struct logical_volume * lv))
+ struct logical_volume * lv,
+ void *handle))
{
int ret_max = 0;
int ret = 0;
@@ -25,7 +27,7 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
- ret = process_single(cmd, lv);
+ ret = process_single(cmd, lv, handle);
if (ret > ret_max)
ret_max = ret;
}
@@ -34,94 +36,163 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
}
+struct volume_group *recover_vg(struct cmd_context *cmd, const char *vgname,
+ int lock_type)
+{
+ int consistent = 1;
+
+ lock_type &= ~LCK_TYPE_MASK;
+ lock_type |= LCK_WRITE;
+
+ if (!lock_vol(cmd, vgname, lock_type)) {
+ log_error("Can't lock %s for metadata recovery: skipping",
+ vgname);
+ return NULL;
+ }
+
+ return vg_read(cmd, vgname, &consistent);
+}
+
int process_each_lv(struct cmd_context *cmd, int argc, char **argv,
- int lock_type,
+ int lock_type, void *handle,
int (*process_single) (struct cmd_context * cmd,
- struct logical_volume * lv))
+ struct logical_volume * lv,
+ void *handle))
{
int opt = 0;
int ret_max = 0;
int ret = 0;
int vg_count = 0;
+ int consistent;
- struct list *vgh, *vgs;
+ struct list *slh, *vgnames;
struct volume_group *vg;
struct logical_volume *lv;
struct lv_list *lvl;
- char *vg_name;
+ char *vgname;
if (argc) {
log_verbose("Using logical volume(s) on command line");
for (; opt < argc; opt++) {
char *lv_name = argv[opt];
-
- /* does VG exist? */
- if (!(vg_name = extract_vgname(cmd, lv_name))) {
- if (ret_max < ECMD_FAILED)
- ret_max = ECMD_FAILED;
- continue;
+ int vgname_provided = 1;
+
+ /* 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;
diff --git a/tools/toollib.h b/tools/toollib.h
index 49f06fbe..8b5ef7ed 100644
--- a/tools/toollib.h
+++ b/tools/toollib.h
@@ -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));
+ struct physical_volume * pv,
+ void *handle));
+
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));
-
-int is_valid_chars(char *n);
+ struct logical_volume * lv,
+ void *handle));
char *default_vgname(struct cmd_context *cmd);
char *extract_vgname(struct cmd_context *cmd, char *lv_name);
diff --git a/tools/tools.h b/tools/tools.h
index cd148967..2f253204 100644
--- a/tools/tools.h
+++ b/tools/tools.h
@@ -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
diff --git a/tools/vgcfgbackup.c b/tools/vgcfgbackup.c
index a7801589..46f90ec6 100644
--- a/tools/vgcfgbackup.c
+++ b/tools/vgcfgbackup.c
@@ -6,44 +6,29 @@
#include "tools.h"
-#include <stdio.h>
-
-static int _backup_to_file(const char *file, struct volume_group *vg)
-{
- 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)
+static int vg_backup_single(struct cmd_context *cmd, const char *vg_name,
+ struct volume_group *vg, int consistent,
+ void *handle)
{
- 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);
}
diff --git a/tools/vgcfgrestore.c b/tools/vgcfgrestore.c
index fe497816..2c38ed64 100644
--- a/tools/vgcfgrestore.c
+++ b/tools/vgcfgrestore.c
@@ -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;
}
diff --git a/tools/vgchange.c b/tools/vgchange.c
index 3165ba88..9579bef3 100644
--- a/tools/vgchange.c
+++ b/tools/vgchange.c
@@ -20,11 +20,6 @@
#include "tools.h"
-static int vgchange_single(struct cmd_context *cmd, const char *vg_name);
-void vgchange_available(struct cmd_context *cmd, struct volume_group *vg);
-void vgchange_resizeable(struct cmd_context *cmd, struct volume_group *vg);
-void vgchange_logicalvolume(struct cmd_context *cmd, struct volume_group *vg);
-
static int _activate_lvs_in_vg(struct cmd_context *cmd,
struct volume_group *vg, int lock)
{
@@ -48,72 +43,6 @@ static int _activate_lvs_in_vg(struct cmd_context *cmd,
return count;
}
-int vgchange(struct cmd_context *cmd, int argc, char **argv)
-{
- if (!
- (arg_count(cmd, available_ARG) + arg_count(cmd, logicalvolume_ARG) +
- arg_count(cmd, resizeable_ARG))) {
- log_error("One of -a, -l or -x options required");
- return EINVALID_CMD_LINE;
- }
-
- if (arg_count(cmd, available_ARG) + arg_count(cmd, logicalvolume_ARG) +
- arg_count(cmd, resizeable_ARG) > 1) {
- log_error("Only one of -a, -l or -x options allowed");
- return EINVALID_CMD_LINE;
- }
-
- if (arg_count(cmd, ignorelockingfailure_ARG) &&
- !arg_count(cmd, available_ARG)) {
- log_error("--ignorelockingfailure only available with -a");
- return EINVALID_CMD_LINE;
- }
-
- if (arg_count(cmd, available_ARG) == 1
- && arg_count(cmd, autobackup_ARG)) {
- log_error("-A option not necessary with -a option");
- return EINVALID_CMD_LINE;
- }
-
- if (!driver_is_loaded())
- return ECMD_FAILED;
-
- return process_each_vg(cmd, argc, argv,
- (arg_count(cmd, available_ARG)) ?
- LCK_VG_READ : LCK_VG_WRITE, &vgchange_single);
-}
-
-static int vgchange_single(struct cmd_context *cmd, const char *vg_name)
-{
- struct volume_group *vg;
-
- if (!(vg = vg_read(cmd, vg_name))) {
- log_error("Unable to find volume group \"%s\"", vg_name);
- return ECMD_FAILED;
- }
-
- if (!(vg->status & LVM_WRITE) && !arg_count(cmd, available_ARG)) {
- log_error("Volume group \"%s\" is read-only", vg->name);
- return ECMD_FAILED;
- }
-
- if (vg->status & EXPORTED_VG) {
- log_error("Volume group \"%s\" is exported", vg_name);
- return ECMD_FAILED;
- }
-
- if (arg_count(cmd, available_ARG))
- vgchange_available(cmd, vg);
-
- if (arg_count(cmd, resizeable_ARG))
- vgchange_resizeable(cmd, vg);
-
- if (arg_count(cmd, logicalvolume_ARG))
- vgchange_logicalvolume(cmd, vg);
-
- return 0;
-}
-
void vgchange_available(struct cmd_context *cmd, struct volume_group *vg)
{
int lv_open, active;
@@ -208,3 +137,74 @@ void vgchange_logicalvolume(struct cmd_context *cmd, struct volume_group *vg)
return;
}
+
+static int vgchange_single(struct cmd_context *cmd, const char *vg_name,
+ struct volume_group *vg, int consistent,
+ void *handle)
+{
+ if (!vg) {
+ log_error("Unable to find volume group \"%s\"", vg_name);
+ return ECMD_FAILED;
+ }
+
+ if (!consistent) {
+ unlock_vg(cmd, vg_name);
+ log_error("Volume group \"%s\" inconsistent", vg_name);
+ if (!(vg = recover_vg(cmd, vg_name, LCK_VG_WRITE)))
+ return ECMD_FAILED;
+ }
+
+ if (!(vg->status & LVM_WRITE) && !arg_count(cmd, available_ARG)) {
+ log_error("Volume group \"%s\" is read-only", vg->name);
+ return ECMD_FAILED;
+ }
+
+ if (vg->status & EXPORTED_VG) {
+ log_error("Volume group \"%s\" is exported", vg_name);
+ return ECMD_FAILED;
+ }
+
+ if (arg_count(cmd, available_ARG))
+ vgchange_available(cmd, vg);
+
+ if (arg_count(cmd, resizeable_ARG))
+ vgchange_resizeable(cmd, vg);
+
+ if (arg_count(cmd, logicalvolume_ARG))
+ vgchange_logicalvolume(cmd, vg);
+
+ return 0;
+}
+
+int vgchange(struct cmd_context *cmd, int argc, char **argv)
+{
+ if (!
+ (arg_count(cmd, available_ARG) + arg_count(cmd, logicalvolume_ARG) +
+ arg_count(cmd, resizeable_ARG))) {
+ log_error("One of -a, -l or -x options required");
+ return EINVALID_CMD_LINE;
+ }
+
+ if (arg_count(cmd, available_ARG) + arg_count(cmd, logicalvolume_ARG) +
+ arg_count(cmd, resizeable_ARG) > 1) {
+ log_error("Only one of -a, -l or -x options allowed");
+ return EINVALID_CMD_LINE;
+ }
+
+ if (arg_count(cmd, ignorelockingfailure_ARG) &&
+ !arg_count(cmd, available_ARG)) {
+ log_error("--ignorelockingfailure only available with -a");
+ return EINVALID_CMD_LINE;
+ }
+
+ if (arg_count(cmd, available_ARG) == 1
+ && arg_count(cmd, autobackup_ARG)) {
+ log_error("-A option not necessary with -a option");
+ return EINVALID_CMD_LINE;
+ }
+
+ return process_each_vg(cmd, argc, argv,
+ (arg_count(cmd, available_ARG)) ?
+ LCK_VG_READ : LCK_VG_WRITE, 0, NULL,
+ &vgchange_single);
+}
diff --git a/tools/vgck.c b/tools/vgck.c
index e90f5317..6a6eb1ec 100644
--- a/tools/vgck.c
+++ b/tools/vgck.c
@@ -20,20 +20,15 @@
#include "tools.h"
-static int vgck_single(struct cmd_context *cmd, const char *vg_name);
-
-int vgck(struct cmd_context *cmd, int argc, char **argv)
+static int vgck_single(struct cmd_context *cmd, const char *vg_name,
+ struct volume_group *vg, int consistent, void *handle)
{
- return process_each_vg(cmd, argc, argv, LCK_VG_READ, &vgck_single);
-}
-
-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 (!consistent) {
+ log_error("Volume group \"%s\" inconsistent", vg_name);
+ return ECMD_FAILED;
+ }
- 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);
+}
diff --git a/tools/vgconvert.c b/tools/vgconvert.c
new file mode 100644
index 00000000..91bd8886
--- /dev/null
+++ b/tools/vgconvert.c
@@ -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);
+}
diff --git a/tools/vgcreate.c b/tools/vgcreate.c
index 7c092e0b..23a8389c 100644
--- a/tools/vgcreate.c
+++ b/tools/vgcreate.c
@@ -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)))
diff --git a/tools/vgdisplay.c b/tools/vgdisplay.c
index 13f30112..72bc3b38 100644
--- a/tools/vgdisplay.c
+++ b/tools/vgdisplay.c
@@ -20,7 +20,45 @@
#include "tools.h"
-static int vgdisplay_single(struct cmd_context *cmd, const char *vg_name);
+static int vgdisplay_single(struct cmd_context *cmd, const char *vg_name,
+ struct volume_group *vg, int consistent,
+ void *handle)
+{
+ /* FIXME Do the active check here if activevolumegroups_ARG ? */
+ 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);
+
+ if (arg_count(cmd, colon_ARG)) {
+ vgdisplay_colons(vg);
+ return 0;
+ }
+
+ if (arg_count(cmd, short_ARG)) {
+ vgdisplay_short(vg);
+ return 0;
+ }
+
+ vgdisplay_full(vg); /* was vg_show */
+
+ if (arg_count(cmd, verbose_ARG)) {
+ vgdisplay_extents(vg);
+
+ process_each_lv_in_vg(cmd, vg, NULL, &lvdisplay_full);
+
+ log_print("--- Physical volumes ---");
+ process_each_pv_in_vg(cmd, vg, NULL, &pvdisplay_short);
+ }
+
+ return 0;
+}
int vgdisplay(struct cmd_context *cmd, int argc, char **argv)
{
@@ -34,11 +72,6 @@ int vgdisplay(struct cmd_context *cmd, int argc, char **argv)
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++) {
@@ -48,7 +81,8 @@ int vgdisplay(struct cmd_context *cmd, int argc, char **argv)
}
**********/
- process_each_vg(cmd, argc, argv, LCK_VG_READ, &vgdisplay_single);
+ 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) ?
@@ -64,43 +98,3 @@ int vgdisplay(struct cmd_context *cmd, int argc, char **argv)
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))) {
- log_error("Volume group \"%s\" doesn't exist", vg_name);
- return ECMD_FAILED;
- }
-
- if (vg->status & EXPORTED_VG)
- log_print("WARNING: volume group \"%s\" is exported", vg_name);
-
- if (arg_count(cmd, colon_ARG)) {
- vgdisplay_colons(vg);
- return 0;
- }
-
- if (arg_count(cmd, short_ARG)) {
- vgdisplay_short(vg);
- return 0;
- }
-
- vgdisplay_full(vg); /* was vg_show */
-
- if (arg_count(cmd, verbose_ARG)) {
- vgdisplay_extents(vg);
-
- process_each_lv_in_vg(cmd, vg, &lvdisplay_full);
-
- log_print("--- Physical volumes ---");
- process_each_pv_in_vg(cmd, vg, &pvdisplay_short);
- }
-
- return 0;
-}
diff --git a/tools/vgexport.c b/tools/vgexport.c
index 50fe605f..5e521f01 100644
--- a/tools/vgexport.c
+++ b/tools/vgexport.c
@@ -20,32 +20,17 @@
#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 (!vg) {
+ log_error("Unable to find volume group \"%s\"", vg_name);
+ goto error;
}
- 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))) {
- log_error("Unable to find volume group \"%s\"", vg_name);
+ if (!consistent) {
+ log_error("Volume group %s inconsistent", 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);
+}
diff --git a/tools/vgextend.c b/tools/vgextend.c
index 6b5adb9a..0cb9f073 100644
--- a/tools/vgextend.c
+++ b/tools/vgextend.c
@@ -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;
}
diff --git a/tools/vgimport.c b/tools/vgimport.c
index bb72d7a7..d515caad 100644
--- a/tools/vgimport.c
+++ b/tools/vgimport.c
@@ -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)
-{
- 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)
+static int vgimport_single(struct cmd_context *cmd, const char *vg_name,
+ struct volume_group *vg, int consistent,
+ void *handle)
{
- 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);
+}
diff --git a/tools/vgmerge.c b/tools/vgmerge.c
index 8d6e7b44..6a705658 100644
--- a/tools/vgmerge.c
+++ b/tools/vgmerge.c
@@ -21,41 +21,12 @@
#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;
+}
diff --git a/tools/vgreduce.c b/tools/vgreduce.c
index b2bd476b..a0855731 100644
--- a/tools/vgreduce.c
+++ b/tools/vgreduce.c
@@ -20,14 +20,64 @@
#include "tools.h"
+/* 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);
+
+ if (pv->pe_alloc_count) {
+ log_error("Physical volume \"%s\" still in use", name);
+ return ECMD_FAILED;
+ }
+
+ if (vg->pv_count == 1) {
+ log_error("Can't remove final physical volume \"%s\" from "
+ "volume group \"%s\"", name, vg->name);
+ return ECMD_FAILED;
+ }
+
+ pvl = find_pv_in_vg(vg, name);
+
+ if (!archive(vg))
+ return ECMD_FAILED;
+ log_verbose("Removing \"%s\" from volume group \"%s\"", name, vg->name);
+
+ if (pvl)
+ list_del(&pvl->list);
+
+ *pv->vg_name = '\0';
+ vg->pv_count--;
+ vg->free_count -= pv->pe_count - pv->pe_alloc_count;
+ vg->extent_count -= pv->pe_count;
+
+ if (!vg_write(vg)) {
+ log_error("Removal of physical volume \"%s\" from "
+ "\"%s\" failed", name, vg->name);
+ return ECMD_FAILED;
+ }
+
+ if (!pv_write(cmd, pv, NULL, -1)) {
+ log_error("Failed to clear metadata from physical "
+ "volume \"%s\" "
+ "after removal from \"%s\"", name, vg->name);
+ return ECMD_FAILED;
+ }
+
+ backup(vg);
+
+ log_print("Removed \"%s\" from volume group \"%s\"", name, vg->name);
+
+ 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 "
@@ -46,9 +96,6 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
- if (!driver_is_loaded())
- return ECMD_FAILED;
-
vg_name = argv[0];
argv++;
argc--;
@@ -59,7 +106,7 @@ int vgreduce(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)) || !consistent) {
log_error("Volume group \"%s\" doesn't exist", vg_name);
unlock_vg(cmd, vg_name);
return ECMD_FAILED;
@@ -85,7 +132,7 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
/* FIXME: Pass private structure through to all these functions */
/* and update in batch here? */
- ret = process_each_pv(cmd, argc, argv, vg, vgreduce_single);
+ ret = process_each_pv(cmd, argc, argv, vg, NULL, vgreduce_single);
unlock_vg(cmd, vg_name);
@@ -107,62 +154,3 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
********/
}
-
-/* Or take pv_name instead? */
-static int vgreduce_single(struct cmd_context *cmd, struct volume_group *vg,
- struct physical_volume *pv)
-{
- struct pv_list *pvl;
- const char *name = dev_name(pv->dev);
-
- if (pv->pe_alloc_count) {
- log_error("Physical volume \"%s\" still in use", name);
- 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);
- return ECMD_FAILED;
- }
-
- pvl = find_pv_in_vg(vg, name);
-
- if (!archive(vg))
- return ECMD_FAILED;
-
- log_verbose("Removing \"%s\" from volume group \"%s\"", name, vg->name);
-
- if (pvl)
- list_del(&pvl->list);
-
- *pv->vg_name = '\0';
- vg->pv_count--;
- vg->free_count -= pv->pe_count - pv->pe_alloc_count;
- vg->extent_count -= pv->pe_count;
-
- if (!vg_write(vg)) {
- log_error("Removal of physical volume \"%s\" from "
- "\"%s\" failed", name, vg->name);
- return ECMD_FAILED;
- }
-
- if (!pv_write(cmd, pv)) {
- log_error("Failed to clear metadata from physical "
- "volume \"%s\" "
- "after removal from \"%s\"", name, vg->name);
- return ECMD_FAILED;
- }
-
- backup(vg);
-
- log_print("Removed \"%s\" from volume group \"%s\"", name, vg->name);
-
- return 0;
-}
diff --git a/tools/vgremove.c b/tools/vgremove.c
index 018976f7..14a0fcf3 100644
--- a/tools/vgremove.c
+++ b/tools/vgremove.c
@@ -20,38 +20,15 @@
#include "tools.h"
-static int vgremove_single(struct cmd_context *cmd, const char *vg_name);
-
-int vgremove(struct cmd_context *cmd, int argc, char **argv)
-{
- int ret;
-
- if (!driver_is_loaded())
- return ECMD_FAILED;
-
- if (!lock_vol(cmd, "", LCK_VG_WRITE)) {
- log_error("Can't get lock for orphan PVs");
- return ECMD_FAILED;
- }
-
- ret = process_each_vg(cmd, argc, argv,
- LCK_VG | LCK_WRITE | LCK_NONBLOCK,
- &vgremove_single);
-
- unlock_vg(cmd, "");
-
- return ret;
-}
-
-static int vgremove_single(struct cmd_context *cmd, const char *vg_name)
+static int vgremove_single(struct cmd_context *cmd, const char *vg_name,
+ struct volume_group *vg, int consistent,
+ void *handle)
{
- struct volume_group *vg;
struct physical_volume *pv;
struct list *pvh;
int ret = 0;
- log_verbose("Checking for volume group \"%s\"", vg_name);
- if (!(vg = vg_read(cmd, vg_name))) {
+ if (!vg || !consistent) {
log_error("Volume group \"%s\" doesn't exist", vg_name);
return ECMD_FAILED;
}
@@ -87,7 +64,8 @@ static int vgremove_single(struct cmd_context *cmd, const char *vg_name)
log_verbose("Removing physical volume \"%s\" from "
"volume group \"%s\"", dev_name(pv->dev), vg_name);
*pv->vg_name = '\0';
- if (!pv_write(cmd, pv)) {
+ /* FIXME Write to same sector label was read from */
+ if (!pv_write(cmd, pv, NULL, -1)) {
log_error("Failed to remove physical volume \"%s\""
" from volume group \"%s\"",
dev_name(pv->dev), vg_name);
@@ -104,3 +82,21 @@ static int vgremove_single(struct cmd_context *cmd, const char *vg_name)
return ret;
}
+
+int vgremove(struct cmd_context *cmd, int argc, char **argv)
+{
+ int ret;
+
+ if (!lock_vol(cmd, "", LCK_VG_WRITE)) {
+ log_error("Can't get lock for orphan PVs");
+ return ECMD_FAILED;
+ }
+
+ ret = process_each_vg(cmd, argc, argv,
+ LCK_VG | LCK_WRITE | LCK_NONBLOCK, 1, NULL,
+ &vgremove_single);
+
+ unlock_vg(cmd, "");
+
+ return ret;
+}
diff --git a/tools/vgrename.c b/tools/vgrename.c
index 4ec3d985..50c04512 100644
--- a/tools/vgrename.c
+++ b/tools/vgrename.c
@@ -24,6 +24,7 @@ int vgrename(struct cmd_context *cmd, int argc, char **argv)
{
char *dev_dir;
int length;
+ int consistent = 1;
char *vg_name_old, *vg_name_new;
@@ -56,7 +57,7 @@ int vgrename(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED;
}
- if (!is_valid_chars(vg_name_new)) {
+ if (!validate_vgname(vg_name_new)) {
log_error("New volume group name \"%s\" has invalid characters",
vg_name_new);
return ECMD_FAILED;
@@ -67,9 +68,6 @@ int vgrename(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED;
}
- if (!driver_is_loaded())
- return ECMD_FAILED;
-
log_verbose("Checking for existing volume group \"%s\"", vg_name_old);
if (!lock_vol(cmd, vg_name_old, LCK_VG_WRITE)) {
@@ -77,7 +75,7 @@ int vgrename(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED;
}
- if (!(vg_old = vg_read(cmd, vg_name_old))) {
+ if (!(vg_old = vg_read(cmd, vg_name_old, &consistent)) || !consistent) {
log_error("Volume group \"%s\" doesn't exist", vg_name_old);
unlock_vg(cmd, vg_name_old);
return ECMD_FAILED;
@@ -115,7 +113,8 @@ int vgrename(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED;
}
- if ((vg_new = vg_read(cmd, vg_name_new))) {
+ consistent = 0;
+ if ((vg_new = vg_read(cmd, vg_name_new, &consistent))) {
log_error("New volume group \"%s\" already exists",
vg_name_new);
goto error;
@@ -133,18 +132,14 @@ int vgrename(struct cmd_context *cmd, int argc, char **argv)
vg_name_new);
}
-/********** FIXME: Check within vg_write now
- log_error("A new logical volume path exceeds "
- "maximum of %d!", NAME_LEN - 2);
- goto error;
-*************/
-
sprintf(old_path, "%s%s", dev_dir, vg_name_old);
sprintf(new_path, "%s%s", dev_dir, vg_name_new);
if (dir_exists(old_path)) {
log_verbose("Renaming \"%s\" to \"%s\"", old_path, new_path);
- if (rename(old_path, new_path)) {
+ if (test_mode())
+ log_verbose("Test mode: Skipping rename.");
+ else if (rename(old_path, new_path)) {
log_error("Renaming \"%s\" to \"%s\" failed: %s",
old_path, new_path, strerror(errno));
goto error;
@@ -175,19 +170,3 @@ int vgrename(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED;
}
-/* FIXME: Moved into vg_write now */
-/*******************
-char *lv_change_vgname(char *vg_name, char *lv_name)
-{
- char *lv_name_ptr = NULL;
- static char lv_name_buf[NAME_LEN] = { 0, };
-
- ** check if lv_name includes a path
- if ((lv_name_ptr = strrchr(lv_name, '/'))) {
- lv_name_ptr++;
- sprintf(lv_name_buf, "%s%s/%s%c", cmd->dev_dir, vg_name,
- lv_name_ptr, 0);}
- else
- strncpy(lv_name_buf, lv_name, NAME_LEN - 1); return lv_name_buf;}
-
-**********************/
diff --git a/tools/vgscan.c b/tools/vgscan.c
index 504f5347..0af067d7 100644
--- a/tools/vgscan.c
+++ b/tools/vgscan.c
@@ -20,7 +20,28 @@
#include "tools.h"
-static int vgscan_single(struct cmd_context *cmd, const char *vg_name);
+static int vgscan_single(struct cmd_context *cmd, const char *vg_name,
+ struct volume_group *vg, int consistent, void *handle)
+{
+ if (!vg) {
+ log_error("Volume group \"%s\" not found", vg_name);
+ return ECMD_FAILED;
+ }
+
+ if (!consistent) {
+ unlock_vg(cmd, vg_name);
+ log_error("Volume group \"%s\" inconsistent", vg_name);
+ /* Don't allow partial switch to this program */
+ if (!(vg = recover_vg(cmd, vg_name, LCK_VG_WRITE)))
+ return ECMD_FAILED;
+ }
+
+ log_print("Found %svolume group \"%s\" using metadata type %s",
+ (vg->status & EXPORTED_VG) ? "exported " : "", vg_name,
+ vg->fid->fmt->name);
+
+ return 0;
+}
int vgscan(struct cmd_context *cmd, int argc, char **argv)
{
@@ -32,28 +53,11 @@ int vgscan(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 of PVs in VGs");
- vgcache_destroy();
+ log_verbose("Wiping internal cache");
+ cache_destroy();
log_print("Reading all physical volumes. This may take a while...");
- return process_each_vg(cmd, argc, argv, LCK_VG_READ, &vgscan_single);
-}
-
-static int vgscan_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))) {
- log_error("Volume group \"%s\" not found", vg_name);
- return ECMD_FAILED;
- }
-
- log_print("Found %svolume group \"%s\" using metadata type %s",
- (vg->status & EXPORTED_VG) ? "exported " : "", vg_name,
- vg->fid->fmt->name);
-
- return 0;
+ return process_each_vg(cmd, argc, argv, LCK_VG_READ, 1, NULL,
+ &vgscan_single);
}
diff --git a/tools/vgsplit.c b/tools/vgsplit.c
index baa7d2e5..00a77ff1 100644
--- a/tools/vgsplit.c
+++ b/tools/vgsplit.c
@@ -65,7 +65,7 @@ static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to)
{
struct list *lvh, *lvht, *segh;
struct logical_volume *lv;
- struct stripe_segment *seg;
+ struct lv_segment *seg;
struct physical_volume *pv;
struct volume_group *vg_with;
int s;
@@ -77,7 +77,7 @@ static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to)
/* VG as each other */
vg_with = NULL;
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++) {
pv = seg->area[s].pv;
if (vg_with) {
@@ -164,6 +164,7 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
struct volume_group *vg_to, *vg_from;
int opt;
int active;
+ int consistent = 1;
if (argc < 3) {
log_error("Existing VG, new VG and physical volumes required.");
@@ -180,16 +181,13 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED;
}
- if (!driver_is_loaded())
- return ECMD_FAILED;
-
log_verbose("Checking for volume group \"%s\"", vg_name_from);
if (!lock_vol(cmd, vg_name_from, LCK_VG_WRITE)) {
log_error("Can't get lock for %s", vg_name_from);
return ECMD_FAILED;
}
- if (!(vg_from = vg_read(cmd, vg_name_from))) {
+ if (!(vg_from = vg_read(cmd, vg_name_from, &consistent)) || !consistent) {
log_error("Volume group \"%s\" doesn't exist", vg_name_from);
unlock_vg(cmd, vg_name_from);
return ECMD_FAILED;
@@ -214,7 +212,8 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED;
}
- if ((vg_to = vg_read(cmd, vg_name_to))) {
+ consistent = 0;
+ if ((vg_to = vg_read(cmd, vg_name_to, &consistent))) {
/* FIXME Remove this restriction */
log_error("Volume group \"%s\" already exists", vg_name_to);
goto error;
@@ -250,6 +249,12 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
if (!(_move_snapshots(vg_from, vg_to)))
goto error;
+ /* FIXME Split mdas properly somehow too! */
+ /* Currently we cheat by sharing the format instance and relying on
+ * vg_write to ignore mdas outside the VG! Done this way, with text
+ * format, vg_from disappears for a short time. */
+ vg_to->fid = vg_from->fid;
+
/* store it on disks */
log_verbose("Writing out updated volume groups");
@@ -271,6 +276,13 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
backup(vg_from);
/* Remove EXPORTED flag from new VG */
+ consistent = 1;
+ if (!(vg_to = vg_read(cmd, vg_name_to, &consistent)) || !consistent) {
+ log_error("Volume group \"%s\" became inconsistent: please "
+ "fix manually", vg_name_to);
+ goto error;
+ }
+
vg_to->status &= ~EXPORTED_VG;
if (!vg_write(vg_to))