r413 - in lvm2/upstream/current: . daemons/clvmd dmeventd/mirror doc lib/activate lib/cache lib/commands lib/config lib/device lib/display lib/error lib/filters lib/format1 lib/format_pool lib/format_text lib/label lib/locking lib/log lib/metadata lib/mirror lib/misc lib/report lib/snapshot lib/striped lib/zero man scripts scripts/lvm2create_initrd tools tools/fsadm

Bastian Blank waldi at alioth.debian.org
Sat Apr 7 15:30:46 UTC 2007


Author: waldi
Date: Sat Apr  7 15:30:42 2007
New Revision: 413

Added:
   lvm2/upstream/current/man/lvmdump.8
   lvm2/upstream/current/scripts/Makefile.in
   lvm2/upstream/current/scripts/lvm2_monitoring_init_rhel4
Modified:
   lvm2/upstream/current/Makefile.in
   lvm2/upstream/current/VERSION
   lvm2/upstream/current/WHATS_NEW
   lvm2/upstream/current/configure
   lvm2/upstream/current/configure.in
   lvm2/upstream/current/daemons/clvmd/Makefile.in
   lvm2/upstream/current/daemons/clvmd/clvmd-command.c
   lvm2/upstream/current/daemons/clvmd/clvmd-gulm.c
   lvm2/upstream/current/daemons/clvmd/clvmd-gulm.h
   lvm2/upstream/current/daemons/clvmd/clvmd.c
   lvm2/upstream/current/daemons/clvmd/clvmd.h
   lvm2/upstream/current/daemons/clvmd/lvm-functions.c
   lvm2/upstream/current/daemons/clvmd/refresh_clvmd.c
   lvm2/upstream/current/dmeventd/mirror/dmeventd_mirror.c
   lvm2/upstream/current/doc/example.conf
   lvm2/upstream/current/lib/activate/activate.c
   lvm2/upstream/current/lib/activate/activate.h
   lvm2/upstream/current/lib/activate/dev_manager.c
   lvm2/upstream/current/lib/cache/lvmcache.c
   lvm2/upstream/current/lib/commands/toolcontext.c
   lvm2/upstream/current/lib/commands/toolcontext.h
   lvm2/upstream/current/lib/config/config.c
   lvm2/upstream/current/lib/config/config.h
   lvm2/upstream/current/lib/config/defaults.h
   lvm2/upstream/current/lib/device/dev-io.c
   lvm2/upstream/current/lib/device/dev-md.c
   lvm2/upstream/current/lib/device/device.c
   lvm2/upstream/current/lib/display/display.c
   lvm2/upstream/current/lib/error/errseg.c
   lvm2/upstream/current/lib/filters/filter-persistent.c
   lvm2/upstream/current/lib/filters/filter-persistent.h
   lvm2/upstream/current/lib/filters/filter-sysfs.c
   lvm2/upstream/current/lib/filters/filter.c
   lvm2/upstream/current/lib/format1/disk-rep.c
   lvm2/upstream/current/lib/format1/disk-rep.h
   lvm2/upstream/current/lib/format1/format1.c
   lvm2/upstream/current/lib/format1/import-export.c
   lvm2/upstream/current/lib/format1/import-extents.c
   lvm2/upstream/current/lib/format1/lvm1-label.c
   lvm2/upstream/current/lib/format_pool/disk_rep.c
   lvm2/upstream/current/lib/format_pool/disk_rep.h
   lvm2/upstream/current/lib/format_pool/pool_label.c
   lvm2/upstream/current/lib/format_text/archive.c
   lvm2/upstream/current/lib/format_text/export.c
   lvm2/upstream/current/lib/format_text/format-text.c
   lvm2/upstream/current/lib/format_text/import.c
   lvm2/upstream/current/lib/format_text/import_vsn1.c
   lvm2/upstream/current/lib/format_text/text_label.c
   lvm2/upstream/current/lib/label/label.c
   lvm2/upstream/current/lib/label/label.h
   lvm2/upstream/current/lib/locking/cluster_locking.c
   lvm2/upstream/current/lib/locking/file_locking.c
   lvm2/upstream/current/lib/locking/locking.c
   lvm2/upstream/current/lib/locking/locking.h
   lvm2/upstream/current/lib/locking/no_locking.c
   lvm2/upstream/current/lib/log/log.c
   lvm2/upstream/current/lib/log/log.h
   lvm2/upstream/current/lib/metadata/lv_manip.c
   lvm2/upstream/current/lib/metadata/metadata.c
   lvm2/upstream/current/lib/metadata/metadata.h
   lvm2/upstream/current/lib/metadata/mirror.c
   lvm2/upstream/current/lib/metadata/pv_map.c
   lvm2/upstream/current/lib/metadata/pv_map.h
   lvm2/upstream/current/lib/metadata/segtype.h
   lvm2/upstream/current/lib/mirror/mirrored.c
   lvm2/upstream/current/lib/misc/lvm-file.c
   lvm2/upstream/current/lib/misc/lvm-file.h
   lvm2/upstream/current/lib/report/columns.h
   lvm2/upstream/current/lib/report/report.c
   lvm2/upstream/current/lib/snapshot/snapshot.c
   lvm2/upstream/current/lib/striped/striped.c
   lvm2/upstream/current/lib/zero/zero.c
   lvm2/upstream/current/make.tmpl.in
   lvm2/upstream/current/man/Makefile.in
   lvm2/upstream/current/man/clvmd.8
   lvm2/upstream/current/man/lvchange.8
   lvm2/upstream/current/man/lvconvert.8
   lvm2/upstream/current/man/lvcreate.8
   lvm2/upstream/current/man/lvextend.8
   lvm2/upstream/current/man/lvm.conf.5
   lvm2/upstream/current/man/lvreduce.8
   lvm2/upstream/current/man/lvremove.8
   lvm2/upstream/current/man/lvresize.8
   lvm2/upstream/current/man/lvs.8
   lvm2/upstream/current/man/pvmove.8
   lvm2/upstream/current/man/pvs.8
   lvm2/upstream/current/man/vgchange.8
   lvm2/upstream/current/man/vgcreate.8
   lvm2/upstream/current/man/vgs.8
   lvm2/upstream/current/scripts/clvmd_init_rhel4
   lvm2/upstream/current/scripts/lvm2create_initrd/lvm2create_initrd
   lvm2/upstream/current/scripts/lvm_dump.sh
   lvm2/upstream/current/tools/Makefile.in
   lvm2/upstream/current/tools/args.h
   lvm2/upstream/current/tools/commands.h
   lvm2/upstream/current/tools/dumpconfig.c
   lvm2/upstream/current/tools/fsadm/Makefile.in
   lvm2/upstream/current/tools/lvchange.c
   lvm2/upstream/current/tools/lvconvert.c
   lvm2/upstream/current/tools/lvcreate.c
   lvm2/upstream/current/tools/lvm-static.c
   lvm2/upstream/current/tools/lvm.c
   lvm2/upstream/current/tools/lvm2cmdline.h
   lvm2/upstream/current/tools/lvmcmdlib.c
   lvm2/upstream/current/tools/lvmcmdline.c
   lvm2/upstream/current/tools/lvremove.c
   lvm2/upstream/current/tools/lvrename.c
   lvm2/upstream/current/tools/pvchange.c
   lvm2/upstream/current/tools/pvmove.c
   lvm2/upstream/current/tools/pvremove.c
   lvm2/upstream/current/tools/pvscan.c
   lvm2/upstream/current/tools/reporter.c
   lvm2/upstream/current/tools/toollib.c
   lvm2/upstream/current/tools/toollib.h
   lvm2/upstream/current/tools/vgcfgrestore.c
   lvm2/upstream/current/tools/vgchange.c
   lvm2/upstream/current/tools/vgcreate.c
   lvm2/upstream/current/tools/vgextend.c
   lvm2/upstream/current/tools/vgmerge.c
   lvm2/upstream/current/tools/vgreduce.c
   lvm2/upstream/current/tools/vgremove.c
   lvm2/upstream/current/tools/vgrename.c
   lvm2/upstream/current/tools/vgsplit.c
Log:
Load into /lvm2/upstream/current.


Modified: lvm2/upstream/current/Makefile.in
==============================================================================
--- lvm2/upstream/current/Makefile.in	(original)
+++ lvm2/upstream/current/Makefile.in	Sat Apr  7 15:30:42 2007
@@ -16,7 +16,7 @@
 top_srcdir = @top_srcdir@
 VPATH = @srcdir@
 
-SUBDIRS = doc include man 
+SUBDIRS = doc include man scripts
 
 ifeq ("@INTL@", "yes")
   SUBDIRS += po

Modified: lvm2/upstream/current/VERSION
==============================================================================
--- lvm2/upstream/current/VERSION	(original)
+++ lvm2/upstream/current/VERSION	Sat Apr  7 15:30:42 2007
@@ -1 +1 @@
-2.02.12 (2006-10-16)
+2.02.24 (2007-03-19)

Modified: lvm2/upstream/current/WHATS_NEW
==============================================================================
--- lvm2/upstream/current/WHATS_NEW	(original)
+++ lvm2/upstream/current/WHATS_NEW	Sat Apr  7 15:30:42 2007
@@ -1,3 +1,153 @@
+Version 2.02.24 - 19th March 2007
+=================================
+  Fix processing of exit status in init scripts
+  Fix vgremove to require at least one vg argument.
+  Fix reading of striped LVs in LVM1 format.
+  Flag nolocking as clustered so clvmd startup sees clustered LVs. (2.02.10)
+  Add a few missing pieces of vgname command line validation.
+  Support the /dev/mapper prefix on most command lines.
+
+Version 2.02.23 - 8th March 2007
+================================
+  Fix vgrename active LV check to ignore differing vgids.
+  Remove no-longer-used uuid_out parameter from activation info functions.
+  Fix two more segfaults if an empty config file section encountered.
+  Move .cache file into a new /etc/lvm/cache directory by default.
+  Add devices/cache_dir & devices/cache_file_prefix, deprecating devices/cache.
+  Create directory in fcntl_lock_file() if required.
+  Exclude readline support from lvm.static.
+  Fix a leak in a reporting error path (2.02.19).
+
+Version 2.02.22 - 13th February 2007
+====================================
+  Correct -b and -P on a couple of man pages.
+  Add global/units to example.conf.
+  Fix loading of segment_libraries.
+  If a PV reappears after it was removed from its VG, make it an orphan.
+  Don't update metadata automatically if VGIDs don't match.
+  Fix some vgreduce --removemissing command line validation.
+
+Version 2.02.21 - 30th January 2007
+===================================
+  Add warning to lvm2_monitoring_init_rhel4 if attempting to stop monitoring.
+  Fix vgsplit to handle mirrors.
+  Reorder fields in reporting field definitions.
+  Fix vgs to treat args as VGs even when PV fields are displayed.
+  Fix md signature check to handle both endiannesses.
+
+Version 2.02.20 - 25th January 2007
+===================================
+  dmeventd mirror sets ignore_suspended_devices and avoids scanning mirrors.
+  Add devices/ignore_suspended_devices to ignore suspended dm devices.
+  Add some missing close() and fclose() return code checks.
+  Fix exit statuses of reporting tools (2.02.19).
+  Add init script for dmeventd monitoring.
+  lvm.static no longer interacts with dmeventd unless explicitly asked to.
+  Add field definitions to report help text.
+  Remove unnecessary cmd arg from target_*monitor_events().
+  Add private variable to dmeventd shared library interface.
+  Long-lived processes write out persistent dev cache in refresh_toolcontext().
+  Fix refresh_toolcontext() always to wipe persistent device filter cache.
+  Add is_long_lived to toolcontext.
+  Add --clustered to man pages.
+  Streamline dm_report_field_* interface.
+  Change remaining dmeventd terminology 'register' to 'monitor'.
+  Update reporting man pages.
+  No longer necessary to specify alignment type for report fields.
+
+Version 2.02.19 - 17th January 2007
+===================================
+  Fix a segfault if an empty config file section encountered.
+  Move basic reporting functions into libdevmapper.
+  Fix partition table processing after sparc changes (2.02.16).
+  Fix cmdline PE range processing segfault (2.02.13).
+  Some libdevmapper-event interface changes.
+  Report dmeventd mirror monitoring status.
+  Fix dmeventd mirror status line processing.
+
+Version 2.02.18 - 11th January 2007
+===================================
+  Revised libdevmapper-event interface for dmeventd.
+  Remove dmeventd mirror status line word limit.
+  Use CFLAGS when linking so mixed sparc builds can supply -m64.
+  Prevent permission changes on active mirrors.
+  Print warning instead of error message if lvconvert cannot zero volume.
+  Add snapshot options to lvconvert man page.
+  dumpconfig accepts a list of configuration variables to display.
+  Change dumpconfig to use --file to redirect output to a file.
+  Avoid vgreduce error when mirror code removes the log LV.
+  Remove 3 redundant AC_MSG_RESULTs from configure.in.
+  Free memory in _raw_read_mda_header() error paths.
+  Fix ambiguous vgsplit error message for split LV.
+  Fix lvextend man page typo.
+  Add configure --with-dmdir to compile against a device-mapper source tree.
+  Use no flush suspending for mirrors.
+  Add dmeventd_mirror register_mutex, tidy initialisation & add memlock.
+  Fix create mirror with name longer than 22 chars.
+  Fix some activate.c prototypes when compiled without devmapper.
+  Fix dmeventd mirror to cope if monitored device disappears.
+
+Version 2.02.17 - 14th December 2006
+====================================
+  Add missing pvremove error message when device doesn't exist.
+  When lvconvert allocates a mirror log, respect parallel area constraints.
+  Use loop to iterate through the now-ordered policy list in _allocate().
+  Check for failure to allocate just the mirror log.
+  Introduce calc_area_multiple().
+  Support mirror log allocation when there is only one PV: area_count now 0.
+  Fix detection of smallest area in _alloc_parallel_area() for cling policy.
+  Add manpage entry for clvmd -T
+  Fix gulm operation of clvmd, including a hang when doing lvchange -aey
+  Fix hang in clvmd if a pre-command failed.
+
+Version 2.02.16 - 1st December 2006
+===================================
+  Fix VG clustered read locks to use PR not CR.
+  Adjust some alignments for ia64/sparc.
+  Fix mirror segment removal to use temporary error segment.
+  Always compile debug logging into clvmd.
+  Add startup timeout to RHEL4 clvmd startup script.
+  Add -T (startup timeout) switch to clvmd.
+  Improve lvm_dump.sh robustness.
+  Update lvm2create_initrd to support gentoo.
+
+Version 2.02.15 - 21st November 2006
+====================================
+  Fix clvmd_init_rhel4 line truncation (2.02.14).
+  Install lvmdump by default.
+  Fix check for snapshot module when activating snapshot.
+  Fix pvremove error path for case when PV is in use.
+  Warn if certain duplicate config file entries are seen.
+  Enhance lvm_dump.sh for sysreport integration and add man page.
+  Fix --autobackup argument which could never disable backups.
+  Fix a label_verify error path.
+
+Version 2.02.14 - 10th November 2006
+====================================
+  Fix adjusted_mirror_region_size() to handle 64-bit size.
+  Add some missing bounds checks on 32-bit extent counters.
+  Add Petabyte and Exabyte support.
+  Fix lvcreate error message when 0 extents requested.
+  lvremove man page: volumes must be cluster inactive before being removed.
+  Protect .cache manipulations with fcntl locking.
+  Change .cache timestamp comparisons to use ctime.
+  Fix mirror log LV writing to set all bits in whole LV.
+  Fix clustered VG detection and default runlevels in clvmd_init_rhel4.
+  Fix high-level free space check for partial allocations.
+
+Version 2.02.13 - 27th October 2006
+===================================
+  Add couple of missing files to tools/Makefile CLEAN_TARGETS.
+  When adding snapshot leave cow LV mapped device active after zeroing.
+  Fix a clvmd debug message.
+  Add dev_flush() to set_lv().
+  Add lvchange --resync.
+  Perform high-level free space check before each allocation attempt.
+  Don't allow a node to remove an LV that's exclusively active on anther node.
+  Cope if same PV is included more than once in cmdline PE range list.
+  Set PV size to current device size if it is found to be zero.
+  Add segment parameter to target_present functions.
+
 Version 2.02.12 - 16th October 2006
 ===================================
   Fix pvdisplay to use vg_read() for non-orphans.

Modified: lvm2/upstream/current/configure
==============================================================================
--- lvm2/upstream/current/configure	(original)
+++ lvm2/upstream/current/configure	Sat Apr  7 15:30:42 2007
@@ -310,7 +310,7 @@
 #endif"
 
 ac_default_prefix=/usr
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os AWK CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S SET_MAKE RANLIB ac_ct_RANLIB CFLOW_CMD CSCOPE_CMD CPP EGREP ALLOCA LIBOBJS POW_LIB MSGFMT MODPROBE_CMD JOBS STATIC_LINK LVM1 POOL SNAPSHOTS MIRRORS OWNER GROUP COPTIMISE_FLAG CLDFLAGS CLDWHOLEARCHIVE CLDNOWHOLEARCHIVE LDDEPS LIB_SUFFIX LVM_VERSION LVM1_FALLBACK DEBUG DEVMAPPER HAVE_LIBDL HAVE_SELINUX HAVE_REALTIME CMDLIB LOCALEDIR CONFDIR STATICDIR INTL_PACKAGE INTL CLVMD CLUSTER FSADM DMEVENTD LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os AWK CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S SET_MAKE RANLIB ac_ct_RANLIB CFLOW_CMD CSCOPE_CMD CPP EGREP ALLOCA LIBOBJS POW_LIB MSGFMT MODPROBE_CMD JOBS STATIC_LINK LVM1 POOL SNAPSHOTS MIRRORS OWNER GROUP COPTIMISE_FLAG CLDFLAGS CLDWHOLEARCHIVE CLDNOWHOLEARCHIVE LDDEPS LIB_SUFFIX LVM_VERSION LVM1_FALLBACK DEBUG DEVMAPPER HAVE_LIBDL HAVE_SELINUX HAVE_REALTIME CMDLIB LOCALEDIR CONFDIR STATICDIR DMDIR INTL_PACKAGE INTL CLVMD CLUSTER FSADM DMEVENTD LTLIBOBJS'
 ac_subst_files=''
 
 # Initialize some variables set by options.
@@ -883,6 +883,7 @@
   --with-localedir=DIR    Translation files in DIR PREFIX/share/locale
   --with-confdir=DIR      Configuration files in DIR /etc
   --with-staticdir=DIR    Static binary in DIR EXEC_PREFIX/sbin
+  --with-dmdir=DIR        Build against device-mapper source tree in DIR
 
 Some influential environment variables:
   CC          C compiler command
@@ -8267,8 +8268,6 @@
 
 ################################################################################
 if test x$SELINUX = xyes; then
-	echo "$as_me:$LINENO: checking for sepol_check_context function" >&5
-echo $ECHO_N "checking for sepol_check_context function... $ECHO_C" >&6
 	echo "$as_me:$LINENO: checking for sepol_check_context in -lsepol" >&5
 echo $ECHO_N "checking for sepol_check_context in -lsepol... $ECHO_C" >&6
 if test "${ac_cv_lib_sepol_sepol_check_context+set}" = set; then
@@ -8339,15 +8338,11 @@
   HAVE_SEPOL=no
 fi
 
-	echo "$as_me:$LINENO: result: $HAVE_SEPOL" >&5
-echo "${ECHO_T}$HAVE_SEPOL" >&6
 
 	if test x$HAVE_SEPOL = xyes; then
 		LIBS="-lsepol $LIBS"
 	fi
 
-	echo "$as_me:$LINENO: checking for is_selinux_enabled function" >&5
-echo $ECHO_N "checking for is_selinux_enabled function... $ECHO_C" >&6
 	echo "$as_me:$LINENO: checking for is_selinux_enabled in -lselinux" >&5
 echo $ECHO_N "checking for is_selinux_enabled in -lselinux... $ECHO_C" >&6
 if test "${ac_cv_lib_selinux_is_selinux_enabled+set}" = set; then
@@ -8418,8 +8413,6 @@
   HAVE_SELINUX=no
 fi
 
-	echo "$as_me:$LINENO: result: $HAVE_SELINUX" >&5
-echo "${ECHO_T}$HAVE_SELINUX" >&6
 
 	if test x$HAVE_SELINUX = xyes; then
 
@@ -8436,8 +8429,6 @@
 
 ################################################################################
 if test x$REALTIME = xyes; then
-	echo "$as_me:$LINENO: checking for clock_gettime function" >&5
-echo $ECHO_N "checking for clock_gettime function... $ECHO_C" >&6
 	echo "$as_me:$LINENO: checking for clock_gettime in -lrt" >&5
 echo $ECHO_N "checking for clock_gettime in -lrt... $ECHO_C" >&6
 if test "${ac_cv_lib_rt_clock_gettime+set}" = set; then
@@ -8508,8 +8499,6 @@
   HAVE_REALTIME=no
 fi
 
-	echo "$as_me:$LINENO: result: $HAVE_REALTIME" >&5
-echo "${ECHO_T}$HAVE_REALTIME" >&6
 
 	if test x$HAVE_REALTIME = xyes; then
 
@@ -8964,6 +8953,15 @@
    STATICDIR='${exec_prefix}/sbin'
 fi;
 
+
+# Check whether --with-dmdir or --without-dmdir was given.
+if test "${with_dmdir+set}" = set; then
+  withval="$with_dmdir"
+   DMDIR="$withval"
+else
+   DMDIR=
+fi;
+
 ################################################################################
 if test x$READLINE = xyes; then
 
@@ -11202,8 +11200,9 @@
 
 
 
+
 ################################################################################
-                                                                                                                                                                                                                                                ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile dmeventd/Makefile dmeventd/mirror/Makefile doc/Makefile include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/snapshot/Makefile man/Makefile po/Makefile tools/Makefile tools/version.h tools/fsadm/Makefile test/mm/Makefile test/device/Makefile test/format1/Makefile test/regex/Makefile test/filters/Makefile"
+                                                                                                                                                                                                                                                          ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile dmeventd/Makefile dmeventd/mirror/Makefile doc/Makefile include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/snapshot/Makefile man/Makefile po/Makefile scripts/Makefile tools/Makefile tools/version.h tools/fsadm/Makefile test/mm/Makefile test/device/Makefile test/format1/Makefile test/regex/Makefile test/filters/Makefile"
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
 # tests run on this system so they can be shared between configure
@@ -11745,6 +11744,7 @@
   "lib/snapshot/Makefile" ) CONFIG_FILES="$CONFIG_FILES lib/snapshot/Makefile" ;;
   "man/Makefile" ) CONFIG_FILES="$CONFIG_FILES man/Makefile" ;;
   "po/Makefile" ) CONFIG_FILES="$CONFIG_FILES po/Makefile" ;;
+  "scripts/Makefile" ) CONFIG_FILES="$CONFIG_FILES scripts/Makefile" ;;
   "tools/Makefile" ) CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;;
   "tools/version.h" ) CONFIG_FILES="$CONFIG_FILES tools/version.h" ;;
   "tools/fsadm/Makefile" ) CONFIG_FILES="$CONFIG_FILES tools/fsadm/Makefile" ;;
@@ -11899,6 +11899,7 @@
 s, at LOCALEDIR@,$LOCALEDIR,;t t
 s, at CONFDIR@,$CONFDIR,;t t
 s, at STATICDIR@,$STATICDIR,;t t
+s, at DMDIR@,$DMDIR,;t t
 s, at INTL_PACKAGE@,$INTL_PACKAGE,;t t
 s, at INTL@,$INTL,;t t
 s, at CLVMD@,$CLVMD,;t t

Modified: lvm2/upstream/current/configure.in
==============================================================================
--- lvm2/upstream/current/configure.in	(original)
+++ lvm2/upstream/current/configure.in	Sat Apr  7 15:30:42 2007
@@ -438,17 +438,13 @@
 ################################################################################
 dnl -- Check for selinux
 if test x$SELINUX = xyes; then
-	AC_MSG_CHECKING(for sepol_check_context function)
 	AC_CHECK_LIB(sepol, sepol_check_context, HAVE_SEPOL=yes, HAVE_SEPOL=no)
-	AC_MSG_RESULT($HAVE_SEPOL)
 
 	if test x$HAVE_SEPOL = xyes; then
 		LIBS="-lsepol $LIBS"
 	fi
 
-	AC_MSG_CHECKING(for is_selinux_enabled function)
 	AC_CHECK_LIB(selinux, is_selinux_enabled, HAVE_SELINUX=yes, HAVE_SELINUX=no)
-	AC_MSG_RESULT($HAVE_SELINUX)
 
 	if test x$HAVE_SELINUX = xyes; then
 		AC_DEFINE([HAVE_SELINUX], 1, [Define to 1 to include support for selinux.])
@@ -461,9 +457,7 @@
 ################################################################################
 dnl -- Check for realtime clock support
 if test x$REALTIME = xyes; then
-	AC_MSG_CHECKING(for clock_gettime function)
 	AC_CHECK_LIB(rt, clock_gettime, HAVE_REALTIME=yes, HAVE_REALTIME=no)
-	AC_MSG_RESULT($HAVE_REALTIME)
 
 	if test x$HAVE_REALTIME = xyes; then
 		AC_DEFINE([HAVE_REALTIME], 1, [Define to 1 to include support for realtime clock.])
@@ -526,6 +520,11 @@
   	    [ STATICDIR="$withval" ],
  	    [ STATICDIR='${exec_prefix}/sbin' ])
 
+AC_ARG_WITH(dmdir,
+	    [  --with-dmdir=DIR        Build against device-mapper source tree in DIR],
+  	    [ DMDIR="$withval" ],
+	    [ DMDIR= ])
+
 ################################################################################
 dnl -- Ensure additional headers required
 if test x$READLINE = xyes; then
@@ -608,6 +607,7 @@
 AC_SUBST(LOCALEDIR)
 AC_SUBST(CONFDIR)
 AC_SUBST(STATICDIR)
+AC_SUBST(DMDIR)
 AC_SUBST(INTL_PACKAGE)
 AC_SUBST(INTL)
 AC_SUBST(CLVMD)
@@ -637,6 +637,7 @@
 lib/snapshot/Makefile							\
 man/Makefile							 	\
 po/Makefile								\
+scripts/Makefile								\
 tools/Makefile							 	\
 tools/version.h								\
 tools/fsadm/Makefile							\

Modified: lvm2/upstream/current/daemons/clvmd/Makefile.in
==============================================================================
--- lvm2/upstream/current/daemons/clvmd/Makefile.in	(original)
+++ lvm2/upstream/current/daemons/clvmd/Makefile.in	Sat Apr  7 15:30:42 2007
@@ -71,7 +71,8 @@
 	install_clvmd
 
 clvmd: $(OBJECTS) $(top_srcdir)/lib/liblvm.a
-	$(CC) -o clvmd $(OBJECTS) $(LDFLAGS) $(LVMLIBS) $(LMLIBS) $(LIBS)
+	$(CC) -o clvmd $(OBJECTS) $(CFLAGS) $(LDFLAGS) \
+		$(LVMLIBS) $(LMLIBS) $(LIBS)
 
 .PHONY: install_clvmd
 

Modified: lvm2/upstream/current/daemons/clvmd/clvmd-command.c
==============================================================================
--- lvm2/upstream/current/daemons/clvmd/clvmd-command.c	(original)
+++ lvm2/upstream/current/daemons/clvmd/clvmd-command.c	Sat Apr  7 15:30:42 2007
@@ -191,12 +191,16 @@
 	    dm_hash_remove(lock_hash, lockname);
     }
     else {
-
+	/* Read locks need to be PR; other modes get passed through */
+	if ((lock_cmd & LCK_TYPE_MASK) == LCK_READ) {
+	    lock_cmd &= ~LCK_TYPE_MASK;
+	    lock_cmd |= LCK_PREAD;
+	}
 	status = sync_lock(lockname, (int)lock_cmd, (lock_flags & LCK_NONBLOCK) ? LKF_NOQUEUE : 0, &lkid);
 	if (status)
 	    status = errno;
 	else
-	    dm_hash_insert(lock_hash, lockname, (void *)lkid);
+	    dm_hash_insert(lock_hash, lockname, (void *)(long)lkid);
     }
 
     return status;
@@ -220,7 +224,7 @@
 	switch (header->cmd) {
 	case CLVMD_CMD_TEST:
 		status = sync_lock("CLVMD_TEST", LKM_EXMODE, 0, &lockid);
-		client->bits.localsock.private = (void *) lockid;
+		client->bits.localsock.private = (void *)(long)lockid;
 		break;
 
 	case CLVMD_CMD_LOCK_VG:

Modified: lvm2/upstream/current/daemons/clvmd/clvmd-gulm.c
==============================================================================
--- lvm2/upstream/current/daemons/clvmd/clvmd-gulm.c	(original)
+++ lvm2/upstream/current/daemons/clvmd/clvmd-gulm.c	Sat Apr  7 15:30:42 2007
@@ -730,7 +730,7 @@
     pthread_mutex_lock(&lwait.mutex);
 
     /* This needs to be converted from DLM/LVM2 value for GULM */
-    if (flags == LCK_NONBLOCK) flags = lg_lock_flag_Try;
+    if (flags & LKF_NOQUEUE) flags = lg_lock_flag_Try;
 
     dm_hash_insert(lock_hash, resource, &lwait);
     DEBUGLOG("lock_resource '%s', flags=%d, mode=%d\n", resource, flags, mode);
@@ -828,6 +828,7 @@
         }
 	break;
 
+    case LCK_PREAD:
     case LCK_READ:
 	status = _lock_resource(lock1, lg_lock_state_Shared, flags, lockid);
 	if (status)
@@ -864,6 +865,7 @@
     /* The held lock mode is in the lock id */
     assert(lockid == LCK_EXCL ||
 	   lockid == LCK_READ ||
+	   lockid == LCK_PREAD ||
 	   lockid == LCK_WRITE);
 
     status = _unlock_resource(lock1, lockid);

Modified: lvm2/upstream/current/daemons/clvmd/clvmd-gulm.h
==============================================================================
--- lvm2/upstream/current/daemons/clvmd/clvmd-gulm.h	(original)
+++ lvm2/upstream/current/daemons/clvmd/clvmd-gulm.h	Sat Apr  7 15:30:42 2007
@@ -1,5 +1,6 @@
 
-
+/* DLM constant that clvmd uses as a generic NONBLOCK lock flag */
+#define LKF_NOQUEUE 1
 
 extern int get_next_node_csid(void **context, char *csid);
 extern void add_down_node(char *csid);

Modified: lvm2/upstream/current/daemons/clvmd/clvmd.c
==============================================================================
--- lvm2/upstream/current/daemons/clvmd/clvmd.c	(original)
+++ lvm2/upstream/current/daemons/clvmd/clvmd.c	Sat Apr  7 15:30:42 2007
@@ -30,6 +30,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <stddef.h>
+#include <stdarg.h>
 #include <signal.h>
 #include <unistd.h>
 #include <fcntl.h>
@@ -85,6 +86,7 @@
 	int msglen;
 	unsigned short xid;
 };
+static int debug = 0;
 static pthread_t lvm_thread;
 static pthread_mutex_t lvm_thread_mutex;
 static pthread_cond_t lvm_thread_cond;
@@ -99,6 +101,7 @@
 #define DFAIL_LOCAL_SOCK 2
 #define DFAIL_CLUSTER_IF 3
 #define DFAIL_MALLOC     4
+#define DFAIL_TIMEOUT    5
 #define SUCCESS          0
 
 /* Prototypes for code further down */
@@ -122,7 +125,7 @@
 static int open_local_sock(void);
 static struct local_client *find_client(int clientid);
 static void main_loop(int local_sock, int cmd_timeout);
-static void be_daemon(void);
+static void be_daemon(int start_timeout);
 static int check_all_clvmds_running(struct local_client *client);
 static int local_rendezvous_callback(struct local_client *thisfd, char *buf,
 				     int len, char *csid,
@@ -146,6 +149,7 @@
 	fprintf(file, "   -d       Don't fork, run in the foreground\n");
 	fprintf(file, "   -R       Tell all running clvmds in the cluster to reload their device cache\n");
 	fprintf(file, "   -t<secs> Command timeout (default 60 seconds)\n");
+	fprintf(file, "   -T<secs> Startup timeout (default none)\n");
 	fprintf(file, "\n");
 }
 
@@ -161,21 +165,36 @@
 }
 
 
+void debuglog(const char *fmt, ...)
+{
+	time_t P;
+	va_list ap;
+
+	if (!debug)
+		return;
+
+	va_start(ap,fmt);
+	time(&P);
+ 	fprintf(stderr, "CLVMD[%x]: %.15s ", (int)pthread_self(), ctime(&P)+4 );
+	vfprintf(stderr, fmt, ap);
+	va_end(ap);
+}
+
 int main(int argc, char *argv[])
 {
 	int local_sock;
 	struct local_client *newfd;
 	struct utsname nodeinfo;
 	signed char opt;
-	int debug = 0;
 	int cmd_timeout = DEFAULT_CMD_TIMEOUT;
+	int start_timeout = 0;
 	sigset_t ss;
 	int using_gulm = 0;
 
 	/* Deal with command-line arguments */
 	opterr = 0;
 	optind = 0;
-	while ((opt = getopt(argc, argv, "?vVhdt:R")) != EOF) {
+	while ((opt = getopt(argc, argv, "?vVhdt:RT:")) != EOF) {
 		switch (opt) {
 		case 'h':
 			usage(argv[0], stdout);
@@ -200,6 +219,14 @@
 				exit(1);
 			}
 			break;
+		case 'T':
+			start_timeout = atoi(optarg);
+			if (start_timeout <= 0) {
+				fprintf(stderr, "startup timeout is invalid\n");
+				usage(argv[0], stderr);
+				exit(1);
+			}
+			break;
 
 		case 'V':
 		        printf("Cluster LVM daemon version: %s\n", LVM_VERSION);
@@ -214,7 +241,7 @@
 
 	/* Fork into the background (unless requested not to) */
 	if (!debug) {
-		be_daemon();
+		be_daemon(start_timeout);
 	}
 
 	DEBUGLOG("CLVMD started\n");
@@ -298,7 +325,8 @@
 	/* This needs to be started after cluster initialisation
 	   as it may need to take out locks */
 	DEBUGLOG("starting LVM thread\n");
-	pthread_create(&lvm_thread, NULL, lvm_thread_fn, (void *)using_gulm);
+	pthread_create(&lvm_thread, NULL, lvm_thread_fn, 
+			(void *)(long)using_gulm);
 
 	/* Tell the rest of the cluster our version number */
 	/* CMAN can do this immediately, gulm needs to wait until
@@ -385,16 +413,17 @@
 
 	len = read(thisfd->fd, buffer, sizeof(int));
 
-	DEBUGLOG("read on PIPE %d: %d bytes: status: %d\n",
-		 thisfd->fd, len, *(int *) buffer);
-
 	if (len == sizeof(int)) {
-		status = *(int *) buffer;
+		memcpy(&status, buffer, sizeof(int));
 	}
 
+	DEBUGLOG("read on PIPE %d: %d bytes: status: %d\n",
+		 thisfd->fd, len, status);
+
 	/* EOF on pipe or an error, close it */
 	if (len <= 0) {
 		int jstat;
+		void *ret = &status;
 		close(thisfd->fd);
 
 		/* Clear out the cross-link */
@@ -404,9 +433,7 @@
 
 		/* Reap child thread */
 		if (thisfd->bits.pipe.threadid) {
-			jstat =
-			    pthread_join(thisfd->bits.pipe.threadid,
-					 (void **) &status);
+			jstat = pthread_join(thisfd->bits.pipe.threadid, &ret);
 			thisfd->bits.pipe.threadid = 0;
 			if (thisfd->bits.pipe.client != NULL)
 				thisfd->bits.pipe.client->bits.localsock.
@@ -647,16 +674,66 @@
 	close(local_sock);
 }
 
+static __attribute__ ((noreturn)) void wait_for_child(int c_pipe, int timeout)
+{
+	int child_status;
+	int sstat;
+	fd_set fds;
+	struct timeval tv = {timeout, 0};
+
+	FD_ZERO(&fds);
+	FD_SET(c_pipe, &fds);
+
+	sstat = select(c_pipe+1, &fds, NULL, NULL, timeout? &tv: NULL);
+	if (sstat == 0) {
+		fprintf(stderr, "clvmd startup timed out\n");
+		exit(DFAIL_TIMEOUT);
+	}
+	if (sstat == 1) {
+		if (read(c_pipe, &child_status, sizeof(child_status)) !=
+		    sizeof(child_status)) {
+
+			fprintf(stderr, "clvmd failed in initialisation\n");
+			exit(DFAIL_INIT);
+		}
+		else {
+			switch (child_status) {
+			case SUCCESS:
+				break;
+			case DFAIL_INIT:
+				fprintf(stderr, "clvmd failed in initialisation\n");
+				break;
+			case DFAIL_LOCAL_SOCK:
+				fprintf(stderr, "clvmd could not create local socket\n");
+				fprintf(stderr, "Another clvmd is probably already running\n");
+				break;
+			case DFAIL_CLUSTER_IF:
+				fprintf(stderr, "clvmd could not connect to cluster manager\n");
+				fprintf(stderr, "Consult syslog for more information\n");
+				break;
+			case DFAIL_MALLOC:
+				fprintf(stderr, "clvmd failed, not enough memory\n");
+				break;
+			default:
+				fprintf(stderr, "clvmd failed, error was %d\n", child_status);
+				break;
+			}
+			exit(child_status);
+		}
+	}
+	fprintf(stderr, "clvmd startup, select failed: %s\n", strerror(errno));
+	exit(DFAIL_INIT);
+}
+
 /*
  * Fork into the background and detach from our parent process.
  * In the interests of user-friendliness we wait for the daemon
  * to complete initialisation before returning its status
  * the the user.
  */
-static void be_daemon()
+static void be_daemon(int timeout)
 {
         pid_t pid;
-	int child_status;
 	int devnull = open("/dev/null", O_RDWR);
 	if (devnull == -1) {
 		perror("Can't open /dev/null");
@@ -676,36 +753,7 @@
 
 	default:       /* Parent */
 		close(child_pipe[1]);
-		if (read(child_pipe[0], &child_status, sizeof(child_status)) !=
-		    sizeof(child_status)) {
-
-		        fprintf(stderr, "clvmd failed in initialisation\n");
-		        exit(DFAIL_INIT);
-		}
-		else {
-		        switch (child_status) {
-			case SUCCESS:
-			        break;
-			case DFAIL_INIT:
-			        fprintf(stderr, "clvmd failed in initialisation\n");
-				break;
-			case DFAIL_LOCAL_SOCK:
-			        fprintf(stderr, "clvmd could not create local socket\n");
-				fprintf(stderr, "Another clvmd is probably already running\n");
-				break;
-			case DFAIL_CLUSTER_IF:
-			        fprintf(stderr, "clvmd could not connect to cluster manager\n");
-				fprintf(stderr, "Consult syslog for more information\n");
-				break;
-			case DFAIL_MALLOC:
-			        fprintf(stderr, "clvmd failed, not enough memory\n");
-				break;
-			default:
-			        fprintf(stderr, "clvmd failed, error was %d\n", child_status);
-				break;
-			}
-			exit(child_status);
-		}
+		wait_for_child(child_pipe[0], timeout);
 	}
 
 	/* Detach ourself from the calling environment */
@@ -1091,8 +1139,8 @@
 }
 
 /* Process a command from a remote node and return the result */
-void process_remote_command(struct clvm_header *msg, int msglen, int fd,
-			    char *csid)
+static void process_remote_command(struct clvm_header *msg, int msglen, int fd,
+			    	   char *csid)
 {
 	char *replyargs;
 	char nodename[max_cluster_member_name_len];
@@ -1116,11 +1164,12 @@
 		    (struct clvm_header *) malloc(msg->arglen +
 						  sizeof(struct clvm_header));
 		if (newmsg) {
-			if (system_lv_read_data
-			    (nodename, (char *) newmsg,
-			     (size_t *) &msglen) == 0) {
+			ssize_t len;
+			if (system_lv_read_data(nodename, (char *) newmsg,
+			     			&len) == 0) {
 				msg = newmsg;
 				msg_malloced = 1;
+				msglen = len;
 			} else {
 				struct clvm_header head;
 				DEBUGLOG("System LV read failed\n");
@@ -1166,8 +1215,11 @@
 	/* Version check is internal - don't bother exposing it in
 	   clvmd-command.c */
 	if (msg->cmd == CLVMD_CMD_VERSION) {
-		int *version_nums = (int *) msg->args;
+		int version_nums[3]; 
 		char node[256];
+
+		memcpy(version_nums, msg->args, sizeof(version_nums));
+
 		clops->name_from_csid(csid, node);
 		DEBUGLOG("Remote node %s is version %d.%d.%d\n",
 			 node,
@@ -1339,7 +1391,7 @@
 }
 
 /* This is the thread that runs the PRE and post commands for a particular connection */
-static void *pre_and_post_thread(void *arg)
+static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
 {
 	struct local_client *client = (struct local_client *) arg;
 	int status;
@@ -1374,6 +1426,8 @@
 		DEBUGLOG("Writing status %d down pipe %d\n", status, pipe_fd);
 		/* Tell the parent process we have finished this bit */
 		write(pipe_fd, &status, sizeof(int));
+		if (status)
+			continue; /* Wait for another PRE command */
 
 		/* We may need to wait for the condition variable before running the post command */
 		pthread_mutex_lock(&client->bits.localsock.mutex);
@@ -1407,7 +1461,6 @@
 	}
 	DEBUGLOG("Subthread finished\n");
 	pthread_exit((void *) 0);
-	return 0;
 }
 
 /* Process a command on the local node and store the result */
@@ -1516,7 +1569,7 @@
 		if (thisreply->status)
 			clientreply->flags |= CLVMD_FLAG_NODEERRS;
 
-		*(int *) ptr = thisreply->status;
+		memcpy(ptr, &thisreply->status, sizeof(int));
 		ptr += sizeof(int);
 
 		if (thisreply->replymsg) {
@@ -1572,19 +1625,22 @@
 {
 	char message[sizeof(struct clvm_header) + sizeof(int) * 3];
 	struct clvm_header *msg = (struct clvm_header *) message;
-	int *version_nums = (int *) msg->args;
+	int version_nums[3];
 
 	msg->cmd = CLVMD_CMD_VERSION;
 	msg->status = 0;
 	msg->flags = 0;
 	msg->clientid = 0;
-	msg->arglen = sizeof(int) * 3;
+	msg->arglen = sizeof(version_nums);
 
 	version_nums[0] = htonl(CLVMD_MAJOR_VERSION);
 	version_nums[1] = htonl(CLVMD_MINOR_VERSION);
 	version_nums[2] = htonl(CLVMD_PATCH_VERSION);
 
+	memcpy(&msg->args, version_nums, sizeof(version_nums));
+
 	hton_clvm(msg);
+
 	clops->cluster_send_message(message, sizeof(message), NULL,
 			     "Error Sending version number");
 }
@@ -1641,11 +1697,11 @@
 /*
  * Routine that runs in the "LVM thread".
  */
-static void *lvm_thread_fn(void *arg)
+static __attribute__ ((noreturn)) void *lvm_thread_fn(void *arg)
 {
 	struct list *cmdl, *tmp;
 	sigset_t ss;
-	int using_gulm = (int)arg;
+	int using_gulm = (int)(long)arg;
 
 	/* Don't let anyone else to do work until we are started */
 	pthread_mutex_lock(&lvm_start_mutex);
@@ -1689,7 +1745,6 @@
 		}
 		pthread_mutex_unlock(&lvm_thread_mutex);
 	}
-	return NULL;
 }
 
 /* Pass down some work to the LVM thread */

Modified: lvm2/upstream/current/daemons/clvmd/clvmd.h
==============================================================================
--- lvm2/upstream/current/daemons/clvmd/clvmd.h	(original)
+++ lvm2/upstream/current/daemons/clvmd/clvmd.h	Sat Apr  7 15:30:42 2007
@@ -95,11 +95,7 @@
 	} bits;
 };
 
-#ifdef DEBUG
-#define DEBUGLOG(fmt, args...) {time_t P; time(&P); fprintf(stderr, "CLVMD[%x]: %.15s ", (int)pthread_self(), ctime(&P)+4 ); fprintf(stderr, fmt, ## args);}
-#else
-#define DEBUGLOG(fmt, args...)
-#endif
+#define DEBUGLOG(fmt, args...) debuglog(fmt, ## args);
 
 #ifndef max
 #define max(a,b) ((a)>(b)?(a):(b))
@@ -117,6 +113,7 @@
 
 extern void clvmd_cluster_init_completed(void);
 extern void process_message(struct local_client *client, char *buf, int len, char *csid);
+extern void debuglog(const char *fmt, ... );
 
 int sync_lock(const char *resource, int mode, int flags, int *lockid);
 int sync_unlock(const char *resource, int lockid);

Modified: lvm2/upstream/current/daemons/clvmd/lvm-functions.c
==============================================================================
--- lvm2/upstream/current/daemons/clvmd/lvm-functions.c	(original)
+++ lvm2/upstream/current/daemons/clvmd/lvm-functions.c	Sat Apr  7 15:30:42 2007
@@ -243,7 +243,7 @@
 	/* Is it open ? */
 	oldmode = get_current_lock(resource);
 	if (oldmode == -1) {
-		DEBUGLOG("do_deactivate_lock, lock not already held\n");
+		DEBUGLOG("do_resume_lv, lock not already held\n");
 		return 0;	/* We don't need to do anything */
 	}
 
@@ -325,8 +325,8 @@
 	if (lock_flags & LCK_MIRROR_NOSYNC_MODE)
 		init_mirror_in_sync(1);
 
-	if (!(lock_flags & LCK_DMEVENTD_REGISTER_MODE))
-		init_dmeventd_register(0);
+	if (!(lock_flags & LCK_DMEVENTD_MONITOR_MODE))
+		init_dmeventd_monitor(0);
 
 	switch (command) {
 	case LCK_LV_EXCLUSIVE:
@@ -362,8 +362,8 @@
 	if (lock_flags & LCK_MIRROR_NOSYNC_MODE)
 		init_mirror_in_sync(0);
 
-	if (!(lock_flags & LCK_DMEVENTD_REGISTER_MODE))
-		init_dmeventd_register(DEFAULT_DMEVENTD_MONITOR);
+	if (!(lock_flags & LCK_DMEVENTD_MONITOR_MODE))
+		init_dmeventd_monitor(DEFAULT_DMEVENTD_MONITOR);
 
 	/* clean the pool for another command */
 	dm_pool_empty(cmd->mem);
@@ -473,7 +473,8 @@
 		sync_unlock(vg, LCK_EXCL);
 
 	}
-	fclose(vgs);
+	if (fclose(vgs))
+		DEBUGLOG("vgs fclose failed: %s\n", strerror(errno));
 }
 
 /*
@@ -523,7 +524,8 @@
 			}
 		}
 	}
-	fclose(lvs);
+	if (fclose(lvs))
+		DEBUGLOG("lvs fclose failed: %s\n", strerror(errno));
 	return NULL;
 }
 
@@ -575,7 +577,7 @@
 /* Called to initialise the LVM context of the daemon */
 int init_lvm(int using_gulm)
 {
-	if (!(cmd = create_toolcontext(NULL, 0))) {
+	if (!(cmd = create_toolcontext(NULL, 0, 1))) {
 		log_error("Failed to allocate command context");
 		return 0;
 	}

Modified: lvm2/upstream/current/daemons/clvmd/refresh_clvmd.c
==============================================================================
--- lvm2/upstream/current/daemons/clvmd/refresh_clvmd.c	(original)
+++ lvm2/upstream/current/daemons/clvmd/refresh_clvmd.c	Sat Apr  7 15:30:42 2007
@@ -183,7 +183,6 @@
 			   lvm_response_t ** response, int *num)
 {
 	char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1];
-	int *outptr;
 	char *inptr;
 	char *retbuf = NULL;
 	int status;
@@ -223,17 +222,14 @@
 	 * With an extra pair of INTs on the front to sanity
 	 * check the pointer when we are given it back to free
 	 */
-	outptr = dm_malloc(sizeof(lvm_response_t) * num_responses +
+	*response = dm_malloc(sizeof(lvm_response_t) * num_responses +
 			    sizeof(int) * 2);
-	if (!outptr) {
+	if (!*response) {
 		errno = ENOMEM;
 		status = 0;
 		goto out;
 	}
 
-	*response = (lvm_response_t *) (outptr + 2);
-	outptr[0] = LVM_SIGNATURE;
-	outptr[1] = num_responses;
 	rarray = *response;
 
 	/* Unpack the response into an lvm_response_t array */
@@ -252,7 +248,7 @@
 			int j;
 			for (j = 0; j < i; j++)
 				dm_free(rarray[i].response);
-			free(outptr);
+			free(*response);
 			errno = ENOMEM;
 			status = -1;
 			goto out;
@@ -274,25 +270,15 @@
 }
 
 /* Free reply array */
-static int _cluster_free_request(lvm_response_t * response)
+static int _cluster_free_request(lvm_response_t * response, int num)
 {
-	int *ptr = (int *) response - 2;
 	int i;
-	int num;
-
-	/* Check it's ours to free */
-	if (response == NULL || *ptr != LVM_SIGNATURE) {
-		errno = EINVAL;
-		return 0;
-	}
-
-	num = ptr[1];
 
 	for (i = 0; i < num; i++) {
 		dm_free(response[i].response);
 	}
 
-	dm_free(ptr);
+	dm_free(response);
 
 	return 1;
 }
@@ -327,7 +313,7 @@
 	}
 
 	saved_errno = errno;
-	_cluster_free_request(response);
+	_cluster_free_request(response, num_responses);
 	errno = saved_errno;
 
 	return status;

Modified: lvm2/upstream/current/dmeventd/mirror/dmeventd_mirror.c
==============================================================================
--- lvm2/upstream/current/dmeventd/mirror/dmeventd_mirror.c	(original)
+++ lvm2/upstream/current/dmeventd/mirror/dmeventd_mirror.c	Sat Apr  7 15:30:42 2007
@@ -15,7 +15,6 @@
 #include "libdevmapper.h"
 #include "libdevmapper-event.h"
 #include "lvm2cmd.h"
-#include "lvm-string.h"
 
 #include <errno.h>
 #include <signal.h>
@@ -26,79 +25,104 @@
 #include <unistd.h>
 
 #include <syslog.h> /* FIXME Replace syslog with multilog */
+/* FIXME Missing openlog? */
 
 #define ME_IGNORE    0
 #define ME_INSYNC    1
 #define ME_FAILURE   2
 
-static pthread_mutex_t _lock = PTHREAD_MUTEX_INITIALIZER;
+/*
+ * register_device() is called first and performs initialisation.
+ * Only one device may be registered or unregistered at a time.
+ */
+static pthread_mutex_t _register_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/*
+ * Number of active registrations.
+ */
+static int _register_count = 0;
 
-/* FIXME: We may need to lock around operations to these */
-static int register_count = 0;
-static struct dm_pool *mem_pool = NULL;
+static struct dm_pool *_mem_pool = NULL;
+static void *_lvm_handle = NULL;
+
+/*
+ * Currently only one event can be processed at a time.
+ */
+static pthread_mutex_t _event_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 static int _get_mirror_event(char *params)
 {
-	int i, rtn = ME_INSYNC;
-	int max_args = 30;  /* should support at least 8-way mirrors */
-	char *args[max_args];
+	int i, r = ME_INSYNC;
+	char **args = NULL;
 	char *dev_status_str;
 	char *log_status_str;
 	char *sync_str;
-	char *p;
-	int log_argc, num_devs, num_failures=0;
-
-	if (max_args <= dm_split_words(params, max_args, 0, args)) {
-		syslog(LOG_ERR, "Unable to split mirror parameters: Arg list too long");
-		return -E2BIG;
-	}
+	char *p = NULL;
+	int log_argc, num_devs;
 
 	/*
-	 * Unused:  0 409600 mirror
-	 * Used  :  2 253:4 253:5 400/400 1 AA 3 cluster 253:3 A
-	*/
-	num_devs = atoi(args[0]);
-	dev_status_str = args[3 + num_devs];
-	log_argc = atoi(args[4 + num_devs]);
-	log_status_str = args[4 + num_devs + log_argc];
-	sync_str = args[1 + num_devs];
+	 * dm core parms:	     0 409600 mirror
+	 * Mirror core parms:	     2 253:4 253:5 400/400
+	 * New-style failure params: 1 AA
+	 * New-style log params:     3 cluster 253:3 A
+	 *			 or  3 disk 253:3 A
+	 *			 or  1 core
+	 */
+
+	/* number of devices */
+	if (!dm_split_words(params, 1, 0, &p))
+		goto out_parse;
+
+	if (!(num_devs = atoi(p)))
+		goto out_parse;
+	p += strlen(p) + 1;
+
+	/* devices names + "400/400" + "1 AA" + 1 or 3 log parms + NULL */
+	args = dm_malloc((num_devs + 7) * sizeof(char *));
+	if (!args || dm_split_words(p, num_devs + 7, 0, args) < num_devs + 5)
+		goto out_parse;
+
+	dev_status_str = args[2 + num_devs];
+	log_argc = atoi(args[3 + num_devs]);
+	log_status_str = args[3 + num_devs + log_argc];
+	sync_str = args[num_devs];
 
 	/* Check for bad mirror devices */
-	for (i = 0; i < num_devs; i++) {
+	for (i = 0; i < num_devs; i++)
 		if (dev_status_str[i] == 'D') {
-			syslog(LOG_ERR, "Mirror device, %s, has failed.\n", args[i+1]);
-			num_failures++;
+			syslog(LOG_ERR, "Mirror device, %s, has failed.\n", args[i]);
+			r = ME_FAILURE;
 		}
-	}
 
-	/* Check for bad log device */
-	if (log_status_str[0] == 'D') {
+	/* Check for bad disk log device */
+	if (log_argc > 1 && log_status_str[0] == 'D') {
 		syslog(LOG_ERR, "Log device, %s, has failed.\n",
-		       args[3 + num_devs + log_argc]);
-		num_failures++;
+		       args[2 + num_devs + log_argc]);
+		r = ME_FAILURE;
 	}
 
-	if (num_failures) {
-		rtn = ME_FAILURE;
+	if (r == ME_FAILURE)
 		goto out;
-	}
 
 	p = strstr(sync_str, "/");
 	if (p) {
 		p[0] = '\0';
 		if (strcmp(sync_str, p+1))
-			rtn = ME_IGNORE;
+			r = ME_IGNORE;
 		p[0] = '/';
-	} else {
-		/*
-		 * How the hell did we get this?
-		 * Might mean all our parameters are screwed.
-		 */
-		syslog(LOG_ERR, "Unable to parse sync string.");
-		rtn = ME_IGNORE;
-	}
- out:
-	return rtn;
+	} else
+		goto out_parse;
+
+out:
+	if (args)
+		dm_free(args);
+	return r;
+	
+out_parse:
+	if (args)
+		dm_free(args);
+	syslog(LOG_ERR, "Unable to parse mirror status string.");
+	return ME_IGNORE;
 }
 
 static void _temporary_log_fn(int level, const char *file,
@@ -113,69 +137,55 @@
 static int _remove_failed_devices(const char *device)
 {
 	int r;
-	void *handle;
-	int cmd_size = 256;	/* FIXME Use system restriction */
-	char cmd_str[cmd_size];
+#define CMD_SIZE 256	/* FIXME Use system restriction */
+	char cmd_str[CMD_SIZE];
 	char *vg = NULL, *lv = NULL, *layer = NULL;
 
-	if (strlen(device) > 200)
-		return -ENAMETOOLONG;
+	if (strlen(device) > 200)  /* FIXME Use real restriction */
+		return -ENAMETOOLONG;	/* FIXME These return code distinctions are not used so remove them! */
 
-	if (!dm_split_lvm_name(mem_pool, device, &vg, &lv, &layer)) {
+	if (!dm_split_lvm_name(_mem_pool, device, &vg, &lv, &layer)) {
 		syslog(LOG_ERR, "Unable to determine VG name from %s",
 		       device);
-		return -ENOMEM;
+		return -ENOMEM;	/* FIXME Replace with generic error return - reason for failure has already got logged */
 	}
 
 	/* FIXME Is any sanity-checking required on %s? */
-	if (cmd_size <= snprintf(cmd_str, cmd_size, "vgreduce --removemissing %s", vg)) {
+	if (CMD_SIZE <= snprintf(cmd_str, CMD_SIZE, "vgreduce --config devices{ignore_suspended_devices=1} --removemissing %s", vg)) {
 		/* this error should be caught above, but doesn't hurt to check again */
 		syslog(LOG_ERR, "Unable to form LVM command: Device name too long");
-		dm_pool_empty(mem_pool);  /* FIXME: not safe with multiple threads */
-		return -ENAMETOOLONG;
+		dm_pool_empty(_mem_pool);  /* FIXME: not safe with multiple threads */
+		return -ENAMETOOLONG; /* FIXME Replace with generic error return - reason for failure has already got logged */
 	}
 
-	lvm2_log_fn(_temporary_log_fn);
-	handle = lvm2_init();
-	lvm2_log_level(handle, 1);
-	r = lvm2_run(handle, cmd_str);
+	r = lvm2_run(_lvm_handle, cmd_str);
 
-	dm_pool_empty(mem_pool);  /* FIXME: not safe with multiple threads */
-	return (r == 1)? 0: -1;
+	dm_pool_empty(_mem_pool);  /* FIXME: not safe with multiple threads */
+	return (r == 1) ? 0 : -1;
 }
 
-void process_event(const char *device, enum dm_event_type event)
+void process_event(struct dm_task *dmt, enum dm_event_mask event,
+		   void **unused __attribute((unused)))
 {
-	struct dm_task *dmt;
 	void *next = NULL;
 	uint64_t start, length;
 	char *target_type = NULL;
 	char *params;
+	const char *device = dm_task_get_name(dmt);
 
-	if (pthread_mutex_trylock(&_lock)) {
+	if (pthread_mutex_trylock(&_event_mutex)) {
 		syslog(LOG_NOTICE, "Another thread is handling an event.  Waiting...");
-		pthread_mutex_lock(&_lock);
-	}
-	/* FIXME Move inside libdevmapper */
-	if (!(dmt = dm_task_create(DM_DEVICE_STATUS))) {
-		syslog(LOG_ERR, "Unable to create dm_task.\n");
-		goto fail;
-	}
-
-	if (!dm_task_set_name(dmt, device)) {
-		syslog(LOG_ERR, "Unable to set device name.\n");
-		goto fail;
+		pthread_mutex_lock(&_event_mutex);
 	}
-
-	if (!dm_task_run(dmt)) {
-		syslog(LOG_ERR, "Unable to run task.\n");
-		goto fail;
-	}
-
 	do {
 		next = dm_get_next_target(dmt, next, &start, &length,
 					  &target_type, &params);
 
+		if (!target_type) {
+			syslog(LOG_INFO, "%s mapping lost.\n", device);
+			continue;
+		}
+
 		if (strcmp(target_type, "mirror")) {
 			syslog(LOG_INFO, "%s has unmirrored portion.\n", device);
 			continue;
@@ -192,6 +202,7 @@
 		case ME_FAILURE:
 			syslog(LOG_ERR, "Device failure in %s\n", device);
 			if (_remove_failed_devices(device))
+				/* FIXME Why are all the error return codes unused? Get rid of them? */
 				syslog(LOG_ERR, "Failed to remove faulty devices in %s\n",
 				       device);
 			/* Should check before warning user that device is now linear
@@ -203,52 +214,68 @@
 		case ME_IGNORE:
 			break;
 		default:
+			/* FIXME Provide value then! */
 			syslog(LOG_INFO, "Unknown event received.\n");
 		}
 	} while (next);
 
- fail:
-	if (dmt)
-		dm_task_destroy(dmt);
-	pthread_mutex_unlock(&_lock);
+	pthread_mutex_unlock(&_event_mutex);
 }
 
-int register_device(const char *device)
+int register_device(const char *device, const char *uuid, int major, int minor,
+		   void **unused __attribute((unused)))
 {
-	syslog(LOG_INFO, "Monitoring mirror device, %s for events\n", device);
+	int r = 0;
+
+	pthread_mutex_lock(&_register_mutex);
+
+	syslog(LOG_INFO, "Monitoring mirror device %s for events\n", device);
 
 	/*
 	 * Need some space for allocations.  1024 should be more
 	 * than enough for what we need (device mapper name splitting)
 	 */
-	if (!mem_pool)
-		mem_pool = dm_pool_create("mirror_dso", 1024);
+	if (!_mem_pool && !(_mem_pool = dm_pool_create("mirror_dso", 1024)))
+		goto out;
 
-	if (!mem_pool)
-		return 0;
+	if (!_lvm_handle) {
+		lvm2_log_fn(_temporary_log_fn);
+		if (!(_lvm_handle = lvm2_init())) {
+			dm_pool_destroy(_mem_pool);
+			_mem_pool = NULL;
+			goto out;
+		}
+		lvm2_log_level(_lvm_handle, LVM2_LOG_SUPPRESS);
+		/* FIXME Temporary: move to dmeventd core */
+		lvm2_run(_lvm_handle, "_memlock_inc");
+	}
+
+	_register_count++;
+	r = 1;
 
-	register_count++;
+out:
+	pthread_mutex_unlock(&_register_mutex);
 
-        return 1;
+	return r;
 }
 
-int unregister_device(const char *device)
+int unregister_device(const char *device, const char *uuid, int major, int minor,
+		   void **unused __attribute((unused)))
 {
-	if (!(--register_count)) {
-		dm_pool_destroy(mem_pool);
-		mem_pool = NULL;
+	pthread_mutex_lock(&_register_mutex);
+
+	syslog(LOG_INFO, "No longer monitoring mirror device %s for events\n",
+	       device);
+
+	if (!--_register_count) {
+		dm_pool_destroy(_mem_pool);
+		_mem_pool = NULL;
+		lvm2_run(_lvm_handle, "_memlock_dec");
+		lvm2_exit(_lvm_handle);
+		_lvm_handle = NULL;
 	}
 
-        return 1;
-}
+	pthread_mutex_unlock(&_register_mutex);
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
+	return 1;
+}

Modified: lvm2/upstream/current/doc/example.conf
==============================================================================
--- lvm2/upstream/current/doc/example.conf	(original)
+++ lvm2/upstream/current/doc/example.conf	Sat Apr  7 15:30:42 2007
@@ -56,10 +56,14 @@
     # filter = [ "a|^/dev/hda8$|", "r/.*/" ]
 
     # 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 safe to delete this file: the tools regenerate it.
-    cache = "/etc/lvm/.cache"
+    # rescanning dud devices (which can take a very long time).
+    # By default this cache is stored in the /etc/lvm/cache directory
+    # in a file called '.cache'.
+    # It is safe to delete the contents: the tools regenerate it.
+    # (The old setting 'cache' is still respected if neither of
+    # these new ones is present.)
+    cache_dir = "/etc/lvm/cache"
+    cache_file_prefix = ""
 
     # You can turn off writing this cache file by setting this to 0.
     write_cache_state = 1
@@ -79,6 +83,12 @@
     # software RAID (md) devices by looking for md superblocks.
     # 1 enables; 0 disables.
     md_component_detection = 1
+
+    # If, while scanning the system for PVs, LVM2 encounters a device-mapper
+    # device that has its I/O suspended, it waits for it to become accessible.
+    # Set this to 1 to skip such devices.  This should only be needed
+    # in recovery situations.
+    ignore_suspended_devices = 0
 }
 
 # This section that allows you to configure the nature of the
@@ -182,6 +192,9 @@
     # command.  Defaults to off.
     test = 0
 
+    # Default value for --units argument
+    units = "h"
+
     # 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.

Modified: lvm2/upstream/current/lib/activate/activate.c
==============================================================================
--- lvm2/upstream/current/lib/activate/activate.c	(original)
+++ lvm2/upstream/current/lib/activate/activate.c	Sat Apr  7 15:30:42 2007
@@ -141,7 +141,7 @@
 {
 	return 0;
 }
-int target_present(const char *target_name)
+int target_present(const char *target_name, int use_modprobe)
 {
 	return 0;
 }
@@ -168,6 +168,10 @@
 {
 	return 0;
 }
+int lvs_in_vg_activated_by_uuid_only(struct volume_group *vg);
+{
+	return 0;
+}
 int lvs_in_vg_opened(struct volume_group *vg)
 {
 	return 0;
@@ -211,7 +215,7 @@
 	return 1;
 }
 
-int pv_uses_vg(struct cmd_context *cmd, struct physical_volume *pv,
+int pv_uses_vg(struct physical_volume *pv,
 	       struct volume_group *vg)
 {
 	return 0;
@@ -421,21 +425,23 @@
  * Returns 1 if info structure populated, else 0 on failure.
  */
 static int _lv_info(struct cmd_context *cmd, const struct logical_volume *lv, int with_mknodes,
-		    struct lvinfo *info, int with_open_count)
+		    struct lvinfo *info, int with_open_count, unsigned by_uuid_only)
 {
 	struct dm_info dminfo;
-	char *name;
+	char *name = NULL;
 
 	if (!activation())
 		return 0;
 
-	if (!(name = build_dm_name(cmd->mem, lv->vg->name, lv->name, NULL)))
+	if (!by_uuid_only &&
+	    !(name = build_dm_name(cmd->mem, lv->vg->name, lv->name, NULL)))
 		return_0;
 
 	log_debug("Getting device info for %s", name);
 	if (!dev_manager_info(lv->vg->cmd->mem, name, lv, with_mknodes,
 			      with_open_count, &dminfo)) {
-		dm_pool_free(cmd->mem, name);
+		if (name)
+			dm_pool_free(cmd->mem, name);
 		return_0;
 	}
 
@@ -448,14 +454,16 @@
 	info->live_table = dminfo.live_table;
 	info->inactive_table = dminfo.inactive_table;
 
-	dm_pool_free(cmd->mem, name);
+	if (name)
+		dm_pool_free(cmd->mem, name);
+
 	return 1;
 }
 
 int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, struct lvinfo *info,
 	    int with_open_count)
 {
-	return _lv_info(cmd, lv, 0, info, with_open_count);
+	return _lv_info(cmd, lv, 0, info, with_open_count, 0);
 }
 
 int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s,
@@ -466,7 +474,7 @@
 	if (!(lv = lv_from_lvid(cmd, lvid_s, 0)))
 		return 0;
 
-	return _lv_info(cmd, lv, 0, info, with_open_count);
+	return _lv_info(cmd, lv, 0, info, with_open_count, 0);
 }
 
 /*
@@ -519,11 +527,12 @@
 	return r;
 }
 
-static int _lv_active(struct cmd_context *cmd, struct logical_volume *lv)
+static int _lv_active(struct cmd_context *cmd, struct logical_volume *lv,
+		      unsigned by_uuid_only)
 {
 	struct lvinfo info;
 
-	if (!lv_info(cmd, lv, &info, 0)) {
+	if (!_lv_info(cmd, lv, 0, &info, 0, by_uuid_only)) {
 		stack;
 		return -1;
 	}
@@ -607,7 +616,7 @@
  * These two functions return the number of visible LVs in the state,
  * or -1 on error.
  */
-int lvs_in_vg_activated(struct volume_group *vg)
+static int _lvs_in_vg_activated(struct volume_group *vg, unsigned by_uuid_only)
 {
 	struct lv_list *lvl;
 	int count = 0;
@@ -617,12 +626,22 @@
 
 	list_iterate_items(lvl, &vg->lvs) {
 		if (lvl->lv->status & VISIBLE_LV)
-			count += (_lv_active(vg->cmd, lvl->lv) == 1);
+			count += (_lv_active(vg->cmd, lvl->lv, by_uuid_only) == 1);
 	}
 
 	return count;
 }
 
+int lvs_in_vg_activated_by_uuid_only(struct volume_group *vg)
+{
+	return _lvs_in_vg_activated(vg, 1);
+}
+
+int lvs_in_vg_activated(struct volume_group *vg)
+{
+	return _lvs_in_vg_activated(vg, 0);
+}
+
 int lvs_in_vg_opened(struct volume_group *vg)
 {
 	struct lv_list *lvl;
@@ -640,50 +659,89 @@
 }
 
 /*
- * register_dev_for_events
- *
- * This function uses proper error codes (but breaks convention)
- * to return:
- *      -1 on error
- *       0 if the lv's targets don't do event [un]registration
- *       0 if the lv is already [un]registered -- FIXME: not implemented
- *       1 if the lv had a segment which was [un]registered
- *
- * Returns: -1 on error
+ * Returns 0 if an attempt to (un)monitor the device failed.
+ * Returns 1 otherwise.
  */
-int register_dev_for_events(struct cmd_context *cmd,
-			    struct logical_volume *lv, int do_reg)
+int monitor_dev_for_events(struct cmd_context *cmd,
+			    struct logical_volume *lv, int monitor)
 {
 #ifdef DMEVENTD
-	int r = 0;
+	int i, pending = 0, monitored;
+	int r = 1;
 	struct list *tmp;
 	struct lv_segment *seg;
-	int (*reg) (struct lv_segment *, int events);
+	int (*monitor_fn) (struct lv_segment *s, int e);
 
-	if (do_reg && !dmeventd_register_mode())
+	/* skip dmeventd code altogether */
+	if (dmeventd_monitor_mode() == DMEVENTD_MONITOR_IGNORE)
+		return 1;
+
+	/*
+	 * Nothing to do if dmeventd configured not to be used.
+	 */
+	if (monitor && !dmeventd_monitor_mode())
 		return 1;
 
 	list_iterate(tmp, &lv->segments) {
 		seg = list_item(tmp, struct lv_segment);
 
-		reg = NULL;
+		if (!seg_monitored(seg) || (seg->status & PVMOVE))
+			continue;
+
+		monitor_fn = NULL;
 
-		if (do_reg) {
-			if (seg->segtype->ops->target_register_events)
-				reg = seg->segtype->ops->target_register_events;
-		} else if (seg->segtype->ops->target_unregister_events)
-			reg = seg->segtype->ops->target_unregister_events;
+		/* Check monitoring status */
+		if (seg->segtype->ops->target_monitored)
+			monitored = seg->segtype->ops->target_monitored(seg, &pending);
+		else
+			continue;  /* segtype doesn't support registration */
+
+		/*
+		 * FIXME: We should really try again if pending
+		 */
+		monitored = (pending) ? 0 : monitored;
+
+		if (monitor) {
+			if (monitored)
+				log_verbose("%s/%s already monitored.", lv->vg->name, lv->name);
+			else if (seg->segtype->ops->target_monitor_events)
+				monitor_fn = seg->segtype->ops->target_monitor_events;
+		} else {
+			if (!monitored)
+				log_verbose("%s/%s already not monitored.", lv->vg->name, lv->name);
+			else if (seg->segtype->ops->target_unmonitor_events)
+				monitor_fn = seg->segtype->ops->target_unmonitor_events;
+		}
 
-		if (!reg)
+		/* Do [un]monitor */
+		if (!monitor_fn)
 			continue;
 
+		log_verbose("%sonitoring %s/%s", monitor ? "M" : "Not m", lv->vg->name, lv->name);
+
 		/* FIXME specify events */
-		if (!reg(seg, 0)) {
-			stack;
-			return -1;
+		if (!monitor_fn(seg, 0)) {
+			log_error("%s/%s: %s segment monitoring function failed.",
+				  lv->vg->name, lv->name, seg->segtype->name);
+			return 0;
+		}
+
+		/* Check [un]monitor results */
+		/* Try a couple times if pending, but not forever... */
+		for (i = 0; i < 10; i++) {
+			pending = 0;
+			monitored = seg->segtype->ops->target_monitored(seg, &pending);
+			if (pending ||
+			    (!monitored && monitor) ||
+			    (monitored && !monitor))
+				log_very_verbose("%s/%s %smonitoring still pending: waiting...",
+						 lv->vg->name, lv->name, monitor ? "" : "un");
+			else
+				break;
+			sleep(1);
 		}
 
-		r = 1;
+		r = (monitored && monitor) || (!monitored && !monitor);
 	}
 
 	return r;
@@ -728,7 +786,7 @@
 		}
 	}
 
-	if (register_dev_for_events(cmd, lv, 0) != 1)
+	if (!monitor_dev_for_events(cmd, lv, 0))
 		/* FIXME Consider aborting here */
 		stack;
 
@@ -786,7 +844,7 @@
 	memlock_dec();
 	fs_unlock();
 
-	if (register_dev_for_events(cmd, lv, 1) != 1)
+	if (!monitor_dev_for_events(cmd, lv, 1))
 		stack;
 
 	return 1;
@@ -832,7 +890,7 @@
 		return 0;
 	}
 
-	if (register_dev_for_events(cmd, lv, 0) != 1)
+	if (!monitor_dev_for_events(cmd, lv, 0))
 		stack;
 
 	memlock_inc();
@@ -905,7 +963,7 @@
 	memlock_dec();
 	fs_unlock();
 
-	if (!register_dev_for_events(cmd, lv, 1) != 1)
+	if (!monitor_dev_for_events(cmd, lv, 1))
 		stack;
 
 	return r;
@@ -934,7 +992,7 @@
 		return r;
 	}
 
-	if (!_lv_info(cmd, lv, 1, &info, 0))
+	if (!_lv_info(cmd, lv, 1, &info, 0, 0))
 		return_0;
 
 	if (info.exists)

Modified: lvm2/upstream/current/lib/activate/activate.h
==============================================================================
--- lvm2/upstream/current/lib/activate/activate.h	(original)
+++ lvm2/upstream/current/lib/activate/activate.h	Sat Apr  7 15:30:42 2007
@@ -83,10 +83,11 @@
  * Return number of LVs in the VG that are active.
  */
 int lvs_in_vg_activated(struct volume_group *vg);
+int lvs_in_vg_activated_by_uuid_only(struct volume_group *vg);
 int lvs_in_vg_opened(struct volume_group *vg);
 
 
-int register_dev_for_events(struct cmd_context *cmd,
+int monitor_dev_for_events(struct cmd_context *cmd,
 			    struct logical_volume *lv, int do_reg);
 
 /*
@@ -95,4 +96,9 @@
 int pv_uses_vg(struct physical_volume *pv,
 	       struct volume_group *vg);
 
+/*
+ * Returns 1 if mapped device is not suspended.
+ */
+int device_is_usable(dev_t dev);
+
 #endif

Modified: lvm2/upstream/current/lib/activate/dev_manager.c
==============================================================================
--- lvm2/upstream/current/lib/activate/dev_manager.c	(original)
+++ lvm2/upstream/current/lib/activate/dev_manager.c	Sat Apr  7 15:30:42 2007
@@ -25,6 +25,7 @@
 #include "targets.h"
 #include "config.h"
 #include "filter.h"
+#include "activate.h"
 
 #include <limits.h>
 #include <dirent.h>
@@ -117,12 +118,10 @@
 }
 
 static int _info_run(const char *name, const char *dlid, struct dm_info *info,
-		     int mknodes, int with_open_count, struct dm_pool *mem,
-		     char **uuid_out)
+		     int mknodes, int with_open_count)
 {
 	int r = 0;
 	struct dm_task *dmt;
-	const char *u;
 	int dmtask;
 
 	dmtask = mknodes ? DM_DEVICE_MKNODES : DM_DEVICE_INFO;
@@ -142,11 +141,58 @@
 	if (!dm_task_get_info(dmt, info))
 		goto_out;
 
-	if (info->exists && uuid_out) {
-		if (!(u = dm_task_get_uuid(dmt)))
-			goto_out;
-		*uuid_out = dm_pool_strdup(mem, u);
+	r = 1;
+
+      out:
+	dm_task_destroy(dmt);
+	return r;
+}
+
+int device_is_usable(dev_t dev)
+{
+	struct dm_task *dmt;
+	struct dm_info info;
+	const char *name;
+        uint64_t start, length;
+        char *target_type = NULL;
+        char *params;
+	void *next = NULL;
+	int r = 0;
+
+	if (!(dmt = dm_task_create(DM_DEVICE_STATUS))) {
+		log_error("Failed to allocate dm_task struct to check dev status");
+		return 0;
 	}
+
+	if (!dm_task_set_major(dmt, MAJOR(dev)) || !dm_task_set_minor(dmt, MINOR(dev)))
+		goto_out;
+
+	if (!dm_task_run(dmt)) {
+		log_error("Failed to get state of mapped device");
+		goto out;
+	}
+
+	if (!dm_task_get_info(dmt, &info))
+		goto_out;
+
+	if (!info.exists || info.suspended)
+		goto out;
+
+	name = dm_task_get_name(dmt);
+
+	/* FIXME Also check for mirror block_on_error and mpath no paths */
+	/* For now, we exclude all mirrors */
+
+        do {
+                next = dm_get_next_target(dmt, next, &start, &length,
+                                          &target_type, &params);
+                /* Skip if target type doesn't match */
+                if (!strcmp(target_type, "mirror"))
+			goto out;
+        } while (next);
+
+	/* FIXME Also check dependencies? */
+
 	r = 1;
 
       out:
@@ -155,23 +201,20 @@
 }
 
 static int _info(const char *name, const char *dlid, int mknodes,
-		 int with_open_count, struct dm_info *info,
-		 struct dm_pool *mem, char **uuid_out)
+		 int with_open_count, struct dm_info *info)
 {
 	if (!mknodes && dlid && *dlid) {
-		if (_info_run(NULL, dlid, info, 0, with_open_count, mem,
-			      uuid_out) &&
+		if (_info_run(NULL, dlid, info, 0, with_open_count) &&
 	    	    info->exists)
 			return 1;
 		else if (_info_run(NULL, dlid + sizeof(UUID_PREFIX) - 1, info,
-				   0, with_open_count, mem, uuid_out) &&
+				   0, with_open_count) &&
 			 info->exists)
 			return 1;
 	}
 
 	if (name)
-		return _info_run(name, NULL, info, mknodes, with_open_count,
-				 mem, uuid_out);
+		return _info_run(name, NULL, info, mknodes, with_open_count);
 
 	return 0;
 }
@@ -187,8 +230,7 @@
 		return 0;
 	}
 
-	return _info(name, dlid, with_mknodes, with_open_count, info,
-		     NULL, NULL);
+	return _info(name, dlid, with_mknodes, with_open_count, info);
 }
 
 /* FIXME Interface must cope with multiple targets */
@@ -593,7 +635,7 @@
 		return_0;
 
         log_debug("Getting device info for %s [%s]", name, dlid);
-        if (!_info(name, dlid, 0, 1, &info, dm->mem, NULL)) {
+        if (!_info(name, dlid, 0, 1, &info)) {
                 log_error("Failed to get info for %s [%s].", name, dlid);
                 return 0;
         }
@@ -782,12 +824,19 @@
 {
 	uint32_t s;
 	struct list *snh;
+	struct lv_segment *seg_present;
 
 	/* Ensure required device-mapper targets are loaded */
-	if (seg->segtype->ops->target_present &&
-	    !seg->segtype->ops->target_present()) {
+	seg_present = find_cow(seg->lv) ? : seg;
+
+	log_debug("Checking kernel supports %s segment type for %s%s%s",
+		  seg_present->segtype->name, seg->lv->name,
+		  layer ? "-" : "", layer ? : "");
+
+	if (seg_present->segtype->ops->target_present &&
+	    !seg_present->segtype->ops->target_present(seg_present)) {
 		log_error("Can't expand LV %s: %s target support missing "
-			  "from kernel?", seg->lv->name, seg->segtype->name);
+			  "from kernel?", seg->lv->name, seg_present->segtype->name);
 		return 0;
 	}
 
@@ -986,6 +1035,8 @@
 		break;
 	case SUSPEND:
 		dm_tree_skip_lockfs(root);
+		if ((lv->status & MIRRORED) && !(lv->status & PVMOVE))
+			dm_tree_use_no_flush_suspend(root);
 	case SUSPEND_WITH_LOCKFS:
 		if (!dm_tree_suspend_children(root, dlid, ID_LEN + sizeof(UUID_PREFIX) - 1))
 			goto_out;
@@ -1065,7 +1116,7 @@
 {
 	struct dm_tree *dtree;
 	struct dm_tree_node *root;
-	char dlid[sizeof(UUID_PREFIX) + sizeof(struct id) - 1];
+	char dlid[sizeof(UUID_PREFIX) + sizeof(struct id) - 1] __attribute((aligned(8)));
 	int r = 1;
 
 	if (!(dtree = dm_tree_create())) {

Modified: lvm2/upstream/current/lib/cache/lvmcache.c
==============================================================================
--- lvm2/upstream/current/lib/cache/lvmcache.c	(original)
+++ lvm2/upstream/current/lib/cache/lvmcache.c	Sat Apr  7 15:30:42 2007
@@ -114,7 +114,7 @@
 	struct list *devh, *tmp;
 	struct list devs;
 	struct device_list *devl;
-	char vgid_found[ID_LEN + 1];
+	char vgid_found[ID_LEN + 1] __attribute((aligned(8)));
 
 	if (!(vginfo = vginfo_from_vgname(vgname, vgid)))
 		return NULL;
@@ -151,7 +151,7 @@
 struct lvmcache_vginfo *vginfo_from_vgid(const char *vgid)
 {
 	struct lvmcache_vginfo *vginfo;
-	char id[ID_LEN + 1];
+	char id[ID_LEN + 1] __attribute((aligned(8)));
 
 	if (!_vgid_hash || !vgid)
 		return NULL;
@@ -186,7 +186,7 @@
 struct lvmcache_info *info_from_pvid(const char *pvid)
 {
 	struct lvmcache_info *info;
-	char id[ID_LEN + 1];
+	char id[ID_LEN + 1] __attribute((aligned(8)));
 
 	if (!_pvid_hash || !pvid)
 		return NULL;
@@ -476,7 +476,8 @@
 			  struct lvmcache_vginfo *primary_vginfo)
 {
 	struct lvmcache_vginfo *last_vginfo = primary_vginfo;
-	char uuid_primary[64], uuid_new[64];
+	char uuid_primary[64] __attribute((aligned(8)));
+	char uuid_new[64] __attribute((aligned(8)));
 	int use_new = 0;
 	
 	/* Pre-existing VG takes precedence. Unexported VG takes precedence. */
@@ -709,7 +710,7 @@
 {
 	struct pv_list *pvl;
 	struct lvmcache_info *info;
-	char pvid_s[ID_LEN + 1];
+	char pvid_s[ID_LEN + 1] __attribute((aligned(8)));
 
 	pvid_s[sizeof(pvid_s) - 1] = '\0';
 
@@ -733,7 +734,7 @@
 {
 	struct label *label;
 	struct lvmcache_info *existing, *info;
-	char pvid_s[ID_LEN + 1];
+	char pvid_s[ID_LEN + 1] __attribute((aligned(8)));
 
 	if (!_vgname_hash && !lvmcache_init()) {
 		log_error("Internal cache initialisation failed");

Modified: lvm2/upstream/current/lib/commands/toolcontext.c
==============================================================================
--- lvm2/upstream/current/lib/commands/toolcontext.c	(original)
+++ lvm2/upstream/current/lib/commands/toolcontext.c	Sat Apr  7 15:30:42 2007
@@ -59,8 +59,6 @@
 #  include <malloc.h>
 #endif
 
-static FILE *_log;
-
 static int _get_env_vars(struct cmd_context *cmd)
 {
 	const char *e;
@@ -330,7 +328,7 @@
 		return 0;
 	}
 
-	if (!(cfl->cft = create_config_tree(config_file))) {
+	if (!(cfl->cft = create_config_tree(config_file, 0))) {
 		log_error("config_tree allocation failed");
 		return 0;
 	}
@@ -370,7 +368,7 @@
 {
 	/* No config file if LVM_SYSTEM_DIR is empty */
 	if (!*cmd->sys_dir) {
-		if (!(cmd->cft = create_config_tree(NULL))) {
+		if (!(cmd->cft = create_config_tree(NULL, 0))) {
 			log_error("Failed to create config tree");
 			return 0;
 		}
@@ -408,7 +406,7 @@
 
 	/* Replace temporary duplicate copy of lvm.conf */
 	if (cmd->cft->root) {
-		if (!(cmd->cft = create_config_tree(NULL))) {
+		if (!(cmd->cft = create_config_tree(NULL, 0))) {
 			log_error("Failed to create config tree");
 			return 0;
 		}
@@ -575,9 +573,9 @@
 	    filters[0] : composite_filter_create(nr_filt, filters);
 }
 
-static int _init_filters(struct cmd_context *cmd)
+static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache)
 {
-	const char *dev_cache;
+	const char *dev_cache = NULL, *cache_dir, *cache_file_prefix;
 	struct dev_filter *f3, *f4;
 	struct stat st;
 	char cache_file[PATH_MAX];
@@ -587,16 +585,35 @@
 	if (!(f3 = _init_filter_components(cmd)))
 		return 0;
 
-	if (dm_snprintf(cache_file, sizeof(cache_file),
-			 "%s/.cache", cmd->sys_dir) < 0) {
-		log_error("Persistent cache filename too long ('%s/.cache').",
-			  cmd->sys_dir);
+	init_ignore_suspended_devices(find_config_tree_int(cmd,
+	    "devices/ignore_suspended_devices", DEFAULT_IGNORE_SUSPENDED_DEVICES));
+
+	/*
+	 * If 'cache_dir' or 'cache_file_prefix' is set, ignore 'cache'.
+	 */
+	cache_dir = find_config_tree_str(cmd, "devices/cache_dir", NULL);
+	cache_file_prefix = find_config_tree_str(cmd, "devices/cache_file_prefix", NULL);
+
+	if (cache_dir || cache_file_prefix) {
+		if (dm_snprintf(cache_file, sizeof(cache_file),
+		    "%s%s%s/%s.cache",
+		    cache_dir ? "" : cmd->sys_dir,
+		    cache_dir ? "" : "/",
+		    cache_dir ? : DEFAULT_CACHE_SUBDIR,
+		    cache_file_prefix ? : DEFAULT_CACHE_FILE_PREFIX) < 0) {
+			log_error("Persistent cache filename too long.");
+			return 0;
+		}
+	} else if (!(dev_cache = find_config_tree_str(cmd, "devices/cache", NULL)) &&
+		   (dm_snprintf(cache_file, sizeof(cache_file),
+				"%s/%s/%s.cache",
+				cmd->sys_dir, DEFAULT_CACHE_SUBDIR,
+				DEFAULT_CACHE_FILE_PREFIX) < 0)) {
+		log_error("Persistent cache filename too long.");
 		return 0;
 	}
 
-	dev_cache = find_config_tree_str(cmd, "devices/cache",
-				    cache_file);
-	if (!(f4 = persistent_filter_create(f3, dev_cache))) {
+	if (!(f4 = persistent_filter_create(f3, dev_cache ? : cache_file))) {
 		log_error("Failed to create persistent device filter");
 		return 0;
 	}
@@ -608,9 +625,14 @@
 	if (!*cmd->sys_dir)
 		cmd->dump_filter = 0;
 
-	if (!stat(dev_cache, &st) &&
-	    (st.st_mtime > config_file_timestamp(cmd->cft)) &&
-	    !persistent_filter_load(f4))
+	/*
+	 * Only load persistent filter device cache on startup if it is newer
+	 * than the config file and this is not a long-lived process.
+	 */
+	if (load_persistent_cache && !cmd->is_long_lived &&
+	    !stat(dev_cache, &st) &&
+	    (st.st_ctime > config_file_timestamp(cmd->cft)) &&
+	    !persistent_filter_load(f4, NULL))
 		log_verbose("Failed to load existing device cache from %s",
 			    dev_cache);
 
@@ -748,7 +770,6 @@
 		struct config_value *cv;
 		struct segment_type *(*init_segtype_fn) (struct cmd_context *);
 		void *lib;
-		struct list *sgtl, *tmp;
 		struct segment_type *segtype2;
 
 		for (cv = cn->v; cv; cv = cv->next) {
@@ -775,18 +796,16 @@
 			segtype->library = lib;
 			list_add(&cmd->segtypes, &segtype->list);
 
-			list_iterate_safe(sgtl, tmp, &cmd->segtypes) {
-				segtype2 = list_item(sgtl, struct segment_type);
-				if (!strcmp(segtype2->name, segtype->name)) {
-					log_error("Duplicate segment type %s: "
-						  "unloading shared library %s",
-						  segtype->name, cv->v.str);
-					list_del(&segtype->list);
-					segtype->ops->destroy(segtype);
-					dlclose(lib);
-					break;
-				}
-
+			list_iterate_items(segtype2, &cmd->segtypes) {
+				if ((segtype == segtype2) ||
+				     strcmp(segtype2->name, segtype->name))
+					continue;
+				log_error("Duplicate segment type %s: "
+					  "unloading shared library %s",
+					  segtype->name, cv->v.str);
+				list_del(&segtype->list);
+				segtype->ops->destroy(segtype);
+				dlclose(lib);
 			}
 		}
 	}
@@ -881,7 +900,8 @@
 }
 
 /* Entry point */
-struct cmd_context *create_toolcontext(struct arg *the_args, unsigned is_static)
+struct cmd_context *create_toolcontext(struct arg *the_args, unsigned is_static,
+				       unsigned is_long_lived)
 {
 	struct cmd_context *cmd;
 
@@ -905,6 +925,7 @@
 	memset(cmd, 0, sizeof(*cmd));
 	cmd->args = the_args;
 	cmd->is_static = is_static;
+	cmd->is_long_lived = is_long_lived;
 	cmd->hosttags = 0;
 	list_init(&cmd->formats);
 	list_init(&cmd->segtypes);
@@ -953,7 +974,7 @@
 	if (!_init_dev_cache(cmd))
 		goto error;
 
-	if (!_init_filters(cmd))
+	if (!_init_filters(cmd, 1))
 		goto error;
 
 	if (!(cmd->mem = dm_pool_create("command", 4 * 1024))) {
@@ -1022,10 +1043,10 @@
 {
 	log_verbose("Reloading config files");
 
-	if (cmd->config_valid) {
-		if (cmd->dump_filter)
-			persistent_filter_dump(cmd->filter);
-	}
+	/*
+	 * Don't update the persistent filter cache as we will
+	 * perform a full rescan.
+	 */
 
 	activation_release();
 	lvmcache_destroy();
@@ -1064,7 +1085,7 @@
 	if (!_init_dev_cache(cmd))
 		return 0;
 
-	if (!_init_filters(cmd))
+	if (!_init_filters(cmd, 0))
 		return 0;
 
 	if (!_init_formats(cmd))
@@ -1073,6 +1094,13 @@
 	if (!_init_segtypes(cmd))
 		return 0;
 
+	/*
+	 * If we are a long-lived process, write out the updated persistent
+	 * device cache for the benefit of short-lived processes.
+	 */
+	if (cmd->is_long_lived && cmd->dump_filter)
+		persistent_filter_dump(cmd->filter);
+
 	cmd->config_valid = 1;
 	return 1;
 }
@@ -1100,8 +1128,4 @@
 	activation_exit();
 	fin_log();
 	fin_syslog();
-
-	if (_log)
-		fclose(_log);
-
 }

Modified: lvm2/upstream/current/lib/commands/toolcontext.h
==============================================================================
--- lvm2/upstream/current/lib/commands/toolcontext.h	(original)
+++ lvm2/upstream/current/lib/commands/toolcontext.h	Sat Apr  7 15:30:42 2007
@@ -65,6 +65,7 @@
 	struct arg *args;
 	char **argv;
 	unsigned is_static;	/* Static binary? */
+	unsigned is_long_lived;	/* Optimises persistent_filter handling */
 
 	struct dev_filter *filter;
 	int dump_filter;	/* Dump filter when exiting? */
@@ -88,7 +89,7 @@
 	char proc_dir[PATH_MAX];
 };
 
-struct cmd_context *create_toolcontext(struct arg *the_args, unsigned is_static);
+struct cmd_context *create_toolcontext(struct arg *the_args, unsigned is_static, unsigned is_long_lived);
 void destroy_toolcontext(struct cmd_context *cmd);
 int refresh_toolcontext(struct cmd_context *cmd);
 int config_files_changed(struct cmd_context *cmd);

Modified: lvm2/upstream/current/lib/config/config.c
==============================================================================
--- lvm2/upstream/current/lib/config/config.c	(original)
+++ lvm2/upstream/current/lib/config/config.c	Sat Apr  7 15:30:42 2007
@@ -58,6 +58,8 @@
 	time_t timestamp;
 	char *filename;
 	int exists;
+	int keep_open;
+	struct device *dev;
 };
 
 static void _get_token(struct parser *p, int tok_prev);
@@ -95,7 +97,7 @@
 /*
  * public interface
  */
-struct config_tree *create_config_tree(const char *filename)
+struct config_tree *create_config_tree(const char *filename, int keep_open)
 {
 	struct cs *c;
 	struct dm_pool *mem = dm_pool_create("config", 10 * 1024);
@@ -115,6 +117,8 @@
 	c->cft.root = (struct config_node *) NULL;
 	c->timestamp = 0;
 	c->exists = 0;
+	c->keep_open = keep_open;
+	c->dev = 0;
 	if (filename)
 		c->filename = dm_pool_strdup(c->mem, filename);
 	return &c->cft;
@@ -122,7 +126,12 @@
 
 void destroy_config_tree(struct config_tree *cft)
 {
-	dm_pool_destroy(((struct cs *) cft)->mem);
+	struct cs *c = (struct cs *) cft;
+
+	if (c->dev)
+		dev_close(c->dev);
+
+	dm_pool_destroy(c->mem);
 }
 
 static int _parse_config_file(struct parser *p, struct config_tree *cft)
@@ -143,7 +152,7 @@
 	struct config_tree *cft;
 	struct parser *p;
 
-	if (!(cft = create_config_tree(NULL)))
+	if (!(cft = create_config_tree(NULL, 0)))
 		return_NULL;
 
 	c = (struct cs *) cft;
@@ -250,7 +259,6 @@
 {
 	struct cs *c = (struct cs *) cft;
 	struct stat info;
-	struct device *dev;
 	int r = 1;
 
 	if (stat(c->filename, &info)) {
@@ -272,22 +280,23 @@
 		return 1;
 	}
 
-	if (!(dev = dev_create_file(c->filename, NULL, NULL, 1))) {
-		stack;
-		return 0;
-	}
+	if (!c->dev) {
+		if (!(c->dev = dev_create_file(c->filename, NULL, NULL, 1)))
+			return_0;
 
-	if (!dev_open_flags(dev, O_RDONLY, 0, 0)) {
-		stack;
-		return 0;
+		if (!dev_open_flags(c->dev, O_RDONLY, 0, 0))
+			return_0;
 	}
 
-	r = read_config_fd(cft, dev, 0, (size_t) info.st_size, 0, 0,
+	r = read_config_fd(cft, c->dev, 0, (size_t) info.st_size, 0, 0,
 			   (checksum_fn_t) NULL, 0);
 
-	dev_close(dev);
+	if (!c->keep_open) {
+		dev_close(c->dev);
+		c->dev = 0;
+	}
 
-	c->timestamp = info.st_mtime;
+	c->timestamp = info.st_ctime;
 
 	return r;
 }
@@ -331,7 +340,7 @@
 	}
 
 	/* Unchanged? */
-	if (c->timestamp == info.st_mtime)
+	if (c->timestamp == info.st_ctime)
 		return 0;
 
       reload:
@@ -364,7 +373,8 @@
 	}
 }
 
-static int _write_config(struct config_node *n, FILE *fp, int level)
+static int _write_config(struct config_node *n, int only_one, FILE *fp,
+			 int level)
 {
 	char space[MAX_INDENT + 1];
 	int l = (level < MAX_INDENT) ? level : MAX_INDENT;
@@ -377,12 +387,12 @@
 		space[i] = '\t';
 	space[i] = '\0';
 
-	while (n) {
+	do {
 		fprintf(fp, "%s%s", space, n->key);
 		if (!n->v) {
 			/* it's a sub section */
 			fprintf(fp, " {\n");
-			_write_config(n->child, fp, level + 1);
+			_write_config(n->child, 0, fp, level + 1);
 			fprintf(fp, "%s}", space);
 		} else {
 			/* it's a value */
@@ -402,13 +412,15 @@
 		}
 		fprintf(fp, "\n");
 		n = n->sib;
-	}
+	} while (n && !only_one);
 	/* FIXME: add error checking */
 	return 1;
 }
 
-int write_config_file(struct config_tree *cft, const char *file)
+int write_config_file(struct config_tree *cft, const char *file,
+		      int argc, char **argv)
 {
+	struct config_node *cn;
 	int r = 1;
 	FILE *fp;
 
@@ -421,13 +433,28 @@
 	}
 
 	log_verbose("Dumping configuration to %s", file);
-	if (!_write_config(cft->root, fp, 0)) {
-		log_error("Failure while writing configuration");
-		r = 0;
+	if (!argc) {
+		if (!_write_config(cft->root, 0, fp, 0)) {
+			log_error("Failure while writing to %s", file);
+			r = 0;
+		}
+	} else while (argc--) {
+		if ((cn = find_config_node(cft->root, *argv))) {
+			if (!_write_config(cn, 1, fp, 0)) {
+				log_error("Failure while writing to %s", file);
+				r = 0;
+			}
+		} else {
+			log_error("Configuration node %s not found", *argv);
+			r = 0;
+		}
+		argv++;
 	}
 
-	if (fp != stdout)
-		fclose(fp);
+	if ((fp != stdout) && fclose(fp)) {
+		log_sys_error("fclose", file);
+		r = 0;
+	}
 
 	return r;
 }
@@ -763,6 +790,7 @@
 					     const char *path)
 {
 	const char *e;
+	const struct config_node *cn_found = NULL;
 
 	while (cn) {
 		/* trim any leading slashes */
@@ -773,22 +801,30 @@
 		for (e = path; *e && (*e != sep); e++) ;
 
 		/* hunt for the node */
+		cn_found = NULL;
 		while (cn) {
-			if (_tok_match(cn->key, path, e))
-				break;
+			if (_tok_match(cn->key, path, e)) {
+				/* Inefficient */
+				if (!cn_found)
+					cn_found = cn;
+				else
+					log_error("WARNING: Ignoring duplicate"
+						  " config node: %s ("
+						  "seeking %s)", cn->key, path);
+			}
 
 			cn = cn->sib;
 		}
 
-		if (cn && *e)
-			cn = cn->child;
+		if (cn_found && *e)
+			cn = cn_found->child;
 		else
 			break;	/* don't move into the last node */
 
 		path = e;
 	}
 
-	return (struct config_node *) cn;
+	return (struct config_node *) cn_found;
 }
 
 static struct config_node *_find_first_config_node(const struct config_node *cn1,
@@ -819,7 +855,7 @@
 	const struct config_node *n = _find_first_config_node(cn1, cn2, path);
 
 	/* Empty strings are ignored */
-	if ((n && n->v->type == CFG_STRING) && (*n->v->v.str)) {
+	if ((n && n->v && n->v->type == CFG_STRING) && (*n->v->v.str)) {
 		log_very_verbose("Setting %s to %s", path, n->v->v.str);
 		return n->v->v.str;
 	}
@@ -842,7 +878,7 @@
 {
 	const struct config_node *n = _find_first_config_node(cn1, cn2, path);
 
-	if (n && n->v->type == CFG_INT) {
+	if (n && n->v && n->v->type == CFG_INT) {
 		log_very_verbose("Setting %s to %d", path, n->v->v.i);
 		return n->v->v.i;
 	}
@@ -863,7 +899,7 @@
 {
 	const struct config_node *n = _find_first_config_node(cn1, cn2, path);
 
-	if (n && n->v->type == CFG_FLOAT) {
+	if (n && n->v && n->v->type == CFG_FLOAT) {
 		log_very_verbose("Setting %s to %f", path, n->v->v.r);
 		return n->v->v.r;
 	}

Modified: lvm2/upstream/current/lib/config/config.h
==============================================================================
--- lvm2/upstream/current/lib/config/config.h	(original)
+++ lvm2/upstream/current/lib/config/config.h	Sat Apr  7 15:30:42 2007
@@ -53,7 +53,7 @@
 	struct config_tree *cft;
 };
 
-struct config_tree *create_config_tree(const char *filename);
+struct config_tree *create_config_tree(const char *filename, int keep_open);
 struct config_tree *create_config_tree_from_string(struct cmd_context *cmd,
 						   const char *config_settings);
 void destroy_config_tree(struct config_tree *cft);
@@ -65,7 +65,8 @@
 		   checksum_fn_t checksum_fn, uint32_t checksum);
 
 int read_config_file(struct config_tree *cft);
-int write_config_file(struct config_tree *cft, const char *file);
+int write_config_file(struct config_tree *cft, const char *file,
+		      int argc, char **argv);
 time_t config_file_timestamp(struct config_tree *cft);
 int config_file_changed(struct config_tree *cft);
 int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft,

Modified: lvm2/upstream/current/lib/config/defaults.h
==============================================================================
--- lvm2/upstream/current/lib/config/defaults.h	(original)
+++ lvm2/upstream/current/lib/config/defaults.h	Sat Apr  7 15:30:42 2007
@@ -21,6 +21,8 @@
 
 #define DEFAULT_ARCHIVE_SUBDIR "archive"
 #define DEFAULT_BACKUP_SUBDIR "backup"
+#define DEFAULT_CACHE_SUBDIR "cache"
+#define DEFAULT_CACHE_FILE_PREFIX ""
 
 #define DEFAULT_ARCHIVE_DAYS 30
 #define DEFAULT_ARCHIVE_NUMBER 10
@@ -30,6 +32,7 @@
 #define DEFAULT_PROC_DIR "/proc"
 #define DEFAULT_SYSFS_SCAN 1
 #define DEFAULT_MD_COMPONENT_DETECTION 1
+#define DEFAULT_IGNORE_SUSPENDED_DEVICES 1
 
 #define DEFAULT_LOCK_DIR "/var/lock/lvm"
 #define DEFAULT_LOCKING_LIB "liblvm2clusterlock.so"

Modified: lvm2/upstream/current/lib/device/dev-io.c
==============================================================================
--- lvm2/upstream/current/lib/device/dev-io.c	(original)
+++ lvm2/upstream/current/lib/device/dev-io.c	Sat Apr  7 15:30:42 2007
@@ -292,11 +292,14 @@
 
 	if (ioctl(fd, BLKSSZGET, &s) < 0) {
 		log_sys_error("ioctl BLKSSZGET", name);
-		close(fd);
+		if (close(fd))
+			log_sys_error("close", name);
 		return 0;
 	}
 
-	close(fd);
+	if (close(fd))
+		log_sys_error("close", name);
+
 	*size = (uint32_t) s;
 
 	log_very_verbose("%s: sector size is %" PRIu32 " bytes", name, *size);
@@ -605,7 +608,7 @@
 int dev_set(struct device *dev, uint64_t offset, size_t len, int value)
 {
 	size_t s;
-	char buffer[4096];
+	char buffer[4096] __attribute((aligned(8)));
 
 	if (!dev_open(dev)) {
 		stack;

Modified: lvm2/upstream/current/lib/device/dev-md.c
==============================================================================
--- lvm2/upstream/current/lib/device/dev-md.c	(original)
+++ lvm2/upstream/current/lib/device/dev-md.c	Sat Apr  7 15:30:42 2007
@@ -53,8 +53,10 @@
 	sb_offset = MD_NEW_SIZE_SECTORS(size) << SECTOR_SHIFT;
 
 	/* Check if it is an md component device. */
+	/* Version 1 is little endian; version 0.90.0 is machine endian */
 	if (dev_read(dev, sb_offset, sizeof(uint32_t), &md_magic) &&
-	    (md_magic == xlate32(MD_SB_MAGIC))) {
+	    ((md_magic == xlate32(MD_SB_MAGIC)) ||
+	     (md_magic == MD_SB_MAGIC))) {
 		if (sb)
 			*sb = sb_offset;
 		ret = 1;

Modified: lvm2/upstream/current/lib/device/device.c
==============================================================================
--- lvm2/upstream/current/lib/device/device.c	(original)
+++ lvm2/upstream/current/lib/device/device.c	Sat Apr  7 15:30:42 2007
@@ -53,7 +53,7 @@
 {
 	int ret = 0;
 	unsigned p;
-	uint8_t buf[SECTOR_SIZE];
+	uint16_t buf[SECTOR_SIZE/sizeof(uint16_t)];
 	uint16_t *part_magic;
 	struct partition *part;
 
@@ -70,9 +70,9 @@
 	/* FIXME Check for other types of partition table too */
 
 	/* Check for msdos partition table */
-	part_magic = (uint16_t *)(buf + PART_MAGIC_OFFSET);
+	part_magic = buf + PART_MAGIC_OFFSET/sizeof(buf[0]);
 	if ((*part_magic == xlate16(PART_MAGIC))) {
-		part = (struct partition *) (buf + PART_OFFSET);
+		part = (struct partition *) (buf + PART_OFFSET/sizeof(buf[0]));
 		for (p = 0; p < 4; p++, part++) {
 			/* Table is invalid if boot indicator not 0 or 0x80 */
 			if ((part->boot_ind & 0x7f)) {

Modified: lvm2/upstream/current/lib/display/display.c
==============================================================================
--- lvm2/upstream/current/lib/display/display.c	(original)
+++ lvm2/upstream/current/lib/display/display.c	Sat Apr  7 15:30:42 2007
@@ -82,6 +82,12 @@
 	case 't':
 		v *= KILO * KILO * KILO * KILO;
 		break;
+	case 'p':
+		v *= KILO * KILO * KILO * KILO * KILO;
+		break;
+	case 'e':
+		v *= KILO * KILO * KILO * KILO * KILO * KILO;
+		break;
 #undef KILO
 #define KILO UINT64_C(1000)
 	case 'K':
@@ -96,6 +102,12 @@
 	case 'T':
 		v *= KILO * KILO * KILO * KILO;
 		break;
+	case 'P':
+		v *= KILO * KILO * KILO * KILO * KILO;
+		break;
+	case 'E':
+		v *= KILO * KILO * KILO * KILO * KILO * KILO;
+		break;
 #undef KILO
 	default:
 		return 0;
@@ -143,6 +155,8 @@
 	uint64_t units = UINT64_C(1024);
 	char *size_buf = NULL;
 	const char *size_str[][3] = {
+		{" Exabyte", " EB", "E"},
+		{" Petabyte", " PB", "P"},
 		{" Terabyte", " TB", "T"},
 		{" Gigabyte", " GB", "G"},
 		{" Megabyte", " MB", "M"},
@@ -161,7 +175,7 @@
 
 	suffix = cmd->current_settings.suffix;
 
-	for (s = 0; s < 8; s++)
+	for (s = 0; s < 10; s++)
 		if (toupper((int) cmd->current_settings.unit_type) ==
 		    *size_str[s][2])
 			break;
@@ -171,7 +185,7 @@
 		return size_buf;
 	}
 
-	if (s < 8) {
+	if (s < 10) {
 		byte = cmd->current_settings.unit_factor;
 		size *= UINT64_C(512);
 	} else {
@@ -181,7 +195,7 @@
 			units = UINT64_C(1000);
 		else
 			units = UINT64_C(1024);
-		byte = units * units * units;
+		byte = units * units * units * units * units;
 		s = 0;
 		while (size_str[s] && size < byte)
 			s++, byte /= units;
@@ -220,7 +234,7 @@
 
 void pvdisplay_colons(struct physical_volume *pv)
 {
-	char uuid[64];
+	char uuid[64] __attribute((aligned(8)));
 
 	if (!pv)
 		return;
@@ -248,7 +262,7 @@
 void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv,
 		    void *handle __attribute((unused)))
 {
-	char uuid[64];
+	char uuid[64] __attribute((aligned(8)));
 	const char *size;
 
 	uint32_t pe_free;
@@ -310,7 +324,7 @@
 		    struct physical_volume *pv,
 		    void *handle __attribute((unused)))
 {
-	char uuid[64];
+	char uuid[64] __attribute((aligned(8)));
 
 	if (!pv)
 		return 0;
@@ -357,7 +371,7 @@
 {
 	struct lvinfo info;
 	int inkernel, snap_active = 0;
-	char uuid[64];
+	char uuid[64] __attribute((aligned(8)));
 	struct lv_segment *snap_seg = NULL;
 	float snap_percent;	/* fused, fsize; */
 
@@ -523,7 +537,7 @@
 {
 	uint32_t access;
 	uint32_t active_pvs;
-	char uuid[64];
+	char uuid[64] __attribute((aligned(8)));
 
 	if (vg->status & PARTIAL_VG)
 		active_pvs = list_size(&vg->pvs);
@@ -602,7 +616,7 @@
 {
 	uint32_t active_pvs;
 	const char *access;
-	char uuid[64];
+	char uuid[64] __attribute((aligned(8)));
 
 	if (vg->status & PARTIAL_VG)
 		active_pvs = list_size(&vg->pvs);

Modified: lvm2/upstream/current/lib/error/errseg.c
==============================================================================
--- lvm2/upstream/current/lib/error/errseg.c	(original)
+++ lvm2/upstream/current/lib/error/errseg.c	Sat Apr  7 15:30:42 2007
@@ -50,7 +50,7 @@
 	return dm_tree_node_add_error_target(node, len);
 }
 
-static int _errseg_target_present(void)
+static int _errseg_target_present(const struct lv_segment *seg __attribute((unused)))
 {
 	static int _errseg_checked = 0;
 	static int _errseg_present = 0;

Modified: lvm2/upstream/current/lib/filters/filter-persistent.c
==============================================================================
--- lvm2/upstream/current/lib/filters/filter-persistent.c	(original)
+++ lvm2/upstream/current/lib/filters/filter-persistent.c	Sat Apr  7 15:30:42 2007
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.  
- * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -17,6 +17,7 @@
 #include "config.h"
 #include "dev-cache.h"
 #include "filter-persistent.h"
+#include "lvm-file.h"
 
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -26,11 +27,12 @@
 	char *file;
 	struct dm_hash_table *devices;
 	struct dev_filter *real;
+	time_t ctime;
 };
 
 /*
- * entries in the table can be in one of these
- * states.
+ * The hash table holds one of these two states
+ * against each entry.
  */
 #define PF_BAD_DEVICE ((void *) 1)
 #define PF_GOOD_DEVICE ((void *) 2)
@@ -93,22 +95,26 @@
 	return 1;
 }
 
-int persistent_filter_load(struct dev_filter *f)
+int persistent_filter_load(struct dev_filter *f, struct config_tree **cft_out)
 {
 	struct pfilter *pf = (struct pfilter *) f->private;
-
-	int r = 0;
 	struct config_tree *cft;
+        struct stat info;
+	int r = 0;
 
-	if (!(cft = create_config_tree(pf->file))) {
-		stack;
-		return 0;
+        if (!stat(pf->file, &info))
+		pf->ctime = info.st_ctime;
+	else {
+                log_very_verbose("%s: stat failed: %s", pf->file,
+				 strerror(errno));
+		return_0;
 	}
 
-	if (!read_config_file(cft)) {
-		stack;
-		goto out;
-	}
+	if (!(cft = create_config_tree(pf->file, 1)))
+		return_0;
+
+	if (!read_config_file(cft))
+		goto_out;
 
 	_read_array(pf, cft, "persistent_filter_cache/valid_devices",
 		    PF_GOOD_DEVICE);
@@ -126,7 +132,10 @@
 	log_very_verbose("Loaded persistent filter cache from %s", pf->file);
 
       out:
-	destroy_config_tree(cft);
+	if (r && cft_out)
+		*cft_out = cft;
+	else
+		destroy_config_tree(cft);
 	return r;
 }
 
@@ -163,8 +172,12 @@
 int persistent_filter_dump(struct dev_filter *f)
 {
 	struct pfilter *pf = (struct pfilter *) f->private;
-
+	char *tmp_file;
+	struct stat info, info2;
+	struct config_tree *cft = NULL;
 	FILE *fp;
+	int lockfd;
+	int r = 0;
 
 	if (!dm_hash_get_num_entries(pf->devices)) {
 		log_very_verbose("Internal persistent device cache empty "
@@ -179,11 +192,43 @@
 
 	log_very_verbose("Dumping persistent device cache to %s", pf->file);
 
-	fp = fopen(pf->file, "w");
-	if (!fp) {
-		if (errno != EROFS)
-			log_sys_error("fopen", pf->file);
-		return 0;
+	while (1) {
+		if ((lockfd = fcntl_lock_file(pf->file, F_WRLCK, 0)) < 0)
+			return_0;
+
+		/*
+		 * Ensure we locked the file we expected
+		 */
+		if (fstat(lockfd, &info)) {
+			log_sys_error("fstat", pf->file);
+			goto out;
+		}
+		if (stat(pf->file, &info2)) {
+			log_sys_error("stat", pf->file);
+			goto out;
+		}
+
+		if (!memcmp(&info.st_ino, &info2.st_ino, sizeof(ino_t)))
+			break;
+	
+		fcntl_unlock_file(lockfd);
+	}
+
+	/*
+	 * If file contents changed since we loaded it, merge new contents
+	 */
+	if (info.st_ctime != pf->ctime)
+		/* Keep cft open to avoid losing lock */
+		persistent_filter_load(f, &cft);
+
+	tmp_file = alloca(strlen(pf->file) + 5);
+	sprintf(tmp_file, "%s.tmp", pf->file);
+
+	if (!(fp = fopen(tmp_file, "w"))) {
+		/* EACCES has been reported over NFS */
+		if (errno != EROFS && errno != EACCES)
+			log_sys_error("fopen", tmp_file);
+		goto out;
 	}
 
 	fprintf(fp, "# This file is automatically maintained by lvm.\n\n");
@@ -194,8 +239,24 @@
 	/* _write_array(pf, fp, "invalid_devices", PF_BAD_DEVICE); */
 
 	fprintf(fp, "}\n");
-	fclose(fp);
-	return 1;
+	if (fclose(fp)) {
+		log_sys_error("fclose", tmp_file);
+		goto out;
+	}
+
+	if (rename(tmp_file, pf->file))
+		log_error("%s: rename to %s failed: %s", tmp_file, pf->file,
+			  strerror(errno));
+
+	r = 1;
+
+out:
+	fcntl_unlock_file(lockfd);
+
+	if (cft)
+		destroy_config_tree(cft);
+
+	return r;
 }
 
 static int _lookup_p(struct dev_filter *f, struct device *dev)

Modified: lvm2/upstream/current/lib/filters/filter-persistent.h
==============================================================================
--- lvm2/upstream/current/lib/filters/filter-persistent.h	(original)
+++ lvm2/upstream/current/lib/filters/filter-persistent.h	Sat Apr  7 15:30:42 2007
@@ -22,7 +22,7 @@
 					    const char *file);
 
 int persistent_filter_wipe(struct dev_filter *f);
-int persistent_filter_load(struct dev_filter *f);
+int persistent_filter_load(struct dev_filter *f, struct config_tree **cft_out);
 int persistent_filter_dump(struct dev_filter *f);
 
 #endif

Modified: lvm2/upstream/current/lib/filters/filter-sysfs.c
==============================================================================
--- lvm2/upstream/current/lib/filters/filter-sysfs.c	(original)
+++ lvm2/upstream/current/lib/filters/filter-sysfs.c	Sat Apr  7 15:30:42 2007
@@ -54,7 +54,9 @@
 		}
 	}
 
-	fclose(fp);
+	if (fclose(fp))
+		log_sys_error("fclose", proc_mounts);
+
 	return r;
 }
 
@@ -156,7 +158,9 @@
 	}
 
 	r = _parse_dev(file, fp, result);
-	fclose(fp);
+
+	if (fclose(fp))
+		log_sys_error("fclose", file);
 
 	return r;
 }

Modified: lvm2/upstream/current/lib/filters/filter.c
==============================================================================
--- lvm2/upstream/current/lib/filters/filter.c	(original)
+++ lvm2/upstream/current/lib/filters/filter.c	Sat Apr  7 15:30:42 2007
@@ -19,6 +19,7 @@
 #include "lvm-string.h"
 #include "config.h"
 #include "metadata.h"
+#include "activate.h"
 
 #include <dirent.h>
 #include <unistd.h>
@@ -37,6 +38,7 @@
 } device_info_t;
 
 static int _md_major = -1;
+static int _device_mapper_major = -1;
 
 int md_major(void)
 {
@@ -90,6 +92,13 @@
 		return 0;
 	}
 
+	/* Skip suspended devices */
+	if (MAJOR(dev->dev) == _device_mapper_major &&
+	    ignore_suspended_devices() && !device_is_usable(dev->dev)) {
+		log_debug("%s: Skipping: Suspended dm device", name);
+		return 0;
+	}
+
 	/* Check it's accessible */
 	if (!dev_open_flags(dev, O_RDONLY, 0, 1)) {
 		log_debug("%s: Skipping: open failed", name);
@@ -182,10 +191,14 @@
 		if (!strncmp("md", line + i, 2) && isspace(*(line + i + 2)))
 			_md_major = line_maj;
 
+		/* Look for device-mapper device */
+		/* FIXME Cope with multiple majors */
+		if (!strncmp("device-mapper", line + i, 13) && isspace(*(line + i + 13)))
+			_device_mapper_major = line_maj;
+
 		/* Go through the valid device names and if there is a
 		   match store max number of partitions */
 		for (j = 0; device_info[j].name != NULL; j++) {
-
 			dev_len = strlen(device_info[j].name);
 			if (dev_len <= strlen(line + i) &&
 			    !strncmp(device_info[j].name, line + i, dev_len) &&
@@ -204,7 +217,8 @@
 			if (cv->type != CFG_STRING) {
 				log_error("Expecting string in devices/types "
 					  "in config file");
-				fclose(pd);
+				if (fclose(pd))
+					log_sys_error("fclose", proc_devices);
 				return 0;
 			}
 			dev_len = strlen(cv->v.str);
@@ -214,14 +228,16 @@
 				log_error("Max partition count missing for %s "
 					  "in devices/types in config file",
 					  name);
-				fclose(pd);
+				if (fclose(pd))
+					log_sys_error("fclose", proc_devices);
 				return 0;
 			}
 			if (!cv->v.i) {
 				log_error("Zero partition count invalid for "
 					  "%s in devices/types in config file",
 					  name);
-				fclose(pd);
+				if (fclose(pd))
+					log_sys_error("fclose", proc_devices);
 				return 0;
 			}
 			if (dev_len <= strlen(line + i) &&
@@ -232,7 +248,10 @@
 			}
 		}
 	}
-	fclose(pd);
+
+	if (fclose(pd))
+		log_sys_error("fclose", proc_devices);
+
 	return 1;
 }
 

Modified: lvm2/upstream/current/lib/format1/disk-rep.c
==============================================================================
--- lvm2/upstream/current/lib/format1/disk-rep.c	(original)
+++ lvm2/upstream/current/lib/format1/disk-rep.c	Sat Apr  7 15:30:42 2007
@@ -248,7 +248,7 @@
 {
 	unsigned num_read = 0;
 	struct uuid_list *ul;
-	char buffer[NAME_LEN];
+	char buffer[NAME_LEN] __attribute((aligned(8)));
 	uint64_t pos = data->pvd.pv_uuidlist_on_disk.base;
 	uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size;
 

Modified: lvm2/upstream/current/lib/format1/disk-rep.h
==============================================================================
--- lvm2/upstream/current/lib/format1/disk-rep.h	(original)
+++ lvm2/upstream/current/lib/format1/disk-rep.h	Sat Apr  7 15:30:42 2007
@@ -148,7 +148,7 @@
 
 struct uuid_list {
 	struct list list;
-	char uuid[NAME_LEN];
+	char uuid[NAME_LEN] __attribute((aligned(8)));
 };
 
 struct lvd_list {
@@ -161,11 +161,11 @@
 	struct dm_pool *mem;
 	struct device *dev;
 
-	struct pv_disk pvd;
-	struct vg_disk vgd;
-	struct list uuids;
-	struct list lvds;
-	struct pe_disk *extents;
+	struct pv_disk pvd __attribute((aligned(8)));
+	struct vg_disk vgd __attribute((aligned(8)));
+	struct list uuids __attribute((aligned(8)));
+	struct list lvds __attribute((aligned(8)));
+	struct pe_disk *extents __attribute((aligned(8)));
 };
 
 /*
@@ -203,8 +203,8 @@
  * Functions to translate to between disk and in
  * core structures.
  */
-int import_pv(struct dm_pool *mem, struct device *dev,
-	      struct volume_group *vg,
+int import_pv(const struct format_type *fmt, struct dm_pool *mem,
+	      struct device *dev, struct volume_group *vg,
 	      struct physical_volume *pv, struct pv_disk *pvd,
 	      struct vg_disk *vgd);
 int export_pv(struct cmd_context *cmd, struct dm_pool *mem,

Modified: lvm2/upstream/current/lib/format1/format1.c
==============================================================================
--- lvm2/upstream/current/lib/format1/format1.c	(original)
+++ lvm2/upstream/current/lib/format1/format1.c	Sat Apr  7 15:30:42 2007
@@ -312,7 +312,7 @@
 		goto out;
 	}
 
-	if (!import_pv(fmt->cmd->mem, dl->dev, NULL, pv, &dl->pvd, &dl->vgd)) {
+	if (!import_pv(fmt, fmt->cmd->mem, dl->dev, NULL, pv, &dl->pvd, &dl->vgd)) {
 		stack;
 		goto out;
 	}

Modified: lvm2/upstream/current/lib/format1/import-export.c
==============================================================================
--- lvm2/upstream/current/lib/format1/import-export.c	(original)
+++ lvm2/upstream/current/lib/format1/import-export.c	Sat Apr  7 15:30:42 2007
@@ -24,6 +24,7 @@
 #include "toolcontext.h"
 #include "segtype.h"
 #include "pv_alloc.h"
+#include "display.h"
 
 #include <time.h>
 
@@ -47,11 +48,13 @@
 	return dm_pool_strdup(mem, ptr);
 }
 
-int import_pv(struct dm_pool *mem, struct device *dev,
-	      struct volume_group *vg,
+int import_pv(const struct format_type *fmt, struct dm_pool *mem,
+	      struct device *dev, struct volume_group *vg,
 	      struct physical_volume *pv, struct pv_disk *pvd,
 	      struct vg_disk *vgd)
 {
+	uint64_t size;
+
 	memset(pv, 0, sizeof(*pv));
 	memcpy(&pv->id, pvd->pv_uuid, ID_LEN);
 
@@ -89,6 +92,25 @@
 	pv->pe_count = pvd->pe_total;
 	pv->pe_alloc_count = 0;
 
+	/* Fix up pv size if missing */
+	if (!pv->size) {
+		if (!dev_get_size(dev, &pv->size)) {
+			log_error("%s: Couldn't get size.", dev_name(pv->dev));
+			return 0;
+		}
+		log_verbose("Fixing up missing format1 size (%s) "
+			    "for PV %s", display_size(fmt->cmd, pv->size),
+			    dev_name(pv->dev));
+		if (vg) {
+			size = pv->pe_count * (uint64_t) vg->extent_size +
+			       pv->pe_start;
+			if (size > pv->size)
+				log_error("WARNING: Physical Volume %s is too "
+					  "large for underlying device",
+					  dev_name(pv->dev));
+		}
+	}
+
 	list_init(&pv->tags);
 	list_init(&pv->segments);
 
@@ -427,7 +449,7 @@
 			return 0;
 		}
 
-		if (!import_pv(mem, dl->dev, vg, pvl->pv, &dl->pvd, &dl->vgd)) {
+		if (!import_pv(fmt, mem, dl->dev, vg, pvl->pv, &dl->pvd, &dl->vgd)) {
 			stack;
 			return 0;
 		}

Modified: lvm2/upstream/current/lib/format1/import-extents.c
==============================================================================
--- lvm2/upstream/current/lib/format1/import-extents.c	(original)
+++ lvm2/upstream/current/lib/format1/import-extents.c	Sat Apr  7 15:30:42 2007
@@ -203,6 +203,19 @@
 	return 1;
 }
 
+static uint32_t _area_length(struct lv_map *lvm, uint32_t le)
+{
+	uint32_t len = 0;
+
+	do
+		len++;
+	while ((lvm->map[le + len].pv == lvm->map[le].pv) &&
+		 (lvm->map[le].pv &&
+		  lvm->map[le + len].pe == lvm->map[le].pe + len));
+
+	return len;
+}
+
 static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
 {
 	uint32_t le = 0, len;
@@ -215,13 +228,7 @@
 	}
 
 	while (le < lvm->lv->le_count) {
-		len = 0;
-
-		do
-			len++;
-		while ((lvm->map[le + len].pv == lvm->map[le].pv) &&
-			 (lvm->map[le].pv &&
-			  lvm->map[le + len].pe == lvm->map[le].pe + len));
+		len = _area_length(lvm, le);
 
 		if (!(seg = alloc_lv_segment(cmd->mem, segtype, lvm->lv, le,
 					     len, 0, 0, NULL, 1, len, 0, 0, 0))) {
@@ -230,10 +237,8 @@
 		}
 
 		if (!set_lv_segment_area_pv(seg, 0, lvm->map[le].pv,
-					    lvm->map[le].pe)) {
-			stack;
-			return 0;
-		}
+					    lvm->map[le].pe))
+			return_0;
 
 		list_add(&lvm->lv->segments, &seg->list);
 
@@ -244,7 +249,8 @@
 }
 
 static int _check_stripe(struct lv_map *lvm, uint32_t area_count,
-			 uint32_t seg_len, uint32_t base_le, uint32_t len)
+			 uint32_t area_len, uint32_t base_le,
+			 uint32_t total_area_len)
 {
 	uint32_t st;
 
@@ -252,11 +258,11 @@
 	 * Is the next physical extent in every stripe adjacent to the last?
 	 */
 	for (st = 0; st < area_count; st++)
-		if ((lvm->map[base_le + st * len + seg_len].pv !=
-		     lvm->map[base_le + st * len].pv) ||
-		    (lvm->map[base_le + st * len].pv &&
-		     lvm->map[base_le + st * len + seg_len].pe !=
-		     lvm->map[base_le + st * len].pe + seg_len))
+		if ((lvm->map[base_le + st * total_area_len + area_len].pv !=
+		     lvm->map[base_le + st * total_area_len].pv) ||
+		    (lvm->map[base_le + st * total_area_len].pv &&
+		     lvm->map[base_le + st * total_area_len + area_len].pe !=
+		     lvm->map[base_le + st * total_area_len].pe + area_len))
 			return 0;
 
 	return 1;
@@ -264,7 +270,7 @@
 
 static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
 {
-	uint32_t st, le = 0, len;
+	uint32_t st, first_area_le = 0, total_area_len;
 	uint32_t area_len;
 	struct lv_segment *seg;
 	struct segment_type *segtype;
@@ -277,26 +283,25 @@
 			  "with logical extent count (%u) for %s",
 			  lvm->stripes, lvm->lv->le_count, lvm->lv->name);
 	}
-	len = lvm->lv->le_count / lvm->stripes;
 
-	if (!(segtype = get_segtype_from_string(cmd, "striped"))) {
-		stack;
-		return 0;
-	}
+	total_area_len = lvm->lv->le_count / lvm->stripes;
+
+	if (!(segtype = get_segtype_from_string(cmd, "striped")))
+		return_0;
 
-	while (le < len) {
+	while (first_area_le < total_area_len) {
 		area_len = 1;
 
 		/* 
-		 * Find how many blocks are contiguous in all stripes
+		 * Find how many extents are contiguous in all stripes
 		 * and so can form part of this segment
 		 */
 		while (_check_stripe(lvm, lvm->stripes,
-				     area_len * lvm->stripes, le, len))
+				     area_len, first_area_le, total_area_len))
 			area_len++;
 
 		if (!(seg = alloc_lv_segment(cmd->mem, segtype, lvm->lv,
-					     lvm->stripes * le,
+					     lvm->stripes * first_area_le,
 					     lvm->stripes * area_len,
 					     0, lvm->stripe_size, NULL,
 					     lvm->stripes,
@@ -310,15 +315,13 @@
 		 */
 		for (st = 0; st < seg->area_count; st++)
 			if (!set_lv_segment_area_pv(seg, st,
-						    lvm->map[le + st * len].pv,
-						    lvm->map[le + st * len].pe)) {
-				stack;
-				return 0;
-			}
+			      lvm->map[first_area_le + st * total_area_len].pv,
+			      lvm->map[first_area_le + st * total_area_len].pe))
+				return_0;
 
 		list_add(&lvm->lv->segments, &seg->list);
 
-		le += seg->len;
+		first_area_le += area_len;
 	}
 
 	return 1;

Modified: lvm2/upstream/current/lib/format1/lvm1-label.c
==============================================================================
--- lvm2/upstream/current/lib/format1/lvm1-label.c	(original)
+++ lvm2/upstream/current/lib/format1/lvm1-label.c	Sat Apr  7 15:30:42 2007
@@ -30,7 +30,7 @@
 		op);
 }
 
-static int _lvm1_can_handle(struct labeller *l, char *buf, uint64_t sector)
+static int _lvm1_can_handle(struct labeller *l, void *buf, uint64_t sector)
 {
 	struct pv_disk *pvd = (struct pv_disk *) buf;
 	uint32_t version;
@@ -48,13 +48,13 @@
 	return 0;
 }
 
-static int _lvm1_write(struct label *label, char *buf)
+static int _lvm1_write(struct label *label, void *buf)
 {
 	_not_supported("write");
 	return 0;
 }
 
-static int _lvm1_read(struct labeller *l, struct device *dev, char *buf,
+static int _lvm1_read(struct labeller *l, struct device *dev, void *buf,
 		 struct label **label)
 {
 	struct pv_disk *pvd = (struct pv_disk *) buf;

Modified: lvm2/upstream/current/lib/format_pool/disk_rep.c
==============================================================================
--- lvm2/upstream/current/lib/format_pool/disk_rep.c	(original)
+++ lvm2/upstream/current/lib/format_pool/disk_rep.c	Sat Apr  7 15:30:42 2007
@@ -36,7 +36,7 @@
 			    struct dm_pool *mem, struct pool_list *pl,
 			    const char *vg_name)
 {
-	char buf[512];
+	char buf[512] __attribute((aligned(8)));
 
 	/* FIXME: Need to check the cache here first */
 	if (!dev_read(dev, UINT64_C(0), 512, buf)) {
@@ -59,7 +59,7 @@
 
 	list_iterate_items(pl, head) {
 		if (id_equal(&data->pv_uuid, &pl->pv_uuid)) {
-			char uuid[ID_LEN + 7];
+			char uuid[ID_LEN + 7] __attribute((aligned(8)));
 
 			id_write_format(&pl->pv_uuid, uuid, ID_LEN + 7);
 
@@ -84,7 +84,7 @@
 	struct lvmcache_info *info;
 	struct id pvid;
 	struct id vgid;
-	char uuid[ID_LEN + 7];
+	char uuid[ID_LEN + 7] __attribute((aligned(8)));
 	struct pool_disk *pd = &pl->pd;
 
 	pool_label_in(pd, buf);
@@ -128,7 +128,7 @@
  * be able to interpret ondisk labels correctly.  Always use
  * this function before writing to disk.
  */
-void pool_label_out(struct pool_disk *pl, char *buf)
+void pool_label_out(struct pool_disk *pl, void *buf)
 {
 	struct pool_disk *bufpl = (struct pool_disk *) buf;
 
@@ -163,7 +163,7 @@
  * correctly.  Always use this function before using labels that
  * were read from disk.
  */
-void pool_label_in(struct pool_disk *pl, char *buf)
+void pool_label_in(struct pool_disk *pl, void *buf)
 {
 	struct pool_disk *bufpl = (struct pool_disk *) buf;
 

Modified: lvm2/upstream/current/lib/format_pool/disk_rep.h
==============================================================================
--- lvm2/upstream/current/lib/format_pool/disk_rep.h	(original)
+++ lvm2/upstream/current/lib/format_pool/disk_rep.h	Sat Apr  7 15:30:42 2007
@@ -134,8 +134,8 @@
 
 int read_pool_label(struct pool_list *pl, struct labeller *l,
 		    struct device *dev, char *buf, struct label **label);
-void pool_label_out(struct pool_disk *pl, char *buf);
-void pool_label_in(struct pool_disk *pl, char *buf);
+void pool_label_out(struct pool_disk *pl, void *buf);
+void pool_label_in(struct pool_disk *pl, void *buf);
 void get_pool_uuid(char *uuid, uint64_t poolid, uint32_t spid, uint32_t devid);
 int import_pool_vg(struct volume_group *vg, struct dm_pool *mem, struct list *pls);
 int import_pool_lvs(struct volume_group *vg, struct dm_pool *mem,

Modified: lvm2/upstream/current/lib/format_pool/pool_label.c
==============================================================================
--- lvm2/upstream/current/lib/format_pool/pool_label.c	(original)
+++ lvm2/upstream/current/lib/format_pool/pool_label.c	Sat Apr  7 15:30:42 2007
@@ -29,7 +29,7 @@
 		  op);
 }
 
-static int _pool_can_handle(struct labeller *l, char *buf, uint64_t sector)
+static int _pool_can_handle(struct labeller *l, void *buf, uint64_t sector)
 {
 
 	struct pool_disk pd;
@@ -50,13 +50,13 @@
 	return 0;
 }
 
-static int _pool_write(struct label *label, char *buf)
+static int _pool_write(struct label *label, void *buf)
 {
 	_pool_not_supported("write");
 	return 0;
 }
 
-static int _pool_read(struct labeller *l, struct device *dev, char *buf,
+static int _pool_read(struct labeller *l, struct device *dev, void *buf,
 		 struct label **label)
 {
 	struct pool_list pl;

Modified: lvm2/upstream/current/lib/format_text/archive.c
==============================================================================
--- lvm2/upstream/current/lib/format_text/archive.c	(original)
+++ lvm2/upstream/current/lib/format_text/archive.c	Sat Apr  7 15:30:42 2007
@@ -249,17 +249,23 @@
 
 	if (!(fp = fdopen(fd, "w"))) {
 		log_err("Couldn't create FILE object for archive.");
-		close(fd);
+		if (close(fd))
+			log_sys_error("close", temp_file);
 		return 0;
 	}
 
 	if (!text_vg_export_file(vg, desc, fp)) {
 		stack;
-		fclose(fp);
+		if (fclose(fp))
+			log_sys_error("fclose", temp_file);
 		return 0;
 	}
 
-	fclose(fp);
+	if (fclose(fp)) {
+		log_sys_error("fclose", temp_file);
+		/* Leave file behind as evidence of failure */
+		return 0;
+	}
 
 	/*
 	 * Now we want to rename this file to <vg>_index.vg.

Modified: lvm2/upstream/current/lib/format_text/export.c
==============================================================================
--- lvm2/upstream/current/lib/format_text/export.c	(original)
+++ lvm2/upstream/current/lib/format_text/export.c	Sat Apr  7 15:30:42 2007
@@ -221,6 +221,8 @@
 		"Megabytes",
 		"Gigabytes",
 		"Terabytes",
+		"Petabytes",
+		"Exabytes",
 		NULL
 	};
 

Modified: lvm2/upstream/current/lib/format_text/format-text.c
==============================================================================
--- lvm2/upstream/current/lib/format_text/format-text.c	(original)
+++ lvm2/upstream/current/lib/format_text/format-text.c	Sat Apr  7 15:30:42 2007
@@ -132,37 +132,40 @@
 
 	if (!dev_read(dev_area->dev, dev_area->start, MDA_HEADER_SIZE, mdah)) {
 		stack;
-		dm_pool_free(fmt->cmd->mem, mdah);
-		return NULL;
+		goto error;
 	}
 
 	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;
+		goto error;
 	}
 
 	_xlate_mdah(mdah);
 
 	if (strncmp((char *)mdah->magic, FMTT_MAGIC, sizeof(mdah->magic))) {
 		log_error("Wrong magic number in metadata area header");
-		return NULL;
+		goto error;
 	}
 
 	if (mdah->version != FMTT_VERSION) {
 		log_error("Incompatible metadata area header version: %d",
 			  mdah->version);
-		return NULL;
+		goto error;
 	}
 
 	if (mdah->start != dev_area->start) {
 		log_error("Incorrect start sector in metadata area header: %"
 			  PRIu64, mdah->start);
-		return NULL;
+		goto error;
 	}
 
 	return mdah;
+
+error:
+	dm_pool_free(fmt->cmd->mem, mdah);
+	return NULL;
 }
 
 static int _raw_write_mda_header(const struct format_type *fmt,
@@ -193,7 +196,7 @@
 				       int *precommitted)
 {
 	size_t len;
-	char vgnamebuf[NAME_LEN + 2];
+	char vgnamebuf[NAME_LEN + 2] __attribute((aligned(8)));
 	struct raw_locn *rlocn, *rlocn_precommitted;
 	struct lvmcache_info *info;
 
@@ -707,7 +710,8 @@
 
 	if (!(fp = fdopen(fd, "w"))) {
 		log_sys_error("fdopen", temp_file);
-		close(fd);
+		if (close(fd))
+			log_sys_error("fclose", temp_file);
 		return 0;
 	}
 
@@ -715,13 +719,15 @@
 
 	if (!text_vg_export_file(vg, tc->desc, fp)) {
 		log_error("Failed to write metadata to %s.", temp_file);
-		fclose(fp);
+		if (fclose(fp))
+			log_sys_error("fclose", temp_file);
 		return 0;
 	}
 
 	if (fsync(fd) && (errno != EROFS) && (errno != EINVAL)) {
 		log_sys_error("fsync", tc->path_edit);
-		fclose(fp);
+		if (fclose(fp))
+			log_sys_error("fclose", tc->path_edit);
 		return 0;
 	}
 
@@ -885,8 +891,8 @@
 	uint32_t wrap = 0;
 	const char *vgname = NULL;
 	unsigned int len = 0;
-	char buf[NAME_LEN + 1];
-        char uuid[64];
+	char buf[NAME_LEN + 1] __attribute((aligned(8)));
+	char uuid[64] __attribute((aligned(8)));
 
 	if (!dev_open(dev_area->dev)) {
 		stack;
@@ -1131,7 +1137,7 @@
 	struct lvmcache_info *info;
 	struct mda_context *mdac;
 	struct metadata_area *mda;
-	char buf[MDA_HEADER_SIZE];
+	char buf[MDA_HEADER_SIZE] __attribute((aligned(8)));
 	struct mda_header *mdah = (struct mda_header *) buf;
 	uint64_t adjustment;
 
@@ -1408,6 +1414,7 @@
 	uint64_t pe_end = 0;
 	unsigned mda_count = 0;
 	uint64_t mda_size2 = 0;
+	uint64_t pe_count;
 
 	/* FIXME Cope with pvchange */
 	/* FIXME Merge code with _text_create_text_instance */
@@ -1473,8 +1480,17 @@
 				   pv->pe_start + mda_size2;
 
 		/* Recalculate number of extents that will fit */
-		if (!pv->pe_count)
-			pv->pe_count = (pv->size - pv->pe_start - mda_size2) / vg->extent_size;
+		if (!pv->pe_count) {
+			pe_count = (pv->size - pv->pe_start - mda_size2) /
+				   vg->extent_size;
+			if (pe_count > UINT32_MAX) {
+				log_error("PV %s too large for extent size %s.",
+					  dev_name(pv->dev),
+					  display_size(vg->cmd, (uint64_t) vg->extent_size));
+				return 0;
+			}
+			pv->pe_count = (uint32_t) pe_count;
+		}
 
 		/* Unlike LVM1, we don't store this outside a VG */
 		/* FIXME Default from config file? vgextend cmdline flag? */
@@ -1732,7 +1748,7 @@
 	}
 
 	if (!(dev_area.dev = device_from_pvid(cmd, &id))) {
-		char buffer[64];
+		char buffer[64] __attribute((aligned(8)));
 
 		if (!id_write_format(&id, buffer, sizeof(buffer)))
 			log_err("Couldn't find device.");

Modified: lvm2/upstream/current/lib/format_text/import.c
==============================================================================
--- lvm2/upstream/current/lib/format_text/import.c	(original)
+++ lvm2/upstream/current/lib/format_text/import.c	Sat Apr  7 15:30:42 2007
@@ -43,7 +43,7 @@
 		_text_import_initialised = 1;
 	}
 
-	if (!(cft = create_config_tree(NULL)))
+	if (!(cft = create_config_tree(NULL, 0)))
 		return_NULL;
 
 	if ((!dev && !read_config_file(cft)) ||
@@ -94,7 +94,7 @@
 	*desc = NULL;
 	*when = 0;
 
-	if (!(cft = create_config_tree(file)))
+	if (!(cft = create_config_tree(file, 0)))
 		return_NULL;
 
 	if ((!dev && !read_config_file(cft)) ||

Modified: lvm2/upstream/current/lib/format_text/import_vsn1.c
==============================================================================
--- lvm2/upstream/current/lib/format_text/import_vsn1.c	(original)
+++ lvm2/upstream/current/lib/format_text/import_vsn1.c	Sat Apr  7 15:30:42 2007
@@ -116,6 +116,7 @@
 	struct physical_volume *pv;
 	struct pv_list *pvl;
 	struct config_node *cn;
+	uint64_t size;
 
 	if (!(pvl = dm_pool_zalloc(mem, sizeof(*pvl))) ||
 	    !(pvl->pv = dm_pool_zalloc(mem, sizeof(*pvl->pv)))) {
@@ -148,7 +149,7 @@
 	 * Convert the uuid into a device.
 	 */
 	if (!(pv->dev = device_from_pvid(fid->fmt->cmd, &pv->id))) {
-		char buffer[64];
+		char buffer[64] __attribute((aligned(8)));
 
 		if (!id_write_format(&pv->id, buffer, sizeof(buffer)))
 			log_error("Couldn't find device.");
@@ -213,6 +214,25 @@
 	pv->pe_alloc_count = 0;
 	pv->fmt = fid->fmt;
 
+        /* Fix up pv size if missing */
+        if (!pv->size && pv->dev) {
+                if (!dev_get_size(pv->dev, &pv->size)) {
+                        log_error("%s: Couldn't get size.", dev_name(pv->dev));
+                        return 0;
+                }
+                log_verbose("Fixing up missing format1 size (%s) "
+                            "for PV %s", display_size(fid->fmt->cmd, pv->size),
+                            dev_name(pv->dev));
+                if (vg) {
+                        size = pv->pe_count * (uint64_t) vg->extent_size +
+                               pv->pe_start;
+                        if (size > pv->size)
+                                log_error("WARNING: Physical Volume %s is too "
+                                          "large for underlying device",
+                                          dev_name(pv->dev));
+                }
+        }
+
 	if (!alloc_pv_segment_whole_pv(mem, pv)) {
 		stack;
 		return 0;

Modified: lvm2/upstream/current/lib/format_text/text_label.c
==============================================================================
--- lvm2/upstream/current/lib/format_text/text_label.c	(original)
+++ lvm2/upstream/current/lib/format_text/text_label.c	Sat Apr  7 15:30:42 2007
@@ -24,7 +24,7 @@
 #include <fcntl.h>
 
 static int _text_can_handle(struct labeller *l __attribute((unused)),
-			    char *buf,
+			    void *buf,
 			    uint64_t sector __attribute((unused)))
 {
 	struct label_header *lh = (struct label_header *) buf;
@@ -35,7 +35,7 @@
 	return 0;
 }
 
-static int _text_write(struct label *label, char *buf)
+static int _text_write(struct label *label, void *buf)
 {
 	struct label_header *lh = (struct label_header *) buf;
 	struct pv_header *pvhdr;
@@ -189,7 +189,7 @@
 	return 1;
 }
 
-static int _text_read(struct labeller *l, struct device *dev, char *buf,
+static int _text_read(struct labeller *l, struct device *dev, void *buf,
 		 struct label **label)
 {
 	struct label_header *lh = (struct label_header *) buf;

Modified: lvm2/upstream/current/lib/label/label.c
==============================================================================
--- lvm2/upstream/current/lib/label/label.c	(original)
+++ lvm2/upstream/current/lib/label/label.c	Sat Apr  7 15:30:42 2007
@@ -115,7 +115,7 @@
 	struct lvmcache_info *info;
 	uint64_t sector;
 	int found = 0;
-	char readbuf[LABEL_SCAN_SIZE];
+	char readbuf[LABEL_SCAN_SIZE] __attribute((aligned(8)));
 
 	if (!dev_read(dev, UINT64_C(0), LABEL_SCAN_SIZE, readbuf)) {
 		log_debug("%s: Failed to read label area", dev_name(dev));
@@ -186,8 +186,8 @@
 /* FIXME Also wipe associated metadata area headers? */
 int label_remove(struct device *dev)
 {
-	char buf[LABEL_SIZE];
-	char readbuf[LABEL_SCAN_SIZE];
+	char buf[LABEL_SIZE] __attribute((aligned(8)));
+	char readbuf[LABEL_SCAN_SIZE] __attribute((aligned(8)));
 	int r = 1;
 	uint64_t sector;
 	int wipe;
@@ -258,7 +258,7 @@
 /* FIXME Avoid repeated re-reading if cache lock held */
 int label_read(struct device *dev, struct label **result)
 {
-	char buf[LABEL_SIZE];
+	char buf[LABEL_SIZE] __attribute((aligned(8)));
 	struct labeller *l;
 	uint64_t sector;
 	struct lvmcache_info *info;
@@ -290,7 +290,7 @@
 /* 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];
+	char buf[LABEL_SIZE] __attribute((aligned(8)));
 	struct label_header *lh = (struct label_header *) buf;
 	int r = 1;
 
@@ -341,19 +341,17 @@
 int label_verify(struct device *dev)
 {
 	struct labeller *l;
-	char buf[LABEL_SIZE];
+	char buf[LABEL_SIZE] __attribute((aligned(8)));
 	uint64_t sector;
 	struct lvmcache_info *info;
 	int r = 0;
 
 	if (!dev_open(dev)) {
-		stack;
-
 		if ((info = info_from_pvid(dev->pvid)))
 			lvmcache_update_vgname_and_id(info, ORPHAN, ORPHAN,
 						      0, NULL);
 
-		goto out;
+		return_0;
 	}
 
 	if (!(l = _find_labeller(dev, buf, &sector)))

Modified: lvm2/upstream/current/lib/label/label.h
==============================================================================
--- lvm2/upstream/current/lib/label/label.h	(original)
+++ lvm2/upstream/current/lib/label/label.h	Sat Apr  7 15:30:42 2007
@@ -49,23 +49,23 @@
 	/*
 	 * Is the device labelled with this format ?
 	 */
-	int (*can_handle) (struct labeller * l, char *buf, uint64_t sector);
+	int (*can_handle) (struct labeller * l, void *buf, uint64_t sector);
 
 	/*
 	 * Write a label to a volume.
 	 */
-	int (*write) (struct label * label, char *buf);
+	int (*write) (struct label * label, void *buf);
 
 	/*
 	 * Read a label from a volume.
 	 */
 	int (*read) (struct labeller * l, struct device * dev,
-		     char *buf, struct label ** label);
+		     void *buf, struct label ** label);
 
 	/*
 	 * Additional consistency checks for the paranoid.
 	 */
-	int (*verify) (struct labeller * l, char *buf, uint64_t sector);
+	int (*verify) (struct labeller * l, void *buf, uint64_t sector);
 
 	/*
 	 * Populate label_type etc.

Modified: lvm2/upstream/current/lib/locking/cluster_locking.c
==============================================================================
--- lvm2/upstream/current/lib/locking/cluster_locking.c	(original)
+++ lvm2/upstream/current/lib/locking/cluster_locking.c	Sat Apr  7 15:30:42 2007
@@ -94,7 +94,7 @@
 /* Send a request and return the status */
 static int _send_request(char *inbuf, int inlen, char **retbuf)
 {
-	char outbuf[PIPE_BUF];
+	char outbuf[PIPE_BUF] __attribute((aligned(8)));
 	struct clvm_header *outheader = (struct clvm_header *) outbuf;
 	int len;
 	int off;
@@ -195,8 +195,7 @@
 static int _cluster_request(char cmd, const char *node, void *data, int len,
 			   lvm_response_t ** response, int *num)
 {
-	char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1];
-	int *outptr;
+	char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1] __attribute((aligned(8)));
 	char *inptr;
 	char *retbuf = NULL;
 	int status;
@@ -236,17 +235,13 @@
 	 * With an extra pair of INTs on the front to sanity
 	 * check the pointer when we are given it back to free
 	 */
-	outptr = dm_malloc(sizeof(lvm_response_t) * num_responses +
-			    sizeof(int) * 2);
-	if (!outptr) {
+	*response = dm_malloc(sizeof(lvm_response_t) * num_responses);
+	if (!*response) {
 		errno = ENOMEM;
 		status = 0;
 		goto out;
 	}
 
-	*response = (lvm_response_t *) (outptr + 2);
-	outptr[0] = LVM_SIGNATURE;
-	outptr[1] = num_responses;
 	rarray = *response;
 
 	/* Unpack the response into an lvm_response_t array */
@@ -265,7 +260,7 @@
 			int j;
 			for (j = 0; j < i; j++)
 				dm_free(rarray[i].response);
-			free(outptr);
+			free(*response);
 			errno = ENOMEM;
 			status = -1;
 			goto out;
@@ -287,25 +282,15 @@
 }
 
 /* Free reply array */
-static int _cluster_free_request(lvm_response_t * response)
+static int _cluster_free_request(lvm_response_t * response, int num)
 {
-	int *ptr = (int *) response - 2;
 	int i;
-	int num;
-
-	/* Check it's ours to free */
-	if (response == NULL || *ptr != LVM_SIGNATURE) {
-		errno = EINVAL;
-		return 0;
-	}
-
-	num = ptr[1];
 
 	for (i = 0; i < num; i++) {
 		dm_free(response[i].response);
 	}
 
-	dm_free(ptr);
+	dm_free(response);
 
 	return 1;
 }
@@ -336,8 +321,8 @@
 	if (mirror_in_sync())
 		args[1] |= LCK_MIRROR_NOSYNC_MODE;
 
-	if (dmeventd_register_mode())
-		args[1] |= LCK_DMEVENTD_REGISTER_MODE;
+	if (dmeventd_monitor_mode())
+		args[1] |= LCK_DMEVENTD_MONITOR_MODE;
 
 	/*
 	 * VG locks are just that: locks, and have no side effects
@@ -374,7 +359,7 @@
 	}
 
 	saved_errno = errno;
-	_cluster_free_request(response);
+	_cluster_free_request(response, num_responses);
 	errno = saved_errno;
 
 	return status;

Modified: lvm2/upstream/current/lib/locking/file_locking.c
==============================================================================
--- lvm2/upstream/current/lib/locking/file_locking.c	(original)
+++ lvm2/upstream/current/lib/locking/file_locking.c	Sat Apr  7 15:30:42 2007
@@ -163,8 +163,8 @@
 	log_very_verbose("Locking %s %c%c", ll->res, state,
 			 flags & LCK_NONBLOCK ? ' ' : 'B');
 	do {
-		if (ll->lf > -1)
-			close(ll->lf);
+		if ((ll->lf > -1) && close(ll->lf))
+			log_sys_error("close", file);
 
 		if ((ll->lf = open(file, O_CREAT | O_APPEND | O_RDWR, 0777))
 		    < 0) {

Modified: lvm2/upstream/current/lib/locking/locking.c
==============================================================================
--- lvm2/upstream/current/lib/locking/locking.c	(original)
+++ lvm2/upstream/current/lib/locking/locking.c	Sat Apr  7 15:30:42 2007
@@ -249,7 +249,7 @@
 
 int lock_vol(struct cmd_context *cmd, const char *vol, int flags)
 {
-	char resource[258];
+	char resource[258] __attribute((aligned(8)));
 
 	switch (flags & LCK_SCOPE_MASK) {
 	case LCK_VG:

Modified: lvm2/upstream/current/lib/locking/locking.h
==============================================================================
--- lvm2/upstream/current/lib/locking/locking.h	(original)
+++ lvm2/upstream/current/lib/locking/locking.h	Sat Apr  7 15:30:42 2007
@@ -50,7 +50,7 @@
 #define LCK_NULL	0x00000000	/* LCK$_NLMODE */
 #define LCK_READ	0x00000001	/* LCK$_CRMODE */
 					/* LCK$_CWMODE */
-					/* LCK$_PRMODE */
+#define LCK_PREAD       0x00000003      /* LCK$_PRMODE */
 #define LCK_WRITE	0x00000004	/* LCK$_PWMODE */
 #define LCK_EXCL	0x00000005	/* LCK$_EXMODE */
 #define LCK_UNLOCK      0x00000006	/* This is ours */
@@ -75,7 +75,7 @@
  */
 #define LCK_PARTIAL_MODE	0x00000001	/* Running in partial mode */
 #define LCK_MIRROR_NOSYNC_MODE	0x00000002	/* Mirrors don't require sync */
-#define LCK_DMEVENTD_REGISTER_MODE	0x00000004	/* Register with dmeventd */
+#define LCK_DMEVENTD_MONITOR_MODE	0x00000004	/* Register with dmeventd */
 
 
 /*

Modified: lvm2/upstream/current/lib/locking/no_locking.c
==============================================================================
--- lvm2/upstream/current/lib/locking/no_locking.c	(original)
+++ lvm2/upstream/current/lib/locking/no_locking.c	Sat Apr  7 15:30:42 2007
@@ -81,7 +81,7 @@
 	locking->lock_resource = _no_lock_resource;
 	locking->reset_locking = _no_reset_locking;
 	locking->fin_locking = _no_fin_locking;
-	locking->flags = 0;
+	locking->flags = LCK_CLUSTERED;
 
 	return 1;
 }

Modified: lvm2/upstream/current/lib/log/log.c
==============================================================================
--- lvm2/upstream/current/lib/log/log.c	(original)
+++ lvm2/upstream/current/lib/log/log.c	Sat Apr  7 15:30:42 2007
@@ -48,7 +48,8 @@
 static char _msg_prefix[30] = "  ";
 static int _already_logging = 0;
 static int _mirror_in_sync = 0;
-static int _dmeventd_register = DEFAULT_DMEVENTD_MONITOR;
+static int _dmeventd_monitor = DEFAULT_DMEVENTD_MONITOR;
+static int _ignore_suspended_devices = 0;
 
 static lvm2_log_fn_t _lvm2_log_fn = NULL;
 
@@ -120,7 +121,8 @@
 	}
 
 	if (_log_to_file) {
-		fclose(_log_file);
+		if (fclose(_log_file))
+			fprintf(stderr, "fclose() on log file failed: %s", strerror(errno));
 		_log_to_file = 0;
 	}
 }
@@ -189,9 +191,14 @@
 	_mirror_in_sync = in_sync;
 }
 
-void init_dmeventd_register(int reg)
+void init_dmeventd_monitor(int reg)
 {
-	_dmeventd_register = reg;
+	_dmeventd_monitor = reg;
+}
+
+void init_ignore_suspended_devices(int ignore)
+{
+	_ignore_suspended_devices = ignore;
 }
 
 void init_cmd_name(int status)
@@ -268,9 +275,14 @@
 	return _mirror_in_sync;
 }
 
-int dmeventd_register_mode(void)
+int dmeventd_monitor_mode(void)
+{
+	return _dmeventd_monitor;
+}
+
+int ignore_suspended_devices(void)
 {
-	return _dmeventd_register;
+	return _ignore_suspended_devices;
 }
 
 void init_debug(int level)

Modified: lvm2/upstream/current/lib/log/log.h
==============================================================================
--- lvm2/upstream/current/lib/log/log.h	(original)
+++ lvm2/upstream/current/lib/log/log.h	Sat Apr  7 15:30:42 2007
@@ -75,7 +75,8 @@
 void init_lockingfailed(int level);
 void init_security_level(int level);
 void init_mirror_in_sync(int in_sync);
-void init_dmeventd_register(int reg);
+void init_dmeventd_monitor(int reg);
+void init_ignore_suspended_devices(int ignore);
 
 void set_cmd_name(const char *cmd_name);
 
@@ -90,7 +91,10 @@
 int lockingfailed(void);
 int security_level(void);
 int mirror_in_sync(void);
-int dmeventd_register_mode(void);
+int ignore_suspended_devices(void);
+
+#define DMEVENTD_MONITOR_IGNORE -1
+int dmeventd_monitor_mode(void);
 
 /* Suppress messages to stdout/stderr (1) or everywhere (2) */
 /* Returns previous setting */

Modified: lvm2/upstream/current/lib/metadata/lv_manip.c
==============================================================================
--- lvm2/upstream/current/lib/metadata/lv_manip.c	(original)
+++ lvm2/upstream/current/lib/metadata/lv_manip.c	Sat Apr  7 15:30:42 2007
@@ -415,6 +415,15 @@
 	struct list alloced_areas[0];	/* Lists of areas in each stripe */
 };
 
+static uint32_t calc_area_multiple(const struct segment_type *segtype,
+				   const uint32_t area_count)
+{
+	if (!segtype_is_striped(segtype) || !area_count)
+		return 1;
+
+	return area_count;
+}
+
 /*
  * Preparation for a specific allocation attempt
  */
@@ -476,7 +485,7 @@
 	ah->area_count = area_count;
 	ah->log_count = log_count;
 	ah->alloc = alloc;
-	ah->area_multiple = segtype_is_striped(segtype) ? ah->area_count : 1;
+	ah->area_multiple = calc_area_multiple(segtype, area_count);
 
 	for (s = 0; s < ah->area_count; s++)
 		list_init(&ah->alloced_areas[s]);
@@ -553,7 +562,7 @@
 	if (mirrored_pv)
 		extra_areas = 1;
 
-	area_multiple = segtype_is_striped(segtype) ? area_count : 1;
+	area_multiple = calc_area_multiple(segtype, area_count);
 
 	/* log_lv gets set up elsehere */
 	if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv,
@@ -628,17 +637,17 @@
 				struct pv_area **areas,
 				uint32_t *ix, struct pv_area *log_area)
 {
-	uint32_t area_len, smallest, remaining;
+	uint32_t area_len, remaining;
 	uint32_t s;
 	struct alloced_area *aa;
 
 	remaining = needed - *ix;
 	area_len = remaining / ah->area_multiple;
 
-	smallest = areas[ah->area_count - 1]->count;
-
-	if (area_len > smallest)
-		area_len = smallest;
+	/* Reduce area_len to the smallest of the areas */
+	for (s = 0; s < ah->area_count; s++)
+		if (area_len > areas[s]->count)
+			area_len = areas[s]->count;
 
 	if (!(aa = dm_pool_alloc(ah->mem, sizeof(*aa) *
 			      (ah->area_count + (log_area ? 1 : 0))))) {
@@ -707,7 +716,7 @@
 	if (max_seg_len && *max_seg_len > remaining_seg_len)
 		*max_seg_len = remaining_seg_len;
 
-	area_multiple = segtype_is_striped(seg->segtype) ? seg->area_count : 1;
+	area_multiple = calc_area_multiple(seg->segtype, seg->area_count);
 	area_len = remaining_seg_len / area_multiple ? : 1;
 
 	for (s = first_area;
@@ -890,8 +899,17 @@
 	uint32_t next_le;
 	struct seg_pvs *spvs;
 	struct list *parallel_pvs;
+	uint32_t free_pes;
+
+	/* Is there enough total space? */
+	free_pes = pv_maps_size(pvms);
+	if (needed - *allocated > free_pes) {
+		log_error("Insufficient free space: %" PRIu32 " extents needed,"
+			  " but only %" PRIu32 " available",
+			  needed - *allocated, free_pes);
+		return 0;
+	}
 
-	/* FIXME Do calculations on free extent counts before selecting space */
 	/* FIXME Select log PV appropriately if there isn't one yet */
 
 	/* Are there any preceding segments we must follow on from? */
@@ -1057,6 +1075,7 @@
 	int r = 0;
 	struct list *pvms;
 	uint32_t areas_size;
+	alloc_policy_t alloc;
 
 	if (allocated >= new_extents && !ah->log_count) {
 		log_error("_allocate called with no work to do!");
@@ -1102,50 +1121,18 @@
 		return 0;
 	}
 
-	old_allocated = allocated;
-	if (!_find_parallel_space(ah, ALLOC_CONTIGUOUS, pvms, areas,
-				  areas_size, can_split,
-				  prev_lvseg, &allocated, new_extents)) {
-		stack;
-		goto out;
-	}
-
-	if ((allocated == new_extents) || (ah->alloc == ALLOC_CONTIGUOUS) ||
-	    (!can_split && (allocated != old_allocated)))
-		goto finished;
-
-	old_allocated = allocated;
-	if (!_find_parallel_space(ah, ALLOC_CLING, pvms, areas,
-				  areas_size, can_split,
-				  prev_lvseg, &allocated, new_extents)) {
-		stack;
-		goto out;
-	}
-
-	if ((allocated == new_extents) || (ah->alloc == ALLOC_CLING) ||
-	    (!can_split && (allocated != old_allocated)))
-		goto finished;
-
-	old_allocated = allocated;
-	if (!_find_parallel_space(ah, ALLOC_NORMAL, pvms, areas,
-				  areas_size, can_split,
-				  prev_lvseg, &allocated, new_extents)) {
-		stack;
-		goto out;
-	}
-
-	if ((allocated == new_extents) || (ah->alloc == ALLOC_NORMAL) ||
-	    (!can_split && (allocated != old_allocated)))
-		goto finished;
-
-	if (!_find_parallel_space(ah, ALLOC_ANYWHERE, pvms, areas,
-				  areas_size, can_split,
-				  prev_lvseg, &allocated, new_extents)) {
-		stack;
-		goto out;
+	/* Attempt each defined allocation policy in turn */
+	for (alloc = ALLOC_CONTIGUOUS; alloc < ALLOC_INHERIT; alloc++) {
+		old_allocated = allocated;
+		if (!_find_parallel_space(ah, alloc, pvms, areas,
+					  areas_size, can_split,
+					  prev_lvseg, &allocated, new_extents))
+			goto_out;
+		if ((allocated == new_extents) || (ah->alloc == alloc) ||
+		    (!can_split && (allocated != old_allocated)))
+			break;
 	}
 
-      finished:
 	if (allocated != new_extents) {
 		log_error("Insufficient suitable %sallocatable extents "
 			  "for logical volume %s: %u more required",
@@ -1156,6 +1143,13 @@
 		goto out;
 	}
 
+	if (ah->log_count && !ah->log_area.len) {
+		log_error("Insufficient extents for log allocation "
+			  "for logical volume %s.",
+			  lv ? lv->name : "");
+		goto out;
+	}
+
 	r = 1;
 
       out:
@@ -1499,7 +1493,7 @@
 	struct cmd_context *cmd = vg->cmd;
 	struct lv_list *ll = NULL;
 	struct logical_volume *lv;
-	char dname[32];
+	char dname[NAME_LEN];
 
 	if (vg->max_lv && (vg->max_lv == vg->lv_count)) {
 		log_error("Maximum number of logical volumes (%u) reached "

Modified: lvm2/upstream/current/lib/metadata/metadata.c
==============================================================================
--- lvm2/upstream/current/lib/metadata/metadata.c	(original)
+++ lvm2/upstream/current/lib/metadata/metadata.c	Sat Apr  7 15:30:42 2007
@@ -23,6 +23,7 @@
 #include "str_list.h"
 #include "pv_alloc.h"
 #include "activate.h"
+#include "display.h"
 
 #include <sys/param.h>
 
@@ -122,6 +123,15 @@
 	pvl->pv = pv;
 	list_add(&vg->pvs, &pvl->list);
 
+	if ((uint64_t) vg->extent_count + pv->pe_count > UINT32_MAX) {
+		log_error("Unable to add %s to %s: new extent count (%"
+			  PRIu64 ") exceeds limit (%" PRIu32 ").",
+			  pv_name, vg->name,
+			  (uint64_t) vg->extent_count + pv->pe_count,
+			  UINT32_MAX);
+		return 0;
+	}
+
 	vg->pv_count++;
 	vg->extent_count += pv->pe_count;
 	vg->free_count += pv->pe_count;
@@ -728,7 +738,7 @@
 {
 	struct pv_list *pvl, *pvl2;
 	struct lv_list *lvl, *lvl2;
-	char uuid[64];
+	char uuid[64] __attribute((aligned(8)));
 	int r = 1;
 
 	/* FIXME Also check there's no data/metadata overlap */
@@ -953,6 +963,30 @@
 	return vg;
 }
 
+static int _update_pv_list(struct list *all_pvs, struct volume_group *vg)
+{
+	struct pv_list *pvl, *pvl2;
+
+	list_iterate_items(pvl, &vg->pvs) {
+		list_iterate_items(pvl2, all_pvs) {
+			if (pvl->pv->dev == pvl2->pv->dev)
+				goto next_pv;
+		}
+		/* PV is not on list so add it.  Note that we don't copy it. */
+       		if (!(pvl2 = dm_pool_zalloc(vg->cmd->mem, sizeof(*pvl2)))) {
+			log_error("pv_list allocation for '%s' failed",
+				  dev_name(pvl->pv->dev));
+			return 0;
+		}
+		pvl2->pv = pvl->pv;
+		list_add(all_pvs, &pvl2->list);
+  next_pv:
+		;
+	}
+
+	return 1;
+}
+
 /* 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.
@@ -972,9 +1006,12 @@
 	struct volume_group *vg, *correct_vg = NULL;
 	struct metadata_area *mda;
 	int inconsistent = 0;
+	int inconsistent_vgid = 0;
 	int use_precommitted = precommitted;
 	struct list *pvids;
-	struct pv_list *pvl;
+	struct pv_list *pvl, *pvl2;
+	struct list all_pvs;
+	char uuid[64] __attribute((aligned(8)));
 
 	if (!*vgname) {
 		if (use_precommitted) {
@@ -1059,6 +1096,8 @@
 		}
 	}
 
+	list_init(&all_pvs);
+
 	/* Failed to find VG where we expected it - full scan and retry */
 	if (!correct_vg) {
 		inconsistent = 0;
@@ -1094,13 +1133,25 @@
 			}
 			if (!correct_vg) {
 				correct_vg = vg;
+				if (!_update_pv_list(&all_pvs, correct_vg))
+					return_NULL;
 				continue;
 			}
+
+			if (strncmp((char *)vg->id.uuid,
+			    (char *)correct_vg->id.uuid, ID_LEN)) {
+				inconsistent = 1;
+				inconsistent_vgid = 1;
+			}
+
 			/* FIXME Also ensure contents same - checksums same? */
 			if (correct_vg->seqno != vg->seqno) {
 				inconsistent = 1;
-				if (vg->seqno > correct_vg->seqno)
+				if (vg->seqno > correct_vg->seqno) {
+					if (!_update_pv_list(&all_pvs, vg))
+						return_NULL;
 					correct_vg = vg;
+				}
 			}
 		}
 
@@ -1133,17 +1184,42 @@
 			return correct_vg;
 		}
 
-		log_print("Inconsistent metadata copies found - updating "
-			  "to use version %u", correct_vg->seqno);
+		/* Don't touch if vgids didn't match */
+		if (inconsistent_vgid) {
+			log_error("Inconsistent metadata UUIDs found for "
+				  "volume group %s", vgname);
+			*consistent = 0;
+			return correct_vg;
+		}
+
+		log_print("Inconsistent metadata found for VG %s - updating "
+			  "to use version %u", vgname, correct_vg->seqno);
+
 		if (!vg_write(correct_vg)) {
 			log_error("Automatic metadata correction failed");
 			return NULL;
 		}
+
 		if (!vg_commit(correct_vg)) {
 			log_error("Automatic metadata correction commit "
 				  "failed");
 			return NULL;
 		}
+
+		list_iterate_items(pvl, &all_pvs) {
+			list_iterate_items(pvl2, &correct_vg->pvs) {
+				if (pvl->pv->dev == pvl2->pv->dev)
+					goto next_pv;
+			}
+			if (!id_write_format(&pvl->pv->id, uuid, sizeof(uuid)))
+				return_NULL;
+			log_error("Removing PV %s (%s) that no longer belongs to VG %s",
+				  dev_name(pvl->pv->dev), uuid, correct_vg->name);
+			if (!pv_write_orphan(cmd, pvl->pv))
+				return_NULL;
+      next_pv:
+			;
+		}
 	}
 
 	if ((correct_vg->status & PVMOVE) && !pvmove_mode()) {
@@ -1423,3 +1499,25 @@
 
 	return 1;
 }
+
+int pv_write_orphan(struct cmd_context *cmd, struct physical_volume *pv)
+{
+	const char *old_vg_name = pv->vg_name;
+
+	pv->vg_name = ORPHAN;
+	pv->status = ALLOCATABLE_PV;
+
+	if (!dev_get_size(pv->dev, &pv->size)) {
+		log_error("%s: Couldn't get size.", dev_name(pv->dev));
+		return 0;
+	}
+
+	if (!pv_write(cmd, pv, NULL, INT64_C(-1))) {
+		log_error("Failed to clear metadata from physical "
+			  "volume \"%s\" after removal from \"%s\"",
+			  dev_name(pv->dev), old_vg_name);
+		return 0;
+	}
+
+	return 1;
+}

Modified: lvm2/upstream/current/lib/metadata/metadata.h
==============================================================================
--- lvm2/upstream/current/lib/metadata/metadata.h	(original)
+++ lvm2/upstream/current/lib/metadata/metadata.h	Sat Apr  7 15:30:42 2007
@@ -78,17 +78,18 @@
 #define FMT_RESIZE_PV		0x00000080U	/* Supports pvresize? */
 #define FMT_UNLIMITED_STRIPESIZE 0x00000100U	/* Unlimited stripe size? */
 
+/* Ordered list - see lv_manip.c */
 typedef enum {
-	ALLOC_INVALID = 0,
-	ALLOC_INHERIT,
+	ALLOC_INVALID,
 	ALLOC_CONTIGUOUS,
 	ALLOC_CLING,
 	ALLOC_NORMAL,
-	ALLOC_ANYWHERE
+	ALLOC_ANYWHERE,
+	ALLOC_INHERIT
 } alloc_policy_t;
 
 typedef enum {
-	AREA_UNASSIGNED = 0,
+	AREA_UNASSIGNED,
 	AREA_PV,
 	AREA_LV
 } area_type_t;
@@ -285,7 +286,7 @@
 	int32_t major;
 	int32_t minor;
 
-	uint64_t size;
+	uint64_t size;		/* Sectors */
 	uint32_t le_count;
 
 	uint32_t origin_count;
@@ -422,6 +423,7 @@
 
 int pv_write(struct cmd_context *cmd, struct physical_volume *pv,
 	     struct list *mdas, int64_t label_sector);
+int pv_write_orphan(struct cmd_context *cmd, struct physical_volume *pv);
 
 /* pe_start and pe_end relate to any existing data so that new metadata
  * areas can avoid overlap */

Modified: lvm2/upstream/current/lib/metadata/mirror.c
==============================================================================
--- lvm2/upstream/current/lib/metadata/mirror.c	(original)
+++ lvm2/upstream/current/lib/metadata/mirror.c	Sat Apr  7 15:30:42 2007
@@ -36,20 +36,20 @@
 }
 
 /*
- * Ensure region size is compatible with volume size.
+ * Reduce the region size if necessary to ensure
+ * the volume size is a multiple of the region size.
  */
 uint32_t adjusted_mirror_region_size(uint32_t extent_size, uint32_t extents,
 				     uint32_t region_size)
 {
-	uint32_t region_max;
+	uint64_t region_max;
 
-	region_max = (1 << (ffs((int)extents) - 1)) * extent_size;
+	region_max = (1 << (ffs((int)extents) - 1)) * (uint64_t) extent_size;
 
-	if (region_max < region_size) {
-		region_size = region_max;
+	if (region_max < UINT32_MAX && region_size > region_max) {
+		region_size = (uint32_t) region_max;
 		log_print("Using reduced mirror region size of %" PRIu32
-			  " sectors", region_max);
-		return region_max;
+			  " sectors", region_size);
 	}
 
 	return region_size;
@@ -84,6 +84,7 @@
 			 struct list *removable_pvs, int remove_log)
 {
 	uint32_t m;
+	uint32_t extents;
 	uint32_t s, s1;
 	struct logical_volume *sub_lv;
 	struct logical_volume *log_lv = NULL;
@@ -95,6 +96,7 @@
 	struct pv_list *pvl;
 	uint32_t old_area_count = mirrored_seg->area_count;
 	uint32_t new_area_count = mirrored_seg->area_count;
+	struct segment_type *segtype;
 
 	log_very_verbose("Reducing mirror set from %" PRIu32 " to %"
 			 PRIu32 " image(s)%s.",
@@ -156,9 +158,14 @@
 	/* If no more mirrors, remove mirror layer */
 	if (num_mirrors == 1) {
 		lv1 = seg_lv(mirrored_seg, 0);
+		extents = lv1->le_count;
 		_move_lv_segments(mirrored_seg->lv, lv1);
 		mirrored_seg->lv->status &= ~MIRRORED;
 		remove_log = 1;
+		/* Replace mirror with error segment */
+		segtype = get_segtype_from_string(mirrored_seg->lv->vg->cmd, "error");
+		if (!lv_add_virtual_segment(lv1, 0, extents, segtype))
+			return_0;
 	}
 
 	if (remove_log && mirrored_seg->log_lv) {
@@ -174,8 +181,6 @@
 	 * then deactivate and remove them fully.
 	 */
 
-	/* FIXME lv1 has no segments here so shouldn't be written to disk! */
-
 	if (!vg_write(mirrored_seg->lv->vg)) {
 		log_error("intermediate VG write failed.");
 		return 0;
@@ -562,7 +567,7 @@
 	}
 
         if (activation() && segtype->ops->target_present &&
-            !segtype->ops->target_present()) {
+            !segtype->ops->target_present(NULL)) {
                 log_error("%s: Required device-mapper target(s) not "
                           "detected in your kernel", segtype->name);
                 return 0;

Modified: lvm2/upstream/current/lib/metadata/pv_map.c
==============================================================================
--- lvm2/upstream/current/lib/metadata/pv_map.c	(original)
+++ lvm2/upstream/current/lib/metadata/pv_map.c	Sat Apr  7 15:30:42 2007
@@ -19,6 +19,8 @@
 
 /*
  * Areas are maintained in size order, largest first.
+ *
+ * FIXME Cope with overlap.
  */
 static void _insert_area(struct list *head, struct pv_area *a)
 {
@@ -30,6 +32,7 @@
 	}
 
 	list_add(&pva->list, &a->list);
+	a->map->pe_count += a->count;
 }
 
 static int _create_single_area(struct dm_pool *mem, struct pv_map *pvm,
@@ -126,22 +129,31 @@
 
 static int _create_maps(struct dm_pool *mem, struct list *pvs, struct list *pvms)
 {
-	struct pv_map *pvm;
+	struct pv_map *pvm, *pvm2;
 	struct pv_list *pvl;
 
 	list_iterate_items(pvl, pvs) {
 		if (!(pvl->pv->status & ALLOCATABLE_PV))
 			continue;
 
-		if (!(pvm = dm_pool_zalloc(mem, sizeof(*pvm)))) {
-			stack;
-			return 0;
-		}
-
-		pvm->pv = pvl->pv;
+		pvm = NULL;
 
-		list_init(&pvm->areas);
-		list_add(pvms, &pvm->list);
+		list_iterate_items(pvm2, pvms)
+			if (pvm2->pv->dev == pvl->pv->dev) {
+				pvm = pvm2;
+				break;
+			}
+
+		if (!pvm) {
+			if (!(pvm = dm_pool_zalloc(mem, sizeof(*pvm)))) {
+				stack;
+				return 0;
+			}
+
+			pvm->pv = pvl->pv;
+			list_init(&pvm->areas);
+			list_add(pvms, &pvm->list);
+		}
 
 		if (!_create_all_areas_for_pv(mem, pvm, pvl->pe_ranges)) {
 			stack;
@@ -180,6 +192,7 @@
 void consume_pv_area(struct pv_area *pva, uint32_t to_go)
 {
 	list_del(&pva->list);
+	pva->map->pe_count -= pva->count;
 
 	assert(to_go <= pva->count);
 
@@ -190,3 +203,14 @@
 		_insert_area(&pva->map->areas, pva);
 	}
 }
+
+uint32_t pv_maps_size(struct list *pvms)
+{
+	struct pv_map *pvm;
+	uint32_t pe_count = 0;
+
+	list_iterate_items(pvm, pvms)
+		pe_count += pvm->pe_count;
+
+	return pe_count;
+}

Modified: lvm2/upstream/current/lib/metadata/pv_map.h
==============================================================================
--- lvm2/upstream/current/lib/metadata/pv_map.h	(original)
+++ lvm2/upstream/current/lib/metadata/pv_map.h	Sat Apr  7 15:30:42 2007
@@ -37,6 +37,7 @@
 struct pv_map {
 	struct physical_volume *pv;
 	struct list areas;		/* struct pv_areas */
+	uint32_t pe_count;		/* Total number of PEs */
 
 	struct list list;
 };
@@ -49,4 +50,6 @@
 
 void consume_pv_area(struct pv_area *area, uint32_t to_go);
 
+uint32_t pv_maps_size(struct list *pvms);
+
 #endif

Modified: lvm2/upstream/current/lib/metadata/segtype.h
==============================================================================
--- lvm2/upstream/current/lib/metadata/segtype.h	(original)
+++ lvm2/upstream/current/lib/metadata/segtype.h	Sat Apr  7 15:30:42 2007
@@ -32,6 +32,7 @@
 #define SEG_FORMAT1_SUPPORT	0x00000010U
 #define SEG_VIRTUAL		0x00000020U
 #define SEG_CANNOT_BE_ZEROED	0x00000040U
+#define SEG_MONITORED		0x00000080U
 
 #define seg_is_mirrored(seg)	((seg)->segtype->flags & SEG_AREAS_MIRRORED ? 1 : 0)
 #define seg_is_striped(seg)	((seg)->segtype->flags & SEG_AREAS_STRIPED ? 1 : 0)
@@ -39,6 +40,7 @@
 #define seg_is_virtual(seg)	((seg)->segtype->flags & SEG_VIRTUAL ? 1 : 0)
 #define seg_can_split(seg)	((seg)->segtype->flags & SEG_CAN_SPLIT ? 1 : 0)
 #define seg_cannot_be_zeroed(seg) ((seg)->segtype->flags & SEG_CANNOT_BE_ZEROED ? 1 : 0)
+#define seg_monitored(seg)	((seg)->segtype->flags & SEG_MONITORED ? 1 : 0)
 
 #define segtype_is_striped(segtype)	((segtype)->flags & SEG_AREAS_STRIPED ? 1 : 0)
 #define segtype_is_mirrored(segtype)	((segtype)->flags & SEG_AREAS_MIRRORED ? 1 : 0)
@@ -76,13 +78,14 @@
 			       struct lv_segment *seg, char *params,
 			       uint64_t *total_numerator,
 			       uint64_t *total_denominator, float *percent);
-	int (*target_present) (void);
+	int (*target_present) (const struct lv_segment *seg);
 	int (*modules_needed) (struct dm_pool *mem,
 			       const struct lv_segment *seg,
 			       struct list *modules);
 	void (*destroy) (const struct segment_type * segtype);
-	int (*target_register_events) (struct lv_segment *seg, int events);
-	int (*target_unregister_events) (struct lv_segment *seg, int events);
+	int (*target_monitored) (struct lv_segment *seg, int *pending);
+	int (*target_monitor_events) (struct lv_segment *seg, int events);
+	int (*target_unmonitor_events) (struct lv_segment *seg, int events);
 };
 
 struct segment_type *get_segtype_from_string(struct cmd_context *cmd,

Modified: lvm2/upstream/current/lib/mirror/mirrored.c
==============================================================================
--- lvm2/upstream/current/lib/mirror/mirrored.c	(original)
+++ lvm2/upstream/current/lib/mirror/mirrored.c	Sat Apr  7 15:30:42 2007
@@ -336,7 +336,7 @@
 	return add_areas_line(dm, seg, node, start_area, area_count);
 }
 
-static int _mirrored_target_present(void)
+static int _mirrored_target_present(const struct lv_segment *seg __attribute((unused)))
 {
 	static int _mirrored_checked = 0;
 	static int _mirrored_present = 0;
@@ -368,13 +368,12 @@
 }
 
 #ifdef DMEVENTD
-static int _setup_registration(struct dm_pool *mem, struct cmd_context *cmd,
-			       char **dso)
+static int _get_mirror_dso_path(struct cmd_context *cmd, char **dso)
 {
 	char *path;
 	const char *libpath;
 
-	if (!(path = dm_pool_alloc(mem, PATH_MAX))) {
+	if (!(path = dm_pool_alloc(cmd->mem, PATH_MAX))) {
 		log_error("Failed to allocate dmeventd library path.");
 		return 0;
 	}
@@ -389,62 +388,107 @@
 	return 1;
 }
 
-/* FIXME This gets run while suspended and performs banned operations. */
-/* FIXME Merge these two functions */
-static int _target_register_events(struct lv_segment *seg,
-				   int events)
+static struct dm_event_handler *_create_dm_event_handler(const char *dmname,
+							 const char *dso,
+							 enum dm_event_mask mask)
+{
+	struct dm_event_handler *dmevh;
+
+	if (!(dmevh = dm_event_handler_create()))
+		return_0;
+
+       if (dm_event_handler_set_dso(dmevh, dso))
+		goto fail;
+
+	if (dm_event_handler_set_dev_name(dmevh, dmname))
+		goto fail;
+
+	dm_event_handler_set_event_mask(dmevh, mask);
+	return dmevh;
+
+fail:
+	dm_event_handler_destroy(dmevh);
+	return NULL;
+}
+
+static int _target_monitored(struct lv_segment *seg, int *pending)
 {
 	char *dso, *name;
 	struct logical_volume *lv;
 	struct volume_group *vg;
+	enum dm_event_mask evmask = 0;
+	struct dm_event_handler *dmevh;
 
 	lv = seg->lv;
 	vg = lv->vg;
 
-	if (!_setup_registration(vg->cmd->mem, vg->cmd, &dso)) {
-		stack;
-		return 0;
-	}
+	*pending = 0;
+	if (!_get_mirror_dso_path(vg->cmd, &dso))
+		return_0;
 
 	if (!(name = build_dm_name(vg->cmd->mem, vg->name, lv->name, NULL)))
 		return_0;
 
-	/* FIXME Save a returned handle here so we can unregister it later */
-	if (!dm_event_register(dso, name, DM_EVENT_ALL_ERRORS))
+	if (!(dmevh = _create_dm_event_handler(name, dso, DM_EVENT_ALL_ERRORS)))
 		return_0;
 
-	log_info("Registered %s for events", name);
+	if (dm_event_get_registered_device(dmevh, 0)) {
+		dm_event_handler_destroy(dmevh);
+		return 0;
+	}
+
+	evmask = dm_event_handler_get_event_mask(dmevh);
+	if (evmask & DM_EVENT_REGISTRATION_PENDING) {
+		*pending = 1;
+		evmask &= ~DM_EVENT_REGISTRATION_PENDING;
+	}
 
-	return 1;
+	dm_event_handler_destroy(dmevh);
+
+	return evmask;
 }
 
-static int _target_unregister_events(struct lv_segment *seg,
-				     int events)
+/* FIXME This gets run while suspended and performs banned operations. */
+static int _target_set_events(struct lv_segment *seg, int evmask, int set)
 {
-	char *dso;
-	char *name;
+	char *dso, *name;
 	struct logical_volume *lv;
 	struct volume_group *vg;
+	struct dm_event_handler *dmevh;
+	int r;
 
 	lv = seg->lv;
 	vg = lv->vg;
 
-	/* FIXME Remove this and use handle to avoid config file race */
-	if (!_setup_registration(vg->cmd->mem, vg->cmd, &dso))
+	if (!_get_mirror_dso_path(vg->cmd, &dso))
 		return_0;
 
 	if (!(name = build_dm_name(vg->cmd->mem, vg->name, lv->name, NULL)))
 		return_0;
 
-	/* FIXME Use handle returned by registration function instead of dso */
-	if (!dm_event_unregister(dso, name, DM_EVENT_ALL_ERRORS))
+	if (!(dmevh = _create_dm_event_handler(name, dso, DM_EVENT_ALL_ERRORS)))
 		return_0;
 
-	log_info("Unregistered %s for events", name);
+	r = set ? dm_event_register_handler(dmevh) : dm_event_unregister_handler(dmevh);
+	dm_event_handler_destroy(dmevh);
+	if (!r)
+		return_0;
+
+	log_info("%s %s for events", set ? "Monitored" : "Unmonitored", name);
 
 	return 1;
 }
 
+static int _target_monitor_events(struct lv_segment *seg, int events)
+{
+	return _target_set_events(seg, events, 1);
+}
+
+static int _target_unmonitor_events(struct lv_segment *seg, int events)
+{
+	return _target_set_events(seg, events, 0);
+}
+
 #endif /* DMEVENTD */
 #endif /* DEVMAPPER_SUPPORT */
 
@@ -486,8 +530,9 @@
 	.target_percent = _mirrored_target_percent,
 	.target_present = _mirrored_target_present,
 #ifdef DMEVENTD
-	.target_register_events = _target_register_events,
-	.target_unregister_events = _target_unregister_events,
+	.target_monitored = _target_monitored,
+	.target_monitor_events = _target_monitor_events,
+	.target_unmonitor_events = _target_unmonitor_events,
 #endif
 #endif
 	.modules_needed = _mirrored_modules_needed,
@@ -512,7 +557,7 @@
 	segtype->ops = &_mirrored_ops;
 	segtype->name = "mirror";
 	segtype->private = NULL;
-	segtype->flags = SEG_AREAS_MIRRORED;
+	segtype->flags = SEG_AREAS_MIRRORED | SEG_MONITORED;
 
 	log_very_verbose("Initialised segtype: %s", segtype->name);
 

Modified: lvm2/upstream/current/lib/misc/lvm-file.c
==============================================================================
--- lvm2/upstream/current/lib/misc/lvm-file.c	(original)
+++ lvm2/upstream/current/lib/misc/lvm-file.c	Sat Apr  7 15:30:42 2007
@@ -66,7 +66,8 @@
 		if (!fcntl(*fd, F_SETLK, &lock))
 			return 1;
 
-		close(*fd);
+		if (close(*fd))
+			log_sys_error("close", buffer);
 	}
 
 	return 0;
@@ -239,8 +240,80 @@
 	if (fsync(fd) && (errno != EROFS) && (errno != EINVAL))
 		log_sys_error("fsync", dir);
 
-	close(fd);
+	if (close(fd))
+		log_sys_error("close", dir);
 
       out:
 	dm_free(dir);
 }
+
+/*
+ * Attempt to obtain fcntl lock on a file, if necessary creating file first
+ * or waiting.
+ * Returns file descriptor on success, else -1.
+ * mode is F_WRLCK or F_RDLCK
+ */
+int fcntl_lock_file(const char *file, short lock_type, int warn_if_read_only)
+{
+	int lockfd;
+	char *dir;
+	char *c;
+	struct flock lock = {
+		.l_type = lock_type,
+		.l_whence = 0,
+		.l_start = 0,
+		.l_len = 0
+	};
+
+	if (!(dir = dm_strdup(file))) {
+		log_error("fcntl_lock_file failed in strdup.");
+		return -1;
+	}
+
+	if ((c = strrchr(dir, '/')))
+		*c = '\0';
+
+	if (!create_dir(dir))
+		return -1;
+
+	log_very_verbose("Locking %s (%s, %hd)", file,
+			 (lock_type == F_WRLCK) ? "F_WRLCK" : "F_RDLCK",
+			 lock_type);
+	if ((lockfd = open(file, O_RDWR | O_CREAT, 0777)) < 0) {
+		/* EACCES has been reported on NFS */
+		if (warn_if_read_only || (errno != EROFS && errno != EACCES))
+			log_sys_error("open", file);
+		else
+			stack;
+
+		return -1;
+	}
+
+	if (fcntl(lockfd, F_SETLKW, &lock)) {
+		log_sys_error("fcntl", file);
+		return -1;
+	}
+
+	return lockfd;
+}
+
+void fcntl_unlock_file(int lockfd)
+{
+	struct flock lock = {
+		.l_type = F_UNLCK,
+		.l_whence = 0,
+		.l_start = 0,
+		.l_len = 0
+	};
+
+	log_very_verbose("Unlocking fd %d", lockfd);
+
+	if (fcntl(lockfd, F_SETLK, &lock) == -1)
+		log_error("fcntl unlock failed on fd %d: %s", lockfd,
+			  strerror(errno));
+
+	if (close(lockfd))
+		log_error("lock file close failed on fd %d: %s", lockfd,
+			  strerror(errno));
+}
+

Modified: lvm2/upstream/current/lib/misc/lvm-file.h
==============================================================================
--- lvm2/upstream/current/lib/misc/lvm-file.h	(original)
+++ lvm2/upstream/current/lib/misc/lvm-file.h	Sat Apr  7 15:30:42 2007
@@ -48,4 +48,8 @@
 /* Sync directory changes */
 void sync_dir(const char *file);
 
+/* fcntl locking wrappers */
+int fcntl_lock_file(const char *file, short lock_type, int warn_if_read_only);
+void fcntl_unlock_file(int lockfd);
+
 #endif

Modified: lvm2/upstream/current/lib/report/columns.h
==============================================================================
--- lvm2/upstream/current/lib/report/columns.h	(original)
+++ lvm2/upstream/current/lib/report/columns.h	Sat Apr  7 15:30:42 2007
@@ -18,67 +18,67 @@
  * Display Fn, Unique format identifier */
 
 /* *INDENT-OFF* */
-FIELD(LVS, lv, STR, "LV UUID", lvid.id[1], 38, uuid, "lv_uuid")
-FIELD(LVS, lv, STR, "LV", lvid, 4, lvname, "lv_name")
-FIELD(LVS, lv, STR, "Attr", lvid, 4, lvstatus, "lv_attr")
-FIELD(LVS, lv, NUM, "Maj", major, 3, int32, "lv_major")
-FIELD(LVS, lv, NUM, "Min", minor, 3, int32, "lv_minor")
-FIELD(LVS, lv, STR, "KMaj", lvid, 4, lvkmaj, "lv_kernel_major")
-FIELD(LVS, lv, STR, "KMin", lvid, 4, lvkmin, "lv_kernel_minor")
-FIELD(LVS, lv, NUM, "LSize", size, 5, size64, "lv_size")
-FIELD(LVS, lv, NUM, "#Seg", lvid, 4, lvsegcount, "seg_count")
-FIELD(LVS, lv, STR, "Origin", lvid, 6, origin, "origin")
-FIELD(LVS, lv, NUM, "Snap%", lvid, 6, snpercent, "snap_percent")
-FIELD(LVS, lv, NUM, "Copy%", lvid, 6, copypercent, "copy_percent")
-FIELD(LVS, lv, STR, "Move", lvid, 4, movepv, "move_pv")
-FIELD(LVS, lv, STR, "LV Tags", tags, 7, tags, "lv_tags")
-FIELD(LVS, lv, STR, "Log", lvid, 3, loglv, "mirror_log")
-FIELD(LVS, lv, STR, "Modules", lvid, 7, modules, "modules")
+FIELD(LVS, lv, STR, "LV UUID", lvid.id[1], 38, uuid, "lv_uuid", "Unique identifier")
+FIELD(LVS, lv, STR, "LV", lvid, 4, lvname, "lv_name", "Name.  LVs created for internal use are enclosed in brackets.")
+FIELD(LVS, lv, STR, "Attr", lvid, 4, lvstatus, "lv_attr", "Various attributes - see man page.")
+FIELD(LVS, lv, NUM, "Maj", major, 3, int32, "lv_major", "Persistent major number or -1 if not persistent.")
+FIELD(LVS, lv, NUM, "Min", minor, 3, int32, "lv_minor", "Persistent minor number or -1 if not persistent.")
+FIELD(LVS, lv, STR, "KMaj", lvid, 4, lvkmaj, "lv_kernel_major", "Currently assigned major number or -1 if LV is not active.")
+FIELD(LVS, lv, STR, "KMin", lvid, 4, lvkmin, "lv_kernel_minor", "Currently assigned minor number or -1 if LV is not active.")
+FIELD(LVS, lv, NUM, "LSize", size, 5, size64, "lv_size", "Size of LV in current units.")
+FIELD(LVS, lv, NUM, "#Seg", lvid, 4, lvsegcount, "seg_count", "Number of segments in LV.")
+FIELD(LVS, lv, STR, "Origin", lvid, 6, origin, "origin", "For snapshots, the origin device of this LV")
+FIELD(LVS, lv, NUM, "Snap%", lvid, 6, snpercent, "snap_percent", "For snapshots, the percentage full if LV is active.")
+FIELD(LVS, lv, NUM, "Copy%", lvid, 6, copypercent, "copy_percent", "For mirrors and pvmove, current percentage in-sync.")
+FIELD(LVS, lv, STR, "Move", lvid, 4, movepv, "move_pv", "For pvmove, Source PV of temporary LV created by pvmove")
+FIELD(LVS, lv, STR, "LV Tags", tags, 7, tags, "lv_tags", "Tags, if any.")
+FIELD(LVS, lv, STR, "Log", lvid, 3, loglv, "mirror_log", "For mirrors, the LV holding the synchronisation log.")
+FIELD(LVS, lv, STR, "Modules", lvid, 7, modules, "modules", "Kernel device-mapper modules required for this LV.")
 
-FIELD(PVS, pv, STR, "Fmt", id, 3, pvfmt, "pv_fmt")
-FIELD(PVS, pv, STR, "PV UUID", id, 38, uuid, "pv_uuid")
-FIELD(PVS, pv, NUM, "PSize", id, 5, pvsize, "pv_size")
-FIELD(PVS, pv, NUM, "DevSize", dev, 7, devsize, "dev_size")
-FIELD(PVS, pv, NUM, "1st PE", pe_start, 7, size64, "pe_start")
-FIELD(PVS, pv, NUM, "PFree", id, 5, pvfree, "pv_free")
-FIELD(PVS, pv, NUM, "Used", id, 4, pvused, "pv_used")
-FIELD(PVS, pv, STR, "PV", dev, 10, dev_name, "pv_name")
-FIELD(PVS, pv, STR, "Attr", status, 4, pvstatus, "pv_attr")
-FIELD(PVS, pv, NUM, "PE", pe_count, 3, uint32, "pv_pe_count")
-FIELD(PVS, pv, NUM, "Alloc", pe_alloc_count, 5, uint32, "pv_pe_alloc_count")
-FIELD(PVS, pv, STR, "PV Tags", tags, 7, tags, "pv_tags")
+FIELD(PVS, pv, STR, "Fmt", id, 3, pvfmt, "pv_fmt", "Type of metadata.")
+FIELD(PVS, pv, STR, "PV UUID", id, 38, uuid, "pv_uuid", "Unique identifier.")
+FIELD(PVS, pv, NUM, "PSize", id, 5, pvsize, "pv_size", "Size of PV in current units.")
+FIELD(PVS, pv, NUM, "DevSize", dev, 7, devsize, "dev_size", "Size of underlying device in current units.")
+FIELD(PVS, pv, NUM, "1st PE", pe_start, 7, size64, "pe_start", "Offset to the start of data on the underlying device.")
+FIELD(PVS, pv, NUM, "PFree", id, 5, pvfree, "pv_free", "Total amount of unallocated space in current units.")
+FIELD(PVS, pv, NUM, "Used", id, 4, pvused, "pv_used", "Total amount of allocated space in current units.")
+FIELD(PVS, pv, STR, "PV", dev, 10, dev_name, "pv_name", "Name.")
+FIELD(PVS, pv, STR, "Attr", status, 4, pvstatus, "pv_attr", "Various attributes - see man page.")
+FIELD(PVS, pv, NUM, "PE", pe_count, 3, uint32, "pv_pe_count", "Total number of Physical Extents.")
+FIELD(PVS, pv, NUM, "Alloc", pe_alloc_count, 5, uint32, "pv_pe_alloc_count", "Total number of allocated Physical Extents.")
+FIELD(PVS, pv, STR, "PV Tags", tags, 7, tags, "pv_tags", "Tags, if any.")
 
-FIELD(VGS, vg, STR, "Fmt", cmd, 3, vgfmt, "vg_fmt")
-FIELD(VGS, vg, STR, "VG UUID", id, 38, uuid, "vg_uuid")
-FIELD(VGS, vg, STR, "VG", name, 4, string, "vg_name")
-FIELD(VGS, vg, STR, "Attr", cmd, 5, vgstatus, "vg_attr")
-FIELD(VGS, vg, NUM, "VSize", cmd, 5, vgsize, "vg_size")
-FIELD(VGS, vg, NUM, "VFree", cmd, 5, vgfree, "vg_free")
-FIELD(VGS, vg, STR, "SYS ID", system_id, 6, string, "vg_sysid")
-FIELD(VGS, vg, NUM, "Ext", extent_size, 3, size32, "vg_extent_size")
-FIELD(VGS, vg, NUM, "#Ext", extent_count, 4, uint32, "vg_extent_count")
-FIELD(VGS, vg, NUM, "Free", free_count, 4, uint32, "vg_free_count")
-FIELD(VGS, vg, NUM, "MaxLV", max_lv, 5, uint32, "max_lv")
-FIELD(VGS, vg, NUM, "MaxPV", max_pv, 5, uint32, "max_pv")
-FIELD(VGS, vg, NUM, "#PV", pv_count, 3, uint32, "pv_count")
-FIELD(VGS, vg, NUM, "#LV", lv_count, 3, uint32, "lv_count")
-FIELD(VGS, vg, NUM, "#SN", snapshot_count, 3, uint32, "snap_count")
-FIELD(VGS, vg, NUM, "Seq", seqno, 3, uint32, "vg_seqno")
-FIELD(VGS, vg, STR, "VG Tags", tags, 7, tags, "vg_tags")
+FIELD(VGS, vg, STR, "Fmt", cmd, 3, vgfmt, "vg_fmt", "Type of metadata.")
+FIELD(VGS, vg, STR, "VG UUID", id, 38, uuid, "vg_uuid", "Unique identifier.")
+FIELD(VGS, vg, STR, "VG", name, 4, string, "vg_name", "Name.")
+FIELD(VGS, vg, STR, "Attr", cmd, 5, vgstatus, "vg_attr", "Various attributes - see man page.")
+FIELD(VGS, vg, NUM, "VSize", cmd, 5, vgsize, "vg_size", "Total size of VG in current units.")
+FIELD(VGS, vg, NUM, "VFree", cmd, 5, vgfree, "vg_free", "Total amount of free space in current units.")
+FIELD(VGS, vg, STR, "SYS ID", system_id, 6, string, "vg_sysid", "System ID indicating when and where it was created.")
+FIELD(VGS, vg, NUM, "Ext", extent_size, 3, size32, "vg_extent_size", "Size of Physical Extents in current units.")
+FIELD(VGS, vg, NUM, "#Ext", extent_count, 4, uint32, "vg_extent_count", "Total number of Physical Extents.")
+FIELD(VGS, vg, NUM, "Free", free_count, 4, uint32, "vg_free_count", "Total number of unallocated Physical Extents.")
+FIELD(VGS, vg, NUM, "MaxLV", max_lv, 5, uint32, "max_lv", "Maximum number of LVs allowed in VG or 0 if unlimited.")
+FIELD(VGS, vg, NUM, "MaxPV", max_pv, 5, uint32, "max_pv", "Maximum number of PVs allowed in VG or 0 if unlimited.")
+FIELD(VGS, vg, NUM, "#PV", pv_count, 3, uint32, "pv_count", "Number of PVs.")
+FIELD(VGS, vg, NUM, "#LV", lv_count, 3, uint32, "lv_count", "Number of LVs.")
+FIELD(VGS, vg, NUM, "#SN", snapshot_count, 3, uint32, "snap_count", "Number of snapshots.")
+FIELD(VGS, vg, NUM, "Seq", seqno, 3, uint32, "vg_seqno", "Revision number of internal metadata.  Incremented whenever it changes.")
+FIELD(VGS, vg, STR, "VG Tags", tags, 7, tags, "vg_tags", "Tags, if any.")
 
-FIELD(SEGS, seg, STR, "Type", list, 4, segtype, "segtype")
-FIELD(SEGS, seg, NUM, "#Str", area_count, 4, uint32, "stripes")
-FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripesize")
-FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripe_size")
-FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, "chunksize")
-FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, "chunk_size")
-FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "regionsize")
-FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "region_size")
-FIELD(SEGS, seg, NUM, "Start", list, 5, segstart, "seg_start")
-FIELD(SEGS, seg, NUM, "SSize", list, 5, segsize, "seg_size")
-FIELD(SEGS, seg, STR, "Seg Tags", tags, 8, tags, "seg_tags")
-FIELD(SEGS, seg, STR, "Devices", list, 5, devices, "devices")
+FIELD(SEGS, seg, STR, "Type", list, 4, segtype, "segtype", "Type of LV segment")
+FIELD(SEGS, seg, NUM, "#Str", area_count, 4, uint32, "stripes", "Number of stripes or mirror legs.")
+FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripesize", "For stripes, amount of data placed on one device before switching to the next.")
+FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripe_size", "For stripes, amount of data placed on one device before switching to the next.")
+FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "regionsize", "For mirrors, the unit of data copied when synchronising devices.")
+FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "region_size", "For mirrors, the unit of data copied when synchronising devices.")
+FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, "chunksize", "For snapshots, the unit of data used when tracking changes.")
+FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, "chunk_size", "For snapshots, the unit of data used when tracking changes.")
+FIELD(SEGS, seg, NUM, "Start", list, 5, segstart, "seg_start", "Offset within the LV to the start of the segment in current units.")
+FIELD(SEGS, seg, NUM, "SSize", list, 5, segsize, "seg_size", "Size of segment in current units.")
+FIELD(SEGS, seg, STR, "Seg Tags", tags, 8, tags, "seg_tags", "Tags, if any.")
+FIELD(SEGS, seg, STR, "Devices", list, 5, devices, "devices", "Underlying devices used with starting extent numbers.")
 
-FIELD(PVSEGS, pvseg, NUM, "Start", pe, 5, uint32, "pvseg_start")
-FIELD(PVSEGS, pvseg, NUM, "SSize", len, 5, uint32, "pvseg_size")
+FIELD(PVSEGS, pvseg, NUM, "Start", pe, 5, uint32, "pvseg_start", "Physical Extent number of start of segment.")
+FIELD(PVSEGS, pvseg, NUM, "SSize", len, 5, uint32, "pvseg_size", "Number of extents in segment.")
 /* *INDENT-ON* */

Modified: lvm2/upstream/current/lib/report/report.c
==============================================================================
--- lvm2/upstream/current/lib/report/report.c	(original)
+++ lvm2/upstream/current/lib/report/report.c	Sat Apr  7 15:30:42 2007
@@ -22,8 +22,17 @@
 #include "activate.h"
 #include "segtype.h"
 #include "str_list.h"
+#include "lvmcache.h"
 
-/* 
+struct lvm_report_object {
+	struct volume_group *vg;
+	struct logical_volume *lv;
+	struct physical_volume *pv;
+	struct lv_segment *seg;
+	struct pv_segment *pvseg;
+};
+
+/*
  * For macro use
  */
 static union {
@@ -34,71 +43,6 @@
 	struct pv_segment _pvseg;
 } _dummy;
 
-/*
- * Report handle flags
- */
-#define RH_SORT_REQUIRED	0x00000001
-#define RH_HEADINGS_PRINTED	0x00000002
-#define RH_BUFFERED		0x00000004
-#define RH_ALIGNED		0x00000008
-#define RH_HEADINGS		0x00000010
-
-struct report_handle {
-	struct cmd_context *cmd;
-	struct dm_pool *mem;
-
-	report_type_t type;
-	const char *field_prefix;
-	uint32_t flags;
-	const char *separator;
-
-	uint32_t keys_count;
-
-	/* Ordered list of fields needed for this report */
-	struct list field_props;
-
-	/* Rows of report data */
-	struct list rows;
-};
-
-/* 
- * Per-field flags
- */
-#define FLD_ALIGN_LEFT	0x00000001
-#define FLD_ALIGN_RIGHT	0x00000002
-#define FLD_STRING	0x00000004
-#define FLD_NUMBER	0x00000008
-#define FLD_HIDDEN	0x00000010
-#define FLD_SORT_KEY	0x00000020
-#define FLD_ASCENDING	0x00000040
-#define FLD_DESCENDING	0x00000080
-
-struct field_properties {
-	struct list list;
-	uint32_t field_num;
-	uint32_t sort_posn;
-	int width;
-	uint32_t flags;
-};
-
-/* 
- * Report data
- */
-struct field {
-	struct list list;
-	struct field_properties *props;
-
-	const char *report_string;	/* Formatted ready for display */
-	const void *sort_value;	/* Raw value for sorting */
-};
-
-struct row {
-	struct list list;
-	struct report_handle *rh;
-	struct list fields;	/* Fields in display order */
-	struct field *(*sort_fields)[];	/* Fields in sort order */
-};
-
 static char _alloc_policy_char(alloc_policy_t alloc)
 {
 	switch (alloc) {
@@ -118,31 +62,25 @@
 /*
  * Data-munging functions to prepare each data type for display and sorting
  */
-static int _string_disp(struct report_handle *rh, struct field *field,
-			const void *data)
+static int _string_disp(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field,
+			const void *data, void *private)
 {
-	if (!
-	    (field->report_string =
-	     dm_pool_strdup(rh->mem, *(const char **) data))) {
-		log_error("dm_pool_strdup failed");
-		return 0;
-	}
-
-	field->sort_value = (const void *) field->report_string;
-
-	return 1;
+	return dm_report_field_string(rh, field, (const char **) data);
 }
 
-static int _dev_name_disp(struct report_handle *rh, struct field *field,
-			  const void *data)
+static int _dev_name_disp(struct dm_report *rh, struct dm_pool *mem,
+			  struct dm_report_field *field,
+			  const void *data, void *private)
 {
 	const char *name = dev_name(*(const struct device **) data);
 
-	return _string_disp(rh, field, &name);
+	return dm_report_field_string(rh, field, &name);
 }
 
-static int _devices_disp(struct report_handle *rh, struct field *field,
-			 const void *data)
+static int _devices_disp(struct dm_report *rh, struct dm_pool *mem,
+			 struct dm_report_field *field,
+			 const void *data, void *private)
 {
 	const struct lv_segment *seg = (const struct lv_segment *) data;
 	unsigned int s;
@@ -150,7 +88,7 @@
 	uint32_t extent = 0;
 	char extent_str[32];
 
-	if (!dm_pool_begin_object(rh->mem, 256)) {
+	if (!dm_pool_begin_object(mem, 256)) {
 		log_error("dm_pool_begin_object failed");
 		return 0;
 	}
@@ -170,7 +108,7 @@
 			extent = 0;
 		}
 
-		if (!dm_pool_grow_object(rh->mem, name, strlen(name))) {
+		if (!dm_pool_grow_object(mem, name, strlen(name))) {
 			log_error("dm_pool_grow_object failed");
 			return 0;
 		}
@@ -181,173 +119,143 @@
 			return 0;
 		}
 
-		if (!dm_pool_grow_object(rh->mem, extent_str, strlen(extent_str))) {
+		if (!dm_pool_grow_object(mem, extent_str, strlen(extent_str))) {
 			log_error("dm_pool_grow_object failed");
 			return 0;
 		}
 
 		if ((s != seg->area_count - 1) &&
-		    !dm_pool_grow_object(rh->mem, ",", 1)) {
+		    !dm_pool_grow_object(mem, ",", 1)) {
 			log_error("dm_pool_grow_object failed");
 			return 0;
 		}
 	}
 
-	if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
+	if (!dm_pool_grow_object(mem, "\0", 1)) {
 		log_error("dm_pool_grow_object failed");
 		return 0;
 	}
 
-	field->report_string = dm_pool_end_object(rh->mem);
-	field->sort_value = (const void *) field->report_string;
+	dm_report_field_set_value(field, dm_pool_end_object(mem), NULL);
 
 	return 1;
 }
 
-static int _tags_disp(struct report_handle *rh, struct field *field,
-		      const void *data)
+static int _tags_disp(struct dm_report *rh, struct dm_pool *mem,
+		      struct dm_report_field *field,
+		      const void *data, void *private)
 {
 	const struct list *tags = (const struct list *) data;
 	struct str_list *sl;
 
-	if (!dm_pool_begin_object(rh->mem, 256)) {
+	if (!dm_pool_begin_object(mem, 256)) {
 		log_error("dm_pool_begin_object failed");
 		return 0;
 	}
 
 	list_iterate_items(sl, tags) {
-		if (!dm_pool_grow_object(rh->mem, sl->str, strlen(sl->str)) ||
-		    (sl->list.n != tags && !dm_pool_grow_object(rh->mem, ",", 1))) {
+		if (!dm_pool_grow_object(mem, sl->str, strlen(sl->str)) ||
+		    (sl->list.n != tags && !dm_pool_grow_object(mem, ",", 1))) {
 			log_error("dm_pool_grow_object failed");
 			return 0;
 		}
 	}
 
-	if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
+	if (!dm_pool_grow_object(mem, "\0", 1)) {
 		log_error("dm_pool_grow_object failed");
 		return 0;
 	}
 
-	field->report_string = dm_pool_end_object(rh->mem);
-	field->sort_value = (const void *) field->report_string;
+	dm_report_field_set_value(field, dm_pool_end_object(mem), NULL);
 
 	return 1;
 }
 
-static int _modules_disp(struct report_handle *rh, struct field *field,
-			 const void *data)
+static int _modules_disp(struct dm_report *rh, struct dm_pool *mem,
+			 struct dm_report_field *field,
+			 const void *data, void *private)
 {
 	const struct logical_volume *lv = (const struct logical_volume *) data;
 	struct list *modules;
 
-	if (!(modules = str_list_create(rh->mem))) {
+	if (!(modules = str_list_create(mem))) {
 		log_error("modules str_list allocation failed");
 		return 0;
 	}
 
-	if (!list_lv_modules(rh->mem, lv, modules))
+	if (!list_lv_modules(mem, lv, modules))
 		return_0;
 
-	return _tags_disp(rh, field, modules);
+	return _tags_disp(rh, mem, field, modules, private);
 }
 
-static int _vgfmt_disp(struct report_handle *rh, struct field *field,
-		       const void *data)
+static int _vgfmt_disp(struct dm_report *rh, struct dm_pool *mem,
+		       struct dm_report_field *field,
+		       const void *data, void *private)
 {
 	const struct volume_group *vg = (const struct volume_group *) data;
 
 	if (!vg->fid) {
-		field->report_string = "";
-		field->sort_value = (const void *) field->report_string;
+		dm_report_field_set_value(field, "", NULL);
 		return 1;
 	}
 
-	return _string_disp(rh, field, &vg->fid->fmt->name);
+	return _string_disp(rh, mem, field, &vg->fid->fmt->name, private);
 }
 
-static int _pvfmt_disp(struct report_handle *rh, struct field *field,
-		       const void *data)
+static int _pvfmt_disp(struct dm_report *rh, struct dm_pool *mem,
+		       struct dm_report_field *field,
+		       const void *data, void *private)
 {
 	const struct physical_volume *pv =
 	    (const struct physical_volume *) data;
 
 	if (!pv->fmt) {
-		field->report_string = "";
-		field->sort_value = (const void *) field->report_string;
+		dm_report_field_set_value(field, "", NULL);
 		return 1;
 	}
 
-	return _string_disp(rh, field, &pv->fmt->name);
+	return _string_disp(rh, mem, field, &pv->fmt->name, private);
 }
 
-static int _int_disp(struct report_handle *rh, struct field *field,
-		     const void *data)
-{
-	const int value = *(const int *) data;
-	uint64_t *sortval;
-	char *repstr;
-
-	if (!(repstr = dm_pool_zalloc(rh->mem, 13))) {
-		log_error("dm_pool_alloc failed");
-		return 0;
-	}
-
-	if (!(sortval = dm_pool_alloc(rh->mem, sizeof(int64_t)))) {
-		log_error("dm_pool_alloc failed");
-		return 0;
-	}
-
-	if (dm_snprintf(repstr, 12, "%d", value) < 0) {
-		log_error("int too big: %d", value);
-		return 0;
-	}
-
-	*sortval = (const uint64_t) value;
-	field->sort_value = sortval;
-	field->report_string = repstr;
-
-	return 1;
-}
-
-static int _lvkmaj_disp(struct report_handle *rh, struct field *field,
-			const void *data)
+static int _lvkmaj_disp(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field,
+			const void *data, void *private)
 {
 	const struct logical_volume *lv = (const struct logical_volume *) data;
 	struct lvinfo info;
 	uint64_t minusone = UINT64_C(-1);
 
 	if (lv_info(lv->vg->cmd, lv, &info, 0) && info.exists)
-		return _int_disp(rh, field, &info.major);
-	else
-		return _int_disp(rh, field, &minusone);
+		return dm_report_field_int(rh, field, &info.major);
 
-	return 1;
+	return dm_report_field_uint64(rh, field, &minusone);
 }
 
-static int _lvkmin_disp(struct report_handle *rh, struct field *field,
-			const void *data)
+static int _lvkmin_disp(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field,
+			const void *data, void *private)
 {
 	const struct logical_volume *lv = (const struct logical_volume *) data;
 	struct lvinfo info;
 	uint64_t minusone = UINT64_C(-1);
 
 	if (lv_info(lv->vg->cmd, lv, &info, 0) && info.exists)
-		return _int_disp(rh, field, &info.minor);
-	else
-		return _int_disp(rh, field, &minusone);
+		return dm_report_field_int(rh, field, &info.minor);
 
-	return 1;
+	return dm_report_field_uint64(rh, field, &minusone);
 }
 
-static int _lvstatus_disp(struct report_handle *rh, struct field *field,
-			  const void *data)
+static int _lvstatus_disp(struct dm_report *rh, struct dm_pool *mem,
+			  struct dm_report_field *field,
+			  const void *data, void *private)
 {
 	const struct logical_volume *lv = (const struct logical_volume *) data;
 	struct lvinfo info;
 	char *repstr;
 	float snap_percent;
 
-	if (!(repstr = dm_pool_zalloc(rh->mem, 7))) {
+	if (!(repstr = dm_pool_zalloc(mem, 7))) {
 		log_error("dm_pool_alloc failed");
 		return 0;
 	}
@@ -419,19 +327,18 @@
 		repstr[5] = '-';
 	}
 
-	field->report_string = repstr;
-	field->sort_value = (const void *) field->report_string;
-
+	dm_report_field_set_value(field, repstr, NULL);
 	return 1;
 }
 
-static int _pvstatus_disp(struct report_handle *rh, struct field *field,
-			  const void *data)
+static int _pvstatus_disp(struct dm_report *rh, struct dm_pool *mem,
+			  struct dm_report_field *field,
+			  const void *data, void *private)
 {
 	const uint32_t status = *(const uint32_t *) data;
 	char *repstr;
 
-	if (!(repstr = dm_pool_zalloc(rh->mem, 4))) {
+	if (!(repstr = dm_pool_zalloc(mem, 4))) {
 		log_error("dm_pool_alloc failed");
 		return 0;
 	}
@@ -446,19 +353,18 @@
 	else
 		repstr[1] = '-';
 
-	field->report_string = repstr;
-	field->sort_value = (const void *) field->report_string;
-
+	dm_report_field_set_value(field, repstr, NULL);
 	return 1;
 }
 
-static int _vgstatus_disp(struct report_handle *rh, struct field *field,
-			  const void *data)
+static int _vgstatus_disp(struct dm_report *rh, struct dm_pool *mem,
+			  struct dm_report_field *field,
+			  const void *data, void *private)
 {
 	const struct volume_group *vg = (const struct volume_group *) data;
 	char *repstr;
 
-	if (!(repstr = dm_pool_zalloc(rh->mem, 7))) {
+	if (!(repstr = dm_pool_zalloc(mem, 7))) {
 		log_error("dm_pool_alloc failed");
 		return 0;
 	}
@@ -490,43 +396,43 @@
 	else
 		repstr[5] = '-';
 
-	field->report_string = repstr;
-	field->sort_value = (const void *) field->report_string;
-
+	dm_report_field_set_value(field, repstr, NULL);
 	return 1;
 }
 
-static int _segtype_disp(struct report_handle *rh __attribute((unused)),
-			 struct field *field,
-			 const void *data)
+static int _segtype_disp(struct dm_report *rh __attribute((unused)),
+			 struct dm_pool *mem,
+			 struct dm_report_field *field,
+			 const void *data, void *private)
 {
 	const struct lv_segment *seg = (const struct lv_segment *) data;
 
-	if (seg->area_count == 1)
-		field->report_string = "linear";
-	else
-		field->report_string = seg->segtype->ops->name(seg);
-	field->sort_value = (const void *) field->report_string;
+	if (seg->area_count == 1) {
+		dm_report_field_set_value(field, "linear", NULL);
+		return 1;
+	}
 
+	dm_report_field_set_value(field, seg->segtype->ops->name(seg), NULL);
 	return 1;
 }
 
-static int _origin_disp(struct report_handle *rh, struct field *field,
-			const void *data)
+static int _origin_disp(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field,
+			const void *data, void *private)
 {
 	const struct logical_volume *lv = (const struct logical_volume *) data;
 
 	if (lv_is_cow(lv))
-		return _string_disp(rh, field, &origin_from_cow(lv)->name);
-
-	field->report_string = "";
-	field->sort_value = (const void *) field->report_string;
+		return dm_report_field_string(rh, field,
+					      (const char **) &origin_from_cow(lv)->name);
 
+	dm_report_field_set_value(field, "", NULL);
 	return 1;
 }
 
-static int _loglv_disp(struct report_handle *rh, struct field *field,
-		       const void *data)
+static int _loglv_disp(struct dm_report *rh, struct dm_pool *mem,
+		       struct dm_report_field *field,
+		       const void *data, void *private)
 {
 	const struct logical_volume *lv = (const struct logical_volume *) data;
 	struct lv_segment *seg;
@@ -534,29 +440,29 @@
 	list_iterate_items(seg, &lv->segments) {
 		if (!seg_is_mirrored(seg) || !seg->log_lv)
 			continue;
-		return _string_disp(rh, field, &seg->log_lv->name);
+		return dm_report_field_string(rh, field,
+					      (const char **) &seg->log_lv->name);
 	}
 
-	field->report_string = "";
-	field->sort_value = (const void *) field->report_string;
-
+	dm_report_field_set_value(field, "", NULL);
 	return 1;
 }
 
-static int _lvname_disp(struct report_handle *rh, struct field *field,
-			const void *data)
+static int _lvname_disp(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field,
+			const void *data, void *private)
 {
 	const struct logical_volume *lv = (const struct logical_volume *) data;
-	char *repstr;
+	char *repstr, *lvname;
 	size_t len;
 
 	if (lv_is_visible(lv)) {
 		repstr = lv->name;
-		return _string_disp(rh, field, &repstr);
+		return dm_report_field_string(rh, field, (const char **) &repstr);
 	}
 
 	len = strlen(lv->name) + 3;
-	if (!(repstr = dm_pool_zalloc(rh->mem, len))) {
+	if (!(repstr = dm_pool_zalloc(mem, len))) {
 		log_error("dm_pool_alloc failed");
 		return 0;
 	}
@@ -566,18 +472,19 @@
 		return 0;
 	}
 
-	field->report_string = repstr;
-
-	if (!(field->sort_value = dm_pool_strdup(rh->mem, lv->name))) {
+	if (!(lvname = dm_pool_strdup(mem, lv->name))) {
 		log_error("dm_pool_strdup failed");
 		return 0;
 	}
 
+	dm_report_field_set_value(field, repstr, lvname);
+
 	return 1;
 }
 
-static int _movepv_disp(struct report_handle *rh, struct field *field,
-			const void *data)
+static int _movepv_disp(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field,
+			const void *data, void *private)
 {
 	const struct logical_volume *lv = (const struct logical_volume *) data;
 	const char *name;
@@ -587,106 +494,111 @@
 		if (!(seg->status & PVMOVE))
 			continue;
 		name = dev_name(seg_dev(seg, 0));
-		return _string_disp(rh, field, &name);
+		return dm_report_field_string(rh, field, &name);
 	}
 
-	field->report_string = "";
-	field->sort_value = (const void *) field->report_string;
-
+	dm_report_field_set_value(field, "", NULL);
 	return 1;
 }
 
-static int _size32_disp(struct report_handle *rh, struct field *field,
-			const void *data)
+static int _size32_disp(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field,
+			const void *data, void *private)
 {
 	const uint32_t size = *(const uint32_t *) data;
-	const char *disp;
+	const char *disp, *repstr;
 	uint64_t *sortval;
 
-	if (!*(disp = display_size_units(rh->cmd, (uint64_t) size))) {
+	if (!*(disp = display_size_units(private, (uint64_t) size))) {
 		stack;
 		return 0;
 	}
 
-	if (!(field->report_string = dm_pool_strdup(rh->mem, disp))) {
+	if (!(repstr = dm_pool_strdup(mem, disp))) {
 		log_error("dm_pool_strdup failed");
 		return 0;
 	}
 
-	if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
+	if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
 		log_error("dm_pool_alloc failed");
 		return 0;
 	}
 
 	*sortval = (const uint64_t) size;
-	field->sort_value = (const void *) sortval;
+
+	dm_report_field_set_value(field, repstr, sortval);
 
 	return 1;
 }
 
-static int _size64_disp(struct report_handle *rh, struct field *field,
-			const void *data)
+static int _size64_disp(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field,
+			const void *data, void *private)
 {
 	const uint64_t size = *(const uint64_t *) data;
-	const char *disp;
+	const char *disp, *repstr;
 	uint64_t *sortval;
 
-	if (!*(disp = display_size_units(rh->cmd, size))) {
+	if (!*(disp = display_size_units(private, size))) {
 		stack;
 		return 0;
 	}
 
-	if (!(field->report_string = dm_pool_strdup(rh->mem, disp))) {
+	if (!(repstr = dm_pool_strdup(mem, disp))) {
 		log_error("dm_pool_strdup failed");
 		return 0;
 	}
 
-	if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
+	if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
 		log_error("dm_pool_alloc failed");
 		return 0;
 	}
 
 	*sortval = size;
-	field->sort_value = sortval;
+	dm_report_field_set_value(field, repstr, sortval);
 
 	return 1;
 }
 
-static int _vgsize_disp(struct report_handle *rh, struct field *field,
-			const void *data)
+static int _vgsize_disp(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field,
+			const void *data, void *private)
 {
 	const struct volume_group *vg = (const struct volume_group *) data;
 	uint64_t size;
 
 	size = (uint64_t) vg->extent_count * vg->extent_size;
 
-	return _size64_disp(rh, field, &size);
+	return _size64_disp(rh, mem, field, &size, private);
 }
 
-static int _segstart_disp(struct report_handle *rh, struct field *field,
-			  const void *data)
+static int _segstart_disp(struct dm_report *rh, struct dm_pool *mem,
+			  struct dm_report_field *field,
+			  const void *data, void *private)
 {
 	const struct lv_segment *seg = (const struct lv_segment *) data;
 	uint64_t start;
 
 	start = (uint64_t) seg->le * seg->lv->vg->extent_size;
 
-	return _size64_disp(rh, field, &start);
+	return _size64_disp(rh, mem, field, &start, private);
 }
 
-static int _segsize_disp(struct report_handle *rh, struct field *field,
-			 const void *data)
+static int _segsize_disp(struct dm_report *rh, struct dm_pool *mem,
+			 struct dm_report_field *field,
+			 const void *data, void *private)
 {
 	const struct lv_segment *seg = (const struct lv_segment *) data;
 	uint64_t size;
 
 	size = (uint64_t) seg->len * seg->lv->vg->extent_size;
 
-	return _size64_disp(rh, field, &size);
+	return _size64_disp(rh, mem, field, &size, private);
 }
 
-static int _chunksize_disp(struct report_handle *rh, struct field *field,
-			   const void *data)
+static int _chunksize_disp(struct dm_report *rh, struct dm_pool *mem,
+			   struct dm_report_field *field,
+			   const void *data, void *private)
 {
 	const struct lv_segment *seg = (const struct lv_segment *) data;
 	uint64_t size;
@@ -696,11 +608,12 @@
 	else
 		size = 0;
 
-	return _size64_disp(rh, field, &size);
+	return _size64_disp(rh, mem, field, &size, private);
 }
 
-static int _pvused_disp(struct report_handle *rh, struct field *field,
-			const void *data)
+static int _pvused_disp(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field,
+			const void *data, void *private)
 {
 	const struct physical_volume *pv =
 	    (const struct physical_volume *) data;
@@ -711,11 +624,12 @@
 	else
 		used = (uint64_t) pv->pe_alloc_count * pv->pe_size;
 
-	return _size64_disp(rh, field, &used);
+	return _size64_disp(rh, mem, field, &used, private);
 }
 
-static int _pvfree_disp(struct report_handle *rh, struct field *field,
-			const void *data)
+static int _pvfree_disp(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field,
+			const void *data, void *private)
 {
 	const struct physical_volume *pv =
 	    (const struct physical_volume *) data;
@@ -726,11 +640,12 @@
 	else
 		freespace = (uint64_t) (pv->pe_count - pv->pe_alloc_count) * pv->pe_size;
 
-	return _size64_disp(rh, field, &freespace);
+	return _size64_disp(rh, mem, field, &freespace, private);
 }
 
-static int _pvsize_disp(struct report_handle *rh, struct field *field,
-			const void *data)
+static int _pvsize_disp(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field,
+			const void *data, void *private)
 {
 	const struct physical_volume *pv =
 	    (const struct physical_volume *) data;
@@ -741,11 +656,12 @@
 	else
 		size = (uint64_t) pv->pe_count * pv->pe_size;
 
-	return _size64_disp(rh, field, &size);
+	return _size64_disp(rh, mem, field, &size, private);
 }
 
-static int _devsize_disp(struct report_handle *rh, struct field *field,
-			const void *data)
+static int _devsize_disp(struct dm_report *rh, struct dm_pool *mem,
+			 struct dm_report_field *field,
+			 const void *data, void *private)
 {
 	const struct device *dev = *(const struct device **) data;
 	uint64_t size;
@@ -753,26 +669,28 @@
 	if (!dev_get_size(dev, &size))
 		size = 0;
 
-	return _size64_disp(rh, field, &size);
+	return _size64_disp(rh, mem, field, &size, private);
 }
 
-static int _vgfree_disp(struct report_handle *rh, struct field *field,
-			const void *data)
+static int _vgfree_disp(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field,
+			const void *data, void *private)
 {
 	const struct volume_group *vg = (const struct volume_group *) data;
 	uint64_t freespace;
 
 	freespace = (uint64_t) vg->free_count * vg->extent_size;
 
-	return _size64_disp(rh, field, &freespace);
+	return _size64_disp(rh, mem, field, &freespace, private);
 }
 
-static int _uuid_disp(struct report_handle *rh, struct field *field,
-		      const void *data)
+static int _uuid_disp(struct dm_report *rh, struct dm_pool *mem,
+		      struct dm_report_field *field,
+		      const void *data, void *private)
 {
 	char *repstr = NULL;
 
-	if (!(repstr = dm_pool_alloc(rh->mem, 40))) {
+	if (!(repstr = dm_pool_alloc(mem, 40))) {
 		log_error("dm_pool_alloc failed");
 		return 0;
 	}
@@ -782,83 +700,39 @@
 		return 0;
 	}
 
-	field->report_string = repstr;
-	field->sort_value = (const void *) field->report_string;
-
+	dm_report_field_set_value(field, repstr, NULL);
 	return 1;
 }
 
-static int _uint32_disp(struct report_handle *rh, struct field *field,
-			const void *data)
+static int _uint32_disp(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field,
+			const void *data, void *private)
 {
-	const uint32_t value = *(const uint32_t *) data;
-	uint64_t *sortval;
-	char *repstr;
-
-	if (!(repstr = dm_pool_zalloc(rh->mem, 12))) {
-		log_error("dm_pool_alloc failed");
-		return 0;
-	}
-
-	if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
-		log_error("dm_pool_alloc failed");
-		return 0;
-	}
-
-	if (dm_snprintf(repstr, 11, "%u", value) < 0) {
-		log_error("uint32 too big: %u", value);
-		return 0;
-	}
-
-	*sortval = (const uint64_t) value;
-	field->sort_value = sortval;
-	field->report_string = repstr;
-
-	return 1;
+	return dm_report_field_uint32(rh, field, data);
 }
 
-static int _int32_disp(struct report_handle *rh, struct field *field,
-		       const void *data)
+static int _int32_disp(struct dm_report *rh, struct dm_pool *mem,
+		       struct dm_report_field *field,
+		       const void *data, void *private)
 {
-	const int32_t value = *(const int32_t *) data;
-	uint64_t *sortval;
-	char *repstr;
-
-	if (!(repstr = dm_pool_zalloc(rh->mem, 13))) {
-		log_error("dm_pool_alloc failed");
-		return 0;
-	}
-
-	if (!(sortval = dm_pool_alloc(rh->mem, sizeof(int64_t)))) {
-		log_error("dm_pool_alloc failed");
-		return 0;
-	}
-
-	if (dm_snprintf(repstr, 12, "%d", value) < 0) {
-		log_error("int32 too big: %d", value);
-		return 0;
-	}
-
-	*sortval = (const uint64_t) value;
-	field->sort_value = sortval;
-	field->report_string = repstr;
-
-	return 1;
+	return dm_report_field_int32(rh, field, data);
 }
 
-static int _lvsegcount_disp(struct report_handle *rh, struct field *field,
-			    const void *data)
+static int _lvsegcount_disp(struct dm_report *rh, struct dm_pool *mem,
+			    struct dm_report_field *field,
+			    const void *data, void *private)
 {
 	const struct logical_volume *lv = (const struct logical_volume *) data;
 	uint32_t count;
 
 	count = list_size(&lv->segments);
 
-	return _uint32_disp(rh, field, &count);
+	return _uint32_disp(rh, mem, field, &count, private);
 }
 
-static int _snpercent_disp(struct report_handle *rh, struct field *field,
-			   const void *data)
+static int _snpercent_disp(struct dm_report *rh, struct dm_pool *mem,
+			   struct dm_report_field *field,
+			   const void *data, void *private)
 {
 	const struct logical_volume *lv = (const struct logical_volume *) data;
 	struct lvinfo info;
@@ -866,27 +740,31 @@
 	uint64_t *sortval;
 	char *repstr;
 
-	if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
+	/* Suppress snapshot percentage if not using driver */
+	if (!activation()) {
+		dm_report_field_set_value(field, "", NULL);
+		return 1;
+	}
+
+	if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
 		log_error("dm_pool_alloc failed");
 		return 0;
 	}
 
 	if (!lv_is_cow(lv) ||
 	    (lv_info(lv->vg->cmd, lv, &info, 0) && !info.exists)) {
-		field->report_string = "";
 		*sortval = UINT64_C(0);
-		field->sort_value = sortval;
+		dm_report_field_set_value(field, "", sortval);
 		return 1;
 	}
 
 	if (!lv_snapshot_percent(lv, &snap_percent) || snap_percent < 0) {
-		field->report_string = "100.00";
 		*sortval = UINT64_C(100);
-		field->sort_value = sortval;
+		dm_report_field_set_value(field, "100.00", sortval);
 		return 1;
 	}
 
-	if (!(repstr = dm_pool_zalloc(rh->mem, 8))) {
+	if (!(repstr = dm_pool_zalloc(mem, 8))) {
 		log_error("dm_pool_alloc failed");
 		return 0;
 	}
@@ -897,36 +775,35 @@
 	}
 
 	*sortval = snap_percent * UINT64_C(1000);
-	field->sort_value = sortval;
-	field->report_string = repstr;
+	dm_report_field_set_value(field, repstr, sortval);
 
 	return 1;
 }
 
-static int _copypercent_disp(struct report_handle *rh, struct field *field,
-			     const void *data)
+static int _copypercent_disp(struct dm_report *rh, struct dm_pool *mem,
+			     struct dm_report_field *field,
+			     const void *data, void *private)
 {
 	struct logical_volume *lv = (struct logical_volume *) data;
 	float percent;
 	uint64_t *sortval;
 	char *repstr;
 
-	if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
+	if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
 		log_error("dm_pool_alloc failed");
 		return 0;
 	}
 
 	if ((!(lv->status & PVMOVE) && !(lv->status & MIRRORED)) ||
 	    !lv_mirror_percent(lv->vg->cmd, lv, 0, &percent, NULL)) {
-		field->report_string = "";
 		*sortval = UINT64_C(0);
-		field->sort_value = sortval;
+		dm_report_field_set_value(field, "", sortval);
 		return 1;
 	}
 
 	percent = copy_percent(lv);
 
-	if (!(repstr = dm_pool_zalloc(rh->mem, 8))) {
+	if (!(repstr = dm_pool_zalloc(mem, 8))) {
 		log_error("dm_pool_alloc failed");
 		return 0;
 	}
@@ -937,330 +814,88 @@
 	}
 
 	*sortval = percent * UINT64_C(1000);
-	field->sort_value = sortval;
-	field->report_string = repstr;
+	dm_report_field_set_value(field, repstr, sortval);
 
 	return 1;
 }
 
-/*
- * Import column definitions
- */
+/* Report object types */
 
-#define STR (FLD_STRING | FLD_ALIGN_LEFT)
-#define NUM (FLD_NUMBER | FLD_ALIGN_RIGHT)
-#define FIELD(type, strct, sorttype, head, field, width, func, id) {type, id, (off_t)((void *)&_dummy._ ## strct.field - (void *)&_dummy._ ## strct), head, width, sorttype, &_ ## func ## _disp},
-
-static struct {
-	report_type_t type;
-	const char id[32];
-	off_t offset;
-	const char heading[32];
-	int width;
-	uint32_t flags;
-	field_report_fn report_fn;
-} _fields[] = {
-#include "columns.h"
+/* necessary for displaying something for PVs not belonging to VG */
+static struct volume_group _dummy_vg = {
+	.name = (char *) ORPHAN,
 };
 
-#undef STR
-#undef NUM
-#undef FIELD
-
-const unsigned int _num_fields = sizeof(_fields) / sizeof(_fields[0]);
-
-static void _display_fields(void)
+static void *_obj_get_vg(void *obj)
 {
-	uint32_t f;
-	const char *type, *last_type = "";
-
-	for (f = 0; f < _num_fields; f++) {
-		switch (_fields[f].type) {
-		case PVS:
-			type = "Physical Volume";
-			break;
-		case LVS:
-			type = "Logical Volume";
-			break;
-		case VGS:
-			type = "Volume Group";
-			break;
-		case SEGS:
-			type = "Logical Volume Segment";
-			break;
-		case PVSEGS:
-			type = "Physical Volume Segment";
-			break;
-		default:
-			type = " ";
-		}
-
-		if (type != last_type) {
-			if (*last_type)
-				log_print(" ");
-			log_print("%s Fields", type);
-		}
-
-		log_print("- %s", _fields[f].id);
+	struct volume_group *vg = ((struct lvm_report_object *)obj)->vg;
 
-		last_type = type;
-	}
+	return vg ? vg : &_dummy_vg;
 }
 
-/*
- * Initialise report handle
- */
-static int _field_match(struct report_handle *rh, const char *field, size_t len)
+static void *_obj_get_lv(void *obj)
 {
-	uint32_t f, l;
-	struct field_properties *fp;
-
-	if (!len)
-		return 0;
-
-	for (f = 0; f < _num_fields; f++) {
-		if ((!strncasecmp(_fields[f].id, field, len) &&
-		     strlen(_fields[f].id) == len) ||
-		    (l = strlen(rh->field_prefix),
-		     !strncasecmp(rh->field_prefix, _fields[f].id, l) &&
-		     !strncasecmp(_fields[f].id + l, field, len) &&
-		     strlen(_fields[f].id) == l + len)) {
-			rh->type |= _fields[f].type;
-			if (!(fp = dm_pool_zalloc(rh->mem, sizeof(*fp)))) {
-				log_error("struct field_properties allocation "
-					  "failed");
-				return 0;
-			}
-			fp->field_num = f;
-			fp->width = _fields[f].width;
-			fp->flags = _fields[f].flags;
-
-			/* Suppress snapshot percentage if not using driver */
-			if (!activation()
-			    && !strncmp(field, "snap_percent", len))
-				fp->flags |= FLD_HIDDEN;
-
-			list_add(&rh->field_props, &fp->list);
-			return 1;
-		}
-	}
-
-	return 0;
+	return ((struct lvm_report_object *)obj)->lv;
 }
 
-static int _add_sort_key(struct report_handle *rh, uint32_t field_num,
-			 uint32_t flags)
+static void *_obj_get_pv(void *obj)
 {
-	struct field_properties *fp, *found = NULL;
-
-	list_iterate_items(fp, &rh->field_props) {
-		if (fp->field_num == field_num) {
-			found = fp;
-			break;
-		}
-	}
-
-	if (!found) {
-		/* Add as a non-display field */
-		if (!(found = dm_pool_zalloc(rh->mem, sizeof(*found)))) {
-			log_error("struct field_properties allocation failed");
-			return 0;
-		}
-
-		rh->type |= _fields[field_num].type;
-		found->field_num = field_num;
-		found->width = _fields[field_num].width;
-		found->flags = _fields[field_num].flags | FLD_HIDDEN;
-
-		list_add(&rh->field_props, &found->list);
-	}
-
-	if (found->flags & FLD_SORT_KEY) {
-		log_error("Ignoring duplicate sort field: %s",
-			  _fields[field_num].id);
-		return 1;
-	}
-
-	found->flags |= FLD_SORT_KEY;
-	found->sort_posn = rh->keys_count++;
-	found->flags |= flags;
-
-	return 1;
+	return ((struct lvm_report_object *)obj)->pv;
 }
 
-static int _key_match(struct report_handle *rh, const char *key, size_t len)
+static void *_obj_get_seg(void *obj)
 {
-	uint32_t f, l;
-	uint32_t flags = 0;
-
-	if (!len)
-		return 0;
-
-	if (*key == '+') {
-		key++;
-		len--;
-		flags = FLD_ASCENDING;
-	} else if (*key == '-') {
-		key++;
-		len--;
-		flags = FLD_DESCENDING;
-	} else
-		flags = FLD_ASCENDING;
-
-	if (!len) {
-		log_error("Missing sort field name");
-		return 0;
-	}
-
-	for (f = 0; f < _num_fields; f++) {
-		if ((!strncasecmp(_fields[f].id, key, len) &&
-		     strlen(_fields[f].id) == len) ||
-		    (l = strlen(rh->field_prefix),
-		     !strncasecmp(rh->field_prefix, _fields[f].id, l) &&
-		     !strncasecmp(_fields[f].id + l, key, len) &&
-		     strlen(_fields[f].id) == l + len)) {
-			return _add_sort_key(rh, f, flags);
-		}
-	}
-
-	return 0;
+	return ((struct lvm_report_object *)obj)->seg;
 }
 
-static int _parse_options(struct report_handle *rh, const char *format)
+static void *_obj_get_pvseg(void *obj)
 {
-	const char *ws;		/* Word start */
-	const char *we = format;	/* Word end */
+	return ((struct lvm_report_object *)obj)->pvseg;
+}
 
-	while (*we) {
-		/* Allow consecutive commas */
-		while (*we && *we == ',')
-			we++;
-		ws = we;
-		while (*we && *we != ',')
-			we++;
-		if (!_field_match(rh, ws, (size_t) (we - ws))) {
-			_display_fields();
-			log_print(" ");
-			log_error("Unrecognised field: %.*s", (int) (we - ws),
-				  ws);
-			return 0;
-		}
-	}
+static const struct dm_report_object_type _report_types[] = {
+	{ VGS, "Volume Group", "vg_", _obj_get_vg },
+	{ LVS, "Logical Volume", "lv_", _obj_get_lv },
+	{ PVS, "Physical Volume", "pv_", _obj_get_pv },
+	{ SEGS, "Logical Volume Segment", "seg_", _obj_get_seg },
+	{ PVSEGS, "Physical Volume Segment", "pvseg_", _obj_get_pvseg },
+	{ 0, "", "", NULL },
+};
 
-	return 1;
-}
+/*
+ * Import column definitions
+ */
 
-static int _parse_keys(struct report_handle *rh, const char *keys)
-{
-	const char *ws;		/* Word start */
-	const char *we = keys;	/* Word end */
+#define STR DM_REPORT_FIELD_TYPE_STRING
+#define NUM DM_REPORT_FIELD_TYPE_NUMBER
+#define FIELD(type, strct, sorttype, head, field, width, func, id, desc) {type, sorttype, (off_t)((void *)&_dummy._ ## strct.field - (void *)&_dummy._ ## strct), width, id, head, &_ ## func ## _disp, desc},
 
-	while (*we) {
-		/* Allow consecutive commas */
-		while (*we && *we == ',')
-			we++;
-		ws = we;
-		while (*we && *we != ',')
-			we++;
-		if (!_key_match(rh, ws, (size_t) (we - ws))) {
-			log_error("Unrecognised field: %.*s", (int) (we - ws),
-				  ws);
-			return 0;
-		}
-	}
+static struct dm_report_field_type _fields[] = {
+#include "columns.h"
+{0, 0, 0, 0, "", "", NULL, NULL},
+};
 
-	return 1;
-}
+#undef STR
+#undef NUM
+#undef FIELD
 
 void *report_init(struct cmd_context *cmd, const char *format, const char *keys,
-		  report_type_t *report_type, const char *separator,
-		  int aligned, int buffered, int headings)
+                  report_type_t *report_type, const char *separator,
+                  int aligned, int buffered, int headings)
 {
-	struct report_handle *rh;
-
-	if (!(rh = dm_pool_zalloc(cmd->mem, sizeof(*rh)))) {
-		log_error("report_handle dm_pool_zalloc failed");
-		return 0;
-	}
-
-	rh->cmd = cmd;
-	rh->type = *report_type;
-	rh->separator = separator;
+	uint32_t report_flags = 0;
 
 	if (aligned)
-		rh->flags |= RH_ALIGNED;
+		report_flags |= DM_REPORT_OUTPUT_ALIGNED;
 
 	if (buffered)
-		rh->flags |= RH_BUFFERED | RH_SORT_REQUIRED;
+		report_flags |= DM_REPORT_OUTPUT_BUFFERED;
 
 	if (headings)
-		rh->flags |= RH_HEADINGS;
-
-	list_init(&rh->field_props);
-	list_init(&rh->rows);
-
-	switch (rh->type) {
-	case PVS:
-		rh->field_prefix = "pv_";
-		break;
-	case LVS:
-		rh->field_prefix = "lv_";
-		break;
-	case VGS:
-		rh->field_prefix = "vg_";
-		break;
-	case SEGS:
-		rh->field_prefix = "seg_";
-		break;
-	case PVSEGS:
-		rh->field_prefix = "pvseg_";
-		break;
-	default:
-		rh->field_prefix = "";
-	}
-
-	if (!(rh->mem = dm_pool_create("report", 10 * 1024))) {
-		log_error("Allocation of memory pool for report failed");
-		return NULL;
-	}
-
-	/* Generate list of fields for output based on format string & flags */
-	if (!_parse_options(rh, format))
-		return NULL;
-
-	if (!_parse_keys(rh, keys))
-		return NULL;
+		report_flags |= DM_REPORT_OUTPUT_HEADINGS;
 
-	/* Ensure options selected are compatible */
-	if (rh->type & SEGS)
-		rh->type |= LVS;
-	if (rh->type & PVSEGS)
-		rh->type |= PVS;
-	if ((rh->type & LVS) && (rh->type & PVS)) {
-		log_error("Can't report LV and PV fields at the same time");
-		return NULL;
-	}
-
-	/* Change report type if fields specified makes this necessary */
-	if (rh->type & SEGS)
-		*report_type = SEGS;
-	else if (rh->type & LVS)
-		*report_type = LVS;
-	else if (rh->type & PVSEGS)
-		*report_type = PVSEGS;
-	else if (rh->type & PVS)
-		*report_type = PVS;
-
-	return rh;
-}
-
-void report_free(void *handle)
-{
-	struct report_handle *rh = handle;
-
-	dm_pool_destroy(rh->mem);
-
-	return;
+        return dm_report_init(report_type, _report_types, _fields, format,
+			      separator, report_flags, keys, cmd);
 }
 
 /*
@@ -1270,303 +905,13 @@
 		  struct logical_volume *lv, struct physical_volume *pv,
 		  struct lv_segment *seg, struct pv_segment *pvseg)
 {
-	struct report_handle *rh = handle;
-	struct field_properties *fp;
-	struct row *row;
-	struct field *field;
-	void *data = NULL;
-	int skip;
-
-	if (lv && pv) {
-		log_error("report_object: One of *lv and *pv must be NULL!");
-		return 0;
-	}
-
-	if (!(row = dm_pool_zalloc(rh->mem, sizeof(*row)))) {
-		log_error("struct row allocation failed");
-		return 0;
-	}
-
-	row->rh = rh;
-
-	if ((rh->flags & RH_SORT_REQUIRED) &&
-	    !(row->sort_fields = dm_pool_zalloc(rh->mem, sizeof(struct field *) *
-					     rh->keys_count))) {
-		log_error("row sort value structure allocation failed");
-		return 0;
-	}
-
-	list_init(&row->fields);
-	list_add(&rh->rows, &row->list);
-
-	/* For each field to be displayed, call its report_fn */
-	list_iterate_items(fp, &rh->field_props) {
-		skip = 0;
-
-		if (!(field = dm_pool_zalloc(rh->mem, sizeof(*field)))) {
-			log_error("struct field allocation failed");
-			return 0;
-		}
-		field->props = fp;
-
-		switch (_fields[fp->field_num].type) {
-		case LVS:
-			data = (void *) lv + _fields[fp->field_num].offset;
-			break;
-		case VGS:
-			if (!vg) {
-				skip = 1;
-				break;
-			}
-			data = (void *) vg + _fields[fp->field_num].offset;
-			break;
-		case PVS:
-			data = (void *) pv + _fields[fp->field_num].offset;
-			break;
-		case SEGS:
-			data = (void *) seg + _fields[fp->field_num].offset;
-			break;
-		case PVSEGS:
-			data = (void *) pvseg + _fields[fp->field_num].offset;
-		}
-
-		if (skip) {
-			field->report_string = "";
-			field->sort_value = (const void *) field->report_string;
-		} else if (!_fields[fp->field_num].report_fn(rh, field, data)) {
-			log_error("report function failed for field %s",
-				  _fields[fp->field_num].id);
-			return 0;
-		}
-
-		if ((strlen(field->report_string) > field->props->width))
-			field->props->width = strlen(field->report_string);
-
-		if ((rh->flags & RH_SORT_REQUIRED) &&
-		    (field->props->flags & FLD_SORT_KEY)) {
-			(*row->sort_fields)[field->props->sort_posn] = field;
-		}
-		list_add(&row->fields, &field->list);
-	}
-
-	if (!(rh->flags & RH_BUFFERED))
-		report_output(handle);
-
-	return 1;
-}
-
-/* 
- * Print row of headings 
- */
-static int _report_headings(void *handle)
-{
-	struct report_handle *rh = handle;
-	struct field_properties *fp;
-	const char *heading;
-	char buf[1024];
-
-	if (rh->flags & RH_HEADINGS_PRINTED)
-		return 1;
-
-	rh->flags |= RH_HEADINGS_PRINTED;
-
-	if (!(rh->flags & RH_HEADINGS))
-		return 1;
-
-	if (!dm_pool_begin_object(rh->mem, 128)) {
-		log_error("dm_pool_begin_object failed for headings");
-		return 0;
-	}
-
-	/* First heading line */
-	list_iterate_items(fp, &rh->field_props) {
-		if (fp->flags & FLD_HIDDEN)
-			continue;
-
-		heading = _fields[fp->field_num].heading;
-		if (rh->flags & RH_ALIGNED) {
-			if (dm_snprintf(buf, sizeof(buf), "%-*.*s",
-					 fp->width, fp->width, heading) < 0) {
-				log_error("snprintf heading failed");
-				dm_pool_end_object(rh->mem);
-				return 0;
-			}
-			if (!dm_pool_grow_object(rh->mem, buf, fp->width))
-				goto bad;
-		} else if (!dm_pool_grow_object(rh->mem, heading, strlen(heading)))
-			goto bad;
-
-		if (!list_end(&rh->field_props, &fp->list))
-			if (!dm_pool_grow_object(rh->mem, rh->separator,
-					      strlen(rh->separator)))
-				goto bad;
-	}
-	if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
-		log_error("dm_pool_grow_object failed");
-		goto bad;
-	}
-	log_print("%s", (char *) dm_pool_end_object(rh->mem));
-
-	return 1;
-
-      bad:
-	log_error("Failed to generate report headings for printing");
-
-	return 0;
-}
-
-/*
- * Sort rows of data
- */
-static int _row_compare(const void *a, const void *b)
-{
-	const struct row *rowa = *(const struct row **) a;
-	const struct row *rowb = *(const struct row **) b;
-	const struct field *sfa, *sfb;
-	int32_t cnt = -1;
-
-	for (cnt = 0; cnt < rowa->rh->keys_count; cnt++) {
-		sfa = (*rowa->sort_fields)[cnt];
-		sfb = (*rowb->sort_fields)[cnt];
-		if (sfa->props->flags & FLD_NUMBER) {
-			const uint64_t numa =
-			    *(const uint64_t *) sfa->sort_value;
-			const uint64_t numb =
-			    *(const uint64_t *) sfb->sort_value;
-
-			if (numa == numb)
-				continue;
-
-			if (sfa->props->flags & FLD_ASCENDING) {
-				return (numa > numb) ? 1 : -1;
-			} else {	/* FLD_DESCENDING */
-				return (numa < numb) ? 1 : -1;
-			}
-		} else {	/* FLD_STRING */
-			const char *stra = (const char *) sfa->sort_value;
-			const char *strb = (const char *) sfb->sort_value;
-			int cmp = strcmp(stra, strb);
-
-			if (!cmp)
-				continue;
-
-			if (sfa->props->flags & FLD_ASCENDING) {
-				return (cmp > 0) ? 1 : -1;
-			} else {	/* FLD_DESCENDING */
-				return (cmp < 0) ? 1 : -1;
-			}
-		}
-	}
-
-	return 0;		/* Identical */
-}
-
-static int _sort_rows(struct report_handle *rh)
-{
-	struct row *(*rows)[];
-	uint32_t count = 0;
-	struct row *row;
-
-	if (!(rows = dm_pool_alloc(rh->mem, sizeof(**rows) *
-				list_size(&rh->rows)))) {
-		log_error("sort array allocation failed");
-		return 0;
-	}
+	struct lvm_report_object obj;
 
-	list_iterate_items(row, &rh->rows)
-		(*rows)[count++] = row;
-
-	qsort(rows, count, sizeof(**rows), _row_compare);
-
-	list_init(&rh->rows);
-	while (count--)
-		list_add_h(&rh->rows, &(*rows)[count]->list);
-
-	return 1;
-}
-
-/*
- * Produce report output
- */
-int report_output(void *handle)
-{
-	struct report_handle *rh = handle;
-	struct list *fh, *rowh, *ftmp, *rtmp;
-	struct row *row = NULL;
-	struct field *field;
-	const char *repstr;
-	char buf[4096];
-	int width;
-
-	if (list_empty(&rh->rows))
-		return 1;
-
-	/* Sort rows */
-	if ((rh->flags & RH_SORT_REQUIRED))
-		_sort_rows(rh);
-
-	/* If headings not printed yet, calculate field widths and print them */
-	if (!(rh->flags & RH_HEADINGS_PRINTED))
-		_report_headings(rh);
-
-	/* Print and clear buffer */
-	list_iterate_safe(rowh, rtmp, &rh->rows) {
-		if (!dm_pool_begin_object(rh->mem, 512)) {
-			log_error("dm_pool_begin_object failed for row");
-			return 0;
-		}
-		row = list_item(rowh, struct row);
-		list_iterate_safe(fh, ftmp, &row->fields) {
-			field = list_item(fh, struct field);
-			if (field->props->flags & FLD_HIDDEN)
-				continue;
-
-			repstr = field->report_string;
-			width = field->props->width;
-			if (!(rh->flags & RH_ALIGNED)) {
-				if (!dm_pool_grow_object(rh->mem, repstr,
-						      strlen(repstr)))
-					goto bad;
-			} else if (field->props->flags & FLD_ALIGN_LEFT) {
-				if (dm_snprintf(buf, sizeof(buf), "%-*.*s",
-						 width, width, repstr) < 0) {
-					log_error("snprintf repstr failed");
-					dm_pool_end_object(rh->mem);
-					return 0;
-				}
-				if (!dm_pool_grow_object(rh->mem, buf, width))
-					goto bad;
-			} else if (field->props->flags & FLD_ALIGN_RIGHT) {
-				if (dm_snprintf(buf, sizeof(buf), "%*.*s",
-						 width, width, repstr) < 0) {
-					log_error("snprintf repstr failed");
-					dm_pool_end_object(rh->mem);
-					return 0;
-				}
-				if (!dm_pool_grow_object(rh->mem, buf, width))
-					goto bad;
-			}
-
-			if (!list_end(&row->fields, fh))
-				if (!dm_pool_grow_object(rh->mem, rh->separator,
-						      strlen(rh->separator)))
-					goto bad;
-			list_del(&field->list);
-		}
-		if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
-			log_error("dm_pool_grow_object failed for row");
-			return 0;
-		}
-		log_print("%s", (char *) dm_pool_end_object(rh->mem));
-		list_del(&row->list);
-	}
-
-	if (row)
-		dm_pool_free(rh->mem, row);
-
-	return 1;
+	obj.vg = vg;
+	obj.lv = lv;
+	obj.pv = pv;
+	obj.seg = seg;
+	obj.pvseg = pvseg;
 
-      bad:
-	log_error("Failed to generate row for printing");
-	return 0;
+	return dm_report_object(handle, &obj);
 }

Modified: lvm2/upstream/current/lib/snapshot/snapshot.c
==============================================================================
--- lvm2/upstream/current/lib/snapshot/snapshot.c	(original)
+++ lvm2/upstream/current/lib/snapshot/snapshot.c	Sat Apr  7 15:30:42 2007
@@ -112,7 +112,7 @@
 	return 1;
 }
 
-static int _snap_target_present(void)
+static int _snap_target_present(const struct lv_segment *seg __attribute((unused)))
 {
 	static int _snap_checked = 0;
 	static int _snap_present = 0;

Modified: lvm2/upstream/current/lib/striped/striped.c
==============================================================================
--- lvm2/upstream/current/lib/striped/striped.c	(original)
+++ lvm2/upstream/current/lib/striped/striped.c	Sat Apr  7 15:30:42 2007
@@ -174,7 +174,7 @@
 	return add_areas_line(dm, seg, node, 0u, seg->area_count);
 }
 
-static int _striped_target_present(void)
+static int _striped_target_present(const struct lv_segment *seg __attribute((unused)))
 {
 	static int _striped_checked = 0;
 	static int _striped_present = 0;

Modified: lvm2/upstream/current/lib/zero/zero.c
==============================================================================
--- lvm2/upstream/current/lib/zero/zero.c	(original)
+++ lvm2/upstream/current/lib/zero/zero.c	Sat Apr  7 15:30:42 2007
@@ -49,7 +49,7 @@
 	return dm_tree_node_add_zero_target(node, len);
 }
 
-static int _zero_target_present(void)
+static int _zero_target_present(const struct lv_segment *seg __attribute((unused)))
 {
 	static int _zero_checked = 0;
 	static int _zero_present = 0;

Modified: lvm2/upstream/current/make.tmpl.in
==============================================================================
--- lvm2/upstream/current/make.tmpl.in	(original)
+++ lvm2/upstream/current/make.tmpl.in	Sat Apr  7 15:30:42 2007
@@ -73,6 +73,13 @@
   DEFS += -DINTL_PACKAGE=\"@INTL_PACKAGE@\" -DLOCALEDIR=\"@LOCALEDIR@\"
 endif
 
+ifneq ("@DMDIR@", "")
+  LDFLAGS += -L at DMDIR@/lib/ioctl
+  ifeq ("@DMEVENTD@", "yes")
+    LDFLAGS += -L at DMDIR@/dmeventd
+  endif
+endif
+
 LDFLAGS += -L$(top_srcdir)/lib -L$(libdir)
 
 #DEFS += -DDEBUG_POOL
@@ -89,6 +96,10 @@
 
 INCLUDES += -I. -I$(top_srcdir)/include
 
+ifneq ("@DMDIR@", "")
+  INCLUDES += -I at DMDIR@/include
+endif
+
 ifdef DESTDIR
   INCLUDES += -I$(DESTDIR)/usr/include
 endif
@@ -162,18 +173,19 @@
 ifeq ("@LIB_SUFFIX@","so")
 $(LIB_SHARED): $(OBJECTS) $(LDDEPS)
 	$(CC) -shared -Wl,-soname,$(notdir $@).$(LIB_VERSION) \
-	$(CLDFLAGS) $(OBJECTS) $(LIBS) -o $@
+	$(CFLAGS) $(CLDFLAGS) $(OBJECTS) $(LIBS) -o $@
 endif
 
 ifeq ("@LIB_SUFFIX@","dylib")
 $(LIB_SHARED): $(OBJECTS) $(LDDEPS)
 	$(CC) -dynamiclib -dylib_current_version,$(LIB_VERSION) \
-	$(CLDFLAGS) $(OBJECTS) $(LIBS) -o $@
+	$(CFLAGS) $(CLDFLAGS) $(OBJECTS) $(LIBS) -o $@
 endif
 
 %.so: %.a
 	$(CC) -shared -Wl,-soname,$(notdir $@).$(LIB_VERSION) \
-	$(CLDFLAGS) $(LIBS) -o $@ @CLDWHOLEARCHIVE@ $< @CLDNOWHOLEARCHIVE@
+	$(CFLAGS) $(CLDFLAGS) $(LIBS) -o $@ \
+	@CLDWHOLEARCHIVE@ $< @CLDNOWHOLEARCHIVE@
 
 $(LIB_STATIC): $(OBJECTS)
 	$(RM) $@

Modified: lvm2/upstream/current/man/Makefile.in
==============================================================================
--- lvm2/upstream/current/man/Makefile.in	(original)
+++ lvm2/upstream/current/man/Makefile.in	Sat Apr  7 15:30:42 2007
@@ -18,8 +18,8 @@
 
 MAN5=lvm.conf.5
 MAN8=lvchange.8 lvconvert.8 lvcreate.8 lvdisplay.8 lvextend.8 lvm.8 \
-	lvmchange.8 \
-	lvmdiskscan.8 lvreduce.8 lvremove.8 lvrename.8 lvresize.8 lvs.8 \
+	lvmchange.8 lvmdiskscan.8 lvmdump.8 \
+	lvreduce.8 lvremove.8 lvrename.8 lvresize.8 lvs.8 \
 	lvscan.8 pvchange.8 pvcreate.8 pvdisplay.8 pvmove.8 pvremove.8 \
 	pvresize.8 pvs.8 pvscan.8 vgcfgbackup.8 vgcfgrestore.8 vgchange.8 \
 	vgck.8 vgcreate.8 vgconvert.8 vgdisplay.8 vgexport.8 vgextend.8 \

Modified: lvm2/upstream/current/man/clvmd.8
==============================================================================
--- lvm2/upstream/current/man/clvmd.8	(original)
+++ lvm2/upstream/current/man/clvmd.8	Sat Apr  7 15:30:42 2007
@@ -6,6 +6,7 @@
 [\-d] [\-h]
 [\-R]
 [\-t <timeout>]
+[\-T <start timeout>]
 [\-V]
 .SH DESCRIPTION
 clvmd is the daemon that distributes LVM metadata updates around a cluster.
@@ -23,6 +24,23 @@
 may need to increase this on systems with very large disk farms. 
 The default is 30 seconds.
 .TP
+.I \-T <start timeout>
+Specifies the timeout for clvmd daemon startup. If the daemon does not report 
+that it has started up within this time then the parent command will exit with 
+status of 5. This does NOT mean that clvmd has not started! What it means is 
+that the startup of clvmd has been delayed for some reason; the most likely 
+cause of this is an inquorate cluster though it could be due to locking 
+latencies on a cluster with large numbers of logical volumes. If you get the 
+return code of 5 it is usually not necessary to restart clvmd - it will start
+as soon as that blockage has cleared. This flag is to allow startup scripts
+to exit in a timely fashion even if the cluster is stalled for some reason.
+<br>
+The default is 0 (no timeout) and the value is in seconds. Don't set this too
+small or you will experience spurious errors. 10 or 20 seconds might be
+sensible.
+<br>
+This timeout will be ignored if you start clvmd with the -d switch.
+.TP
 .I \-R
 Tells all the running clvmd in the cluster to reload their device cache and
 re-read the lvm configuration file. This command should be run whenever the

Modified: lvm2/upstream/current/man/lvchange.8
==============================================================================
--- lvm2/upstream/current/man/lvchange.8	(original)
+++ lvm2/upstream/current/man/lvchange.8	Sat Apr  7 15:30:42 2007
@@ -7,11 +7,12 @@
 [\-A/\-\-autobackup y/n] [\-a/\-\-available y/n/ey/en/ly/ln]
 [\-\-alloc AllocationPolicy]
 [\-C/\-\-contiguous y/n] [\-d/\-\-debug] [\-\-deltag Tag]
+[\-\-resync]
 [\-h/\-?/\-\-help]
 [\-\-ignorelockingfailure]
 [\-\-monitor {y|n}]
 [\-M/\-\-persistent y/n] [\-\-minor minor]
-[\-P/\-\-partial y/n]
+[\-P/\-\-partial]
 [\-p/\-\-permission r/w] [\-r/\-\-readahead ReadAheadSectors]
 [\-\-refresh]
 [\-t/\-\-test]
@@ -40,6 +41,14 @@
 logical volume's allocation policy to contiguous, if all of the
 allocated physical extents are already contiguous.
 .TP
+.I \-\-resync
+Forces the complete resynchronization of a mirror.  In normal
+circumstances you should not need this option because synchronization
+happens automatically.  Data is read from the primary mirror device
+and copied to the others, so this can take a considerable amount of
+time - and during this time you are without a complete redundant copy
+of your data.
+.TP
 .I \-\-minor minor
 Set the minor number.
 .TP

Modified: lvm2/upstream/current/man/lvconvert.8
==============================================================================
--- lvm2/upstream/current/man/lvconvert.8	(original)
+++ lvm2/upstream/current/man/lvconvert.8	Sat Apr  7 15:30:42 2007
@@ -1,20 +1,35 @@
 .TH LVCONVERT 8 "LVM TOOLS" "Red Hat, Inc" \" -*- nroff -*-
 .SH NAME
-lvconvert \- convert a logical volume between linear and mirror
+lvconvert \- convert a logical volume from linear to mirror or snapshot
 .SH SYNOPSIS
 .B lvconvert
-[\-m/\-\-mirrors Mirrors [\-\-corelog] [\-R/\-\-regionsize MirrorLogRegionSize]]
+\-m/\-\-mirrors Mirrors [\-\-corelog] [\-R/\-\-regionsize MirrorLogRegionSize]
 [\-A/\-\-alloc AllocationPolicy]
 [\-h/\-?/\-\-help]
 [\-v/\-\-verbose]
 [\-\-version]
+.br
 LogicalVolume[Path] [PhysicalVolume[Path]...]
+.br
+
+.br
+.B lvconvert
+\-s/\-\-snapshot [\-c/\-\-chunksize ChunkSize]
+[\-h/\-?/\-\-help]
+[\-v/\-\-verbose]
+[\-Z/\-\-zero y/n]
+[\-\-version]
+.br
+OriginalLogicalVolume[Path] SnapshotLogicalVolume[Path]
 .SH DESCRIPTION
 lvconvert will change a linear logical volume to a mirror
-logical volume or vis versa.  It is also used to add and
-remove disk logs from mirror devices.
+logical volume or to a snapshot of linear volume and vice versa.
+It is also used to add and remove disk logs from mirror devices.
 .SH OPTIONS
 See \fBlvm\fP for common options.
+.br
+Exactly one of \-\-mirrors or \-\-snapshot arguments required.
+.br
 .TP
 .I \-m, \-\-mirrors Mirrors
 Specifies the degree of the mirror you wish to create.
@@ -32,6 +47,19 @@
 .I \-R, \-\-regionsize MirrorLogRegionSize
 A mirror is divided into regions of this size (in MB), and the mirror log
 uses this granularity to track which regions are in sync.
+.br
+.TP
+.I \-s, \-\-snapshot
+Create a snapshot from existing logical volume using another
+existing logical volume as its origin.
+.TP
+.I \-c, \-\-chunksize ChunkSize
+Power of 2 chunk size for the snapshot logical volume between 4k and 512k.
+.TP
+.I \-Z, \-\-zero y/n
+Controls zeroing of the first KB of data in the snapshot.
+If the volume is read-only the snapshot will not be zeroed.
+.br
 .SH Examples
 "lvconvert -m1 vg00/lvol1"
 .br
@@ -49,6 +77,12 @@
 .br
 converts a mirror logical volume to a linear logical
 volume.
+.br
+
+.br
+"lvconvert -s vg00/lvol1 vg00/lvol2"
+.br
+converts logical volume "vg00/lvol2" to snapshot of original volume "vg00/lvol1"
 
 .SH SEE ALSO
 .BR lvm (8),

Modified: lvm2/upstream/current/man/lvcreate.8
==============================================================================
--- lvm2/upstream/current/man/lvcreate.8	(original)
+++ lvm2/upstream/current/man/lvcreate.8	Sat Apr  7 15:30:42 2007
@@ -70,10 +70,11 @@
 in the Volume Group with the suffix %VG or of the remaining free space
 with the suffix %FREE.
 .TP
-.I \-L, \-\-size LogicalVolumeSize[kKmMgGtT]
+.I \-L, \-\-size LogicalVolumeSize[kKmMgGtTpPeE]
 Gives the size to allocate for the new logical volume.
 A size suffix of K for kilobytes, M for megabytes,
-G for gigabytes or T for terabytes is optional.
+G for gigabytes, T for terabytes, P for petabytes
+or E for exabytes is optional.
 .br
 Default unit is megabytes.
 .TP
@@ -138,6 +139,10 @@
 Controls zeroing of the first KB of data in the new logical volume.
 .br
 Default is yes.
+.br
+Volume will not be zeroed if read only flag is set.
+.br
+Snapshot volumes are zeroed always.
 
 .br
 Warning: trying to mount an unzeroed logical volume can cause the system to

Modified: lvm2/upstream/current/man/lvextend.8
==============================================================================
--- lvm2/upstream/current/man/lvextend.8	(original)
+++ lvm2/upstream/current/man/lvextend.8	Sat Apr  7 15:30:42 2007
@@ -30,10 +30,12 @@
 size of the Logical Volume with the suffix %LV or as a percentage of the remaining
 free space in the Volume Group with the suffix %FREE.
 .TP
-.I \-L, \-\-size [+]LogicalVolumeSize[kKmMgGtT]
-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
+.I \-L, \-\-size [+]LogicalVolumeSize[kKmMgGtTpPeE]
+Extend or set the logical volume size in units of megabytes.
+A size suffix of M for megabytes,
+G for gigabytes, T for terabytes, P for petabytes 
+or E for exabytes 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

Modified: lvm2/upstream/current/man/lvm.conf.5
==============================================================================
--- lvm2/upstream/current/man/lvm.conf.5	(original)
+++ lvm2/upstream/current/man/lvm.conf.5	Sat Apr  7 15:30:42 2007
@@ -95,8 +95,8 @@
 As an example, to ignore /dev/cdrom you could use:
 \fBdevices { filter=["r|cdrom|"] }\fP 
 .IP
-\fBcache\fP \(em Persistent filter cache file.
-Defaults to "/etc/lvm/.cache".
+\fBcache_dir\fP \(em Persistent filter cache file directory.
+Defaults to "/etc/lvm/cache".
 .IP
 \fBwrite_cache_state\fP \(em Set to 0 to disable the writing out of the 
 persistent filter cache file when \fBlvm\fP exits.
@@ -364,9 +364,9 @@
 the tools as normal, or else vgcfgbackup, edit backup, vgcfgrestore.
 .SH FILES
 .I /etc/lvm/lvm.conf
-.I /etc/lvm/.cache
 .I /etc/lvm/archive
 .I /etc/lvm/backup
+.I /etc/lvm/cache/.cache
 .I /var/lock/lvm
 .SH SEE ALSO
 .BR lvm (8),

Added: lvm2/upstream/current/man/lvmdump.8
==============================================================================
--- (empty file)
+++ lvm2/upstream/current/man/lvmdump.8	Sat Apr  7 15:30:42 2007
@@ -0,0 +1,50 @@
+.TH LVMDUMP "8" "" "Red Hat, Inc."
+.SH NAME
+lvmdump - create lvm2 information dumps for diagnostic purposes
+.SH SYNOPSIS
+\fBlvmdump\fP [options] [-d directory]
+.SH DESCRIPTION
+\fBlvmdump\fP is a tool to dump various information concerning LVM2. By default, it creates a tarball suitable for submission along with a problem report.
+.PP
+The content of the tarball is as follows:
+.br
+- dmsetup info
+.br
+- table of currently running processes
+.br
+- recent entries from /var/log/messages (containing system messages)
+.br
+- complete lvm configuration and cache
+.br
+- list of device nodes present under /dev
+.br
+- if enabled with -m, metadata dump will be also included
+.br
+- if enabled with -a, debug output of vgscan, pvscan and list of all available volume groups, physical volumes and logical volumes will be included
+.br
+- if enabled with -c, cluster status info
+.SH OPTIONS
+.TP
+\fB\-h\fR \(em print help message
+.TP
+\fB\-a\fR \(em advanced collection 
+\fBWARNING\fR: if lvm is already hung, then this script may hang as well if \fB\-a\fR is used
+.TP
+\fB\-m\fR \(em gather LVM metadata from the PVs
+This option generates a 1:1 dump of the metadata area from all PVs visible to the system, which can cause the dump to increase in size considerably. However, the metadata dump may represent a valuable diagnostic resource.
+.TP
+\fB\-d\fR directory \(em dump into a directory instead of tarball
+By default, lvmdump will produce a single compressed tarball containing all the information. Using this option, it can be instructed to only produce the raw dump tree, rooted in \fBdirectory\fP.
+.TP
+\fB\-c\fR \(em if clvmd is running, gather cluster data as well
+.SH ENVIRONMENT VARIABLES
+.TP
+\fBLVM_BINARY\fP 
+The LVM2 binary to use.
+Defaults to "lvm".
+Sometimes you might need to set this to "/sbin/lvm.static", for example.
+.TP
+\fBDMSETUP_BINARY\fP 
+The dmsetup binary to use.
+Defaults to "dmsetup".
+.PP

Modified: lvm2/upstream/current/man/lvreduce.8
==============================================================================
--- lvm2/upstream/current/man/lvreduce.8	(original)
+++ lvm2/upstream/current/man/lvreduce.8	Sat Apr  7 15:30:42 2007
@@ -46,10 +46,11 @@
 size of the Logical Volume with the suffix %LV or as a percentage of the remaining
 free space in the Volume Group with the suffix %FREE.
 .TP
-.I \-L, \-\-size [\-]LogicalVolumeSize[kKmMgGtT]
+.I \-L, \-\-size [\-]LogicalVolumeSize[kKmMgGtTpPeE]
 Reduce or set the logical volume size in units of megabyte by default.
-A size suffix of k for kilobyte, m for megabyte, g for gigabyte or
-t for terabyte is optional.
+A size suffix of k for kilobyte, m for megabyte, 
+g for gigabytes, t for terabytes, p for petabytes 
+or e for exabytes is optional.
 With the - sign the value will be subtracted from
 the logical volume's actual size and without it it will be taken as
 an absolute size.

Modified: lvm2/upstream/current/man/lvremove.8
==============================================================================
--- lvm2/upstream/current/man/lvremove.8	(original)
+++ lvm2/upstream/current/man/lvremove.8	Sat Apr  7 15:30:42 2007
@@ -12,6 +12,10 @@
 Confirmation will be requested before deactivating any active logical
 volume prior to removal.  Logical volumes cannot be deactivated
 or removed while they are open (e.g. if they contain a mounted filesystem).
+.sp
+If the logical volume is clustered then it must be deactivated on all
+nodes in the cluster before it can be removed. A single lvchange command
+issued from one node can do this.
 .SH OPTIONS
 See \fBlvm\fP(8) for common options.
 .TP
@@ -28,7 +32,8 @@
 \	\fBlvremove vg00\fP
 .SH SEE ALSO
 .BR lvcreate (8), 
-.BR lvdisplay (8), 
+.BR lvdisplay (8),
+.BR lvchange (8),  
 .BR lvm (8), 
 .BR lvs (8),
 .BR lvscan (8),

Modified: lvm2/upstream/current/man/lvresize.8
==============================================================================
--- lvm2/upstream/current/man/lvresize.8	(original)
+++ lvm2/upstream/current/man/lvresize.8	Sat Apr  7 15:30:42 2007
@@ -34,10 +34,12 @@
 size of the Logical Volume with the suffix %LV or as a percentage of the remaining 
 free space in the Volume Group with the suffix %FREE.
 .TP
-.I \-L, \-\-size [+/-]LogicalVolumeSize[kKmMgGtT]
+.I \-L, \-\-size [+/-]LogicalVolumeSize[kKmMgGtTpPeE]
 Change or set the logical volume size in units of megabytes.
-A size suffix of M for megabytes, G for gigabytes or T for terabytes is
-optional.  With the + or - sign the value is added to or subtracted from
+A size suffix of M for megabytes,
+G for gigabytes, T for terabytes, P for petabytes 
+or E for exabytes is optional.
+With the + or - sign the value is added to or subtracted from
 the actual size of the logical volume and without it, the value is taken as an
 absolute one.
 .TP

Modified: lvm2/upstream/current/man/lvs.8
==============================================================================
--- lvm2/upstream/current/man/lvs.8	(original)
+++ lvm2/upstream/current/man/lvs.8	Sat Apr  7 15:30:42 2007
@@ -35,11 +35,13 @@
 lv_size, seg_count, origin, snap_percent,
 copy_percent, move_pv, lv_tags,
 segtype, stripes,
-stripesize, chunksize, seg_start, seg_size, seg_tags, devices.
+stripesize, chunksize, seg_start, seg_size, seg_tags, devices,
+regionsize, mirror_log, modules.
 .IP
 With \-\-segments, any "seg_" prefixes are optional; otherwise any "lv_"
 prefixes are optional.  Columns mentioned in \fBvgs (8)\fP 
 can also be chosen.
+Use \fb-o help\fP to view the full list of fields available.
 .IP
 The lv_attr bits are: 
 .RS

Modified: lvm2/upstream/current/man/pvmove.8
==============================================================================
--- lvm2/upstream/current/man/pvmove.8	(original)
+++ lvm2/upstream/current/man/pvmove.8	Sat Apr  7 15:30:42 2007
@@ -5,7 +5,7 @@
 .B pvmove
 [\-\-abort]
 [\-\-alloc AllocationPolicy]
-[\-\-background]
+[\-b/\-\-background]
 [\-d/\-\-debug] [\-h/\-\-help] [\-i/\-\-interval Seconds] [\-v/\-\-verbose]
 [\-n/\-\-name LogicalVolume] 
 [SourcePhysicalVolume[:PE[-PE]...] [DestinationPhysicalVolume[:PE[-PE]...]...]]
@@ -73,7 +73,7 @@
 .I \-\-abort
 Abort any moves in progress.
 .TP
-.I \-\-background
+.I \-b, \-\-background
 Run the daemon in the background.
 .TP
 .I \-i, \-\-interval Seconds

Modified: lvm2/upstream/current/man/pvs.8
==============================================================================
--- lvm2/upstream/current/man/pvs.8	(original)
+++ lvm2/upstream/current/man/pvs.8	Sat Apr  7 15:30:42 2007
@@ -31,9 +31,16 @@
 Comma-separated ordered list of columns.  Precede the list with '+' to append
 to the default selection of columns.  Column names are: pv_fmt, pv_uuid,
 pv_size, dev_size, pv_free, pv_used, pv_name, pv_attr, pv_pe_count, 
-pv_pe_alloc_count, pv_tags.
-The "pv_" prefix is optional.  Columns mentioned in \fBvgs (8)\fP can also
+pv_pe_alloc_count, pv_tags, pvseg_start, pvseg_size, pe_start.
+With --segments, any "pvseg_" prefixes are optional; otherwise any
+"pv_" prefixes are optional.  Columns mentioned in \fBvgs (8)\fP can also
 be chosen. The pv_attr bits are: (a)llocatable and e(x)ported.
+Use \fb-o help\fP to view the full list of fields available.
+.TP
+.I \-\-segments
+Produces one line of output for each contiguous allocation of space on each
+Physical Volume, showing the start (pvseg_start) and length (pvseg_size) in
+units of physical extents.
 .TP
 .I \-O, \-\-sort
 Comma-separated ordered list of columns to sort by.  Replaces the default

Modified: lvm2/upstream/current/man/vgchange.8
==============================================================================
--- lvm2/upstream/current/man/vgchange.8	(original)
+++ lvm2/upstream/current/man/vgchange.8	Sat Apr  7 15:30:42 2007
@@ -10,6 +10,7 @@
 .RB [ \-A | \-\-autobackup " {" y | n }]
 .RB [ \-a | \-\-available " [e|l] {" y | n }]
 .RB [ \-\-monitor " {" y | n }]
+.RB [ \-c | \-\-clustered " {" y | n }]
 .RB [ \-d | \-\-debug]
 .RB [ \-\-deltag
 .IR Tag ]
@@ -44,12 +45,12 @@
 .SH OPTIONS
 See \fBlvm\fP for common options.
 .TP
-.BR \-A ", " \-\-autobackup { y | n }
+.BR \-A ", " \-\-autobackup " " { y | n }
 Controls automatic backup of metadata after the change.  See
 .B vgcfgbackup (8).
 Default is yes.
 .TP
-.BR \-a ", " \-\-available [e|l] { y | n }
+.BR \-a ", " \-\-available " " [e|l] { y | n }
 Controls the availability of the logical volumes in the volume 
 group for input/output.
 In other words, makes the logical volumes known/unknown to the kernel.
@@ -60,6 +61,14 @@
 Logical volumes with single-host snapshots are always activated
 exclusively because they can only be used on one node at once.
 .TP
+.BR \-c ", " \-\-clustered " " { y | n }
+If clustered locking is enabled, this indicates whether this
+Volume Group is shared with other nodes in the cluster or whether
+it contains only local disks that are not visible on the other nodes.
+If the cluster infrastructure is unavailable on a particular node at a
+particular time, you may still be able to use Volume Groups that
+are not marked as clustered.
+.TP
 .BR \-\-monitor " " { y | n }
 Controls whether or not a mirrored logical volume is monitored by
 dmeventd, if it is installed.
@@ -108,7 +117,7 @@
  
 The 2.4 kernel has a limitation of 2TB per block device.
 .TP
-.BR \-x ", " \-\-resizeable { y | n }
+.BR \-x ", " \-\-resizeable " " { y | n }
 Enables or disables the extension/reduction of this volume group
 with/by physical volumes.
 .SH EXAMPLES

Modified: lvm2/upstream/current/man/vgcreate.8
==============================================================================
--- lvm2/upstream/current/man/vgcreate.8	(original)
+++ lvm2/upstream/current/man/vgcreate.8	Sat Apr  7 15:30:42 2007
@@ -8,6 +8,7 @@
 .RB [ \-\-alloc 
 .IR AllocationPolicy ]
 .RB [ \-A | \-\-autobackup " {" y | n }]
+.RB [ \-c | \-\-clustered " {" y | n }]
 .RB [ \-d | \-\-debug ]
 .RB [ \-h | \-\-help ]
 .RB [ \-l | \-\-maxlogicalvolumes
@@ -33,6 +34,14 @@
 .SH OPTIONS
 See \fBlvm\fP for common options.
 .TP
+.BR \-c ", " \-\-clustered " " { y | n }
+If clustered locking is enabled, this indicates whether this
+Volume Group is shared with other nodes in the cluster or whether
+it contains only local disks that are not visible on the other nodes.
+If the cluster infrastructure is unavailable on a particular node at a
+particular time, you may still be able to use Volume Groups that
+are not marked as clustered.
+.TP
 .BR \-l ", " \-\-maxlogicalvolumes " " \fIMaxLogicalVolumes\fR
 Sets the maximum number of logical volumes allowed in this
 volume group. 

Modified: lvm2/upstream/current/man/vgs.8
==============================================================================
--- lvm2/upstream/current/man/vgs.8	(original)
+++ lvm2/upstream/current/man/vgs.8	Sat Apr  7 15:30:42 2007
@@ -38,6 +38,7 @@
 or \fBlvs (8)\fP can also be chosen, but columns cannot be taken from both
 at the same time.  The vg_attr bits are: (w)riteable, (r)eadonly, 
 resi(z)eable, e(x)ported, (p)artial and (c)lustered.
+Use \fb-o help\fP to view the full list of fields available.
 .TP
 .I \-O, \-\-sort
 Comma-separated ordered list of columns to sort by.  Replaces the default

Added: lvm2/upstream/current/scripts/Makefile.in
==============================================================================
--- (empty file)
+++ lvm2/upstream/current/scripts/Makefile.in	Sat Apr  7 15:30:42 2007
@@ -0,0 +1,23 @@
+#
+# Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+#
+# This file is part of the LVM2.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+
+include $(top_srcdir)/make.tmpl
+
+install:
+	$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) lvm_dump.sh \
+		$(sbindir)/lvmdump
+

Modified: lvm2/upstream/current/scripts/clvmd_init_rhel4
==============================================================================
--- lvm2/upstream/current/scripts/clvmd_init_rhel4	(original)
+++ lvm2/upstream/current/scripts/clvmd_init_rhel4	Sat Apr  7 15:30:42 2007
@@ -1,6 +1,6 @@
 #!/bin/bash
 #
-# chkconfig: 345 24 76
+# chkconfig: - 24 76
 # description: Starts and stops clvmd
 #
 #	       
@@ -15,6 +15,7 @@
 VGSCAN="/usr/sbin/vgscan"
 VGDISPLAY="/usr/sbin/vgdisplay"
 VGS="/usr/sbin/vgs"
+CLVMDOPTS="-T20"
 
 [ -f /etc/sysconfig/cluster ] && . /etc/sysconfig/cluster
 
@@ -27,7 +28,7 @@
 		if ! pidof clvmd > /dev/null 
 		then 
 			echo -n "Starting clvmd: "
-			daemon clvmd
+			daemon clvmd $CLVMDOPTS
 			rtrn=$?
 			echo
 			if [ $rtrn -ne 0 ]
@@ -42,16 +43,10 @@
 		then
 			for vg in $LVM_VGS
 			do
-				if ! action "Activating VG $vg:" $VGCHANGE -ayl $vg
-				then
-					rtrn=$?
-                                fi
+				action "Activating VG $vg:" $VGCHANGE -ayl $vg || rtrn=$?
 			done
 		else
-			if ! action "Activating VGs:" $VGCHANGE -ayl
-			then
-				rtrn=$?
-                        fi
+			action "Activating VGs:" $VGCHANGE -ayl || rtrn=$?
 		fi
 	done
 
@@ -66,19 +61,13 @@
 		then
 			for vg in $LVM_VGS
 			do
-				if ! action "Deactivating VG $vg:" $VGCHANGE -anl $vg
-				then
-					rtrn=$?
-				fi
+				action "Deactivating VG $vg:" $VGCHANGE -anl $vg || rtrn=$?
 			done
 		else
 			# Hack to only deactivate clustered volumes
-		        clustervgs=`$VGDISPLAY \`$VGS --noheadings -o name\` | awk 'BEGIN {RS="VG Name"} {if (/Clustered/) print $1;}'`
+			clustervgs=`$VGDISPLAY 2> /dev/null | awk 'BEGIN {RS="VG Name"} {if (/Clustered/) print $1;}'`
 			for vg in $clustervgs; do
-				if ! action "Deactivating VG $vg:" $VGCHANGE -anl $vg
-				then
-					rtrn=$?
-				fi
+				action "Deactivating VG $vg:" $VGCHANGE -anl $vg || rtrn=$?
 			done
 		fi
 

Added: lvm2/upstream/current/scripts/lvm2_monitoring_init_rhel4
==============================================================================
--- (empty file)
+++ lvm2/upstream/current/scripts/lvm2_monitoring_init_rhel4	Sat Apr  7 15:30:42 2007
@@ -0,0 +1,100 @@
+#!/bin/bash
+#
+# Copyright (C) 2007 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# This file is part of LVM2.
+# It is required for the proper handling of failures of LVM2 mirror
+# devices that were created using the -m option of lvcreate.
+#
+#
+# chkconfig: 12345 02 99
+# description: Starts and stops dmeventd monitoring for lvm2
+#	       
+### BEGIN INIT INFO
+# Provides: 
+### END INIT INFO
+
+. /etc/init.d/functions
+
+VGCHANGE="/usr/sbin/vgchange"
+WARN=1
+
+start()
+{
+	ret=0
+	# TODO do we want to separate out already active groups only?
+	VGS=`vgs --noheadings -o name`
+	for vg in $VGS
+	do
+	    action "Starting monitoring for VG $vg:" $VGCHANGE --monitor y $vg || ret=$?
+	done
+
+	return $ret
+}
+
+
+stop()
+{
+	ret=0
+	# TODO do we want to separate out already active groups only?
+	if test "$WARN" = "1"; then
+	   echo "Not stopping monitoring, this is a dangerous operation. Please use force-stop to override."
+	   return 1
+	fi
+	VGS=`vgs --noheadings -o name`
+	for vg in $VGS
+	do
+	    action "Stopping monitoring for VG $vg:" $VGCHANGE --monitor n $vg || ret=$?
+	done
+	return $ret
+}
+
+result=1
+
+# See how we were called.
+case "$1" in
+  start)
+	start
+	result=$?
+	;;
+
+  force-stop)
+	WARN=0
+	stop
+	result=$?
+	;;
+
+  stop)
+	test "$runlevel" = "0" && WARN=0
+	test "$runlevel" = "6" && WARN=0
+	stop
+	result=$?
+	;;
+
+  restart)
+	WARN=0
+	if stop
+	then
+		start
+	fi 
+	result=$?
+	;;
+
+  status)
+	# TODO anyone with an idea how to dump monitored volumes?
+	;;
+
+  *)
+	echo $"Usage: $0 {start|stop|restart|status|force-stop}"
+	;;
+esac
+
+exit $result

Modified: lvm2/upstream/current/scripts/lvm2create_initrd/lvm2create_initrd
==============================================================================
--- lvm2/upstream/current/scripts/lvm2create_initrd/lvm2create_initrd	(original)
+++ lvm2/upstream/current/scripts/lvm2create_initrd/lvm2create_initrd	Sat Apr  7 15:30:42 2007
@@ -29,6 +29,8 @@
 #               PATH entries to /sbin/init shell script so chroot works without /usr mounted. Remove
 #               mkdir /initrd so we don't cause problems if root filesystem is corrupted. -- Jeff Layton
 # 15/05/2004	initial support for modules, create lvm.conf from lvm dumpconfig, other cleanups -- Jeff Layton
+# 14/11/2006	Update handling of ldd output to handle hardcoded library links and virtual dll linux-gate.
+#		Add support for Gentoo-style MAKEDEV. Remove hardcoded BINUTILS paths -- Douglas Mayle
 #
 # Copyright Miguel Cabeca, Jeffrey Layton, 2004
 #
@@ -46,13 +48,13 @@
 #    along with this program; if not, write to the Free Software
 #    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 #
-# $Id: lvm2create_initrd,v 1.1 2004/06/07 16:20:05 agk Exp $
+# $Id: lvm2create_initrd,v 1.2 2006/11/21 22:41:56 agk Exp $
 
 TMPMNT=/tmp/mnt.$$
 DEVRAM=/tmp/initrd.$$
 
 # set defaults
-BINFILES=${BINFILES:-"/lib/lvm-200/lvm /bin/bash /bin/busybox /sbin/pivot_root"}
+BINFILES=${BINFILES:-"`which lvm` `which bash` `which busybox` `which pivot_root`"}
 BASICDEVICES=${BASICDEVICES:-"std consoleonly fd"}
 BLOCKDEVICES=${BLOCKDEVICES:-"md hda hdb hdc hdd sda sdb sdc sdd"}
 MAKEDEV=${MAKEDEV:-"debian"}
@@ -269,7 +271,27 @@
 # Figure out which shared libraries we actually need in our initrd
 echo "$cmd -- finding required shared libraries"
 verbose "BINFILES: `echo $BINFILES`"
-LIBFILES=`ldd $BINFILES 2>/dev/null | awk '{if (/=>/) { print $3 }}' | sort -u`
+
+# We need to strip certain lines from ldd output.  This is the full output of an example ldd:
+#lvmhost~ # ldd /sbin/lvm /bin/bash
+#/sbin/lvm:
+#        not a dynamic executable
+#/bin/bash:
+#        linux-gate.so.1 =>  (0xbfffe000)
+#        libncurses.so.5 => /lib/libncurses.so.5 (0xb7ee3000)
+#        libdl.so.2 => /lib/libdl.so.2 (0xb7edf000)
+#        libc.so.6 => /lib/libc.so.6 (0xb7dc1000)
+#        /lib/ld-linux.so.2 (0xb7f28000)
+#
+# 1) Lines with a ":" contain the name of the original binary we're examining, and so are unnecessary.
+#    We need to strip them because they contain "/", and can be confused with links with a hardcoded path.
+# 2) The linux-gate library is a virtual dll that does not exist on disk, but is instead loaded automatically
+#    into the process space, and can't be copied to the ramdisk
+#
+# After these lines have been stripped, we're interested in the lines remaining if they
+# 1) Contain "=>" because they are pathless links, and the value following the token is the path on the disk
+# 2) Contain "/" because it's a link with a hardcoded path, and so we're interested in the link itself.
+LIBFILES=`ldd $BINFILES 2>/dev/null |grep -v -E \(linux-gate\|:\) | awk '{if (/=>/) { print $3 } else if (/\//) { print $1 }}' | sort -u`
 if [ $? -ne 0 ]; then
    echo "$cmd -- ERROR figuring out needed shared libraries"
    exit 1
@@ -356,6 +378,10 @@
     (cd $TMPMNT/dev; /dev/MAKEDEV $OPT_Q -d $TMPMNT/dev -m 2)
     RETCODE=$?
     ;;
+gentoo)
+    (cd $TMPMNT/dev; /usr/sbin/MAKEDEV $OPT_Q $BASICDEVICES $BLOCKDEVICES)
+    RETCODE=$?
+    ;;
 *)
     echo "$cmd -- ERROR: $MAKEDEV is not a known MAKEDEV style."
     RETCODE=1

Modified: lvm2/upstream/current/scripts/lvm_dump.sh
==============================================================================
--- lvm2/upstream/current/scripts/lvm_dump.sh	(original)
+++ lvm2/upstream/current/scripts/lvm_dump.sh	Sat Apr  7 15:30:42 2007
@@ -1,8 +1,41 @@
 #!/bin/bash
-#
+# we use some bash-isms (getopts?)
+
 # lvm_dump: This script is used to collect pertinent information for
 #           the debugging of lvm issues.
-#
+
+# following external commands are used throughout the script
+# which, echo and test are internal in bash at least
+MKDIR=mkdir # need -p
+TAR=tar # need czf
+RM=rm # need -rf
+CP=cp
+TAIL=tail # we need -n
+LS=ls # need -la
+PS=ps # need alx
+SED=sed
+DD=dd
+CUT=cut
+DATE=date
+BASENAME=basename
+
+# user may override lvm and dmsetup location by setting LVM_BINARY
+# and DMSETUP_BINARY respectively
+LVM=${LVM_BINARY-lvm}
+DMSETUP=${DMSETUP_BINARY-dmsetup}
+
+die() {
+    code=$1; shift
+    echo "$@" 1>&2
+    exit $code
+}
+
+# which should error out if the binary is not executable, although i
+# am not sure we can rely on this
+which $LVM >& /dev/null || die 2 "Fatal: could not find lvm binary '$LVM'"
+test -x `which $LVM` || die 2 "Fatal: lvm binary '$LVM' not executable"
+which $DMSETUP >& /dev/null || die 2 "Fatal: could not find dmsetup binary '$DMSETUP'"
+test -x `which $DMSETUP` || die 2 "Fatal: dmsetup binary '$DMSETUP' not executable"
 
 function usage {
 	echo "$0 [options]"
@@ -10,7 +43,7 @@
 	echo "    -a advanced collection - warning: if lvm is already hung,"
 	echo "       then this script may hang as well if -a is used"
 	echo "    -m gather LVM metadata from the PVs"
-	echo "    -d dump directory to place data in (default=/tmp/lvm_dump.\$\$)"
+	echo "    -d <directory> dump into a directory instead of tarball"
 	echo "    -c if running clvmd, gather cluster data as well"
 	echo ""
 	
@@ -22,9 +55,10 @@
 metadata=0
 while getopts :acd:hm opt; do
 	case $opt in 
+		s)      sysreport=1 ;;
 		a)	advanced=1 ;;
 		c)	clustered=1 ;;
-		d)	lvm_dir=$OPTARG ;;
+		d)	userdir=$OPTARG ;;
 		h)	usage ;;
 		m)	metadata=1 ;;
 		:)	echo "$0: $OPTARG requires a value:"; usage ;;
@@ -33,86 +67,119 @@
 	esac
 done
 
-dir=`mktemp -d -p /tmp lvm_dump.XXXXXX` || exit 2
-lvm_dir="$dir/lvm_dump"
+NOW=`$DATE -u +%G%m%d%k%M%S | /usr/bin/tr -d ' '`
+if test -n "$userdir"; then
+	dir="$userdir"
+else
+	dirbase="lvmdump-$HOSTNAME-$NOW"
+	dir="$HOME/$dirbase"
+fi
+
+test -e $dir && die 3 "Fatal: $dir already exists"
+$MKDIR -p $dir || die 4 "Fatal: could not create $dir"
+
+log="$dir/lvmdump.log"
+
+myecho() {
+	echo "$@"
+	echo "$@" >> $log
+}
+
+log() {
+	echo "$@" >> $log
+	eval "$@"
+}
 
 echo " "
-echo "Creating dump directory: $lvm_dir"
+myecho "Creating dump directory: $dir"
 echo " "
 
-mkdir -p $lvm_dir || exit 3
-
 if (( $advanced )); then
-	echo "Gathering LVM volume info..."
+	myecho "Gathering LVM volume info..."
 
-	echo "  vgscan..."
-	vgscan -vvvv > $lvm_dir/vgscan 2>&1
+	myecho "  vgscan..."
+	log "$LVM vgscan -vvvv > $dir/vgscan 2>&1"
 
-	echo "  pvscan..."
-	pvscan -v >> $lvm_dir/pvscan 2>/dev/null
+	myecho "  pvscan..."
+	log "$LVM pvscan -v >> $dir/pvscan 2>> $log"
 
-	echo "  lvs..."
-	lvs -a -o +devices >> $lvm_dir/lvs 2>/dev/null
+	myecho "  lvs..."
+	log "$LVM lvs -a -o +devices >> $dir/lvs 2>> $log"
 
-	echo "  pvs..."
-	pvs -a -v > $lvm_dir/pvs 2>/dev/null
+	myecho "  pvs..."
+	log "$LVM pvs -a -v > $dir/pvs 2>> $log"
 
 	echo "  vgs..."
-	vgs -v > $lvm_dir/vgs 2>/dev/null
+	log "$LVM vgs -v > $dir/vgs 2>> $log"
 fi
 
 if (( $clustered )); then
-	echo "Gathering cluster info..."
-	echo "STATUS: " > $lvm_dir/cluster_info
-	echo "----------------------------------" >> $lvm_dir/cluster_info
-	cman_tool status >> $lvm_dir/cluster_info
-	echo " " >> $lvm_dir/lvm_info
-
-	echo "SERVICES: " >> $lvm_dir/cluster_info
-	echo "----------------------------------" >> $lvm_dir/cluster_info
-	cman_tool services >> $lvm_dir/cluster_info
-	echo " " >> $lvm_dir/lvm_info
-fi
-
-echo "Gathering LVM & device-mapper version info..."
-echo "LVM VERSION:" > $lvm_dir/versions
-lvs --version >> $lvm_dir/versions
-echo "DEVICE MAPPER VERSION:" >> $lvm_dir/versions
-dmsetup --version >> $lvm_dir/versions
-
-echo "Gathering dmsetup info..."
-dmsetup info -c > $lvm_dir/dmsetup_info
-dmsetup table > $lvm_dir/dmsetup_table
-dmsetup status > $lvm_dir/dmsetup_status
-
-echo "Gathering process info..."
-ps alx > $lvm_dir/ps_info
+	myecho "Gathering cluster info..."
+	echo "STATUS: " > $dir/cluster_info
+	echo "----------------------------------" >> $dir/cluster_info
+	log "cman_tool status >> $dir/cluster_info 2>> $log"
+	echo " " >> $dir/lvm_info
+
+	echo "SERVICES: " >> $dir/cluster_info
+	echo "----------------------------------" >> $dir/cluster_info
+	log "cman_tool services >> $dir/cluster_info 2>> $log"
+	echo " " >> $dir/lvm_info
+fi
 
-echo "Gathering console messages..."
-tail -n 75 /var/log/messages > $lvm_dir/messages
+myecho "Gathering LVM & device-mapper version info..."
+echo "LVM VERSION:" > $dir/versions
+$LVM lvs --version >> $dir/versions 2>> $log
+echo "DEVICE MAPPER VERSION:" >> $dir/versions
+$DMSETUP --version >> $dir/versions 2>> $log
+
+myecho "Gathering dmsetup info..."
+log "$DMSETUP info -c > $dir/dmsetup_info 2>> $log"
+log "$DMSETUP table > $dir/dmsetup_table 2>> $log"
+log "$DMSETUP status > $dir/dmsetup_status 2>> $log"
+
+myecho "Gathering process info..."
+log "$PS alx > $dir/ps_info 2>> $log"
 
-echo "Gathering /etc/lvm info..."
-cp -a /etc/lvm $lvm_dir/lvm
+myecho "Gathering console messages..."
+log "$TAIL -n 75 /var/log/messages > $dir/messages 2>> $log"
 
-echo "Gathering /dev listing..."
-ls -la /dev > $lvm_dir/dev_listing
+myecho "Gathering /etc/lvm info..."
+log "$CP -a /etc/lvm $dir/lvm 2>> $log"
+
+myecho "Gathering /dev listing..."
+log "$LS -la /dev > $dir/dev_listing 2>> $log"
 
 if (( $metadata )); then
-	echo "Gathering LVM metadata from Physical Volumes..."
+	myecho "Gathering LVM metadata from Physical Volumes..."
 
-	mkdir -p $lvm_dir/metadata
+	log "$MKDIR -p $dir/metadata"
 
-	for pv in `pvs --noheadings -o name`
+	pvs="$($LVM pvs --separator , --noheadings --units s --nosuffix -o \
+	    name,pe_start 2>> $log | $SED -e 's/^ *//')"
+	for line in "$pvs"
 	do
-		echo "  $pv"
-		name=`basename $pv`
-		dd if=$pv of=$lvm_dir/metadata/$name bs=512 count=`pvs --noheadings --nosuffix --units s -o pe_start $pv | tr -d \ `
-	done 2>/dev/null
+		test -z "$line" && continue
+		pv="$(echo $line | $CUT -d, -f1)"
+		pe_start="$(echo $line | $CUT -d, -f2)"
+		name="$($BASENAME $pv)"
+		myecho "  $pv"
+		log "$DD if=$pv of=$dir/metadata/$name bs=512 count=$pe_start 2>> $log"
+	done
+fi
+
+if test -z "$userdir"; then
+	lvm_dump="$dirbase.tgz"
+	myecho "Creating report tarball in $HOME/$lvm_dump..."
+	cd $HOME
+	$TAR czf $lvm_dump $dirbase 2>/dev/null
+	$RM -rf $dir
 fi
 
-lvm_dump=$lvm_dir.tgz
-echo "Creating tarball $lvm_dump..."
-tar czf $lvm_dump $lvm_dir 2>/dev/null
+if test "$UID" != "0" && test "$EUID" != "0"; then
+	myecho
+	myecho "WARNING! Running as non-privileged user, dump is likely incomplete!"
+	myecho
+fi
 
 exit 0
 

Modified: lvm2/upstream/current/tools/Makefile.in
==============================================================================
--- lvm2/upstream/current/tools/Makefile.in	(original)
+++ lvm2/upstream/current/tools/Makefile.in	Sat Apr  7 15:30:42 2007
@@ -82,7 +82,8 @@
 
 CLEAN_TARGETS = liblvm2cmd.so liblvm2cmd.a liblvm2cmd-static.a lvm lvm.o \
 		lvm2cmd.o lvm2cmd-static.o lvm2cmdlib.o lvm.static \
-		lvm.cflow lvm.xref lvm.tree lvm.rxref lvm.rtree
+		lvm.cflow lvm.xref lvm.tree lvm.rxref lvm.rtree \
+		lvmcmdlib.o lvm-static.o
 
 ifeq ("@CMDLIB@", "yes")
 	TARGETS += liblvm2cmd.so
@@ -100,11 +101,12 @@
 include $(top_srcdir)/make.tmpl
 
 lvm: $(OBJECTS) lvm.o $(top_srcdir)/lib/liblvm.a
-	$(CC) -o $@ $(OBJECTS) lvm.o $(LDFLAGS) $(LVMLIBS) $(LIBS) -rdynamic
+	$(CC) -o $@ $(CFLAGS) $(OBJECTS) lvm.o \
+		$(LDFLAGS) $(LVMLIBS) $(LIBS) -rdynamic
 
 lvm.static: $(OBJECTS) lvm-static.o $(top_srcdir)/lib/liblvm.a
-	$(CC) -o $@ $(OBJECTS) lvm-static.o -static $(LDFLAGS) $(LVMLIBS) \
-		$(LIBS) -rdynamic
+	$(CC) -o $@ $(CFLAGS) $(OBJECTS) lvm-static.o -static \
+		$(LDFLAGS) $(LVMLIBS) $(LIBS) -rdynamic
 
 liblvm2cmd.a: $(top_srcdir)/lib/liblvm.a $(OBJECTS) lvmcmdlib.o lvm2cmd.o
 	cat $(top_srcdir)/lib/liblvm.a > $@

Modified: lvm2/upstream/current/tools/args.h
==============================================================================
--- lvm2/upstream/current/tools/args.h	(original)
+++ lvm2/upstream/current/tools/args.h	Sat Apr  7 15:30:42 2007
@@ -46,6 +46,7 @@
 arg(separator_ARG, '\0', "separator", string_arg)
 arg(mirrorsonly_ARG, '\0', "mirrorsonly", NULL)
 arg(nosync_ARG, '\0', "nosync", NULL)
+arg(resync_ARG, '\0', "resync", NULL)
 arg(corelog_ARG, '\0', "corelog", NULL)
 arg(monitor_ARG, '\0', "monitor", yes_no_arg)
 arg(config_ARG, '\0', "config", string_arg)

Modified: lvm2/upstream/current/tools/commands.h
==============================================================================
--- lvm2/upstream/current/tools/commands.h	(original)
+++ lvm2/upstream/current/tools/commands.h	Sat Apr  7 15:30:42 2007
@@ -19,7 +19,7 @@
    "e2fsadm "
    "[-d|--debug] " "[-h|--help] " "[-n|--nofsck]" "\n"
    "\t{[-l|--extents] [+|-]LogicalExtentsNumber |" "\n"
-   "\t [-L|--size] [+|-]LogicalVolumeSize[kKmMgGtT]}" "\n"
+   "\t [-L|--size] [+|-]LogicalVolumeSize[kKmMgGtTpPeE]}" "\n"
    "\t[-t|--test] "  "\n"
    "\t[-v|--verbose] "  "\n"
    "\t[--version] " "\n"
@@ -30,7 +30,10 @@
 
 xx(dumpconfig,
    "Dump active configuration",
-   "dumpconfig <filename>\n")
+   "dumpconfig "
+   "\t[-f|--file filename] " "\n"
+   "[ConfigurationVariable...]\n",
+   file_ARG)
 
 xx(formats,
    "List available metadata formats",
@@ -69,15 +72,17 @@
    "\t[-p|--permission r|rw]\n"
    "\t[-r|--readahead ReadAheadSectors]\n"
    "\t[--refresh]\n"
+   "\t[--resync]\n"
    "\t[-t|--test]\n"
    "\t[-v|--verbose]\n"
+   "\t[-y|--yes]\n"
    "\t[--version]" "\n"
    "\tLogicalVolume[Path] [LogicalVolume[Path]...]\n",
 
    alloc_ARG, autobackup_ARG, available_ARG, contiguous_ARG, force_ARG,
    ignorelockingfailure_ARG, major_ARG, minor_ARG, monitor_ARG,
-   partial_ARG, permission_ARG, persistent_ARG, readahead_ARG,
-   refresh_ARG, addtag_ARG, deltag_ARG, test_ARG)
+   partial_ARG, permission_ARG, persistent_ARG, readahead_ARG, resync_ARG,
+   refresh_ARG, addtag_ARG, deltag_ARG, test_ARG, yes_ARG)
 
 xx(lvconvert,
    "Change logical volume layout",
@@ -115,7 +120,7 @@
    "\t[-h|-?|--help]\n"
    "\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n"
    "\t{-l|--extents LogicalExtentsNumber |\n"
-   "\t -L|--size LogicalVolumeSize[kKmMgGtT]}\n"
+   "\t -L|--size LogicalVolumeSize[kKmMgGtTpPeE]}\n"
    "\t[-M|--persistent {y|n}] [--major major] [--minor minor]\n"
    "\t[-m|--mirrors Mirrors [--nosync] [--corelog]]\n"
    "\t[-n|--name LogicalVolumeName]\n"
@@ -139,7 +144,7 @@
    "\t[-h|-?|--help]\n"
    "\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n"
    "\t{-l|--extents LogicalExtentsNumber[%{VG|LV|FREE}] |\n"
-   "\t -L|--size LogicalVolumeSize[kKmMgGtT]}\n"
+   "\t -L|--size LogicalVolumeSize[kKmMgGtTpPeE]}\n"
    "\t[-M|--persistent {y|n}] [--major major] [--minor minor]\n"
    "\t[-n|--name LogicalVolumeName]\n"
    "\t[-p|--permission {r|rw}]\n"
@@ -204,7 +209,7 @@
    "\t[-h|--help]\n"
    "\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n"
    "\t{-l|--extents [+]LogicalExtentsNumber[%{VG|FREE}] |\n"
-   "\t -L|--size [+]LogicalVolumeSize[kKmMgGtT]}\n"
+   "\t -L|--size [+]LogicalVolumeSize[kKmMgGtTpPeE]}\n"
    "\t[-m|--mirrors Mirrors]\n"
    "\t[-n|--nofsck]\n"
    "\t[-r|--resizefs]\n"
@@ -269,11 +274,12 @@
    "\t[-f|--force]\n"
    "\t[-h|--help]\n"
    "\t{-l|--extents [-]LogicalExtentsNumber[%{VG|LV|FREE}] |\n"
-   "\t -L|--size [-]LogicalVolumeSize[kKmMgGtT]}\n"
+   "\t -L|--size [-]LogicalVolumeSize[kKmMgGtTpPeE]}\n"
    "\t[-n|--nofsck]\n"
    "\t[-r|--resizefs]\n"
    "\t[-t|--test]\n"
    "\t[-v|--verbose]\n"
+   "\t[-y|--yes]\n"
    "\t[--version]" "\n"
    "\tLogicalVolume[Path]\n",
 
@@ -317,7 +323,7 @@
    "\t[-h|--help]\n"
    "\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n"
    "\t{-l|--extents [+|-]LogicalExtentsNumber[%{VG|LV|FREE}] |\n"
-   "\t -L|--size [+|-]LogicalVolumeSize[kKmMgGtT]}\n"
+   "\t -L|--size [+|-]LogicalVolumeSize[kKmMgGtTpPeE]}\n"
    "\t[-n|--nofsck]\n"
    "\t[-r|--resizefs]\n"
    "\t[-t|--test]\n"
@@ -393,7 +399,7 @@
    "pvresize " "\n"
    "\t[-d|--debug]" "\n"
    "\t[-h|-?|--help] " "\n"
-   "\t[--setphysicalvolumesize PhysicalVolumeSize[kKmMgGtT]" "\n"
+   "\t[--setphysicalvolumesize PhysicalVolumeSize[kKmMgGtTpPeE]" "\n"
    "\t[-t|--test] " "\n"
    "\t[-v|--verbose] " "\n"
    "\t[--version] " "\n"
@@ -411,8 +417,8 @@
    "\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[--metadatasize MetadataSize[kKmMgGtTpPeE]]" "\n"
+   "\t[--setphysicalvolumesize PhysicalVolumeSize[kKmMgGtTpPeE]" "\n"
    "\t[-t|--test] " "\n"
    "\t[-u|--uuid uuid] " "\n"
    "\t[-v|--verbose] " "\n"
@@ -609,7 +615,7 @@
    "\t -x|--resizeable {y|n} |" "\n"
    "\t -l|--logicalvolume MaxLogicalVolumes |" "\n"
    "\t -p|--maxphysicalvolumes MaxPhysicalVolumes |" "\n"
-   "\t -s|--physicalextentsize PhysicalExtentSize[kKmMgGtT] |" "\n"
+   "\t -s|--physicalextentsize PhysicalExtentSize[kKmMgGtTpPeE] |" "\n"
    "\t --addtag Tag |\n"
    "\t --deltag Tag}\n"
    "\t[VolumeGroupName...]\n",
@@ -636,7 +642,7 @@
    "\t[--labelsector sector] " "\n"
    "\t[-M|--metadatatype 1|2]" "\n"
    "\t[--metadatacopies #copies]" "\n"
-   "\t[--metadatasize MetadataSize[kKmMgGtT]]" "\n"
+   "\t[--metadatasize MetadataSize[kKmMgGtTpPeE]]" "\n"
    "\t[-t|--test] " "\n"
    "\t[-v|--verbose] " "\n"
    "\t[--version] " "\n"
@@ -651,13 +657,13 @@
    "\t[-A|--autobackup {y|n}] " "\n"
    "\t[--addtag Tag] " "\n"
    "\t[--alloc AllocationPolicy] " "\n"
-   "\t[-c|--clustered] " "\n"
+   "\t[-c|--clustered {y|n}] " "\n"
    "\t[-d|--debug]" "\n"
    "\t[-h|--help]" "\n"
    "\t[-l|--maxlogicalvolumes MaxLogicalVolumes]" "\n"
    "\t[-M|--metadatatype 1|2] " "\n"
    "\t[-p|--maxphysicalvolumes MaxPhysicalVolumes] " "\n"
-   "\t[-s|--physicalextentsize PhysicalExtentSize[kKmMgGtT]] " "\n"
+   "\t[-s|--physicalextentsize PhysicalExtentSize[kKmMgGtTpPeE]] " "\n"
    "\t[-t|--test] " "\n"
    "\t[-v|--verbose]" "\n"
    "\t[--version] " "\n"

Modified: lvm2/upstream/current/tools/dumpconfig.c
==============================================================================
--- lvm2/upstream/current/tools/dumpconfig.c	(original)
+++ lvm2/upstream/current/tools/dumpconfig.c	Sat Apr  7 15:30:42 2007
@@ -19,15 +19,10 @@
 {
 	const char *file = NULL;
 
-	if (argc == 1)
-		file = argv[0];
+	if (arg_count(cmd, file_ARG))
+		file = arg_str_value(cmd, file_ARG, "");
 
-	if (argc > 1) {
-		log_error("Please specify one file for output");
-		return EINVALID_CMD_LINE;
-	}
-
-	if (!write_config_file(cmd->cft, file))
+	if (!write_config_file(cmd->cft, file, argc, argv))
 		return ECMD_FAILED;
 
 	return ECMD_PROCESSED;

Modified: lvm2/upstream/current/tools/fsadm/Makefile.in
==============================================================================
--- lvm2/upstream/current/tools/fsadm/Makefile.in	(original)
+++ lvm2/upstream/current/tools/fsadm/Makefile.in	Sat Apr  7 15:30:42 2007
@@ -23,7 +23,7 @@
 include $(top_srcdir)/make.tmpl
 
 fsadm: $(OBJECTS)
-	$(CC) -o $@ $(OBJECTS) -rdynamic
+	$(CC) -o $@ $(CFLAGS) $(OBJECTS) -rdynamic
 
 install: fsadm
 	$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) fsadm \

Modified: lvm2/upstream/current/tools/lvchange.c
==============================================================================
--- lvm2/upstream/current/tools/lvchange.c	(original)
+++ lvm2/upstream/current/tools/lvchange.c	Sat Apr  7 15:30:42 2007
@@ -19,6 +19,7 @@
 			       struct logical_volume *lv)
 {
 	uint32_t lv_access;
+	struct lvinfo info;
 
 	lv_access = arg_uint_value(cmd, permission_ARG, 0);
 
@@ -34,6 +35,13 @@
 		return 0;
 	}
 
+	if ((lv->status & MIRRORED) && (lv->vg->status & CLUSTERED) &&
+	    lv_info(cmd, lv, &info, 0) && info.exists) {
+		log_error("Cannot change permissions of mirror \"%s\" "
+			  "while active.", lv->name);
+		return 0;
+	}
+
 	if (lv_access & LVM_WRITE) {
 		lv->status |= LVM_WRITE;
 		log_verbose("Setting logical volume \"%s\" read/write",
@@ -72,10 +80,9 @@
 	return 1;
 }
 
-static int lvchange_registration(struct cmd_context *cmd,
-				 struct logical_volume *lv)
+static int lvchange_monitoring(struct cmd_context *cmd,
+			       struct logical_volume *lv)
 {
-	int r;
 	struct lvinfo info;
 
 	if (!lv_info(cmd, lv, &info, 0) || !info.exists) {
@@ -83,25 +90,15 @@
 		return 0;
 	}
 
-	/* do not register pvmove lv's */
+	/* do not monitor pvmove lv's */
 	if (lv->status & PVMOVE)
 		return 1;
 
-	log_verbose("%smonitoring logical volume \"%s\"",
-		    (dmeventd_register_mode()) ? "" : "Not ", lv->name);
-	r = register_dev_for_events(cmd, lv, dmeventd_register_mode());
-
-	if (r < 0) {
-		log_error("Unable to %smonitor logical volume, %s",
-			  (dmeventd_register_mode()) ? "" : "un", lv->name);
-		r = 0;
-	} else if (!r) {
-		log_verbose("Logical volume %s needs no monitoring.",
-			    lv->name);
-		r = 1;
-	}
+	if ((dmeventd_monitor_mode() != DMEVENTD_MONITOR_IGNORE) &&
+	    !monitor_dev_for_events(cmd, lv, dmeventd_monitor_mode()))
+		stack;
 
-	return r;
+	return 1;
 }
 
 static int lvchange_availability(struct cmd_context *cmd,
@@ -127,10 +124,10 @@
 		}
 	} else {
 		if (lockingfailed() && (lv->vg->status & CLUSTERED)) {
-                	log_verbose("Locking failed: ignoring clustered "
+			log_verbose("Locking failed: ignoring clustered "
 				    "logical volume %s", lv->name);
-                	return 0;
-        	}
+			return 0;
+		}
 
 		if (lv_is_origin(lv) || (activate == CHANGE_AE)) {
 			log_verbose("Activating logical volume \"%s\" "
@@ -175,6 +172,159 @@
 	return 1;
 }
 
+static int lvchange_resync(struct cmd_context *cmd,
+			      struct logical_volume *lv)
+{
+	int active = 0;
+	struct lvinfo info;
+	struct logical_volume *log_lv;
+
+	if (!(lv->status & MIRRORED)) {
+		log_error("Unable to resync %s because it is not mirrored.",
+			  lv->name);
+		return 1;
+	}
+
+	if (lv->status & PVMOVE) {
+		log_error("Unable to resync pvmove volume %s", lv->name);
+		return 0;
+	}
+
+	if (lv->status & LOCKED) {
+		log_error("Unable to resync locked volume %s", lv->name);
+		return 0;
+	}
+
+	if (lv_info(cmd, lv, &info, 1)) {
+		if (info.open_count) {
+			log_error("Can't resync open logical volume \"%s\"",
+				  lv->name);
+			return ECMD_FAILED;
+		}
+
+		if (info.exists) {
+			if (!arg_count(cmd, yes_ARG) &&
+			    yes_no_prompt("Do you really want to deactivate "
+					  "logical volume %s to resync it? [y/n]: ",
+					  lv->name) == 'n') {
+				log_print("Logical volume \"%s\" not resynced",
+					  lv->name);
+				return ECMD_FAILED;
+			}
+
+			active = 1;
+		}
+	}
+
+	if ((lv->vg->status & CLUSTERED) && !activate_lv_excl(cmd, lv)) {
+		log_error("Can't get exclusive access to clustered volume %s",
+			  lv->name);
+		return ECMD_FAILED;
+	}
+
+	if (!deactivate_lv(cmd, lv)) {
+		log_error("Unable to deactivate %s for resync", lv->name);
+		return 0;
+	}
+
+	log_lv = first_seg(lv)->log_lv;
+
+	log_very_verbose("Starting resync of %s%s%s mirror \"%s\"",
+			 (active) ? "active " : "",
+			 (lv->vg->status & CLUSTERED) ? "clustered " : "",
+			 (log_lv) ? "disk-logged" : "core-logged",
+			 lv->name);
+
+	/*
+	 * If this mirror has a core log (i.e. !log_lv),
+	 * then simply deactivating/activating will cause
+	 * it to reset the sync status.  We only need to
+	 * worry about persistent logs.
+	 */
+	if (!log_lv && !(lv->status & MIRROR_NOTSYNCED)) {
+		if (active && !activate_lv(cmd, lv)) {
+			log_error("Failed to reactivate %s to resynchronize "
+				  "mirror", lv->name);
+			return 0;
+		}
+		return 1;
+	}
+
+	lv->status &= ~MIRROR_NOTSYNCED;
+
+	if (log_lv) {
+		/* Separate mirror log so we can clear it */
+		first_seg(lv)->log_lv = NULL;
+		log_lv->status &= ~MIRROR_LOG;
+		log_lv->status |= VISIBLE_LV;
+
+		if (!vg_write(lv->vg)) {
+			log_error("Failed to write intermediate VG metadata.");
+			if (active) {
+				first_seg(lv)->log_lv = log_lv;
+				log_lv->status |= MIRROR_LOG;
+				log_lv->status &= ~VISIBLE_LV;
+				if (!activate_lv(cmd, lv))
+					stack;
+			}
+			return 0;
+		}
+
+		backup(lv->vg);
+
+		if (!vg_commit(lv->vg)) {
+			log_error("Failed to commit intermediate VG metadata.");
+			if (active) {
+				first_seg(lv)->log_lv = log_lv;
+				log_lv->status |= MIRROR_LOG;
+				log_lv->status &= ~VISIBLE_LV;
+				if (!activate_lv(cmd, lv))
+					stack;
+			}
+			return 0;
+		}
+
+		if (!activate_lv(cmd, log_lv)) {
+			log_error("Unable to activate %s for mirror log resync",
+				  log_lv->name);
+			return 0;
+		}
+
+		log_very_verbose("Clearing log device %s", log_lv->name);
+		if (!set_lv(cmd, log_lv, log_lv->size, 0)) {
+			log_error("Unable to reset sync status for %s", lv->name);
+			if (!deactivate_lv(cmd, log_lv))
+				log_error("Failed to deactivate log LV after "
+					  "wiping failed");
+			return 0;
+		}
+
+		if (!deactivate_lv(cmd, log_lv)) {
+			log_error("Unable to deactivate log LV %s after wiping "
+				  "for resync", log_lv->name);
+			return 0;
+		}
+
+		/* Put mirror log back in place */
+		first_seg(lv)->log_lv = log_lv;
+		log_lv->status |= MIRROR_LOG;
+		log_lv->status &= ~VISIBLE_LV;
+	}
+
+	log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
+	if (!vg_write(lv->vg) || !vg_commit(lv->vg)) {
+		log_error("Failed to update metadata on disk.");
+		return 0;
+	}
+
+	if (active && !activate_lv(cmd, lv)) {
+		log_error("Failed to reactivate %s after resync", lv->name);
+		return 0;
+	}
+
+	return 1;
+}
+
 static int lvchange_alloc(struct cmd_context *cmd, struct logical_volume *lv)
 {
 	int want_contiguous = 0;
@@ -442,7 +592,9 @@
 		return ECMD_FAILED;
 	}
 
-	init_dmeventd_register(arg_int_value(cmd, monitor_ARG, DEFAULT_DMEVENTD_MONITOR));
+	init_dmeventd_monitor(arg_int_value(cmd, monitor_ARG,
+					    cmd->is_static ?
+					    DMEVENTD_MONITOR_IGNORE : DEFAULT_DMEVENTD_MONITOR));
 
 	/* access permission change */
 	if (arg_count(cmd, permission_ARG)) {
@@ -495,6 +647,10 @@
 	if (doit)
 		log_print("Logical volume \"%s\" changed", lv->name);
 
+	if (arg_count(cmd, resync_ARG))
+		if (!lvchange_resync(cmd, lv))
+			return ECMD_FAILED;
+
 	/* availability change */
 	if (arg_count(cmd, available_ARG)) {
 		if (!lvchange_availability(cmd, lv))
@@ -508,7 +664,7 @@
 	if (!arg_count(cmd, available_ARG) &&
 	    !arg_count(cmd, refresh_ARG) &&
 	    arg_count(cmd, monitor_ARG)) {
-		if (!lvchange_registration(cmd, lv))
+		if (!lvchange_monitoring(cmd, lv))
 			return ECMD_FAILED;
 	}
 
@@ -522,9 +678,10 @@
 	    && !arg_count(cmd, minor_ARG) && !arg_count(cmd, major_ARG)
 	    && !arg_count(cmd, persistent_ARG) && !arg_count(cmd, addtag_ARG)
 	    && !arg_count(cmd, deltag_ARG) && !arg_count(cmd, refresh_ARG)
-	    && !arg_count(cmd, alloc_ARG) && !arg_count(cmd, monitor_ARG)) {
+	    && !arg_count(cmd, alloc_ARG) && !arg_count(cmd, monitor_ARG)
+	    && !arg_count(cmd, resync_ARG)) {
 		log_error("Need 1 or more of -a, -C, -j, -m, -M, -p, -r, "
-			  "--refresh, --alloc, --addtag, --deltag "
+			  "--resync, --refresh, --alloc, --addtag, --deltag "
 			  "or --monitor");
 		return EINVALID_CMD_LINE;
 	}

Modified: lvm2/upstream/current/tools/lvconvert.c
==============================================================================
--- lvm2/upstream/current/tools/lvconvert.c	(original)
+++ lvm2/upstream/current/tools/lvconvert.c	Sat Apr  7 15:30:42 2007
@@ -212,7 +212,7 @@
 	}
 
 	if (activation() && lp->segtype->ops->target_present &&
-	    !lp->segtype->ops->target_present()) {
+	    !lp->segtype->ops->target_present(NULL)) {
 		log_error("%s: Required device-mapper target(s) not "
 			  "detected in your kernel", lp->segtype->name);
 		return 0;
@@ -281,15 +281,8 @@
 			if (lp->mirrors == existing_mirrors) {
 				if (!seg->log_lv && !arg_count(cmd, corelog_ARG)) {
 					/* No disk log present, add one. */
-					/* FIXME: Why doesn't this work?  Without
-					   it, we will probably put the log on the
-					   same device as a mirror leg.
-					  if (!(parallel_areas = build_parallel_areas_from_lv(cmd, lv))) {
-					  stack;
-					  return 0;
-					  }
-					*/
-					parallel_areas = NULL;
+					if (!(parallel_areas = build_parallel_areas_from_lv(cmd, lv)))
+						return_0;
 					if (!lv_mirror_percent(cmd, lv, 0, &sync_percent, NULL)) {
 						log_error("Unable to determine mirror sync status.");
 						return 0;
@@ -297,7 +290,7 @@
 
 					segtype = get_segtype_from_string(cmd, "striped");
 
-					if (!(ah = allocate_extents(lv->vg, NULL, segtype, 1,
+					if (!(ah = allocate_extents(lv->vg, NULL, segtype, 0,
 								    0, 1, 0,
 								    NULL, 0, 0, lp->pvh,
 								    lp->alloc,
@@ -453,9 +446,9 @@
 		return 0;
 	}
 
-	if (!lp->zero)
-		log_error("WARNING: \"%s\" not zeroed", lv->name);
-	else if (!set_lv(cmd, lv, 0)) {
+	if (!lp->zero || !(lv->status & LVM_WRITE))
+		log_print("WARNING: \"%s\" not zeroed", lv->name);
+	else if (!set_lv(cmd, lv, 0, 0)) {
 			log_error("Aborting. Failed to wipe snapshot "
 				  "exception store.");
 			return 0;

Modified: lvm2/upstream/current/tools/lvcreate.c
==============================================================================
--- lvm2/upstream/current/tools/lvcreate.c	(original)
+++ lvm2/upstream/current/tools/lvcreate.c	Sat Apr  7 15:30:42 2007
@@ -95,7 +95,7 @@
 			}
 
 		} else {
-			vg_name = skip_dev_dir(cmd, argv[0]);
+			vg_name = skip_dev_dir(cmd, argv[0], NULL);
 			if (strrchr(vg_name, '/')) {
 				log_error("Volume group name expected "
 					  "(no slash)");
@@ -386,7 +386,7 @@
 	}
 
 	if (activation() && lp->segtype->ops->target_present &&
-	    !lp->segtype->ops->target_present()) {
+	    !lp->segtype->ops->target_present(NULL)) {
 		log_error("%s: Required device-mapper target(s) not "
 			  "detected in your kernel", lp->segtype->name);
 		return 0;
@@ -434,6 +434,10 @@
 	else
 		lp->permission = LVM_READ | LVM_WRITE;
 
+	/* Must not zero read only volume */
+	if (!(lp->permission & LVM_WRITE))
+		lp->zero = 0;
+
 	lp->minor = arg_int_value(cmd, minor_ARG, -1);
 	lp->major = arg_int_value(cmd, major_ARG, -1);
 
@@ -556,7 +560,16 @@
 				  display_size(cmd, tmp_size));
 		}
 
-		lp->extents = tmp_size / vg->extent_size;
+		if (tmp_size > (uint64_t) UINT32_MAX * vg->extent_size) {
+			log_error("Volume too large (%s) for extent size %s. "
+				  "Upper limit is %s.",
+				  display_size(cmd, tmp_size),
+				  display_size(cmd, vg->extent_size),
+				  display_size(cmd, (uint64_t) UINT32_MAX *
+						   vg->extent_size));
+			return 0;
+		}
+		lp->extents = (uint64_t) tmp_size / vg->extent_size;
 	}
 
 	switch(lp->percent) {
@@ -618,8 +631,7 @@
 	}
 
 	if (!lp->extents) {
-		log_error("Unable to create logical volume %s with no extents",
-			  lp->lv_name);
+		log_error("Unable to create new logical volume with no extents");
 		return 0;
 	}
 
@@ -761,18 +773,19 @@
 		return 0;
 	}
 
-	if (!activate_lv(cmd, lv)) {
-		if (lp->snapshot)
-			/* FIXME Remove the failed lv we just added */
+	if (lp->snapshot) {
+		if (!activate_lv_excl(cmd, lv)) {
 			log_error("Aborting. Failed to activate snapshot "
 				  "exception store. Remove new LV and retry.");
-		else
-			log_error("Failed to activate new LV.");
+			return 0;
+		}
+	} else if (!activate_lv(cmd, lv)) {
+		log_error("Failed to activate new LV.");
 		return 0;
 	}
 
 	if ((lp->zero || lp->snapshot) && activation()) {
-		if (!set_lv(cmd, lv, 0) && lp->snapshot) {
+		if (!set_lv(cmd, lv, 0, 0) && lp->snapshot) {
 			/* FIXME Remove the failed lv we just added */
 			log_error("Aborting. Failed to wipe snapshot "
 				  "exception store. Remove new LV and retry.");
@@ -787,10 +800,8 @@
 		/* Reset permission after zeroing */
 		if (!(lp->permission & LVM_WRITE))
 			lv->status &= ~LVM_WRITE;
-		if (!deactivate_lv(cmd, lv)) {
-			log_err("Couldn't deactivate new snapshot.");
-			return 0;
-		}
+
+		/* cow LV remains active and becomes snapshot LV */
 
 		if (!vg_add_snapshot(vg->fid, NULL, org, lv, NULL,
 				     org->le_count, lp->chunk_size)) {

Modified: lvm2/upstream/current/tools/lvm-static.c
==============================================================================
--- lvm2/upstream/current/tools/lvm-static.c	(original)
+++ lvm2/upstream/current/tools/lvm-static.c	Sat Apr  7 15:30:42 2007
@@ -19,3 +19,8 @@
 {
 	return lvm2_main(argc, argv, 1);
 }
+
+int lvm_shell(struct cmd_context *cmd, struct cmdline_context *cmdline)
+{
+	return 0;
+}

Modified: lvm2/upstream/current/tools/lvm.c
==============================================================================
--- lvm2/upstream/current/tools/lvm.c	(original)
+++ lvm2/upstream/current/tools/lvm.c	Sat Apr  7 15:30:42 2007
@@ -13,9 +13,233 @@
  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include "tools.h"
 #include "lvm2cmdline.h"
 
 int main(int argc, char **argv)
 {
 	return lvm2_main(argc, argv, 0);
 }
+
+#ifdef READLINE_SUPPORT
+
+#  include <readline/readline.h>
+#  include <readline/history.h>
+#  ifndef HAVE_RL_COMPLETION_MATCHES
+#    define rl_completion_matches(a, b) completion_matches((char *)a, b)
+#  endif
+
+static struct cmdline_context *_cmdline;
+
+/* List matching commands */
+static char *_list_cmds(const char *text, int state)
+{
+	static int i = 0;
+	static size_t len = 0;
+
+	/* Initialise if this is a new completion attempt */
+	if (!state) {
+		i = 0;
+		len = strlen(text);
+	}
+
+	while (i < _cmdline->num_commands)
+		if (!strncmp(text, _cmdline->commands[i++].name, len))
+			return strdup(_cmdline->commands[i - 1].name);
+
+	return NULL;
+}
+
+/* List matching arguments */
+static char *_list_args(const char *text, int state)
+{
+	static int match_no = 0;
+	static size_t len = 0;
+	static struct command *com;
+
+	/* Initialise if this is a new completion attempt */
+	if (!state) {
+		char *s = rl_line_buffer;
+		int j = 0;
+
+		match_no = 0;
+		com = NULL;
+		len = strlen(text);
+
+		/* Find start of first word in line buffer */
+		while (isspace(*s))
+			s++;
+
+		/* Look for word in list of commands */
+		for (j = 0; j < _cmdline->num_commands; j++) {
+			const char *p;
+			char *q = s;
+
+			p = _cmdline->commands[j].name;
+			while (*p == *q) {
+				p++;
+				q++;
+			}
+			if ((!*p) && *q == ' ') {
+				com = _cmdline->commands + j;
+				break;
+			}
+		}
+
+		if (!com)
+			return NULL;
+	}
+
+	/* Short form arguments */
+	if (len < 3) {
+		while (match_no < com->num_args) {
+			char s[3];
+			char c;
+			if (!(c = (_cmdline->the_args +
+				   com->valid_args[match_no++])->short_arg))
+				continue;
+
+			sprintf(s, "-%c", c);
+			if (!strncmp(text, s, len))
+				return strdup(s);
+		}
+	}
+
+	/* Long form arguments */
+	if (match_no < com->num_args)
+		match_no = com->num_args;
+
+	while (match_no - com->num_args < com->num_args) {
+		const char *l;
+		l = (_cmdline->the_args +
+		     com->valid_args[match_no++ - com->num_args])->long_arg;
+		if (*(l + 2) && !strncmp(text, l, len))
+			return strdup(l);
+	}
+
+	return NULL;
+}
+
+/* Custom completion function */
+static char **_completion(const char *text, int start_pos, int end_pos)
+{
+	char **match_list = NULL;
+	int p = 0;
+
+	while (isspace((int) *(rl_line_buffer + p)))
+		p++;
+
+	/* First word should be one of our commands */
+	if (start_pos == p)
+		match_list = rl_completion_matches(text, _list_cmds);
+
+	else if (*text == '-')
+		match_list = rl_completion_matches(text, _list_args);
+	/* else other args */
+
+	/* No further completion */
+	rl_attempted_completion_over = 1;
+	return match_list;
+}
+
+static int _hist_file(char *buffer, size_t size)
+{
+	char *e = getenv("HOME");
+
+	if (dm_snprintf(buffer, size, "%s/.lvm_history", e) < 0) {
+		log_error("$HOME/.lvm_history: path too long");
+		return 0;
+	}
+
+	return 1;
+}
+
+static void _read_history(struct cmd_context *cmd)
+{
+	char hist_file[PATH_MAX];
+
+	if (!_hist_file(hist_file, sizeof(hist_file)))
+		return;
+
+	if (read_history(hist_file))
+		log_very_verbose("Couldn't read history from %s.", hist_file);
+
+	stifle_history(find_config_tree_int(cmd, "shell/history_size",
+				       DEFAULT_MAX_HISTORY));
+
+}
+
+static void _write_history(void)
+{
+	char hist_file[PATH_MAX];
+
+	if (!_hist_file(hist_file, sizeof(hist_file)))
+		return;
+
+	if (write_history(hist_file))
+		log_very_verbose("Couldn't write history to %s.", hist_file);
+}
+
+int lvm_shell(struct cmd_context *cmd, struct cmdline_context *cmdline)
+{
+	int argc, ret;
+	char *input = NULL, *args[MAX_ARGS], **argv;
+
+	rl_readline_name = "lvm";
+	rl_attempted_completion_function = (CPPFunction *) _completion;
+
+	_read_history(cmd);
+
+	_cmdline = cmdline;
+
+	_cmdline->interactive = 1;
+	while (1) {
+		free(input);
+		input = readline("lvm> ");
+
+		/* EOF */
+		if (!input) {
+			printf("\n");
+			break;
+		}
+
+		/* empty line */
+		if (!*input)
+			continue;
+
+		add_history(input);
+
+		argv = args;
+
+		if (lvm_split(input, &argc, argv, MAX_ARGS) == MAX_ARGS) {
+			log_error("Too many arguments, sorry.");
+			continue;
+		}
+
+		if (!strcmp(argv[0], "lvm")) {
+			argv++;
+			argc--;
+		}
+
+		if (!argc)
+			continue;
+
+		if (!strcmp(argv[0], "quit") || !strcmp(argv[0], "exit")) {
+			remove_history(history_length - 1);
+			log_error("Exiting.");
+			break;
+		}
+
+		ret = lvm_run_command(cmd, argc, argv);
+		if (ret == ENO_SUCH_CMD)
+			log_error("No such command '%s'.  Try 'help'.",
+				  argv[0]);
+
+		_write_history();
+	}
+
+	free(input);
+	return 0;
+}
+
+#endif	/* READLINE_SUPPORT */

Modified: lvm2/upstream/current/tools/lvm2cmdline.h
==============================================================================
--- lvm2/upstream/current/tools/lvm2cmdline.h	(original)
+++ lvm2/upstream/current/tools/lvm2cmdline.h	Sat Apr  7 15:30:42 2007
@@ -18,6 +18,14 @@
 
 struct cmd_context;
 
+struct cmdline_context {
+        struct arg *the_args;
+        struct command *commands;
+        int num_commands;
+        int commands_size;
+        int interactive;
+};
+
 int lvm2_main(int argc, char **argv, unsigned is_static);
 
 void *cmdlib_lvm2_init(unsigned is_static);
@@ -27,5 +35,6 @@
 void lvm_register_commands(void);
 int lvm_split(char *str, int *argc, char **argv, int max);
 int lvm_run_command(struct cmd_context *cmd, int argc, char **argv);
+int lvm_shell(struct cmd_context *cmd, struct cmdline_context *cmdline);
 
 #endif

Modified: lvm2/upstream/current/tools/lvmcmdlib.c
==============================================================================
--- lvm2/upstream/current/tools/lvmcmdlib.c	(original)
+++ lvm2/upstream/current/tools/lvmcmdlib.c	Sat Apr  7 15:30:42 2007
@@ -16,6 +16,7 @@
 #include "tools.h"
 #include "lvm2cmdline.h"
 #include "label.h"
+#include "memlock.h"
 #include "version.h"
 
 #include "lvm2cmd.h"
@@ -77,7 +78,13 @@
 		goto out;
 	}
 
-	ret = lvm_run_command(cmd, argc, argv);
+	/* FIXME Temporary - move to libdevmapper */
+	if (!strcmp(cmdline, "_memlock_inc"))
+		memlock_inc();
+	if (!strcmp(cmdline, "_memlock_dec"))
+		memlock_dec();
+	else
+		ret = lvm_run_command(cmd, argc, argv);
 
       out:
 	dm_free(cmdcopy);

Modified: lvm2/upstream/current/tools/lvmcmdline.c
==============================================================================
--- lvm2/upstream/current/tools/lvmcmdline.c	(original)
+++ lvm2/upstream/current/tools/lvmcmdline.c	Sat Apr  7 15:30:42 2007
@@ -41,30 +41,16 @@
 #  define OPTIND_INIT 1
 #endif
 
-#ifdef READLINE_SUPPORT
-#  include <readline/readline.h>
-#  include <readline/history.h>
-#  ifndef HAVE_RL_COMPLETION_MATCHES
-#    define rl_completion_matches(a, b) completion_matches((char *)a, b)
-#  endif
-#endif
-
 /*
- * Exported table of valid switches
+ * Table of valid switches
  */
-struct arg the_args[ARG_COUNT + 1] = {
-
+static struct arg _the_args[ARG_COUNT + 1] = {
 #define arg(a, b, c, d) {b, "", "--" c, d, 0, NULL, 0, 0, INT64_C(0), UINT64_C(0), SIGN_NONE, PERCENT_NONE, NULL},
 #include "args.h"
 #undef arg
-
 };
 
-static int _array_size;
-static int _num_commands;
-static struct command *_commands;
-
-static int _interactive;
+static struct cmdline_context _cmdline;
 
 int yes_no_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a)
 {
@@ -186,7 +172,7 @@
 {
 	char *ptr;
 	int i;
-	static const char *suffixes = "kmgt";
+	static const char *suffixes = "kmgtpe";
 	char *val;
 	double v;
 
@@ -412,21 +398,21 @@
 
 static void __alloc(int size)
 {
-	if (!(_commands = dm_realloc(_commands, sizeof(*_commands) * size))) {
+	if (!(_cmdline.commands = dm_realloc(_cmdline.commands, sizeof(*_cmdline.commands) * size))) {
 		log_fatal("Couldn't allocate memory.");
 		exit(ECMD_FAILED);
 	}
 
-	_array_size = size;
+	_cmdline.commands_size = size;
 }
 
 static void _alloc_command(void)
 {
-	if (!_array_size)
+	if (!_cmdline.commands_size)
 		__alloc(32);
 
-	if (_array_size <= _num_commands)
-		__alloc(2 * _array_size);
+	if (_cmdline.commands_size <= _cmdline.num_commands)
+		__alloc(2 * _cmdline.commands_size);
 }
 
 static void _create_new_command(const char *name, command_fn command,
@@ -437,7 +423,7 @@
 
 	_alloc_command();
 
-	nc = _commands + _num_commands++;
+	nc = _cmdline.commands + _cmdline.num_commands++;
 
 	nc->name = name;
 	nc->desc = desc;
@@ -495,17 +481,17 @@
 	namebase = strdup(name);
 	base = basename(namebase);
 
-	for (i = 0; i < _num_commands; i++) {
-		if (!strcmp(base, _commands[i].name))
+	for (i = 0; i < _cmdline.num_commands; i++) {
+		if (!strcmp(base, _cmdline.commands[i].name))
 			break;
 	}
 
 	free(namebase);
 
-	if (i >= _num_commands)
+	if (i >= _cmdline.num_commands)
 		return 0;
 
-	return _commands + i;
+	return _cmdline.commands + i;
 }
 
 static void _usage(const char *name)
@@ -527,7 +513,7 @@
  */
 static void _add_getopt_arg(int arg, char **ptr, struct option **o)
 {
-	struct arg *a = the_args + arg;
+	struct arg *a = _cmdline.the_args + arg;
 
 	if (a->short_arg) {
 		*(*ptr)++ = a->short_arg;
@@ -556,12 +542,12 @@
 
 	for (i = 0; i < com->num_args; i++) {
 		arg = com->valid_args[i];
-		a = the_args + arg;
+		a = _cmdline.the_args + arg;
 
 		/*
 		 * opt should equal either the
 		 * short arg, or the index into
-		 * 'the_args'.
+		 * the_args.
 		 */
 		if ((a->short_arg && (opt == a->short_arg)) ||
 		    (!a->short_arg && (opt == arg)))
@@ -580,7 +566,7 @@
 	struct arg *a;
 
 	for (i = 0; i < ARG_COUNT; i++) {
-		a = the_args + i;
+		a = _cmdline.the_args + i;
 
 		/* zero the count and arg */
 		a->count = 0;
@@ -651,15 +637,15 @@
 
 	if (arg_count(cmd, oldarg) && arg_count(cmd, newarg)) {
 		log_error("%s and %s are synonyms.  Please only supply one.",
-			  the_args[oldarg].long_arg, the_args[newarg].long_arg);
+			  _cmdline.the_args[oldarg].long_arg, _cmdline.the_args[newarg].long_arg);
 		return 0;
 	}
 
 	if (!arg_count(cmd, oldarg))
 		return 1;
 
-	old = the_args + oldarg;
-	new = the_args + newarg;
+	old = _cmdline.the_args + oldarg;
+	new = _cmdline.the_args + newarg;
 
 	new->count = old->count;
 	new->value = old->value;
@@ -712,10 +698,8 @@
 				  cmd->default_settings.activation);
 	}
 
-	if (arg_count(cmd, autobackup_ARG)) {
-		cmd->current_settings.archive = 1;
-		cmd->current_settings.backup = 1;
-	}
+	cmd->current_settings.archive = arg_int_value(cmd, autobackup_ARG, cmd->current_settings.archive);
+	cmd->current_settings.backup = arg_int_value(cmd, autobackup_ARG, cmd->current_settings.backup);
 
 	if (arg_count(cmd, partial_ARG)) {
 		init_partial(1);
@@ -784,8 +768,8 @@
 	log_error("Use 'lvm help <command>' for more information");
 	log_error(" ");
 
-	for (i = 0; i < _num_commands; i++) {
-		struct command *com = _commands + i;
+	for (i = 0; i < _cmdline.num_commands; i++) {
+		struct command *com = _cmdline.commands + i;
 
 		log_error("%-16.16s%s", com->name, com->desc);
 	}
@@ -961,7 +945,7 @@
 	 */
 	dm_pool_empty(cmd->mem);
 
-	if (ret == EINVALID_CMD_LINE && !_interactive)
+	if (ret == EINVALID_CMD_LINE && !_cmdline.interactive)
 		_usage(cmd->command->name);
 
 	log_debug("Completed: %s", cmd->cmd_line);
@@ -1032,7 +1016,9 @@
 {
 	struct cmd_context *cmd;
 
-	if (!(cmd = create_toolcontext(&the_args[0], is_static))) {
+	_cmdline.the_args = &_the_args[0];
+
+	if (!(cmd = create_toolcontext(_cmdline.the_args, is_static, 0))) {
 		stack;
 		return NULL;
 	}
@@ -1048,10 +1034,10 @@
 {
 	int i;
 
-	for (i = 0; i < _num_commands; i++)
-		dm_free(_commands[i].valid_args);
+	for (i = 0; i < _cmdline.num_commands; i++)
+		dm_free(_cmdline.commands[i].valid_args);
 
-	dm_free(_commands);
+	dm_free(_cmdline.commands);
 }
 
 void lvm_fin(struct cmd_context *cmd)
@@ -1067,8 +1053,9 @@
 	char buffer[CMD_LEN];
 	int ret = 0;
 	int magic_number = 0;
+	char *script_file = argv[0];
 
-	if ((script = fopen(argv[0], "r")) == NULL)
+	if ((script = fopen(script_file, "r")) == NULL)
 		return ENO_SUCH_CMD;
 
 	while (fgets(buffer, sizeof(buffer), script) != NULL) {
@@ -1101,222 +1088,12 @@
 		lvm_run_command(cmd, argc, argv);
 	}
 
-	fclose(script);
-	return ret;
-}
-
-#ifdef READLINE_SUPPORT
-/* List matching commands */
-static char *_list_cmds(const char *text, int state)
-{
-	static int i = 0;
-	static size_t len = 0;
-
-	/* Initialise if this is a new completion attempt */
-	if (!state) {
-		i = 0;
-		len = strlen(text);
-	}
-
-	while (i < _num_commands)
-		if (!strncmp(text, _commands[i++].name, len))
-			return strdup(_commands[i - 1].name);
-
-	return NULL;
-}
-
-/* List matching arguments */
-static char *_list_args(const char *text, int state)
-{
-	static int match_no = 0;
-	static size_t len = 0;
-	static struct command *com;
-
-	/* Initialise if this is a new completion attempt */
-	if (!state) {
-		char *s = rl_line_buffer;
-		int j = 0;
-
-		match_no = 0;
-		com = NULL;
-		len = strlen(text);
-
-		/* Find start of first word in line buffer */
-		while (isspace(*s))
-			s++;
-
-		/* Look for word in list of commands */
-		for (j = 0; j < _num_commands; j++) {
-			const char *p;
-			char *q = s;
-
-			p = _commands[j].name;
-			while (*p == *q) {
-				p++;
-				q++;
-			}
-			if ((!*p) && *q == ' ') {
-				com = _commands + j;
-				break;
-			}
-		}
-
-		if (!com)
-			return NULL;
-	}
-
-	/* Short form arguments */
-	if (len < 3) {
-		while (match_no < com->num_args) {
-			char s[3];
-			char c;
-			if (!(c = (the_args +
-				   com->valid_args[match_no++])->short_arg))
-				continue;
-
-			sprintf(s, "-%c", c);
-			if (!strncmp(text, s, len))
-				return strdup(s);
-		}
-	}
-
-	/* Long form arguments */
-	if (match_no < com->num_args)
-		match_no = com->num_args;
-
-	while (match_no - com->num_args < com->num_args) {
-		const char *l;
-		l = (the_args +
-		     com->valid_args[match_no++ - com->num_args])->long_arg;
-		if (*(l + 2) && !strncmp(text, l, len))
-			return strdup(l);
-	}
-
-	return NULL;
-}
-
-/* Custom completion function */
-static char **_completion(const char *text, int start_pos, int end_pos)
-{
-	char **match_list = NULL;
-	int p = 0;
-
-	while (isspace((int) *(rl_line_buffer + p)))
-		p++;
-
-	/* First word should be one of our commands */
-	if (start_pos == p)
-		match_list = rl_completion_matches(text, _list_cmds);
-
-	else if (*text == '-')
-		match_list = rl_completion_matches(text, _list_args);
-	/* else other args */
-
-	/* No further completion */
-	rl_attempted_completion_over = 1;
-	return match_list;
-}
-
-static int _hist_file(char *buffer, size_t size)
-{
-	char *e = getenv("HOME");
-
-	if (dm_snprintf(buffer, size, "%s/.lvm_history", e) < 0) {
-		log_error("$HOME/.lvm_history: path too long");
-		return 0;
-	}
-
-	return 1;
-}
-
-static void _read_history(struct cmd_context *cmd)
-{
-	char hist_file[PATH_MAX];
-
-	if (!_hist_file(hist_file, sizeof(hist_file)))
-		return;
-
-	if (read_history(hist_file))
-		log_very_verbose("Couldn't read history from %s.", hist_file);
-
-	stifle_history(find_config_tree_int(cmd, "shell/history_size",
-				       DEFAULT_MAX_HISTORY));
-
-}
-
-static void _write_history(void)
-{
-	char hist_file[PATH_MAX];
-
-	if (!_hist_file(hist_file, sizeof(hist_file)))
-		return;
-
-	if (write_history(hist_file))
-		log_very_verbose("Couldn't write history to %s.", hist_file);
-}
-
-static int _shell(struct cmd_context *cmd)
-{
-	int argc, ret;
-	char *input = NULL, *args[MAX_ARGS], **argv;
-
-	rl_readline_name = "lvm";
-	rl_attempted_completion_function = (CPPFunction *) _completion;
-
-	_read_history(cmd);
-
-	_interactive = 1;
-	while (1) {
-		free(input);
-		input = readline("lvm> ");
-
-		/* EOF */
-		if (!input) {
-			printf("\n");
-			break;
-		}
+	if (fclose(script))
+		log_sys_error("fclose", script_file);
 
-		/* empty line */
-		if (!*input)
-			continue;
-
-		add_history(input);
-
-		argv = args;
-
-		if (lvm_split(input, &argc, argv, MAX_ARGS) == MAX_ARGS) {
-			log_error("Too many arguments, sorry.");
-			continue;
-		}
-
-		if (!strcmp(argv[0], "lvm")) {
-			argv++;
-			argc--;
-		}
-
-		if (!argc)
-			continue;
-
-		if (!strcmp(argv[0], "quit") || !strcmp(argv[0], "exit")) {
-			remove_history(history_length - 1);
-			log_error("Exiting.");
-			break;
-		}
-
-		ret = lvm_run_command(cmd, argc, argv);
-		if (ret == ENO_SUCH_CMD)
-			log_error("No such command '%s'.  Try 'help'.",
-				  argv[0]);
-
-		_write_history();
-	}
-
-	free(input);
-	return 0;
+	return ret;
 }
 
-#endif
-
 /*
  * Determine whether we should fall back and exec the equivalent LVM1 tool
  */
@@ -1402,7 +1179,7 @@
 	}
 #ifdef READLINE_SUPPORT
 	if (!alias && argc == 1) {
-		ret = _shell(cmd);
+		ret = lvm_shell(cmd, &_cmdline);
 		goto out;
 	}
 #endif

Modified: lvm2/upstream/current/tools/lvremove.c
==============================================================================
--- lvm2/upstream/current/tools/lvremove.c	(original)
+++ lvm2/upstream/current/tools/lvremove.c	Sat Apr  7 15:30:42 2007
@@ -75,6 +75,16 @@
 	if (!archive(vg))
 		return ECMD_FAILED;
 
+	/* If the VG is clustered then make sure no-one else is using the LV
+	   we are about to remove */
+	if (vg->status & CLUSTERED) {
+		if (!activate_lv_excl(cmd, lv)) {
+			log_error("Can't get exclusive access to volume \"%s\"",
+				  lv->name);
+			return ECMD_FAILED;
+		}
+	}
+
 	/* FIXME Snapshot commit out of sequence if it fails after here? */
 	if (!deactivate_lv(cmd, lv)) {
 		log_error("Unable to deactivate logical volume \"%s\"",

Modified: lvm2/upstream/current/tools/lvrename.c
==============================================================================
--- lvm2/upstream/current/tools/lvrename.c	(original)
+++ lvm2/upstream/current/tools/lvrename.c	Sat Apr  7 15:30:42 2007
@@ -29,7 +29,7 @@
 	struct lv_list *lvl;
 
 	if (argc == 3) {
-		vg_name = skip_dev_dir(cmd, argv[0]);
+		vg_name = skip_dev_dir(cmd, argv[0], NULL);
 		lv_name_old = argv[1];
 		lv_name_new = argv[2];
 		if (strchr(lv_name_old, '/') &&
@@ -152,6 +152,14 @@
 		goto error;
 	}
 
+	if ((lv->status & MIRRORED) ||
+	    (lv->status & MIRROR_LOG) ||
+	    (lv->status & MIRROR_IMAGE)) {
+		log_error("Mirrored LV, \"%s\" cannot be renamed: %s",
+			  lv->name, strerror(ENOSYS));
+		goto error;
+	}
+
 	if (!archive(lv->vg)) {
 		stack;
 		goto error;

Modified: lvm2/upstream/current/tools/pvchange.c
==============================================================================
--- lvm2/upstream/current/tools/pvchange.c	(original)
+++ lvm2/upstream/current/tools/pvchange.c	Sat Apr  7 15:30:42 2007
@@ -29,7 +29,7 @@
 	const char *pv_name = dev_name(pv->dev);
 	const char *tag = NULL;
 	const char *orig_vg_name;
-	char uuid[64];
+	char uuid[64] __attribute((aligned(8)));
 
 	int consistent = 1;
 	int allocatable = 0;

Modified: lvm2/upstream/current/tools/pvmove.c
==============================================================================
--- lvm2/upstream/current/tools/pvmove.c	(original)
+++ lvm2/upstream/current/tools/pvmove.c	Sat Apr  7 15:30:42 2007
@@ -27,7 +27,7 @@
 	if (!strchr(arg, '/'))
 		return arg;
 
-	lvname = skip_dev_dir(cmd, arg);
+	lvname = skip_dev_dir(cmd, arg, NULL);
 	while (*lvname == '/')
 		lvname++;
 	if (!strchr(lvname, '/')) {

Modified: lvm2/upstream/current/tools/pvremove.c
==============================================================================
--- lvm2/upstream/current/tools/pvremove.c	(original)
+++ lvm2/upstream/current/tools/pvremove.c	Sat Apr  7 15:30:42 2007
@@ -38,8 +38,8 @@
 	if (!(pv = pv_read(cmd, name, NULL, NULL, 1))) {
 		if (arg_count(cmd, force_ARG))
 			return 1;
-		else
-			return 0;
+		log_error("Physical Volume %s not found", name);
+		return 0;
 	}
 
 	/* orphan ? */
@@ -92,9 +92,9 @@
 	}
 
 	if (!dev_test_excl(dev)) {
-		log_error("Can't open %s exclusively.  Mounted filesystem?",
-			  dev_name(dev));
-		return 0;
+		log_error("Can't open %s exclusively - not removing. "
+			  "Mounted filesystem?", dev_name(dev));
+		goto error;
 	}
 
 	/* Wipe existing label(s) */

Modified: lvm2/upstream/current/tools/pvscan.c
==============================================================================
--- lvm2/upstream/current/tools/pvscan.c	(original)
+++ lvm2/upstream/current/tools/pvscan.c	Sat Apr  7 15:30:42 2007
@@ -22,7 +22,7 @@
 				   struct physical_volume *pv,
 				   void *handle __attribute((unused)))
 {
-	char uuid[64];
+	char uuid[64] __attribute((aligned(8)));
 	unsigned vg_name_len = 0;
 
 	char pv_tmp_name[NAME_LEN] = { 0, };

Modified: lvm2/upstream/current/tools/reporter.c
==============================================================================
--- lvm2/upstream/current/tools/reporter.c	(original)
+++ lvm2/upstream/current/tools/reporter.c	Sat Apr  7 15:30:42 2007
@@ -138,6 +138,30 @@
 	return ret;
 }
 
+static int _pvs_in_vg(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;
+	}                     
+
+	return process_each_pv_in_vg(cmd, vg, NULL, handle, &_pvs_single);
+}
+
+static int _pvsegs_in_vg(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;
+	}                     
+
+	return process_each_pv_in_vg(cmd, vg, NULL, handle, &_pvsegs_single);
+}
+
 static int _report(struct cmd_context *cmd, int argc, char **argv,
 		   report_type_t report_type)
 {
@@ -146,8 +170,8 @@
 	char *str;
 	const char *keys = NULL, *options = NULL, *separator;
 	int r = ECMD_PROCESSED;
-
 	int aligned, buffered, headings;
+	unsigned args_are_pvs;
 
 	aligned = find_config_tree_int(cmd, "report/aligned",
 				  DEFAULT_REP_ALIGNED);
@@ -158,6 +182,8 @@
 	separator = find_config_tree_str(cmd, "report/separator",
 				    DEFAULT_REP_SEPARATOR);
 
+	args_are_pvs = (report_type == PVS || report_type == PVSEGS) ? 1 : 0;
+
 	switch (report_type) {
 	case LVS:
 		keys = find_config_tree_str(cmd, "report/lvs_sort",
@@ -260,7 +286,28 @@
 	if (!(report_handle = report_init(cmd, options, keys, &report_type,
 					  separator, aligned, buffered,
 					  headings)))
+		return_0;
+
+	/* Ensure options selected are compatible */
+	if (report_type & SEGS)
+		report_type |= LVS;
+	if (report_type & PVSEGS)
+		report_type |= PVS;
+	if ((report_type & LVS) && (report_type & PVS)) {
+		log_error("Can't report LV and PV fields at the same time");
+		dm_report_free(report_handle);
 		return 0;
+	}
+
+	/* Change report type if fields specified makes this necessary */
+	if (report_type & SEGS)
+		report_type = SEGS;
+	else if (report_type & LVS)
+		report_type = LVS;
+	else if (report_type & PVSEGS)
+		report_type = PVSEGS;
+	else if (report_type & PVS)
+		report_type = PVS;
 
 	switch (report_type) {
 	case LVS:
@@ -272,22 +319,30 @@
 				    report_handle, &_vgs_single);
 		break;
 	case PVS:
-		r = process_each_pv(cmd, argc, argv, NULL, report_handle,
-				    &_pvs_single);
+		if (args_are_pvs)
+			r = process_each_pv(cmd, argc, argv, NULL,
+					    report_handle, &_pvs_single);
+		else
+			r = process_each_vg(cmd, argc, argv, LCK_VG_READ, 0,
+					    report_handle, &_pvs_in_vg);
 		break;
 	case SEGS:
 		r = process_each_lv(cmd, argc, argv, LCK_VG_READ, report_handle,
 				    &_lvsegs_single);
 		break;
 	case PVSEGS:
-		r = process_each_pv(cmd, argc, argv, NULL, report_handle,
-				    &_pvsegs_single);
+		if (args_are_pvs)
+			r = process_each_pv(cmd, argc, argv, NULL,
+					    report_handle, &_pvsegs_single);
+		else
+			r = process_each_vg(cmd, argc, argv, LCK_VG_READ, 0,
+					    report_handle, &_pvsegs_in_vg);
 		break;
 	}
 
-	report_output(report_handle);
+	dm_report_output(report_handle);
 
-	report_free(report_handle);
+	dm_report_free(report_handle);
 	return r;
 }
 

Modified: lvm2/upstream/current/tools/toollib.c
==============================================================================
--- lvm2/upstream/current/tools/toollib.c	(original)
+++ lvm2/upstream/current/tools/toollib.c	Sat Apr  7 15:30:42 2007
@@ -88,21 +88,53 @@
 /*
  * Strip dev_dir if present
  */
-char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name)
+char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name,
+		   unsigned *dev_dir_found)
 {
-	/* FIXME Do this properly */
+	const char *dmdir = dm_dir();
+	size_t dmdir_len = strlen(dmdir), vglv_sz;
+	char *vgname, *lvname, *layer, *vglv;
 
+	/* FIXME Do this properly */
 	if (*vg_name == '/') {
 		while (*vg_name == '/')
 			vg_name++;
 		vg_name--;
 	}
 
+	/* Reformat string if /dev/mapper found */
+	if (!strncmp(vg_name, dmdir, dmdir_len) && vg_name[dmdir_len] == '/') {
+		if (dev_dir_found)
+			*dev_dir_found = 1;
+		vg_name += dmdir_len;
+		while (*vg_name == '/')
+			vg_name++;
+
+		if (!dm_split_lvm_name(cmd->mem, vg_name, &vgname, &lvname, &layer) ||
+		    *layer) {
+			log_error("skip_dev_dir: Couldn't split up device name %s",
+				  vg_name);
+			return (char *) vg_name;
+		}
+		vglv_sz = strlen(vgname) + strlen(lvname) + 2;
+		if (!(vglv = dm_pool_alloc(cmd->mem, vglv_sz)) ||
+		    dm_snprintf(vglv, vglv_sz, "%s%s%s", vgname,
+				 *lvname ? "/" : "",
+				 lvname) < 0) {
+			log_error("vg/lv string alloc failed");
+			return (char *) vg_name;
+		}
+		return vglv;
+	}
+
 	if (!strncmp(vg_name, cmd->dev_dir, strlen(cmd->dev_dir))) {
+		if (dev_dir_found)
+			*dev_dir_found = 1;
 		vg_name += strlen(cmd->dev_dir);
 		while (*vg_name == '/')
 			vg_name++;
-	}
+	} else if (dev_dir_found)
+		*dev_dir_found = 0;
 
 	return (char *) vg_name;
 }
@@ -222,7 +254,7 @@
 		for (; opt < argc; opt++) {
 			const char *lv_name = argv[opt];
 			char *vgname_def;
-			int dev_dir_found = 0;
+			unsigned dev_dir_found = 0;
 
 			/* Do we have a tag or vgname or lvname? */
 			vgname = lv_name;
@@ -243,18 +275,8 @@
 			}
 
 			/* FIXME Jumbled parsing */
-			if (*vgname == '/') {
-				while (*vgname == '/')
-					vgname++;
-				vgname--;
-			}
-			if (!strncmp(vgname, cmd->dev_dir,
-				     strlen(cmd->dev_dir))) {
-				vgname += strlen(cmd->dev_dir);
-				dev_dir_found = 1;
-				while (*vgname == '/')
-					vgname++;
-			}
+			vgname = skip_dev_dir(cmd, vgname, &dev_dir_found);
+
 			if (*vgname == '/') {
 				log_error("\"%s\": Invalid path for Logical "
 					  "Volume", argv[opt]);
@@ -528,7 +550,7 @@
 				continue;
 			}
 
-			vg_name = skip_dev_dir(cmd, vg_name);
+			vg_name = skip_dev_dir(cmd, vg_name, NULL);
 			if (strchr(vg_name, '/')) {
 				log_error("Invalid volume group name: %s",
 					  vg_name);
@@ -830,7 +852,7 @@
 	if (!vg_path)
 		return 0;
 
-	vg_path = skip_dev_dir(cmd, vg_path);
+	vg_path = skip_dev_dir(cmd, vg_path, NULL);
 
 	if (strchr(vg_path, '/')) {
 		log_error("Environment Volume Group in LVM_VG_NAME invalid: "
@@ -844,23 +866,24 @@
 /*
  * Process physical extent range specifiers
  */
-static int _add_pe_range(struct dm_pool *mem, struct list *pe_ranges,
-			 uint32_t start, uint32_t count)
+static int _add_pe_range(struct dm_pool *mem, const char *pvname,
+			 struct list *pe_ranges, uint32_t start, uint32_t count)
 {
 	struct pe_range *per;
 
-	log_debug("Adding PE range: start PE %" PRIu32 " length %" PRIu32,
-		  start, count);
+	log_debug("Adding PE range: start PE %" PRIu32 " length %" PRIu32
+		  " on %s", start, count, pvname);
 
 	/* Ensure no overlap with existing areas */
 	list_iterate_items(per, pe_ranges) {
 		if (((start < per->start) && (start + count - 1 >= per->start))
 		    || ((start >= per->start) &&
 			(per->start + per->count - 1) >= start)) {
-			log_error("Overlapping PE ranges detected (%" PRIu32
-				  "-%" PRIu32 ", %" PRIu32 "-%" PRIu32 ")",
+			log_error("Overlapping PE ranges specified (%" PRIu32
+				  "-%" PRIu32 ", %" PRIu32 "-%" PRIu32 ")"
+				  " on %s",
 				  start, start + count - 1, per->start,
-				  per->start + per->count - 1);
+				  per->start + per->count - 1, pvname);
 			return 0;
 		}
 	}
@@ -878,14 +901,14 @@
 }
 
 static int _parse_pes(struct dm_pool *mem, char *c, struct list *pe_ranges,
-		      uint32_t size)
+		      const char *pvname, uint32_t size)
 {
 	char *endptr;
 	uint32_t start, end;
 
 	/* Default to whole PV */
 	if (!c) {
-		if (!_add_pe_range(mem, pe_ranges, UINT32_C(0), size)) {
+		if (!_add_pe_range(mem, pvname, pe_ranges, UINT32_C(0), size)) {
 			stack;
 			return 0;
 		}
@@ -935,7 +958,7 @@
 			return 0;
 		}
 
-		if (!_add_pe_range(mem, pe_ranges, start, end - start + 1)) {
+		if (!_add_pe_range(mem, pvname, pe_ranges, start, end - start + 1)) {
 			stack;
 			return 0;
 		}
@@ -949,46 +972,56 @@
 	return 0;
 }
 
-static void _create_pv_entry(struct dm_pool *mem, struct pv_list *pvl,
+static int _create_pv_entry(struct dm_pool *mem, struct pv_list *pvl,
 			     char *colon, int allocatable_only, struct list *r)
 {
 	const char *pvname;
-	struct pv_list *new_pvl;
+	struct pv_list *new_pvl = NULL, *pvl2;
 	struct list *pe_ranges;
 
 	pvname = dev_name(pvl->pv->dev);
 	if (allocatable_only && !(pvl->pv->status & ALLOCATABLE_PV)) {
 		log_error("Physical volume %s not allocatable", pvname);
-		return;
+		return 1;
 	}
 
 	if (allocatable_only &&
 	    (pvl->pv->pe_count == pvl->pv->pe_alloc_count)) {
 		log_err("No free extents on physical volume \"%s\"", pvname);
-		return;
+		return 1;
 	}
 
-	if (!(new_pvl = dm_pool_alloc(mem, sizeof(*new_pvl)))) {
-		log_err("Unable to allocate physical volume list.");
-		return;
-	}
+	list_iterate_items(pvl2, r)
+		if (pvl->pv->dev == pvl2->pv->dev) {
+			new_pvl = pvl2;
+			break;
+		}
+	
+	if (!new_pvl) {
+		if (!(new_pvl = dm_pool_alloc(mem, sizeof(*new_pvl)))) {
+			log_err("Unable to allocate physical volume list.");
+			return 0;
+		}
 
-	memcpy(new_pvl, pvl, sizeof(*new_pvl));
+		memcpy(new_pvl, pvl, sizeof(*new_pvl));
 
-	if (!(pe_ranges = dm_pool_alloc(mem, sizeof(*pe_ranges)))) {
-		log_error("Allocation of pe_ranges list failed");
-		return;
+		if (!(pe_ranges = dm_pool_alloc(mem, sizeof(*pe_ranges)))) {
+			log_error("Allocation of pe_ranges list failed");
+			return 0;
+		}
+		list_init(pe_ranges);
+		new_pvl->pe_ranges = pe_ranges;
+		list_add(r, &new_pvl->list);
 	}
-	list_init(pe_ranges);
 
 	/* Determine selected physical extents */
-	if (!_parse_pes(mem, colon, pe_ranges, pvl->pv->pe_count)) {
+	if (!_parse_pes(mem, colon, new_pvl->pe_ranges, dev_name(pvl->pv->dev),
+			pvl->pv->pe_count)) {
 		stack;
-		return;
+		return 0;
 	}
-	new_pvl->pe_ranges = pe_ranges;
 
-	list_add(r, &new_pvl->list);
+	return 1;
 }
 
 struct list *create_pv_list(struct dm_pool *mem, struct volume_group *vg, int argc,
@@ -1021,8 +1054,12 @@
 			list_iterate_items(pvl, &vg->pvs) {
 				if (str_list_match_item(&pvl->pv->tags,
 							tagname)) {
-					_create_pv_entry(mem, pvl, NULL,
-							 allocatable_only, r);
+					if (!_create_pv_entry(mem, pvl, NULL,
+							      allocatable_only,
+							      r)) {
+						stack;
+						return NULL;
+					}
 				}
 			}
 			continue;
@@ -1044,7 +1081,10 @@
 				"Volume Group \"%s\"", pvname, vg->name);
 			return NULL;
 		}
-		_create_pv_entry(mem, pvl, colon, allocatable_only, r);
+		if (!_create_pv_entry(mem, pvl, colon, allocatable_only, r)) {
+			stack;
+			return NULL;
+		}
 	}
 
 	if (list_empty(r))
@@ -1170,7 +1210,8 @@
 /*
  * Initialize the LV with 'value'.
  */
-int set_lv(struct cmd_context *cmd, struct logical_volume *lv, int value)
+int set_lv(struct cmd_context *cmd, struct logical_volume *lv,
+	   uint64_t sectors, int value)
 {
 	struct device *dev;
 	char *name;
@@ -1203,7 +1244,10 @@
 	if (!dev_open_quiet(dev))
 		return 0;
 
-	dev_set(dev, UINT64_C(0), (size_t) 4096, value);
+	dev_set(dev, UINT64_C(0),
+		sectors ? (size_t) sectors << SECTOR_SHIFT : (size_t) 4096,
+		value);
+	dev_flush(dev);
 	dev_close_immediate(dev);
 
 	return 1;
@@ -1317,7 +1361,8 @@
 		goto error;
 	}
 
-	if (activation() && !set_lv(cmd, log_lv, in_sync)) {
+	if (activation() && !set_lv(cmd, log_lv, log_lv->size,
+				    in_sync ? -1 : 0)) {
 		log_error("Aborting. Failed to wipe mirror log. "
 			  "Remove new LV and retry.");
 		goto error;

Modified: lvm2/upstream/current/tools/toollib.h
==============================================================================
--- lvm2/upstream/current/tools/toollib.h	(original)
+++ lvm2/upstream/current/tools/toollib.h	Sat Apr  7 15:30:42 2007
@@ -76,7 +76,8 @@
 
 char *default_vgname(struct cmd_context *cmd);
 const char *extract_vgname(struct cmd_context *cmd, const char *lv_name);
-char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name);
+char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name,
+		   unsigned *dev_dir_found);
 
 /*
  * Builds a list of pv's from the names in argv.  Used in
@@ -101,6 +102,7 @@
 					 const char *lv_name,
 					 int in_sync);
 
-int set_lv(struct cmd_context *cmd, struct logical_volume *lv, int value);
+int set_lv(struct cmd_context *cmd, struct logical_volume *lv,
+	   uint64_t sectors, int value);
 
 #endif

Modified: lvm2/upstream/current/tools/vgcfgrestore.c
==============================================================================
--- lvm2/upstream/current/tools/vgcfgrestore.c	(original)
+++ lvm2/upstream/current/tools/vgcfgrestore.c	Sat Apr  7 15:30:42 2007
@@ -24,7 +24,7 @@
 		return ECMD_FAILED;
 	}
 
-	vg_name = skip_dev_dir(cmd, argv[0]);
+	vg_name = skip_dev_dir(cmd, argv[0], NULL);
 
 	if (!validate_name(vg_name)) {
 		log_error("Volume group name \"%s\" is invalid", vg_name);

Modified: lvm2/upstream/current/tools/vgchange.c
==============================================================================
--- lvm2/upstream/current/tools/vgchange.c	(original)
+++ lvm2/upstream/current/tools/vgchange.c	Sat Apr  7 15:30:42 2007
@@ -15,7 +15,7 @@
 
 #include "tools.h"
 
-static int _register_lvs_in_vg(struct cmd_context *cmd,
+static int _monitor_lvs_in_vg(struct cmd_context *cmd,
 			       struct volume_group *vg, int reg)
 {
 	struct lv_list *lvl;
@@ -23,7 +23,6 @@
 	struct lvinfo info;
 	int lv_active;
 	int count = 0;
-	int r;
 
 	list_iterate_items(lvl, &vg->lvs) {
 		lv = lvl->lv;
@@ -39,22 +38,14 @@
 		if ((lv->status & PVMOVE) || !lv_active)
 			continue;
 
-		r = register_dev_for_events(cmd, lv, reg);
-
-		if (r < 0) {
-			log_error("Failed to %s logical volume, %s",
-				  (reg) ? "register" : "unregister",
-				  lv->name);
+		if (!monitor_dev_for_events(cmd, lv, reg)) {
 			continue;
-		}
-
-		if (r)
+		} else
 			count++;
 	}
 
 	/*
-	 * returns the number of monitored devices, not the number
-	 * of _new_ monitored devices
+	 * returns the number of _new_ monitored devices
 	 */
 
 	return count;
@@ -114,11 +105,12 @@
 {
 	int active, monitored;
 
-	if ((active = lvs_in_vg_activated(vg))) {
-		monitored = _register_lvs_in_vg(cmd, vg, dmeventd_register_mode());
+	if ((active = lvs_in_vg_activated(vg)) &&
+	    dmeventd_monitor_mode() != DMEVENTD_MONITOR_IGNORE) {
+		monitored = _monitor_lvs_in_vg(cmd, vg, dmeventd_monitor_mode());
 		log_print("%d logical volume(s) in volume group "
-			    "\"%s\" now %smonitored",
-			    monitored, vg->name, (dmeventd_register_mode()) ? "" : "un");
+			    "\"%s\" %smonitored",
+			    monitored, vg->name, (dmeventd_monitor_mode()) ? "" : "un");
 	}
 
 	return ECMD_PROCESSED;
@@ -155,11 +147,13 @@
 	if (activate && (active = lvs_in_vg_activated(vg))) {
 		log_verbose("%d logical volume(s) in volume group \"%s\" "
 			    "already active", active, vg->name);
-		monitored = _register_lvs_in_vg(cmd, vg, dmeventd_register_mode());
-		log_verbose("%d existing logical volume(s) in volume "
-			    "group \"%s\" now %smonitored",
-			    monitored, vg->name,
-			    dmeventd_register_mode() ? "" : "un");
+		if (dmeventd_monitor_mode() != DMEVENTD_MONITOR_IGNORE) {
+			monitored = _monitor_lvs_in_vg(cmd, vg, dmeventd_monitor_mode());
+			log_verbose("%d existing logical volume(s) in volume "
+				    "group \"%s\" %smonitored",
+				    monitored, vg->name,
+				    dmeventd_monitor_mode() ? "" : "un");
+		}
 	}
 
 	if (activate && _activate_lvs_in_vg(cmd, vg, available))
@@ -541,7 +535,9 @@
 		return ECMD_FAILED;
 	}
 
-	init_dmeventd_register(arg_int_value(cmd, monitor_ARG, DEFAULT_DMEVENTD_MONITOR));
+	init_dmeventd_monitor(arg_int_value(cmd, monitor_ARG,
+					    cmd->is_static ?
+					    DMEVENTD_MONITOR_IGNORE : DEFAULT_DMEVENTD_MONITOR));
 
 	if (arg_count(cmd, available_ARG))
 		r = _vgchange_available(cmd, vg);

Modified: lvm2/upstream/current/tools/vgcreate.c
==============================================================================
--- lvm2/upstream/current/tools/vgcreate.c	(original)
+++ lvm2/upstream/current/tools/vgcreate.c	Sat Apr  7 15:30:42 2007
@@ -38,7 +38,7 @@
 		return EINVALID_CMD_LINE;
 	}
 
-	vg_name = skip_dev_dir(cmd, argv[0]);
+	vg_name = skip_dev_dir(cmd, argv[0], NULL);
 	max_lv = arg_uint_value(cmd, maxlogicalvolumes_ARG, 0);
 	max_pv = arg_uint_value(cmd, maxphysicalvolumes_ARG, 0);
 	alloc = arg_uint_value(cmd, alloc_ARG, ALLOC_NORMAL);

Modified: lvm2/upstream/current/tools/vgextend.c
==============================================================================
--- lvm2/upstream/current/tools/vgextend.c	(original)
+++ lvm2/upstream/current/tools/vgextend.c	Sat Apr  7 15:30:42 2007
@@ -32,7 +32,7 @@
 		return EINVALID_CMD_LINE;
 	}
 
-	vg_name = skip_dev_dir(cmd, argv[0]);
+	vg_name = skip_dev_dir(cmd, argv[0], NULL);
 	argc--;
 	argv++;
 
@@ -41,6 +41,12 @@
 		return ECMD_FAILED;
 	}
 
+	if (!validate_name(vg_name)) {
+		log_error("Volume group name \"%s\" is invalid",
+			  vg_name);
+		return ECMD_FAILED;
+	}
+
 	log_verbose("Checking for volume group \"%s\"", vg_name);
 	if (!lock_vol(cmd, vg_name, LCK_VG_WRITE | LCK_NONBLOCK)) {
 		unlock_vg(cmd, ORPHAN);

Modified: lvm2/upstream/current/tools/vgmerge.c
==============================================================================
--- lvm2/upstream/current/tools/vgmerge.c	(original)
+++ lvm2/upstream/current/tools/vgmerge.c	Sat Apr  7 15:30:42 2007
@@ -176,7 +176,7 @@
 	/* Fix up LVIDs */
 	list_iterate_items(lvl1, &vg_to->lvs) {
 		union lvid *lvid1 = &lvl1->lv->lvid;
-		char uuid[64];
+		char uuid[64] __attribute((aligned(8)));
 
 		list_iterate_items(lvl2, &vg_from->lvs) {
 			union lvid *lvid2 = &lvl2->lv->lvid;
@@ -253,12 +253,12 @@
 		return EINVALID_CMD_LINE;
 	}
 
-	vg_name_to = skip_dev_dir(cmd, argv[0]);
+	vg_name_to = skip_dev_dir(cmd, argv[0], NULL);
 	argc--;
 	argv++;
 
 	for (; opt < argc; opt++) {
-		vg_name_from = skip_dev_dir(cmd, argv[opt]);
+		vg_name_from = skip_dev_dir(cmd, argv[opt], NULL);
 
 		ret = _vgmerge_single(cmd, vg_name_to, vg_name_from);
 		if (ret > ret_max)

Modified: lvm2/upstream/current/tools/vgreduce.c
==============================================================================
--- lvm2/upstream/current/tools/vgreduce.c	(original)
+++ lvm2/upstream/current/tools/vgreduce.c	Sat Apr  7 15:30:42 2007
@@ -18,7 +18,7 @@
 
 static int _remove_pv(struct volume_group *vg, struct pv_list *pvl)
 {
-	char uuid[64];
+	char uuid[64] __attribute((aligned(8)));
 
 	if (vg->pv_count == 1) {
 		log_error("Volume Groups must always contain at least one PV");
@@ -347,7 +347,9 @@
 		list_iterate_items(lvl, &lvs_changed) {
 			log_verbose("Removing LV %s from VG %s", lvl->lv->name,
 				    lvl->lv->vg->name);
-			if (!lv_remove(lvl->lv)) {
+				/* Skip LVs already removed by mirror code */
+				if (find_lv_in_vg(vg, lvl->lv->name) &&
+				    !lv_remove(lvl->lv)) {
 				stack;
 				return 0;
 			}
@@ -425,13 +427,13 @@
 	int ret = 1;
 	int consistent = 1;
 
-	if (!argc & !arg_count(cmd, removemissing_ARG)) {
+	if (!argc && !arg_count(cmd, removemissing_ARG)) {
 		log_error("Please give volume group name and "
 			  "physical volume paths");
 		return EINVALID_CMD_LINE;
 	}
 
-	if (!argc & arg_count(cmd, removemissing_ARG)) {
+	if (!argc && arg_count(cmd, removemissing_ARG)) {
 		log_error("Please give volume group name");
 		return EINVALID_CMD_LINE;
 	}
@@ -459,10 +461,16 @@
 		return EINVALID_CMD_LINE;
 	}
 
-	vg_name = skip_dev_dir(cmd, argv[0]);
+	vg_name = skip_dev_dir(cmd, argv[0], NULL);
 	argv++;
 	argc--;
 
+	if (!validate_name(vg_name)) {
+		log_error("Volume group name \"%s\" is invalid",
+			  vg_name);
+		return ECMD_FAILED;
+	}
+
 	log_verbose("Finding volume group \"%s\"", vg_name);
 	if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) {
 		log_error("Can't get lock for %s", vg_name);

Modified: lvm2/upstream/current/tools/vgremove.c
==============================================================================
--- lvm2/upstream/current/tools/vgremove.c	(original)
+++ lvm2/upstream/current/tools/vgremove.c	Sat Apr  7 15:30:42 2007
@@ -87,6 +87,11 @@
 {
 	int ret;
 
+	if (!argc) {
+		log_error("Please enter one or more volume group paths");
+		return EINVALID_CMD_LINE;
+	}
+
 	if (!lock_vol(cmd, ORPHAN, LCK_VG_WRITE)) {
 		log_error("Can't get lock for orphan PVs");
 		return ECMD_FAILED;

Modified: lvm2/upstream/current/tools/vgrename.c
==============================================================================
--- lvm2/upstream/current/tools/vgrename.c	(original)
+++ lvm2/upstream/current/tools/vgrename.c	Sat Apr  7 15:30:42 2007
@@ -35,8 +35,8 @@
 		return EINVALID_CMD_LINE;
 	}
 
-	vg_name_old = skip_dev_dir(cmd, argv[0]);
-	vg_name_new = skip_dev_dir(cmd, argv[1]);
+	vg_name_old = skip_dev_dir(cmd, argv[0], NULL);
+	vg_name_new = skip_dev_dir(cmd, argv[1], NULL);
 
 	dev_dir = cmd->dev_dir;
 	length = strlen(dev_dir);
@@ -118,7 +118,7 @@
 		return ECMD_FAILED;
 	}
 
-	if (lvs_in_vg_activated(vg_old)) {
+	if (lvs_in_vg_activated_by_uuid_only(vg_old)) {
 		unlock_vg(cmd, vg_name_old);
 		log_error("Volume group \"%s\" still has active LVs",
 			  vg_name_old);

Modified: lvm2/upstream/current/tools/vgsplit.c
==============================================================================
--- lvm2/upstream/current/tools/vgsplit.c	(original)
+++ lvm2/upstream/current/tools/vgsplit.c	Sat Apr  7 15:30:42 2007
@@ -72,6 +72,9 @@
 		if ((lv->status & SNAPSHOT))
 			continue;
 
+		if ((lv->status & MIRRORED))
+			continue;
+
 		/* Ensure all the PVs used by this LV remain in the same */
 		/* VG as each other */
 		vg_with = NULL;
@@ -84,9 +87,9 @@
 				pv = seg_pv(seg, s);
 				if (vg_with) {
 					if (!pv_is_in_vg(vg_with, pv)) {
-						log_error("Logical Volume %s "
-							  "split between "
-							  "Volume Groups",
+						log_error("Can't split Logical "
+							  "Volume %s between "
+							  "two Volume Groups",
 							  lv->name);
 						return 0;
 					}
@@ -161,6 +164,48 @@
 	return 1;
 }
 
+static int _move_mirrors(struct volume_group *vg_from,
+			 struct volume_group *vg_to)
+{
+	struct list *lvh, *lvht;
+	struct logical_volume *lv;
+	struct lv_segment *seg;
+	int i, seg_in, log_in;
+
+	list_iterate_safe(lvh, lvht, &vg_from->lvs) {
+		lv = list_item(lvh, struct lv_list)->lv;
+
+		if (!(lv->status & MIRRORED))
+			continue;
+
+		seg = first_seg(lv); 
+
+		seg_in = 0;
+		for (i = 0; i < seg->area_count; i++)
+			if (_lv_is_in_vg(vg_to, seg_lv(seg, i)))
+			    seg_in++;
+
+		log_in = (!seg->log_lv || _lv_is_in_vg(vg_to, seg->log_lv));
+		
+		if ((seg_in && seg_in < seg->area_count) || 
+		    (seg_in && seg->log_lv && !log_in) || 
+		    (!seg_in && seg->log_lv && log_in)) {
+			log_error("Mirror %s split", lv->name);
+			return 0;
+		}
+
+		if (seg_in == seg->area_count && log_in) {
+			list_del(lvh);
+			list_add(&vg_to->lvs, lvh);
+
+			vg_from->lv_count--;
+			vg_to->lv_count++;
+		}
+	}
+
+	return 1;
+}
+
 int vgsplit(struct cmd_context *cmd, int argc, char **argv)
 {
 	char *vg_name_from, *vg_name_to;
@@ -174,11 +219,17 @@
 		return EINVALID_CMD_LINE;
 	}
 
-	vg_name_from = argv[0];
-	vg_name_to = argv[1];
+	vg_name_from = skip_dev_dir(cmd, argv[0], NULL);
+	vg_name_to = skip_dev_dir(cmd, argv[1], NULL);
 	argc -= 2;
 	argv += 2;
 
+	if (!validate_name(vg_name_from)) {
+		log_error("Volume group name \"%s\" is invalid",
+			  vg_name_from);
+		return ECMD_FAILED;
+	}
+
 	if (!strcmp(vg_name_to, vg_name_from)) {
 		log_error("Duplicate volume group name \"%s\"", vg_name_from);
 		return ECMD_FAILED;
@@ -275,6 +326,10 @@
 	if (!(_move_snapshots(vg_from, vg_to)))
 		goto error;
 
+	/* Move required mirrors across */
+	if (!(_move_mirrors(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 



More information about the pkg-lvm-commits mailing list