]> sourceware.org Git - lvm2.git/commitdiff
Some new features.
authorAlasdair Kergon <agk@redhat.com>
Mon, 18 Nov 2002 14:04:08 +0000 (14:04 +0000)
committerAlasdair Kergon <agk@redhat.com>
Mon, 18 Nov 2002 14:04:08 +0000 (14:04 +0000)
104 files changed:
INSTALL
INTRO [deleted file]
Makefile.in
README
TODO [deleted file]
VERSION
WHATS_NEW [new file with mode: 0644]
configure
configure.in
doc/example.conf
include/.symlinks
lib/Makefile.in
lib/format_text/archive.c
lib/format_text/export.c
lib/format_text/flags.c
lib/format_text/format-text.c
lib/format_text/format-text.h
lib/format_text/import-export.h
lib/format_text/import.c
lib/format_text/import_vsn1.c [new file with mode: 0644]
lib/format_text/layout.h [new file with mode: 0644]
lib/format_text/sample.vg [deleted file]
lib/format_text/text_label.c [new file with mode: 0644]
lib/label/label.c
lib/label/label.h
lib/label/lvm2_label.c [deleted file]
lib/label/lvm2_label.h [deleted file]
lib/label/uuid-map.c [deleted file]
lib/label/uuid-map.h [deleted file]
lib/metadata/lv_manip.c
lib/metadata/merge.c
lib/metadata/metadata.c
lib/metadata/metadata.h
lib/metadata/pv_map.c
lib/metadata/snapshot_manip.c
make.tmpl.in
man/Makefile.in
man/lvchange.8
man/lvcreate.8
man/lvdisplay.8
man/lvextend.8
man/lvm.8
man/lvmchange.8
man/lvreduce.8
man/lvremove.8
man/lvrename.8
man/lvscan.8
man/pvchange.8
man/pvcreate.8
man/pvdisplay.8
man/pvremove.8 [new file with mode: 0644]
man/pvscan.8
man/vgcfgbackup.8
man/vgcfgrestore.8 [new file with mode: 0644]
man/vgchange.8
man/vgconvert.8 [new file with mode: 0644]
man/vgcreate.8
man/vgdisplay.8
man/vgextend.8
man/vgmerge.8
man/vgreduce.8
man/vgremove.8
man/vgrename.8
man/vgscan.8
scripts/vg_convert [new file with mode: 0755]
tools/Makefile.in
tools/archive.c
tools/archive.h
tools/args.h
tools/commands.h
tools/lvchange.c
tools/lvcreate.c
tools/lvdisplay.c
tools/lvm.c
tools/lvmdiskscan.c
tools/lvremove.c
tools/lvrename.c
tools/lvresize.c
tools/lvscan.c
tools/pvchange.c
tools/pvcreate.c
tools/pvdisplay.c
tools/pvremove.c [new file with mode: 0644]
tools/pvscan.c
tools/stub.h
tools/toollib.c
tools/toollib.h
tools/tools.h
tools/vgcfgbackup.c
tools/vgcfgrestore.c
tools/vgchange.c
tools/vgck.c
tools/vgconvert.c [new file with mode: 0644]
tools/vgcreate.c
tools/vgdisplay.c
tools/vgexport.c
tools/vgextend.c
tools/vgimport.c
tools/vgmerge.c
tools/vgreduce.c
tools/vgremove.c
tools/vgrename.c
tools/vgscan.c
tools/vgsplit.c

diff --git a/INSTALL b/INSTALL
index 8c9e33bb9b9ede908e34fa2e1212c635f7e2e711..93259a06c0435f16a55e253d0f08935a6f97baa0 100644 (file)
--- 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 (file)
index bc54a16..0000000
--- a/INTRO
+++ /dev/null
@@ -1,18 +0,0 @@
-An introduction to LVM2
-=======================
-
-Background
-
-
-Compatibility with LVM1
-
-
-New features
-
-
-Missing features
-
-
-Future enhancements
-
-
index ef815a4ec8bba5691e64d56fb0574bac31e076ce..ed1fd7ca33e2df7a2981e1831ad45c546f74f64b 100644 (file)
@@ -23,7 +23,8 @@ VPATH = @srcdir@
 SUBDIRS = include man lib tools
 
 ifeq ($(MAKECMDGOALS),distclean)
-  SUBDIRS += test/mm test/device test/format1 test/regex test/filters
+  SUBDIRS += lib/format1 \
+            test/mm test/device test/format1 test/regex test/filters
 endif
 
 include make.tmpl
diff --git a/README b/README
index 9cf704d08cb689097ab7016609b418f7f20b84d0..c66c11f1129412a1194f527f6493f0f93a1e9276 100644 (file)
--- 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 (file)
index c3862f2..0000000
--- 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 25c80ade41a93e86d02da86053815cb20767ee77..146b0f6a33a6e0dd275566c5faeaf44d2d25d95a 100644 (file)
--- 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 (file)
index 0000000..26c8fd3
--- /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!
+
+
index 8b891deeb30a3b0a74118207950d4e758335933f..31c584d5b77b35d28715f8884b9608a4e70bfbdc 100755 (executable)
--- a/configure
+++ b/configure
@@ -16,13 +16,16 @@ ac_help="$ac_help
   --with-user=USER        Set the owner of installed files "
 ac_help="$ac_help
   --with-group=GROUP      Set the group owner of installed files "
+ac_help="$ac_help
+  --with-lvm1=TYPE        LVM1 metadata support: internal/shared/none
+                          [TYPE=internal] "
 ac_help="$ac_help
   --enable-jobs=NUM       Number of jobs to run simultaneously"
 ac_help="$ac_help
   --enable-static_link    Use this to link the tools to the liblvm library
                           statically.  Default is dynamic linking"
 ac_help="$ac_help
-  --disable-readline      Disable readline support"
+  --enable-readline       Enable readline support"
 
 # Initialize some variables set by options.
 # The variables have the same names as the options, with
@@ -559,7 +562,7 @@ do
 # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:563: checking for $ac_word" >&5
+echo "configure:566: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -591,7 +594,7 @@ done
 # Extract the first word of "gcc", so it can be a program name with args.
 set dummy gcc; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:595: checking for $ac_word" >&5
+echo "configure:598: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -621,7 +624,7 @@ if test -z "$CC"; then
   # Extract the first word of "cc", so it can be a program name with args.
 set dummy cc; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:625: checking for $ac_word" >&5
+echo "configure:628: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -672,7 +675,7 @@ fi
       # Extract the first word of "cl", so it can be a program name with args.
 set dummy cl; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:676: checking for $ac_word" >&5
+echo "configure:679: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -704,7 +707,7 @@ fi
 fi
 
 echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
-echo "configure:708: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+echo "configure:711: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
 
 ac_ext=c
 # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
@@ -715,12 +718,12 @@ cross_compiling=$ac_cv_prog_cc_cross
 
 cat > conftest.$ac_ext << EOF
 
-#line 719 "configure"
+#line 722 "configure"
 #include "confdefs.h"
 
 main(){return(0);}
 EOF
-if { (eval echo configure:724: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:727: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   ac_cv_prog_cc_works=yes
   # If we can't run a trivial program, we are probably using a cross compiler.
   if (./conftest; exit) 2>/dev/null; then
@@ -746,12 +749,12 @@ if test $ac_cv_prog_cc_works = no; then
   { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
 fi
 echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
-echo "configure:750: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "configure:753: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
 echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
 cross_compiling=$ac_cv_prog_cc_cross
 
 echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
-echo "configure:755: checking whether we are using GNU C" >&5
+echo "configure:758: checking whether we are using GNU C" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -760,7 +763,7 @@ else
   yes;
 #endif
 EOF
-if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:764: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:767: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
   ac_cv_prog_gcc=yes
 else
   ac_cv_prog_gcc=no
@@ -779,7 +782,7 @@ ac_test_CFLAGS="${CFLAGS+set}"
 ac_save_CFLAGS="$CFLAGS"
 CFLAGS=
 echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
-echo "configure:783: checking whether ${CC-cc} accepts -g" >&5
+echo "configure:786: checking whether ${CC-cc} accepts -g" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -822,7 +825,7 @@ fi
 # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
 # ./install, which can be erroneously created by make from ./install.sh.
 echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
-echo "configure:826: checking for a BSD compatible install" >&5
+echo "configure:829: checking for a BSD compatible install" >&5
 if test -z "$INSTALL"; then
 if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -875,7 +878,7 @@ test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
 test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
 
 echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6
-echo "configure:879: checking whether ln -s works" >&5
+echo "configure:882: checking whether ln -s works" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -896,7 +899,7 @@ else
 fi
 
 echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
-echo "configure:900: checking whether ${MAKE-make} sets \${MAKE}" >&5
+echo "configure:903: checking whether ${MAKE-make} sets \${MAKE}" >&5
 set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -925,7 +928,7 @@ fi
 # Extract the first word of "ranlib", so it can be a program name with args.
 set dummy ranlib; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:929: checking for $ac_word" >&5
+echo "configure:932: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -958,12 +961,12 @@ for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h
 do
 ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
 echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6
-echo "configure:962: checking for $ac_hdr that defines DIR" >&5
+echo "configure:965: checking for $ac_hdr that defines DIR" >&5
 if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 967 "configure"
+#line 970 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <$ac_hdr>
@@ -971,7 +974,7 @@ int main() {
 DIR *dirp = 0;
 ; return 0; }
 EOF
-if { (eval echo configure:975: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:978: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   eval "ac_cv_header_dirent_$ac_safe=yes"
 else
@@ -996,7 +999,7 @@ done
 # Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
 if test $ac_header_dirent = dirent.h; then
 echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6
-echo "configure:1000: checking for opendir in -ldir" >&5
+echo "configure:1003: checking for opendir in -ldir" >&5
 ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1004,7 +1007,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-ldir  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1008 "configure"
+#line 1011 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1015,7 +1018,7 @@ int main() {
 opendir()
 ; return 0; }
 EOF
-if { (eval echo configure:1019: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1022: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1037,7 +1040,7 @@ fi
 
 else
 echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6
-echo "configure:1041: checking for opendir in -lx" >&5
+echo "configure:1044: checking for opendir in -lx" >&5
 ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1045,7 +1048,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lx  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1049 "configure"
+#line 1052 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1056,7 +1059,7 @@ int main() {
 opendir()
 ; return 0; }
 EOF
-if { (eval echo configure:1060: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1063: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1079,7 +1082,7 @@ fi
 fi
 
 echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
-echo "configure:1083: checking how to run the C preprocessor" >&5
+echo "configure:1086: checking how to run the C preprocessor" >&5
 # On Suns, sometimes $CPP names a directory.
 if test -n "$CPP" && test -d "$CPP"; then
   CPP=
@@ -1094,13 +1097,13 @@ else
   # On the NeXT, cc -E runs the code through the compiler's parser,
   # not just through cpp.
   cat > conftest.$ac_ext <<EOF
-#line 1098 "configure"
+#line 1101 "configure"
 #include "confdefs.h"
 #include <assert.h>
 Syntax Error
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1104: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1107: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 if test -z "$ac_err"; then
   :
@@ -1111,13 +1114,13 @@ else
   rm -rf conftest*
   CPP="${CC-cc} -E -traditional-cpp"
   cat > conftest.$ac_ext <<EOF
-#line 1115 "configure"
+#line 1118 "configure"
 #include "confdefs.h"
 #include <assert.h>
 Syntax Error
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1121: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1124: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 if test -z "$ac_err"; then
   :
@@ -1128,13 +1131,13 @@ else
   rm -rf conftest*
   CPP="${CC-cc} -nologo -E"
   cat > conftest.$ac_ext <<EOF
-#line 1132 "configure"
+#line 1135 "configure"
 #include "confdefs.h"
 #include <assert.h>
 Syntax Error
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1138: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1141: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 if test -z "$ac_err"; then
   :
@@ -1159,12 +1162,12 @@ fi
 echo "$ac_t""$CPP" 1>&6
 
 echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
-echo "configure:1163: checking for ANSI C header files" >&5
+echo "configure:1166: checking for ANSI C header files" >&5
 if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1168 "configure"
+#line 1171 "configure"
 #include "confdefs.h"
 #include <stdlib.h>
 #include <stdarg.h>
@@ -1172,7 +1175,7 @@ else
 #include <float.h>
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1176: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1179: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 if test -z "$ac_err"; then
   rm -rf conftest*
@@ -1189,7 +1192,7 @@ rm -f conftest*
 if test $ac_cv_header_stdc = yes; then
   # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
 cat > conftest.$ac_ext <<EOF
-#line 1193 "configure"
+#line 1196 "configure"
 #include "confdefs.h"
 #include <string.h>
 EOF
@@ -1207,7 +1210,7 @@ fi
 if test $ac_cv_header_stdc = yes; then
   # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
 cat > conftest.$ac_ext <<EOF
-#line 1211 "configure"
+#line 1214 "configure"
 #include "confdefs.h"
 #include <stdlib.h>
 EOF
@@ -1228,7 +1231,7 @@ if test "$cross_compiling" = yes; then
   :
 else
   cat > conftest.$ac_ext <<EOF
-#line 1232 "configure"
+#line 1235 "configure"
 #include "confdefs.h"
 #include <ctype.h>
 #define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
@@ -1239,7 +1242,7 @@ if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
 exit (0); }
 
 EOF
-if { (eval echo configure:1243: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:1246: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   :
 else
@@ -1266,17 +1269,17 @@ for ac_hdr in fcntl.h malloc.h sys/ioctl.h unistd.h
 do
 ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
 echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:1270: checking for $ac_hdr" >&5
+echo "configure:1273: checking for $ac_hdr" >&5
 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1275 "configure"
+#line 1278 "configure"
 #include "confdefs.h"
 #include <$ac_hdr>
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1280: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1283: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 if test -z "$ac_err"; then
   rm -rf conftest*
@@ -1304,12 +1307,12 @@ done
 
 
 echo $ac_n "checking for working const""... $ac_c" 1>&6
-echo "configure:1308: checking for working const" >&5
+echo "configure:1311: checking for working const" >&5
 if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1313 "configure"
+#line 1316 "configure"
 #include "confdefs.h"
 
 int main() {
@@ -1358,7 +1361,7 @@ ccp = (char const *const *) p;
 
 ; return 0; }
 EOF
-if { (eval echo configure:1362: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1365: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   ac_cv_c_const=yes
 else
@@ -1379,21 +1382,21 @@ EOF
 fi
 
 echo $ac_n "checking for inline""... $ac_c" 1>&6
-echo "configure:1383: checking for inline" >&5
+echo "configure:1386: checking for inline" >&5
 if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   ac_cv_c_inline=no
 for ac_kw in inline __inline__ __inline; do
   cat > conftest.$ac_ext <<EOF
-#line 1390 "configure"
+#line 1393 "configure"
 #include "confdefs.h"
 
 int main() {
 } int $ac_kw foo() {
 ; return 0; }
 EOF
-if { (eval echo configure:1397: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1400: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   ac_cv_c_inline=$ac_kw; break
 else
@@ -1419,12 +1422,12 @@ EOF
 esac
 
 echo $ac_n "checking for off_t""... $ac_c" 1>&6
-echo "configure:1423: checking for off_t" >&5
+echo "configure:1426: checking for off_t" >&5
 if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1428 "configure"
+#line 1431 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #if STDC_HEADERS
@@ -1452,12 +1455,12 @@ EOF
 fi
 
 echo $ac_n "checking for pid_t""... $ac_c" 1>&6
-echo "configure:1456: checking for pid_t" >&5
+echo "configure:1459: checking for pid_t" >&5
 if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1461 "configure"
+#line 1464 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #if STDC_HEADERS
@@ -1485,12 +1488,12 @@ EOF
 fi
 
 echo $ac_n "checking for size_t""... $ac_c" 1>&6
-echo "configure:1489: checking for size_t" >&5
+echo "configure:1492: checking for size_t" >&5
 if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1494 "configure"
+#line 1497 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #if STDC_HEADERS
@@ -1518,12 +1521,12 @@ EOF
 fi
 
 echo $ac_n "checking for st_rdev in struct stat""... $ac_c" 1>&6
-echo "configure:1522: checking for st_rdev in struct stat" >&5
+echo "configure:1525: checking for st_rdev in struct stat" >&5
 if eval "test \"`echo '$''{'ac_cv_struct_st_rdev'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1527 "configure"
+#line 1530 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -1531,7 +1534,7 @@ int main() {
 struct stat s; s.st_rdev;
 ; return 0; }
 EOF
-if { (eval echo configure:1535: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1538: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   ac_cv_struct_st_rdev=yes
 else
@@ -1552,12 +1555,12 @@ EOF
 fi
 
 echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
-echo "configure:1556: checking whether time.h and sys/time.h may both be included" >&5
+echo "configure:1559: checking whether time.h and sys/time.h may both be included" >&5
 if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1561 "configure"
+#line 1564 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <sys/time.h>
@@ -1566,7 +1569,7 @@ int main() {
 struct tm *tp;
 ; return 0; }
 EOF
-if { (eval echo configure:1570: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1573: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   ac_cv_header_time=yes
 else
@@ -1607,6 +1610,21 @@ else
 fi
 
 
+# Check whether --with-lvm1 or --without-lvm1 was given.
+if test "${with_lvm1+set}" = set; then
+  withval="$with_lvm1"
+   LVM1="$withval" 
+else
+   LVM1="internal" 
+fi
+
+
+if [ "x$LVM1" != xnone -a "x$LVM1" != xinternal -a "x$LVM1" != xshared ];
+ then  { echo "configure: error: --with-lvm1 parameter invalid
+" 1>&2; exit 1; }
+ exit
+fi;
+
 # Check whether --enable-jobs or --disable-jobs was given.
 if test "${enable_jobs+set}" = set; then
   enableval="$enable_jobs"
@@ -1631,7 +1649,7 @@ if test "${enable_readline+set}" = set; then
   \
 READLINE=$enableval
 else
-  READLINE=yes
+  READLINE=no
 fi
 
 
@@ -1641,13 +1659,13 @@ fi;
 
 if test $ac_cv_prog_gcc = yes; then
     echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6
-echo "configure:1645: checking whether ${CC-cc} needs -traditional" >&5
+echo "configure:1663: checking whether ${CC-cc} needs -traditional" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
     ac_pattern="Autoconf.*'x'"
   cat > conftest.$ac_ext <<EOF
-#line 1651 "configure"
+#line 1669 "configure"
 #include "confdefs.h"
 #include <sgtty.h>
 Autoconf TIOCGETP
@@ -1665,7 +1683,7 @@ rm -f conftest*
 
   if test $ac_cv_prog_gcc_traditional = no; then
     cat > conftest.$ac_ext <<EOF
-#line 1669 "configure"
+#line 1687 "configure"
 #include "confdefs.h"
 #include <termio.h>
 Autoconf TCGETA
@@ -1687,12 +1705,12 @@ echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6
 fi
 
 echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
-echo "configure:1691: checking return type of signal handlers" >&5
+echo "configure:1709: checking return type of signal handlers" >&5
 if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1696 "configure"
+#line 1714 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <signal.h>
@@ -1709,7 +1727,7 @@ int main() {
 int i;
 ; return 0; }
 EOF
-if { (eval echo configure:1713: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1731: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   ac_cv_type_signal=void
 else
@@ -1728,12 +1746,12 @@ EOF
 
 
 echo $ac_n "checking for vprintf""... $ac_c" 1>&6
-echo "configure:1732: checking for vprintf" >&5
+echo "configure:1750: checking for vprintf" >&5
 if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1737 "configure"
+#line 1755 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char vprintf(); below.  */
@@ -1756,7 +1774,7 @@ vprintf();
 
 ; return 0; }
 EOF
-if { (eval echo configure:1760: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1778: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_func_vprintf=yes"
 else
@@ -1780,12 +1798,12 @@ fi
 
 if test "$ac_cv_func_vprintf" != yes; then
 echo $ac_n "checking for _doprnt""... $ac_c" 1>&6
-echo "configure:1784: checking for _doprnt" >&5
+echo "configure:1802: checking for _doprnt" >&5
 if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1789 "configure"
+#line 1807 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char _doprnt(); below.  */
@@ -1808,7 +1826,7 @@ _doprnt();
 
 ; return 0; }
 EOF
-if { (eval echo configure:1812: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1830: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_func__doprnt=yes"
 else
@@ -1835,12 +1853,12 @@ fi
 for ac_func in mkdir rmdir uname
 do
 echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:1839: checking for $ac_func" >&5
+echo "configure:1857: checking for $ac_func" >&5
 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1844 "configure"
+#line 1862 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char $ac_func(); below.  */
@@ -1863,7 +1881,7 @@ $ac_func();
 
 ; return 0; }
 EOF
-if { (eval echo configure:1867: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1885: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_func_$ac_func=yes"
 else
@@ -1891,14 +1909,14 @@ done
 if test x$READLINE = xyes; then
        
 echo $ac_n "checking for library containing tgetent""... $ac_c" 1>&6
-echo "configure:1895: checking for library containing tgetent" >&5
+echo "configure:1913: checking for library containing tgetent" >&5
 if eval "test \"`echo '$''{'ac_cv_search_tgetent'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   ac_func_search_save_LIBS="$LIBS"
 ac_cv_search_tgetent="no"
 cat > conftest.$ac_ext <<EOF
-#line 1902 "configure"
+#line 1920 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1909,7 +1927,7 @@ int main() {
 tgetent()
 ; return 0; }
 EOF
-if { (eval echo configure:1913: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1931: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   ac_cv_search_tgetent="none required"
 else
@@ -1920,7 +1938,7 @@ rm -f conftest*
 test "$ac_cv_search_tgetent" = "no" && for i in ncurses curses termcap termlib; do
 LIBS="-l$i  $ac_func_search_save_LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1924 "configure"
+#line 1942 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1931,7 +1949,7 @@ int main() {
 tgetent()
 ; return 0; }
 EOF
-if { (eval echo configure:1935: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1953: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   ac_cv_search_tgetent="-l$i"
 break
@@ -1965,7 +1983,7 @@ fi
 
 if test x$READLINE = xyes; then
        echo $ac_n "checking for readline in -lreadline""... $ac_c" 1>&6
-echo "configure:1969: checking for readline in -lreadline" >&5
+echo "configure:1987: checking for readline in -lreadline" >&5
 ac_lib_var=`echo readline'_'readline | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1973,7 +1991,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lreadline  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1977 "configure"
+#line 1995 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1984,7 +2002,7 @@ int main() {
 readline()
 ; return 0; }
 EOF
-if { (eval echo configure:1988: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2006: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -2021,12 +2039,12 @@ package as well (which may be called readline-devel or something similar).
 fi
 
        echo $ac_n "checking for rl_completion_matches""... $ac_c" 1>&6
-echo "configure:2025: checking for rl_completion_matches" >&5
+echo "configure:2043: checking for rl_completion_matches" >&5
 if eval "test \"`echo '$''{'ac_cv_func_rl_completion_matches'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2030 "configure"
+#line 2048 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char rl_completion_matches(); below.  */
@@ -2049,7 +2067,7 @@ rl_completion_matches();
 
 ; return 0; }
 EOF
-if { (eval echo configure:2053: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2071: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_func_rl_completion_matches=yes"
 else
@@ -2085,6 +2103,7 @@ fi
 
 
 
+
 trap '' 1 2 15
 cat > confcache <<\EOF
 # This file is a shell script that caches the results of configure
@@ -2203,6 +2222,7 @@ Makefile                                                          \
 make.tmpl                                                               \
 include/Makefile                                                       \
 lib/Makefile                                                           \
+lib/format1/Makefile                                                   \
 man/Makefile                                                           \
 tools/Makefile                                                         \
 tools/version.h                                                                \
@@ -2255,6 +2275,7 @@ s%@CPP@%$CPP%g
 s%@JOBS@%$JOBS%g
 s%@STATIC_LINK@%$STATIC_LINK%g
 s%@READLINE@%$READLINE%g
+s%@LVM1@%$LVM1%g
 s%@HAVE_RL_COMPLETION_MATCHES@%$HAVE_RL_COMPLETION_MATCHES%g
 s%@OWNER@%$OWNER%g
 s%@GROUP@%$GROUP%g
@@ -2305,6 +2326,7 @@ Makefile                                                          \
 make.tmpl                                                               \
 include/Makefile                                                       \
 lib/Makefile                                                           \
+lib/format1/Makefile                                                   \
 man/Makefile                                                           \
 tools/Makefile                                                         \
 tools/version.h                                                                \
index c95e8c6f8f61291d44ebdb3e73e9ebe7d4711827..28f87b809213577f7f62e4a3f93e57c75733fa00 100644 (file)
@@ -61,15 +61,29 @@ AC_ARG_WITH(group,
   [ GROUP="$withval" ],
   [ GROUP="root" ])
 
+dnl -- format1 inclusion type
+AC_ARG_WITH(lvm1,
+  [  --with-lvm1=TYPE        LVM1 metadata support: internal/shared/none
+                          [TYPE=internal] ],
+  [ LVM1="$withval" ],
+  [ LVM1="internal" ])
+
+if [[ "x$LVM1" != xnone -a "x$LVM1" != xinternal -a "x$LVM1" != xshared ]];
+ then  AC_MSG_ERROR(
+--with-lvm1 parameter invalid
+)
+ exit
+fi;
+
 AC_ARG_ENABLE(jobs, [  --enable-jobs=NUM       Number of jobs to run simultaneously], JOBS=-j$enableval, JOBS=)
 
 dnl Enables staticly linked tools
 AC_ARG_ENABLE(static_link, [  --enable-static_link    Use this to link the tools to the liblvm library
                           statically.  Default is dynamic linking],  STATIC_LINK=$enableval, STATIC_LINK=no)
 
-dnl Disable readline
-AC_ARG_ENABLE(readline, [  --disable-readline      Disable readline support],  \
-READLINE=$enableval, READLINE=yes)
+dnl Enable readline
+AC_ARG_ENABLE(readline, [  --enable-readline       Enable readline support],  \
+READLINE=$enableval, READLINE=no)
 
 dnl Mess with default exec_prefix
 if [[ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ]];
@@ -125,6 +139,7 @@ fi
 AC_SUBST(JOBS)
 AC_SUBST(STATIC_LINK)
 AC_SUBST(READLINE)
+AC_SUBST(LVM1)
 AC_SUBST(HAVE_RL_COMPLETION_MATCHES)
 AC_SUBST(OWNER)
 AC_SUBST(GROUP)
@@ -137,6 +152,7 @@ Makefile                                                            \
 make.tmpl                                                               \
 include/Makefile                                                       \
 lib/Makefile                                                           \
+lib/format1/Makefile                                                   \
 man/Makefile                                                           \
 tools/Makefile                                                         \
 tools/version.h                                                                \
index 60554a83704af8d1c544babdfb0a52381f15d821..df97131ba1de561150407149a59a9547998dd7f3 100644 (file)
@@ -1,24 +1,25 @@
-# This is an example configuration file for the LVM2 system.  It
-# contains the default settings that would be used if there was no
+# This is an example configuration file for the LVM2 system.
+# It contains the default settings that would be used if there was no
 # /etc/lvm/lvm.conf file.
-# Refer to 'man lvm.conf' for further information.
+#
+# Refer to 'man lvm.conf' for further information including the file layout.
+#
+# To put this file in a different directory and override /etc/lvm set
+# the environment variable LVM_SYSTEM_DIR before running the tools.
 
 
-# This section allows the user to configure which block devices should
+# This section allows you to configure which block devices should
 # be used by the LVM system.
 devices {
 
-    # where do you want your volume groups to appear ?
+    # Where do you want your volume groups to appear ?
     dir = "/dev"
 
     # An array of directories that contain the device nodes you wish
     # to use with LVM2.
-    scan = "/dev"
-
-    # A very important option, that allows you to tune the LVM2 system
-    # to just look at a restricted set of devices that you're
-    # interested in.
+    scan = [ "/dev" ]
 
+    # A filter that tells LVM2 to only use a restricted set of devices.
     # The filter consists of an array of regular expressions.  These
     # expressions can be delimited by a character of your choice, and
     # prefixed with either an 'a' (for accept) or 'r' (for reject).
@@ -26,51 +27,56 @@ devices {
     # Remember to run vgscan after you change this parameter.
 
     # By default we accept every block device:
-    filter = "a/.*/"
+    filter = [ "a/.*/" ]
+
+    # Exclude the cdrom drive
+    # filter = [ "r|/dev/cdrom|" ]
 
     # When testing I like to work with just loopback devices:
-    # filter = ["a/loop/", "r/.*/"]
+    # filter = [ "a/loop/", "r/.*/" ]
 
     # Or maybe all loops and ide drives except hdc:
-    # filter =["a|loop|", "r|/dev/hdc|", "a|/dev/ide|", "r|.*|"]
+    # filter =[ "a|loop|", "r|/dev/hdc|", "a|/dev/ide|", "r|.*|" ]
 
     # Use anchors if you want to be really specific
-    # filter = ["a|^/dev/hda8$|", "r/.*/"]
+    # filter = [ "a|^/dev/hda8$|", "r/.*/" ]
 
-    # The results of all the filtering are cached on disk to avoid
+    # The results of the filtering are cached on disk to avoid
     # rescanning dud devices (which can take a very long time).  By
-    # default this cache file is hidden in the /etc/lvm directory, it
-    # is human readable to aid filter debugging.
+    # default this cache file is hidden in the /etc/lvm directory.
+    # It is safe to delete this file. vgscan regenerates it.
     cache = "/etc/lvm/.cache"
 
     # You can turn off writing this cache file by setting this to 0.
     write_cache_state = 1
 }
 
-# A section that allows the user to configure the nature of the
+# This section that allows you to configure the nature of the
 # information that LVM2 reports.
 log {
 
-    # Where should the log of error and debug messages go ?  By
-    # default there is no log.
-    #file = "/var/log/lvm2.log"
-
-    # Should we overwrite the last log.  By default we append.
-    overwrite = 0
-
-    # There are 9 log levels, with 9 being the most verbose.
-    level = 3
-    
-    # Controls the messages sent to stdout or stderr while running 
-    # LVM2.  There are three levels of verbosity, 3 being the most 
-    # verbose.
+    # Controls the messages sent to stdout or stderr.
+    # There are three levels of verbosity, 3 being the most verbose.
     verbose = 0
 
     # Should we send log messages through syslog?
     # 1 is yes; 0 is no.
     syslog = 1
 
-    # Choose format of output messages
+    # Should we log error and debug messages to a file?
+    # By default there is no log file.
+    #file = "/var/log/lvm2.log"
+
+    # Should we overwrite the log file each time the program is run?
+    # By default we append.
+    overwrite = 0
+
+    # What level of log messages should we send to the log file and/or syslog?
+    # There are 6 syslog-like log levels currently in use - 2 to 7 inclusive.
+    # 7 is the most verbose (LOG_DEBUG).
+    level = 0
+    
+    # Format of output messages
     # Whether or not (1 or 0) to indent messages according to their severity
     indent = 1
 
@@ -78,10 +84,11 @@ log {
     command_names = 0
 
     # A prefix to use before the message text (but after the command name,
-    # if selected)
+    # if selected).  Default is two spaces, so you can see/grep the severity
+    # of each message.
     prefix = "  "
 
-    # To make the messages look similar to the original LVM use:
+    # To make the messages look similar to the original LVM tools use:
     #   indent = 0
     #   command_names = 1
     #   prefix = " -- "
@@ -95,19 +102,20 @@ backup {
 
     # Should we maintain a backup of the current metadata configuration ?
     # Use 1 for Yes; 0 for No.
-    # Think very hard before turning this off.
+    # Think very hard before turning this off!
     backup = 1
 
     # Where shall we keep it ?
+    # Remember to back up this directory regularly!
     backup_dir = "/etc/lvm/backup"
 
-
     # Should we maintain an archive of old metadata configurations.
     # Use 1 for Yes; 0 for No.
     # On by default.  Think very hard before turning this off.
     archive = 1
 
     # Where should archived files go ?
+    # Remember to back up this directory regularly!
     archive_dir = "/etc/lvm/archive"
     
     # What is the minimum number of archive files you wish to keep ?
@@ -117,20 +125,15 @@ backup {
     retain_days = 30
 }
 
-# Settings for the running LVM2 in shell mode.
+# Settings for the running LVM2 in shell (readline) mode.
 shell {
 
     # Number of lines of history to store in ~/.lvm_history
     history_size = 100
 }
 
-# Metadata settings
-metadata {
-    # List of directories holding copies of text format metadata
-    dirs = [ "/etc/lvm/metadata" ]
-}
 
-# Miscellaneous global settings
+# Miscellaneous global LVM2 settings
 global {
     
     # The file creation mask for any files and directories created.
@@ -145,10 +148,73 @@ global {
     # command.  Defaults to off.
     test = 0
 
-    # Default metadata format commands use - "lvm1" (default) or "text"
-    format = "lvm1"
+    # Whether or not to communicate with the kernel device-mapper.
+    # Set to 0 if you want to use the tools to manipulate LVM metadata 
+    # without activating any logical volumes.
+    # If the device-mapper kernel driver is not present in your kernel
+    # setting this to 0 should suppress the error messages.
+    activation = 1
+
+    # The default metadata format that commands should use - "lvm1" or "lvm2".
+    # The command line override is -M1 or -M2.
+    # Defaults to "lvm1" if compiled in, else "lvm2".
+    # format = "lvm1"
 
     # Location of proc filesystem
     proc = "/proc"
+
+    # Type of locking to use. Defaults to file-based locking (1).
+    # Turn locking off by setting to 0 (dangerous: risks metadata corruption
+    # if LVM2 commands get run concurrently).
+    locking_type = 1
+
+    # Local non-LV directory that holds file-based locks while commands are
+    # in progress.  A directory like /tmp that may get wiped on reboot is OK.
+    locking_dir = "/var/lock/lvm"
+
+    # Other entries can go here to allow you to load shared libraries
+    # e.g. if support for LVM1 metadata was compiled as a shared library use
+    #   format_libraries = "liblvm2format1.so" 
+    # Full pathnames can be given.
+
+    # Search this directory first for shared libraries.
+    #   library_dir = "/lib"
 }
 
+
+####################
+# Advanced section #
+####################
+
+# Metadata settings
+#
+# metadata {
+    # Default number of copies of metadata to hold on each PV.  0, 1 or 2.
+    # It's best to leave this at 2.
+    # You might want to override it from the command line with 0 or 1 
+    # when running pvcreate on new PVs which are to be added to large VGs.
+
+    # pvmetadatacopies = 2
+
+    # Approximate default size of on-disk metadata areas in sectors.
+    # You should increase this if you have large volume groups or
+    # you want to retain a large on-disk history of your metadata changes.
+
+    # pvmetadatasize = 255
+
+    # List of directories holding live copies of text format metadata.
+    # These directories must not be on logical volumes!
+    # It's possible to use LVM2 with a couple of directories here,
+    # preferably on different (non-LV) filesystems, and with no other 
+    # on-disk metadata (pvmetadatacopies = 0). Or this can be in
+    # addition to on-disk metadata areas.
+    # The feature was originally added to simplify testing.
+    #
+    # Never edit any files in these directories by hand unless you
+    # you are absolutely sure you know what you are doing! Use
+    # the supplied toolset to make changes (e.g. vgcfgrestore).
+
+    # dirs = [ "/etc/lvm/metadata", "/mnt/disk2/lvm/metadata2" ]
+#}
+
+
index 681709e9ce6dbe8cc6c7b610591024c66e982280..dc1449c46b8987927760d4c987d52cc82bc3ed6a 100644 (file)
@@ -1,4 +1,5 @@
 ../lib/activate/activate.h
+../lib/cache/cache.h
 ../lib/commands/errors.h
 ../lib/commands/toolcontext.h
 ../lib/config/config.h
 ../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
index f3842ca57a328e4f8c214977acba751952471fa8..d208a2e7d3a0dce10a805c8e606f07f7cfb97c6a 100644 (file)
@@ -8,10 +8,16 @@ srcdir = @srcdir@
 top_srcdir = @top_srcdir@
 VPATH = @srcdir@
 
+ifeq ("@LVM1@", "shared")
+  SUBDIRS = format1
+endif
+
 SOURCES=\
        activate/activate.c \
        activate/dev_manager.c \
        activate/fs.c \
+       cache/cache.c \
+       commands/toolcontext.c \
        config/config.c \
        datastruct/bitset.c \
        datastruct/btree.c \
@@ -24,20 +30,14 @@ SOURCES=\
        filters/filter-persistent.c \
        filters/filter-regex.c \
        filters/filter.c \
-       format1/disk-rep.c \
-       format1/format1.c \
-       format1/import-export.c \
-       format1/import-extents.c \
-       format1/layout.c \
-       format1/lvm1_label.c \
-       format1/vg_number.c \
        format_text/archive.c \
        format_text/export.c \
        format_text/flags.c \
        format_text/format-text.c \
        format_text/import.c \
+       format_text/import_vsn1.c \
+       format_text/text_label.c \
        label/label.c \
-       label/uuid-map.c \
        locking/external_locking.c \
        locking/file_locking.c \
        locking/locking.c \
@@ -48,14 +48,26 @@ SOURCES=\
        metadata/metadata.c \
        metadata/pv_map.c \
        metadata/snapshot_manip.c \
+       misc/crc.c \
        misc/lvm-file.c \
+       misc/sharedlib.c \
        mm/dbg_malloc.c \
        mm/pool.c \
        regex/matcher.c \
        regex/parse_rx.c \
        regex/ttree.c \
-       uuid/uuid.c \
-       vgcache/vgcache.c
+       uuid/uuid.c 
+
+ifeq ("@LVM1@", "internal")
+  SOURCES+=\
+       format1/disk-rep.c \
+       format1/format1.c \
+       format1/import-export.c \
+       format1/import-extents.c \
+       format1/layout.c \
+       format1/lvm1-label.c \
+       format1/vg_number.c
+endif
 
 TARGETS=liblvm.a
 
index 100ff9a93cd2b4c14fc0724e79da7491dfc1c460..f2397d26cb8cacf79d313bbfbf88e85993ec5736 100644 (file)
@@ -4,9 +4,9 @@
  * This file is released under the LGPL.
  */
 
+#include "lib.h"
 #include "format-text.h"
 
-#include "log.h"
 #include "pool.h"
 #include "config.h"
 #include "hash.h"
@@ -17,7 +17,6 @@
 
 #include <dirent.h>
 #include <unistd.h>
-#include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/file.h>
 #include <fcntl.h>
@@ -52,7 +51,7 @@ struct archive_file {
  * Extract vg name and version number from a filename.
  */
 static int _split_vg(const char *filename, char *vg, size_t vg_size,
-                    uint32_t * index)
+                    uint32_t *index)
 {
        int len, vg_len;
        char *dot, *underscore;
@@ -202,7 +201,7 @@ static void _remove_expired(struct list *archives, uint32_t archives_size,
                return;
 
        /* Convert retain_days into the time after which we must retain */
-       retain_time = time(NULL) - (time_t) retain_days * SECS_PER_DAY;
+       retain_time = time(NULL) - (time_t) retain_days *SECS_PER_DAY;
 
        /* Assume list is ordered oldest first (by index) */
        list_iterate(bh, archives) {
@@ -252,7 +251,7 @@ int archive_vg(struct volume_group *vg,
                return 0;
        }
 
-       if (!text_vg_export(fp, vg, desc)) {
+       if (!text_vg_export_file(vg, desc, fp)) {
                stack;
                fclose(fp);
                return 0;
@@ -297,8 +296,7 @@ int archive_vg(struct volume_group *vg,
        return 1;
 }
 
-static void _display_archive(struct cmd_context *cmd, struct uuid_map *um,
-                            struct archive_file *af)
+static void _display_archive(struct cmd_context *cmd, struct archive_file *af)
 {
        struct volume_group *vg = NULL;
        struct format_instance *tf;
@@ -308,8 +306,9 @@ static void _display_archive(struct cmd_context *cmd, struct uuid_map *um,
 
        log_print("path:\t\t%s", af->path);
 
-       if (!(context = create_text_context(cmd->fmtt, af->path, NULL)) ||
-           !(tf = cmd->fmtt->ops->create_instance(cmd->fmtt, NULL, context))) {
+       if (!(context = create_text_context(cmd, af->path, NULL)) ||
+           !(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
+                                                        context))) {
                log_error("Couldn't create text instance object.");
                return;
        }
@@ -319,7 +318,7 @@ static void _display_archive(struct cmd_context *cmd, struct uuid_map *um,
         * retrieve the archive time and description.
         */
        /* FIXME Use variation on _vg_read */
-       if (!(vg = text_vg_import(tf, af->path, um, &when, &desc))) {
+       if (!(vg = text_vg_import_file(tf, af->path, &when, &desc))) {
                log_print("Unable to read archive file.");
                tf->fmt->ops->destroy_instance(tf);
                return;
@@ -332,8 +331,7 @@ static void _display_archive(struct cmd_context *cmd, struct uuid_map *um,
        tf->fmt->ops->destroy_instance(tf);
 }
 
-int archive_list(struct cmd_context *cmd, struct uuid_map *um,
-                const char *dir, const char *vg)
+int archive_list(struct cmd_context *cmd, const char *dir, const char *vg)
 {
        struct list *archives, *ah;
        struct archive_file *af;
@@ -349,7 +347,7 @@ int archive_list(struct cmd_context *cmd, struct uuid_map *um,
        list_iterate(ah, archives) {
                af = list_item(ah, struct archive_file);
 
-               _display_archive(cmd, um, af);
+               _display_archive(cmd, af);
                log_print(" ");
        }
 
index a95540686c6da9aa1a0927448a932b27fe42776c..8c7e545726a24602dd39682d0d383ad108d71238 100644 (file)
@@ -4,40 +4,74 @@
  * This file is released under the LGPL.
  */
 
+#include "lib.h"
 #include "import-export.h"
 #include "metadata.h"
-#include "log.h"
 #include "hash.h"
 #include "pool.h"
-#include "dbg_malloc.h"
-#include "lvm-string.h"
 #include "display.h"
+#include "lvm-string.h"
 
-#include <stdio.h>
 #include <stdarg.h>
 #include <time.h>
+#include <sys/utsname.h>
 
-
+struct formatter;
+typedef int (*out_with_comment_fn) (struct formatter * f, const char *comment,
+                                   const char *fmt, va_list ap);
+typedef void (*nl_fn) (struct formatter * f);
+/*
+ * The first half of this file deals with
+ * exporting the vg, ie. writing it to a file.
+ */
 struct formatter {
        struct pool *mem;       /* pv names allocated from here */
        struct hash_table *pv_names;    /* dev_name -> pv_name (eg, pv1) */
 
-       FILE *fp;               /* where we're writing to */
-       int indent;             /* current level of indentation */
+       union {
+               FILE *fp;       /* where we're writing to */
+               struct {
+                       char *buf;
+                       uint32_t size;
+                       uint32_t used;
+               } buf;
+       } data;
+
+       out_with_comment_fn out_with_comment;
+       nl_fn nl;
 
+       int indent;             /* current level of indentation */
        int error;
+       int header;             /* 1 => comments at start; 0 => end */
 };
 
+static struct utsname _utsname;
+
+static void _init(void)
+{
+       static int _initialised = 0;
+
+       if (_initialised)
+               return;
+
+       if (uname(&_utsname)) {
+               log_error("uname failed: %s", strerror(errno));
+               memset(&_utsname, 0, sizeof(_utsname));
+       }
+
+       _initialised = 1;
+}
+
 /*
  * Formatting functions.
  */
-static void _out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
+static int _out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
     __attribute__ ((format(printf, 3, 4)));
 
-static void _out_hint(struct formatter *f, const char *fmt, ...)
+static int _out_hint(struct formatter *f, const char *fmt, ...)
     __attribute__ ((format(printf, 2, 3)));
 
-static void _out(struct formatter *f, const char *fmt, ...)
+static int _out(struct formatter *f, const char *fmt, ...)
     __attribute__ ((format(printf, 2, 3)));
 
 #define MAX_INDENT 5
@@ -58,26 +92,39 @@ static void _dec_indent(struct formatter *f)
 /*
  * Newline function for prettier layout.
  */
-static void _nl(struct formatter *f)
+static void _nl_file(struct formatter *f)
 {
-       fprintf(f->fp, "\n");
+       fprintf(f->data.fp, "\n");
+}
+
+static void _nl_raw(struct formatter *f)
+{
+       if (f->data.buf.used >= f->data.buf.size - 1)
+               return;
+
+       *f->data.buf.buf = '\n';
+       f->data.buf.buf += 1;
+       f->data.buf.used += 1;
+       *f->data.buf.buf = '\0';
+
+       return;
 }
 
 #define COMMENT_TAB 6
-static void _out_with_comment(struct formatter *f, const char *comment,
-                             const char *fmt, va_list ap)
+static int _out_with_comment_file(struct formatter *f, const char *comment,
+                                 const char *fmt, va_list ap)
 {
        int i;
        char white_space[MAX_INDENT + 1];
 
-       if (ferror(f->fp))
-               return;
+       if (ferror(f->data.fp))
+               return 0;
 
        for (i = 0; i < f->indent; i++)
                white_space[i] = '\t';
        white_space[i] = '\0';
-       fprintf(f->fp, white_space);
-       i = vfprintf(f->fp, fmt, ap);
+       fprintf(f->data.fp, white_space);
+       i = vfprintf(f->data.fp, fmt, ap);
 
        if (comment) {
                /*
@@ -88,13 +135,34 @@ static void _out_with_comment(struct formatter *f, const char *comment,
                i++;
 
                do
-                       fputc('\t', f->fp);
+                       fputc('\t', f->data.fp);
 
                while (++i < COMMENT_TAB);
 
-               fprintf(f->fp, comment);
+               fprintf(f->data.fp, comment);
        }
-       fputc('\n', f->fp);
+       fputc('\n', f->data.fp);
+
+       return 1;
+}
+
+static int _out_with_comment_raw(struct formatter *f, const char *comment,
+                                const char *fmt, va_list ap)
+{
+       int n;
+
+       n = vsnprintf(f->data.buf.buf, f->data.buf.size - f->data.buf.used,
+                     fmt, ap);
+
+       if (n < 0 || (n > f->data.buf.size - f->data.buf.used - 1))
+               return 0;
+
+       f->data.buf.buf += n;
+       f->data.buf.used += n;
+
+       f->nl(f);
+
+       return 1;
 }
 
 /*
@@ -109,7 +177,7 @@ static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
                "Kilobytes",
                "Megabytes",
                "Gigabytes",
-               "Terrabytes",
+               "Terabytes",
                NULL
        };
 
@@ -129,43 +197,55 @@ static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
  * Appends a comment giving a size in more easily
  * readable form (eg, 4M instead of 8096).
  */
-static void _out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
+static int _out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
 {
        char buffer[64];
        va_list ap;
+       int r;
 
-       _sectors_to_units(size, buffer, sizeof(buffer));
+       if (!_sectors_to_units(size, buffer, sizeof(buffer)))
+               return 0;
 
        va_start(ap, fmt);
-       _out_with_comment(f, buffer, fmt, ap);
+       r = f->out_with_comment(f, buffer, fmt, ap);
        va_end(ap);
+
+       return r;
 }
 
 /*
  * Appends a comment indicating that the line is
  * only a hint.
  */
-static void _out_hint(struct formatter *f, const char *fmt, ...)
+static int _out_hint(struct formatter *f, const char *fmt, ...)
 {
        va_list ap;
+       int r;
 
        va_start(ap, fmt);
-       _out_with_comment(f, "# Hint only", fmt, ap);
+       r = f->out_with_comment(f, "# Hint only", fmt, ap);
        va_end(ap);
+
+       return r;
 }
 
 /*
  * The normal output function.
  */
-static void _out(struct formatter *f, const char *fmt, ...)
+static int _out(struct formatter *f, const char *fmt, ...)
 {
        va_list ap;
+       int r;
 
        va_start(ap, fmt);
-       _out_with_comment(f, NULL, fmt, ap);
+       r = f->out_with_comment(f, NULL, fmt, ap);
        va_end(ap);
+
+       return r;
 }
 
+#define _outf(args...) do {if (!_out(args)) {stack; return 0;}} while (0)
+
 static int _print_header(struct formatter *f,
                         struct volume_group *vg, const char *desc)
 {
@@ -173,15 +253,17 @@ static int _print_header(struct formatter *f,
 
        t = time(NULL);
 
-       _out(f,
-            "# This file was originally generated by the LVM2 library\n"
-            "# Generated: %s", ctime(&t));
-
-       _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
index 080e507dcf238a858d8158b272ed697c35fac1f9..63f8a479598e94149bc289086cc7b7dd76c26305 100644 (file)
@@ -4,7 +4,7 @@
  * This file is released under the LGPL.
  */
 
-#include "log.h"
+#include "lib.h"
 #include "metadata.h"
 #include "import-export.h"
 #include "lvm-string.h"
@@ -60,7 +60,7 @@ static struct flag *_get_flags(int type)
        return NULL;
 }
 
-static int _emit(char **buffer, size_t * size, const char *fmt, ...)
+static int _emit(char **buffer, size_t *size, const char *fmt, ...)
 {
        size_t n;
        va_list ap;
@@ -122,7 +122,7 @@ int print_flags(uint32_t status, int type, char *buffer, size_t size)
        return 1;
 }
 
-int read_flags(uint32_t * status, int type, struct config_value *cv)
+int read_flags(uint32_t *status, int type, struct config_value *cv)
 {
        int f;
        uint32_t s = 0;
@@ -133,31 +133,30 @@ int read_flags(uint32_t * status, int type, struct config_value *cv)
                return 0;
        }
 
-       /*
-        * Only scan the flags if it wasn't an empty array.
-        */
-       if (cv->type != CFG_EMPTY_ARRAY) {
-               while (cv) {
-                       if (cv->type != CFG_STRING) {
-                               log_err("Status value is not a string.");
-                               return 0;
-                       }
+       if (cv->type == CFG_EMPTY_ARRAY)
+               goto out;
 
-                       for (f = 0; flags[f].description; f++)
-                               if (!strcmp(flags[f].description, cv->v.str)) {
-                                       s |= flags[f].mask;
-                                       break;
-                               }
+       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;
 }
index 076e228e5a4f6da52af5aaebb33e40bddb699fe3..6f493e5aa949515bd29444f81923f1dc12546952 100644 (file)
@@ -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;
index d5c77c71da179bc25abc27efd2d86635f067d5a5..f14c0adfb78165e14cef76dd2bfd56ab0548d606 100644 (file)
@@ -9,7 +9,10 @@
 
 #include "lvm-types.h"
 #include "metadata.h"
-#include "uuid-map.h"
+#include "pool.h"
+
+#define FMT_TEXT_NAME "lvm2"
+#define FMT_TEXT_ALIAS "text"
 
 /*
  * Archives a vg config.  'retain_days' is the minimum number of
  */
 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
index f86249a9585e615320772894af6f77ee79eefb63..f630285c95416bd3cf9d7ebba0aa1606b70f80c5 100644 (file)
@@ -10,7 +10,7 @@
 #include "config.h"
 #include "lvm-types.h"
 #include "metadata.h"
-#include "uuid-map.h"
+#include "pool.h"
 
 #include <stdio.h>
 
@@ -33,14 +33,32 @@ enum {
        LV_FLAGS
 };
 
+struct text_vg_version_ops {
+       int (*check_version) (struct config_tree * cf);
+       struct volume_group *(*read_vg) (struct format_instance * fid,
+                                        struct config_tree * cf);
+       void (*read_desc) (struct pool * mem, struct config_tree * cf,
+                          time_t *when, char **desc);
+};
+
+struct text_vg_version_ops *text_vg_vsn1_init(void);
+
 int print_flags(uint32_t status, int type, char *buffer, size_t size);
 int read_flags(uint32_t *status, int type, struct config_value *cv);
 
-
-int text_vg_export(FILE *fp, struct volume_group *vg, const char *desc);
-struct volume_group *text_vg_import(struct format_instance *fid,
-                                   const char *file,
-                                   struct uuid_map *um,
-                                   time_t *when, char **desc);
+int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp);
+int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf,
+                      uint32_t size);
+struct volume_group *text_vg_import_file(struct format_instance *fid,
+                                        const char *file,
+                                        time_t *when, char **desc);
+struct volume_group *text_vg_import_fd(struct format_instance *fid,
+                                      const char *file,
+                                      int fd,
+                                      off_t offset, uint32_t size,
+                                      off_t offset2, uint32_t size2,
+                                      checksum_fn_t checksum_fn,
+                                      uint32_t checksum,
+                                      time_t *when, char **desc);
 
 #endif
index 4028d71e727389bc8243380aba9912879c337877..8d8acd1e7cd03cb55c975f07164c0d8d44eaf362 100644 (file)
  * 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 (file)
index 0000000..cb944f7
--- /dev/null
@@ -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 (file)
index 0000000..92ba02b
--- /dev/null
@@ -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 (file)
index f4c28e4..0000000
+++ /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 (file)
index 0000000..b39d61e
--- /dev/null
@@ -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;
+}
index dcc523ecc6544021e1c67da5a0bc51a55cfb2aa7..d1618b70ebf2cea22401e402438b0d73d77619cd 100644 (file)
@@ -4,10 +4,18 @@
  * This file is released under the LGPL.
  */
 
+#include "lib.h"
 #include "label.h"
 #include "list.h"
-#include "dbg_malloc.h"
-#include "log.h"
+#include "crc.h"
+#include "xlate.h"
+#include "cache.h"
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+/* FIXME Allow for larger labels?  Restricted to single sector currently */
 
 /*
  * Internal labeller struct.
@@ -58,6 +66,7 @@ void label_exit(void)
        for (c = _labellers.n; c != &_labellers; c = n) {
                n = c->n;
                li = list_item(c, struct labeller_i);
+               li->l->ops->destroy(li->l);
                _free_li(li);
        }
 }
@@ -89,64 +98,257 @@ struct labeller *label_get_handler(const char *name)
        return NULL;
 }
 
-static struct labeller *_find_labeller(struct device *dev)
+static struct labeller *_find_labeller(struct device *dev, char *buf,
+                                      uint64_t *label_sector)
 {
        struct list *lih;
        struct labeller_i *li;
+       struct labeller *r = NULL;
+       int already_open;
+       struct label_header *lh;
+       uint64_t sector;
+       int found = 0;
+       char readbuf[LABEL_SCAN_SIZE];
 
-       list_iterate(lih, &_labellers) {
-               li = list_item(lih, struct labeller_i);
-               if (li->l->ops->can_handle(li->l, dev))
-                       return li->l;
+       already_open = dev_is_open(dev);
+
+       if (!already_open && !dev_open(dev, O_RDONLY)) {
+               stack;
+               return NULL;
        }
 
-       log_debug("No label on device '%s'.", dev_name(dev));
-       return NULL;
+       if (dev_read(dev, 0, LABEL_SCAN_SIZE, readbuf) != LABEL_SCAN_SIZE) {
+               log_debug("%s: Failed to read label area", dev_name(dev));
+               goto out;
+       }
+
+       /* Scan first few sectors for a valid label */
+       for (sector = 0; sector < LABEL_SCAN_SECTORS;
+            sector += LABEL_SIZE >> SECTOR_SHIFT) {
+               lh = (struct label_header *) (readbuf +
+                                             (sector << SECTOR_SHIFT));
+
+               if (!strncmp(lh->id, LABEL_ID, sizeof(lh->id))) {
+                       if (found) {
+                               log_error("Ignoring additional label on %s at "
+                                         "sector %" PRIu64, dev_name(dev),
+                                         sector);
+                       }
+                       if (xlate64(lh->sector_xl) != sector) {
+                               log_info("%s: Label for sector %" PRIu64
+                                        " found at sector %" PRIu64
+                                        " - ignoring", dev_name(dev),
+                                        xlate64(lh->sector_xl), sector);
+                               continue;
+                       }
+                       if (calc_crc(INITIAL_CRC, &lh->offset_xl, LABEL_SIZE -
+                                    ((void *) &lh->offset_xl - (void *) lh)) !=
+                           xlate32(lh->crc_xl)) {
+                               log_info("Label checksum incorrect on %s - "
+                                        "ignoring", dev_name(dev));
+                               continue;
+                       }
+                       if (found)
+                               continue;
+               }
+
+               list_iterate(lih, &_labellers) {
+                       li = list_item(lih, struct labeller_i);
+                       if (li->l->ops->can_handle(li->l, (char *) lh, sector)) {
+                               log_very_verbose("%s: %s label detected",
+                                                dev_name(dev), li->name);
+                               if (found) {
+                                       log_error("Ignoring additional label "
+                                                 "on %s at sector %" PRIu64,
+                                                 dev_name(dev), sector);
+                                       continue;
+                               }
+                               r = li->l;
+                               memcpy(buf, lh, LABEL_SIZE);
+                               if (label_sector)
+                                       *label_sector = sector;
+                               found = 1;
+                               break;
+                       }
+               }
+       }
+
+       if (!found)
+               log_very_verbose("%s: No label detected", dev_name(dev));
+
+      out:
+       if (!already_open && !dev_close(dev))
+               stack;
+
+       return r;
 }
 
+/* FIXME Also wipe associated metadata area headers? */
 int label_remove(struct device *dev)
 {
-       struct labeller *l;
+       char buf[LABEL_SIZE];
+       char readbuf[LABEL_SCAN_SIZE];
+       int r = 1;
+       uint64_t sector;
+       int wipe;
+       struct list *lih;
+       struct labeller_i *li;
+       struct label_header *lh;
+
+       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;
 }
index ec652c843b611559e59d9526e06ce73137bca7d6..bd9549bb0e3e276c5ebb492ef17dc7adbf739bfd 100644 (file)
@@ -7,18 +7,31 @@
 #ifndef _LVM_LABEL_H
 #define _LVM_LABEL_H
 
+#include "cache.h"
+#include "lvm-types.h"
 #include "uuid.h"
 #include "device.h"
 
+#define LABEL_ID "LABELONE"
+#define LABEL_SIZE SECTOR_SIZE /* Think very carefully before changing this */
+#define LABEL_SCAN_SECTORS 4L
+#define LABEL_SCAN_SIZE (LABEL_SCAN_SECTORS << SECTOR_SHIFT)
+
+/* On disk - 32 bytes */
+struct label_header {
+       uint8_t id[8];          /* LABELONE */
+       uint64_t sector_xl;     /* Sector number of this label */
+       uint32_t crc_xl;        /* From next field to end of sector */
+       uint32_t offset_xl;     /* Offset from start of struct to contents */
+       uint8_t type[8];        /* LVM2 001 */
+} __attribute__ ((packed));
+
+/* In core */
 struct label {
-       struct id id;
-
-       char volume_type[32];
-       uint32_t version[3];
-
-       void *extra_info;
-
+       char type[8];
+       uint64_t sector;
        struct labeller *labeller;
+       void *info;
 };
 
 struct labeller;
@@ -27,39 +40,38 @@ struct label_ops {
        /*
         * Is the device labelled with this format ?
         */
-       int (*can_handle)(struct labeller *l, struct device *dev);
+       int (*can_handle) (struct labeller * l, char *buf, uint64_t sector);
 
        /*
         * Write a label to a volume.
         */
-       int (*write)(struct labeller *l,
-                    struct device *dev, struct label *label);
+       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 (file)
index d02675c..0000000
+++ /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 (file)
index e981184..0000000
+++ /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 (file)
index 0e31021..0000000
+++ /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 (file)
index aff7a02..0000000
+++ /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
index 5a2136c66015cc99051801ae68d39924ed963e72..569abfc3e58afa737d56c88a06530686bf417024 100644 (file)
@@ -4,10 +4,9 @@
  * This file is released under the LGPL.
  */
 
+#include "lib.h"
 #include "metadata.h"
 #include "pv_map.h"
-#include "log.h"
-#include "dbg_malloc.h"
 #include "lvm-string.h"
 #include "toolcontext.h"
 
@@ -17,7 +16,7 @@
  * These functions adjust the pe counts in pv's
  * after we've added or removed segments.
  */
-static void _get_extents(struct stripe_segment *seg)
+static void _get_extents(struct lv_segment *seg)
 {
        int s, count;
        struct physical_volume *pv;
@@ -29,7 +28,7 @@ static void _get_extents(struct stripe_segment *seg)
        }
 }
 
-static void _put_extents(struct stripe_segment *seg)
+static void _put_extents(struct lv_segment *seg)
 {
        int s, count;
        struct physical_volume *pv;
@@ -43,9 +42,9 @@ static void _put_extents(struct stripe_segment *seg)
        }
 }
 
-static struct stripe_segment *_alloc_segment(struct pool *mem, int stripes)
+static struct lv_segment *_alloc_segment(struct pool *mem, int stripes)
 {
-       struct stripe_segment *seg;
+       struct lv_segment *seg;
        uint32_t len = sizeof(*seg) + (stripes * sizeof(seg->area[0]));
 
        if (!(seg = pool_zalloc(mem, len))) {
@@ -58,13 +57,13 @@ static struct stripe_segment *_alloc_segment(struct pool *mem, int stripes)
 
 static int _alloc_stripe_area(struct logical_volume *lv, uint32_t stripes,
                              uint32_t stripe_size,
-                             struct pv_area **areas, uint32_t * index)
+                             struct pv_area **areas, uint32_t *index)
 {
        uint32_t count = lv->le_count - *index;
        uint32_t per_area = count / stripes;
        uint32_t smallest = areas[stripes - 1]->count;
        uint32_t s;
-       struct stripe_segment *seg;
+       struct lv_segment *seg;
 
        if (smallest < per_area)
                per_area = smallest;
@@ -75,6 +74,7 @@ static int _alloc_stripe_area(struct logical_volume *lv, uint32_t stripes,
        }
 
        seg->lv = lv;
+       seg->type = SEG_STRIPED;
        seg->le = *index;
        seg->len = per_area * stripes;
        seg->stripes = stripes;
@@ -169,11 +169,11 @@ static int _alloc_striped(struct logical_volume *lv,
  * the complete area then the area is split, otherwise the area
  * is unlinked from the pv_map.
  */
-static int _alloc_linear_area(struct logical_volume *lv, uint32_t * index,
+static int _alloc_linear_area(struct logical_volume *lv, uint32_t *index,
                              struct pv_map *map, struct pv_area *pva)
 {
        uint32_t count, remaining;
-       struct stripe_segment *seg;
+       struct lv_segment *seg;
 
        count = pva->count;
        remaining = lv->le_count - *index;
@@ -186,6 +186,7 @@ static int _alloc_linear_area(struct logical_volume *lv, uint32_t * index,
        }
 
        seg->lv = lv;
+       seg->type = SEG_STRIPED;
        seg->le = *index;
        seg->len = count;
        seg->stripe_size = 0;
@@ -248,8 +249,8 @@ static int _alloc_contiguous(struct logical_volume *lv,
  * Areas just get allocated in order until the lv
  * is full.
  */
-static int _alloc_simple(struct logical_volume *lv,
-                        struct list *pvms, uint32_t allocated)
+static int _alloc_next_free(struct logical_volume *lv,
+                           struct list *pvms, uint32_t allocated)
 {
        struct list *tmp1, *tmp2;
        struct pv_map *pvm;
@@ -305,8 +306,8 @@ static int _allocate(struct volume_group *vg, struct logical_volume *lv,
        else if (lv->alloc == ALLOC_CONTIGUOUS)
                r = _alloc_contiguous(lv, pvms, allocated);
 
-       else if (lv->alloc == ALLOC_NEXT_FREE)
-               r = _alloc_simple(lv, pvms, allocated);
+       else if (lv->alloc == ALLOC_NEXT_FREE || lv->alloc == ALLOC_DEFAULT)
+               r = _alloc_next_free(lv, pvms, allocated);
 
        else {
                log_error("Unknown allocation policy: "
@@ -322,7 +323,7 @@ static int _allocate(struct volume_group *vg, struct logical_volume *lv,
                 * counts in pv's.
                 */
                for (segh = lv->segments.p; segh != old_tail; segh = segh->p)
-                       _get_extents(list_item(segh, struct stripe_segment));
+                       _get_extents(list_item(segh, struct lv_segment));
        } else {
                /*
                 * Put the segment list back how we found it.
@@ -456,12 +457,12 @@ int lv_reduce(struct format_instance *fi,
              struct logical_volume *lv, uint32_t extents)
 {
        struct list *segh;
-       struct stripe_segment *seg;
+       struct lv_segment *seg;
        uint32_t count = extents;
 
        for (segh = lv->segments.p;
             (segh != &lv->segments) && count; segh = segh->p) {
-               seg = list_item(segh, struct stripe_segment);
+               seg = list_item(segh, struct lv_segment);
 
                if (seg->len <= count) {
                        /* remove this segment completely */
@@ -534,7 +535,7 @@ int lv_remove(struct volume_group *vg, struct logical_volume *lv)
 
        /* iterate through the lv's segments freeing off the pe's */
        list_iterate(segh, &lv->segments)
-           _put_extents(list_item(segh, struct stripe_segment));
+           _put_extents(list_item(segh, struct lv_segment));
 
        vg->lv_count--;
        vg->free_count += lv->le_count;
index 86220046f2f2a91cdd103f83be31e3aa64fdbe91..67413a95621cdc3ff3f348bc37c12ea2b83464e6 100644 (file)
@@ -4,7 +4,7 @@
  * This file is released under the LGPL.
  */
 
-#include "log.h"
+#include "lib.h"
 #include "metadata.h"
 
 /*
  * 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);
index 668502322ff037e35107b38e6403099fe4b56093..8941f82613c4a7a679187e194e4604f31e26c4bb 100644 (file)
@@ -4,24 +4,21 @@
  * This file is released under the LGPL.
  */
 
-#include "log.h"
+#include "lib.h"
 #include "pool.h"
 #include "device.h"
-#include "dev-cache.h"
 #include "metadata.h"
 #include "toolcontext.h"
 #include "lvm-string.h"
-#include "uuid.h"
-#include "vgcache.h"
+#include "cache.h"
 
-#include <string.h>
-
-int _add_pv_to_vg(struct format_instance *fi, struct volume_group *vg,
+int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg,
                  const char *pv_name)
 {
        struct pv_list *pvl;
        struct physical_volume *pv;
-       struct pool *mem = fi->fmt->cmd->mem;
+       struct pool *mem = fid->fmt->cmd->mem;
+       struct list mdas;
 
        log_verbose("Adding physical volume '%s' to volume group '%s'",
                    pv_name, vg->name);
@@ -31,7 +28,8 @@ int _add_pv_to_vg(struct format_instance *fi, struct volume_group *vg,
                return 0;
        }
 
-       if (!(pv = pv_read(fi->fmt->cmd, pv_name))) {
+       list_init(&mdas);
+       if (!(pv = pv_read(fid->fmt->cmd, pv_name, &mdas, NULL))) {
                log_error("Failed to read existing physical volume '%s'",
                          pv_name);
                return 0;
@@ -43,6 +41,12 @@ int _add_pv_to_vg(struct format_instance *fi, struct volume_group *vg,
                return 0;
        }
 
+       if (pv->fmt != fid->fmt) {
+               log_error("Physical volume %s is of different format type (%s)",
+                         pv_name, pv->fmt->name);
+               return 0;
+       }
+
        if (!(pv->vg_name = pool_strdup(mem, vg->name))) {
                log_error("vg->name allocation failed for '%s'", pv_name);
                return 0;
@@ -58,13 +62,14 @@ int _add_pv_to_vg(struct format_instance *fi, struct volume_group *vg,
 
        /*
         * The next two fields should be corrected
-        * by fi->pv_setup.
+        * by fid->pv_setup.
         */
-       pv->pe_count = (pv->size - pv->pe_start) / pv->pe_size;
+       pv->pe_count = (pv->size - pv->pe_start) / vg->extent_size;
 
        pv->pe_alloc_count = 0;
 
-       if (!fi->fmt->ops->pv_setup(fi, pv, vg)) {
+       if (!fid->fmt->ops->pv_setup(fid->fmt, 0, 0, vg->extent_size, 0, 0,
+                                    &fid->metadata_areas, pv, vg)) {
                log_error("Format-specific setup of physical volume '%s' "
                          "failed.", pv_name);
                return 0;
@@ -93,19 +98,21 @@ int _add_pv_to_vg(struct format_instance *fi, struct volume_group *vg,
        return 1;
 }
 
-int vg_extend(struct format_instance *fi,
+int vg_extend(struct format_instance *fid,
              struct volume_group *vg, int pv_count, char **pv_names)
 {
        int i;
 
        /* attach each pv */
        for (i = 0; i < pv_count; i++)
-               if (!_add_pv_to_vg(fi, vg, pv_names[i])) {
+               if (!_add_pv_to_vg(fid, vg, pv_names[i])) {
                        log_error("Unable to add physical volume '%s' to "
                                  "volume group '%s'.", pv_names[i], vg->name);
                        return 0;
                }
 
+/* FIXME Decide whether to initialise and add new mdahs to format instance */
+
        return 1;
 }
 
@@ -124,6 +131,7 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
 {
        struct volume_group *vg;
        struct pool *mem = cmd->mem;
+       int consistent = 0;
 
        if (!(vg = pool_zalloc(mem, sizeof(*vg)))) {
                stack;
@@ -132,7 +140,7 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
 
        /* is this vg name already in use ? */
        init_partial(1);
-       if (vg_read(cmd, vg_name)) {
+       if (vg_read(cmd, vg_name, &consistent)) {
                log_err("A volume group called '%s' already exists.", vg_name);
                goto bad;
        }
@@ -198,11 +206,17 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
        return NULL;
 }
 
-struct physical_volume *pv_create(struct format_instance *fid,
-                                 const char *name,
-                                 struct id *id, uint64_t size)
+/* Sizes in sectors */
+struct physical_volume *pv_create(struct format_type *fmt,
+                                 struct device *dev,
+                                 struct id *id, uint64_t size,
+                                 uint64_t pe_start,
+                                 uint32_t existing_extent_count,
+                                 uint32_t existing_extent_size,
+                                 int pvmetadatacopies,
+                                 uint64_t pvmetadatasize, struct list *mdas)
 {
-       struct pool *mem = fid->fmt->cmd->mem;
+       struct pool *mem = fmt->cmd->mem;
        struct physical_volume *pv = pool_alloc(mem, sizeof(*pv));
 
        if (!pv) {
@@ -215,10 +229,7 @@ struct physical_volume *pv_create(struct format_instance *fid,
        else
                memcpy(&pv->id, id, sizeof(*id));
 
-       if (!(pv->dev = dev_cache_get(name, fid->fmt->cmd->filter))) {
-               log_error("%s: Couldn't find device.", name);
-               goto bad;
-       }
+       pv->dev = dev;
 
        if (!(pv->vg_name = pool_alloc(mem, NAME_LEN))) {
                stack;
@@ -229,22 +240,22 @@ struct physical_volume *pv_create(struct format_instance *fid,
        pv->status = ALLOCATABLE_PV;
 
        if (!dev_get_size(pv->dev, &pv->size)) {
-               log_error("%s: Couldn't get size.", name);
+               log_error("%s: Couldn't get size.", dev_name(pv->dev));
                goto bad;
        }
 
        if (size) {
                if (size > pv->size)
                        log_print("WARNING: %s: Overriding real size. "
-                                 "You could lose data.", name);
+                                 "You could lose data.", dev_name(pv->dev));
                log_verbose("%s: Pretending size is %" PRIu64 " sectors.",
-                           name, size);
+                           dev_name(pv->dev), size);
                pv->size = size;
        }
 
        if (pv->size < PV_MIN_SIZE) {
-               log_error("%s: Size must exceed minimum of %lu sectors.",
-                         name, PV_MIN_SIZE);
+               log_error("%s: Size must exceed minimum of %ld sectors.",
+                         dev_name(pv->dev), PV_MIN_SIZE);
                goto bad;
        }
 
@@ -252,11 +263,14 @@ struct physical_volume *pv_create(struct format_instance *fid,
        pv->pe_start = 0;
        pv->pe_count = 0;
        pv->pe_alloc_count = 0;
-       pv->fid = fid;
+       pv->fmt = fmt;
 
-       if (!fid->fmt->ops->pv_setup(fid, pv, NULL)) {
+       if (!fmt->ops->pv_setup(fmt, pe_start, existing_extent_count,
+                               existing_extent_size,
+                               pvmetadatacopies, pvmetadatasize, mdas,
+                               pv, NULL)) {
                log_error("%s: Format-specific setup of physical volume "
-                         "failed.", name);
+                         "failed.", dev_name(pv->dev));
                goto bad;
        }
        return pv;
@@ -278,7 +292,21 @@ struct pv_list *find_pv_in_vg(struct volume_group *vg, const char *pv_name)
        }
 
        return NULL;
+}
+
+struct physical_volume *find_pv_in_vg_by_uuid(struct volume_group *vg,
+                                             struct id *id)
+{
+       struct list *pvh;
+       struct pv_list *pvl;
 
+       list_iterate(pvh, &vg->pvs) {
+               pvl = list_item(pvh, struct pv_list);
+               if (id_equal(&pvl->pv->id, id))
+                       return pvl->pv;
+       }
+
+       return NULL;
 }
 
 struct lv_list *find_lv_in_vg(struct volume_group *vg, const char *lv_name)
@@ -339,16 +367,14 @@ struct physical_volume *find_pv(struct volume_group *vg, struct device *dev)
 int vg_remove(struct volume_group *vg)
 {
        struct list *mdah;
-       void *mdl;
-
-       if (!vg->fid->fmt->ops->vg_remove)
-               return 1;
+       struct metadata_area *mda;
 
        /* FIXME Improve recovery situation? */
        /* Remove each copy of the metadata */
        list_iterate(mdah, &vg->fid->metadata_areas) {
-               mdl = list_item(mdah, struct metadata_area)->metadata_locn;
-               if (!vg->fid->fmt->ops->vg_remove(vg->fid, vg, mdl)) {
+               mda = list_item(mdah, struct metadata_area);
+               if (mda->ops->vg_remove &&
+                   !mda->ops->vg_remove(vg->fid, vg, mda)) {
                        stack;
                        return 0;
                }
@@ -360,7 +386,8 @@ int vg_remove(struct volume_group *vg)
 int vg_write(struct volume_group *vg)
 {
        struct list *mdah;
-       void *mdl;
+       struct metadata_area *mda;
+       int cache_updated = 0;
 
        if (vg->status & PARTIAL_VG) {
                log_error("Cannot change metadata for partial volume group %s",
@@ -368,24 +395,31 @@ int vg_write(struct volume_group *vg)
                return 0;
        }
 
+       if (list_empty(&vg->fid->metadata_areas)) {
+               log_error("Aborting vg_write: No metadata areas to write to!");
+               return 0;
+       }
+
        vg->seqno++;
 
        /* Write to each copy of the metadata area */
        list_iterate(mdah, &vg->fid->metadata_areas) {
-               mdl = list_item(mdah, struct metadata_area)->metadata_locn;
-               if (!vg->fid->fmt->ops->vg_write(vg->fid, vg, mdl)) {
+               mda = list_item(mdah, struct metadata_area);
+               if (!mda->ops->vg_write(vg->fid, vg, mda)) {
                        stack;
                        return 0;
                }
        }
 
-       if (!vg->fid->fmt->ops->vg_commit)
-               return 1;
-
        /* Commit to each copy of the metadata area */
        list_iterate(mdah, &vg->fid->metadata_areas) {
-               mdl = list_item(mdah, struct metadata_area)->metadata_locn;
-               if (!vg->fid->fmt->ops->vg_commit(vg->fid, vg, mdl)) {
+               mda = list_item(mdah, struct metadata_area);
+               if (!cache_updated) {
+                       cache_update_vg(vg);
+                       cache_updated = 1;
+               }
+               if (mda->ops->vg_commit &&
+                   !mda->ops->vg_commit(vg->fid, vg, mda)) {
                        stack;
                        return 0;
                }
@@ -394,46 +428,105 @@ int vg_write(struct volume_group *vg)
        return 1;
 }
 
-struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name)
+/* Make orphan PVs look like a VG */
+struct volume_group *_vg_read_orphans(struct cmd_context *cmd)
+{
+       struct cache_vginfo *vginfo;
+       struct list *ih;
+       struct device *dev;
+       struct pv_list *pvl;
+       struct volume_group *vg;
+       struct physical_volume *pv;
+
+       if (!(vginfo = vginfo_from_vgname(ORPHAN))) {
+               stack;
+               return NULL;
+       }
+
+       if (!(vg = pool_zalloc(cmd->mem, sizeof(*vg)))) {
+               log_error("vg allocation failed");
+               return NULL;
+       }
+       list_init(&vg->pvs);
+       list_init(&vg->lvs);
+       list_init(&vg->snapshots);
+       vg->cmd = cmd;
+       if (!(vg->name = pool_strdup(cmd->mem, ORPHAN))) {
+               log_error("vg name allocation failed");
+               return NULL;
+       }
+
+       list_iterate(ih, &vginfo->infos) {
+               dev = list_item(ih, struct cache_info)->dev;
+               if (!(pv = pv_read(cmd, dev_name(dev), NULL, NULL))) {
+                       continue;
+               }
+               if (!(pvl = pool_zalloc(cmd->mem, sizeof(*pvl)))) {
+                       log_error("pv_list allocation failed");
+                       return NULL;
+               }
+               pvl->pv = pv;
+               list_add(&vg->pvs, &pvl->list);
+               vg->pv_count++;
+       }
+
+       return vg;
+}
+
+/* Caller sets consistent to 1 if it's safe for vg_read to correct
+ * inconsistent metadata on disk (i.e. the VG write lock is held).
+ * This guarantees only consistent metadata is returned unless PARTIAL_VG.
+ * If consistent is 0, caller must check whether consistent == 1 on return
+ * and take appropriate action if it isn't (e.g. abort; get write lock 
+ * and call vg_read again).
+ */
+struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
+                            int *consistent)
 {
        struct format_instance *fid;
        struct format_type *fmt;
        struct volume_group *vg, *correct_vg;
-       struct list *mdah, *names;
-       void *mdl;
+       struct list *mdah;
+       struct metadata_area *mda;
        int inconsistent = 0, first_time = 1;
 
-       /* create format instance with appropriate metadata area */
-       if (!(fmt = vgcache_find_format(vg_name))) {
-               /* Do full scan */
-               if (!(names = get_vgs(cmd))) {
-                       stack;
-                       return NULL;
-               }
-               pool_free(cmd->mem, names);
-               if (!(fmt = vgcache_find_format(vg_name))) {
-                       stack;
-                       return NULL;
+       if (!*vgname) {
+               *consistent = 1;
+               return _vg_read_orphans(cmd);
+       }
+
+       /* Find the vgname in the cache */
+       /* If it's not there we must do full scan to be completely sure */
+       if (!(fmt = fmt_from_vgname(vgname))) {
+               cache_label_scan(cmd, 0);
+               if (!(fmt = fmt_from_vgname(vgname))) {
+                       cache_label_scan(cmd, 1);
+                       if (!(fmt = fmt_from_vgname(vgname))) {
+                               stack;
+                               return NULL;
+                       }
                }
        }
 
-       if (!(fid = fmt->ops->create_instance(fmt, vg_name, NULL))) {
+       /* create format instance with appropriate metadata area */
+       if (!(fid = fmt->ops->create_instance(fmt, vgname, NULL))) {
                log_error("Failed to create format instance");
                return NULL;
        }
 
        /* Ensure contents of all metadata areas match - else do recovery */
        list_iterate(mdah, &fid->metadata_areas) {
-               mdl = list_item(mdah, struct metadata_area)->metadata_locn;
-               if (!(vg = fid->fmt->ops->vg_read(fid, vg_name, mdl))) {
-                       inconsistent = 1;
-                       continue;
+               mda = list_item(mdah, struct metadata_area);
+               if (!(vg = mda->ops->vg_read(fid, vgname, mda))) {
+                       inconsistent = 1;
+                       continue;
                }
                if (first_time) {
                        correct_vg = vg;
                        first_time = 0;
                        continue;
                }
+               /* FIXME Also ensure contents same - checksum compare? */
                if (correct_vg->seqno != vg->seqno) {
                        inconsistent = 1;
                        if (vg->seqno > correct_vg->seqno)
@@ -447,7 +540,21 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name)
                return NULL;
        }
 
+       cache_update_vg(correct_vg);
+
        if (inconsistent) {
+               if (!*consistent)
+                       return correct_vg;
+
+               /* Don't touch partial volume group metadata */
+               /* Should be fixed manually with vgcfgbackup/restore etc. */
+               if ((correct_vg->status & PARTIAL_VG)) {
+                       log_error("Inconsistent metadata copies found for "
+                                 "partial volume group %s", vgname);
+                       *consistent = 0;
+                       return correct_vg;
+               }
+
                log_print("Inconsistent metadata copies found - updating "
                          "to use version %u", correct_vg->seqno);
                if (!vg_write(correct_vg)) {
@@ -456,51 +563,121 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name)
                }
        }
 
-       vgcache_add(vg_name, correct_vg->id.uuid, NULL, fmt);
+       *consistent = 1;
 
        return correct_vg;
 }
 
+/* This is only called by lv_from_lvid, which is only called from 
+ * activate.c so we know the appropriate VG lock is already held and 
+ * the vg_read is therefore safe.
+ */
 struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid)
 {
        char *vgname;
-       struct list *vgs, *vgh;
+       struct list *vgnames, *slh;
        struct volume_group *vg;
+       struct cache_vginfo *vginfo;
+       int consistent = 0;
+
+       /* 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;
index 9908470fe8e715e037eeb08a3b99aa2804c2845e..2c101048cda9d48a09525ee73e9bc88ba739e3b7 100644 (file)
 #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
index a30019e8bcf68aae140f78452ce875da0ecad0cf..efde0848caffde9b609db49e20a06a8767b0813b 100644 (file)
@@ -4,8 +4,8 @@
  * This file is released under the LGPL.
  */
 
+#include "lib.h"
 #include "pv_map.h"
-#include "log.h"
 #include "hash.h"
 
 #include <assert.h>
@@ -73,7 +73,7 @@ static int _fill_bitsets(struct volume_group *vg, struct list *maps)
        struct pv_map *pvm;
        uint32_t s, pe;
        struct hash_table *hash;
-       struct stripe_segment *seg;
+       struct lv_segment *seg;
        int r = 0;
 
        if (!(hash = hash_create(128))) {
@@ -95,7 +95,7 @@ static int _fill_bitsets(struct volume_group *vg, struct list *maps)
                lv = list_item(lvh, struct lv_list)->lv;
 
                list_iterate(segh, &lv->segments) {
-                       seg = list_item(segh, struct stripe_segment);
+                       seg = list_item(segh, struct lv_segment);
 
                        for (s = 0; s < seg->stripes; s++) {
                                for (pe = 0; pe < (seg->len / seg->stripes);
@@ -142,7 +142,7 @@ static void _insert_area(struct list *head, struct pv_area *a)
 }
 
 static int _create_single_area(struct pool *mem, struct pv_map *pvm,
-                              uint32_t * extent)
+                              uint32_t *extent)
 {
        uint32_t e = *extent, b, count = pvm->pv->pe_count;
        struct pv_area *pva;
index 06384ce85e2bf84ba1e4e92b41fe46e3983a97c4..23aeb18d80d7f6cc3fca35ad508c06273a93a919 100644 (file)
@@ -4,7 +4,7 @@
  * This file is released under the LGPL.
  */
 
-#include "log.h"
+#include "lib.h"
 #include "metadata.h"
 #include "toolcontext.h"
 
@@ -97,7 +97,7 @@ struct list *find_snapshots(struct logical_volume *lv)
 
 int vg_add_snapshot(struct logical_volume *origin,
                    struct logical_volume *cow,
-                   int persistent, uint32_t chunk_size)
+                   int persistent, struct id *id, uint32_t chunk_size)
 {
        struct snapshot *s;
        struct snapshot_list *sl;
@@ -121,12 +121,20 @@ int vg_add_snapshot(struct logical_volume *origin,
        s->origin = origin;
        s->cow = cow;
 
+       if (id)
+               s->id = *id;
+       else if (!id_create(&s->id)) {
+               log_error("Snapshot UUID creation failed");
+               return 0;
+       }
+
        if (!(sl = pool_alloc(mem, sizeof(*sl)))) {
                stack;
                pool_free(mem, s);
                return 0;
        }
 
+       cow->status &= ~VISIBLE_LV;
        sl->snapshot = s;
        list_add(&origin->vg->snapshots, &sl->list);
 
index 21988cba385e1228212510d38523f822c53670dd..e388b698919411c25630982495d27fea31994c10 100644 (file)
@@ -48,7 +48,7 @@ MAKEFLAGS = @JOBS@
 endif
 
 SUFFIXES=
-SUFFIXES=.c .d .o
+SUFFIXES=.c .d .o .so
 
 CFLAGS+=-Wall 
 #CFLAGS+=-O2
@@ -57,10 +57,13 @@ CFLAGS+=-g -fno-omit-frame-pointer
 #CFLAGS+=-pg
 #LD_FLAGS=-pg
 
-CFLAGS+=-D_REENTRANT -DDEBUG_MEM -DDEBUG -D_GNU_SOURCE
+CFLAGS+=-DDEBUG_MEM -DDEBUG
 #CFLAGS+=-DDEBUG_POOL
 #CFLAGS+=-DBOUNDS_CHECK
 
+LIB_VERSION := $(shell cat $(top_srcdir)/VERSION | \
+                awk -F '.' '{printf "%s.%s",$$1,$$2}')
+
 INCLUDES+=-I. -I$(top_srcdir)/include
 INC_LNS=$(top_srcdir)/include/.symlinks_created
 
@@ -81,6 +84,10 @@ ifeq ("@HAVE_RL_COMPLETION_MATCHES@", "yes")
   CFLAGS += -DHAVE_RL_COMPLETION_MATCHES
 endif
 
+ifeq ("@LVM1@", "internal")
+  CFLAGS += -DLVM1_INTERNAL
+endif
+
 OBJECTS=$(SOURCES:%.c=%.o)
 
 SUBDIRS.install := $(SUBDIRS:=.install)
@@ -101,14 +108,21 @@ $(SUBDIRS.install):
        $(MAKE) -C $(@:.install=) install
 
 $(SUBDIRS.clean):
-       $(MAKE) -C $(@:.clean=) clean
+       -$(MAKE) -C $(@:.clean=) clean
 
 $(SUBDIRS.distclean):
-       $(MAKE) -C $(@:.distclean=) distclean
+       -$(MAKE) -C $(@:.distclean=) distclean
 
 %.o: %.c
        $(CC) -c $(INCLUDES) $(CFLAGS) $< -o $@
 
+%.so: %.o
+       $(CC) -c $(INCLUDES) $(CFLAGS) %< -o $@
+
+%.so: $(OBJECTS)
+       $(CC) -shared -Wl,-soname,$(notdir $@).$(LIB_VERSION) \
+       -Wl,--version-script,.export.sym $(OBJECTS) -o $@
+
 %.d: %.c
        set -e; FILE=`echo $@ | sed 's/\\//\\\\\\//g;s/\\.d//g'`; \
                DEPS=`echo $(DEPS) | sed -e 's/\\//\\\\\\//g'`; \
index bd114b1c11a32f7342240d2923bfdddce576f76e..0b688cb482be439cddd3c88b183528461f4b93bb 100644 (file)
@@ -23,8 +23,9 @@ VPATH = @srcdir@
 MAN5=lvm.conf.5
 MAN8=lvchange.8 lvcreate.8 lvdisplay.8 lvextend.8 lvm.8 lvmchange.8 \
        lvreduce.8 lvremove.8 lvrename.8 lvscan.8 pvchange.8 \
-       pvcreate.8 pvdisplay.8 pvscan.8 vgcfgbackup.8 vgchange.8 vgck.8 \
-       vgcreate.8 vgdisplay.8 vgextend.8 vgmerge.8 vgreduce.8 vgremove.8 \
+       pvcreate.8 pvdisplay.8 pvremove.8 pvscan.8 vgcfgbackup.8 \
+       vgcfgrestore.8 vgchange.8 vgck.8 vgcreate.8 \
+       vgconvert.8 vgdisplay.8 vgextend.8 vgmerge.8 vgreduce.8 vgremove.8 \
        vgrename.8 vgscan.8
 MAN5DIR=${mandir}/man5
 MAN8DIR=${mandir}/man8
index 0b5fe2c10d68fd66fb46ff5945a3cb87edd0f9ae..f5fa1a42a637d520b3b307f506669561fd743358 100644 (file)
@@ -5,18 +5,17 @@ lvchange \- change attributes of a logical volume
 .B lvchange
 [\-A/\-\-autobackup y/n] [\-a/\-\-available y/n]
 [\-C/\-\-contiguous y/n] [\-d/\-\-debug] [\-h/\-?/\-\-help]
+[\-\-ignorelockingfailure]
+[\-M/\-\-persistent y/n] [\-\-minor minor]
+[\-P/\-\-partial y/n]
 [\-p/\-\-permission r/w] [\-r/\-\-readahead ReadAheadSectors]
+[\-t/\-\-test]
 [\-v/\-\-verbose] LogicalVolumePath [LogicalVolumePath...]
 .SH DESCRIPTION
 lvchange allows you to change the attributes of a logical volume.
 .SH OPTIONS
 See \fBlvm\fP for common options.
 .TP
-.I \-A, \-\-autobackup y/n
-Controls automatic backup of VG metadata after the change ( see
-.B vgcfgbackup(8)
-). Default is yes.
-.TP
 .I \-a, \-\-available y/n
 Controls the availability of the logical volumes for use.
 This is (among others) useful for changing the logical volume's name
@@ -25,18 +24,25 @@ This is (among others) useful for changing the logical volume's name
 ) safely.
 .TP
 .I \-C, \-\-contiguous y/n
-Tries to set or resets the contiguous allocation policy for
+Tries to set or reset the contiguous allocation policy for
 logical volumes. It's only possible to change a non-contiguous
 logical volume's allocation policy to contiguous, if all of the
 allocated physical extents are already contiguous.
 .TP
+.I \-\-minor minor
+Set the minor number.
+.TP
+.I \-M, \-\-persistent y/n
+Set to y to make the minor number specified persistent.
+.TP
 .I \-p, \-\-permission r/w
 Change access permission to read-only or read/write.
 .TP
 .I \-r, \-\-readahead ReadAheadSectors
 Change read ahead sector count per logical between 2 and 120.
+Not used by device-mapper.
 .SH Examples
-"lvchange -x n /dev/vg00/lvol1" prevents the allocation of any physical
+"lvchange -x n vg00/lvol1" prevents the allocation of any physical
 extents on logical volume lvol1 in volume group vg00.
 .SH SEE ALSO
 .BR lvm (8), 
index da16d1702f96eebc1cf73c506d2c4aea85a84aac..ed4ab82c3b07a968e2cb2ecac06554052f231e48 100644 (file)
@@ -8,8 +8,10 @@ lvcreate \- create a logical volume in an existing volume group
 [\-i/\-\-stripes Stripes [\-I/\-\-stripesize StripeSize]]
 {\-l/\-\-extents LogicalExtentsNumber |
  \-L/\-\-size LogicalVolumeSize[kKmMgGtT]}
+[\-M/\-\-persistent y/n] [\-\-minor minor]
 [\-n/\-\-name LogicalVolumeName]
 [\-p/\-\-permission r/rw] [\-r/\-\-readahead ReadAheadSectors]
+[\-t/\-\-test]
 [\-v/\-\-verbose] [\-Z/\-\-zero y/n]
 VolumeGroupName [PhysicalVolumePath...]
 .br
@@ -37,13 +39,6 @@ keep the contents of the original logical volume for backup purposes.
 .SH OPTIONS
 See \fBlvm\fP for common options.
 .TP
-.I \-A, \-\-autobackup y/n
-Controls automatic backup of VG metadata after the change ( see
-.B vgcfgbackup(8)
-).
-.br
-Default is yes.
-.TP
 .I \-c, \-\-chunksize ChunkSize
 Power of 2 chunk size for the snapshot logical volume between 4k and 1024k.
 .TP
@@ -73,6 +68,12 @@ G for gigabytes or T for terabytes is optional.
 .br
 Default unit is megabytes.
 .TP
+.I \-\-minor minor
+Set the minor number.
+.TP
+.I \-M, \-\-persistent y/n
+Set to y to make the minor number specified persistent.
+.TP
 .I \-n, \-\-name LogicalVolumeName
 The name for the new logical volume.
 .br
@@ -86,6 +87,7 @@ Default is read and write.
 .TP
 .I \-r, \-\-readahead ReadAheadSectors
 Set read ahead sector count of this logical volume to a value between 2 and 120.
+Ignored by device-mapper.
 .TP
 .I \-s, \-\-snapshot
 Create a snapshot logical volume (or snapshot) for an existing, so called
@@ -122,7 +124,7 @@ contents of the original logical volume named /dev/vg00/lvol1
 at snapshot logical volume creation time. If the original logical volume
 contains a file system, you can mount the snapshot logical volume on an
 arbitrary directory in order to access the contents of the filesystem to run
-a backup while the original filesystem is updated.
+a backup while the original filesystem continues to get updated.
 
 .SH SEE ALSO
 .BR lvm (8), 
index 0a9f68af811ec4bdc4ca1111c4a5f817caec3850..401d3de1d8fbe4e642999631f87908e985d7c0ab 100644 (file)
@@ -3,8 +3,10 @@
 lvdisplay \- display attributes of a logical volume
 .SH SYNOPSIS
 .B lvdisplay
-[\-c/\-\-colon] [\-d/\-\-debug] [\-D/\-\-disk] [\-h/\-?/\-\-help]
-[\-v[v]/\-\-verbose] LogicalVolumePath [LogicalVolumePath...]
+[\-c/\-\-colon] [\-d/\-\-debug] [\-h/\-?/\-\-help]
+[\-\-ignorelockingfailure]
+[\-\-maps] [\-P/\-\-partial]
+[\-v/\-\-verbose] LogicalVolumePath [LogicalVolumePath...]
 .SH DESCRIPTION
 lvdisplay allows you to see the attributes of a logical volume
 like size, read/write status, snapshot information etc.
@@ -12,7 +14,8 @@ like size, read/write status, snapshot information etc.
 See \fBlvm\fP for common options.
 .TP
 .I \-c, \-\-colon
-Generate colon seperated output for easier parsing in scripts or programs.
+Deprecated.  To be replaced with a more-powerful reporting tool.
+Generate colon separated output for easier parsing in scripts or programs.
 .nf
 
 The values are:
@@ -33,11 +36,6 @@ The values are:
 
 .fi
 .TP
-.I \-D, \-\-disk
-Show attributes of the volume group descriptor array on disk(s).
-Without this switch they are derived from kernel space.
-Useful, if the volume group isn't active.
-.TP
 .I \-m, \-\-maps
 Display the mapping of logical extents to physical volumes and
 physical extents.
index 98c379be4090ad1acb9f4c4335afa98fb925cad2..f9bb73aa5bd7f32ef6ea326cf57e90b462ffe9a0 100644 (file)
@@ -4,8 +4,10 @@ lvextend \- extend the size of a logical volume
 .SH SYNOPSIS
 .B lvextend
 [\-A/\-\-autobackup y/n] [\-d/\-\-debug] [\-h/\-?/\-\-help]
+[\-i/\-\-stripes Stripes [\-I/\-\-stripesize StripeSize]]
 {\-l/\-\-extents [+]LogicalExtentsNumber |
 \-L/\-\-size [+]LogicalVolumeSize[kKmMgGtT]}
+[\-t/\-\-test]
 [\-v/\-\-verbose] LogicalVolumePath [PhysicalVolumePath...]
 .SH DESCRIPTION
 lvextend allows you to extend the size of a logical volume.
@@ -15,11 +17,6 @@ for information to create snapshots) is supprted as well.
 .SH OPTIONS
 See \fBlvm\fP for common options.
 .TP
-.I \-A, \-\-autobackup y/n
-Controls automatic backup of VG metadata after the change ( see
-.B vgcfgbackup(8)
-). Default is yes.
-.TP
 .I \-l, \-\-extents [+]LogicalExtentsNumber
 Extend or set the logical volume size in units of logical extents.
 With the + sign the value is added to the actual size
@@ -30,6 +27,18 @@ Extend or set the logical volume size in units in units of megabytes.
 A size suffix of M for megabytes, G for gigabytes or T for terabytes is
 optional.  With the + sign the value is added to the actual size
 of the logical volume and without it, the value is taken as an absolute one.
+.TP
+.I \-i, \-\-stripes Stripes
+Gives the number of stripes for the extension.
+Not applicable to PVs using the original metadata LVM format.
+This is equal to the number of physical volumes to scatter
+the logical volume.
+.TP
+.I \-I, \-\-stripesize StripeSize
+Gives the number of kilobytes for the granularity of the stripes.
+Not applicable to PVs using the original metadata LVM format.
+.br
+StripeSize must be 2^n (n = 2 to 9)
 .SH Examples
 "lvextend -L +54 /dev/vg01/lvol10 /dev/sdk3" tries to extend the size of
 that logical volume by 54MB on physical volume /dev/sdk3.
index 055b73a1f7aefa9cbf086d3580ffe6bddeeb09f2..e9882567a3f42bd1530daf6bb4a86c2f271925ed 100644 (file)
--- 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.
index 3bc3a72ad3249180c061630e5a84ba5563277173..ef18c6b800b527e2d12bbff1619f78ff8ad6128a 100644 (file)
@@ -4,6 +4,7 @@ lvmchange \- change attributes of the logical volume manager
 .SH SYNOPSIS
 .B lvmchange
 .SH DESCRIPTION
-lvmchange is not currently supported under LVM2
+lvmchange is not currently supported under LVM2, although
+\fBdmsetup (8)\fP has a \fBremove_all\fP command.
 .SH SEE ALSO
 .BR dmsetup (8)
index cc288f37749c967db1ec2b019e9efe6d9cdfe742..d9ce55e59a9439b9066e6a99cbb3ed08bda49886 100644 (file)
@@ -6,7 +6,8 @@ lvreduce \- reduce the size of a logical volume
 [\-A/\-\-autobackup y/n] [\-d/\-\-debug] [\-f/\-\-force]
 [\-h/\-?/\-\-help] {\-l/\-\-extents [\-]LogicalExtentsNumber |
 \-L/\-\-size [\-]LogicalVolumeSize[kKmMgGtT]}
-[\-v/\-\-verbose] LogicalVolumePath
+[\-t/\-\-test]
+[\-v/\-\-verbose] LogicalVolume[Path]
 .SH DESCRIPTION
 lvreduce allows you to reduce the size of a logical volume.
 Be careful when reducing a logical volume's size, because data in the
@@ -26,11 +27,6 @@ for information to create snapshots) is supported as well.
 .SH OPTIONS
 See \fBlvm\fP for common options.
 .TP
-.I \-A, \-\-autobackup y/n
-Controls automatic backup of VG metadata after the change ( see
-.B vgcfgbackup(8)
-). Default is yes.
-.TP
 .I \-f, \-\-force
 Force size reduction without any question.
 .TP
index 9e89c92b4db5c2088cd6a344e87e4baeac1d00b8..69f693b8439c2b93d52087c4d78680e7db406d64 100644 (file)
@@ -4,17 +4,14 @@ lvremove \- remove a logical volume
 .SH SYNOPSIS
 .B lvremove
 [\-A/\-\-autobackup y/n] [\-d/\-\-debug] [\-f/\-\-force]
-[\-h/\-?/\-\-help] [\-v/\-\-verbose] LogicalVolumePath [LogicalVolumePath...]
+[\-h/\-?/\-\-help] 
+[\-t/\-\-test]
+[\-v/\-\-verbose] LogicalVolumePath [LogicalVolumePath...]
 .SH DESCRIPTION
 lvremove allows you to remove one or more inactive logical volumes.
 .SH OPTIONS
 See \fBlvm\fP for common options.
 .TP
-.I \-A, \-\-autobackup y/n
-Controls automatic backup of VG metadata after the change ( see
-.B vgcfgbackup(8)
-). Default is yes.
-.TP
 .I \-f, \-\-force
 Force remove without confirmation.
 .SH Example
index 4704141322197c570ce196a74fab897862833695..11b4f24f60ff226d11819bec8c7b6558c3f26c1a 100644 (file)
@@ -5,7 +5,9 @@ lvrename \- rename a logical volume
 .B lvrename
 .RB [ \-A | \-\-autobackup " {" y | n }]
 .RB [ \-d | \-\-debug ]
+.RB [ \-f | \-\-force ]
 .RB [ \-h | \-\-help ]
+.RB [ \-t | \-\-test ]
 .RB [ \-v | \-\-verbose ]
 .RB [ \-\-version ]
 .TP
@@ -20,11 +22,6 @@ to
 .IR NewLogicalVolume { Name | Path }.
 .SH OPTIONS
 See \fBlvm\fP for common options.
-.TP
-.BR \-A ", " \-\-autobackup " {" y | n }
-Controls automatic backup of VG metadata after the change (see
-.BR vgcfgbackup (8)).
-Default is yes.
 .SH EXAMPLE
 To rename
 .B lvold
index 39859551b6741dee8d2a7b54f16ded4455b2e3f4..04b2b873257da7209152e4927c4306cd550f5421 100644 (file)
@@ -5,8 +5,9 @@ lvscan \- scan (all disks) for logical volumes
 .B lvscan
 .RB [ \-b | \-\-blockdevice ]
 .RB [ \-d | \-\-debug ]
-.RB [ \-D | \-\-disk ]
 .RB [ \-h | \-\-help ]
+.RB [ \-\-ignorelockingfailure ]
+.RB [ \-P | \-\-partial ]
 .RB [ \-v | \-\-verbose ]
 .SH DESCRIPTION
 .B lvscan
@@ -18,10 +19,6 @@ See \fBlvm\fP for common options.
 .BR \-b ", " \-\-blockdevice
 Adds the device major and minor numbers to the display
 of each logical volume.
-.TP
-.BR \-D ", " \-\-disk
-Scan for logical volumes on disk(s) instead of getting the information
-from the kernel.
 .SH SEE ALSO
 .BR lvm (8), 
 .BR lvcreate (8),
index 41224d6e7fbc287d18f5c46b8b4f7d9703877eac..e18cb890369fa9f9092725a2cced2ab2d26cede6 100644 (file)
@@ -4,6 +4,7 @@ pvchange \- change attributes of a physical volume
 .SH SYNOPSIS
 .B pvchange
 [\-A/\-\-autobackup y/n] [\-d/\-\-debug] [\-h/\-?/\-\-help]
+[\-t/\-\-test]
 [\-v/\-\-verbose] [\-a/\-\-all] [\-x/\-\-allocatable y/n] [PhysicalVolumePath...]
 .SH DESCRIPTION
 pvchange allows you to change the allocation permissions of one or
@@ -11,11 +12,6 @@ more physical volumes.
 .SH OPTIONS
 See \fBlvm\fP for common options.
 .TP
-.I \-A, \-\-autobackup y/n
-Controls automatic backup of VG metadata after the change ( see
-.B vgcfgbackup(8)
-). Default is yes.
-.TP
 .I \-a, \-\-all
 If PhysicalVolumePath is not specified on the command line all
 physical volumes are searched for and used.
index 681e3978caa64eb7d71542c7f8a2ea6a85777dac..5bec86fd8dff6d6b23dc1b2d198a64a1fbc15414 100644 (file)
@@ -7,8 +7,15 @@ pvcreate \- initialize a disk or partition for use by LVM
 .RB [ \-f [ f ]| \-\-force " [" \-\-force ]]
 .RB [ \-y | \-\-yes ]
 .RB [ \-h | \-\-help ]
+.RB [ \-t | \-\-test ]
 .RB [ \-v | \-\-verbose ]
-.RB [ \-V | \-\-version ]
+.RB [ \-\-labelsector ]
+.RB [ \-M | \-\-metadatatype type ]
+.RB [ \-\-metadatacopies #copies ]
+.RB [ \-\-metadatasize size ]
+.RB [ \-\-restorefile file ]
+.RB [ \-\-setphysicalvolumesize size ]
+.RB [ \-\-version ]
 .IR PhysicalVolume " [" PhysicalVolume ...]
 .SH DESCRIPTION
 .B pvcreate
@@ -17,7 +24,7 @@ initializes
 for later use by the Logical Volume Manager (LVM).  Each
 .I PhysicalVolume
 can be a disk partition, whole disk, meta device, or loopback file.
-For DOS disk partitions, the partition id must be set to 0x8e using
+For DOS disk partitions, the partition id should be set to 0x8e using
 .BR fdisk "(8), " cfdisk "(8), "
 or a equivalent.  For
 .B whole disk devices only
@@ -47,11 +54,61 @@ In an emergency you can override this behaviour with -ff.
 Specify the uuid for the device.  
 Without this option, \fBpvcreate\fP generates a random uuid.
 All of your physical volumes must have unique uuids.
-You need to use this option to restore a backup of LVM metadata onto 
-a replacement device - see \fBvgcfgrestore\fP(8).
+You need to use this option before restoring a backup of LVM metadata 
+onto a replacement device - see \fBvgcfgrestore\fP(8).
 .TP
 .BR \-y ", " \-\-yes
 Answer yes to all questions.
+.SH NEW METADATA OPTIONS
+LVM2 introduces a new format for storing metadata on disk.
+This new format is more efficient and resilient than the format the 
+original version of LVM used and offers the advanced user greater 
+flexibility and control.
+.sp
+The new format may be selected on the command line with \fB-M2\fP or by 
+setting \fBformat = "lvm2"\fP in the \fBglobal\fP section of \fBlvm.conf\fP.
+Each physical volume in the same volume group must use the same format, but
+different volume groups on a machine may use different formats 
+simultaneously: the tools can handle both formats.
+Additional formats can be added as shared libraries.
+.sp
+Additional tools for manipulating the locations and sizes of metadata areas 
+will be written in due course.  Use the verbose/debug options on the tools
+to see where the metadata areas are placed.
+.TP
+.BR \-\-metadatasize " size"
+The approximate amount of space to be set aside for each metadata area.
+(The size you specify may get rounded.)
+.TP
+.BR \-\-metadatacopies " copies"
+The number of metadata areas to set aside on each PV.  Currently
+this can be 0, 1 or 2.  
+If set to 2 (the default), two copies of the volume group metadata 
+are held on the PV, one at the front of the PV and one at the end.  
+If set to 1, one copy is kept at the front of the PV (starting in the
+5th sector).
+If set to 0, no copies are kept on this PV - you might wish to use this
+with VGs containing large numbers of PVs.  But if you do this and
+then later use \fBvgsplit\fP you must ensure that each VG is still going 
+to have a suitable number of copies of the metadata after the split!
+.TP
+.BR \-\-restorefile " file"
+In conjunction with \fB--uuid\fP, this extracts the location and size
+of the data on the PV from the file (produced by \fBvgcfgbackup\fP)
+and ensures that the metadata that the program produces is consistent 
+with the contents of the file i.e. the physical extents will be in 
+the same place and not get overwritten by new metadata.  This provides
+a mechanism to upgrade the metadata format or to add/remove metadata
+areas. Use with care. See also \fBvgconvert\fP(8).
+.TP
+.BR \-\-labelsector " sector"
+By default the PV is labelled with an LVM2 identifier in its second 
+sector (sector 1).  This lets you use a different sector near the
+start of the disk (between 0 and 3 inclusive - see LABEL_SCAN_SECTORS
+in the source).  Use with care.
+.TP
+.BR \-\-setphysicalvolumesize " size"
+Overrides the automatically-detected size of the PV.  Use with care.
 .SH Example
 Initialize partition #4 on the third SCSI disk and the entire fifth
 SCSI disk for later use by LVM:
@@ -61,4 +118,4 @@ SCSI disk for later use by LVM:
 .SH SEE ALSO
 .BR lvm "(8), " vgcreate "(8), " vgextend "(8), " lvcreate "(8), "
 .BR cfdisk "(8), " fdisk "(8), " losetup "(8), " mdadd "(8), "
-.BR vgcfgrestore "(8)"
+.BR vgcfgrestore "(8), " vgconvert "(8)"
index 840a4f9aae16a0f2915f1df1d08ff4ea004ecbed..b1d0a08993948f5d16fcbe05866d66aa0fc21546 100644 (file)
@@ -22,7 +22,7 @@ The values are:
 * physical volume device name
 * volume group name
 * physical volume size in kilobytes
-* internal physical volume number
+* internal physical volume number (obsolete)
 * physical volume status
 * physical volume (not) allocatable
 * current number of logical volumes on this physical volume
diff --git a/man/pvremove.8 b/man/pvremove.8
new file mode 100644 (file)
index 0000000..7dcf423
--- /dev/null
@@ -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)
index 7473685729cb3f6a69ccb7c9fd14a5b20f0c8178..b8440c8f1f6c2bd08b8567dd591cc4d915391b53 100644 (file)
@@ -6,6 +6,7 @@ pvscan \- scan all disks for physical volumes
 .RB [ \-d | \-\-debug]
 .RB [\-e | \-\-exported]
 .RB [\-h | \-\-help]
+.RB [\-\-ignorelockingfailure]
 .RB [ \-n | \-\-novolumegroup]
 .RB [\-s | \-\-short]
 .RB [\-u | \-\-uuid]
@@ -26,7 +27,7 @@ Only show physical volumes not belonging to any volume group.
 Short listing format.
 .TP
 .BR \-u ", " \-\-uuid
-Show UUIDs (Unifrom Unique Identifiers) in addition to device special names.
+Show UUIDs (Uniform Unique Identifiers) in addition to device special names.
 .SH SEE ALSO
 .BR lvm (8),
 .BR pvcreate (8),
index f6b340fe4e7e939cbd64f5b238e663789080e3c4..85f47395516a93da4bea1939c6d3e0787da7e9bd 100644 (file)
@@ -4,17 +4,19 @@ vgcfgbackup \- backup volume group descriptor area
 .SH SYNOPSIS
 .B vgcfgbackup
 .RB [ \-d | \-\-debug ]
+.RB [ \-f | \-\-file " filename" ]
 .RB [ \-h | \-\-help ]
+.RB [ \-\-ignorelockingfailure ]
+.RB [ \-P | \-\-partial ]
 .RB [ \-v | \-\-verbose ]
 .RI [ VolumeGroupName ...]
 .SH DESCRIPTION
 .B vgcfgbackup
 allows you to backup the metadata 
-of one to all volume groups to files in
-.IR /etc/lvm .
-If you don't give any volume groups in the command line, all of them 
+of your volume groups.
+If you don't name any volume groups pn the command line, all of them 
 will be backed up.  This DOESN'T backup user/system data in logical
-volume(s)! 
+volume(s)!  Backup /etc/lvm regularly too.
 .SH OPTIONS
 See \fBlvm\fP for common options.
 .SH SEE ALSO
diff --git a/man/vgcfgrestore.8 b/man/vgcfgrestore.8
new file mode 100644 (file)
index 0000000..6ce8e6c
--- /dev/null
@@ -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)
index 54f6b5c1b4e399fd6162478330eed2fb0a21ca6a..e48efd21ee91a28ad4d2bcff8dff481ae38499d9 100644 (file)
@@ -3,14 +3,17 @@
 vgchange \- change attributes of a volume group
 .SH SYNOPSIS
 .B vgchange
-.RB [ \-A | \-\-autobackup " {" y | n }]
+.RB [\-A | \-\-autobackup " {" y | n }]
 .RB [\-a | \-\-available " {" y | n }]
 .RB [\-d | \-\-debug]
-.RB [ \-h | \-\-help]
+.RB [\-h | \-\-help]
+.RB [\-\-ignorelockingfailure]
 .RB [\-l | \-\-logicalvolume
 .IR MaxLogicalVolumes ]
-.RB [ \-v | \-\-verbose ]
-.RB [ \-\-version ]
+.RB [\-P | \-\-partial]
+.RB [-t | \-\-test]
+.RB [\-v | \-\-verbose]
+.RB [\-\-version ]
 .RB [\-x | \-\-resizeable " {" y | n }]
 .RI [ VolumeGroupName ...]
 .SH DESCRIPTION
@@ -20,12 +23,13 @@ Its main purpose is to activate and deactivate
 .IR VolumeGroupName ,
 or all volume groups if none is specified.  Only active volume groups
 are subject to changes and allow access to their logical volumes.
-During volume group activation, if
+[Not yet implemented: During volume group activation, if
 .B vgchange
 recognizes snapshot logical volumes which were dropped because they ran
 out of space, it displays a message informing the administrator that such
 snapshots should be removed (see
 .BR lvremove (8)).
+]
 .SH OPTIONS
 See \fBlvm\fP for common options.
 .TP
diff --git a/man/vgconvert.8 b/man/vgconvert.8
new file mode 100644 (file)
index 0000000..4de0da4
--- /dev/null
@@ -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)"
index 01241ea7ff8c24855024e2f72ad9854643bdd819..6916bebf370f5b9b0bebc95bc4c4c2607e6ec2c0 100644 (file)
@@ -8,10 +8,12 @@ vgcreate \- create a volume group
 .RB [ \-h | \-\-help ]
 .RB [ \-l | \-\-maxlogicalvolumes
 .IR MaxLogicalVolumes ]
+.RB [ -M | \-\-metadatatype type]
 .RB [ -p | \-\-maxphysicalvolumes
 .IR MaxPhysicalVolumes ]
 .RB [ \-s | \-\-physicalextentsize
 .IR PhysicalExtentSize [ \fBkKmMgGtT\fR ]]
+.RB [ \-t | \-\-test ]
 .RB [ \-v | \-\-verbose ]
 .RB [ \-\-version ]
 .I VolumeGroupName PhysicalVolumePath
index a4849408f5117a0cddb719fa80a43d9069de2a16..4f958bb90d5d22787356ab9d1da240d3f4e4a215 100644 (file)
@@ -6,8 +6,9 @@ vgdisplay \- display attributes of volume groups
 .RB [ \-A | \-\-activevolumegroups ]
 .RB [ \-c | \-\-colon ]
 .RB [ \-d | \-\-debug ]
-.RB [ \-D | \-\-disk ]
 .RB [ \-h | \-\-help ]
+.RB [ \-\-ignorelockingfailure ]
+.RB [ \-P | \-\-partial ]
 .RB [ \-s | \-\-short ]
 .RB [ \-v [ v ]| \-\-verbose " [" \-\-verbose ]]
 .RB [ \-\-version ]
@@ -50,11 +51,6 @@ The values are:
 
 .fi
 .TP
-.BR \-D ", " \-\-disk
-Show attributes from the volume group descriptor area on disk(s).
-Without this switch they are shown from the kernel.
-Useful if the volume group isn't activated.
-.TP
 .BR \-s ", " \-\-short
 Give a short listing showing the existence of volume groups.
 .TP
index cd81503ce9a9289f99c2693357ffec6cf3c3476c..1e8d84aa66d07c58bef3c50d011244a58ba51ae4 100644 (file)
@@ -3,7 +3,9 @@
 vgextend \- add physical volumes to a volume group
 .SH SYNOPSIS
 .B vgextend
-[\-A/\-\-autobackup y/n] [\-d/\-\-debug] [\-h/\-?/\-\-help] [\-v/\-\-verbose]
+[\-A/\-\-autobackup y/n] [\-d/\-\-debug] [\-h/\-?/\-\-help] 
+[\-t/\-\-test]
+[\-v/\-\-verbose]
 VolumeGroupName PhysicalDevicePath [PhysicalDevicePath...]
 .SH DESCRIPTION
 vgextend allows you to add one or more initialized physical volumes ( see
@@ -11,11 +13,6 @@ vgextend allows you to add one or more initialized physical volumes ( see
 ) to an existing volume group to extend it in size.
 .SH OPTIONS
 See \fBlvm\fP for common options.
-.TP
-.I \-A, \-\-autobackup y/n
-Controls automatic backup of VG metadata after the change ( see
-.B vgcfgbackup(8)
-). Default is yes.
 .SH Examples
 "vgextend vg00 /dev/sda4 /dev/sdn1" tries to extend the existing volume
 group "vg00" by the new physical volumes (see
index 12c27934b755c0260196aa0c6e08f8e1712caf77..172d94841f86411d7f034af8a32d221d8b6b322e 100644 (file)
@@ -13,11 +13,6 @@ are equal and physical and logical volume summaries of both volume groups
 fit into DestinationVolumeGroupName's limits.
 .SH OPTIONS
 See \fBlvm\fP for common options.
-.TP
-.I \-A, \-\-autobackup y/n
-Controls automatic backup of VG metadata after the merge ( see
-.B vgcfgbackup(8)
-). Default is yes.
 .I \-l, \-\-list
 Display merged DestinationVolumeGroupName like "vgdisplay -v".
 .TP 
index d81ea9885d0d680a16c9e04700b7c755192960b4..55ab1c246f52aabc5d1d8d812c2e80d569b5a671 100644 (file)
@@ -4,6 +4,7 @@ vgreduce \- reduce a volume group
 .SH SYNOPSIS
 .B vgreduce
 [\-a/\-\-all] [\-A/\-\-autobackup y/n] [\-d/\-\-debug] [\-h/\-?/\-\-help]
+[\-t/\-\-test]
 [\-v/\-\-verbose] VolumeGroupName
 [PhysicalVolumePath...]
 .SH DESCRIPTION
@@ -14,11 +15,6 @@ See \fBlvm\fP for common options.
 .TP
 .I \-a, \-\-all
 Removes all empty physical volumes if none are given on command line.
-.TP
-.I \-A, \-\-autobackup y/n
-Controls automatic backup of VG metadata after the change ( see
-.B vgcfgbackup(8)
-). Default is yes.
 .SH SEE ALSO
 .BR lvm (8), 
 .BR vgextend (8)
index 7a193102d8df72602c85ec99b429fbae97acabef..7096fe2f0bec9b932127cdf1f2bacfaa33017e74 100644 (file)
@@ -3,7 +3,7 @@
 vgremove \- remove a volume group
 .SH SYNOPSIS
 .B vgremove
-[\-d/\-\-debug] [\-h/\-?/\-\-help] [\-v/\-\-verbose]
+[\-d/\-\-debug] [\-h/\-?/\-\-help] [\-t/\-\-test] [\-v/\-\-verbose]
 VolumeGroupName [VolumeGroupName...]
 .SH DESCRIPTION
 vgremove allows you to remove one or more volume groups.
index 3287030409d4e841b5f55f22caf355a57fae3156..b0f570cddc16cd271d58ca4b4bdd90413be653ed 100644 (file)
@@ -6,6 +6,7 @@ vgrename \- rename a volume group
 [\-A/\-\-autobackup y/n]
 [\-d/\-\-debug]
 [\-h/\-?/\-\-help]
+[\-t/\-\-test]
 [\-v/\-\-verbose]
 OldVolumeGroupPath/\-Name NewVolumeGroupPath/\-Name
 .SH DESCRIPTION
@@ -14,11 +15,6 @@ vgrename renames an existing (see
 ) volume group.
 .SH OPTIONS
 See \fBlvm\fP for common options.
-.TP
-.I \-A, \-\-autobackup y/n
-Controls automatic backup of VG metadata after the change ( see
-.B vgcfgbackup(8)
-). Default is yes.
 .SH Examples
 "vgrename /dev/vg02 /dev/my_volume_group" renames existing
 volume group "vg02" to "my_volume_group".
index 1715c0d0919ce650a98b25add63834212f33b6a9..2f596583ed42c67db542e8fe216dc34a98dc7928 100644 (file)
@@ -3,7 +3,10 @@
 vgscan \- scan all disks for volume groups and rebuild caches
 .SH SYNOPSIS
 .B vgscan
-[\-d/\-\-debug] [\-h/\-?/\-\-help] [\-v/\-\-verbose]
+[\-d/\-\-debug] [\-h/\-?/\-\-help] 
+[\-\-ignorelockingfailure]
+[\-P/\-\-partial]
+[\-v/\-\-verbose]
 .SH DESCRIPTION
 vgscan scans all SCSI, (E)IDE disks, multiple devices and a bunch
 of other disk devices in the system looking for LVM physical volumes
diff --git a/scripts/vg_convert b/scripts/vg_convert
new file mode 100755 (executable)
index 0000000..0fa7e71
--- /dev/null
@@ -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
+
index 800b43eb6ada61bb533ac4c2417c79c00eefbe4b..42ae8aef751e3be0412d7f84ada8e80a63f3aa58 100644 (file)
@@ -37,6 +37,7 @@ SOURCES=\
        pvchange.c \
        pvcreate.c \
        pvdisplay.c \
+       pvremove.c \
        pvscan.c \
        toollib.c \
        vgcfgbackup.c \
@@ -44,6 +45,7 @@ SOURCES=\
        vgchange.c \
        vgck.c \
        vgcreate.c \
+       vgconvert.c \
        vgdisplay.c \
        vgexport.c \
        vgextend.c \
index 15251b516a0d0515fa2787e6788ef645c467adbb..8fdafc26f8e4edcff358c0f9bf41ba7ceda507a1 100644 (file)
@@ -4,18 +4,8 @@
  * This file is released under the GPL.
  */
 
-#include "log.h"
-#include "archive.h"
-#include "dbg_malloc.h"
-#include "format-text.h"
-#include "lvm-string.h"
-#include "toollib.h"
-
 #include "tools.h"
 
-#include <unistd.h>
-#include <limits.h>
-
 static struct {
        int enabled;
        char *dir;
@@ -97,7 +87,7 @@ int archive(struct volume_group *vg)
                return 1;
 
        if (test_mode()) {
-               log_print("Test mode: Skipping archiving of volume group.");
+               log_verbose("Test mode: Skipping archiving of volume group.");
                return 1;
        }
 
@@ -113,7 +103,7 @@ int archive(struct volume_group *vg)
 
 int archive_display(struct cmd_context *cmd, const char *vg_name)
 {
-       return archive_list(cmd, cmd->um, _archive_params.dir, vg_name);
+       return archive_list(cmd, _archive_params.dir, vg_name);
 }
 
 static struct {
@@ -153,11 +143,8 @@ void backup_enable(int flag)
 
 static int __backup(struct volume_group *vg)
 {
-       int r;
-       struct format_instance *tf;
        char name[PATH_MAX];
        char *desc;
-       void *context;
 
        if (!(desc = _build_desc(vg->cmd->mem, vg->cmd->cmd_line, 0))) {
                stack;
@@ -173,20 +160,7 @@ static int __backup(struct volume_group *vg)
 
        log_verbose("Creating volume group backup \"%s\"", name);
 
-       if (!(context = create_text_context(vg->cmd->fmtt, name, desc)) ||
-           !(tf = vg->cmd->fmtt->ops->create_instance(vg->cmd->fmtt, NULL,
-                                                      context))) {
-               stack;
-               return 0;
-       }
-
-       if (!(r = tf->fmt->ops->vg_write(tf, vg, context)) ||
-           !(r = tf->fmt->ops->vg_commit(tf, vg, context)))
-               stack;
-
-       tf->fmt->ops->destroy_instance(tf);
-
-       return r;
+       return backup_to_file(name, desc, vg);
 }
 
 int backup(struct volume_group *vg)
@@ -197,7 +171,7 @@ int backup(struct volume_group *vg)
        }
 
        if (test_mode()) {
-               log_print("Test mode: Skipping volume group backup.");
+               log_verbose("Test mode: Skipping volume group backup.");
                return 1;
        }
 
@@ -227,57 +201,73 @@ int backup_remove(const char *vg_name)
        return 1;
 }
 
-static struct volume_group *_read_vg(struct cmd_context *cmd,
-                                    const char *vg_name, const char *file)
+struct volume_group *backup_read_vg(struct cmd_context *cmd,
+                                   const char *vg_name, const char *file)
 {
        struct volume_group *vg;
        struct format_instance *tf;
+       struct list *mdah;
+       struct metadata_area *mda;
        void *context;
 
-       if (!(context = create_text_context(cmd->fmtt, file,
+       if (!(context = create_text_context(cmd, file,
                                            cmd->cmd_line)) ||
-           !(tf = cmd->fmtt->ops->create_instance(cmd->fmtt, NULL, context))) {
+           !(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
+                                                        context))) {
                log_error("Couldn't create text format object.");
                return NULL;
        }
 
-       if (!(vg = tf->fmt->ops->vg_read(tf, vg_name, context)))
-               stack;
+       list_iterate(mdah, &tf->metadata_areas) {
+               mda = list_item(mdah, struct metadata_area);
+               if (!(vg = mda->ops->vg_read(tf, vg_name, mda)))
+                       stack;
+               break;
+       }
 
        tf->fmt->ops->destroy_instance(tf);
        return vg;
 }
 
-int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name,
-                            const char *file)
+/* ORPHAN and VG locks held before calling this */
+int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg)
 {
-       struct volume_group *vg;
+       struct list *pvh;
+       struct physical_volume *pv;
+       struct cache_info *info;
 
        /*
-        * Read in the volume group.
+        * FIXME: Check that the PVs referenced in the backup are
+        * not members of other existing VGs.
         */
-       if (!(vg = _read_vg(cmd, vg_name, file))) {
-               stack;
+
+       /* Attempt to write out using currently active format */
+       if (!(vg->fid = cmd->fmt->ops->create_instance(cmd->fmt, vg->name,
+                                                      NULL))) {
+               log_error("Failed to allocate format instance");
                return 0;
        }
 
-       /*
-        * Check that those pv's referenced in the backup are
-        * currently orphans or members of the vg.s
-        */
-       /*
-        * FIXME: waiting for label code.
-        */
-
-       /*
-        * Write the vg.
-        */
-
-       /* FIXME How do I find what format to write out the VG in? */
-       /* Must store the format type inside the backup? */
-       if (!(vg->fid = cmd->fmt1->ops->create_instance(cmd->fmt1, NULL, NULL))) {
-               log_error("Failed to allocate format1 instance");
-               return 0;
+       /* Add any metadata areas on the PVs */
+       list_iterate(pvh, &vg->pvs) {
+               pv = list_item(pvh, struct pv_list)->pv;
+               if (!(info = info_from_pvid(pv->dev->pvid))) {
+                       log_error("PV %s missing from cache",
+                                 dev_name(pv->dev));
+                       return 0;
+               }
+               if (cmd->fmt != info->fmt) {
+                       log_error("PV %s is a different format (%s)",
+                                 dev_name(pv->dev), info->fmt->name);
+                       return 0;
+               }
+               if (!vg->fid->fmt->ops->
+                   pv_setup(vg->fid->fmt, 0, 0, 0, 0, 0,
+                            &vg->fid->metadata_areas, pv, vg)) {
+                       log_error("Format-specific setup for %s failed",
+                                 dev_name(pv->dev));
+                       return 0;
+               }
        }
 
        if (!vg_write(vg)) {
@@ -288,6 +278,23 @@ int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name,
        return 1;
 }
 
+/* ORPHAN and VG locks held before calling this */
+int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name,
+                            const char *file)
+{
+       struct volume_group *vg;
+
+       /*
+        * Read in the volume group from the text file.
+        */
+       if (!(vg = backup_read_vg(cmd, vg_name, file))) {
+               stack;
+               return 0;
+       }
+
+       return backup_restore_vg(cmd, vg);
+}
+
 int backup_restore(struct cmd_context *cmd, const char *vg_name)
 {
        char path[PATH_MAX];
@@ -300,3 +307,38 @@ int backup_restore(struct cmd_context *cmd, const char *vg_name)
 
        return backup_restore_from_file(cmd, vg_name, path);
 }
+
+int backup_to_file(const char *file, const char *desc, struct volume_group *vg)
+{
+       int r;
+       struct format_instance *tf;
+       struct list *mdah;
+       struct metadata_area *mda;
+       void *context;
+       struct cmd_context *cmd;
+
+       cmd = vg->cmd;
+
+       if (!(context = create_text_context(cmd, file, desc)) ||
+           !(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
+                                                        context))) {
+               log_error("Couldn't create backup object.");
+               return 0;
+       }
+
+       /* Write and commit the metadata area */
+       list_iterate(mdah, &tf->metadata_areas) {
+               mda = list_item(mdah, struct metadata_area);
+               if (!(r = mda->ops->vg_write(tf, vg, mda))) {
+                       stack;
+                       continue;
+               }
+               if (mda->ops->vg_commit &&
+                   !(r = mda->ops->vg_commit(tf, vg, mda))) {
+                       stack;
+               }
+       }
+
+       tf->fmt->ops->destroy_instance(tf);
+       return r;
+}
index f0f34eb2583f07128d55d2fc8d5ce03b7f0967aa..157ae805f109cc43021771042043de10a79e53b1 100644 (file)
@@ -42,8 +42,13 @@ void backup_enable(int flag);
 int backup(struct volume_group *vg);
 int backup_remove(const char *vg_name);
 
+struct volume_group *backup_read_vg(struct cmd_context *cmd,
+                                   const char *vg_name, const char *file);
+int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg);
 int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name,
                             const char *file);
 int backup_restore(struct cmd_context *cmd, const char *vg_name);
 
+int backup_to_file(const char *file, const char *desc, struct volume_group *vg);
+
 #endif
index ecfb1d12c18bb4ac71f799889a49cc81f8ce1264..15d473499cb4882f35fac1809e11f257f835e90c 100644 (file)
@@ -12,6 +12,11 @@ arg(version_ARG, '\0', "version", NULL)
 arg(quiet_ARG, '\0', "quiet", NULL)
 arg(physicalvolumesize_ARG, '\0', "setphysicalvolumesize", size_arg)
 arg(ignorelockingfailure_ARG, '\0', "ignorelockingfailure", NULL)
+arg(metadatacopies_ARG, '\0', "metadatacopies", int_arg)
+arg(metadatasize_ARG, '\0', "metadatasize", size_arg)
+arg(restorefile_ARG, '\0', "restorefile", string_arg)
+arg(labelsector_ARG, '\0', "labelsector", int_arg)
+arg(driverloaded_ARG, '\0', "driverloaded", yes_no_arg)
 
 /* Allow some variations */
 arg(resizable_ARG, '\0', "resizable", yes_no_arg)
@@ -77,4 +82,3 @@ arg(zero_ARG, 'Z', "zero", yes_no_arg)
 
 /* this should always be last */
 arg(ARG_COUNT, '-', "", NULL)
-
index 672cb2f2212efe5015b8fbfa5a2b94a82d76d0e1..b2e4868c48a4797292edfe570e97e3f4b0ec9124 100644 (file)
  *
  */
 
+/***********  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"
index 59d5901cc91a2d3ff931078d123b464c6cec789e..24cc73d097dece4a1b5d3fdeb35ed556d74acb40 100644 (file)
 
 #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);
+}
index 3065806c8b83cda82fec293b2c00d34a311c1c23..59e9ed0adf98f0733cd6265b4170256a3e54751a 100644 (file)
@@ -90,7 +90,7 @@ static int _read_name_params(struct lvcreate_params *lp,
                        if (lp->lv_name && strchr(lp->lv_name, '/')) {
                                if (!(lp->vg_name =
                                      extract_vgname(cmd, lp->lv_name)))
-                                           return 0;
+                                       return 0;
 
                                if (strcmp(lp->vg_name, argv[0])) {
                                        log_error("Inconsistent volume group "
@@ -109,6 +109,13 @@ static int _read_name_params(struct lvcreate_params *lp,
        if (lp->lv_name && (ptr = strrchr(lp->lv_name, '/')))
                lp->lv_name = ptr + 1;
 
+       /* FIXME Remove this restriction eventually */
+       if (lp->lv_name && !strncmp(lp->lv_name, "snapshot", 8)) {
+               log_error("Names starting \"snapshot\" are reserved. "
+                         "Please choose a different LV name.");
+               return 0;
+       }
+
        return 1;
 }
 
@@ -312,20 +319,21 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
 {
        uint32_t size_rest;
        uint32_t status = 0;
-       alloc_policy_t alloc = ALLOC_NEXT_FREE;
+       alloc_policy_t alloc = ALLOC_DEFAULT;
        struct volume_group *vg;
        struct logical_volume *lv, *org;
        struct list *pvh;
+       int consistent = 1;
 
        if (lp->contiguous)
                alloc = ALLOC_CONTIGUOUS;
 
-       status |= lp->permission;
+       status |= lp->permission | VISIBLE_LV;
 
        /* does VG exist? */
        log_verbose("Finding volume group \"%s\"", lp->vg_name);
 
-       if (!(vg = vg_read(cmd, lp->vg_name))) {
+       if (!(vg = vg_read(cmd, lp->vg_name, &consistent))) {
                log_error("Volume group \"%s\" doesn't exist", lp->vg_name);
                return 0;
        }
@@ -391,20 +399,30 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
                lp->extents = lp->extents - size_rest + lp->stripes;
        }
 
-       if (lp->snapshot && !(org = find_lv(vg, lp->origin))) {
-               log_err("Couldn't find origin volume '%s'.", lp->origin);
+       if (!activation()) {
+               if (lp->snapshot)
+                       log_error("Can't create snapshot without using "
+                                 "device-mapper kernel driver");
                return 0;
        }
 
-       /*
-        * For now all logical volumes are visible.
-        */
-       status |= VISIBLE_LV;
-
+       if (lp->snapshot) {
+               if (!(org = find_lv(vg, lp->origin))) {
+                       log_err("Couldn't find origin volume '%s'.",
+                               lp->origin);
+                       return 0;
+               }
+               if (lv_is_cow(org)) {
+                       log_error("Snapshots of snapshots are not supported "
+                                 "yet.");
+                       return 0;
+               }
+       }
 
        if (!(lv = lv_create(vg->fid, lp->lv_name, status, alloc,
                             lp->stripes, lp->stripe_size, lp->extents,
-                            vg, pvh))) return 0;
+                            vg, pvh)))
+               return 0;
 
        if (lp->read_ahead) {
                log_verbose("Setting read ahead sectors");
@@ -421,16 +439,28 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
                return 0;
 
        /* store vg on disk(s) */
-       if (!vg_write(vg))
+       if (!vg_write(vg)) {
                return 0;
+       }
 
-       if (!lock_vol(cmd, lv->lvid.s, LCK_LV_ACTIVATE))
+       if (!lock_vol(cmd, lv->lvid.s, LCK_LV_ACTIVATE)) {
+               /* FIXME Remove the failed lv we just added */
+               log_error("Aborting. Failed to wipe snapshot "
+                         "exception store. Remove new LV and retry.");
                return 0;
+       }
 
-       if (lp->zero || lp->snapshot)
-               _zero_lv(cmd, lv);
-       else
-               log_print("WARNING: \"%s\" not zeroed", lv->name);
+       if ((lp->zero || lp->snapshot) && activation()) {
+               if (!_zero_lv(cmd, lv) && lp->snapshot) {
+                       /* FIXME Remove the failed lv we just added */
+                       log_error("Aborting. Failed to wipe snapshot "
+                                 "exception store. Remove new LV and retry.");
+                       return 0;
+               }
+       } else {
+               log_error("WARNING: \"%s\" not zeroed", lv->name);
+               /* FIXME Remove the failed lv we just added */
+       }
 
        if (lp->snapshot) {
                if (!lock_vol(cmd, lv->lvid.s, LCK_LV_DEACTIVATE)) {
@@ -443,7 +473,7 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
                        return 0;
                }
 
-               if (!vg_add_snapshot(org, lv, 1, lp->chunk_size)) {
+               if (!vg_add_snapshot(org, lv, 1, NULL, lp->chunk_size)) {
                        log_err("Couldn't create snapshot.");
                        return 0;
                }
@@ -480,9 +510,6 @@ int lvcreate(struct cmd_context *cmd, int argc, char **argv)
        if (!_read_params(&lp, cmd, argc, argv))
                return -EINVALID_CMD_LINE;
 
-       if (!driver_is_loaded())
-               return ECMD_FAILED;
-
        if (!lock_vol(cmd, lp.vg_name, LCK_VG_WRITE)) {
                log_error("Can't get lock for %s", lp.vg_name);
                return 0;
index d421327c0cf48e457c3e3c5c55fbfec66e691d4f..69971b1be19540ee43d0189ceecb3c2a11f26a9e 100644 (file)
 
 #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);
 }
index 366b906bc19eba4d97fca72942f13bdf33693539..526c1847a904cd47a7af64ab72df5129a7bc5c07 100644 (file)
@@ -5,9 +5,7 @@
  */
 
 #include "tools.h"
-#include "archive.h"
 #include "defaults.h"
-#include "lvm1_label.h"
 #include "label.h"
 #include "version.h"
 
 #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;
+}
index c573517abee4c90f9677d3f10188b31d6b6183fe..e65f80afaff7f53266a0cb8c632bf0d5f99e80f4 100644 (file)
@@ -29,7 +29,7 @@ int lvmdiskscan(struct cmd_context *cmd, int argc, char **argv)
        uint64_t size;
        struct dev_iter *iter;
        struct device *dev;
-       struct physical_volume *pv;
+       struct label *label;
 
        if (arg_count(cmd, lvmpartition_ARG))
                log_print("WARNING: only considering LVM devices");
@@ -44,7 +44,7 @@ int lvmdiskscan(struct cmd_context *cmd, int argc, char **argv)
        /* Do scan */
        for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter)) {
                /* Try if it is a PV first */
-               if ((pv = pv_read(cmd, dev_name(dev)))) {
+               if ((label_read(dev, &label))) {
                        if (!dev_get_size(dev, &size)) {
                                log_error("Couldn't get size of \"%s\"",
                                          dev_name(dev));
index 0e93866ec85ad5bb54325e3b3b005fa3f73e31e3..a41c1e59d4a40f80fefcb43e3c3b8b2d23812d15 100644 (file)
 
 #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);
+}
index e84e3c910fe3de94dafc5e2201d398270851a6c3..b061abd891e068a0153213e76b2c570d4ee5901d 100644 (file)
@@ -26,6 +26,7 @@ int lvrename(struct cmd_context *cmd, int argc, char **argv)
        char *lv_name_old, *lv_name_new;
        char *vg_name, *vg_name_new, *vg_name_old;
        char *st;
+       int consistent = 1;
 
        struct volume_group *vg;
        struct logical_volume *lv;
@@ -53,7 +54,7 @@ int lvrename(struct cmd_context *cmd, int argc, char **argv)
                return EINVALID_CMD_LINE;
        }
 
-       if (!is_valid_chars(vg_name)) {
+       if (!validate_vgname(vg_name)) {
                log_error("Please provide a valid volume group name");
                return EINVALID_CMD_LINE;
        }
@@ -86,7 +87,14 @@ int lvrename(struct cmd_context *cmd, int argc, char **argv)
                return ECMD_FAILED;
        }
 
-       if (!is_valid_chars(lv_name_new)) {
+       /* FIXME Remove this restriction eventually */
+       if (!strncmp(lv_name_new, "snapshot", 8)) {
+               log_error("Names starting \"snapshot\" are reserved. "
+                         "Please choose a different LV name.");
+               return ECMD_FAILED;
+       }
+
+       if (!validate_vgname(lv_name_new)) {
                log_error
                    ("New logical volume name \"%s\" has invalid characters",
                     lv_name_new);
@@ -98,9 +106,6 @@ int lvrename(struct cmd_context *cmd, int argc, char **argv)
                return EINVALID_CMD_LINE;
        }
 
-       if (!driver_is_loaded())
-               return ECMD_FAILED;
-
        log_verbose("Checking for existing volume group \"%s\"", vg_name);
 
        if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) {
@@ -108,7 +113,7 @@ int lvrename(struct cmd_context *cmd, int argc, char **argv)
                return ECMD_FAILED;
        }
 
-       if (!(vg = vg_read(cmd, vg_name))) {
+       if (!(vg = vg_read(cmd, vg_name, &consistent))) {
                log_error("Volume group \"%s\" doesn't exist", vg_name);
                goto error;
        }
index 974c29b837f9d8fc32725a8022190d3ca93ec495..b058d8f513a6746d7bb820bd54013f414d803067 100644 (file)
@@ -39,6 +39,7 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv)
        struct list *pvh, *segh;
        struct lv_list *lvl;
        int opt = 0;
+       int consistent = 1;
 
        enum {
                LV_ANY = 0,
@@ -94,9 +95,6 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv)
        if ((st = strrchr(lv_name, '/')))
                lv_name = st + 1;
 
-       if (!driver_is_loaded())
-               return ECMD_FAILED;
-
        /* does VG exist? */
        log_verbose("Finding volume group %s", vg_name);
        if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) {
@@ -104,7 +102,7 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv)
                return ECMD_FAILED;
        }
 
-       if (!(vg = vg_read(cmd, vg_name))) {
+       if (!(vg = vg_read(cmd, vg_name, &consistent))) {
                log_error("Volume group %s doesn't exist", vg_name);
                goto error;
        }
@@ -193,10 +191,10 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv)
        if (extents > lv->le_count &&
            !(stripes == 1 || (stripes > 1 && stripesize))) {
                list_iterate(segh, &lv->segments) {
-                       struct stripe_segment *seg;
+                       struct lv_segment *seg;
                        uint32_t sz, str;
 
-                       seg = list_item(segh, struct stripe_segment);
+                       seg = list_item(segh, struct lv_segment);
                        sz = seg->stripe_size;
                        str = seg->stripes;
 
@@ -237,10 +235,10 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv)
                                  "when reducing");
 
                list_iterate(segh, &lv->segments) {
-                       struct stripe_segment *seg;
+                       struct lv_segment *seg;
                        uint32_t seg_extents;
 
-                       seg = list_item(segh, struct stripe_segment);
+                       seg = list_item(segh, struct lv_segment);
                        seg_extents = seg->len;
 
                        seg_stripesize = seg->stripe_size;
@@ -261,7 +259,7 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv)
                log_error("Stripesize for striped segment should not be 0!");
                goto error_cmdline;
        }
-       
+
        if ((stripes > 1)) {
                if (!(stripesize_extents = stripesize / vg->extent_size))
                        stripesize_extents = 1;
index 044e2e6ba6346dca0e8f3647ccd2de4565b62c3b..d0449288ad682c036f7cf09a354d5c591ebd90cc 100644 (file)
 
 #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);
+}
index b509f007c2a856477c8d238c38c4cc7b95116f1b..189c94d330fcb61a30dd916f236824b7450154ec 100644 (file)
 
 #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;
+}
index 0cc1d95fa6e8cdc3f8ab9182cb49ba48dca86560..7ca11ede1b22173691587f762370e6584781769f 100644 (file)
@@ -19,6 +19,7 @@
  */
 
 #include "tools.h"
+#include "defaults.h"
 
 const char _really_init[] =
     "Really INITIALIZE physical volume \"%s\" of volume group \"%s\" [y/n]? ";
@@ -39,7 +40,7 @@ static int pvcreate_check(struct cmd_context *cmd, const char *name)
        }
 
        /* is there a pv here already */
-       if (!(pv = pv_read(cmd, name)))
+       if (!(pv = pv_read(cmd, name, NULL, NULL)))
                return 1;
 
        /* orphan ? */
@@ -72,20 +73,28 @@ static int pvcreate_check(struct cmd_context *cmd, const char *name)
        return 1;
 }
 
-static void pvcreate_single(struct cmd_context *cmd, const char *pv_name)
+static void pvcreate_single(struct cmd_context *cmd, const char *pv_name,
+                           void *handle)
 {
-       struct physical_volume *pv;
-       struct format_instance *fid;
+       struct physical_volume *pv, *existing_pv;
        struct id id, *idp = NULL;
        char *uuid;
        uint64_t size = 0;
        struct device *dev;
+       struct list mdas;
+       int pvmetadatacopies;
+       uint64_t pvmetadatasize;
+       struct volume_group *vg;
+       char *restorefile;
+       uint64_t pe_start = 0;
+       uint32_t extent_count = 0, extent_size = 0;
 
        if (arg_count(cmd, uuidstr_ARG)) {
                uuid = arg_str_value(cmd, uuidstr_ARG, "");
                if (!id_read_format(&id, uuid))
                        return;
-               if ((dev = uuid_map_lookup(cmd->um, &id))) {
+               if ((dev = device_from_pvid(cmd, &id)) &&
+                   (dev != dev_cache_get(pv_name, cmd->filter))) {
                        log_error("uuid %s already in use on \"%s\"", uuid,
                                  dev_name(dev));
                        return;
@@ -93,32 +102,84 @@ static void pvcreate_single(struct cmd_context *cmd, const char *pv_name)
                idp = &id;
        }
 
-       if (!pvcreate_check(cmd, pv_name))
+       if (arg_count(cmd, restorefile_ARG)) {
+               restorefile = arg_str_value(cmd, restorefile_ARG, "");
+               /* The uuid won't already exist */
+               init_partial(1);
+               if (!(vg = backup_read_vg(cmd, NULL, restorefile))) {
+                       log_error("Unable to read volume group from %s",
+                                 restorefile);
+                       return;
+               }
+               init_partial(0);
+               if (!(existing_pv = find_pv_in_vg_by_uuid(vg, idp))) {
+                       log_error("Can't find uuid %s in backup file %s",
+                                 uuid, restorefile);
+                       return;
+               }
+               pe_start = existing_pv->pe_start;
+               extent_size = existing_pv->pe_size;
+               extent_count = existing_pv->pe_count;
+       }
+
+       if (!lock_vol(cmd, "", LCK_VG_WRITE)) {
+               log_error("Can't get lock for orphan PVs");
                return;
+       }
+
+       if (!pvcreate_check(cmd, pv_name))
+               goto error;
 
        size = arg_int64_value(cmd, physicalvolumesize_ARG, 0) * 2;
 
-       /* FIXME Use config file/cmd line to specify format */
-       if (!(fid = cmd->fmt1->ops->create_instance(cmd->fmt1, NULL, NULL))) {
-               log_error("Failed to create format1 instance");
-               return;
+       pvmetadatasize = arg_int64_value(cmd, metadatasize_ARG, 0) * 2;
+       if (!pvmetadatasize)
+               pvmetadatasize = find_config_int(cmd->cf->root,
+                                                "metadata/pvmetadatasize",
+                                                '/', DEFAULT_PVMETADATASIZE);
+
+       pvmetadatacopies = arg_int_value(cmd, metadatacopies_ARG, -1);
+       if (pvmetadatacopies < 0)
+               pvmetadatacopies = find_config_int(cmd->cf->root,
+                                                  "metadata/pvmetadatacopies",
+                                                  '/',
+                                                  DEFAULT_PVMETADATACOPIES);
+
+       if (!(dev = dev_cache_get(pv_name, cmd->filter))) {
+               log_error("%s: Couldn't find device.", pv_name);
+               goto error;
        }
-       if (!(pv = pv_create(fid, pv_name, idp, size))) {
+
+       list_init(&mdas);
+       if (!(pv = pv_create(cmd->fmt, dev, idp, size, pe_start,
+                            extent_count, extent_size,
+                            pvmetadatacopies, pvmetadatasize, &mdas))) {
                log_error("Failed to setup physical volume \"%s\"", pv_name);
-               return;
+               goto error;
        }
 
        log_verbose("Set up physical volume for \"%s\" with %" PRIu64
-                   " sectors", pv_name, pv->size);
+                   " available sectors", pv_name, pv->size);
+
+       /* Wipe existing label first */
+       if (!label_remove(pv->dev)) {
+               log_error("Failed to wipe existing label on %s", pv_name);
+               goto error;
+       }
 
        log_very_verbose("Writing physical volume data to disk \"%s\"",
                         pv_name);
-       if (!(pv_write(cmd, pv))) {
+       if (!(pv_write(cmd, pv, &mdas, arg_int_value(cmd, labelsector_ARG,
+                                                    DEFAULT_LABELSECTOR)))) {
                log_error("Failed to write physical volume \"%s\"", pv_name);
-               return;
+               goto error;
        }
 
        log_print("Physical volume \"%s\" successfully created", pv_name);
+
+      error:
+       unlock_vg(cmd, "");
+       return;
 }
 
 int pvcreate(struct cmd_context *cmd, int argc, char **argv)
@@ -130,6 +191,11 @@ int pvcreate(struct cmd_context *cmd, int argc, char **argv)
                return EINVALID_CMD_LINE;
        }
 
+       if (arg_count(cmd, restorefile_ARG) && !arg_count(cmd, uuidstr_ARG)) {
+               log_error("--uuid is required with --restorefile");
+               return EINVALID_CMD_LINE;
+       }
+
        if (arg_count(cmd, uuidstr_ARG) && argc != 1) {
                log_error("Can only set uuid on one volume at once");
                return EINVALID_CMD_LINE;
@@ -140,8 +206,27 @@ int pvcreate(struct cmd_context *cmd, int argc, char **argv)
                return EINVALID_CMD_LINE;
        }
 
+       if (arg_int_value(cmd, labelsector_ARG, 0) >= LABEL_SCAN_SECTORS) {
+               log_error("labelsector must be less than %lu",
+                         LABEL_SCAN_SECTORS);
+               return EINVALID_CMD_LINE;
+       }
+
+       if (!(cmd->fmt->features & FMT_MDAS) &&
+           (arg_count(cmd, metadatacopies_ARG) ||
+            arg_count(cmd, metadatasize_ARG))) {
+               log_error("Metadata parameters only apply to text format");
+               return EINVALID_CMD_LINE;
+       }
+
+       if (arg_count(cmd, metadatacopies_ARG) &&
+           arg_int_value(cmd, metadatacopies_ARG, -1) > 2) {
+               log_error("Metadatacopies may only be 0, 1 or 2");
+               return EINVALID_CMD_LINE;
+       }
+
        for (i = 0; i < argc; i++) {
-               pvcreate_single(cmd, argv[i]);
+               pvcreate_single(cmd, argv[i], NULL);
                pool_empty(cmd->mem);
        }
 
index b526cc9bc36b6102510128f29826f67ff1a7e77f..ff4d121a1218b5e95df37838177206e60a7fd633 100644 (file)
 
 #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 (file)
index 0000000..3410378
--- /dev/null
@@ -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;
+}
index 868dea4738c0d4ac8f845b7104d177fc2a774697..3f3b2f1ba52273a27365c311500e0222906bab69 100644 (file)
 
 #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;
-}
index 185535c077fb8854517a6bad9cbc98ce34ea6ded..8ffefe134cac54d78f0ed68b69204a978ea755d0 100644 (file)
@@ -6,10 +6,10 @@
 
 #define unimplemented \
        { log_error("Command not implemented yet."); return ECMD_FAILED;}
+/*int e2fsadm(struct cmd_context *cmd, int argc, char **argv) unimplemented*/
 int lvmsadc(struct cmd_context *cmd, int argc, char **argv) unimplemented
 int lvmsar(struct cmd_context *cmd, int argc, char **argv) unimplemented
 int pvdata(struct cmd_context *cmd, int argc, char **argv) unimplemented
 int pvmove(struct cmd_context *cmd, int argc, char **argv) unimplemented
 int pvresize(struct cmd_context *cmd, int argc, char **argv) unimplemented
 int vgmknodes(struct cmd_context *cmd, int argc, char **argv) unimplemented
-
index 9b628ab05c4d91eb89052ee31370e552d6190666..917b4ff05f3d68004bc8aa4cf03d9a242842cb8d 100644 (file)
@@ -9,8 +9,10 @@
 #include <sys/stat.h>
 
 int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
+                         void *handle,
                          int (*process_single) (struct cmd_context * cmd,
-                                                struct logical_volume * lv))
+                                                struct logical_volume * lv,
+                                                void *handle))
 {
        int ret_max = 0;
        int ret = 0;
@@ -25,7 +27,7 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
 
        list_iterate(lvh, &vg->lvs) {
                lv = list_item(lvh, struct lv_list)->lv;
-               ret = process_single(cmd, lv);
+               ret = process_single(cmd, lv, handle);
                if (ret > ret_max)
                        ret_max = ret;
        }
@@ -34,94 +36,163 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
 
 }
 
+struct volume_group *recover_vg(struct cmd_context *cmd, const char *vgname,
+                               int lock_type)
+{
+       int consistent = 1;
+
+       lock_type &= ~LCK_TYPE_MASK;
+       lock_type |= LCK_WRITE;
+
+       if (!lock_vol(cmd, vgname, lock_type)) {
+               log_error("Can't lock %s for metadata recovery: skipping",
+                         vgname);
+               return NULL;
+       }
+
+       return vg_read(cmd, vgname, &consistent);
+}
+
 int process_each_lv(struct cmd_context *cmd, int argc, char **argv,
-                   int lock_type,
+                   int lock_type, void *handle,
                    int (*process_single) (struct cmd_context * cmd,
-                                          struct logical_volume * lv))
+                                          struct logical_volume * lv,
+                                          void *handle))
 {
        int opt = 0;
        int ret_max = 0;
        int ret = 0;
        int vg_count = 0;
+       int consistent;
 
-       struct list *vgh, *vgs;
+       struct list *slh, *vgnames;
        struct volume_group *vg;
        struct logical_volume *lv;
        struct lv_list *lvl;
 
-       char *vg_name;
+       char *vgname;
 
        if (argc) {
                log_verbose("Using logical volume(s) on command line");
                for (; opt < argc; opt++) {
                        char *lv_name = argv[opt];
-
-                       /* 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;
index 49f06fbeaf49668228f3134491888f9cf1b3aa58..8b5ef7ed7dd2680641170fbb50d21a653ba8b593 100644 (file)
@@ -29,30 +29,42 @@ int autobackup_init(const char *backup_dir, int keep_days, int keep_number,
                    int autobackup);
 int autobackup(struct volume_group *vg);
 
+struct volume_group *recover_vg(struct cmd_context *cmd, const char *vgname,
+                               int lock_type);
+
 int process_each_vg(struct cmd_context *cmd, int argc, char **argv,
-                   int lock_type,
+                   int lock_type, int consistent, void *handle,
                    int (*process_single) (struct cmd_context * cmd,
-                                          const char *vg_name));
+                                          const char *vg_name,
+                                          struct volume_group *vg,
+                                          int consistent,
+                                          void *handle));
 
 int process_each_pv(struct cmd_context *cmd, int argc, char **argv,
-                   struct volume_group *vg,
+                   struct volume_group *vg, void *handle,
                    int (*process_single) (struct cmd_context * cmd,
                                           struct volume_group * vg,
-                                          struct physical_volume * pv));
+                                          struct physical_volume * pv,
+                                          void *handle));
+
 int process_each_lv(struct cmd_context *cmd, int argc, char **argv,
-                   int lock_type,
+                   int lock_type, void *handle,
                    int (*process_single) (struct cmd_context * cmd,
-                                          struct logical_volume * lv));
+                                          struct logical_volume * lv,
+                                          void *handle));
 
 int process_each_pv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
+                         void *handle,
                          int (*process_single) (struct cmd_context * cmd,
                                                 struct volume_group * vg,
-                                                struct physical_volume * pv));
+                                                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);
index cd148967f4f7c0ff715bb507303acb3e9950932a..2f253204f745d92a37cd5cc49fa433a88d6e01d8 100644 (file)
@@ -7,39 +7,40 @@
 #ifndef _LVM_TOOLS_H
 #define _LVM_TOOLS_H
 
-#include "pool.h"
-#include "dbg_malloc.h"
-#include "list.h"
-#include "log.h"
-#include "lvm-string.h"
-#include "lvm-file.h"
-#include "metadata.h"
+#define _GNU_SOURCE
+
+#include "activate.h"
+#include "archive.h"
+#include "cache.h"
 #include "config.h"
+#include "dbg_malloc.h"
 #include "dev-cache.h"
 #include "device.h"
-#include "vgcache.h"
 #include "display.h"
 #include "errors.h"
 #include "filter.h"
-#include "filter-persistent.h"
 #include "filter-composite.h"
+#include "filter-persistent.h"
 #include "filter-regex.h"
-#include "format1.h"
 #include "format-text.h"
-#include "toollib.h"
-#include "activate.h"
-#include "archive.h"
+#include "metadata.h"
+#include "list.h"
 #include "locking.h"
+#include "log.h"
+#include "lvm-file.h"
+#include "lvm-string.h"
+#include "pool.h"
 #include "toolcontext.h"
+#include "toollib.h"
 
-#include <stdio.h>
+#include <ctype.h>
+#include <limits.h>
 #include <stdarg.h>
+#include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 #include <sys/types.h>
-#include <ctype.h>
-#include <string.h>
-#include <limits.h>
 
 #define CMD_LEN 256
 #define MAX_ARGS 64
@@ -68,7 +69,7 @@ typedef enum {
 struct arg {
        char short_arg;
        char *long_arg;
-       int (*fn) (struct arg * a);
+       int (*fn) (struct cmd_context * cmd, struct arg * a);
 
        int count;
        char *value;
@@ -92,14 +93,14 @@ struct command {
 void usage(const char *name);
 
 /* the argument verify/normalise functions */
-int yes_no_arg(struct arg *a);
-int size_arg(struct arg *a);
-int int_arg(struct arg *a);
-int int_arg_with_sign(struct arg *a);
-int minor_arg(struct arg *a);
-int string_arg(struct arg *a);
-int permission_arg(struct arg *a);
-int metadatatype_arg(struct arg *a);
+int yes_no_arg(struct cmd_context *cmd, struct arg *a);
+int size_arg(struct cmd_context *cmd, struct arg *a);
+int int_arg(struct cmd_context *cmd, struct arg *a);
+int int_arg_with_sign(struct cmd_context *cmd, struct arg *a);
+int minor_arg(struct cmd_context *cmd, struct arg *a);
+int string_arg(struct cmd_context *cmd, struct arg *a);
+int permission_arg(struct cmd_context *cmd, struct arg *a);
+int metadatatype_arg(struct cmd_context *cmd, struct arg *a);
 
 char yes_no_prompt(const char *prompt, ...);
 
@@ -151,13 +152,4 @@ static inline const char *command_name(struct cmd_context *cmd)
        return cmd->command->name;
 }
 
-static inline int driver_is_loaded(void)
-{
-       int i = driver_version(NULL, 0);
-
-       if (!i)
-               log_error("device-mapper driver/module not loaded?");
-       return i;
-}
-
 #endif
index a78015894d7fcb2d2fd8bd73c21a334316dfea40..46f90ec633084b2453a9d69a9173194c2a85a62e 100644 (file)
@@ -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);
 }
index fe49781661bfde7b1160a136671f987cf36b58c3..2c38ed6430fc948e02cd4ae376a436b82394b4ac 100644 (file)
@@ -13,9 +13,6 @@ int vgcfgrestore(struct cmd_context *cmd, int argc, char **argv)
                return ECMD_FAILED;
        }
 
-       if (!driver_is_loaded())
-               return ECMD_FAILED;     
-
        /*
         * FIXME: overloading the -l arg for now to display a
         * list of archive files for a particular vg
@@ -27,13 +24,28 @@ int vgcfgrestore(struct cmd_context *cmd, int argc, char **argv)
                return 0;
        }
 
+       if (!lock_vol(cmd, ORPHAN, LCK_VG_WRITE)) {
+               log_error("Unable to lock orphans");
+               return ECMD_FAILED;
+       }
+
+       if (!lock_vol(cmd, argv[0], LCK_VG_WRITE | LCK_NONBLOCK)) {
+               log_error("Unable to lock volume group %s", argv[0]);
+               unlock_vg(cmd, ORPHAN);
+               return ECMD_FAILED;
+       }
+
        if (!(arg_count(cmd, file_ARG) ?
              backup_restore_from_file(cmd, argv[0],
                                       arg_str_value(cmd, file_ARG, "")) :
              backup_restore(cmd, argv[0]))) {
+               unlock_vg(cmd, argv[0]);
+               unlock_vg(cmd, ORPHAN);
                log_err("Restore failed.");
                return ECMD_FAILED;
        }
 
+       unlock_vg(cmd, argv[0]);
+       unlock_vg(cmd, ORPHAN);
        return 0;
 }
index 3165ba884e8c7554b5d3412810e6b7f10902b2a3..9579bef365df02279e57660ff762a55fb0357266 100644 (file)
 
 #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);
+}
index e90f531716f6e44c3ef595ca606bad5681034159..6a6eb1ec721dc16852da170e5a7cc223e3144316 100644 (file)
 
 #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 (file)
index 0000000..91bd888
--- /dev/null
@@ -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);
+}
index 7c092e0b0fb6daf708514f95e1618243a8a93a8b..23a8389ca834c375a000b9d7bdea0e959c208a9c 100644 (file)
@@ -73,15 +73,12 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
                return ECMD_FAILED;
        }
 
-       if (!is_valid_chars(vg_name)) {
+       if (!validate_vgname(vg_name)) {
                log_error("New volume group name \"%s\" has invalid characters",
                          vg_name);
                return ECMD_FAILED;
        }
 
-       if (!driver_is_loaded())
-               return ECMD_FAILED;     
-
        /* Create the new VG */
        if (!(vg = vg_create(cmd, vg_name, extent_size, max_pv, max_lv,
                             argc - 1, argv + 1)))
index 13f3011207e56feec9c39ddea9c57168c3ac79c7..72bc3b3888c8305b2db11b4433d0e305491f8f8d 100644 (file)
 
 #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;
-}
index 50fe605fcd19320d131bd59c58e4ef5b5285e424..5e521f0152cf05213310583961c4e4fda5d61eaa 100644 (file)
 
 #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);
+}
index 6b5adb9a621c3b5a3c19eb79e44d707cd28832ad..0cb9f073150a1fc2cf1d2b89bea03241d168ee0d 100644 (file)
@@ -24,6 +24,7 @@ int vgextend(struct cmd_context *cmd, int argc, char **argv)
 {
        char *vg_name;
        struct volume_group *vg = NULL;
+       int consistent = 1;
 
        if (!argc) {
                log_error("Please enter volume group name and "
@@ -36,9 +37,6 @@ int vgextend(struct cmd_context *cmd, int argc, char **argv)
                return EINVALID_CMD_LINE;
        }
 
-       if (!driver_is_loaded())
-               return ECMD_FAILED;     
-
        vg_name = argv[0];
        argc--;
        argv++;
@@ -55,7 +53,7 @@ int vgextend(struct cmd_context *cmd, int argc, char **argv)
                goto error;
        }
 
-       if (!(vg = vg_read(cmd, vg_name))) {
+       if (!(vg = vg_read(cmd, vg_name, &consistent)) || !consistent) {
                log_error("Volume group \"%s\" not found.", vg_name);
                goto error;
        }
index bb72d7a70e8dbc8f327f6ba5c716f03db1c210ee..d515caadae19c8b14b39a269d9865520e05c3336 100644 (file)
 
 #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);
+}
index 8d6e7b4440167c7a31b71fd197053b5d84c8f40f..6a705658fe01f055e22e26238368b9c41edcfe45 100644 (file)
 
 #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;
+}
index b2bd476bed6da5d5db74f1c886f05a36661d26e3..a085573142294e90948c02d29d868dca81041190 100644 (file)
 
 #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;
-}
index 018976f73a4eba0cd86c6913a35cdbad84fb8e5c..14a0fcf370d560b3d05b009f1a9bbcfc110e4481 100644 (file)
 
 #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;
+}
index 4ec3d9855a7c629158589d99455a62f641067219..50c0451218d333bb49793922f10dd50249e98747 100644 (file)
@@ -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;}
-
-**********************/
index 504f534784ff6d79f04403e9b2f277ca33f9fb04..0af067d79bdfd63c207ed26eb06832934a19bb3d 100644 (file)
 
 #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);
 }
index baa7d2e5b03ad9a2c46bd7400153939dbb642303..00a77ff15ecca88945a858c1d8908a0a51f9dd8b 100644 (file)
@@ -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))
This page took 0.468192 seconds and 5 git commands to generate.