r385 - in lvm2/upstream/current: . daemons/clvmd dmeventd/mirror doc include lib lib/activate lib/cache lib/commands lib/config lib/device lib/display lib/error lib/filters lib/format1 lib/format_text lib/locking lib/log lib/metadata lib/mirror lib/misc lib/mm lib/report lib/snapshot lib/zero man scripts tools

Bastian Blank waldi at costa.debian.org
Mon Oct 23 08:49:11 UTC 2006


Author: waldi
Date: Mon Oct 23 08:49:10 2006
New Revision: 385

Added:
   lvm2/upstream/current/daemons/clvmd/refresh_clvmd.c
   lvm2/upstream/current/daemons/clvmd/refresh_clvmd.h
   lvm2/upstream/current/lib/misc/lvm-wrappers.c
   lvm2/upstream/current/lib/misc/lvm-wrappers.h
   lvm2/upstream/current/lib/misc/timestamp.c
   lvm2/upstream/current/lib/misc/timestamp.h
   lvm2/upstream/current/man/lvconvert.8
   lvm2/upstream/current/scripts/lvm_dump.sh   (contents, props changed)
   lvm2/upstream/current/tools/lvm2cmd-static.c
   lvm2/upstream/current/tools/lvm2cmd.c
   lvm2/upstream/current/tools/lvmcmdlib.c
Modified:
   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/clvm.h
   lvm2/upstream/current/daemons/clvmd/clvmd-cman.c
   lvm2/upstream/current/daemons/clvmd/clvmd-command.c
   lvm2/upstream/current/daemons/clvmd/clvmd-comms.h
   lvm2/upstream/current/daemons/clvmd/clvmd-gulm.c
   lvm2/upstream/current/daemons/clvmd/clvmd.c
   lvm2/upstream/current/daemons/clvmd/lvm-functions.c
   lvm2/upstream/current/daemons/clvmd/lvm-functions.h
   lvm2/upstream/current/dmeventd/mirror/dmeventd_mirror.c
   lvm2/upstream/current/doc/example.conf
   lvm2/upstream/current/include/.symlinks
   lvm2/upstream/current/lib/Makefile.in
   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/activate/dev_manager.h
   lvm2/upstream/current/lib/activate/fs.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/defaults.h
   lvm2/upstream/current/lib/device/dev-cache.c
   lvm2/upstream/current/lib/device/dev-io.c
   lvm2/upstream/current/lib/display/display.c
   lvm2/upstream/current/lib/error/errseg.c
   lvm2/upstream/current/lib/filters/filter-md.c
   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/layout.c
   lvm2/upstream/current/lib/format_text/archive.c
   lvm2/upstream/current/lib/format_text/archiver.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_vsn1.c
   lvm2/upstream/current/lib/format_text/layout.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/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/segtype.h
   lvm2/upstream/current/lib/mirror/mirrored.c
   lvm2/upstream/current/lib/misc/configure.h.in
   lvm2/upstream/current/lib/misc/lib.h
   lvm2/upstream/current/lib/misc/lvm-file.c
   lvm2/upstream/current/lib/misc/lvm-string.c
   lvm2/upstream/current/lib/misc/lvm-string.h
   lvm2/upstream/current/lib/misc/sharedlib.c
   lvm2/upstream/current/lib/mm/memlock.c
   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/zero/zero.c
   lvm2/upstream/current/man/Makefile.in
   lvm2/upstream/current/man/clvmd.8
   lvm2/upstream/current/man/lvchange.8
   lvm2/upstream/current/man/lvcreate.8
   lvm2/upstream/current/man/lvextend.8
   lvm2/upstream/current/man/lvm.8
   lvm2/upstream/current/man/lvm.conf.5
   lvm2/upstream/current/man/lvreduce.8
   lvm2/upstream/current/man/lvresize.8
   lvm2/upstream/current/man/vgchange.8
   lvm2/upstream/current/man/vgscan.8
   lvm2/upstream/current/scripts/clvmd_init_rhel4
   lvm2/upstream/current/scripts/lvmconf.sh
   lvm2/upstream/current/tools/Makefile.in
   lvm2/upstream/current/tools/args.h
   lvm2/upstream/current/tools/commands.h
   lvm2/upstream/current/tools/lvchange.c
   lvm2/upstream/current/tools/lvconvert.c
   lvm2/upstream/current/tools/lvcreate.c
   lvm2/upstream/current/tools/lvm2cmdline.h
   lvm2/upstream/current/tools/lvmcmdline.c
   lvm2/upstream/current/tools/lvrename.c
   lvm2/upstream/current/tools/lvresize.c
   lvm2/upstream/current/tools/pvchange.c
   lvm2/upstream/current/tools/pvdisplay.c
   lvm2/upstream/current/tools/pvmove.c
   lvm2/upstream/current/tools/pvresize.c
   lvm2/upstream/current/tools/reporter.c
   lvm2/upstream/current/tools/toollib.c
   lvm2/upstream/current/tools/toollib.h
   lvm2/upstream/current/tools/tools.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/vgrename.c
   lvm2/upstream/current/tools/vgsplit.c

Log:
Load LVM2.2.02.12 into /lvm2/upstream/current.


Modified: lvm2/upstream/current/VERSION
==============================================================================
--- lvm2/upstream/current/VERSION	(original)
+++ lvm2/upstream/current/VERSION	Mon Oct 23 08:49:10 2006
@@ -1 +1 @@
-2.02.07 (2006-07-17)
+2.02.12 (2006-10-16)

Modified: lvm2/upstream/current/WHATS_NEW
==============================================================================
--- lvm2/upstream/current/WHATS_NEW	(original)
+++ lvm2/upstream/current/WHATS_NEW	Mon Oct 23 08:49:10 2006
@@ -1,3 +1,81 @@
+Version 2.02.12 - 16th October 2006
+===================================
+  Fix pvdisplay to use vg_read() for non-orphans.
+  Fall back to internal locking if external locking lib is missing or fails.
+  Retain activation state after changing LV minor number with --force.
+  Propagate clustered flag in vgsplit and require resizeable flag.
+
+Version 2.02.11 - 12th October 2006
+===================================
+  Add clvmd function to return the cluster name. not used by LVM yet.
+  Add cling allocation policy.
+  Change _check_contiguous() to use _for_each_pv().
+  Extend _for_each_pv() to allow termination without error.
+  Abstract _is_contiguous().
+  Remove duplicated pv arg from _check_contiguous().
+  Accept regionsize with lvconvert.
+  Add report columns with underscore before field names ending 'size'.
+  Correct regionsize default on lvcreate man page (MB).
+  Fix clvmd bug that could cause it to die when a node with a long name crashed.
+  Add device size to text metadata.
+  Fix format_text mda_setup pv->size and pv_setup pe_count calculations.
+  Fix _for_each_pv() for mirror with core log.
+  Add lvm_dump.sh script to create a tarball of debugging info from a system.
+  Capture error messages in clvmd and pass them back to the user.
+  Remove unused #defines from filter-md.c.
+  Make clvmd restart init script wait until clvmd has died before starting it.
+  Add -R to clvmd which tells running clvmds to reload their device cache.
+  Add LV column to reports listing kernel modules needed for activation.
+  Show available fields if report given invalid field. (e.g. lvs -o list)
+  Add timestamp functions with --disable-realtime configure option.
+  Add %VG, %LV and %FREE suffices to lvcreate/lvresize --extents arg.
+  Fix two potential NULL pointer derefs in error cases in vg_read().
+  Separate --enable-cluster from locking lib options in lvmconf.sh.
+  Add a missing comma in lvcreate man page.
+
+Version 2.02.10 - 19th September 2006
+=====================================
+  Fix lvconvert mirror change case detection logic.
+  Fix mirror log detachment so it correctly becomes a standalone LV.
+  Extend _check_contiguous() to detect single-area LVs.
+  Include mirror log (untested) in _for_each_pv() processing.
+  Use MIRROR_LOG_SIZE constant.
+  Remove struct seg_pvs from _for_each_pv() to generalise.
+  Avoid adding duplicates to list of parallel PVs to avoid.
+  Fix several incorrect comparisons in parallel area avoidance code.
+  Fix segment lengths when flattening existing parallel areas.
+  Log existing parallel areas prior to allocation.
+  Fix mirror log creation when activation disabled.
+  Don't attempt automatic recovery without proper locking.
+  When using local file locking, skip clustered VGs.
+  Add fallback_to_clustered_locking and fallback_to_local_locking parameters.
+  lvm.static uses built-in cluster locking instead of external locking.
+  Don't attempt to load shared libraries if built statically.
+  Change default locking_lib to liblvm2clusterlock.so.
+  Add skip_dev_dir() to process command line VGs.
+  Stop clvmd complaining about nodes that have left the cluster.
+  Move lvm_snprintf(), split_words() and split_dm_name() into libdevmapper.
+  Add lvconvert man page.
+  Add mirror options to man pages.
+  Prevent mirror renames.
+  Move CMDLIB code into separate file and record whether static build.
+
+Version 2.02.09 - 17th August 2006
+==================================
+  Fix PE_ALIGN for pagesize over 32KB.
+  Separate out LVM1_PE_ALIGN and pe_align().
+  Add lvm_getpagesize wrapper.
+  Add --maxphysicalvolumes to vgchange.
+
+Version 2.02.08 - 15th August 2006
+==================================
+  Add checks for duplicate LV name, lvid and PV id before writing metadata.
+  Report all sanity check failures, not just the first.
+  Fix missing lockfs on first snapshot creation.
+  Add unreliable --trustcache option to reporting commands.
+  Fix locking for mimage removal.
+  Fix clvmd_init_rhel4 'status' exit code.
+
 Version 2.02.07 - 17th July 2006
 ================================
   Fix activation logic in lvchange --persistent.

Modified: lvm2/upstream/current/configure
==============================================================================
--- lvm2/upstream/current/configure	(original)
+++ lvm2/upstream/current/configure	Mon Oct 23 08:49:10 2006
@@ -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 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 INTL_PACKAGE INTL CLVMD CLUSTER FSADM DMEVENTD LTLIBOBJS'
 ac_subst_files=''
 
 # Initialize some variables set by options.
@@ -853,6 +853,7 @@
                           statically.  Default is dynamic linking
   --enable-readline       Enable readline support
   --disable-selinux       Disable selinux support
+  --disable-realtime      Disable realtime clock support
   --enable-debug          Enable debugging
   --disable-devmapper     Disable device-mapper interaction
   --disable-o_direct      Disable O_DIRECT
@@ -1459,6 +1460,7 @@
 		DEVMAPPER=yes
 		ODIRECT=yes
 		SELINUX=yes
+		REALTIME=yes
 		CLUSTER=internal
 		FSADM=no ;;
 	darwin*)
@@ -1473,6 +1475,7 @@
 		DEVMAPPER=yes
 		ODIRECT=no
 		SELINUX=no
+		REALTIME=no
 		CLUSTER=none
 		FSADM=no ;;
 esac
@@ -7432,6 +7435,17 @@
 echo "${ECHO_T}$SELINUX" >&6
 
 ################################################################################
+echo "$as_me:$LINENO: checking whether to enable realtime support" >&5
+echo $ECHO_N "checking whether to enable realtime support... $ECHO_C" >&6
+# Check whether --enable-realtime or --disable-realtime was given.
+if test "${enable_realtime+set}" = set; then
+  enableval="$enable_realtime"
+  REALTIME=$enableval
+fi;
+echo "$as_me:$LINENO: result: $REALTIME" >&5
+echo "${ECHO_T}$REALTIME" >&6
+
+################################################################################
 echo "$as_me:$LINENO: checking whether to build cluster LVM daemon" >&5
 echo $ECHO_N "checking whether to build cluster LVM daemon... $ECHO_C" >&6
 
@@ -7534,14 +7548,6 @@
 echo "$as_me:$LINENO: result: $CMDLIB" >&5
 echo "${ECHO_T}$CMDLIB" >&6
 
-if test x$CMDLIB = xyes; then
-
-cat >>confdefs.h <<\_ACEOF
-#define CMDLIB 1
-_ACEOF
-
-fi
-
 ################################################################################
 echo "$as_me:$LINENO: checking whether to build fsadm" >&5
 echo $ECHO_N "checking whether to build fsadm... $ECHO_C" >&6
@@ -8429,6 +8435,96 @@
 fi
 
 ################################################################################
+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
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lrt  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char clock_gettime ();
+int
+main ()
+{
+clock_gettime ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_rt_clock_gettime=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_rt_clock_gettime=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_rt_clock_gettime" >&5
+echo "${ECHO_T}$ac_cv_lib_rt_clock_gettime" >&6
+if test $ac_cv_lib_rt_clock_gettime = yes; then
+  HAVE_REALTIME=yes
+else
+  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
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_REALTIME 1
+_ACEOF
+
+		LIBS="-lrt $LIBS"
+	else
+		{ echo "$as_me:$LINENO: WARNING: Disabling realtime clock" >&5
+echo "$as_me: WARNING: Disabling realtime clock" >&2;}
+	fi
+fi
+
+################################################################################
 
 for ac_header in getopt.h
 do
@@ -11105,6 +11201,7 @@
 
 
 
+
 ################################################################################
                                                                                                                                                                                                                                                 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"
 cat >confcache <<\_ACEOF
@@ -11797,6 +11894,7 @@
 s, at DEVMAPPER@,$DEVMAPPER,;t t
 s, at HAVE_LIBDL@,$HAVE_LIBDL,;t t
 s, at HAVE_SELINUX@,$HAVE_SELINUX,;t t
+s, at HAVE_REALTIME@,$HAVE_REALTIME,;t t
 s, at CMDLIB@,$CMDLIB,;t t
 s, at LOCALEDIR@,$LOCALEDIR,;t t
 s, at CONFDIR@,$CONFDIR,;t t

Modified: lvm2/upstream/current/configure.in
==============================================================================
--- lvm2/upstream/current/configure.in	(original)
+++ lvm2/upstream/current/configure.in	Mon Oct 23 08:49:10 2006
@@ -42,6 +42,7 @@
 		DEVMAPPER=yes
 		ODIRECT=yes
 		SELINUX=yes
+		REALTIME=yes
 		CLUSTER=internal
 		FSADM=no ;;
 	darwin*)
@@ -56,6 +57,7 @@
 		DEVMAPPER=yes
 		ODIRECT=no
 		SELINUX=no
+		REALTIME=no
 		CLUSTER=none
 		FSADM=no ;;
 esac
@@ -283,6 +285,13 @@
 AC_MSG_RESULT($SELINUX)
 
 ################################################################################
+dnl -- Disable realtime clock support
+AC_MSG_CHECKING(whether to enable realtime support)
+AC_ARG_ENABLE(realtime, [  --disable-realtime      Disable realtime clock support],
+REALTIME=$enableval)
+AC_MSG_RESULT($REALTIME)
+
+################################################################################
 dnl -- Build cluster LVM daemon
 AC_MSG_CHECKING(whether to build cluster LVM daemon)
 AC_ARG_WITH(clvmd,
@@ -351,10 +360,6 @@
 CMDLIB=$enableval, CMDLIB=no)
 AC_MSG_RESULT($CMDLIB)
 
-if test x$CMDLIB = xyes; then
-	AC_DEFINE([CMDLIB], 1, [Define to 1 to build the shared command library.])
-fi
-
 ################################################################################
 dnl -- Enable fsadm
 AC_MSG_CHECKING(whether to build fsadm)
@@ -454,6 +459,21 @@
 fi
 
 ################################################################################
+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.])
+		LIBS="-lrt $LIBS"
+	else
+		AC_MSG_WARN(Disabling realtime clock)
+	fi
+fi
+
+################################################################################
 dnl -- Check for getopt
 AC_CHECK_HEADERS(getopt.h, AC_DEFINE([HAVE_GETOPTLONG], 1, [Define to 1 to if getopt_long is available.]))
 
@@ -582,6 +602,7 @@
 AC_SUBST(DEVMAPPER)
 AC_SUBST(HAVE_LIBDL)
 AC_SUBST(HAVE_SELINUX)
+AC_SUBST(HAVE_REALTIME)
 AC_SUBST(CMDLIB)
 AC_SUBST(MSGFMT)
 AC_SUBST(LOCALEDIR)

Modified: lvm2/upstream/current/daemons/clvmd/Makefile.in
==============================================================================
--- lvm2/upstream/current/daemons/clvmd/Makefile.in	(original)
+++ lvm2/upstream/current/daemons/clvmd/Makefile.in	Mon Oct 23 08:49:10 2006
@@ -19,6 +19,7 @@
 	clvmd-command.c  \
 	clvmd.c          \
 	lvm-functions.c  \
+	refresh_clvmd.c \
 	system-lv.c
 
 ifeq ("@CLVMD@", "gulm")

Modified: lvm2/upstream/current/daemons/clvmd/clvm.h
==============================================================================
--- lvm2/upstream/current/daemons/clvmd/clvm.h	(original)
+++ lvm2/upstream/current/daemons/clvmd/clvm.h	Mon Oct 23 08:49:10 2006
@@ -63,4 +63,8 @@
 #define CLVMD_CMD_LOCK_LV           50
 #define CLVMD_CMD_LOCK_VG           51
 
+/* Misc functions */
+#define CLVMD_CMD_REFRESH	    40
+#define CLVMD_CMD_GET_CLUSTERNAME   41
+
 #endif

Modified: lvm2/upstream/current/daemons/clvmd/clvmd-cman.c
==============================================================================
--- lvm2/upstream/current/daemons/clvmd/clvmd-cman.c	(original)
+++ lvm2/upstream/current/daemons/clvmd/clvmd-cman.c	Mon Oct 23 08:49:10 2006
@@ -137,7 +137,7 @@
 
 	if (cman_send_data(c_handle, buf, msglen, 0, CLUSTER_PORT_CLVMD, nodeid) <= 0)
 	{
-			log_error(errtext);
+		log_error(errtext);
 	}
 	return msglen;
 }
@@ -152,16 +152,18 @@
 
 /* Call a callback routine for each node is that known (down means not running a clvmd) */
 static int _cluster_do_node_callback(struct local_client *client,
-			     void (*callback) (struct local_client *, char *,
-					       int))
+				     void (*callback) (struct local_client *, char *,
+						       int))
 {
 	int i;
 	int somedown = 0;
 
 	for (i = 0; i < _get_num_nodes(); i++) {
-		callback(client, (char *)&nodes[i].cn_nodeid, node_updown[nodes[i].cn_nodeid]);
-		if (!node_updown[nodes[i].cn_nodeid])
-			somedown = -1;
+		if (nodes[i].cn_member) {
+			callback(client, (char *)&nodes[i].cn_nodeid, node_updown[nodes[i].cn_nodeid]);
+			if (!node_updown[nodes[i].cn_nodeid])
+				somedown = -1;
+		}
 	}
 	return somedown;
 }
@@ -170,7 +172,7 @@
    this currently just means that a node has stopped listening on our port */
 static void event_callback(cman_handle_t handle, void *private, int reason, int arg)
 {
-	char namebuf[MAX_CLUSTER_NAME_LEN];
+	char namebuf[MAX_CLUSTER_MEMBER_NAME_LEN];
 
 	switch (reason) {
         case CMAN_REASON_PORTCLOSED:
@@ -205,7 +207,7 @@
 
 static struct local_client *cman_client;
 static int _cluster_fd_callback(struct local_client *fd, char *buf, int len, char *csid,
-			struct local_client **new_client)
+				struct local_client **new_client)
 {
 
 	/* Save this for data_callback */
@@ -243,7 +245,7 @@
 				 max_updown_nodes);
 		} else {
 			log_error
-			    ("Realloc failed. Node status for clvmd will be wrong. quitting\n");
+				("Realloc failed. Node status for clvmd will be wrong. quitting\n");
 			exit(999);
 		}
 	}
@@ -297,35 +299,36 @@
 		return;
 	}
 
-	        /* Not enough room for new nodes list ? */
-	        if (num_nodes > count_nodes && nodes) {
-			free(nodes);
-			nodes = NULL;
-		}
+	/* Not enough room for new nodes list ? */
+	if (num_nodes > count_nodes && nodes) {
+		free(nodes);
+		nodes = NULL;
+	}
 
-		if (nodes == NULL) {
-		        count_nodes = num_nodes + 10; /* Overallocate a little */
+	if (nodes == NULL) {
+		count_nodes = num_nodes + 10; /* Overallocate a little */
 		nodes = malloc(count_nodes * sizeof(struct cman_node));
-			if (!nodes) {
-			        log_error("Unable to allocate nodes array\n");
-				exit(5);
-			}
+		if (!nodes) {
+			log_error("Unable to allocate nodes array\n");
+			exit(5);
 		}
+	}
 
 	status = cman_get_nodes(c_handle, count_nodes, &retnodes, nodes);
 	if (status < 0) {
-		        log_error("Unable to get node details");
-			exit(6);
-		}
+		log_error("Unable to get node details");
+		exit(6);
+	}
 
-		if (node_updown == NULL) {
-			node_updown =
-			    (int *) malloc(sizeof(int) *
-					   max(num_nodes, max_updown_nodes));
-			memset(node_updown, 0,
-			       sizeof(int) * max(num_nodes, max_updown_nodes));
-		}
+	if (node_updown == NULL) {
+		node_updown =
+			(int *) malloc(sizeof(int) *
+				       max(num_nodes, max_updown_nodes));
+		memset(node_updown, 0,
+		       sizeof(int) * max(num_nodes, max_updown_nodes));
 	}
+}
+
 
 /* Convert a node name to a CSID */
 static int _csid_from_name(char *csid, char *name)
@@ -468,6 +471,18 @@
 
 }
 
+static int _get_cluster_name(char *buf, int buflen)
+{
+	cman_cluster_t cluster_info;
+	int status;
+
+	status = cman_get_cluster(c_handle, &cluster_info);
+	if (!status) {
+		strncpy(buf, cluster_info.ci_name, buflen);
+	}
+	return status;
+}
+
 static struct cluster_ops _cluster_cman_ops = {
 	.cluster_init_completed   = _cluster_init_completed,
 	.cluster_send_message     = _cluster_send_message,
@@ -481,6 +496,7 @@
 	.get_our_csid             = _get_our_csid,
 	.add_up_node              = _add_up_node,
 	.cluster_closedown        = _cluster_closedown,
+	.get_cluster_name         = _get_cluster_name,
 	.sync_lock                = _sync_lock,
 	.sync_unlock              = _sync_unlock,
 };

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	Mon Oct 23 08:49:10 2006
@@ -75,6 +75,8 @@
 #include "clvmd.h"
 #include "libdlm.h"
 
+extern struct cluster_ops *clops;
+
 /* This is where all the real work happens:
    NOTE: client will be NULL when this is executed on a remote node */
 int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
@@ -117,11 +119,21 @@
 		if (status == EIO) {
 			*retlen =
 			    1 + snprintf(*buf, buflen,
-					 "Internal lvm error, check syslog");
+					 get_last_lvm_error());
 			return EIO;
 		}
 		break;
 
+	case CLVMD_CMD_REFRESH:
+		do_refresh_cache();
+		break;
+
+	case CLVMD_CMD_GET_CLUSTERNAME:
+		status = clops->get_cluster_name(*buf, buflen);
+		if (!status)
+			*retlen = strlen(*buf);
+		break;
+
 	default:
 		/* Won't get here because command is validated in pre_command */
 		break;
@@ -222,6 +234,10 @@
 		status = pre_lock_lv(lock_cmd, lock_flags, lockname);
 		break;
 
+	case CLVMD_CMD_REFRESH:
+	case CLVMD_CMD_GET_CLUSTERNAME:
+		break;
+
 	default:
 		log_error("Unknown command %d received\n", header->cmd);
 		status = EINVAL;

Modified: lvm2/upstream/current/daemons/clvmd/clvmd-comms.h
==============================================================================
--- lvm2/upstream/current/daemons/clvmd/clvmd-comms.h	(original)
+++ lvm2/upstream/current/daemons/clvmd/clvmd-comms.h	Mon Oct 23 08:49:10 2006
@@ -43,6 +43,8 @@
 	void (*reread_config) (void);
 	void (*cluster_closedown) (void);
 
+	int (*get_cluster_name)(char *buf, int buflen);
+
 	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/clvmd-gulm.c
==============================================================================
--- lvm2/upstream/current/daemons/clvmd/clvmd-gulm.c	(original)
+++ lvm2/upstream/current/daemons/clvmd/clvmd-gulm.c	Mon Oct 23 08:49:10 2006
@@ -973,6 +973,12 @@
 	return gulm_cluster_send_message(buf, msglen, csid, errtext);
 }
 
+static int _get_cluster_name(char *buf, int buflen)
+{
+	strncpy(buf, cluster_name, buflen);
+	return 0;
+}
+
 static struct cluster_ops _cluster_gulm_ops = {
 	.cluster_init_completed   = NULL,
 	.cluster_send_message     = _cluster_send_message,
@@ -987,6 +993,7 @@
 	.add_up_node              = gulm_add_up_node,
 	.reread_config            = _reread_config,
 	.cluster_closedown        = _cluster_closedown,
+	.get_cluster_name         = _get_cluster_name,
 	.sync_lock                = _sync_lock,
 	.sync_unlock              = _sync_unlock,
 };

Modified: lvm2/upstream/current/daemons/clvmd/clvmd.c
==============================================================================
--- lvm2/upstream/current/daemons/clvmd/clvmd.c	(original)
+++ lvm2/upstream/current/daemons/clvmd/clvmd.c	Mon Oct 23 08:49:10 2006
@@ -42,6 +42,7 @@
 #include "clvm.h"
 #include "version.h"
 #include "clvmd.h"
+#include "refresh_clvmd.h"
 #include "libdlm.h"
 #include "system-lv.h"
 #include "list.h"
@@ -66,7 +67,7 @@
 
 static unsigned short global_xid = 0;	/* Last transaction ID issued */
 
-static struct cluster_ops *clops = NULL;
+struct cluster_ops *clops = NULL;
 
 static char our_csid[MAX_CSID_LEN];
 static unsigned max_csid_len;
@@ -143,6 +144,7 @@
 	fprintf(file, "   -V       Show version of clvmd\n");
 	fprintf(file, "   -h       Show this help information\n");
 	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, "\n");
 }
@@ -173,7 +175,7 @@
 	/* Deal with command-line arguments */
 	opterr = 0;
 	optind = 0;
-	while ((opt = getopt(argc, argv, "?vVhdt:")) != EOF) {
+	while ((opt = getopt(argc, argv, "?vVhdt:R")) != EOF) {
 		switch (opt) {
 		case 'h':
 			usage(argv[0], stdout);
@@ -183,6 +185,9 @@
 			usage(argv[0], stderr);
 			exit(0);
 
+		case 'R':
+			return refresh_clvmd();
+
 		case 'd':
 			debug++;
 			break;
@@ -1684,6 +1689,7 @@
 		}
 		pthread_mutex_unlock(&lvm_thread_mutex);
 	}
+	return NULL;
 }
 
 /* Pass down some work to the LVM thread */

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	Mon Oct 23 08:49:10 2006
@@ -50,12 +50,18 @@
 static struct cmd_context *cmd = NULL;
 static struct dm_hash_table *lv_hash = NULL;
 static pthread_mutex_t lv_hash_lock;
+static char last_error[1024];
 
 struct lv_info {
 	int lock_id;
 	int lock_mode;
 };
 
+char *get_last_lvm_error()
+{
+	return last_error;
+}
+
 /* Return the mode a lock is currently held at (or -1 if not held) */
 static int get_current_lock(char *resource)
 {
@@ -201,8 +207,17 @@
 	/* Try to get the lock if it's a clustered volume group */
 	if (lock_flags & LCK_CLUSTER_VG) {
 		status = hold_lock(resource, mode, LKF_NOQUEUE);
-		if (status)
+		if (status) {
+			/* Return an LVM-sensible error for this.
+			 * Forcing EIO makes the upper level return this text
+			 * rather than the strerror text for EAGAIN.
+			 */
+			if (errno == EAGAIN) {
+				sprintf(last_error, "Volume is busy on another node");
+				errno = EIO;
+			}
 			return errno;
+		}
 	}
 
 	/* If it's suspended then resume it */
@@ -416,6 +431,13 @@
 	return status == 1 ? 0 : EBUSY;
 }
 
+int do_refresh_cache()
+{
+	DEBUGLOG("Refreshing context\n");
+	log_notice("Refreshing context");
+	return refresh_toolcontext(cmd)==1?0:-1;
+}
+
 
 /* Only called at gulm startup. Drop any leftover VG or P_orphan locks
    that might be hanging around if we died for any reason
@@ -505,6 +527,20 @@
 	return NULL;
 }
 
+static void lvm2_log_fn(int level, const char *file, int line,
+			const char *message)
+{
+	/*
+	 * Ignore non-error messages, but store the latest one for returning 
+	 * to the user.
+	 */
+	if (level != _LOG_ERR && level != _LOG_FATAL)
+		return;
+
+	strncpy(last_error, message, sizeof(last_error));
+	last_error[sizeof(last_error)-1] = '\0';
+}
+
 /* This checks some basic cluster-LVM configuration stuff */
 static void check_config()
 {
@@ -539,7 +575,7 @@
 /* Called to initialise the LVM context of the daemon */
 int init_lvm(int using_gulm)
 {
-	if (!(cmd = create_toolcontext(NULL))) {
+	if (!(cmd = create_toolcontext(NULL, 0))) {
 		log_error("Failed to allocate command context");
 		return 0;
 	}
@@ -557,5 +593,8 @@
 
 	get_initial_state();
 
+	/* Trap log messages so we can pass them back to the user */
+	init_log_fn(lvm2_log_fn);
+
 	return 1;
 }

Modified: lvm2/upstream/current/daemons/clvmd/lvm-functions.h
==============================================================================
--- lvm2/upstream/current/daemons/clvmd/lvm-functions.h	(original)
+++ lvm2/upstream/current/daemons/clvmd/lvm-functions.h	Mon Oct 23 08:49:10 2006
@@ -25,11 +25,13 @@
 extern int post_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
 			char *resource);
 extern int do_check_lvm1(char *vgname);
+extern int do_refresh_cache(void);
 extern int init_lvm(int using_gulm);
 extern void init_lvhash(void);
 
 extern int hold_unlock(char *resource);
 extern int hold_lock(char *resource, int mode, int flags);
 extern void unlock_all(void);
+extern char *get_last_lvm_error(void);
 
 #endif

Added: lvm2/upstream/current/daemons/clvmd/refresh_clvmd.c
==============================================================================
--- (empty file)
+++ lvm2/upstream/current/daemons/clvmd/refresh_clvmd.c	Mon Oct 23 08:49:10 2006
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of 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
+ */
+
+/*
+ * Tell all clvmds in a cluster to refresh their toolcontext
+ *
+ */
+
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <unistd.h>
+#include <libdevmapper.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include "clvm.h"
+#include "refresh_clvmd.h"
+
+typedef struct lvm_response {
+	char node[255];
+	char *response;
+	int status;
+	int len;
+} lvm_response_t;
+
+/*
+ * This gets stuck at the start of memory we allocate so we
+ * can sanity-check it at deallocation time
+ */
+#define LVM_SIGNATURE 0x434C564D
+
+static int _clvmd_sock = -1;
+
+/* Open connection to the Cluster Manager daemon */
+static int _open_local_sock(void)
+{
+	int local_socket;
+	struct sockaddr_un sockaddr;
+
+	/* Open local socket */
+	if ((local_socket = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
+		fprintf(stderr, "Local socket creation failed: %s", strerror(errno));
+		return -1;
+	}
+
+	memset(&sockaddr, 0, sizeof(sockaddr));
+	memcpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(CLVMD_SOCKNAME));
+
+	sockaddr.sun_family = AF_UNIX;
+
+	if (connect(local_socket,(struct sockaddr *) &sockaddr,
+		    sizeof(sockaddr))) {
+		int saved_errno = errno;
+
+		fprintf(stderr, "connect() failed on local socket: %s\n",
+			  strerror(errno));
+		if (close(local_socket))
+			return -1;
+
+		errno = saved_errno;
+		return -1;
+	}
+
+	return local_socket;
+}
+
+/* Send a request and return the status */
+static int _send_request(char *inbuf, int inlen, char **retbuf)
+{
+	char outbuf[PIPE_BUF];
+	struct clvm_header *outheader = (struct clvm_header *) outbuf;
+	int len;
+	int off;
+	int buflen;
+	int err;
+
+	/* Send it to CLVMD */
+ rewrite:
+	if ( (err = write(_clvmd_sock, inbuf, inlen)) != inlen) {
+	        if (err == -1 && errno == EINTR)
+		        goto rewrite;
+		fprintf(stderr, "Error writing data to clvmd: %s", strerror(errno));
+		return 0;
+	}
+
+	/* Get the response */
+ reread:
+	if ((len = read(_clvmd_sock, outbuf, sizeof(struct clvm_header))) < 0) {
+	        if (errno == EINTR)
+		        goto reread;
+		fprintf(stderr, "Error reading data from clvmd: %s", strerror(errno));
+		return 0;
+	}
+
+	if (len == 0) {
+		fprintf(stderr, "EOF reading CLVMD");
+		errno = ENOTCONN;
+		return 0;
+	}
+
+	/* Allocate buffer */
+	buflen = len + outheader->arglen;
+	*retbuf = dm_malloc(buflen);
+	if (!*retbuf) {
+		errno = ENOMEM;
+		return 0;
+	}
+
+	/* Copy the header */
+	memcpy(*retbuf, outbuf, len);
+	outheader = (struct clvm_header *) *retbuf;
+
+	/* Read the returned values */
+	off = 1;		/* we've already read the first byte */
+	while (off <= outheader->arglen && len > 0) {
+		len = read(_clvmd_sock, outheader->args + off,
+			   buflen - off - offsetof(struct clvm_header, args));
+		if (len > 0)
+			off += len;
+	}
+
+	/* Was it an error ? */
+	if (outheader->status != 0) {
+		errno = outheader->status;
+
+		/* Only return an error here if there are no node-specific
+		   errors present in the message that might have more detail */
+		if (!(outheader->flags & CLVMD_FLAG_NODEERRS)) {
+			fprintf(stderr, "cluster request failed: %s\n", strerror(errno));
+			return 0;
+		}
+
+	}
+
+	return 1;
+}
+
+/* Build the structure header and parse-out wildcard node names */
+static void _build_header(struct clvm_header *head, int cmd, const char *node,
+			  int len)
+{
+	head->cmd = cmd;
+	head->status = 0;
+	head->flags = 0;
+	head->clientid = 0;
+	head->arglen = len;
+
+	if (node) {
+		/*
+		 * Allow a couple of special node names:
+		 * "*" for all nodes,
+		 * "." for the local node only
+		 */
+		if (strcmp(node, "*") == 0) {
+			head->node[0] = '\0';
+		} else if (strcmp(node, ".") == 0) {
+			head->node[0] = '\0';
+			head->flags = CLVMD_FLAG_LOCAL;
+		} else
+			strcpy(head->node, node);
+	} else
+		head->node[0] = '\0';
+}
+
+/*
+ * Send a message to a(or all) node(s) in the cluster and wait for replies
+ */
+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 *inptr;
+	char *retbuf = NULL;
+	int status;
+	int i;
+	int num_responses = 0;
+	struct clvm_header *head = (struct clvm_header *) outbuf;
+	lvm_response_t *rarray;
+
+	*num = 0;
+
+	if (_clvmd_sock == -1)
+		_clvmd_sock = _open_local_sock();
+
+	if (_clvmd_sock == -1)
+		return 0;
+
+	_build_header(head, cmd, node, len);
+	memcpy(head->node + strlen(head->node) + 1, data, len);
+
+	status = _send_request(outbuf, sizeof(struct clvm_header) +
+			      strlen(head->node) + len, &retbuf);
+	if (!status)
+		goto out;
+
+	/* Count the number of responses we got */
+	head = (struct clvm_header *) retbuf;
+	inptr = head->args;
+	while (inptr[0]) {
+		num_responses++;
+		inptr += strlen(inptr) + 1;
+		inptr += sizeof(int);
+		inptr += strlen(inptr) + 1;
+	}
+
+	/*
+	 * Allocate response array.
+	 * 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) {
+		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 */
+	inptr = head->args;
+	i = 0;
+	while (inptr[0]) {
+		strcpy(rarray[i].node, inptr);
+		inptr += strlen(inptr) + 1;
+
+		memcpy(&rarray[i].status, inptr, sizeof(int));
+		inptr += sizeof(int);
+
+		rarray[i].response = dm_malloc(strlen(inptr) + 1);
+		if (rarray[i].response == NULL) {
+			/* Free up everything else and return error */
+			int j;
+			for (j = 0; j < i; j++)
+				dm_free(rarray[i].response);
+			free(outptr);
+			errno = ENOMEM;
+			status = -1;
+			goto out;
+		}
+
+		strcpy(rarray[i].response, inptr);
+		rarray[i].len = strlen(inptr);
+		inptr += strlen(inptr) + 1;
+		i++;
+	}
+	*num = num_responses;
+	*response = rarray;
+
+      out:
+	if (retbuf)
+		dm_free(retbuf);
+
+	return status;
+}
+
+/* Free reply array */
+static int _cluster_free_request(lvm_response_t * response)
+{
+	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);
+
+	return 1;
+}
+
+int refresh_clvmd()
+{
+	int num_responses;
+	char args[1]; // No args really.
+	lvm_response_t *response;
+	int saved_errno;
+	int status;
+	int i;
+
+	status = _cluster_request(CLVMD_CMD_REFRESH, "*", args, 0, &response, &num_responses);
+
+	/* If any nodes were down then display them and return an error */
+	for (i = 0; i < num_responses; i++) {
+		if (response[i].status == EHOSTDOWN) {
+			fprintf(stderr, "clvmd not running on node %s",
+				  response[i].node);
+			status = 0;
+			errno = response[i].status;
+		} else if (response[i].status) {
+			fprintf(stderr, "Error resetting node %s: %s",
+				  response[i].node,
+				  response[i].response[0] ?
+				  	response[i].response :
+				  	strerror(response[i].status));
+			status = 0;
+			errno = response[i].status;
+		}
+	}
+
+	saved_errno = errno;
+	_cluster_free_request(response);
+	errno = saved_errno;
+
+	return status;
+}

Added: lvm2/upstream/current/daemons/clvmd/refresh_clvmd.h
==============================================================================
--- (empty file)
+++ lvm2/upstream/current/daemons/clvmd/refresh_clvmd.h	Mon Oct 23 08:49:10 2006
@@ -0,0 +1,2 @@
+int refresh_clvmd(void);
+

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	Mon Oct 23 08:49:10 2006
@@ -48,7 +48,7 @@
 	char *p;
 	int log_argc, num_devs, num_failures=0;
 
-	if (max_args <= split_words(params, max_args, args)) {
+	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;
 	}
@@ -121,7 +121,7 @@
 	if (strlen(device) > 200)
 		return -ENAMETOOLONG;
 
-	if (!split_dm_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;

Modified: lvm2/upstream/current/doc/example.conf
==============================================================================
--- lvm2/upstream/current/doc/example.conf	(original)
+++ lvm2/upstream/current/doc/example.conf	Mon Oct 23 08:49:10 2006
@@ -207,11 +207,26 @@
     # Location of proc filesystem
     proc = "/proc"
 
-    # Type of locking to use. Defaults to file-based locking (1).
+    # Type of locking to use. Defaults to local file-based locking (1).
     # Turn locking off by setting to 0 (dangerous: risks metadata corruption
     # if LVM2 commands get run concurrently).
+    # Type 2 uses the external shared library locking_library.
+    # Type 3 uses built-in clustered locking.
     locking_type = 1
 
+    # If using external locking (type 2) and initialisation fails,
+    # with this set to 1 an attempt will be made to use the built-in
+    # clustered locking.
+    # If you are using a customised locking_library you should set this to 0.
+    fallback_to_clustered_locking = 1
+
+    # If an attempt to initialise type 2 or type 3 locking failed, perhaps
+    # because cluster components such as clvmd are not running, with this set
+    # to 1 an attempt will be made to use local file-based locking (type 1).
+    # If this succeeds, only commands against local volume groups will proceed.
+    # Volume Groups marked as clustered will be ignored.
+    fallback_to_local_locking = 1
+
     # Local non-LV directory that holds file-based locks while commands are
     # in progress.  A directory like /tmp that may get wiped on reboot is OK.
     locking_dir = "/var/lock/lvm"
@@ -223,6 +238,9 @@
 
     # Search this directory first for shared libraries.
     #   library_dir = "/lib"
+
+    # The external locking library to load if locking_type is set to 2.
+    #   locking_library = "liblvm2clusterlock.so"
 }
 
 activation {

Modified: lvm2/upstream/current/include/.symlinks
==============================================================================
--- lvm2/upstream/current/include/.symlinks	(original)
+++ lvm2/upstream/current/include/.symlinks	Mon Oct 23 08:49:10 2006
@@ -41,6 +41,7 @@
 ../lib/misc/lvm-exec.h
 ../lib/misc/lvm-file.h
 ../lib/misc/lvm-string.h
+../lib/misc/lvm-wrappers.h
 ../lib/misc/sharedlib.h
 ../lib/regex/matcher.h
 ../lib/report/report.h

Modified: lvm2/upstream/current/lib/Makefile.in
==============================================================================
--- lvm2/upstream/current/lib/Makefile.in	(original)
+++ lvm2/upstream/current/lib/Makefile.in	Mon Oct 23 08:49:10 2006
@@ -78,6 +78,8 @@
 	misc/lvm-exec.c \
 	misc/lvm-file.c \
 	misc/lvm-string.c \
+	misc/lvm-wrappers.c \
+	misc/timestamp.c \
 	mm/memlock.c \
 	regex/matcher.c \
 	regex/parse_rx.c \

Modified: lvm2/upstream/current/lib/activate/activate.c
==============================================================================
--- lvm2/upstream/current/lib/activate/activate.c	(original)
+++ lvm2/upstream/current/lib/activate/activate.c	Mon Oct 23 08:49:10 2006
@@ -39,7 +39,7 @@
 {
 	char path[PATH_MAX];
 
-	if (lvm_snprintf(path, sizeof(path), "%s/lvm/global", cmd->proc_dir)
+	if (dm_snprintf(path, sizeof(path), "%s/lvm/global", cmd->proc_dir)
 	    < 0) {
 		log_error("LVM1 proc global snprintf failed");
 		return 0;
@@ -51,6 +51,66 @@
 		return 0;
 }
 
+int list_segment_modules(struct dm_pool *mem, const struct lv_segment *seg,
+			 struct list *modules)
+{
+	unsigned int s;
+	struct lv_segment *seg2, *snap_seg;
+	struct list *snh;
+
+	if (seg->segtype->ops->modules_needed &&
+	    !seg->segtype->ops->modules_needed(mem, seg, modules)) {
+		log_error("module string allocation failed");
+		return 0;
+	}
+
+	if (lv_is_origin(seg->lv))
+		list_iterate(snh, &seg->lv->snapshot_segs)
+			if (!list_lv_modules(mem,
+					     list_struct_base(snh,
+							      struct lv_segment,
+							      origin_list)->cow,
+					     modules))
+				return_0;
+
+	if (lv_is_cow(seg->lv)) {
+		snap_seg = find_cow(seg->lv);
+		if (snap_seg->segtype->ops->modules_needed &&
+		    !snap_seg->segtype->ops->modules_needed(mem, snap_seg,
+							    modules)) {
+			log_error("snap_seg module string allocation failed");
+			return 0;
+		}
+	}
+
+	for (s = 0; s < seg->area_count; s++) {
+		switch (seg_type(seg, s)) {
+		case AREA_LV:
+			seg2 = find_seg_by_le(seg_lv(seg, s), seg_le(seg, s));
+			if (seg2 && !list_segment_modules(mem, seg2, modules))
+				return_0;
+			break;
+		case AREA_PV:
+		case AREA_UNASSIGNED:
+			;
+		}
+	}
+
+	return 1;
+}
+
+int list_lv_modules(struct dm_pool *mem, const struct logical_volume *lv,
+		    struct list *modules)
+{
+	struct lv_segment *seg;
+
+	list_iterate_items(seg, &lv->segments)
+		if (!list_segment_modules(mem, seg, modules))
+			return_0;
+
+	return 1;
+}
+
 #ifndef DEVMAPPER_SUPPORT
 void set_activation(int act)
 {
@@ -257,9 +317,9 @@
 				continue;
 		}
 		/* vgname/lvname */
-		if (lvm_snprintf(path, sizeof(path), "%s/%s", lv->vg->name,
+		if (dm_snprintf(path, sizeof(path), "%s/%s", lv->vg->name,
 				 lv->name) < 0) {
-			log_error("lvm_snprintf error from %s/%s", lv->vg->name,
+			log_error("dm_snprintf error from %s/%s", lv->vg->name,
 				  lv->name);
 			continue;
 		}
@@ -342,7 +402,7 @@
 		if (target_version(target_name, &maj, &min, &patchlevel))
 			return 1;
 
-		if (lvm_snprintf(module, sizeof(module), "dm-%s", target_name)
+		if (dm_snprintf(module, sizeof(module), "dm-%s", target_name)
 		    < 0) {
 			log_error("target_present module name too long: %s",
 				  target_name);
@@ -528,7 +588,7 @@
 	return r;
 }
 
-static int _lv_suspend_lv(struct logical_volume *lv)
+static int _lv_suspend_lv(struct logical_volume *lv, int lockfs)
 {
 	int r;
 	struct dev_manager *dm;
@@ -536,7 +596,7 @@
 	if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name)))
 		return_0;
 
-	if (!(r = dev_manager_suspend(dm, lv)))
+	if (!(r = dev_manager_suspend(dm, lv, lockfs)))
 		stack;
 
 	dev_manager_destroy(dm);
@@ -637,6 +697,7 @@
 {
 	struct logical_volume *lv, *lv_pre;
 	struct lvinfo info;
+	int lockfs = 0;
 
 	if (!activation())
 		return 1;
@@ -672,7 +733,11 @@
 		stack;
 
 	memlock_inc();
-	if (!_lv_suspend_lv(lv)) {
+
+	if (lv_is_origin(lv_pre) || lv_is_cow(lv_pre))
+		lockfs = 1;
+
+	if (!_lv_suspend_lv(lv, lockfs)) {
 		memlock_dec();
 		fs_unlock();
 		return 0;

Modified: lvm2/upstream/current/lib/activate/activate.h
==============================================================================
--- lvm2/upstream/current/lib/activate/activate.h	(original)
+++ lvm2/upstream/current/lib/activate/activate.h	Mon Oct 23 08:49:10 2006
@@ -39,6 +39,10 @@
 int target_present(const char *target_name, int use_modprobe);
 int target_version(const char *target_name, uint32_t *maj,
                    uint32_t *min, uint32_t *patchlevel);
+int list_segment_modules(struct dm_pool *mem, const struct lv_segment *seg,
+			 struct list *modules);
+int list_lv_modules(struct dm_pool *mem, const struct logical_volume *lv,
+		    struct list *modules);
 
 void activation_release(void);
 void activation_exit(void);

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	Mon Oct 23 08:49:10 2006
@@ -37,6 +37,7 @@
 	ACTIVATE,
 	DEACTIVATE,
 	SUSPEND,
+	SUSPEND_WITH_LOCKFS,
 	CLEAN
 } action_t;
 
@@ -911,7 +912,7 @@
 		name = dm_tree_node_get_name(child);
 
 		if (name && lvlayer->old_name && *lvlayer->old_name && strcmp(name, lvlayer->old_name)) {
-	        	if (!split_dm_name(dm->mem, lvlayer->old_name, &vgname, &lvname, &layer)) {
+	        	if (!dm_split_lvm_name(dm->mem, lvlayer->old_name, &vgname, &lvname, &layer)) {
                 		log_error("_create_lv_symlinks: Couldn't split up old device name %s", lvlayer->old_name);
                 		return 0;
         		}
@@ -937,7 +938,7 @@
 		if (!(uuid = dm_tree_node_get_uuid(child)))
 			continue;
 
-        	if (!split_dm_name(dm->mem, name, &vgname, &lvname, &layer)) {
+        	if (!dm_split_lvm_name(dm->mem, name, &vgname, &lvname, &layer)) {
                 	log_error("_clean_tree: Couldn't split up device name %s.", name);
                 	return 0;
         	}
@@ -984,8 +985,8 @@
 			goto_out;
 		break;
 	case SUSPEND:
-		if (!lv_is_origin(lv) && !lv_is_cow(lv))
-			dm_tree_skip_lockfs(root);
+		dm_tree_skip_lockfs(root);
+	case SUSPEND_WITH_LOCKFS:
 		if (!dm_tree_suspend_children(root, dlid, ID_LEN + sizeof(UUID_PREFIX) - 1))
 			goto_out;
 		break;
@@ -1049,9 +1050,10 @@
 	return r;
 }
 
-int dev_manager_suspend(struct dev_manager *dm, struct logical_volume *lv)
+int dev_manager_suspend(struct dev_manager *dm, struct logical_volume *lv,
+			int lockfs)
 {
-	return _tree_action(dm, lv, SUSPEND);
+	return _tree_action(dm, lv, lockfs ? SUSPEND_WITH_LOCKFS : SUSPEND);
 }
 
 /*

Modified: lvm2/upstream/current/lib/activate/dev_manager.h
==============================================================================
--- lvm2/upstream/current/lib/activate/dev_manager.h	(original)
+++ lvm2/upstream/current/lib/activate/dev_manager.h	Mon Oct 23 08:49:10 2006
@@ -47,7 +47,8 @@
 int dev_manager_mirror_percent(struct dev_manager *dm,
 			       struct logical_volume *lv, int wait,
 			       float *percent, uint32_t *event_nr);
-int dev_manager_suspend(struct dev_manager *dm, struct logical_volume *lv);
+int dev_manager_suspend(struct dev_manager *dm, struct logical_volume *lv,
+			int lockfs);
 int dev_manager_activate(struct dev_manager *dm, struct logical_volume *lv);
 int dev_manager_preload(struct dev_manager *dm, struct logical_volume *lv);
 int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv);

Modified: lvm2/upstream/current/lib/activate/fs.c
==============================================================================
--- lvm2/upstream/current/lib/activate/fs.c	(original)
+++ lvm2/upstream/current/lib/activate/fs.c	Mon Oct 23 08:49:10 2006
@@ -30,7 +30,7 @@
 {
 	char vg_path[PATH_MAX];
 
-	if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
+	if (dm_snprintf(vg_path, sizeof(vg_path), "%s%s",
 			 dev_dir, vg_name) == -1) {
 		log_error("Couldn't construct name of volume "
 			  "group directory.");
@@ -53,7 +53,7 @@
 {
 	char vg_path[PATH_MAX];
 
-	if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
+	if (dm_snprintf(vg_path, sizeof(vg_path), "%s%s",
 			 dev_dir, vg_name) == -1) {
 		log_error("Couldn't construct name of volume "
 			  "group directory.");
@@ -87,7 +87,7 @@
 		if (!strcmp(name, ".") || !strcmp(name, ".."))
 			continue;
 
-		if (lvm_snprintf(path, sizeof(path), "%s/%s", dir, name) == -1) {
+		if (dm_snprintf(path, sizeof(path), "%s/%s", dir, name) == -1) {
 			log_error("Couldn't create path for %s", name);
 			continue;
 		}
@@ -109,28 +109,28 @@
 	char vg_path[PATH_MAX];
 	struct stat buf;
 
-	if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
+	if (dm_snprintf(vg_path, sizeof(vg_path), "%s%s",
 			 dev_dir, vg_name) == -1) {
 		log_error("Couldn't create path for volume group dir %s",
 			  vg_name);
 		return 0;
 	}
 
-	if (lvm_snprintf(lv_path, sizeof(lv_path), "%s/%s", vg_path,
+	if (dm_snprintf(lv_path, sizeof(lv_path), "%s/%s", vg_path,
 			 lv_name) == -1) {
 		log_error("Couldn't create source pathname for "
 			  "logical volume link %s", lv_name);
 		return 0;
 	}
 
-	if (lvm_snprintf(link_path, sizeof(link_path), "%s/%s",
+	if (dm_snprintf(link_path, sizeof(link_path), "%s/%s",
 			 dm_dir(), dev) == -1) {
 		log_error("Couldn't create destination pathname for "
 			  "logical volume link for %s", lv_name);
 		return 0;
 	}
 
-	if (lvm_snprintf(lvm1_group_path, sizeof(lvm1_group_path), "%s/group",
+	if (dm_snprintf(lvm1_group_path, sizeof(lvm1_group_path), "%s/group",
 			 vg_path) == -1) {
 		log_error("Couldn't create pathname for LVM1 group file for %s",
 			  vg_name);
@@ -190,7 +190,7 @@
 	struct stat buf;
 	char lv_path[PATH_MAX];
 
-	if (lvm_snprintf(lv_path, sizeof(lv_path), "%s%s/%s",
+	if (dm_snprintf(lv_path, sizeof(lv_path), "%s%s/%s",
 			 dev_dir, vg_name, lv_name) == -1) {
 		log_error("Couldn't determine link pathname.");
 		return 0;

Modified: lvm2/upstream/current/lib/cache/lvmcache.c
==============================================================================
--- lvm2/upstream/current/lib/cache/lvmcache.c	(original)
+++ lvm2/upstream/current/lib/cache/lvmcache.c	Mon Oct 23 08:49:10 2006
@@ -241,7 +241,7 @@
 		goto out;
 	}
 
-	if (!(iter = dev_iter_create(cmd->filter, (full_scan == 2) ? 1: 0))) {
+	if (!(iter = dev_iter_create(cmd->filter, (full_scan == 2) ? 1 : 0))) {
 		log_error("dev_iter creation failed");
 		goto out;
 	}

Modified: lvm2/upstream/current/lib/commands/toolcontext.c
==============================================================================
--- lvm2/upstream/current/lib/commands/toolcontext.c	(original)
+++ lvm2/upstream/current/lib/commands/toolcontext.c	Mon Oct 23 08:49:10 2006
@@ -67,7 +67,7 @@
 
 	/* Set to "" to avoid using any system directory */
 	if ((e = getenv("LVM_SYSTEM_DIR"))) {
-		if (lvm_snprintf(cmd->sys_dir, sizeof(cmd->sys_dir),
+		if (dm_snprintf(cmd->sys_dir, sizeof(cmd->sys_dir),
 				 "%s", e) < 0) {
 			log_error("LVM_SYSTEM_DIR environment variable "
 				  "is too long.");
@@ -167,7 +167,7 @@
 		log_verbose("Set umask to %04o", cmd->default_settings.umask);
 
 	/* dev dir */
-	if (lvm_snprintf(cmd->dev_dir, sizeof(cmd->dev_dir), "%s/",
+	if (dm_snprintf(cmd->dev_dir, sizeof(cmd->dev_dir), "%s/",
 			 find_config_tree_str(cmd, "devices/dir",
 					 DEFAULT_DEV_DIR)) < 0) {
 		log_error("Device directory given in config file too long");
@@ -178,7 +178,7 @@
 #endif
 
 	/* proc dir */
-	if (lvm_snprintf(cmd->proc_dir, sizeof(cmd->proc_dir), "%s",
+	if (dm_snprintf(cmd->proc_dir, sizeof(cmd->proc_dir), "%s",
 			 find_config_tree_str(cmd, "global/proc",
 					 DEFAULT_PROC_DIR)) < 0) {
 		log_error("Device directory given in config file too long");
@@ -319,7 +319,7 @@
 	if (*tag)
 		filler = "_";
 
-	if (lvm_snprintf(config_file, sizeof(config_file), "%s/lvm%s%s.conf",
+	if (dm_snprintf(config_file, sizeof(config_file), "%s/lvm%s%s.conf",
 			 cmd->sys_dir, filler, tag) < 0) {
 		log_error("LVM_SYSTEM_DIR or tag was too long");
 		return 0;
@@ -587,7 +587,7 @@
 	if (!(f3 = _init_filter_components(cmd)))
 		return 0;
 
-	if (lvm_snprintf(cache_file, sizeof(cache_file),
+	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);
@@ -646,8 +646,9 @@
 #endif
 
 #ifdef HAVE_LIBDL
-	/* Load any formats in shared libs */
-	if ((cn = find_config_tree_node(cmd, "global/format_libraries"))) {
+	/* Load any formats in shared libs if not static */
+	if (!cmd->is_static &&
+	    (cn = find_config_tree_node(cmd, "global/format_libraries"))) {
 
 		struct config_value *cv;
 		struct format_type *(*init_format_fn) (struct cmd_context *);
@@ -740,8 +741,9 @@
 #endif
 
 #ifdef HAVE_LIBDL
-	/* Load any formats in shared libs */
-	if ((cn = find_config_tree_node(cmd, "global/segment_libraries"))) {
+	/* Load any formats in shared libs unless static */
+	if (!cmd->is_static &&
+	    (cn = find_config_tree_node(cmd, "global/segment_libraries"))) {
 
 		struct config_value *cv;
 		struct segment_type *(*init_segtype_fn) (struct cmd_context *);
@@ -839,7 +841,7 @@
 	min = (uint32_t) find_config_tree_int(cmd, "backup/retain_min",
 					 DEFAULT_ARCHIVE_NUMBER);
 
-	if (lvm_snprintf
+	if (dm_snprintf
 	    (default_dir, sizeof(default_dir), "%s/%s", cmd->sys_dir,
 	     DEFAULT_ARCHIVE_SUBDIR) == -1) {
 		log_err("Couldn't create default archive path '%s/%s'.",
@@ -860,7 +862,7 @@
 	    find_config_tree_bool(cmd, "backup/backup",
 			     DEFAULT_BACKUP_ENABLED);
 
-	if (lvm_snprintf
+	if (dm_snprintf
 	    (default_dir, sizeof(default_dir), "%s/%s", cmd->sys_dir,
 	     DEFAULT_BACKUP_SUBDIR) == -1) {
 		log_err("Couldn't create default backup path '%s/%s'.",
@@ -879,7 +881,7 @@
 }
 
 /* Entry point */
-struct cmd_context *create_toolcontext(struct arg *the_args)
+struct cmd_context *create_toolcontext(struct arg *the_args, unsigned is_static)
 {
 	struct cmd_context *cmd;
 
@@ -902,6 +904,7 @@
 	}
 	memset(cmd, 0, sizeof(*cmd));
 	cmd->args = the_args;
+	cmd->is_static = is_static;
 	cmd->hosttags = 0;
 	list_init(&cmd->formats);
 	list_init(&cmd->segtypes);

Modified: lvm2/upstream/current/lib/commands/toolcontext.h
==============================================================================
--- lvm2/upstream/current/lib/commands/toolcontext.h	(original)
+++ lvm2/upstream/current/lib/commands/toolcontext.h	Mon Oct 23 08:49:10 2006
@@ -64,6 +64,7 @@
 	struct command *command;
 	struct arg *args;
 	char **argv;
+	unsigned is_static;	/* Static binary? */
 
 	struct dev_filter *filter;
 	int dump_filter;	/* Dump filter when exiting? */
@@ -87,7 +88,7 @@
 	char proc_dir[PATH_MAX];
 };
 
-struct cmd_context *create_toolcontext(struct arg *the_args);
+struct cmd_context *create_toolcontext(struct arg *the_args, unsigned is_static);
 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	Mon Oct 23 08:49:10 2006
@@ -187,7 +187,7 @@
 		use_mmap = 0;
 
 	if (use_mmap) {
-		mmap_offset = offset % getpagesize();
+		mmap_offset = offset % lvm_getpagesize();
 		/* memory map the file */
 		p->fb = mmap((caddr_t) 0, size + mmap_offset, PROT_READ,
 			     MAP_PRIVATE, dev_fd(dev), offset - mmap_offset);

Modified: lvm2/upstream/current/lib/config/defaults.h
==============================================================================
--- lvm2/upstream/current/lib/config/defaults.h	(original)
+++ lvm2/upstream/current/lib/config/defaults.h	Mon Oct 23 08:49:10 2006
@@ -32,7 +32,9 @@
 #define DEFAULT_MD_COMPONENT_DETECTION 1
 
 #define DEFAULT_LOCK_DIR "/var/lock/lvm"
-#define DEFAULT_LOCKING_LIB "lvm2_locking.so"
+#define DEFAULT_LOCKING_LIB "liblvm2clusterlock.so"
+#define DEFAULT_FALLBACK_TO_LOCAL_LOCKING 1
+#define DEFAULT_FALLBACK_TO_CLUSTERED_LOCKING 1
 
 #define DEFAULT_MIRROR_LOG_FAULT_POLICY "allocate"
 #define DEFAULT_MIRROR_DEV_FAULT_POLICY "remove"

Modified: lvm2/upstream/current/lib/device/dev-cache.c
==============================================================================
--- lvm2/upstream/current/lib/device/dev-cache.c	(original)
+++ lvm2/upstream/current/lib/device/dev-cache.c	Mon Oct 23 08:49:10 2006
@@ -645,8 +645,7 @@
 		return NULL;
 	}
 
-
-	if (dev_scan) {
+	if (dev_scan && !trust_cache()) {
 		/* Flag gets reset between each command */
 		if (!full_scan_done())
 			persistent_filter_wipe(f); /* Calls _full_scan(1) */

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	Mon Oct 23 08:49:10 2006
@@ -176,7 +176,7 @@
 	}
 
 	if (!block_size)
-		block_size = getpagesize();
+		block_size = lvm_getpagesize();
 
 	_widen_region(block_size, where, &widened);
 

Modified: lvm2/upstream/current/lib/display/display.c
==============================================================================
--- lvm2/upstream/current/lib/display/display.c	(original)
+++ lvm2/upstream/current/lib/display/display.c	Mon Oct 23 08:49:10 2006
@@ -30,6 +30,7 @@
 } _policies[] = {
 	{
 	ALLOC_CONTIGUOUS, "contiguous"}, {
+	ALLOC_CLING, "cling"}, {
 	ALLOC_NORMAL, "normal"}, {
 	ALLOC_ANYWHERE, "anywhere"}, {
 	ALLOC_INHERIT, "inherit"}

Modified: lvm2/upstream/current/lib/error/errseg.c
==============================================================================
--- lvm2/upstream/current/lib/error/errseg.c	(original)
+++ lvm2/upstream/current/lib/error/errseg.c	Mon Oct 23 08:49:10 2006
@@ -23,6 +23,7 @@
 #include "targets.h"
 #include "lvm-string.h"
 #include "activate.h"
+#include "str_list.h"
 
 static const char *_errseg_name(const struct lv_segment *seg)
 {
@@ -64,6 +65,18 @@
 }
 #endif
 
+static int _errseg_modules_needed(struct dm_pool *mem,
+				  const struct lv_segment *seg,
+				  struct list *modules)
+{
+	if (!str_list_add(mem, modules, "error")) {
+		log_error("error module string list allocation failed");
+		return 0;
+	}
+
+	return 1;
+}
+ 
 static void _errseg_destroy(const struct segment_type *segtype)
 {
 	dm_free((void *)segtype);
@@ -76,6 +89,7 @@
 	.add_target_line = _errseg_add_target_line,
 	.target_present = _errseg_target_present,
 #endif
+	.modules_needed = _errseg_modules_needed,
 	.destroy = _errseg_destroy,
 };
 

Modified: lvm2/upstream/current/lib/filters/filter-md.c
==============================================================================
--- lvm2/upstream/current/lib/filters/filter-md.c	(original)
+++ lvm2/upstream/current/lib/filters/filter-md.c	Mon Oct 23 08:49:10 2006
@@ -18,14 +18,6 @@
 
 #ifdef linux
 
-/* Lifted from <linux/raid/md_p.h> because of difficulty including it */
-
-#define MD_SB_MAGIC 0xa92b4efc
-#define MD_RESERVED_BYTES (64 * 1024)
-#define MD_RESERVED_SECTORS (MD_RESERVED_BYTES / 512)
-#define MD_NEW_SIZE_SECTORS(x) ((x & ~(MD_RESERVED_SECTORS - 1)) \
-				- MD_RESERVED_SECTORS)
-
 static int _ignore_md(struct dev_filter *f, struct device *dev)
 {
 	int ret;

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	Mon Oct 23 08:49:10 2006
@@ -32,7 +32,7 @@
 		return 0;
 	}
 		
-	if (lvm_snprintf(proc_mounts, sizeof(proc_mounts),
+	if (dm_snprintf(proc_mounts, sizeof(proc_mounts),
 			 "%s/mounts", proc) < 0) {
 		log_error("Failed to create /proc/mounts string");
 		return 0;
@@ -44,9 +44,9 @@
 	}
 
 	while (fgets(buffer, sizeof(buffer), fp)) {
-		if (split_words(buffer, 4, split) == 4 &&
+		if (dm_split_words(buffer, 4, 0, split) == 4 &&
 		    !strcmp(split[2], "sysfs")) {
-			if (lvm_snprintf(path, len, "%s/%s", split[1],
+			if (dm_snprintf(path, len, "%s/%s", split[1],
 					 "block") >= 0) {
 				r = 1;
 			}
@@ -183,7 +183,7 @@
                 if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
 			continue;
 
-		if (lvm_snprintf(path, sizeof(path), "%s/%s", dir,
+		if (dm_snprintf(path, sizeof(path), "%s/%s", dir,
 				 d->d_name) < 0) {
 			log_error("sysfs path name too long: %s in %s",
 				  d->d_name, dir);

Modified: lvm2/upstream/current/lib/filters/filter.c
==============================================================================
--- lvm2/upstream/current/lib/filters/filter.c	(original)
+++ lvm2/upstream/current/lib/filters/filter.c	Mon Oct 23 08:49:10 2006
@@ -145,7 +145,7 @@
 	/* All types unrecognised initially */
 	memset(_max_partitions_by_major, 0, sizeof(int) * NUMBER_OF_MAJORS);
 
-	if (lvm_snprintf(proc_devices, sizeof(proc_devices),
+	if (dm_snprintf(proc_devices, sizeof(proc_devices),
 			 "%s/devices", proc) < 0) {
 		log_error("Failed to create /proc/devices string");
 		return 0;

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	Mon Oct 23 08:49:10 2006
@@ -458,7 +458,7 @@
 
 /*
  * Build a list of pv_d's structures, allocated from mem.
- * We keep track of the first object allocated form the pool
+ * We keep track of the first object allocated from the pool
  * so we can free off all the memory if something goes wrong.
  */
 int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name,

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	Mon Oct 23 08:49:10 2006
@@ -172,6 +172,7 @@
  * Layout constants.
  */
 #define METADATA_ALIGN 4096UL
+#define LVM1_PE_ALIGN (65536UL >> SECTOR_SHIFT)      /* PE alignment */
 
 #define	METADATA_BASE 0UL
 #define	PV_SIZE 1024UL

Modified: lvm2/upstream/current/lib/format1/format1.c
==============================================================================
--- lvm2/upstream/current/lib/format1/format1.c	(original)
+++ lvm2/upstream/current/lib/format1/format1.c	Mon Oct 23 08:49:10 2006
@@ -408,7 +408,7 @@
 
 	/* Ensure any residual PE structure is gone */
 	pv->pe_size = pv->pe_count = 0;
-	pv->pe_start = PE_ALIGN;
+	pv->pe_start = LVM1_PE_ALIGN;
 
 	if (!(mem = dm_pool_create("lvm1 pv_write", 1024))) {
 		stack;
@@ -431,7 +431,7 @@
 	   dev_write in order to make other disk tools happy */
 	dl->pvd.pv_on_disk.base = METADATA_BASE;
 	dl->pvd.pv_on_disk.size = PV_SIZE;
-	dl->pvd.pe_on_disk.base = PE_ALIGN << SECTOR_SHIFT;
+	dl->pvd.pe_on_disk.base = LVM1_PE_ALIGN << SECTOR_SHIFT;
 
 	list_add(&pvs, &dl->list);
 	if (!write_disks(fmt, &pvs)) {

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	Mon Oct 23 08:49:10 2006
@@ -103,7 +103,7 @@
 static int _system_id(struct cmd_context *cmd, char *s, const char *prefix)
 {
 
-	if (lvm_snprintf(s, NAME_LEN, "%s%s%lu",
+	if (dm_snprintf(s, NAME_LEN, "%s%s%lu",
 			 prefix, cmd->hostname, time(NULL)) < 0) {
 		log_error("Generated system_id too long");
 		return 0;

Modified: lvm2/upstream/current/lib/format1/layout.c
==============================================================================
--- lvm2/upstream/current/lib/format1/layout.c	(original)
+++ lvm2/upstream/current/lib/format1/layout.c	Mon Oct 23 08:49:10 2006
@@ -153,7 +153,7 @@
 		if (pe_start && end < pe_start)
 			end = pe_start;
 
-		pvd->pe_start = _round_up(end, PE_ALIGN);
+		pvd->pe_start = _round_up(end, LVM1_PE_ALIGN);
 
 	} while ((pvd->pe_start + (pvd->pe_total * extent_size))
 		 > pv->size);

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	Mon Oct 23 08:49:10 2006
@@ -277,7 +277,7 @@
 	}
 
 	for (i = 0; i < 10; i++) {
-		if (lvm_snprintf(archive_name, sizeof(archive_name),
+		if (dm_snprintf(archive_name, sizeof(archive_name),
 				 "%s/%s_%05u.vg", dir, vg->name, ix) < 0) {
 			log_error("Archive file name too long.");
 			return 0;

Modified: lvm2/upstream/current/lib/format_text/archiver.c
==============================================================================
--- lvm2/upstream/current/lib/format_text/archiver.c	(original)
+++ lvm2/upstream/current/lib/format_text/archiver.c	Mon Oct 23 08:49:10 2006
@@ -190,7 +190,7 @@
 		return 0;
 	}
 
-	if (lvm_snprintf(name, sizeof(name), "%s/%s",
+	if (dm_snprintf(name, sizeof(name), "%s/%s",
 			 vg->cmd->backup_params->dir, vg->name) < 0) {
 		log_error("Failed to generate volume group metadata backup "
 			  "filename.");
@@ -233,7 +233,7 @@
 {
 	char path[PATH_MAX];
 
-	if (lvm_snprintf(path, sizeof(path), "%s/%s",
+	if (dm_snprintf(path, sizeof(path), "%s/%s",
 			 cmd->backup_params->dir, vg_name) < 0) {
 		log_err("Failed to generate backup filename (for removal).");
 		return 0;
@@ -342,7 +342,7 @@
 {
 	char path[PATH_MAX];
 
-	if (lvm_snprintf(path, sizeof(path), "%s/%s",
+	if (dm_snprintf(path, sizeof(path), "%s/%s",
 			 cmd->backup_params->dir, vg_name) < 0) {
 		log_err("Failed to generate backup filename (for restore).");
 		return 0;
@@ -397,7 +397,7 @@
 	if ((vg->status & PARTIAL_VG) || (vg->status & EXPORTED_VG))
 		return;
 
-	if (lvm_snprintf(path, sizeof(path), "%s/%s",
+	if (dm_snprintf(path, sizeof(path), "%s/%s",
 			 vg->cmd->backup_params->dir, vg->name) < 0) {
 		log_debug("Failed to generate backup filename.");
 		return;

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	Mon Oct 23 08:49:10 2006
@@ -233,7 +233,7 @@
 	for (i = 0; (d > 1024.0) && _units[i]; i++)
 		d /= 1024.0;
 
-	return lvm_snprintf(buffer, s, "# %g %s", d, _units[i]) > 0;
+	return dm_snprintf(buffer, s, "# %g %s", d, _units[i]) > 0;
 }
 
 /*
@@ -409,6 +409,11 @@
 			outf(f, "tags = %s", buffer);
 		}
 
+		if (!out_size(f, pv->size, "dev_size = %" PRIu64, pv->size)) {
+			stack;
+			return 0;
+		}
+
 		outf(f, "pe_start = %" PRIu64, pv->pe_start);
 		if (!out_size(f, vg->extent_size * (uint64_t) pv->pe_count,
 			      "pe_count = %u", pv->pe_count)) {
@@ -623,7 +628,7 @@
 		pv = pvl->pv;
 
 		/* FIXME But skip if there's already an LV called pv%d ! */
-		if (lvm_snprintf(buffer, sizeof(buffer), "pv%d", count++) < 0)
+		if (dm_snprintf(buffer, sizeof(buffer), "pv%d", count++) < 0)
 			return_0;
 
 		if (!(name = dm_pool_strdup(f->mem, buffer)))

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	Mon Oct 23 08:49:10 2006
@@ -853,7 +853,7 @@
 			     tmp != dirent->d_name + strlen(dirent->d_name)
 			     - 4)) {
 				vgname = dirent->d_name;
-				if (lvm_snprintf(path, PATH_MAX, "%s/%s",
+				if (dm_snprintf(path, PATH_MAX, "%s/%s",
 						 dl->dir, vgname) < 0) {
 					log_error("Name too long %s/%s",
 						  dl->dir, vgname);
@@ -994,7 +994,7 @@
 }
 
 /* For orphan, creates new mdas according to policy.
-   Always have an mda between end-of-label and PE_ALIGN boundary */
+   Always have an mda between end-of-label and pe_align() boundary */
 static int _mda_setup(const struct format_type *fmt,
 		      uint64_t pe_start, uint64_t pe_end,
 		      int pvmetadatacopies,
@@ -1005,15 +1005,12 @@
 	uint64_t start1, mda_size1;	/* First area - start of disk */
 	uint64_t start2, mda_size2;	/* Second area - end of disk */
 	uint64_t wipe_size = 8 << SECTOR_SHIFT;
-	size_t pagesize = getpagesize();
+	size_t pagesize = lvm_getpagesize();
 
-	if (!pvmetadatacopies) {
-		/* Space available for PEs */
-		pv->size -= PE_ALIGN;
+	if (!pvmetadatacopies)
 		return 1;
-	}
 
-	alignment = PE_ALIGN << SECTOR_SHIFT;
+	alignment = pe_align() << SECTOR_SHIFT;
 	disk_size = pv->size << SECTOR_SHIFT;
 	pe_start <<= SECTOR_SHIFT;
 	pe_end <<= SECTOR_SHIFT;
@@ -1027,9 +1024,6 @@
 	/* Requested metadatasize */
 	mda_size1 = pvmetadatasize << SECTOR_SHIFT;
 
-	/* Space available for PEs (before any mdas created) */
-	pv->size -= LABEL_SCAN_SECTORS;
-
 	/* Place mda straight after label area at start of disk */
 	start1 = LABEL_SCAN_SIZE;
 
@@ -1037,11 +1031,8 @@
 	if ((!pe_start && !pe_end) ||
 	    ((pe_start > start1) && (pe_start - start1 >= MDA_SIZE_MIN))) {
 		mda_adjustment = start1 % pagesize;
-		if (mda_adjustment) {
+		if (mda_adjustment)
 			start1 += (pagesize - mda_adjustment);
-			pv->size -= ((pagesize - mda_adjustment) >>
-				     SECTOR_SHIFT);
-		}
 	}
 
 	/* Ensure it's not going to be bigger than the disk! */
@@ -1055,7 +1046,7 @@
 		pvmetadatacopies = 1;
 	}
 
-	/* Round up to PE_ALIGN boundary */
+	/* Round up to pe_align() boundary */
 	mda_adjustment = (mda_size1 + start1) % alignment;
 	if (mda_adjustment)
 		mda_size1 += (alignment - mda_adjustment);
@@ -1071,7 +1062,8 @@
 	/* FIXME If creating new mdas, wipe them! */
 	if (mda_size1) {
 		if (!add_mda(fmt, fmt->cmd->mem, mdas, pv->dev, start1,
-			     mda_size1)) return 0;
+			     mda_size1))
+			return 0;
 
 		if (!dev_set((struct device *) pv->dev, start1,
 			     (size_t) (mda_size1 >
@@ -1080,7 +1072,6 @@
 			return 0;
 		}
 
-		pv->size -= mda_size1 >> SECTOR_SHIFT;
 		if (pvmetadatacopies == 1)
 			return 1;
 	} else
@@ -1125,7 +1116,6 @@
 			log_error("Failed to wipe new metadata area");
 			return 0;
 		}
-		pv->size -= mda_size2 >> SECTOR_SHIFT;
 	} else
 		return 0;
 
@@ -1189,18 +1179,18 @@
 
 	/* Set pe_start to first aligned sector after any metadata 
 	 * areas that begin before pe_start */
-	pv->pe_start = PE_ALIGN;
+	pv->pe_start = pe_align();
 	list_iterate_items(mda, &info->mdas) {
 		mdac = (struct mda_context *) mda->metadata_locn;
 		if (pv->dev == mdac->area.dev &&
-		    (mdac->area.start < (pv->pe_start << SECTOR_SHIFT)) &&
+		    (mdac->area.start <= (pv->pe_start << SECTOR_SHIFT)) &&
 		    (mdac->area.start + mdac->area.size >
 		     (pv->pe_start << SECTOR_SHIFT))) {
 			pv->pe_start = (mdac->area.start + mdac->area.size)
 			    >> SECTOR_SHIFT;
-			adjustment = pv->pe_start % PE_ALIGN;
+			adjustment = pv->pe_start % pe_align();
 			if (adjustment)
-				pv->pe_start += (PE_ALIGN - adjustment);
+				pv->pe_start += (pe_align() - adjustment);
 		}
 	}
 	if (!add_da
@@ -1416,8 +1406,8 @@
 	struct lvmcache_info *info;
 	int found;
 	uint64_t pe_end = 0;
-
-	/* FIXME if vg, adjust start/end of pe area to avoid mdas! */
+	unsigned mda_count = 0;
+	uint64_t mda_size2 = 0;
 
 	/* FIXME Cope with pvchange */
 	/* FIXME Merge code with _text_create_text_instance */
@@ -1428,11 +1418,16 @@
 		if ((info = info_from_pvid(pv->dev->pvid))) {
 			pvmdas = &info->mdas;
 			list_iterate_items(mda, pvmdas) {
+				mda_count++;
 				mdac =
 				    (struct mda_context *) mda->metadata_locn;
 
 				/* FIXME Check it isn't already in use */
 
+				/* Reduce usable device size */
+				if (mda_count > 1)
+					mda_size2 = mdac->area.size >> SECTOR_SHIFT;
+
 				/* Ensure it isn't already on list */
 				found = 0;
 				list_iterate_items(mda2, mdas) {
@@ -1470,6 +1465,17 @@
 			}
 		}
 
+		/* FIXME Cope with genuine pe_count 0 */
+
+		/* If missing, estimate pv->size from file-based metadata */
+		if (!pv->size && pv->pe_count)
+			pv->size = pv->pe_count * (uint64_t) vg->extent_size +
+				   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;
+
 		/* Unlike LVM1, we don't store this outside a VG */
 		/* FIXME Default from config file? vgextend cmdline flag? */
 		pv->status |= ALLOCATABLE_PV;
@@ -1533,7 +1539,7 @@
 		dir_list = &((struct mda_lists *) fmt->private)->dirs;
 
 		list_iterate_items(dl, dir_list) {
-			if (lvm_snprintf(path, PATH_MAX, "%s/%s",
+			if (dm_snprintf(path, PATH_MAX, "%s/%s",
 					 dl->dir, vgname) < 0) {
 				log_error("Name too long %s/%s", dl->dir,
 					  vgname);

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	Mon Oct 23 08:49:10 2006
@@ -179,6 +179,9 @@
 		return 0;
 	}
 
+	/* Late addition */
+	_read_int64(pvn, "dev_size", &pv->size);
+
 	if (!_read_int64(pvn, "pe_start", &pv->pe_start)) {
 		log_error("Couldn't read extent size for volume group.");
 		return 0;
@@ -206,7 +209,7 @@
 	vg->free_count += pv->pe_count;
 
 	pv->pe_size = vg->extent_size;
-	pv->size = vg->extent_size * (uint64_t) pv->pe_count;
+
 	pv->pe_alloc_count = 0;
 	pv->fmt = fid->fmt;
 

Modified: lvm2/upstream/current/lib/format_text/layout.h
==============================================================================
--- lvm2/upstream/current/lib/format_text/layout.h	(original)
+++ lvm2/upstream/current/lib/format_text/layout.h	Mon Oct 23 08:49:10 2006
@@ -83,6 +83,6 @@
 #define FMTT_VERSION 1
 #define MDA_HEADER_SIZE 512
 #define LVM2_LABEL "LVM2 001"
-#define MDA_SIZE_MIN (8 * (unsigned) getpagesize())
+#define MDA_SIZE_MIN (8 * (unsigned) lvm_getpagesize())
 
 #endif

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	Mon Oct 23 08:49:10 2006
@@ -398,9 +398,9 @@
 	case LCK_VG:
 		/* If the VG name is empty then lock the unused PVs */
 		if (!*resource)
-			lvm_snprintf(lockname, sizeof(lockname), "P_orphans");
+			dm_snprintf(lockname, sizeof(lockname), "P_orphans");
 		else
-			lvm_snprintf(lockname, sizeof(lockname), "V_%s",
+			dm_snprintf(lockname, sizeof(lockname), "V_%s",
 				     resource);
 
 		cluster_cmd = CLVMD_CMD_LOCK_VG;

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	Mon Oct 23 08:49:10 2006
@@ -212,10 +212,10 @@
 	switch (flags & LCK_SCOPE_MASK) {
 	case LCK_VG:
 		if (!*resource)
-			lvm_snprintf(lockfile, sizeof(lockfile),
+			dm_snprintf(lockfile, sizeof(lockfile),
 				     "%s/P_orphans", _lock_dir);
 		else
-			lvm_snprintf(lockfile, sizeof(lockfile),
+			dm_snprintf(lockfile, sizeof(lockfile),
 				     "%s/V_%s", _lock_dir, resource);
 
 		if (!_lock_file(lockfile, flags))

Modified: lvm2/upstream/current/lib/locking/locking.c
==============================================================================
--- lvm2/upstream/current/lib/locking/locking.c	(original)
+++ lvm2/upstream/current/lib/locking/locking.c	Mon Oct 23 08:49:10 2006
@@ -20,6 +20,7 @@
 #include "activate.h"
 #include "toolcontext.h"
 #include "memlock.h"
+#include "defaults.h"
 
 #include <signal.h>
 #include <sys/stat.h>
@@ -134,24 +135,31 @@
 		return 1;
 
 	case 1:
+		log_very_verbose("File-based locking selected.");
 		if (!init_file_locking(&_locking, cmd))
 			break;
-		log_very_verbose("File-based locking enabled.");
 		return 1;
 
 #ifdef HAVE_LIBDL
 	case 2:
-		if (!init_external_locking(&_locking, cmd))
+		if (!cmd->is_static) {
+			log_very_verbose("External locking selected.");
+			if (init_external_locking(&_locking, cmd))
+				return 1;
+		}
+		if (!find_config_tree_int(cmd, "locking/fallback_to_clustered_locking",
+					  DEFAULT_FALLBACK_TO_CLUSTERED_LOCKING))
 			break;
-		log_very_verbose("External locking enabled.");
-		return 1;
 #endif
 
 #ifdef CLUSTER_LOCKING_INTERNAL
+		log_very_verbose("Falling back to internal clustered locking.");
+		/* Fall through */
+
 	case 3:
+		log_very_verbose("Cluster locking selected.");
 		if (!init_cluster_locking(&_locking, cmd))
 			break;
-		log_very_verbose("Cluster locking enabled.");
 		return 1;
 #endif
 
@@ -160,6 +168,16 @@
 		return 0;
 	}
 
+	if ((type == 2 || type == 3) &&
+            find_config_tree_int(cmd, "locking/fallback_to_local_locking",
+				 DEFAULT_FALLBACK_TO_LOCAL_LOCKING)) {
+		log_print("WARNING: Falling back to local file-based locking.");
+		log_print("Volume Groups with the clustered attribute will "
+			  "be inaccessible.");
+		if (init_file_locking(&_locking, cmd))
+			return 1;
+	}
+
 	if (!ignorelockingfailure())
 		return 0;
 
@@ -189,7 +207,7 @@
 	if (!*vgname)
 		return 1;
 
-	if (lvm_snprintf(path, sizeof(path), "%s/lvm/VGs/%s", cmd->proc_dir,
+	if (dm_snprintf(path, sizeof(path), "%s/lvm/VGs/%s", cmd->proc_dir,
 			 vgname) < 0) {
 		log_error("LVM1 proc VG pathname too long for %s", vgname);
 		return 0;

Modified: lvm2/upstream/current/lib/log/log.c
==============================================================================
--- lvm2/upstream/current/lib/log/log.c	(original)
+++ lvm2/upstream/current/lib/log/log.c	Mon Oct 23 08:49:10 2006
@@ -32,6 +32,7 @@
 static int _md_filtering = 0;
 static int _pvmove = 0;
 static int _full_scan_done = 0;	/* Restrict to one full scan during each cmd */
+static int _trust_cache = 0; /* Don't scan when incomplete VGs encountered */
 static int _debug_level = 0;
 static int _syslog = 0;
 static int _log_to_file = 0;
@@ -163,6 +164,11 @@
 	_full_scan_done = level;
 }
 
+void init_trust_cache(int trustcache)
+{
+	_trust_cache = trustcache;
+}
+
 void init_ignorelockingfailure(int level)
 {
 	_ignorelockingfailure = level;
@@ -237,6 +243,11 @@
 	return _full_scan_done;
 }
 
+int trust_cache()
+{
+	return _trust_cache;
+}
+
 int lockingfailed()
 {
 	return _lockingfailed;
@@ -307,7 +318,7 @@
       log_it:
 	if (!_log_suppress) {
 		if (_verbose_level > _LOG_DEBUG)
-			lvm_snprintf(locn, sizeof(locn), "#%s:%d ",
+			dm_snprintf(locn, sizeof(locn), "#%s:%d ",
 				     file, line);
 		else
 			locn[0] = '\0';
@@ -402,7 +413,7 @@
 		_already_logging = 1;
 		memset(&buf, ' ', sizeof(buf));
 		bufused = 0;
-		if ((n = lvm_snprintf(buf, sizeof(buf) - bufused - 1,
+		if ((n = dm_snprintf(buf, sizeof(buf) - bufused - 1,
 				      "%s:%d %s%s", file, line, _cmd_name,
 				      _msg_prefix)) == -1)
 			goto done;

Modified: lvm2/upstream/current/lib/log/log.h
==============================================================================
--- lvm2/upstream/current/lib/log/log.h	(original)
+++ lvm2/upstream/current/lib/log/log.h	Mon Oct 23 08:49:10 2006
@@ -66,6 +66,7 @@
 void init_md_filtering(int level);
 void init_pvmove(int level);
 void init_full_scan_done(int level);
+void init_trust_cache(int trustcache);
 void init_debug(int level);
 void init_cmd_name(int status);
 void init_msg_prefix(const char *prefix);
@@ -83,6 +84,7 @@
 int md_filtering(void);
 int pvmove_mode(void);
 int full_scan_done(void);
+int trust_cache(void);
 int debug_level(void);
 int ignorelockingfailure(void);
 int lockingfailed(void);

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	Mon Oct 23 08:49:10 2006
@@ -158,7 +158,7 @@
 	}
 
 	if (seg_lv(seg, s)->status & MIRROR_IMAGE) {
-		lv_reduce(seg_lv(seg, s), area_reduction);	
+		lv_reduce(seg_lv(seg, s), area_reduction);
 		return;
 	}
 
@@ -398,6 +398,7 @@
  * Details of an allocation attempt
  */
 struct alloc_handle {
+	struct cmd_context *cmd;
 	struct dm_pool *mem;
 
 	alloc_policy_t alloc;		/* Overall policy */
@@ -417,7 +418,8 @@
 /*
  * Preparation for a specific allocation attempt
  */
-static struct alloc_handle *_alloc_init(struct dm_pool *mem,
+static struct alloc_handle *_alloc_init(struct cmd_context *cmd,
+					struct dm_pool *mem,
 					const struct segment_type *segtype,
 					alloc_policy_t alloc,
 					uint32_t mirrors,
@@ -464,6 +466,8 @@
 	if (segtype_is_virtual(segtype))
 		return ah;
 
+	ah->cmd = cmd;
+
 	if (!(ah->mem = dm_pool_create("allocation", 1024))) {
 		log_error("allocation pool creation failed");
 		return NULL;
@@ -490,6 +494,49 @@
 		dm_pool_destroy(ah->mem);
 }
 
+static int _log_parallel_areas(struct dm_pool *mem, struct list *parallel_areas)
+{
+	struct seg_pvs *spvs;
+	struct pv_list *pvl;
+	char *pvnames;
+
+	if (!parallel_areas)
+		return 1;
+
+	if (!dm_pool_begin_object(mem, 256)) {
+		log_error("dm_pool_begin_object failed");
+		return 0;
+	}
+
+	list_iterate_items(spvs, parallel_areas) {
+		list_iterate_items(pvl, &spvs->pvs) {
+			if (!dm_pool_grow_object(mem, dev_name(pvl->pv->dev), strlen(dev_name(pvl->pv->dev)))) {
+				log_error("dm_pool_grow_object failed");
+				dm_pool_abandon_object(mem);
+				return 0;
+			}
+			if (!dm_pool_grow_object(mem, " ", 1)) {
+				log_error("dm_pool_grow_object failed");
+				dm_pool_abandon_object(mem);
+				return 0;
+			}
+		}
+
+		if (!dm_pool_grow_object(mem, "\0", 1)) {
+			log_error("dm_pool_grow_object failed");
+			dm_pool_abandon_object(mem);
+			return 0;
+		}
+
+		pvnames = dm_pool_end_object(mem);
+		log_debug("Parallel PVs at LE %" PRIu32 " length %" PRIu32 ": %s",
+			  spvs->le, spvs->len, pvnames);
+		dm_pool_free(mem, pvnames);
+	}
+
+	return 1;
+}
+
 static int _setup_alloced_segment(struct logical_volume *lv, uint32_t status,
 				  uint32_t area_count,
 				  uint32_t stripe_size,
@@ -614,7 +661,7 @@
 	if (log_area) {
 		ah->log_area.pv = log_area->map->pv;
 		ah->log_area.pe = log_area->start;
-		ah->log_area.len = 1;	/* FIXME Calculate & check this */
+		ah->log_area.len = MIRROR_LOG_SIZE;	/* FIXME Calculate & check this */
 		consume_pv_area(log_area, ah->log_area.len);
 	}
 
@@ -623,6 +670,82 @@
 	return 1;
 }
 
+/*
+ * Call fn for each AREA_PV used by the LV segment at lv:le of length *max_seg_len.
+ * If any constituent area contains more than one segment, max_seg_len is
+ * reduced to cover only the first.
+ * fn should return 0 on error, 1 to continue scanning or >1 to terminate without error.
+ * In the last case, this function passes on the return code.
+ */
+static int _for_each_pv(struct cmd_context *cmd, struct logical_volume *lv,
+			uint32_t le, uint32_t len, uint32_t *max_seg_len,
+			uint32_t first_area, uint32_t max_areas,
+			int top_level_area_index,
+			int only_single_area_segments,
+			int (*fn)(struct cmd_context *cmd,
+				  struct pv_segment *peg, uint32_t s,
+				  void *data),
+			void *data)
+{
+	struct lv_segment *seg;
+	uint32_t s;
+	uint32_t remaining_seg_len, area_len, area_multiple;
+	int r = 1;
+
+	if (!(seg = find_seg_by_le(lv, le))) {
+		log_error("Failed to find segment for %s extent %" PRIu32,
+			  lv->name, le);
+		return 0;
+	}
+
+	/* Remaining logical length of segment */
+	remaining_seg_len = seg->len - (le - seg->le);
+
+	if (remaining_seg_len > len)
+		remaining_seg_len = len;
+
+	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_len = remaining_seg_len / area_multiple ? : 1;
+
+	for (s = first_area;
+	     s < seg->area_count && (!max_areas || s <= max_areas);
+	     s++) {
+		if (seg_type(seg, s) == AREA_LV) {
+			if (!(r = _for_each_pv(cmd, seg_lv(seg, s),
+					       seg_le(seg, s) +
+					       (le - seg->le) / area_multiple,
+					       area_len, max_seg_len,
+					       only_single_area_segments ? 0 : 0,
+					       only_single_area_segments ? 1 : 0,
+					       top_level_area_index != -1 ? top_level_area_index : s,
+					       only_single_area_segments, fn,
+					       data)))
+				stack;
+		} else if (seg_type(seg, s) == AREA_PV)
+			if (!(r = fn(cmd, seg_pvseg(seg, s), top_level_area_index != -1 ? top_level_area_index : s, data)))
+				stack;
+		if (r != 1)
+			return r;
+	}
+
+	/* FIXME only_single_area_segments used as workaround to skip log LV - needs new param? */
+	if (!only_single_area_segments && seg_is_mirrored(seg) && seg->log_lv) {
+		if (!(r = _for_each_pv(cmd, seg->log_lv, 0, MIRROR_LOG_SIZE,
+				       NULL, 0, 0, 0, only_single_area_segments,
+				       fn, data)))
+			stack;
+		if (r != 1)
+			return r;
+	}
+
+	/* FIXME Add snapshot cow LVs etc. */
+
+	return 1;
+}
+
 static int _comp_area(const void *l, const void *r)
 {
 	const struct pv_area *lhs = *((const struct pv_area **) l);
@@ -638,32 +761,113 @@
 }
 
 /*
- * Is pva contiguous to any existing areas or on the same PV?
+ * Search for pvseg that matches condition
+ */
+struct pv_match {
+	int (*condition)(struct pv_segment *pvseg, struct pv_area *pva);
+
+	struct pv_area **areas;
+	struct pv_area *pva;
+	uint32_t areas_size;
+	int s;	/* Area index of match */
+};
+
+/*
+ * Is PV area on the same PV?
  */
-static int _check_contiguous(struct lv_segment *prev_lvseg,
-			     struct physical_volume *pv, struct pv_area *pva,
-			     struct pv_area **areas)
+static int _is_same_pv(struct pv_segment *pvseg, struct pv_area *pva)
 {
-	struct pv_segment *prev_pvseg;
-	uint32_t s;
+	if (pvseg->pv != pva->map->pv)
+		return 0;
 
-	for (s = 0; s < prev_lvseg->area_count; s++) {
-		if (seg_type(prev_lvseg, s) != AREA_PV)
-			continue;	/* FIXME Broken */
+	return 1;
+}
 
-		if (!(prev_pvseg = seg_pvseg(prev_lvseg, s)))
-			continue; /* FIXME Broken */
+/*
+ * Is PV area contiguous to PV segment?
+ */
+static int _is_contiguous(struct pv_segment *pvseg, struct pv_area *pva)
+{
+	if (pvseg->pv != pva->map->pv)
+		return 0;
 
-		if ((prev_pvseg->pv != pv))
-			continue;
+	if (pvseg->pe + pvseg->len != pva->start)
+		return 0;
 
-		if (prev_pvseg->pe + prev_pvseg->len == pva->start) {
-			areas[s] = pva;
-			return 1;
-		}
-	}
+	return 1;
+}
 
-	return 0;
+static int _is_condition(struct cmd_context *cmd,
+			 struct pv_segment *pvseg, uint32_t s,
+			 void *data)
+{
+	struct pv_match *pvmatch = data;
+
+	if (!pvmatch->condition(pvseg, pvmatch->pva))
+		return 1;	/* Continue */
+
+	if (s >= pvmatch->areas_size)
+		return 1;
+
+	pvmatch->areas[s] = pvmatch->pva;
+
+	return 2;	/* Finished */
+}
+
+/*
+ * Is pva on same PV as any existing areas?
+ */
+static int _check_cling(struct cmd_context *cmd,
+			struct lv_segment *prev_lvseg, struct pv_area *pva,
+			struct pv_area **areas, uint32_t areas_size)
+{
+	struct pv_match pvmatch;
+	int r;
+
+	pvmatch.condition = _is_same_pv;
+	pvmatch.areas = areas;
+	pvmatch.areas_size = areas_size;
+	pvmatch.pva = pva;
+
+	/* FIXME Cope with stacks by flattening */
+	if (!(r = _for_each_pv(cmd, prev_lvseg->lv,
+			       prev_lvseg->le + prev_lvseg->len - 1, 1, NULL,
+			       0, 0, -1, 1,
+			       _is_condition, &pvmatch)))
+		stack;
+
+	if (r != 2)
+		return 0;
+
+	return 1;
+}
+
+/*
+ * Is pva contiguous to any existing areas or on the same PV?
+ */
+static int _check_contiguous(struct cmd_context *cmd,
+			     struct lv_segment *prev_lvseg, struct pv_area *pva,
+			     struct pv_area **areas, uint32_t areas_size)
+{
+	struct pv_match pvmatch;
+	int r;
+
+	pvmatch.condition = _is_contiguous;
+	pvmatch.areas = areas;
+	pvmatch.areas_size = areas_size;
+	pvmatch.pva = pva;
+
+	/* FIXME Cope with stacks by flattening */
+	if (!(r = _for_each_pv(cmd, prev_lvseg->lv,
+			       prev_lvseg->le + prev_lvseg->len - 1, 1, NULL,
+			       0, 0, -1, 1,
+			       _is_condition, &pvmatch)))
+		stack;
+
+	if (r != 2)
+		return 0;
+
+	return 1;
 }
 
 /*
@@ -679,9 +883,9 @@
 	struct pv_area *pva;
 	struct pv_list *pvl;
 	unsigned already_found_one = 0;
-	unsigned contiguous = 0, contiguous_count = 0;
+	unsigned contiguous = 0, cling = 0, preferred_count = 0;
 	unsigned ix;
-	unsigned ix_offset = 0;	/* Offset for non-contiguous allocations */
+	unsigned ix_offset = 0;	/* Offset for non-preferred allocations */
 	uint32_t max_parallel;	/* Maximum extents to allocate */
 	uint32_t next_le;
 	struct seg_pvs *spvs;
@@ -691,9 +895,14 @@
 	/* FIXME Select log PV appropriately if there isn't one yet */
 
 	/* Are there any preceding segments we must follow on from? */
-	if ((alloc == ALLOC_CONTIGUOUS) && prev_lvseg) {
-		contiguous = 1;
+	if (prev_lvseg) {
 		ix_offset = prev_lvseg->area_count;
+		if ((alloc == ALLOC_CONTIGUOUS))
+			contiguous = 1;
+		else if ((alloc == ALLOC_CLING))
+			cling = 1;
+		else
+			ix_offset = 0;
 	}
 
 	/* FIXME This algorithm needs a lot of cleaning up! */
@@ -702,6 +911,7 @@
 	/* ix holds the number of areas found on other PVs */
 	do {
 		ix = 0;
+		preferred_count = 0;
 
 		parallel_pvs = NULL;
 		max_parallel = needed;
@@ -711,14 +921,15 @@
 		 * the maximum we can allocate in one go accordingly.
 		 */
 		if (ah->parallel_areas) {
+			next_le = (prev_lvseg ? prev_lvseg->le + prev_lvseg->len : 0) + *allocated / ah->area_multiple;
 			list_iterate_items(spvs, ah->parallel_areas) {
-				next_le = (prev_lvseg ? prev_lvseg->le + prev_lvseg->len : 0) + *allocated;
-				if (next_le >= spvs->le) {
-					if (next_le + max_parallel > spvs->le + spvs->len)
-						max_parallel = (spvs->le + spvs->len - next_le) * ah->area_multiple;
-					parallel_pvs = &spvs->pvs;
-					break;
-				}
+				if (next_le >= spvs->le + spvs->len)
+					continue;
+
+				if (max_parallel > (spvs->le + spvs->len) * ah->area_multiple)
+					max_parallel = (spvs->le + spvs->len) * ah->area_multiple;
+				parallel_pvs = &spvs->pvs;
+				break;
 			}
 		}
 
@@ -750,17 +961,30 @@
 			list_iterate_items(pva, &pvm->areas) {
 				if (contiguous) {
 					if (prev_lvseg &&
-					    _check_contiguous(prev_lvseg,
-							      pvm->pv,
-							      pva, areas)) {
-						contiguous_count++;
+					    _check_contiguous(ah->cmd,
+							      prev_lvseg,
+							      pva, areas,
+							      areas_size)) {
+						preferred_count++;
 						goto next_pv;
 					}
 					continue;
 				}
 
+				if (cling) {
+					if (prev_lvseg &&
+					    _check_cling(ah->cmd,
+							   prev_lvseg,
+							   pva, areas,
+							   areas_size)) {
+						preferred_count++;
+					}
+					goto next_pv;
+				}
+
 				/* Is it big enough on its own? */
-				if ((pva->count < max_parallel - *allocated) &&
+				if (pva->count * ah->area_multiple <
+				    max_parallel - *allocated &&
 				    ((!can_split && !ah->log_count) ||
 				     (already_found_one &&
 				      !(alloc == ALLOC_ANYWHERE))))
@@ -781,7 +1005,7 @@
 				break;
 		}
 
-		if (contiguous && (contiguous_count < ix_offset))
+		if ((contiguous || cling) && (preferred_count < ix_offset))
 			break;
 
 		/* Only allocate log_area the first time around */
@@ -853,6 +1077,9 @@
 		return 0;
 	}
 
+	if (!_log_parallel_areas(ah->mem, ah->parallel_areas))
+		stack;
+
 	areas_size = list_size(pvms);
 	if (areas_size < ah->area_count + ah->log_count) {
 		if (ah->alloc != ALLOC_ANYWHERE) {
@@ -888,6 +1115,18 @@
 		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)) {
@@ -982,7 +1221,7 @@
 	if (alloc == ALLOC_INHERIT)
 		alloc = vg->alloc;
 
-	if (!(ah = _alloc_init(vg->cmd->mem, segtype, alloc, mirrors,
+	if (!(ah = _alloc_init(vg->cmd, vg->cmd->mem, segtype, alloc, mirrors,
 			       stripes, log_count, mirrored_pv,
 			       mirrored_pe, parallel_areas))) {
 		stack;
@@ -1213,7 +1452,7 @@
 				log_error("Aborting. Failed to extend %s.",
 					  seg_lv(seg, m)->name);
 				return 0;
-                	}
+			}
 		}
 		seg->area_len += extents;
 		seg->len += extents;
@@ -1240,7 +1479,7 @@
 			high = i;
 	}
 
-	if (lvm_snprintf(buffer, len, format, high + 1) < 0)
+	if (dm_snprintf(buffer, len, format, high + 1) < 0)
 		return NULL;
 
 	return buffer;
@@ -1326,58 +1565,16 @@
 	return lv;
 }
 
-/* Recursively process each PV used by part of an LV */
-static int _for_each_pv(struct cmd_context *cmd, struct logical_volume *lv,
-			uint32_t le, uint32_t len,
-			int (*fn)(struct cmd_context *cmd, struct pv_segment *peg, struct seg_pvs *spvs),
-			struct seg_pvs *spvs)
-{
-	struct lv_segment *seg;
-	uint32_t s;
-	uint32_t remaining_seg_len, area_len, area_multiple;
-
-	if (!(seg = find_seg_by_le(lv, le))) {
-		log_error("Failed to find segment for %s extent %" PRIu32,
-			  lv->name, le);
-		return 0;
-	}
-
-	/* Remaining logical length of segment */
-	remaining_seg_len = seg->len - (le - seg->le);
-
-	if (len > remaining_seg_len)
-		remaining_seg_len = len;
-
-	if (spvs->len > remaining_seg_len)
-		spvs->len = remaining_seg_len;
-
-	area_multiple = segtype_is_striped(seg->segtype) ? seg->area_count : 1;
-	area_len = remaining_seg_len / area_multiple;
-
-	for (s = 0; s < seg->area_count; s++) {
-		if (seg_type(seg, s) == AREA_LV) {
-			if (!_for_each_pv(cmd, seg_lv(seg, s),
-					  seg_le(seg, s) + (le - seg->le) / area_multiple,
-					  area_len, fn, spvs)) {
-				stack;
-				return 0;
-			}
-		} else if (seg_type(seg, s) == AREA_PV) {
-			if (!fn(cmd, seg_pvseg(seg, s), spvs)) {
-				stack;
-				return 0;
-			}
-		}
-	}
-
-	return 1;
-}
-
-static int _add_pvs(struct cmd_context *cmd, struct pv_segment *peg, struct seg_pvs *spvs)
+static int _add_pvs(struct cmd_context *cmd, struct pv_segment *peg,
+		    uint32_t s __attribute((unused)), void *data)
 {
+	struct seg_pvs *spvs = (struct seg_pvs *) data;
 	struct pv_list *pvl;
 
-	/* FIXME Don't add again if it's already on the list! */
+	/* Don't add again if it's already on list. */
+	list_iterate_items(pvl, &spvs->pvs)
+		if (pvl->pv == peg->pv)
+			return 1;
 
 	if (!(pvl = dm_pool_alloc(cmd->mem, sizeof(*pvl)))) {
 		log_error("pv_list allocation failed");
@@ -1386,11 +1583,8 @@
 
 	pvl->pv = peg->pv;
 
-	/* FIXME Use ordered list to facilitate comparison */
 	list_add(&spvs->pvs, &pvl->list);
 
-	/* FIXME Add mirror logs, snapshot cow LVs etc. */
-
 	return 1;
 }
 
@@ -1426,7 +1620,8 @@
 
 		/* Find next segment end */
 		/* FIXME Unnecessary nesting! */
-		if (!_for_each_pv(cmd, lv, current_le, lv->le_count, _add_pvs, spvs)) {
+		if (!_for_each_pv(cmd, lv, current_le, spvs->len, &spvs->len,
+				  0, 0, -1, 0, _add_pvs, (void *) spvs)) {
 			stack;
 			return NULL;
 		}

Modified: lvm2/upstream/current/lib/metadata/metadata.c
==============================================================================
--- lvm2/upstream/current/lib/metadata/metadata.c	(original)
+++ lvm2/upstream/current/lib/metadata/metadata.c	Mon Oct 23 08:49:10 2006
@@ -24,6 +24,13 @@
 #include "pv_alloc.h"
 #include "activate.h"
 
+#include <sys/param.h>
+
+unsigned long pe_align(void)
+{
+	return MAX(65536UL, lvm_getpagesize()) >> SECTOR_SHIFT;
+}
+
 static int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg,
 			 const char *pv_name)
 {
@@ -78,15 +85,12 @@
 
 	/* FIXME Do proper rounding-up alignment? */
 	/* Reserved space for label; this holds 0 for PVs created by LVM1 */
-	if (pv->pe_start < PE_ALIGN)
-		pv->pe_start = PE_ALIGN;
+	if (pv->pe_start < pe_align())
+		pv->pe_start = pe_align();
 
 	/*
-	 * The next two fields should be corrected
-	 * by fid->pv_setup.
+	 * pe_count must always be calculated by pv_setup
 	 */
-	pv->pe_count = (pv->size - pv->pe_start) / vg->extent_size;
-
 	pv->pe_alloc_count = 0;
 
 	if (!fid->fmt->ops->pv_setup(fid->fmt, UINT64_C(0), 0,
@@ -722,23 +726,70 @@
 
 int vg_validate(struct volume_group *vg)
 {
-	struct lv_list *lvl;
+	struct pv_list *pvl, *pvl2;
+	struct lv_list *lvl, *lvl2;
+	char uuid[64];
+	int r = 1;
+
+	/* FIXME Also check there's no data/metadata overlap */
+
+	list_iterate_items(pvl, &vg->pvs) {
+		list_iterate_items(pvl2, &vg->pvs) {
+			if (pvl == pvl2)
+				break;
+			if (id_equal(&pvl->pv->id,
+				     &pvl2->pv->id)) {
+				if (!id_write_format(&pvl->pv->id, uuid,
+						     sizeof(uuid)))
+					 stack;
+				log_error("Internal error: Duplicate PV id "
+					  "%s detected for %s in %s.",
+					  uuid, dev_name(pvl->pv->dev),
+					  vg->name);
+				r = 0;
+			}
+		}
+	}
 
 	if (!check_pv_segments(vg)) {
 		log_error("Internal error: PV segments corrupted in %s.",
 			  vg->name);
-		return 0;
+		r = 0;
+	}
+
+	list_iterate_items(lvl, &vg->lvs) {
+		list_iterate_items(lvl2, &vg->lvs) {
+			if (lvl == lvl2)
+				break;
+			if (!strcmp(lvl->lv->name, lvl2->lv->name)) {
+				log_error("Internal error: Duplicate LV name "
+					  "%s detected in %s.", lvl->lv->name,
+					  vg->name);
+				r = 0;
+			}
+			if (id_equal(&lvl->lv->lvid.id[1],
+				     &lvl2->lv->lvid.id[1])) {
+				if (!id_write_format(&lvl->lv->lvid.id[1], uuid,
+						     sizeof(uuid)))
+					 stack;
+				log_error("Internal error: Duplicate LV id "
+					  "%s detected for %s and %s in %s.",
+					  uuid, lvl->lv->name, lvl2->lv->name,
+					  vg->name);
+				r = 0;
+			}
+		}
 	}
 
 	list_iterate_items(lvl, &vg->lvs) {
 		if (!check_lv_segments(lvl->lv, 1)) {
 			log_error("Internal error: LV segments corrupted in %s.",
 				  lvl->lv->name);
-			return 0;
+			r = 0;
 		}
 	}
 
-	return 1;
+	return r;
 }
 
 /*
@@ -992,7 +1043,7 @@
 	if (correct_vg) {
 		if (list_size(&correct_vg->pvs) != list_size(pvids)) {
 			log_debug("Cached VG %s had incorrect PV list",
-				  vg->name);
+				  vgname);
 
 			if (memlock())
 				inconsistent = 1;
@@ -1001,7 +1052,7 @@
 		} else list_iterate_items(pvl, &correct_vg->pvs) {
 			if (!str_list_match_item(pvids, pvl->pv->dev->pvid)) {
 				log_debug("Cached VG %s had incorrect PV list",
-					  vg->name);
+					  vgname);
 				correct_vg = NULL;
 				break;
 			}

Modified: lvm2/upstream/current/lib/metadata/metadata.h
==============================================================================
--- lvm2/upstream/current/lib/metadata/metadata.h	(original)
+++ lvm2/upstream/current/lib/metadata/metadata.h	Mon Oct 23 08:49:10 2006
@@ -29,12 +29,12 @@
 #define MAX_STRIPES 128U
 #define SECTOR_SHIFT 9L
 #define SECTOR_SIZE ( 1L << SECTOR_SHIFT )
-#define STRIPE_SIZE_MIN ( (unsigned) getpagesize() >> SECTOR_SHIFT)	/* PAGESIZE in sectors */
+#define STRIPE_SIZE_MIN ( (unsigned) lvm_getpagesize() >> SECTOR_SHIFT)	/* PAGESIZE in sectors */
 #define STRIPE_SIZE_MAX ( 512L * 1024L >> SECTOR_SHIFT)	/* 512 KB in sectors */
 #define STRIPE_SIZE_LIMIT ((UINT_MAX >> 2) + 1)
 #define PV_MIN_SIZE ( 512L * 1024L >> SECTOR_SHIFT)	/* 512 KB in sectors */
-#define PE_ALIGN (65536UL >> SECTOR_SHIFT)	/* PE alignment */
 #define MAX_RESTRICTED_LVS 255	/* Used by FMT_RESTRICTED_LVIDS */
+#define MIRROR_LOG_SIZE 1	/* Extents */
 
 /* Various flags */
 /* Note that the bits no longer necessarily correspond to LVM1 disk format */
@@ -82,6 +82,7 @@
 	ALLOC_INVALID = 0,
 	ALLOC_INHERIT,
 	ALLOC_CONTIGUOUS,
+	ALLOC_CLING,
 	ALLOC_NORMAL,
 	ALLOC_ANYWHERE
 } alloc_policy_t;
@@ -403,6 +404,7 @@
 /*
  * Utility functions
  */
+unsigned long pe_align(void);
 int vg_validate(struct volume_group *vg);
 int vg_write(struct volume_group *vg);
 int vg_commit(struct volume_group *vg);

Modified: lvm2/upstream/current/lib/metadata/mirror.c
==============================================================================
--- lvm2/upstream/current/lib/metadata/mirror.c	(original)
+++ lvm2/upstream/current/lib/metadata/mirror.c	Mon Oct 23 08:49:10 2006
@@ -161,9 +161,11 @@
 		remove_log = 1;
 	}
 
-	if (remove_log) {
+	if (remove_log && mirrored_seg->log_lv) {
 		log_lv = mirrored_seg->log_lv;
 		mirrored_seg->log_lv = NULL;
+		log_lv->status &= ~MIRROR_LOG;
+		log_lv->status |= VISIBLE_LV;
 	}
 
 	/*
@@ -199,6 +201,12 @@
 
 	/* Delete the 'orphan' LVs */
 	for (m = num_mirrors; m < old_area_count; m++) {
+		/* LV is now independent of the mirror so must acquire lock. */
+		if (!activate_lv(mirrored_seg->lv->vg->cmd, seg_lv(mirrored_seg, m))) {
+			stack;
+			return 0;
+		}
+
 		if (!deactivate_lv(mirrored_seg->lv->vg->cmd, seg_lv(mirrored_seg, m))) {
 			stack;
 			return 0;
@@ -211,6 +219,11 @@
 	}
 
 	if (lv1) {
+		if (!activate_lv(mirrored_seg->lv->vg->cmd, lv1)) {
+			stack;
+			return 0;
+		}
+
 		if (!deactivate_lv(mirrored_seg->lv->vg->cmd, lv1)) {
 			stack;
 			return 0;
@@ -223,6 +236,11 @@
 	}
 
 	if (log_lv) {
+		if (!activate_lv(mirrored_seg->lv->vg->cmd, log_lv)) {
+			stack;
+			return 0;
+		}
+
 		if (!deactivate_lv(mirrored_seg->lv->vg->cmd, log_lv)) {
 			stack;
 			return 0;
@@ -412,7 +430,7 @@
 		return 0;
 	}
 
-	if (lvm_snprintf(img_name, len, "%s_mimage_%%d", lv->name) < 0) {
+	if (dm_snprintf(img_name, len, "%s_mimage_%%d", lv->name) < 0) {
 		log_error("img_name allocation failed. "
 			  "Remove new LV and retry.");
 		return 0;

Modified: lvm2/upstream/current/lib/metadata/segtype.h
==============================================================================
--- lvm2/upstream/current/lib/metadata/segtype.h	(original)
+++ lvm2/upstream/current/lib/metadata/segtype.h	Mon Oct 23 08:49:10 2006
@@ -77,6 +77,9 @@
 			       uint64_t *total_numerator,
 			       uint64_t *total_denominator, float *percent);
 	int (*target_present) (void);
+	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);

Modified: lvm2/upstream/current/lib/mirror/mirrored.c
==============================================================================
--- lvm2/upstream/current/lib/mirror/mirrored.c	(original)
+++ lvm2/upstream/current/lib/mirror/mirrored.c	Mon Oct 23 08:49:10 2006
@@ -26,6 +26,7 @@
 #include "targets.h"
 #include "activate.h"
 #include "sharedlib.h"
+#include "str_list.h"
 
 #ifdef DMEVENTD
 #  include <libdevmapper-event.h>
@@ -447,6 +448,28 @@
 #endif /* DMEVENTD */
 #endif /* DEVMAPPER_SUPPORT */
 
+static int _mirrored_modules_needed(struct dm_pool *mem,
+				    const struct lv_segment *seg,
+				    struct list *modules)
+{
+	if (seg->log_lv &&
+	    !list_segment_modules(mem, first_seg(seg->log_lv), modules))
+		return_0;
+
+	if ((seg->lv->vg->status & CLUSTERED) &&
+	    !str_list_add(mem, modules, "clog")) {
+		log_error("cluster log string list allocation failed");
+		return 0;
+	}
+
+	if (!str_list_add(mem, modules, "mirror")) {
+		log_error("mirror string list allocation failed");
+		return 0;
+	}
+
+	return 1;
+}
+
 static void _mirrored_destroy(const struct segment_type *segtype)
 {
 	dm_free((void *) segtype);
@@ -467,6 +490,7 @@
 	.target_unregister_events = _target_unregister_events,
 #endif
 #endif
+	.modules_needed = _mirrored_modules_needed,
 	.destroy = _mirrored_destroy,
 };
 

Modified: lvm2/upstream/current/lib/misc/configure.h.in
==============================================================================
--- lvm2/upstream/current/lib/misc/configure.h.in	(original)
+++ lvm2/upstream/current/lib/misc/configure.h.in	Mon Oct 23 08:49:10 2006
@@ -174,6 +174,9 @@
 /* Define to 1 if you have the <selinux/selinux.h> header file. */
 #undef HAVE_SELINUX_SELINUX_H
 
+/* define to 1 to include support for realtime clock */
+#undef HAVE_REALTIME
+
 /* Define to 1 if you have the `setlocale' function. */
 #undef HAVE_SETLOCALE
 

Modified: lvm2/upstream/current/lib/misc/lib.h
==============================================================================
--- lvm2/upstream/current/lib/misc/lib.h	(original)
+++ lvm2/upstream/current/lib/misc/lib.h	Mon Oct 23 08:49:10 2006
@@ -28,6 +28,7 @@
 #include "log.h"
 #include "intl.h"
 #include "lvm-types.h"
+#include "lvm-wrappers.h"
 
 #include <libdevmapper.h>
 

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	Mon Oct 23 08:49:10 2006
@@ -50,7 +50,7 @@
 
 	for (i = 0; i < 20; i++, num++) {
 
-		if (lvm_snprintf(buffer, len, "%s/.lvm_%s_%d_%d",
+		if (dm_snprintf(buffer, len, "%s/.lvm_%s_%d_%d",
 				 dir, hostname, pid, num) == -1) {
 			log_err("Not enough space to build temporary file "
 				"string.");

Modified: lvm2/upstream/current/lib/misc/lvm-string.c
==============================================================================
--- lvm2/upstream/current/lib/misc/lvm-string.c	(original)
+++ lvm2/upstream/current/lib/misc/lvm-string.c	Mon Oct 23 08:49:10 2006
@@ -14,33 +14,10 @@
  */
 
 #include "lib.h"
-#include "lvm-types.h"
 #include "lvm-string.h"
 
 #include <ctype.h>
 
-/*
- * On error, up to glibc 2.0.6, snprintf returned -1 if buffer was too small;
- * From glibc 2.1 it returns number of chars (excl. trailing null) that would 
- * have been written had there been room.
- *
- * lvm_snprintf reverts to the old behaviour.
- */
-int lvm_snprintf(char *buf, size_t bufsize, const char *format, ...)
-{
-	int n;
-	va_list ap;
-
-	va_start(ap, format);
-	n = vsnprintf(buf, bufsize, format, ap);
-	va_end(ap);
-
-	if (n < 0 || (n > bufsize - 1))
-		return -1;
-
-	return n;
-}
-
 int emit_to_buffer(char **buffer, size_t *size, const char *fmt, ...)
 {
 	int n;
@@ -59,47 +36,6 @@
 }
 
 /*
- * consume characters while they match the predicate function.
- */
-static char *_consume(char *buffer, int (*fn) (int))
-{
-	while (*buffer && fn(*buffer))
-		buffer++;
-
-	return buffer;
-}
-
-static int _isword(int c)
-{
-	return !isspace(c);
-}
-
-/*
- * Split buffer into NULL-separated words in argv.
- * Returns number of words.
- */
-int split_words(char *buffer, unsigned max, char **argv)
-{
-	unsigned arg;
-
-	for (arg = 0; arg < max; arg++) {
-		buffer = _consume(buffer, isspace);
-		if (!*buffer)
-			break;
-
-		argv[arg] = buffer;
-		buffer = _consume(buffer, _isword);
-
-		if (*buffer) {
-			*buffer = '\0';
-			buffer++;
-		}
-	}
-
-	return arg;
-}
-
-/*
  * Device layer names are all of the form <vg>-<lv>-<layer>, any
  * other hyphens that appear in these names are quoted with yet
  * another hyphen.  The top layer of any device has no layer
@@ -169,47 +105,6 @@
 	return r;
 }
 
-/*
- * Remove hyphen quoting from a component of a name.
- * NULL-terminates the component and returns start of next component.
- */
-static char *_unquote(char *component)
-{
-	char *c = component;
-	char *o = c;
-	char *r;
-
-	while (*c) {
-		if (*(c + 1)) {
-			if (*c == '-') {
-				if (*(c + 1) == '-')
-					c++;
-				else
-					break;
-			}
-		}
-		*o = *c;
-		o++;
-		c++;
-	}
-
-	r = (*c) ? c + 1 : c;
-	*o = '\0';
-
-	return r;
-}
-
-int split_dm_name(struct dm_pool *mem, const char *dmname,
-		  char **vgname, char **lvname, char **layer)
-{
-	if (!(*vgname = dm_pool_strdup(mem, dmname)))
-		return 0;
-
-	_unquote(*layer = _unquote(*lvname = _unquote(*vgname)));
-
-	return 1;
-}
-
 int validate_name(const char *n)
 {
 	register char c;

Modified: lvm2/upstream/current/lib/misc/lvm-string.h
==============================================================================
--- lvm2/upstream/current/lib/misc/lvm-string.h	(original)
+++ lvm2/upstream/current/lib/misc/lvm-string.h	Mon Oct 23 08:49:10 2006
@@ -23,25 +23,11 @@
 
 struct pool;
 
-/*
- * On error, up to glibc 2.0.6, snprintf returned -1 if buffer was too small;
- * From glibc 2.1 it returns number of chars (excl. trailing null) that would 
- * have been written had there been room.
- *
- * lvm_snprintf reverts to the old behaviour.
- */
-int lvm_snprintf(char *buf, size_t bufsize, const char *format, ...);
-
 int emit_to_buffer(char **buffer, size_t *size, const char *fmt, ...);
 
-int split_words(char *buffer, unsigned max, char **argv);
-
 char *build_dm_name(struct dm_pool *mem, const char *vg,
                     const char *lv, const char *layer);
 
-int split_dm_name(struct dm_pool *mem, const char *dmname,
-                  char **vgname, char **lvname, char **layer);
-
 int validate_name(const char *n);
 
 #endif

Added: lvm2/upstream/current/lib/misc/lvm-wrappers.c
==============================================================================
--- (empty file)
+++ lvm2/upstream/current/lib/misc/lvm-wrappers.c	Mon Oct 23 08:49:10 2006
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of 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
+ */
+
+#include "lib.h"
+
+#include <unistd.h>
+
+int lvm_getpagesize(void)
+{
+	return getpagesize();
+}

Added: lvm2/upstream/current/lib/misc/lvm-wrappers.h
==============================================================================
--- (empty file)
+++ lvm2/upstream/current/lib/misc/lvm-wrappers.h	Mon Oct 23 08:49:10 2006
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.  
+ * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of 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
+ */
+
+#ifndef _LVM_WRAPPERS_H
+#define _LVM_WRAPPERS_H
+
+int lvm_getpagesize(void);
+
+#endif

Modified: lvm2/upstream/current/lib/misc/sharedlib.c
==============================================================================
--- lvm2/upstream/current/lib/misc/sharedlib.c	(original)
+++ lvm2/upstream/current/lib/misc/sharedlib.c	Mon Oct 23 08:49:10 2006
@@ -17,6 +17,7 @@
 #include "config.h"
 #include "lvm-string.h"
 #include "sharedlib.h"
+#include "toolcontext.h"
 
 #include <limits.h>
 #include <sys/stat.h>
@@ -32,7 +33,7 @@
 	 * if present */
 	if (libname[0] == '/' ||
 	    !(lib_dir = find_config_tree_str(cmd, "global/library_dir", 0)) ||
-	    (lvm_snprintf(path, path_len, "%s/%s", lib_dir,
+	    (dm_snprintf(path, path_len, "%s/%s", lib_dir,
 			  libname) == -1) || stat(path, &info) == -1)
 		strncpy(path, libname, path_len);
 }
@@ -43,6 +44,12 @@
 	char path[PATH_MAX];
 	void *library;
 
+	if (cmd->is_static) {
+		log_error("Not loading shared %s library %s in static mode.",
+			  desc, libname);
+		return NULL;
+	}
+
 	get_shared_library_path(cmd, libname, path, sizeof(path));
 
 	log_very_verbose("Opening shared %s library %s", desc, path);

Added: lvm2/upstream/current/lib/misc/timestamp.c
==============================================================================
--- (empty file)
+++ lvm2/upstream/current/lib/misc/timestamp.c	Mon Oct 23 08:49:10 2006
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2006 Rackable Systems All rights reserved.
+ *
+ * This file is part of 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
+ */
+
+/*
+ * Abstract out the time methods used so they can be adjusted later -
+ * the results of these routines should stay in-core.  This implementation
+ * requires librt.
+ */
+
+#include "lib.h"
+#include <stdlib.h>
+
+#include "timestamp.h"
+
+/*
+ * The realtime section uses clock_gettime with the CLOCK_MONOTONIC
+ * parameter to prevent issues with time warps
+ */
+#ifdef HAVE_REALTIME
+
+#include <time.h>
+#include <bits/time.h>
+
+struct timestamp {
+	struct timespec t;
+};
+
+struct timestamp *get_timestamp(void)
+{
+	struct timestamp *ts = NULL;
+
+	if (!(ts = dm_malloc(sizeof(*ts))))
+		return_NULL;
+
+	if (clock_gettime(CLOCK_MONOTONIC, &ts->t)) {
+		log_sys_error("clock_gettime", "get_timestamp");
+		return NULL;
+	}
+
+	return ts;
+}
+
+/* cmp_timestamp: Compare two timestamps
+ *
+ * Return: -1 if t1 is less than t2
+ *          0 if t1 is equal to t2
+ *          1 if t1 is greater than t2
+ */
+int cmp_timestamp(struct timestamp *t1, struct timestamp *t2)
+{
+	if(t1->t.tv_sec < t2->t.tv_sec)
+		return -1;
+	if(t1->t.tv_sec > t2->t.tv_sec)
+		return 1;
+
+	if(t1->t.tv_nsec < t2->t.tv_nsec)
+		return -1;
+	if(t1->t.tv_nsec > t2->t.tv_nsec)
+		return 1;
+
+	return 0;
+}
+
+#else /* ! HAVE_REALTIME */
+
+/*
+ * The !realtime section just uses gettimeofday and is therefore subject
+ * to ntp-type time warps - not sure if should allow that.
+ */
+
+#include <sys/time.h>
+
+struct timestamp {
+	struct timeval t;
+};
+
+struct timestamp *get_timestamp(void)
+{
+	struct timestamp *ts = NULL;
+
+	if (!(ts = dm_malloc(sizeof(*ts))))
+		return_NULL;
+
+	if (gettimeofday(&ts->t, NULL)) {
+		log_sys_error("gettimeofday", "get_timestamp");
+		return NULL;
+	}
+
+	return ts;
+}
+
+/* cmp_timestamp: Compare two timestamps
+ *
+ * Return: -1 if t1 is less than t2
+ *          0 if t1 is equal to t2
+ *          1 if t1 is greater than t2
+ */
+int cmp_timestamp(struct timestamp *t1, struct timestamp *t2)
+{
+	if(t1->t.tv_sec < t2->t.tv_sec)
+		return -1;
+	if(t1->t.tv_sec > t2->t.tv_sec)
+		return 1;
+
+	if(t1->t.tv_usec < t2->t.tv_usec)
+		return -1;
+	if(t1->t.tv_usec > t2->t.tv_usec)
+		return 1;
+
+	return 0;
+}
+
+#endif /* HAVE_REALTIME */
+
+void destroy_timestamp(struct timestamp *t)
+{
+	if (t)
+		dm_free(t);
+}

Added: lvm2/upstream/current/lib/misc/timestamp.h
==============================================================================
--- (empty file)
+++ lvm2/upstream/current/lib/misc/timestamp.h	Mon Oct 23 08:49:10 2006
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2006 Rackable Systems All rights reserved.  
+ *
+ * This file is part of 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
+ */
+
+#ifndef _LVM_TIMESTAMP_H
+#define _LVM_TIMESTAMP_H
+
+struct timestamp;
+
+struct timestamp *get_timestamp(void);
+
+/* cmp_timestamp: Compare two timestamps
+ * 
+ * Return: -1 if t1 is less than t2
+ *  	    0 if t1 is equal to t2
+ *          1 if t1 is greater than t2
+ */
+int cmp_timestamp(struct timestamp *t1, struct timestamp *t2);
+
+void destroy_timestamp(struct timestamp *t);
+
+#endif /* _LVM_TIMESTAMP_H */
+

Modified: lvm2/upstream/current/lib/mm/memlock.c
==============================================================================
--- lvm2/upstream/current/lib/mm/memlock.c	(original)
+++ lvm2/upstream/current/lib/mm/memlock.c	Mon Oct 23 08:49:10 2006
@@ -58,7 +58,7 @@
 
 static void _touch_memory(void *mem, size_t size)
 {
-	size_t pagesize = getpagesize();
+	size_t pagesize = lvm_getpagesize();
 	void *pos = mem;
 	void *end = mem + size - sizeof(long);
 

Modified: lvm2/upstream/current/lib/report/columns.h
==============================================================================
--- lvm2/upstream/current/lib/report/columns.h	(original)
+++ lvm2/upstream/current/lib/report/columns.h	Mon Oct 23 08:49:10 2006
@@ -33,6 +33,7 @@
 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(PVS, pv, STR, "Fmt", id, 3, pvfmt, "pv_fmt")
 FIELD(PVS, pv, STR, "PV UUID", id, 38, uuid, "pv_uuid")
@@ -68,8 +69,11 @@
 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")

Modified: lvm2/upstream/current/lib/report/report.c
==============================================================================
--- lvm2/upstream/current/lib/report/report.c	(original)
+++ lvm2/upstream/current/lib/report/report.c	Mon Oct 23 08:49:10 2006
@@ -21,6 +21,7 @@
 #include "display.h"
 #include "activate.h"
 #include "segtype.h"
+#include "str_list.h"
 
 /* 
  * For macro use
@@ -103,6 +104,8 @@
 	switch (alloc) {
 	case ALLOC_CONTIGUOUS:
 		return 'c';
+	case ALLOC_CLING:
+		return 'C';
 	case ALLOC_NORMAL:
 		return 'n';
 	case ALLOC_ANYWHERE:
@@ -172,9 +175,9 @@
 			return 0;
 		}
 
-		if (lvm_snprintf(extent_str, sizeof(extent_str), "(%" PRIu32
+		if (dm_snprintf(extent_str, sizeof(extent_str), "(%" PRIu32
 				 ")", extent) < 0) {
-			log_error("Extent number lvm_snprintf failed");
+			log_error("Extent number dm_snprintf failed");
 			return 0;
 		}
 
@@ -200,6 +203,7 @@
 
 	return 1;
 }
+
 static int _tags_disp(struct report_handle *rh, struct field *field,
 		      const void *data)
 {
@@ -230,6 +234,23 @@
 	return 1;
 }
 
+static int _modules_disp(struct report_handle *rh, struct field *field,
+			 const void *data)
+{
+	const struct logical_volume *lv = (const struct logical_volume *) data;
+	struct list *modules;
+
+	if (!(modules = str_list_create(rh->mem))) {
+		log_error("modules str_list allocation failed");
+		return 0;
+	}
+
+	if (!list_lv_modules(rh->mem, lv, modules))
+		return_0;
+
+	return _tags_disp(rh, field, modules);
+}
+
 static int _vgfmt_disp(struct report_handle *rh, struct field *field,
 		       const void *data)
 {
@@ -276,7 +297,7 @@
 		return 0;
 	}
 
-	if (lvm_snprintf(repstr, 12, "%d", value) < 0) {
+	if (dm_snprintf(repstr, 12, "%d", value) < 0) {
 		log_error("int too big: %d", value);
 		return 0;
 	}
@@ -540,7 +561,7 @@
 		return 0;
 	}
 
-	if (lvm_snprintf(repstr, len, "[%s]", lv->name) < 0) {
+	if (dm_snprintf(repstr, len, "[%s]", lv->name) < 0) {
 		log_error("lvname snprintf failed");
 		return 0;
 	}
@@ -784,7 +805,7 @@
 		return 0;
 	}
 
-	if (lvm_snprintf(repstr, 11, "%u", value) < 0) {
+	if (dm_snprintf(repstr, 11, "%u", value) < 0) {
 		log_error("uint32 too big: %u", value);
 		return 0;
 	}
@@ -813,7 +834,7 @@
 		return 0;
 	}
 
-	if (lvm_snprintf(repstr, 12, "%d", value) < 0) {
+	if (dm_snprintf(repstr, 12, "%d", value) < 0) {
 		log_error("int32 too big: %d", value);
 		return 0;
 	}
@@ -870,7 +891,7 @@
 		return 0;
 	}
 
-	if (lvm_snprintf(repstr, 7, "%.2f", snap_percent) < 0) {
+	if (dm_snprintf(repstr, 7, "%.2f", snap_percent) < 0) {
 		log_error("snapshot percentage too large");
 		return 0;
 	}
@@ -910,7 +931,7 @@
 		return 0;
 	}
 
-	if (lvm_snprintf(repstr, 7, "%.2f", percent) < 0) {
+	if (dm_snprintf(repstr, 7, "%.2f", percent) < 0) {
 		log_error("copy percentage too large");
 		return 0;
 	}
@@ -948,6 +969,44 @@
 
 const unsigned int _num_fields = sizeof(_fields) / sizeof(_fields[0]);
 
+static void _display_fields(void)
+{
+	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);
+
+		last_type = type;
+	}
+}
+
 /*
  * Initialise report handle
  */
@@ -1080,6 +1139,8 @@
 		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;
@@ -1324,7 +1385,7 @@
 
 		heading = _fields[fp->field_num].heading;
 		if (rh->flags & RH_ALIGNED) {
-			if (lvm_snprintf(buf, sizeof(buf), "%-*.*s",
+			if (dm_snprintf(buf, sizeof(buf), "%-*.*s",
 					 fp->width, fp->width, heading) < 0) {
 				log_error("snprintf heading failed");
 				dm_pool_end_object(rh->mem);
@@ -1467,7 +1528,7 @@
 						      strlen(repstr)))
 					goto bad;
 			} else if (field->props->flags & FLD_ALIGN_LEFT) {
-				if (lvm_snprintf(buf, sizeof(buf), "%-*.*s",
+				if (dm_snprintf(buf, sizeof(buf), "%-*.*s",
 						 width, width, repstr) < 0) {
 					log_error("snprintf repstr failed");
 					dm_pool_end_object(rh->mem);
@@ -1476,7 +1537,7 @@
 				if (!dm_pool_grow_object(rh->mem, buf, width))
 					goto bad;
 			} else if (field->props->flags & FLD_ALIGN_RIGHT) {
-				if (lvm_snprintf(buf, sizeof(buf), "%*.*s",
+				if (dm_snprintf(buf, sizeof(buf), "%*.*s",
 						 width, width, repstr) < 0) {
 					log_error("snprintf repstr failed");
 					dm_pool_end_object(rh->mem);

Modified: lvm2/upstream/current/lib/snapshot/snapshot.c
==============================================================================
--- lvm2/upstream/current/lib/snapshot/snapshot.c	(original)
+++ lvm2/upstream/current/lib/snapshot/snapshot.c	Mon Oct 23 08:49:10 2006
@@ -20,6 +20,7 @@
 #include "text_export.h"
 #include "config.h"
 #include "activate.h"
+#include "str_list.h"
 
 static const char *_snap_name(const struct lv_segment *seg)
 {
@@ -126,6 +127,18 @@
 }
 #endif
 
+static int _snap_modules_needed(struct dm_pool *mem,
+				const struct lv_segment *seg,
+				struct list *modules)
+{
+	if (!str_list_add(mem, modules, "snapshot")) {
+		log_error("snapshot string list allocation failed");
+		return 0;
+	}
+
+	return 1;
+}
+
 static void _snap_destroy(const struct segment_type *segtype)
 {
 	dm_free((void *)segtype);
@@ -139,6 +152,7 @@
 	.target_percent = _snap_target_percent,
 	.target_present = _snap_target_present,
 #endif
+	.modules_needed = _snap_modules_needed,
 	.destroy = _snap_destroy,
 };
 

Modified: lvm2/upstream/current/lib/zero/zero.c
==============================================================================
--- lvm2/upstream/current/lib/zero/zero.c	(original)
+++ lvm2/upstream/current/lib/zero/zero.c	Mon Oct 23 08:49:10 2006
@@ -63,6 +63,18 @@
 }
 #endif
 
+static int _zero_modules_needed(struct dm_pool *mem,
+				const struct lv_segment *seg,
+				struct list *modules)
+{
+	if (!str_list_add(mem, modules, "zero")) {
+		log_error("zero module string list allocation failed");
+		return 0;
+	}
+
+	return 1;
+}
+
 static void _zero_destroy(const struct segment_type *segtype)
 {
 	dm_free((void *) segtype);
@@ -75,6 +87,7 @@
 	.add_target_line = _zero_add_target_line,
 	.target_present = _zero_target_present,
 #endif
+	.modules_needed = _zero_modules_needed,
 	.destroy = _zero_destroy,
 };
 

Modified: lvm2/upstream/current/man/Makefile.in
==============================================================================
--- lvm2/upstream/current/man/Makefile.in	(original)
+++ lvm2/upstream/current/man/Makefile.in	Mon Oct 23 08:49:10 2006
@@ -17,7 +17,8 @@
 VPATH = @srcdir@
 
 MAN5=lvm.conf.5
-MAN8=lvchange.8 lvcreate.8 lvdisplay.8 lvextend.8 lvm.8 lvmchange.8 \
+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 \
 	lvscan.8 pvchange.8 pvcreate.8 pvdisplay.8 pvmove.8 pvremove.8 \
 	pvresize.8 pvs.8 pvscan.8 vgcfgbackup.8 vgcfgrestore.8 vgchange.8 \

Modified: lvm2/upstream/current/man/clvmd.8
==============================================================================
--- lvm2/upstream/current/man/clvmd.8	(original)
+++ lvm2/upstream/current/man/clvmd.8	Mon Oct 23 08:49:10 2006
@@ -4,6 +4,7 @@
 .SH SYNOPSIS
 .B clvmd
 [\-d] [\-h]
+[\-R]
 [\-t <timeout>]
 [\-V]
 .SH DESCRIPTION
@@ -22,6 +23,11 @@
 may need to increase this on systems with very large disk farms. 
 The default is 30 seconds.
 .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
+devices on a cluster system are changed.
+.TP
 .I \-V
 Display the version of the cluster LVM daemon.
 .SH SEE ALSO

Modified: lvm2/upstream/current/man/lvchange.8
==============================================================================
--- lvm2/upstream/current/man/lvchange.8	(original)
+++ lvm2/upstream/current/man/lvchange.8	Mon Oct 23 08:49:10 2006
@@ -9,6 +9,7 @@
 [\-C/\-\-contiguous y/n] [\-d/\-\-debug] [\-\-deltag Tag]
 [\-h/\-?/\-\-help]
 [\-\-ignorelockingfailure]
+[\-\-monitor {y|n}]
 [\-M/\-\-persistent y/n] [\-\-minor minor]
 [\-P/\-\-partial y/n]
 [\-p/\-\-permission r/w] [\-r/\-\-readahead ReadAheadSectors]
@@ -42,6 +43,14 @@
 .I \-\-minor minor
 Set the minor number.
 .TP
+.I \-\-monitor y/n
+Controls whether or not a mirrored logical volume is monitored by
+dmeventd, if it is installed.
+If a device used by a monitored mirror reports an I/O error,
+the failure is handled according to 
+\fBmirror_image_fault_policy\fP and \fBmirror_log_fault_policy\fP
+set in \fBlvm.conf\fP.
+.TP
 .I \-M, \-\-persistent y/n
 Set to y to make the minor number specified persistent.
 .TP

Added: lvm2/upstream/current/man/lvconvert.8
==============================================================================
--- (empty file)
+++ lvm2/upstream/current/man/lvconvert.8	Mon Oct 23 08:49:10 2006
@@ -0,0 +1,61 @@
+.TH LVCONVERT 8 "LVM TOOLS" "Red Hat, Inc" \" -*- nroff -*-
+.SH NAME
+lvconvert \- convert a logical volume between linear and mirror
+.SH SYNOPSIS
+.B lvconvert
+[\-m/\-\-mirrors Mirrors [\-\-corelog] [\-R/\-\-regionsize MirrorLogRegionSize]]
+[\-A/\-\-alloc AllocationPolicy]
+[\-h/\-?/\-\-help]
+[\-v/\-\-verbose]
+[\-\-version]
+LogicalVolume[Path] [PhysicalVolume[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.
+.SH OPTIONS
+See \fBlvm\fP for common options.
+.TP
+.I \-m, \-\-mirrors Mirrors
+Specifies the degree of the mirror you wish to create.
+For example, "-m 1" would convert the original logical
+volume to a mirror volume with 2-sides; that is, a
+linear volume plus one copy.
+.TP
+.I \-\-corelog
+This optional argument tells lvconvert to switch the
+mirror from using a disk-based (persistent) log to
+an in-memory log.  You may only specify this option
+when the \-\-mirror argument is the same degree of
+the mirror you are changing.
+.TP
+.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.
+.SH Examples
+"lvconvert -m1 vg00/lvol1"
+.br
+converts the linear logical volume "vg00/lvol1" to
+a mirror logical volume.  This command could also
+be used to convert a two-way mirror with an
+in-memory log to a two-way mirror with a disk log.
+
+"lvconvert -m1 --corelog vg00/lvol1"
+.br
+converts a two-way mirror with a disk log to a
+two-way mirror with an in-memory log.
+
+"lvconvert -m0 vg00/lvol1"
+.br
+converts a mirror logical volume to a linear logical
+volume.
+
+.SH SEE ALSO
+.BR lvm (8),
+.BR vgcreate (8),
+.BR lvremove (8),
+.BR lvrename (8),
+.BR lvextend (8),
+.BR lvreduce (8),
+.BR lvdisplay (8),
+.BR lvscan (8)

Modified: lvm2/upstream/current/man/lvcreate.8
==============================================================================
--- lvm2/upstream/current/man/lvcreate.8	(original)
+++ lvm2/upstream/current/man/lvcreate.8	Mon Oct 23 08:49:10 2006
@@ -8,12 +8,13 @@
 [\-A/\-\-autobackup y/n] [\-C/\-\-contiguous y/n] [\-d/\-\-debug]
 [\-h/\-?/\-\-help]
 [\-i/\-\-stripes Stripes [\-I/\-\-stripesize StripeSize]]
-{\-l/\-\-extents LogicalExtentsNumber |
+{\-l/\-\-extents LogicalExtentsNumber[%{VG|FREE}] |
  \-L/\-\-size LogicalVolumeSize[kKmMgGtT]}
 [\-M/\-\-persistent y/n] [\-\-minor minor]
+[\-m/\-\-mirrors Mirrors [\-\-nosync] [\-\-corelog]
+[\-R/\-\-regionsize MirrorLogRegionSize]]
 [\-n/\-\-name LogicalVolumeName]
 [\-p/\-\-permission r/rw] [\-r/\-\-readahead ReadAheadSectors]
-[-R|--regionsize MirrorLogRegionSize]
 [\-t/\-\-test]
 [\-v/\-\-verbose] [\-Z/\-\-zero y/n]
 VolumeGroupName [PhysicalVolumePath...]
@@ -21,7 +22,7 @@
 
 .br
 .B lvcreate
-{\-l/\-\-extents LogicalExtentsNumber |
+{\-l/\-\-extents LogicalExtentsNumber[%{VG|FREE}] |
  \-L/\-\-size LogicalVolumeSize[kKmMgGtT]}
 [\-c/\-\-chunksize ChunkSize]
 \-s/\-\-snapshot \-n/\-\-name SnapshotLogicalVolumeName OriginalLogicalVolumePath
@@ -62,9 +63,12 @@
 For metadata in LVM2 format, the stripe size may be a larger
 power of 2 but must not exceed the physical extent size.
 .TP
-.I \-l, \-\-extents LogicalExtentsNumber
+.I \-l, \-\-extents LogicalExtentsNumber[%{VG|FREE}]
 Gives the number of logical extents to allocate for the new
 logical volume.
+This can also be expressed as a percentage of the total space
+in the Volume Group with the suffix %VG or of the remaining free space
+with the suffix %FREE.
 .TP
 .I \-L, \-\-size LogicalVolumeSize[kKmMgGtT]
 Gives the size to allocate for the new logical volume.
@@ -79,6 +83,23 @@
 .I \-M, \-\-persistent y/n
 Set to y to make the minor number specified persistent.
 .TP
+.I \-m, \-\-mirrors Mirrors
+Creates a mirrored logical volume with "Mirrors" copies.  For example,
+specifying "-m 1" would result in a mirror with two-sides; that is, a
+linear volume plus one copy.
+
+Specifying the optional argument "--nosync" will cause the creation
+of the mirror to skip the initial resynchronization.  Any data written
+afterwards will be mirrored, but the original contents will not be
+copied.  This is useful for skipping a potentially long and resource
+intensive initial sync.
+
+Specifying the optional argument "--corelog" will create a mirror with
+an in-memory log verses a disk-based (persistent) log.  While this
+removes the need for an extra log device and *may* be slightly faster,
+it requires that the entire mirror be resynchronized upon each
+instantiation (e.g. a reboot).
+.TP
 .I \-n, \-\-name LogicalVolumeName
 The name for the new logical volume.
 .br
@@ -94,8 +115,8 @@
 Set read ahead sector count of this logical volume to a value between 2 and 120.
 Ignored by device-mapper.
 .TP
-.I \-R \-\-regionsize MirrorLogRegionSize
-A mirror is divided into regions of this size (in KB), and the mirror log 
+.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.
 .TP
 .I \-s, \-\-snapshot
@@ -122,10 +143,15 @@
 Warning: trying to mount an unzeroed logical volume can cause the system to
 hang.
 .SH Examples
-"lvcreate -i 3 -I 8 -L 100 vg00" tries to create a striped logical
+"lvcreate -i 3 -I 8 -L 100M vg00" tries to create a striped logical
 volume with 3 stripes, a stripesize of 8KB and a size of 100MB in the volume
 group named vg00. The logical volume name will be chosen by lvcreate.
 
+"lvcreate -m1 -L 500M vg00" tries to create a mirror logical volume
+with 2 sides with a useable size of 500 MiB.  This operation would
+require 3 devices - two for the mirror devices and one for the disk
+log.
+
 "lvcreate --size 100m --snapshot --name snap /dev/vg00/lvol1"
 .br
 creates a snapshot logical volume named /dev/vg00/snap which has access to the

Modified: lvm2/upstream/current/man/lvextend.8
==============================================================================
--- lvm2/upstream/current/man/lvextend.8	(original)
+++ lvm2/upstream/current/man/lvextend.8	Mon Oct 23 08:49:10 2006
@@ -6,7 +6,7 @@
 [\-\-alloc AllocationPolicy]
 [\-A/\-\-autobackup y/n] [\-d/\-\-debug] [\-h/\-?/\-\-help]
 [\-i/\-\-stripes Stripes [\-I/\-\-stripesize StripeSize]]
-{\-l/\-\-extents [+]LogicalExtentsNumber |
+{\-l/\-\-extents [+]LogicalExtentsNumber[%{VG|LV|FREE}] |
 \-L/\-\-size [+]LogicalVolumeSize[kKmMgGtT]}
 [\-t/\-\-test]
 [\-v/\-\-verbose] LogicalVolumePath [PhysicalVolumePath...]
@@ -15,13 +15,20 @@
 Extension of snapshot logical volumes (see
 .B lvcreate(8)
 for information to create snapshots) is supported as well.
+But to change the number of copies in a mirrored logical
+volume use 
+.BR lvconvert (8).
 .SH OPTIONS
 See \fBlvm\fP for common options.
 .TP
-.I \-l, \-\-extents [+]LogicalExtentsNumber
+.I \-l, \-\-extents [+]LogicalExtentsNumber[%{VG|LV|FREE}]
 Extend or set the logical volume size in units of logical extents.
 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.
+The number can also be expressed as a percentage of the total space
+in the Volume Group with the suffix %VG or relative to the existing
+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.
@@ -48,6 +55,7 @@
 .SH SEE ALSO
 .BR lvm (8), 
 .BR lvcreate (8), 
+.BR lvconvert (8), 
 .BR lvreduce (8), 
 .BR lvresize (8), 
 .BR lvchange (8)

Modified: lvm2/upstream/current/man/lvm.8
==============================================================================
--- lvm2/upstream/current/man/lvm.8	(original)
+++ lvm2/upstream/current/man/lvm.8	Mon Oct 23 08:49:10 2006
@@ -38,7 +38,7 @@
 being created in the filesystem for them.
 .TP
 \fBdumpconfig\fP \(em Display the configuration information after 
-loading \fBlvm.conf\fP (8) and any other configuration files.
+loading \fBlvm.conf\fP (5) and any other configuration files.
 .TP
 \fBformats\fP \(em Display recognised metadata formats.
 .TP
@@ -136,7 +136,7 @@
 Delete the tag \fBtag\fP from a PV, VG or LV, if it's present.
 .TP
 \fB--alloc AllocationPolicy\fP
-The allocation policy to use: \fBcontiguous\fP, \fBnormal\fP, \fBanywhere\fP or \fBinherit\fP.
+The allocation policy to use: \fBcontiguous\fP, \fBcling\fP, \fBnormal\fP, \fBanywhere\fP or \fBinherit\fP.
 When a command needs to allocate physical extents from the volume group,
 the allocation policy controls how they are chosen.  
 Each volume group and logical volume has an allocation policy.
@@ -146,15 +146,18 @@
 which applies the same policy as for the volume group.  These policies can
 be changed using \fBlvchange\fP (8) and \fBvgchange\fP (8) or over-ridden
 on the command line of any command that performs allocation.
-The \fBcontiguous\fP policy requires that new extents are adjacent to
-existing extents. If there are sufficient free extents to satisfy
+The \fBcontiguous\fP policy requires that new extents be placed adjacent
+to existing extents. 
+The \fBcling\fP policy places new extents on the same physical
+volume as existing extents in the same stripe of the Logical Volume.
+If there are sufficient free extents to satisfy
 an allocation request but \fBnormal\fP doesn't use them,
 \fBanywhere\fP will - even if that reduces performance by
 placing two stripes on the same physical volume.
 .IP
 N.B. The policies described above are not implemented fully yet.
-In particular, \fBcontiguous\fP does not place new extents adjacent to existing
-extents and \fBanywhere\fP is not implemented at all.
+In particular, contiguous free space cannot be broken up to
+satisfy allocation attempts.
 .SH ENVIRONMENT VARIABLES
 .TP
 \fBLVM_SYSTEM_DIR\fP 

Modified: lvm2/upstream/current/man/lvm.conf.5
==============================================================================
--- lvm2/upstream/current/man/lvm.conf.5	(original)
+++ lvm2/upstream/current/man/lvm.conf.5	Mon Oct 23 08:49:10 2006
@@ -252,7 +252,7 @@
 .IP
 \fBlocking_library\fP \(em The name of the external locking
 library to load if \fBlocking_type\fP is set to 2.
-The default is \fBlvm2_locking.so\fP.  If you need to write
+The default is \fBliblvm2clusterlock.so\fP.  If you need to write
 such a library, look at the lib/locking source code directory.
 .TP
 \fBtags\fP \(em Host tag settings

Modified: lvm2/upstream/current/man/lvreduce.8
==============================================================================
--- lvm2/upstream/current/man/lvreduce.8	(original)
+++ lvm2/upstream/current/man/lvreduce.8	Mon Oct 23 08:49:10 2006
@@ -4,7 +4,8 @@
 .SH SYNOPSIS
 .B lvreduce
 [\-A/\-\-autobackup y/n] [\-d/\-\-debug] [\-f/\-\-force]
-[\-h/\-?/\-\-help] {\-l/\-\-extents [\-]LogicalExtentsNumber |
+[\-h/\-?/\-\-help]
+{\-l/\-\-extents [\-]LogicalExtentsNumber[%{VG|LV|FREE}] |
 \-L/\-\-size [\-]LogicalVolumeSize[kKmMgGtT]}
 [\-t/\-\-test]
 [\-v/\-\-verbose] LogicalVolume[Path]
@@ -21,21 +22,29 @@
 Shrinking snapshot logical volumes (see
 .B lvcreate(8)
 for information to create snapshots) is supported as well.
+But to change the number of copies in a mirrored logical
+volume use 
+.B lvconvert (8).
 .br
 Sizes will be rounded if necessary - for example, the volume size must
 be an exact number of extents and the size of a striped segment must
 be a multiple of the number of stripes.
+.br
 .SH OPTIONS
 See \fBlvm\fP for common options.
 .TP
 .I \-f, \-\-force
 Force size reduction without any question.
 .TP
-.I \-l, \-\-extents [\-]LogicalExtentsNumber
+.I \-l, \-\-extents [\-]LogicalExtentsNumber[%{VG|LV|FREE}]
 Reduce or set the logical volume size in units of logical extents.
 With the - sign the value will be subtracted from
 the logical volume's actual size and without it the will be taken as
 an absolute size.
+The number can also be expressed as a percentage of the total space
+in the Volume Group with the suffix %VG or relative to the existing
+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]
 Reduce or set the logical volume size in units of megabyte by default.
@@ -49,6 +58,7 @@
 in volume group vg00 by 3 logical extents.
 .SH SEE ALSO
 .BR lvchange (8),
+.BR lvconvert (8), 
 .BR lvcreate (8), 
 .BR lvextend (8), 
 .BR lvm (8), 

Modified: lvm2/upstream/current/man/lvresize.8
==============================================================================
--- lvm2/upstream/current/man/lvresize.8	(original)
+++ lvm2/upstream/current/man/lvresize.8	Mon Oct 23 08:49:10 2006
@@ -6,7 +6,7 @@
 [\-\-alloc AllocationPolicy]
 [\-A/\-\-autobackup y/n] [\-d/\-\-debug] [\-h/\-?/\-\-help]
 [\-i/\-\-stripes Stripes [\-I/\-\-stripesize StripeSize]]
-{\-l/\-\-extents [+]LogicalExtentsNumber |
+{\-l/\-\-extents [+]LogicalExtentsNumber[%{VG|LV|FREE}] |
 \-L/\-\-size [+]LogicalVolumeSize[kKmMgGtT]}
 [\-t/\-\-test]
 [\-v/\-\-verbose] LogicalVolumePath [PhysicalVolumePath...]
@@ -19,13 +19,20 @@
 Resizing snapshot logical volumes (see
 .B lvcreate(8)
 for information about creating snapshots) is supported as well.
+But to change the number of copies in a mirrored logical
+volume use 
+.BR lvconvert (8).
 .SH OPTIONS
 See \fBlvm\fP for common options.
 .TP
-.I \-l, \-\-extents [+/-]LogicalExtentsNumber
+.I \-l, \-\-extents [+/-]LogicalExtentsNumber[%{VG|LV|FREE}]
 Change or set the logical volume size in units of logical extents.
 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.
+The number can also be expressed as a percentage of the total space
+in the Volume Group with the suffix %VG or relative to the existing
+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]
 Change or set the logical volume size in units of megabytes.
@@ -49,6 +56,7 @@
 StripeSize must be 2^n (n = 2 to 9)
 .SH SEE ALSO
 .BR lvm (8), 
+.BR lvconvert (8),
 .BR lvcreate (8), 
 .BR lvreduce (8), 
 .BR lvchange (8)

Modified: lvm2/upstream/current/man/vgchange.8
==============================================================================
--- lvm2/upstream/current/man/vgchange.8	(original)
+++ lvm2/upstream/current/man/vgchange.8	Mon Oct 23 08:49:10 2006
@@ -9,6 +9,7 @@
 .IR AllocationPolicy ]
 .RB [ \-A | \-\-autobackup " {" y | n }]
 .RB [ \-a | \-\-available " [e|l] {" y | n }]
+.RB [ \-\-monitor " {" y | n }]
 .RB [ \-d | \-\-debug]
 .RB [ \-\-deltag
 .IR Tag ]
@@ -16,6 +17,8 @@
 .RB [ \-\-ignorelockingfailure]
 .RB [ \-l | \-\-logicalvolume
 .IR MaxLogicalVolumes ]
+.RB [ -p | \-\-maxphysicalvolumes
+.IR MaxPhysicalVolumes ]
 .RB [ \-P | \-\-partial]
 .RB [ \-s | \-\-physicalextentsize
 .IR PhysicalExtentSize [ \fBkKmMgGtT\fR ]]
@@ -57,10 +60,33 @@
 Logical volumes with single-host snapshots are always activated
 exclusively because they can only be used on one node at once.
 .TP
+.BR \-\-monitor " " { y | n }
+Controls whether or not a mirrored logical volume is monitored by
+dmeventd, if it is installed.
+If a device used by a monitored mirror reports an I/O error,
+the failure is handled according to 
+.BR mirror_image_fault_policy
+and 
+.BR mirror_log_fault_policy
+set in 
+.BR lvm.conf (5).
+.TP
 .BR \-l ", " \-\-logicalvolume " " \fIMaxLogicalVolumes\fR
 Changes the maximum logical volume number of an existing inactive
 volume group.
 .TP
+.BR \-p ", " \-\-maxphysicalvolumes " " \fIMaxPhysicalVolumes\fR
+Changes the maximum number of physical volumes that can belong
+to this volume group.
+For volume groups with metadata in lvm1 format, the limit is 255.
+If the metadata uses lvm2 format, the value 0
+removes this restriction: there is then no limit.
+If you have a large number of physical volumes in
+a volume group with metadata in lvm2 format,
+for tool performance reasons, you should consider
+some use of \fB--metadatacopies 0\fP
+as described in \fBpvcreate(8)\fP.
+.TP
 .BR \-s ", " \-\-physicalextentsize " " \fIPhysicalExtentSize\fR[\fBkKmMgGtT\fR]
 Changes the physical extent size on physical volumes of this volume group.
 A size suffix (k for kilobytes up to t for terabytes) is optional, megabytes

Modified: lvm2/upstream/current/man/vgscan.8
==============================================================================
--- lvm2/upstream/current/man/vgscan.8	(original)
+++ lvm2/upstream/current/man/vgscan.8	Mon Oct 23 08:49:10 2006
@@ -11,7 +11,7 @@
 .SH DESCRIPTION
 vgscan scans all SCSI, (E)IDE disks, multiple devices and a bunch
 of other disk devices in the system looking for LVM physical volumes
-and volume groups.  Define a filter in \fBlvm.conf\fP(8) to restrict 
+and volume groups.  Define a filter in \fBlvm.conf\fP(5) to restrict 
 the scan to avoid a CD ROM, for example.
 .LP
 In LVM2, vgscans take place automatically; but you might still need to

Modified: lvm2/upstream/current/scripts/clvmd_init_rhel4
==============================================================================
--- lvm2/upstream/current/scripts/clvmd_init_rhel4	(original)
+++ lvm2/upstream/current/scripts/clvmd_init_rhel4	Mon Oct 23 08:49:10 2006
@@ -93,6 +93,24 @@
 	return $rtrn
 }
 
+wait_for_finish()
+{
+	count=0
+
+	while [ "$count" -le 10 -a -n "`pidof clvmd`" ]
+	do
+		sleep 1
+		count=$((count + 1))
+	done
+	
+	if [ `pidof clvmd` ]
+	then
+		return 1
+	else
+		return 0
+	fi
+}
+
 rtrn=1
 
 # See how we were called.
@@ -112,6 +130,7 @@
   restart)
 	if stop
 	then
+		wait_for_finish
 		start
 	fi 
 	rtrn=$?
@@ -119,9 +138,9 @@
 
   status)
 	status clvmd
+	rtrn=$?
 	vols=$( $LVDISPLAY -C --nohead 2> /dev/null | awk '($3 ~ /....a./) {print $1}' )
 	echo active volumes: ${vols:-"(none)"}
-	rtrn=0
 	;;
 
   *)

Added: lvm2/upstream/current/scripts/lvm_dump.sh
==============================================================================
--- (empty file)
+++ lvm2/upstream/current/scripts/lvm_dump.sh	Mon Oct 23 08:49:10 2006
@@ -0,0 +1,118 @@
+#!/bin/bash
+#
+# lvm_dump: This script is used to collect pertinent information for
+#           the debugging of lvm issues.
+#
+
+function usage {
+	echo "$0 [options]"
+	echo "    -h print this message"
+	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 "    -c if running clvmd, gather cluster data as well"
+	echo ""
+	
+	exit 1
+}
+
+advanced=0
+clustered=0
+metadata=0
+while getopts :acd:hm opt; do
+	case $opt in 
+		a)	advanced=1 ;;
+		c)	clustered=1 ;;
+		d)	lvm_dir=$OPTARG ;;
+		h)	usage ;;
+		m)	metadata=1 ;;
+		:)	echo "$0: $OPTARG requires a value:"; usage ;;
+		\?)     echo "$0: unknown option $OPTARG"; usage ;;
+		*)	usage ;;
+	esac
+done
+
+dir=`mktemp -d -p /tmp lvm_dump.XXXXXX` || exit 2
+lvm_dir="$dir/lvm_dump"
+
+echo " "
+echo "Creating dump directory: $lvm_dir"
+echo " "
+
+mkdir -p $lvm_dir || exit 3
+
+if (( $advanced )); then
+	echo "Gathering LVM volume info..."
+
+	echo "  vgscan..."
+	vgscan -vvvv > $lvm_dir/vgscan 2>&1
+
+	echo "  pvscan..."
+	pvscan -v >> $lvm_dir/pvscan 2>/dev/null
+
+	echo "  lvs..."
+	lvs -a -o +devices >> $lvm_dir/lvs 2>/dev/null
+
+	echo "  pvs..."
+	pvs -a -v > $lvm_dir/pvs 2>/dev/null
+
+	echo "  vgs..."
+	vgs -v > $lvm_dir/vgs 2>/dev/null
+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
+
+echo "Gathering console messages..."
+tail -n 75 /var/log/messages > $lvm_dir/messages
+
+echo "Gathering /etc/lvm info..."
+cp -a /etc/lvm $lvm_dir/lvm
+
+echo "Gathering /dev listing..."
+ls -la /dev > $lvm_dir/dev_listing
+
+if (( $metadata )); then
+	echo "Gathering LVM metadata from Physical Volumes..."
+
+	mkdir -p $lvm_dir/metadata
+
+	for pv in `pvs --noheadings -o name`
+	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
+fi
+
+lvm_dump=$lvm_dir.tgz
+echo "Creating tarball $lvm_dump..."
+tar czf $lvm_dump $lvm_dir 2>/dev/null
+
+exit 0
+

Modified: lvm2/upstream/current/scripts/lvmconf.sh
==============================================================================
--- lvm2/upstream/current/scripts/lvmconf.sh	(original)
+++ lvm2/upstream/current/scripts/lvmconf.sh	Mon Oct 23 08:49:10 2006
@@ -1,6 +1,6 @@
 #!/bin/sh
 #
-# Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
 #
 # This file is part of the lvm2-cluster package.
 #
@@ -21,8 +21,9 @@
     echo "usage: $0 <command>"
     echo ""
     echo "Commands:"
-    echo "Enable clvm:  --enable-cluster --lockinglibdir <dir> [--lockinglib <lib>]"
+    echo "Enable clvm:  --enable-cluster [--lockinglibdir <dir>] [--lockinglib <lib>]"
     echo "Disable clvm: --disable-cluster"
+    echo "Set locking library: --lockinglibdir <dir> [--lockinglib <lib>]"
     echo ""
     echo "Global options:"
     echo "Config file location: --file <configfile>"
@@ -86,14 +87,13 @@
             exit 10
     fi
 
-    if [ -z "$LOCKING_TYPE" ]; then
+    if [ -z "$LOCKING_TYPE" ] && [ -z "$LOCKINGLIBDIR" ]; then
         usage
         exit 1
     fi
 
-    if [ "$LOCKING_TYPE" == "2" ]; then
+    if [ -n "$LOCKINGLIBDIR" ]; then
 
-        [ -z "$LOCKINGLIBDIR" ] && usage && exit 1    
         [ -z "$LOCKINGLIB" ] && LOCKINGLIB="liblvm2clusterlock.so"
             
         if [ "${LOCKINGLIBDIR:0:1}" != "/" ]
@@ -109,6 +109,10 @@
         fi
         
     fi
+
+    if [ "$LOCKING_TYPE" = "1" ] && [ -n "$LOCKINGLIBDIR" -o -n "$LOCKINGLIB" ]; then
+	echo "Superfluous locking lib parameter, ignoring"
+    fi
 }
 
 umask 0077
@@ -153,11 +157,19 @@
     fi
 fi
 
+if [ "$LOCKING_TYPE" = "2" ] && [ -z "$LOCKINGLIBDIR" ] && [ "$have_dir" = "1" ]; then
+	echo "no library_dir specified in $CONFIGFILE"
+	exit 16
+fi
+
 # So if we don't have "global {" we need to create one and 
 # populate it
 
 if [ "$have_global" = "1" ]
 then
+    if [ -z "$LOCKING_TYPE" ]; then
+	LOCKING_TYPE=1
+    fi
     if [ "$LOCKING_TYPE" = "2" ]; then
         cat $CONFIGFILE - <<EOF > $TMPFILE
 global {
@@ -180,14 +192,16 @@
     # locking entries as appropriate
     #
 
-    if [ "$have_type" = "0" ] 
-    then
-	SEDCMD=" s/^[[:blank:]]*locking_type[[:blank:]]*=.*/\ \ \ \ locking_type = $LOCKING_TYPE/g"
-    else
-	SEDCMD=" /global[[:blank:]]*{/a\ \ \ \ locking_type = $LOCKING_TYPE"
+    if [ -n "$LOCKING_TYPE" ]; then
+	if [ "$have_type" = "0" ] 
+	then
+	    SEDCMD=" s/^[[:blank:]]*locking_type[[:blank:]]*=.*/\ \ \ \ locking_type = $LOCKING_TYPE/g"
+	else
+	    SEDCMD=" /global[[:blank:]]*{/a\ \ \ \ locking_type = $LOCKING_TYPE"
+	fi
     fi
     
-    if [ "$LOCKING_TYPE" = "2" ]; then
+    if [ -n "$LOCKINGLIBDIR" ]; then
         if [ "$have_dir" = "0" ] 
             then
             SEDCMD="${SEDCMD}\ns'^[[:blank:]]*library_dir[[:blank:]]*=.*'\ \ \ \ library_dir = \"$LOCKINGLIBDIR\"'g"
@@ -201,7 +215,9 @@
         else
             SEDCMD="${SEDCMD}\n/global[[:blank:]]*{/a\ \ \ \ locking_library = \"$LOCKINGLIB\""
         fi
-    else
+    fi
+
+    if [ "$LOCKING_TYPE" = "1" ]; then
         # if we're not using cluster locking, remove the library dir and locking library name
         if [ "$have_dir" = "0" ] 
             then

Modified: lvm2/upstream/current/tools/Makefile.in
==============================================================================
--- lvm2/upstream/current/tools/Makefile.in	(original)
+++ lvm2/upstream/current/tools/Makefile.in	Mon Oct 23 08:49:10 2006
@@ -80,7 +80,9 @@
 
 LVMLIBS = -llvm
 
-CLEAN_TARGETS = liblvm2cmd.so liblvm2cmd.a lvm lvm.o lvm.static lvm.cflow lvm.xref lvm.tree lvm.rxref lvm.rtree
+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
 
 ifeq ("@CMDLIB@", "yes")
 	TARGETS += liblvm2cmd.so
@@ -104,9 +106,13 @@
 	$(CC) -o $@ $(OBJECTS) lvm-static.o -static $(LDFLAGS) $(LVMLIBS) \
 		$(LIBS) -rdynamic
 
-liblvm2cmd.a: $(top_srcdir)/lib/liblvm.a $(OBJECTS)
+liblvm2cmd.a: $(top_srcdir)/lib/liblvm.a $(OBJECTS) lvmcmdlib.o lvm2cmd.o
 	cat $(top_srcdir)/lib/liblvm.a > $@
-	$(AR) rs $@ $(OBJECTS)
+	$(AR) rs $@ $(OBJECTS) lvmcmdlib.o lvm2cmd.o
+
+liblvm2cmd-static.a: $(top_srcdir)/lib/liblvm.a $(OBJECTS) lvmcmdlib.o lvm2cmd-static.o
+	cat $(top_srcdir)/lib/liblvm.a > $@
+	$(AR) rs $@ $(OBJECTS) lvmcmdlib.o lvm2cmd-static.o
 
 liblvm2cmd.so: liblvm2cmd.a $(LDDEPS)
 
@@ -141,8 +147,8 @@
 	$(INSTALL) -D $(OWNER) $(GROUP) -m 444 lvm2cmd.h \
 		$(includedir)/lvm2cmd.h
 
-install_cmdlib_static: liblvm2cmd.a
-	$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) liblvm2cmd.a \
+install_cmdlib_static: liblvm2cmd-static.a
+	$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) liblvm2cmd-static.a \
 		$(libdir)/liblvm2cmd.a.$(LIB_VERSION)
 	$(LN_S) -f liblvm2cmd.a.$(LIB_VERSION) $(libdir)/liblvm2cmd.a
 	$(INSTALL) -D $(OWNER) $(GROUP) -m 444 lvm2cmd.h \

Modified: lvm2/upstream/current/tools/args.h
==============================================================================
--- lvm2/upstream/current/tools/args.h	(original)
+++ lvm2/upstream/current/tools/args.h	Mon Oct 23 08:49:10 2006
@@ -49,6 +49,7 @@
 arg(corelog_ARG, '\0', "corelog", NULL)
 arg(monitor_ARG, '\0', "monitor", yes_no_arg)
 arg(config_ARG, '\0', "config", string_arg)
+arg(trustcache_ARG, '\0', "trustcache", NULL)
 
 /* Allow some variations */
 arg(resizable_ARG, '\0', "resizable", yes_no_arg)
@@ -83,7 +84,7 @@
 arg(iop_version_ARG, 'i', "iop_version", NULL)
 arg(logicalvolume_ARG, 'l', "logicalvolume", int_arg)
 arg(maxlogicalvolumes_ARG, 'l', "maxlogicalvolumes", int_arg)
-arg(extents_ARG, 'l', "extents", int_arg_with_sign)
+arg(extents_ARG, 'l', "extents", int_arg_with_sign_and_percent)
 arg(lvmpartition_ARG, 'l', "lvmpartition", NULL)
 arg(list_ARG, 'l', "list", NULL)
 arg(size_ARG, 'L', "size", size_mb_arg)

Modified: lvm2/upstream/current/tools/commands.h
==============================================================================
--- lvm2/upstream/current/tools/commands.h	(original)
+++ lvm2/upstream/current/tools/commands.h	Mon Oct 23 08:49:10 2006
@@ -83,6 +83,7 @@
    "Change logical volume layout",
    "lvconvert "
    "[-m|--mirrors Mirrors [--corelog]]\n"
+   "\t[-R|--regionsize MirrorLogRegionSize]\n"
    "\t[--alloc AllocationPolicy]\n"
    "\t[-d|--debug]\n"
    "\t[-h|-?|--help]\n"
@@ -100,7 +101,7 @@
    "\t[--version]" "\n"
    "\tOriginalLogicalVolume[Path] SnapshotLogicalVolume[Path]\n",
 
-   alloc_ARG, chunksize_ARG, mirrors_ARG, corelog_ARG,
+   alloc_ARG, chunksize_ARG, mirrors_ARG, corelog_ARG, regionsize_ARG,
    snapshot_ARG, test_ARG, zero_ARG)
 
 xx(lvcreate,
@@ -137,7 +138,7 @@
    "\t[-d|--debug]\n"
    "\t[-h|-?|--help]\n"
    "\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n"
-   "\t{-l|--extents LogicalExtentsNumber |\n"
+   "\t{-l|--extents LogicalExtentsNumber[%{VG|LV|FREE}] |\n"
    "\t -L|--size LogicalVolumeSize[kKmMgGtT]}\n"
    "\t[-M|--persistent {y|n}] [--major major] [--minor minor]\n"
    "\t[-n|--name LogicalVolumeName]\n"
@@ -202,7 +203,7 @@
    "\t[-d|--debug]\n"
    "\t[-h|--help]\n"
    "\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n"
-   "\t{-l|--extents [+]LogicalExtentsNumber |\n"
+   "\t{-l|--extents [+]LogicalExtentsNumber[%{VG|FREE}] |\n"
    "\t -L|--size [+]LogicalVolumeSize[kKmMgGtT]}\n"
    "\t[-m|--mirrors Mirrors]\n"
    "\t[-n|--nofsck]\n"
@@ -267,7 +268,7 @@
    "\t[-d|--debug]\n"
    "\t[-f|--force]\n"
    "\t[-h|--help]\n"
-   "\t{-l|--extents [-]LogicalExtentsNumber |\n"
+   "\t{-l|--extents [-]LogicalExtentsNumber[%{VG|LV|FREE}] |\n"
    "\t -L|--size [-]LogicalVolumeSize[kKmMgGtT]}\n"
    "\t[-n|--nofsck]\n"
    "\t[-r|--resizefs]\n"
@@ -315,7 +316,7 @@
    "\t[-d|--debug]\n"
    "\t[-h|--help]\n"
    "\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n"
-   "\t{-l|--extents [+|-]LogicalExtentsNumber |\n"
+   "\t{-l|--extents [+|-]LogicalExtentsNumber[%{VG|LV|FREE}] |\n"
    "\t -L|--size [+|-]LogicalVolumeSize[kKmMgGtT]}\n"
    "\t[-n|--nofsck]\n"
    "\t[-r|--resizefs]\n"
@@ -343,6 +344,7 @@
    "\t[-P|--partial] " "\n"
    "\t[--segments]\n"
    "\t[--separator Separator]\n"
+   "\t[--trustcache]\n"
    "\t[--unbuffered]\n"
    "\t[--units hsbkmgtHKMGT]\n"
    "\t[-v|--verbose]\n"
@@ -351,7 +353,7 @@
 
    aligned_ARG, all_ARG, ignorelockingfailure_ARG, noheadings_ARG,
    nolocking_ARG, nosuffix_ARG, options_ARG, partial_ARG, segments_ARG,
-   separator_ARG, sort_ARG, unbuffered_ARG, units_ARG)
+   separator_ARG, sort_ARG, trustcache_ARG, unbuffered_ARG, units_ARG)
 
 xx(lvscan,
    "List all logical volumes in all volume groups",
@@ -527,6 +529,7 @@
    "\t[-P|--partial] " "\n"
    "\t[--segments]\n"
    "\t[--separator Separator]\n"
+   "\t[--trustcache]\n"
    "\t[--unbuffered]\n"
    "\t[--units hsbkmgtHKMGT]\n"
    "\t[-v|--verbose]\n"
@@ -535,7 +538,7 @@
 
    aligned_ARG, all_ARG, ignorelockingfailure_ARG, noheadings_ARG,
    nolocking_ARG, nosuffix_ARG, options_ARG, partial_ARG, segments_ARG,
-   separator_ARG, sort_ARG, unbuffered_ARG, units_ARG)
+   separator_ARG, sort_ARG, trustcache_ARG, unbuffered_ARG, units_ARG)
 
 xx(pvscan,
    "List all physical volumes",
@@ -605,6 +608,7 @@
    "\t -c|--clustered {y|n} |" "\n"
    "\t -x|--resizeable {y|n} |" "\n"
    "\t -l|--logicalvolume MaxLogicalVolumes |" "\n"
+   "\t -p|--maxphysicalvolumes MaxPhysicalVolumes |" "\n"
    "\t -s|--physicalextentsize PhysicalExtentSize[kKmMgGtT] |" "\n"
    "\t --addtag Tag |\n"
    "\t --deltag Tag}\n"
@@ -612,8 +616,8 @@
 
    addtag_ARG, alloc_ARG, allocation_ARG, autobackup_ARG, available_ARG,
    clustered_ARG, deltag_ARG, ignorelockingfailure_ARG, logicalvolume_ARG,
-   monitor_ARG, partial_ARG, physicalextentsize_ARG, resizeable_ARG,
-   resizable_ARG, test_ARG, uuid_ARG)
+   maxphysicalvolumes_ARG, monitor_ARG, partial_ARG, physicalextentsize_ARG,
+   resizeable_ARG, resizable_ARG, test_ARG, uuid_ARG)
 
 xx(vgck,
    "Check the consistency of volume group(s)",
@@ -819,6 +823,7 @@
    "\t[-O|--sort [+|-]key1[,[+|-]key2[,...]]]\n"
    "\t[-P|--partial] " "\n"
    "\t[--separator Separator]\n"
+   "\t[--trustcache]\n"
    "\t[--unbuffered]\n"
    "\t[--units hsbkmgtHKMGT]\n"
    "\t[-v|--verbose]\n"
@@ -827,7 +832,7 @@
 
    aligned_ARG, all_ARG, ignorelockingfailure_ARG, noheadings_ARG,
    nolocking_ARG, nosuffix_ARG, options_ARG, partial_ARG, separator_ARG,
-   sort_ARG, unbuffered_ARG, units_ARG)
+   sort_ARG, trustcache_ARG, unbuffered_ARG, units_ARG)
 
 xx(vgscan,
    "Search for all volume groups",

Modified: lvm2/upstream/current/tools/lvchange.c
==============================================================================
--- lvm2/upstream/current/tools/lvchange.c	(original)
+++ lvm2/upstream/current/tools/lvchange.c	Mon Oct 23 08:49:10 2006
@@ -294,16 +294,15 @@
 			log_error("Major number must be specified with -My");
 			return 0;
 		}
-		if (lv_info(cmd, lv, &info, 0) && info.exists &&
-		    !arg_count(cmd, force_ARG)) {
-			if (yes_no_prompt("Logical volume %s will be "
-					  "deactivated temporarily. "
-					  "Continue? [y/n]: ", lv->name) == 'n') {
-				log_print("%s device number not changed.",
-					  lv->name);
-				return 0;
-			}
+		if (lv_info(cmd, lv, &info, 0) && info.exists)
 			active = 1;
+		if (active && !arg_count(cmd, force_ARG) &&
+		    yes_no_prompt("Logical volume %s will be "
+				  "deactivated temporarily. "
+				  "Continue? [y/n]: ", lv->name) == 'n') {
+			log_print("%s device number not changed.",
+				  lv->name);
+			return 0;
 		}
 		log_verbose("Ensuring %s is inactive.", lv->name);
 		if (!deactivate_lv(cmd, lv)) {

Modified: lvm2/upstream/current/tools/lvconvert.c
==============================================================================
--- lvm2/upstream/current/tools/lvconvert.c	(original)
+++ lvm2/upstream/current/tools/lvconvert.c	Mon Oct 23 08:49:10 2006
@@ -102,7 +102,7 @@
 			int argc, char **argv)
 {
 	int region_size;
-	int pagesize = getpagesize();
+	int pagesize = lvm_getpagesize();
 
 	memset(lp, 0, sizeof(*lp));
 
@@ -344,8 +344,7 @@
 						  lp->mirrors - 1);
 					return 1;
 				}
-			}
-			if (lp->mirrors > existing_mirrors) {
+			} else if (lp->mirrors > existing_mirrors) {
 				/* FIXME Unless anywhere, remove PV of log_lv 
 				 * from allocatable_pvs & allocate 
 				 * (mirrors - existing_mirrors) new areas
@@ -565,6 +564,12 @@
 		goto error;
 	}
 
+	if ((vg->status & CLUSTERED) && !locking_is_clustered() &&
+	    !lockingfailed()) {
+		log_error("Skipping clustered volume group %s", lp.vg_name);
+		goto error;
+	}
+
 	if (vg->status & EXPORTED_VG) {
 		log_error("Volume group \"%s\" is exported", lp.vg_name);
 		goto error;

Modified: lvm2/upstream/current/tools/lvcreate.c
==============================================================================
--- lvm2/upstream/current/tools/lvcreate.c	(original)
+++ lvm2/upstream/current/tools/lvcreate.c	Mon Oct 23 08:49:10 2006
@@ -43,6 +43,7 @@
 	/* size */
 	uint32_t extents;
 	uint64_t size;
+	percent_t percent;
 
 	uint32_t permission;
 	uint32_t read_ahead;
@@ -94,19 +95,7 @@
 			}
 
 		} else {
-			vg_name = argv[0];
-			/* Strip dev_dir (optional) */
-			if (*vg_name == '/') {
-				while (*vg_name == '/')
-					vg_name++;
-				vg_name--;
-			}
-			if (!strncmp(vg_name, cmd->dev_dir,
-				     strlen(cmd->dev_dir))) {
-				vg_name += strlen(cmd->dev_dir);
-				while (*vg_name == '/')
-					vg_name++;
-			}
+			vg_name = skip_dev_dir(cmd, argv[0]);
 			if (strrchr(vg_name, '/')) {
 				log_error("Volume group name expected "
 					  "(no slash)");
@@ -169,6 +158,7 @@
 			return 0;
 		}
 		lp->extents = arg_uint_value(cmd, extents_ARG, 0);
+		lp->percent = arg_percent_value(cmd, extents_ARG, PERCENT_NONE);
 	}
 
 	/* Size returned in kilobyte units; held in sectors */
@@ -178,6 +168,7 @@
 			return 0;
 		}
 		lp->size = arg_uint64_value(cmd, size_ARG, UINT64_C(0)) * 2;
+		lp->percent = PERCENT_NONE;
 	}
 
 	return 1;
@@ -249,7 +240,7 @@
 {
 	int argc = *pargc;
 	int region_size;
-	int pagesize = getpagesize();
+	int pagesize = lvm_getpagesize();
 
 	if (argc && (unsigned) argc < lp->mirrors) {
 		log_error("Too few physical volumes on "
@@ -498,6 +489,12 @@
 		return 0;
 	}
 
+	if ((vg->status & CLUSTERED) && !locking_is_clustered() &&
+	    !lockingfailed()) {
+		log_error("Skipping clustered volume group %s", lp->vg_name);
+		return 0;
+	}
+
 	if (vg->status & EXPORTED_VG) {
 		log_error("Volume group \"%s\" is exported", lp->vg_name);
 		return 0;
@@ -562,6 +559,20 @@
 		lp->extents = tmp_size / vg->extent_size;
 	}
 
+	switch(lp->percent) {
+		case PERCENT_VG:
+			lp->extents = lp->extents * vg->extent_count / 100;
+			break;
+		case PERCENT_FREE:
+			lp->extents = lp->extents * vg->free_count / 100;
+			break;
+		case PERCENT_LV:
+			log_error("Please express size as %%VG or %%FREE.");
+			return 0;
+		case PERCENT_NONE:
+			break;
+	}
+
 	if ((size_rest = lp->extents % lp->stripes)) {
 		log_print("Rounding size (%d extents) up to stripe boundary "
 			  "size (%d extents)", lp->extents,

Added: lvm2/upstream/current/tools/lvm2cmd-static.c
==============================================================================
--- (empty file)
+++ lvm2/upstream/current/tools/lvm2cmd-static.c	Mon Oct 23 08:49:10 2006
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of 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
+ */
+
+#include "lvm2cmdline.h"
+#include "lvm2cmd.h"
+
+void *lvm2_init(void)
+{
+	return cmdlib_lvm2_init(1);
+}

Added: lvm2/upstream/current/tools/lvm2cmd.c
==============================================================================
--- (empty file)
+++ lvm2/upstream/current/tools/lvm2cmd.c	Mon Oct 23 08:49:10 2006
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of 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
+ */
+
+#include "lvm2cmdline.h"
+#include "lvm2cmd.h"
+
+void *lvm2_init(void)
+{
+	return cmdlib_lvm2_init(0);
+}

Modified: lvm2/upstream/current/tools/lvm2cmdline.h
==============================================================================
--- lvm2/upstream/current/tools/lvm2cmdline.h	(original)
+++ lvm2/upstream/current/tools/lvm2cmdline.h	Mon Oct 23 08:49:10 2006
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2003-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.
  *
@@ -16,6 +16,16 @@
 #ifndef _LVM_CMDLINE_H
 #define _LVM_CMDLINE_H
 
-int lvm2_main(int argc, char **argv, int is_static);
+struct cmd_context;
+
+int lvm2_main(int argc, char **argv, unsigned is_static);
+
+void *cmdlib_lvm2_init(unsigned is_static);
+void lvm_fin(struct cmd_context *cmd);
+
+struct cmd_context *init_lvm(unsigned is_static);
+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);
 
 #endif

Added: lvm2/upstream/current/tools/lvmcmdlib.c
==============================================================================
--- (empty file)
+++ lvm2/upstream/current/tools/lvmcmdlib.c	Mon Oct 23 08:49:10 2006
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.   
+ * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of 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
+ */
+
+#include "tools.h"
+#include "lvm2cmdline.h"
+#include "label.h"
+#include "version.h"
+
+#include "lvm2cmd.h"
+
+#include <signal.h>
+#include <syslog.h>
+#include <libgen.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <sys/resource.h>
+
+void *cmdlib_lvm2_init(unsigned is_static)
+{
+	struct cmd_context *cmd;
+
+	lvm_register_commands();
+
+	if (!(cmd = init_lvm(is_static)))
+		return NULL;
+
+	return (void *) cmd;
+}
+
+int lvm2_run(void *handle, const char *cmdline)
+{
+	int argc, ret, oneoff = 0;
+	char *args[MAX_ARGS], **argv, *cmdcopy = NULL;
+	struct cmd_context *cmd;
+
+	argv = args;
+
+	if (!handle) {
+		oneoff = 1;
+		if (!(handle = lvm2_init())) {
+			log_error("Handle initialisation failed.");
+			return ECMD_FAILED;
+		}
+	}
+
+	cmd = (struct cmd_context *) handle;
+
+	cmd->argv = argv;
+
+	if (!(cmdcopy = dm_strdup(cmdline))) {
+		log_error("Cmdline copy failed.");
+		ret = ECMD_FAILED;
+		goto out;
+	}
+
+	if (lvm_split(cmdcopy, &argc, argv, MAX_ARGS) == MAX_ARGS) {
+		log_error("Too many arguments.  Limit is %d.", MAX_ARGS);
+		ret = EINVALID_CMD_LINE;
+		goto out;
+	}
+
+	if (!argc) {
+		log_error("No command supplied");
+		ret = EINVALID_CMD_LINE;
+		goto out;
+	}
+
+	ret = lvm_run_command(cmd, argc, argv);
+
+      out:
+	dm_free(cmdcopy);
+
+	if (oneoff)
+		lvm2_exit(handle);
+
+	return ret;
+}
+
+void lvm2_log_level(void *handle, int level)
+{
+	struct cmd_context *cmd = (struct cmd_context *) handle;
+
+	cmd->default_settings.verbose = level - VERBOSE_BASE_LEVEL;
+
+	return;
+}
+
+void lvm2_log_fn(lvm2_log_fn_t log_fn)
+{
+	init_log_fn(log_fn);
+}
+
+void lvm2_exit(void *handle)
+{
+	struct cmd_context *cmd = (struct cmd_context *) handle;
+
+	lvm_fin(cmd);
+}

Modified: lvm2/upstream/current/tools/lvmcmdline.c
==============================================================================
--- lvm2/upstream/current/tools/lvmcmdline.c	(original)
+++ lvm2/upstream/current/tools/lvmcmdline.c	Mon Oct 23 08:49:10 2006
@@ -54,7 +54,7 @@
  */
 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), 0, NULL},
+#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
 
@@ -69,6 +69,7 @@
 int yes_no_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a)
 {
 	a->sign = SIGN_NONE;
+	a->percent = PERCENT_NONE;
 
 	if (!strcmp(a->value, "y")) {
 		a->i_value = 1;
@@ -90,6 +91,7 @@
 		    struct arg *a)
 {
 	a->sign = SIGN_NONE;
+	a->percent = PERCENT_NONE;
 
 	if (!strcmp(a->value, "e") || !strcmp(a->value, "ey") ||
 	    !strcmp(a->value, "ye")) {
@@ -148,6 +150,8 @@
 	char *val;
 	long v;
 
+	a->percent = PERCENT_NONE;
+
 	val = a->value;
 	switch (*val) {
 	case '+':
@@ -186,6 +190,8 @@
 	char *val;
 	double v;
 
+	a->percent = PERCENT_NONE;
+
 	val = a->value;
 	switch (*val) {
 	case '+':
@@ -259,6 +265,33 @@
 	return 1;
 }
 
+int int_arg_with_sign_and_percent(struct cmd_context *cmd __attribute((unused)),
+				  struct arg *a)
+{
+	char *ptr;
+
+	if (!_get_int_arg(a, &ptr))
+		return 0;
+
+	if (!*ptr)
+		return 1;
+
+	if (*ptr++ != '%')
+		return 0;
+
+	if (!strcasecmp(ptr, "V") || !strcasecmp(ptr, "VG"))
+		a->percent = PERCENT_VG;
+	else if (!strcasecmp(ptr, "L") || !strcasecmp(ptr, "LV"))
+		a->percent = PERCENT_LV;
+	else if (!strcasecmp(ptr, "F") || !strcasecmp(ptr, "FR") ||
+		 !strcasecmp(ptr, "FREE"))
+		a->percent = PERCENT_FREE;
+	else
+		return 0;
+
+	return 1;
+}
+
 int minor_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a)
 {
 	char *ptr;
@@ -443,7 +476,7 @@
 	_create_new_command(name, fn, desc, usagestr, nargs, args);
 }
 
-static void _register_commands()
+void lvm_register_commands(void)
 {
 #define xx(a, b, c...) _register_command(# a, a, b, ## c, \
 					driverloaded_ARG, \
@@ -707,6 +740,17 @@
 			return EINVALID_CMD_LINE;
 		}
 
+	if (arg_count(cmd, trustcache_ARG)) {
+		if (arg_count(cmd, all_ARG)) {
+			log_error("--trustcache is incompatible with --all");
+			return EINVALID_CMD_LINE;
+		}
+		init_trust_cache(1);
+		log_print("WARNING: Cache file of PVs will be trusted.  "
+			  "New devices holding PVs may get ignored.");
+	} else
+		init_trust_cache(0);
+
 	/* Handle synonyms */
 	if (!_merge_synonym(cmd, resizable_ARG, resizeable_ARG) ||
 	    !_merge_synonym(cmd, allocation_ARG, allocatable_ARG) ||
@@ -832,7 +876,7 @@
 	return NULL;
 }
 
-static int _run_command(struct cmd_context *cmd, int argc, char **argv)
+int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
 {
 	int ret = 0;
 	int locking_type;
@@ -925,7 +969,7 @@
 	return ret;
 }
 
-static int _split(char *str, int *argc, char **argv, int max)
+int lvm_split(char *str, int *argc, char **argv, int max)
 {
 	char *b = str, *e;
 	*argc = 0;
@@ -984,11 +1028,11 @@
 	}
 }
 
-static struct cmd_context *_init_lvm(void)
+struct cmd_context *init_lvm(unsigned is_static)
 {
 	struct cmd_context *cmd;
 
-	if (!(cmd = create_toolcontext(&the_args[0]))) {
+	if (!(cmd = create_toolcontext(&the_args[0], is_static))) {
 		stack;
 		return NULL;
 	}
@@ -1010,7 +1054,7 @@
 	dm_free(_commands);
 }
 
-static void _fin(struct cmd_context *cmd)
+void lvm_fin(struct cmd_context *cmd)
 {
 	_fin_commands();
 	destroy_toolcontext(cmd);
@@ -1044,7 +1088,7 @@
 			ret = EINVALID_CMD_LINE;
 			break;
 		}
-		if (_split(buffer, &argc, argv, MAX_ARGS) == MAX_ARGS) {
+		if (lvm_split(buffer, &argc, argv, MAX_ARGS) == MAX_ARGS) {
 			buffer[50] = '\0';
 			log_error("Too many arguments: %s", buffer);
 			ret = EINVALID_CMD_LINE;
@@ -1054,7 +1098,7 @@
 			continue;
 		if (!strcmp(argv[0], "quit") || !strcmp(argv[0], "exit"))
 			break;
-		_run_command(cmd, argc, argv);
+		lvm_run_command(cmd, argc, argv);
 	}
 
 	fclose(script);
@@ -1177,7 +1221,7 @@
 {
 	char *e = getenv("HOME");
 
-	if (lvm_snprintf(buffer, size, "%s/.lvm_history", e) < 0) {
+	if (dm_snprintf(buffer, size, "%s/.lvm_history", e) < 0) {
 		log_error("$HOME/.lvm_history: path too long");
 		return 0;
 	}
@@ -1240,7 +1284,7 @@
 
 		argv = args;
 
-		if (_split(input, &argc, argv, MAX_ARGS) == MAX_ARGS) {
+		if (lvm_split(input, &argc, argv, MAX_ARGS) == MAX_ARGS) {
 			log_error("Too many arguments, sorry.");
 			continue;
 		}
@@ -1259,7 +1303,7 @@
 			break;
 		}
 
-		ret = _run_command(cmd, argc, argv);
+		ret = lvm_run_command(cmd, argc, argv);
 		if (ret == ENO_SUCH_CMD)
 			log_error("No such command '%s'.  Try 'help'.",
 				  argv[0]);
@@ -1273,92 +1317,6 @@
 
 #endif
 
-#ifdef CMDLIB
-
-void *lvm2_init(void)
-{
-	struct cmd_context *cmd;
-
-	_register_commands();
-
-	if (!(cmd = _init_lvm()))
-		return NULL;
-
-	return (void *) cmd;
-}
-
-int lvm2_run(void *handle, const char *cmdline)
-{
-	int argc, ret, oneoff = 0;
-	char *args[MAX_ARGS], **argv, *cmdcopy = NULL;
-	struct cmd_context *cmd;
-
-	argv = args;
-
-	if (!handle) {
-		oneoff = 1;
-		if (!(handle = lvm2_init())) {
-			log_error("Handle initialisation failed.");
-			return ECMD_FAILED;
-		}
-	}
-
-	cmd = (struct cmd_context *) handle;
-
-	cmd->argv = argv;
-
-	if (!(cmdcopy = dm_strdup(cmdline))) {
-		log_error("Cmdline copy failed.");
-		ret = ECMD_FAILED;
-		goto out;
-	}
-
-	if (_split(cmdcopy, &argc, argv, MAX_ARGS) == MAX_ARGS) {
-		log_error("Too many arguments.  Limit is %d.", MAX_ARGS);
-		ret = EINVALID_CMD_LINE;
-		goto out;
-	}
-
-	if (!argc) {
-		log_error("No command supplied");
-		ret = EINVALID_CMD_LINE;
-		goto out;
-	}
-
-	ret = _run_command(cmd, argc, argv);
-
-      out:
-	dm_free(cmdcopy);
-
-	if (oneoff)
-		lvm2_exit(handle);
-
-	return ret;
-}
-
-void lvm2_log_level(void *handle, int level)
-{
-	struct cmd_context *cmd = (struct cmd_context *) handle;
-
-	cmd->default_settings.verbose = level - VERBOSE_BASE_LEVEL;
-
-	return;
-}
-
-void lvm2_log_fn(lvm2_log_fn_t log_fn)
-{
-	init_log_fn(log_fn);
-}
-
-void lvm2_exit(void *handle)
-{
-	struct cmd_context *cmd = (struct cmd_context *) handle;
-
-	_fin(cmd);
-}
-
-#endif
-
 /*
  * Determine whether we should fall back and exec the equivalent LVM1 tool
  */
@@ -1386,7 +1344,7 @@
 {
 	char path[PATH_MAX];
 
-	if (lvm_snprintf(path, sizeof(path), "%s.lvm1", argv[0]) < 0) {
+	if (dm_snprintf(path, sizeof(path), "%s.lvm1", argv[0]) < 0) {
 		log_error("Failed to create LVM1 tool pathname");
 		return;
 	}
@@ -1395,7 +1353,7 @@
 	log_sys_error("execvp", path);
 }
 
-int lvm2_main(int argc, char **argv, int is_static)
+int lvm2_main(int argc, char **argv, unsigned is_static)
 {
 	char *namebase, *base;
 	int ret, alias = 0;
@@ -1421,11 +1379,11 @@
 
 	free(namebase);
 
-	if (!(cmd = _init_lvm()))
+	if (!(cmd = init_lvm(is_static)))
 		return -1;
 
 	cmd->argv = argv;
-	_register_commands();
+	lvm_register_commands();
 
 	if (_lvm1_fallback(cmd)) {
 		/* Attempt to run equivalent LVM1 tool instead */
@@ -1461,14 +1419,14 @@
 		argv++;
 	}
 
-	ret = _run_command(cmd, argc, argv);
+	ret = lvm_run_command(cmd, argc, argv);
 	if ((ret == ENO_SUCH_CMD) && (!alias))
 		ret = _run_script(cmd, argc, argv);
 	if (ret == ENO_SUCH_CMD)
 		log_error("No such command.  Try 'help'.");
 
       out:
-	_fin(cmd);
+	lvm_fin(cmd);
 	if (ret == ECMD_PROCESSED)
 		ret = 0;
 	return ret;

Modified: lvm2/upstream/current/tools/lvrename.c
==============================================================================
--- lvm2/upstream/current/tools/lvrename.c	(original)
+++ lvm2/upstream/current/tools/lvrename.c	Mon Oct 23 08:49:10 2006
@@ -29,9 +29,7 @@
 	struct lv_list *lvl;
 
 	if (argc == 3) {
-		vg_name = argv[0];
-		if (!strncmp(vg_name, cmd->dev_dir, strlen(cmd->dev_dir)))
-			vg_name += strlen(cmd->dev_dir);
+		vg_name = skip_dev_dir(cmd, argv[0]);
 		lv_name_old = argv[1];
 		lv_name_new = argv[2];
 		if (strchr(lv_name_old, '/') &&
@@ -111,6 +109,12 @@
 		goto error;
 	}
 
+	if ((vg->status & CLUSTERED) && !locking_is_clustered() &&
+	    !lockingfailed()) {
+		log_error("Skipping clustered volume group %s", vg->name);
+		goto error;
+	}
+
 	if (vg->status & EXPORTED_VG) {
 		log_error("Volume group \"%s\" is exported", vg->name);
 		goto error;
@@ -140,6 +144,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/lvresize.c
==============================================================================
--- lvm2/upstream/current/tools/lvresize.c	(original)
+++ lvm2/upstream/current/tools/lvresize.c	Mon Oct 23 08:49:10 2006
@@ -31,6 +31,7 @@
 	uint32_t extents;
 	uint64_t size;
 	sign_t sign;
+	percent_t percent;
 
 	enum {
 		LV_ANY = 0,
@@ -68,12 +69,14 @@
 	if (arg_count(cmd, extents_ARG)) {
 		lp->extents = arg_uint_value(cmd, extents_ARG, 0);
 		lp->sign = arg_sign_value(cmd, extents_ARG, SIGN_NONE);
+		lp->percent = arg_percent_value(cmd, extents_ARG, PERCENT_NONE);
 	}
 
 	/* Size returned in kilobyte units; held in sectors */
 	if (arg_count(cmd, size_ARG)) {
 		lp->size = arg_uint64_value(cmd, size_ARG, UINT64_C(0)) * 2;
 		lp->sign = arg_sign_value(cmd, size_ARG, SIGN_NONE);
+		lp->percent = PERCENT_NONE;
 	}
 
 	if (lp->resize == LV_EXTEND && lp->sign == SIGN_MINUS) {
@@ -138,6 +141,12 @@
 		return ECMD_FAILED;
 	}
 
+	if ((vg->status & CLUSTERED) && !locking_is_clustered() &&
+	    !lockingfailed()) {
+		log_error("Skipping clustered volume group %s", vg->name);
+		return ECMD_FAILED;
+	}
+
 	if (vg->status & EXPORTED_VG) {
 		log_error("Volume group %s is exported", vg->name);
 		return ECMD_FAILED;
@@ -232,6 +241,20 @@
 		lp->extents = lp->size / vg->extent_size;
 	}
 
+	switch(lp->percent) {
+		case PERCENT_VG:
+			lp->extents = lp->extents * vg->extent_count / 100;
+			break;
+		case PERCENT_FREE:
+			lp->extents = lp->extents * vg->free_count / 100;
+			break;
+		case PERCENT_LV:
+			lp->extents = lp->extents * lv->le_count / 100;
+			break;
+		case PERCENT_NONE:
+			break;
+	}
+
 	if (lp->sign == SIGN_PLUS)
 		lp->extents += lv->le_count;
 
@@ -480,14 +503,14 @@
 	}
 
 	if (lp->resizefs) {
-		if (lvm_snprintf(lv_path, PATH_MAX, "%s%s/%s", cmd->dev_dir,
+		if (dm_snprintf(lv_path, PATH_MAX, "%s%s/%s", cmd->dev_dir,
 				 lp->vg_name, lp->lv_name) < 0) {
 			log_error("Couldn't create LV path for %s",
 				  lp->lv_name);
 			return ECMD_FAILED;
 		}
 
-		if (lvm_snprintf(size_buf, SIZE_BUF, "%" PRIu64,
+		if (dm_snprintf(size_buf, SIZE_BUF, "%" PRIu64,
 				 (uint64_t) lp->extents * vg->extent_size / 2)
 				 < 0) {
 			log_error("Couldn't generate new LV size string");

Modified: lvm2/upstream/current/tools/pvchange.c
==============================================================================
--- lvm2/upstream/current/tools/pvchange.c	(original)
+++ lvm2/upstream/current/tools/pvchange.c	Mon Oct 23 08:49:10 2006
@@ -67,6 +67,12 @@
 			return 0;
 		}
 
+		if ((vg->status & CLUSTERED) && !locking_is_clustered() &&
+		    !lockingfailed()) {
+			log_error("Skipping clustered volume group %s", vg->name);
+			return 0;
+		}
+
 		if (vg->status & EXPORTED_VG) {
 			unlock_vg(cmd, pv->vg_name);
 			log_error("Volume group \"%s\" is exported", vg->name);

Modified: lvm2/upstream/current/tools/pvdisplay.c
==============================================================================
--- lvm2/upstream/current/tools/pvdisplay.c	(original)
+++ lvm2/upstream/current/tools/pvdisplay.c	Mon Oct 23 08:49:10 2006
@@ -19,10 +19,32 @@
 			     struct volume_group *vg __attribute((unused)),
 			     struct physical_volume *pv, void *handle)
 {
+	int consistent = 0;
+	int ret = ECMD_PROCESSED;
 	uint64_t size;
 
 	const char *pv_name = dev_name(pv->dev);
 
+	 if (pv->vg_name) {
+	         if (!lock_vol(cmd, pv->vg_name, LCK_VG_READ)) {
+	                 log_error("Can't lock %s: skipping", pv->vg_name);
+	                 return ECMD_FAILED;
+	         }
+
+	         if (!(vg = vg_read(cmd, pv->vg_name, (char *)&pv->vgid, &consistent))) {
+	                 log_error("Can't read %s: skipping", pv->vg_name);
+	                 goto out;
+	         }
+
+	         if ((vg->status & CLUSTERED) && !locking_is_clustered() &&
+	             !lockingfailed()) {
+	                 log_error("Skipping clustered volume group %s",
+	                           vg->name);
+	                 ret = ECMD_FAILED;
+	                 goto out;
+	         }
+	 }
+
 	if (!*pv->vg_name)
 		size = pv->size;
 	else
@@ -31,7 +53,7 @@
 	if (arg_count(cmd, short_ARG)) {
 		log_print("Device \"%s\" has a capacity of %s", pv_name,
 			  display_size(cmd, size));
-		return ECMD_PROCESSED;
+		goto out;
 	}
 
 	if (pv->status & EXPORTED_VG)
@@ -44,15 +66,19 @@
 
 	if (arg_count(cmd, colon_ARG)) {
 		pvdisplay_colons(pv);
-		return ECMD_PROCESSED;
+		goto out;
 	}
 
 	pvdisplay_full(cmd, pv, handle);
 
 	if (!arg_count(cmd, maps_ARG))
-		return ECMD_PROCESSED;
+		goto out;
+
+out:
+        if (pv->vg_name)
+                unlock_vg(cmd, pv->vg_name);
 
-	return ECMD_PROCESSED;
+	return ret;
 }
 
 int pvdisplay(struct cmd_context *cmd, int argc, char **argv)

Modified: lvm2/upstream/current/tools/pvmove.c
==============================================================================
--- lvm2/upstream/current/tools/pvmove.c	(original)
+++ lvm2/upstream/current/tools/pvmove.c	Mon Oct 23 08:49:10 2006
@@ -27,9 +27,7 @@
 	if (!strchr(arg, '/'))
 		return arg;
 
-	lvname = arg;
-	if (!strncmp(lvname, cmd->dev_dir, strlen(cmd->dev_dir)))
-		lvname += strlen(cmd->dev_dir);
+	lvname = skip_dev_dir(cmd, arg);
 	while (*lvname == '/')
 		lvname++;
 	if (!strchr(lvname, '/')) {
@@ -68,6 +66,12 @@
 		return NULL;
 	}
 
+	if ((vg->status & CLUSTERED) && !locking_is_clustered() &&
+	    !lockingfailed()) {
+		log_error("Skipping clustered volume group %s", vgname);
+		return NULL;
+	}
+
 	if (vg->status & EXPORTED_VG) {
 		log_error("Volume group \"%s\" is exported", vgname);
 		unlock_vg(cmd, vgname);

Modified: lvm2/upstream/current/tools/pvresize.c
==============================================================================
--- lvm2/upstream/current/tools/pvresize.c	(original)
+++ lvm2/upstream/current/tools/pvresize.c	Mon Oct 23 08:49:10 2006
@@ -77,6 +77,13 @@
 			return ECMD_FAILED;
 		}
 
+		if ((vg->status & CLUSTERED) && !locking_is_clustered() &&
+		    !lockingfailed()) {
+			unlock_vg(cmd, vg_name);
+			log_error("Skipping clustered volume group %s", vg->name);
+			return ECMD_FAILED;
+		}
+
 		if (vg->status & EXPORTED_VG) {
 			unlock_vg(cmd, vg_name);
 			log_error("Volume group \"%s\" is exported", vg->name);

Modified: lvm2/upstream/current/tools/reporter.c
==============================================================================
--- lvm2/upstream/current/tools/reporter.c	(original)
+++ lvm2/upstream/current/tools/reporter.c	Mon Oct 23 08:49:10 2006
@@ -68,13 +68,20 @@
 
 	if (!(vg = vg_read(cmd, pv->vg_name, NULL, &consistent))) {
 		log_error("Can't read %s: skipping", pv->vg_name);
-		unlock_vg(cmd, pv->vg_name);
-		return ECMD_FAILED;
+		goto out;
+	}
+
+	if ((vg->status & CLUSTERED) && !locking_is_clustered() &&
+	    !lockingfailed()) {
+		log_error("Skipping clustered volume group %s", vg->name);
+		ret = ECMD_FAILED;
+		goto out;
 	}
 
 	if (!report_object(handle, vg, NULL, pv, NULL, pvseg))
 		ret = ECMD_FAILED;
 
+out:
 	unlock_vg(cmd, pv->vg_name);
 	return ret;
 }
@@ -109,14 +116,22 @@
 
 		if (!(vg = vg_read(cmd, pv->vg_name, (char *)&pv->vgid, &consistent))) {
 			log_error("Can't read %s: skipping", pv->vg_name);
-			unlock_vg(cmd, pv->vg_name);
-			return ECMD_FAILED;
+			goto out;
+		}
+
+		if ((vg->status & CLUSTERED) && !locking_is_clustered() &&
+		    !lockingfailed()) {
+			log_error("Skipping clustered volume group %s",
+				  vg->name);
+			ret = ECMD_FAILED;
+			goto out;
 		}
 	}
 
 	if (!report_object(handle, vg, NULL, pv, NULL, NULL))
 		ret = ECMD_FAILED;
 
+out:
 	if (pv->vg_name)
 		unlock_vg(cmd, pv->vg_name);
 

Modified: lvm2/upstream/current/tools/toollib.c
==============================================================================
--- lvm2/upstream/current/tools/toollib.c	(original)
+++ lvm2/upstream/current/tools/toollib.c	Mon Oct 23 08:49:10 2006
@@ -70,6 +70,11 @@
 	return arg_count(cmd, a) ? cmd->args[a].sign : def;
 }
 
+percent_t arg_percent_value(struct cmd_context *cmd, int a, const percent_t def)
+{
+	return arg_count(cmd, a) ? cmd->args[a].percent : def;
+}
+
 int arg_count_increment(struct cmd_context *cmd, int a)
 {
 	return cmd->args[a].count++;
@@ -81,6 +86,28 @@
 }
 
 /*
+ * Strip dev_dir if present
+ */
+char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name)
+{
+	/* FIXME Do this properly */
+
+	if (*vg_name == '/') {
+		while (*vg_name == '/')
+			vg_name++;
+		vg_name--;
+	}
+
+	if (!strncmp(vg_name, cmd->dev_dir, strlen(cmd->dev_dir))) {
+		vg_name += strlen(cmd->dev_dir);
+		while (*vg_name == '/')
+			vg_name++;
+	}
+
+	return (char *) vg_name;
+}
+
+/*
  * Metadata iteration functions
  */
 int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
@@ -268,7 +295,7 @@
 			} else {
 				vglv_sz = strlen(vgname) + strlen(lv_name) + 2;
 				if (!(vglv = dm_pool_alloc(cmd->mem, vglv_sz)) ||
-				    lvm_snprintf(vglv, vglv_sz, "%s/%s", vgname,
+				    dm_snprintf(vglv, vglv_sz, "%s/%s", vgname,
 						 lv_name) < 0) {
 					log_error("vg/lv string alloc failed");
 					return ECMD_FAILED;
@@ -307,9 +334,20 @@
 			if (!vg)
 				log_error("Volume group \"%s\" "
 					  "not found", vgname);
-			else
+			else {
+				if ((vg->status & CLUSTERED) &&
+			    	    !locking_is_clustered() &&
+				    !lockingfailed()) {
+					log_error("Skipping clustered volume "
+						  "group %s", vgname);
+					if (ret_max < ECMD_FAILED)
+						ret_max = ECMD_FAILED;
+					continue;
+				}
 				log_error("Volume group \"%s\" "
 					  "inconsistent", vgname);
+			}
+
 			if (!vg || !(vg = recover_vg(cmd, vgname, lock_type))) {
 				if (ret_max < ECMD_FAILED)
 					ret_max = ECMD_FAILED;
@@ -317,6 +355,15 @@
 			}
 		}
 
+		if ((vg->status & CLUSTERED) && !locking_is_clustered() &&
+		    !lockingfailed()) {
+			unlock_vg(cmd, vgname);
+			log_error("Skipping clustered volume group %s", vgname);
+			if (ret_max < ECMD_FAILED)
+				ret_max = ECMD_FAILED;
+			continue;
+		}
+
 		tags_arg = &tags;
 		list_init(&lvnames);	/* LVs to be processed in this VG */
 		list_iterate_items(sll, &arg_lvnames) {
@@ -416,6 +463,13 @@
 		return ECMD_FAILED;
 	}
 
+	if ((vg->status & CLUSTERED) && !locking_is_clustered() &&
+	    !lockingfailed()) {
+		log_error("Skipping clustered volume group %s", vg_name);
+		unlock_vg(cmd, vg_name);
+		return ECMD_FAILED;
+	}
+
 	if (!list_empty(tags)) {
 		/* Only process if a tag matches or it's on arg_vgnames */
 		if (!str_list_match_item(arg_vgnames, vg_name) &&
@@ -450,7 +504,6 @@
 	struct list arg_vgnames, tags;
 
 	const char *vg_name, *vgid;
-	char *dev_dir = cmd->dev_dir;
 
 	list_init(&tags);
 	list_init(&arg_vgnames);
@@ -475,13 +528,7 @@
 				continue;
 			}
 
-			if (*vg_name == '/') {
-				while (*vg_name == '/')
-					vg_name++;
-				vg_name--;
-			}
-			if (!strncmp(vg_name, dev_dir, strlen(dev_dir)))
-				vg_name += strlen(dev_dir);
+			vg_name = skip_dev_dir(cmd, vg_name);
 			if (strchr(vg_name, '/')) {
 				log_error("Invalid volume group name: %s",
 					  vg_name);
@@ -665,6 +712,15 @@
 				}
 				if (!consistent)
 					continue;
+
+				if ((vg->status & CLUSTERED) &&
+				    !locking_is_clustered() &&
+				    !lockingfailed()) {
+					log_error("Skipping clustered volume "
+						  "group %s", sll->str);
+					continue;
+				}
+
 				ret = process_each_pv_in_vg(cmd, vg, &tags,
 							    handle,
 							    process_single);
@@ -768,21 +824,13 @@
 char *default_vgname(struct cmd_context *cmd)
 {
 	char *vg_path;
-	char *dev_dir = cmd->dev_dir;
 
 	/* Take default VG from environment? */
 	vg_path = getenv("LVM_VG_NAME");
 	if (!vg_path)
 		return 0;
 
-	/* Strip dev_dir (optional) */
-	if (*vg_path == '/') {
-		while (*vg_path == '/')
-			vg_path++;
-		vg_path--;
-	}
-	if (!strncmp(vg_path, dev_dir, strlen(dev_dir)))
-		vg_path += strlen(dev_dir);
+	vg_path = skip_dev_dir(cmd, vg_path);
 
 	if (strchr(vg_path, '/')) {
 		log_error("Environment Volume Group in LVM_VG_NAME invalid: "
@@ -1038,6 +1086,10 @@
 {
 	int consistent = 1;
 
+	/* Don't attempt automatic recovery without proper locking */
+	if (lockingfailed())
+		return NULL;
+
 	lock_type &= ~LCK_TYPE_MASK;
 	lock_type |= LCK_WRITE;
 
@@ -1098,14 +1150,14 @@
 int generate_log_name_format(struct volume_group *vg __attribute((unused)),
 			     const char *lv_name, char *buffer, size_t size)
 {
-	if (lvm_snprintf(buffer, size, "%s_mlog", lv_name) < 0) {
+	if (dm_snprintf(buffer, size, "%s_mlog", lv_name) < 0) {
 		stack;
 		return 0;
 	}
 
 	/* FIXME I think we can cope without this.  Cf. _add_lv_to_dtree()
 	if (find_lv_in_vg(vg, buffer) &&
-	    lvm_snprintf(buffer, size, "%s_mlog_%%d",
+	    dm_snprintf(buffer, size, "%s_mlog_%%d",
 			 lv_name) < 0) {
 		stack;
 		return 0;
@@ -1135,7 +1187,7 @@
 		return 0;
 	}
 
-	if (lvm_snprintf(name, PATH_MAX, "%s%s/%s", cmd->dev_dir,
+	if (dm_snprintf(name, PATH_MAX, "%s%s/%s", cmd->dev_dir,
 			 lv->vg->name, lv->name) < 0) {
 		log_error("Name too long - device not cleared (%s)", lv->name);
 		return 0;
@@ -1157,7 +1209,6 @@
 	return 1;
 }
 
-
 /*
  * This function writes a new header to the mirror log header to the lv
  *
@@ -1183,7 +1234,7 @@
 		return 0;
 	}
 
-	if (lvm_snprintf(name, PATH_MAX, "%s%s/%s", cmd->dev_dir,
+	if (dm_snprintf(name, PATH_MAX, "%s%s/%s", cmd->dev_dir,
 			 lv->vg->name, lv->name) < 0) {
 		log_error("Name too long - log header not written (%s)", lv->name);
 		return 0;
@@ -1254,6 +1305,12 @@
 		goto error;
 	}
 
+	if (!activation() && in_sync) {
+		log_error("Aborting. Unable to create in-sync mirror log "
+			  "while activation is disabled.");
+		goto error;
+	}
+
 	if (!activate_lv(cmd, log_lv)) {
 		log_error("Aborting. Failed to activate mirror log. "
 			  "Remove new LVs and retry.");
@@ -1266,7 +1323,7 @@
 		goto error;
 	}
 
-	if (!_write_log_header(cmd, log_lv)) {
+	if (activation() && !_write_log_header(cmd, log_lv)) {
 		log_error("Aborting. Failed to write mirror log header. "
 			  "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	Mon Oct 23 08:49:10 2006
@@ -76,6 +76,7 @@
 
 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);
 
 /*
  * Builds a list of pv's from the names in argv.  Used in

Modified: lvm2/upstream/current/tools/tools.h
==============================================================================
--- lvm2/upstream/current/tools/tools.h	(original)
+++ lvm2/upstream/current/tools/tools.h	Mon Oct 23 08:49:10 2006
@@ -80,6 +80,13 @@
 	SIGN_MINUS = 2
 } sign_t;
 
+typedef enum {
+	PERCENT_NONE = 0,
+	PERCENT_VG,
+	PERCENT_FREE,
+	PERCENT_LV
+} percent_t;
+
 enum {
 	CHANGE_AY = 0,
 	CHANGE_AN = 1,
@@ -103,6 +110,7 @@
 	int64_t i64_value;
 	uint64_t ui64_value;
 	sign_t sign;
+	percent_t percent;
 	void *ptr;
 };
 
@@ -126,6 +134,7 @@
 int size_mb_arg(struct cmd_context *cmd, struct arg *a);
 int int_arg(struct cmd_context *cmd, struct arg *a);
 int int_arg_with_sign(struct cmd_context *cmd, struct arg *a);
+int int_arg_with_sign_and_percent(struct cmd_context *cmd, struct arg *a);
 int major_arg(struct cmd_context *cmd, struct arg *a);
 int minor_arg(struct cmd_context *cmd, struct arg *a);
 int string_arg(struct cmd_context *cmd, struct arg *a);
@@ -148,6 +157,7 @@
 uint64_t arg_uint64_value(struct cmd_context *cmd, int a, const uint64_t def);
 const void *arg_ptr_value(struct cmd_context *cmd, int a, const void *def);
 sign_t arg_sign_value(struct cmd_context *cmd, int a, const sign_t def);
+percent_t arg_percent_value(struct cmd_context *cmd, int a, const percent_t def);
 int arg_count_increment(struct cmd_context *cmd, int a);
 
 const char *command_name(struct cmd_context *cmd);

Modified: lvm2/upstream/current/tools/vgcfgrestore.c
==============================================================================
--- lvm2/upstream/current/tools/vgcfgrestore.c	(original)
+++ lvm2/upstream/current/tools/vgcfgrestore.c	Mon Oct 23 08:49:10 2006
@@ -24,10 +24,7 @@
 		return ECMD_FAILED;
 	}
 
-	vg_name = argv[0];
-
-	if (!strncmp(vg_name, cmd->dev_dir, strlen(cmd->dev_dir)))
-		vg_name += strlen(cmd->dev_dir);
+	vg_name = skip_dev_dir(cmd, argv[0]);
 
 	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	Mon Oct 23 08:49:10 2006
@@ -312,7 +312,7 @@
 
 	if (max_lv && max_lv < vg->lv_count) {
 		log_error("MaxLogicalVolume is less than the current number "
-			  "%d of logical volume(s) for \"%s\"", vg->lv_count,
+			  "%d of LVs for \"%s\"", vg->lv_count,
 			  vg->name);
 		return ECMD_FAILED;
 	}
@@ -332,6 +332,53 @@
 	return ECMD_PROCESSED;
 }
 
+static int _vgchange_physicalvolumes(struct cmd_context *cmd,
+				     struct volume_group *vg)
+{
+	uint32_t max_pv = arg_uint_value(cmd, maxphysicalvolumes_ARG, 0);
+
+	if (!(vg->status & RESIZEABLE_VG)) {
+		log_error("Volume group \"%s\" must be resizeable "
+			  "to change MaxPhysicalVolumes", vg->name);
+		return ECMD_FAILED;
+	}
+
+	if (arg_sign_value(cmd, maxphysicalvolumes_ARG, 0) == SIGN_MINUS) {
+		log_error("MaxPhysicalVolumes may not be negative");
+		return EINVALID_CMD_LINE;
+	}
+
+	if (!(vg->fid->fmt->features & FMT_UNLIMITED_VOLS)) {
+		if (!max_pv)
+			max_pv = 255;
+		else if (max_pv > 255) {
+			log_error("MaxPhysicalVolume limit is 255");
+			return ECMD_FAILED;
+		}
+	}
+
+	if (max_pv && max_pv < vg->pv_count) {
+		log_error("MaxPhysicalVolumes is less than the current number "
+			  "%d of PVs for \"%s\"", vg->pv_count,
+			  vg->name);
+		return ECMD_FAILED;
+	}
+
+	if (!archive(vg))
+		return ECMD_FAILED;
+
+	vg->max_pv = max_pv;
+
+	if (!vg_write(vg) || !vg_commit(vg))
+		return ECMD_FAILED;
+
+	backup(vg);
+
+	log_print("Volume group \"%s\" successfully changed", vg->name);
+
+	return ECMD_PROCESSED;
+}
+
 static int _vgchange_pesize(struct cmd_context *cmd, struct volume_group *vg)
 {
 	uint32_t extent_size;
@@ -508,6 +555,9 @@
 	else if (arg_count(cmd, logicalvolume_ARG))
 		r = _vgchange_logicalvolume(cmd, vg);
 
+	else if (arg_count(cmd, maxphysicalvolumes_ARG))
+		r = _vgchange_physicalvolumes(cmd, vg);
+
 	else if (arg_count(cmd, addtag_ARG))
 		r = _vgchange_tag(cmd, vg, addtag_ARG);
 
@@ -533,24 +583,26 @@
 {
 	if (!
 	    (arg_count(cmd, available_ARG) + arg_count(cmd, logicalvolume_ARG) +
+	     arg_count(cmd, maxphysicalvolumes_ARG) +
 	     arg_count(cmd, resizeable_ARG) + arg_count(cmd, deltag_ARG) +
 	     arg_count(cmd, addtag_ARG) + arg_count(cmd, uuid_ARG) +
 	     arg_count(cmd, physicalextentsize_ARG) +
 	     arg_count(cmd, clustered_ARG) + arg_count(cmd, alloc_ARG) +
 	     arg_count(cmd, monitor_ARG))) {
-		log_error("One of -a, -c, -l, -s, -x, --uuid, --alloc, --addtag or "
-			  "--deltag required");
+		log_error("One of -a, -c, -l, -p, -s, -x, --uuid, --alloc, "
+			  "--addtag or --deltag required");
 		return EINVALID_CMD_LINE;
 	}
 
 	/* FIXME Cope with several changes at once! */
 	if (arg_count(cmd, available_ARG) + arg_count(cmd, logicalvolume_ARG) +
+	    arg_count(cmd, maxphysicalvolumes_ARG) +
 	    arg_count(cmd, resizeable_ARG) + arg_count(cmd, deltag_ARG) +
 	    arg_count(cmd, addtag_ARG) + arg_count(cmd, alloc_ARG) +
 	    arg_count(cmd, uuid_ARG) + arg_count(cmd, clustered_ARG) +
 	    arg_count(cmd, physicalextentsize_ARG) > 1) {
-		log_error("Only one of -a, -c, -l, -s, -x, --uuid, --alloc, "
-			  "--addtag or --deltag allowed");
+		log_error("Only one of -a, -c, -l, -p, -s, -x, --uuid, "
+			  "--alloc, --addtag or --deltag allowed");
 		return EINVALID_CMD_LINE;
 	}
 

Modified: lvm2/upstream/current/tools/vgcreate.c
==============================================================================
--- lvm2/upstream/current/tools/vgcreate.c	(original)
+++ lvm2/upstream/current/tools/vgcreate.c	Mon Oct 23 08:49:10 2006
@@ -38,7 +38,7 @@
 		return EINVALID_CMD_LINE;
 	}
 
-	vg_name = argv[0];
+	vg_name = skip_dev_dir(cmd, argv[0]);
 	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);
@@ -84,10 +84,6 @@
 		return EINVALID_CMD_LINE;
 	}
 
-	/* Strip dev_dir if present */
-	if (!strncmp(vg_name, cmd->dev_dir, strlen(cmd->dev_dir)))
-		vg_name += strlen(cmd->dev_dir);
-
 	if (!validate_vg_name(cmd, vg_name)) {
 		log_error("New volume group name \"%s\" is invalid", vg_name);
 		return ECMD_FAILED;

Modified: lvm2/upstream/current/tools/vgextend.c
==============================================================================
--- lvm2/upstream/current/tools/vgextend.c	(original)
+++ lvm2/upstream/current/tools/vgextend.c	Mon Oct 23 08:49:10 2006
@@ -32,7 +32,7 @@
 		return EINVALID_CMD_LINE;
 	}
 
-	vg_name = argv[0];
+	vg_name = skip_dev_dir(cmd, argv[0]);
 	argc--;
 	argv++;
 
@@ -53,6 +53,12 @@
 		goto error;
 	}
 
+	if ((vg->status & CLUSTERED) && !locking_is_clustered() &&
+	    !lockingfailed()) {
+		log_error("Skipping clustered volume group %s", vg->name);
+		goto error;
+	}
+
 	if (vg->status & EXPORTED_VG) {
 		log_error("Volume group \"%s\" is exported", vg->name);
 		goto error;

Modified: lvm2/upstream/current/tools/vgmerge.c
==============================================================================
--- lvm2/upstream/current/tools/vgmerge.c	(original)
+++ lvm2/upstream/current/tools/vgmerge.c	Mon Oct 23 08:49:10 2006
@@ -41,6 +41,13 @@
 		return ECMD_FAILED;
 	}
 
+	if ((vg_to->status & CLUSTERED) && !locking_is_clustered() &&
+	    !lockingfailed()) {
+		log_error("Skipping clustered volume group %s", vg_name_to);
+		unlock_vg(cmd, vg_name_to);
+		return ECMD_FAILED;
+	}
+
 	if (vg_to->status & EXPORTED_VG) {
 		log_error("Volume group \"%s\" is exported", vg_to->name);
 		unlock_vg(cmd, vg_name_to);
@@ -66,6 +73,12 @@
 		goto error;
 	}
 
+        if ((vg_from->status & CLUSTERED) && !locking_is_clustered() &&
+            !lockingfailed()) {
+                log_error("Skipping clustered volume group %s", vg_name_from);
+                goto error;
+        }
+
 	if (vg_from->status & EXPORTED_VG) {
 		log_error("Volume group \"%s\" is exported", vg_from->name);
 		goto error;
@@ -231,7 +244,7 @@
 
 int vgmerge(struct cmd_context *cmd, int argc, char **argv)
 {
-	char *vg_name_to;
+	char *vg_name_to, *vg_name_from;
 	int opt = 0;
 	int ret = 0, ret_max = 0;
 
@@ -240,12 +253,14 @@
 		return EINVALID_CMD_LINE;
 	}
 
-	vg_name_to = argv[0];
+	vg_name_to = skip_dev_dir(cmd, argv[0]);
 	argc--;
 	argv++;
 
 	for (; opt < argc; opt++) {
-		ret = _vgmerge_single(cmd, vg_name_to, argv[opt]);
+		vg_name_from = skip_dev_dir(cmd, argv[opt]);
+
+		ret = _vgmerge_single(cmd, vg_name_to, vg_name_from);
 		if (ret > ret_max)
 			ret_max = ret;
 	}

Modified: lvm2/upstream/current/tools/vgreduce.c
==============================================================================
--- lvm2/upstream/current/tools/vgreduce.c	(original)
+++ lvm2/upstream/current/tools/vgreduce.c	Mon Oct 23 08:49:10 2006
@@ -459,7 +459,7 @@
 		return EINVALID_CMD_LINE;
 	}
 
-	vg_name = argv[0];
+	vg_name = skip_dev_dir(cmd, argv[0]);
 	argv++;
 	argc--;
 
@@ -476,6 +476,13 @@
 		return ECMD_FAILED;
 	}
 
+	if (vg && (vg->status & CLUSTERED) && !locking_is_clustered() &&
+	    !lockingfailed()) {
+		log_error("Skipping clustered volume group %s", vg->name);
+		unlock_vg(cmd, vg_name);
+		return ECMD_FAILED;
+	}
+
 	if (arg_count(cmd, removemissing_ARG)) {
 		if (vg && consistent) {
 			log_error("Volume group \"%s\" is already consistent",
@@ -491,6 +498,13 @@
 			unlock_vg(cmd, vg_name);
 			return ECMD_FAILED;
 		}
+		if ((vg->status & CLUSTERED) && !locking_is_clustered() &&
+		    !lockingfailed()) {
+			log_error("Skipping clustered volume group %s",
+				  vg->name);
+			unlock_vg(cmd, vg_name);
+			return ECMD_FAILED;
+		}
 		if (!archive(vg)) {
 			init_partial(0);
 			unlock_vg(cmd, vg_name);

Modified: lvm2/upstream/current/tools/vgrename.c
==============================================================================
--- lvm2/upstream/current/tools/vgrename.c	(original)
+++ lvm2/upstream/current/tools/vgrename.c	Mon Oct 23 08:49:10 2006
@@ -35,18 +35,12 @@
 		return EINVALID_CMD_LINE;
 	}
 
-	vg_name_old = argv[0];
-	vg_name_new = argv[1];
+	vg_name_old = skip_dev_dir(cmd, argv[0]);
+	vg_name_new = skip_dev_dir(cmd, argv[1]);
 
 	dev_dir = cmd->dev_dir;
 	length = strlen(dev_dir);
 
-	/* If present, strip dev_dir */
-	if (!strncmp(vg_name_old, dev_dir, length))
-		vg_name_old += length;
-	if (!strncmp(vg_name_new, dev_dir, length))
-		vg_name_new += length;
-
 	/* Check sanity of new name */
 	if (strlen(vg_name_new) > NAME_LEN - length - 2) {
 		log_error("New volume group path exceeds maximum length "
@@ -108,6 +102,13 @@
 		return ECMD_FAILED;
 	}
 
+	if ((vg_old->status & CLUSTERED) && !locking_is_clustered() &&
+	    !lockingfailed()) {
+		log_error("Skipping clustered volume group %s", vg_old->name);
+		unlock_vg(cmd, vg_name_old);
+		return ECMD_FAILED;
+	}
+
 	if (vg_old->status & EXPORTED_VG)
 		log_info("Volume group \"%s\" is exported", vg_old->name);
 

Modified: lvm2/upstream/current/tools/vgsplit.c
==============================================================================
--- lvm2/upstream/current/tools/vgsplit.c	(original)
+++ lvm2/upstream/current/tools/vgsplit.c	Mon Oct 23 08:49:10 2006
@@ -196,12 +196,25 @@
 		return ECMD_FAILED;
 	}
 
+	if ((vg_from->status & CLUSTERED) && !locking_is_clustered() &&
+	    !lockingfailed()) {
+		log_error("Skipping clustered volume group %s", vg_from->name);
+		unlock_vg(cmd, vg_name_from);
+		return ECMD_FAILED;
+	}
+
 	if (vg_from->status & EXPORTED_VG) {
 		log_error("Volume group \"%s\" is exported", vg_from->name);
 		unlock_vg(cmd, vg_name_from);
 		return ECMD_FAILED;
 	}
 
+	if (!(vg_from->status & RESIZEABLE_VG)) {
+		log_error("Volume group \"%s\" is not resizeable", vg_from->name);
+		unlock_vg(cmd, vg_name_from);
+		return ECMD_FAILED;
+	}
+
 	if (!(vg_from->status & LVM_WRITE)) {
 		log_error("Volume group \"%s\" is read-only", vg_from->name);
 		unlock_vg(cmd, vg_name_from);
@@ -241,6 +254,9 @@
 				vg_from->alloc, 0, NULL)))
 		goto error;
 
+	if (vg_from->status & CLUSTERED)
+		vg_to->status |= CLUSTERED;
+
 	/* Archive vg_from before changing it */
 	if (!archive(vg_from))
 		goto error;



More information about the pkg-lvm-commits mailing list