r97 - in lvm2/trunk: . daemons/clvmd doc include lib lib/activate lib/cache lib/commands lib/config lib/datastruct lib/device lib/display lib/filters lib/format1 lib/format_pool lib/format_text lib/label lib/locking lib/log lib/metadata lib/mirror lib/misc lib/mm lib/report lib/snapshot lib/striped lib/uuid man po scripts tools

Bastian Blank waldi at costa.debian.org
Thu Jul 21 12:48:14 UTC 2005


Author: waldi
Date: Tue Jun 14 11:23:47 2005
New Revision: 97

Added:
   lvm2/trunk/CONTRIBUTORS
   lvm2/trunk/lib/format_text/archiver.c
   lvm2/trunk/lib/format_text/archiver.h
   lvm2/trunk/lib/metadata/pv_alloc.h
   lvm2/trunk/lib/metadata/pv_manip.c
   lvm2/trunk/scripts/lvmconf.sh
   lvm2/trunk/tools/lvconvert.c
   lvm2/trunk/tools/lvm-static.c
Removed:
   lvm2/trunk/tools/archiver.c
   lvm2/trunk/tools/archiver.h
Modified:
   lvm2/trunk/   (props changed)
   lvm2/trunk/VERSION
   lvm2/trunk/WHATS_NEW
   lvm2/trunk/daemons/clvmd/Makefile.in
   lvm2/trunk/daemons/clvmd/clvmd-cman.c
   lvm2/trunk/daemons/clvmd/clvmd-command.c
   lvm2/trunk/daemons/clvmd/clvmd-comms.h
   lvm2/trunk/daemons/clvmd/clvmd-gulm.c
   lvm2/trunk/daemons/clvmd/clvmd.c
   lvm2/trunk/daemons/clvmd/clvmd.h
   lvm2/trunk/daemons/clvmd/lvm-functions.c
   lvm2/trunk/daemons/clvmd/lvm-functions.h
   lvm2/trunk/daemons/clvmd/tcp-comms.c
   lvm2/trunk/daemons/clvmd/tcp-comms.h
   lvm2/trunk/doc/example.conf
   lvm2/trunk/include/.symlinks
   lvm2/trunk/lib/Makefile.in
   lvm2/trunk/lib/activate/activate.c
   lvm2/trunk/lib/activate/dev_manager.c
   lvm2/trunk/lib/activate/fs.c
   lvm2/trunk/lib/activate/targets.h
   lvm2/trunk/lib/cache/lvmcache.c
   lvm2/trunk/lib/cache/lvmcache.h
   lvm2/trunk/lib/commands/toolcontext.c
   lvm2/trunk/lib/commands/toolcontext.h
   lvm2/trunk/lib/config/config.c
   lvm2/trunk/lib/config/defaults.h
   lvm2/trunk/lib/datastruct/list.h
   lvm2/trunk/lib/datastruct/lvm-types.h
   lvm2/trunk/lib/device/dev-cache.c
   lvm2/trunk/lib/device/dev-cache.h
   lvm2/trunk/lib/device/dev-io.c
   lvm2/trunk/lib/device/device.h
   lvm2/trunk/lib/display/display.c
   lvm2/trunk/lib/filters/filter-persistent.c
   lvm2/trunk/lib/filters/filter-regex.c
   lvm2/trunk/lib/filters/filter-sysfs.c
   lvm2/trunk/lib/filters/filter.c
   lvm2/trunk/lib/format1/disk-rep.c
   lvm2/trunk/lib/format1/format1.c
   lvm2/trunk/lib/format1/import-export.c
   lvm2/trunk/lib/format1/import-extents.c
   lvm2/trunk/lib/format1/vg_number.c
   lvm2/trunk/lib/format_pool/disk_rep.c
   lvm2/trunk/lib/format_pool/format_pool.c
   lvm2/trunk/lib/format_pool/import_export.c
   lvm2/trunk/lib/format_text/archive.c
   lvm2/trunk/lib/format_text/export.c
   lvm2/trunk/lib/format_text/flags.c
   lvm2/trunk/lib/format_text/format-text.c
   lvm2/trunk/lib/format_text/import-export.h
   lvm2/trunk/lib/format_text/import_vsn1.c
   lvm2/trunk/lib/format_text/layout.h
   lvm2/trunk/lib/format_text/text_export.h
   lvm2/trunk/lib/format_text/text_import.h
   lvm2/trunk/lib/format_text/text_label.c
   lvm2/trunk/lib/label/label.c
   lvm2/trunk/lib/locking/cluster_locking.c
   lvm2/trunk/lib/locking/file_locking.c
   lvm2/trunk/lib/locking/locking.c
   lvm2/trunk/lib/locking/locking.h
   lvm2/trunk/lib/locking/locking_types.h
   lvm2/trunk/lib/log/log.c
   lvm2/trunk/lib/log/log.h
   lvm2/trunk/lib/metadata/lv_alloc.h
   lvm2/trunk/lib/metadata/lv_manip.c
   lvm2/trunk/lib/metadata/merge.c
   lvm2/trunk/lib/metadata/metadata.c
   lvm2/trunk/lib/metadata/metadata.h
   lvm2/trunk/lib/metadata/mirror.c
   lvm2/trunk/lib/metadata/pv_map.c
   lvm2/trunk/lib/metadata/pv_map.h
   lvm2/trunk/lib/metadata/segtype.h
   lvm2/trunk/lib/metadata/snapshot_manip.c
   lvm2/trunk/lib/mirror/mirrored.c
   lvm2/trunk/lib/misc/lvm-file.c
   lvm2/trunk/lib/misc/selinux.c
   lvm2/trunk/lib/misc/selinux.h
   lvm2/trunk/lib/mm/dbg_malloc.c
   lvm2/trunk/lib/mm/dbg_malloc.h
   lvm2/trunk/lib/report/columns.h
   lvm2/trunk/lib/report/report.c
   lvm2/trunk/lib/report/report.h
   lvm2/trunk/lib/snapshot/snapshot.c
   lvm2/trunk/lib/striped/striped.c
   lvm2/trunk/lib/uuid/uuid.h
   lvm2/trunk/man/pvcreate.8
   lvm2/trunk/po/lvm2.po
   lvm2/trunk/scripts/clvmd_init_rhel4
   lvm2/trunk/tools/Makefile.in
   lvm2/trunk/tools/args.h
   lvm2/trunk/tools/commands.h
   lvm2/trunk/tools/lvchange.c
   lvm2/trunk/tools/lvcreate.c
   lvm2/trunk/tools/lvdisplay.c
   lvm2/trunk/tools/lvm.c
   lvm2/trunk/tools/lvm2cmdline.h
   lvm2/trunk/tools/lvmcmdline.c
   lvm2/trunk/tools/lvmdiskscan.c
   lvm2/trunk/tools/lvremove.c
   lvm2/trunk/tools/lvrename.c
   lvm2/trunk/tools/lvresize.c
   lvm2/trunk/tools/polldaemon.c
   lvm2/trunk/tools/pvchange.c
   lvm2/trunk/tools/pvcreate.c
   lvm2/trunk/tools/pvdisplay.c
   lvm2/trunk/tools/pvmove.c
   lvm2/trunk/tools/pvscan.c
   lvm2/trunk/tools/reporter.c
   lvm2/trunk/tools/toollib.c
   lvm2/trunk/tools/toollib.h
   lvm2/trunk/tools/tools.h
   lvm2/trunk/tools/vgcfgbackup.c
   lvm2/trunk/tools/vgchange.c
   lvm2/trunk/tools/vgconvert.c
   lvm2/trunk/tools/vgcreate.c
   lvm2/trunk/tools/vgdisplay.c
   lvm2/trunk/tools/vgmerge.c
   lvm2/trunk/tools/vgreduce.c
   lvm2/trunk/tools/vgremove.c
   lvm2/trunk/tools/vgrename.c
   lvm2/trunk/tools/vgscan.c
   lvm2/trunk/tools/vgsplit.c
Log:
Merge /lvm2/upstream/current (2.01.11).


Added: lvm2/trunk/CONTRIBUTORS
==============================================================================

Modified: lvm2/trunk/VERSION
==============================================================================
--- lvm2/trunk/VERSION	(original)
+++ lvm2/trunk/VERSION	Tue Jun 14 11:23:47 2005
@@ -1 +1 @@
-2.01.04 (2005-02-09)
+2.01.11 (2005-06-13)

Modified: lvm2/trunk/WHATS_NEW
==============================================================================
--- lvm2/trunk/WHATS_NEW	(original)
+++ lvm2/trunk/WHATS_NEW	Tue Jun 14 11:23:47 2005
@@ -1,3 +1,105 @@
+Version 2.01.11 - 13th June 2005
+================================
+  Use matchpathcon mode parameter.
+  Don't defer closing dead FDs in clvmd.
+  Remove hard-coded 64k text metadata writing restriction.
+  Make VG name restrictions consistent.
+  Introduce lvconvert.  So far only removes mirror images.
+  Allow mirror images to be resized.
+  Allow mirror images to have more than one segment.
+  Centralise restrictions on LV names.
+  Always insert an intermediate layer for mirrors.
+  Suppress hidden LVs from reports unless --all is given.
+  Use square brackets for hidden LVs in reports.
+  Allow the creation of mirrors with contiguous extents.
+  Always perform sanity checks against metadata before committing it to disk.
+  Split lv_extend into two steps: choosing extents + allocation to LV(s).
+  Add mirror log region size to metadata.
+  Use list_iterate_items throughout and add list*back macros.
+  Introduce seg_ macros to access areas.
+  Add segtype_is_ macros.
+  Support tiny metadata areas for pool conversions.
+  Mirror activation handles disk log as well as core.
+  Activation code recognises mirror log dependency.
+  Add mirror_log and regionsize fields to report.
+  Fix non-orphan pvchange -u.
+  Fix vgmerge to handle duplicate LVIDs.
+  Move archiver code from tools into library.
+  vgscan/change/display/vgs automatically create metadata backups if needed.
+  Merge cloned allocation functions.
+  Fix contiguous allocation policy with linear.
+  Cope with missing format1 PVs again.
+  Remove lists of free PV segments.
+  Simplify pv_maps code and remove slow bitset algorithm.
+  Red-Hat-ify the clvmd rhel4 initscript.
+  %Zu->%zu
+  Fix loopfiles alias alloc & mem debugging.
+  Un-inline dbg_strdup.
+  lv_reduce tidying.
+  Remove some unnecessary parameters.
+  Introduce seg_is macros.
+
+Version 2.01.10 - 3rd May 2005
+==============================
+  Don't create backup and archive dirs till needed.
+  Reinstate full PV size when removing from VG.
+  Support loopfiles for testing.
+  Tidy lv_segment interface.
+  pv_segment support.
+  vgchange --physicalextentsize
+  Internal snapshot restructuring.
+  Remove unused internal non-persistent snapshot option.
+  Allow offline extension of snapshot volumes.
+  Move from 2-step to 3-step on-disk metadata commit.
+  Scan ramdisks too and allow non-O_DIRECT fallback.
+  Annotate, tidy and extend list.h.
+  Alignment tidying.
+  Make clvmd work around some "bugs" in gulm's node state notifications.
+  Tidy clvmd's SIGHUP handler
+
+Version 2.01.09 - 4th April 2005
+================================
+  Add --ignorelockingfailure to vgmknodes.
+  clvmd: Don't allow user operations to start until the lvm thread is fully up.
+  clvmd-gulm: set KEEPALIVE on sockets.
+
+Version 2.01.08 - 22nd March 2005
+=================================
+  Add clustered attribute so vgchange can identify clustered VGs w/o locking.
+  Improve detection of external changes affecting internal cache.
+  Add 'already in device cache' debug message.
+  Add -a to pvdisplay -C.
+  Avoid rmdir opendir error messsages when dir was already removed.
+  Tighten signal handlers.
+  Avoid some compiler warnings.
+  Additional rename failure error message.
+  read/write may be macros.
+  clvmd: don't take out lvm thread lock at startup, it only protects jobs list.
+
+Version 2.01.07 - 8th March 2005
+================================
+  Cope with new devices appearing by rescanning /dev if a uuid can't be found.
+  Remove DESTDIR from LVM_SHARED_PATH.
+  clvmd fixes: make FDs close-on-exec
+               gulm unlocks VG & orphan locks at startup in case they are stale
+               gulm now unlocks VG & orphan locks if client dies.
+
+Version 2.01.06 - 1st March 2005
+================================
+  Suppress 'open failed' error messages during scanning.
+  Option to suppress warnings of file descriptors left open.
+  Fix default value of metadatacopies in documentation (2->1).
+  Fix clvmd-gulm locking.
+  ./configure --enable-debug now enables debugging code in clvmd.
+  Fix clvmd-gulm node up/down code so it actually works.
+  clvmd-gulm now releases locks when shut down.
+
+Version 2.01.05 - 18th February 2005
+====================================
+  Static binary invokes dynamic binary if appropriate.
+  Make clvmd config check a little more tolerant.
+  gulm clvmd can now cope with >1 message arriving in a TCP message.
+
 Version 2.01.04 - 9th February 2005
 ===================================
   Add fixed offset to imported pool minor numbers.

Modified: lvm2/trunk/daemons/clvmd/Makefile.in
==============================================================================
--- lvm2/trunk/daemons/clvmd/Makefile.in	(original)
+++ lvm2/trunk/daemons/clvmd/Makefile.in	Tue Jun 14 11:23:47 2005
@@ -34,6 +34,10 @@
 	CMAN = yes
 endif
 
+ifeq ("@DEBUG@", "yes")
+	CFLAGS += -DDEBUG
+endif
+
 ifeq ("$(GULM)", "yes")
 	SOURCES += clvmd-gulm.c tcp-comms.c
 	LMLIBS += -lccs -lgulm

Modified: lvm2/trunk/daemons/clvmd/clvmd-cman.c
==============================================================================
--- lvm2/trunk/daemons/clvmd/clvmd-cman.c	(original)
+++ lvm2/trunk/daemons/clvmd/clvmd-cman.c	Tue Jun 14 11:23:47 2005
@@ -77,6 +77,8 @@
 		/* Don't print an error here because we could be just probing for CMAN */
 		return -1;
 	}
+	/* Set Close-on-exec */
+	fcntl(cluster_sock, F_SETFD, 1);
 
 	/* Bind to our port number on the cluster.
 	   Writes to this will block if the cluster loses quorum */
@@ -101,6 +103,7 @@
 		return -1;
 	}
 	dlm_ls_pthread_init(lockspace);
+
 	return 0;
 }
 

Modified: lvm2/trunk/daemons/clvmd/clvmd-command.c
==============================================================================
--- lvm2/trunk/daemons/clvmd/clvmd-command.c	(original)
+++ lvm2/trunk/daemons/clvmd/clvmd-command.c	Tue Jun 14 11:23:47 2005
@@ -274,9 +274,10 @@
 
 	hash_iterate(v, lock_hash) {
 		int lkid = (int)(long)hash_get_data(lock_hash, v);
+		char *lockname = hash_get_key(lock_hash, v);
 
-		DEBUGLOG("cleanup: Unlocking lkid %x\n", lkid);
-		sync_unlock("DUMMY", lkid);
+		DEBUGLOG("cleanup: Unlocking lock %s %x\n", lockname, lkid);
+		sync_unlock(lockname, lkid);
 	}
 
 	hash_destroy(lock_hash);

Modified: lvm2/trunk/daemons/clvmd/clvmd-comms.h
==============================================================================
--- lvm2/trunk/daemons/clvmd/clvmd-comms.h	(original)
+++ lvm2/trunk/daemons/clvmd/clvmd-comms.h	Tue Jun 14 11:23:47 2005
@@ -40,6 +40,7 @@
 
 	void (*get_our_csid) (char *csid);
 	void (*add_up_node) (char *csid);
+	void (*reread_config) (void);
 	void (*cluster_closedown) (void);
 
 	int (*sync_lock) (const char *resource, int mode, int flags, int *lockid);

Modified: lvm2/trunk/daemons/clvmd/clvmd-gulm.c
==============================================================================
--- lvm2/trunk/daemons/clvmd/clvmd-gulm.c	(original)
+++ lvm2/trunk/daemons/clvmd/clvmd-gulm.c	Tue Jun 14 11:23:47 2005
@@ -2,6 +2,7 @@
 *******************************************************************************
 **
 **  Copyright (C) Sistina Software, Inc.  2002-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
 **
 *******************************************************************************
 ******************************************************************************/
@@ -46,6 +47,7 @@
 #include "log.h"
 #include "clvm.h"
 #include "clvmd-comms.h"
+#include "lvm-functions.h"
 #include "clvmd.h"
 #include "hash.h"
 #include "clvmd-gulm.h"
@@ -58,13 +60,15 @@
 /* hash list of outstanding lock requests */
 static struct hash_table *lock_hash;
 
-/* Copy of the current core state */
-static uint8_t current_corestate;
+/* Copy of the current quorate state */
+static uint8_t gulm_quorate = 0;
+static enum {INIT_NOTDONE, INIT_DONE, INIT_WAITQUORATE} init_state = INIT_NOTDONE;
 
 /* Number of active nodes */
 static int num_nodes;
 
 static char *cluster_name;
+static int in_shutdown = 0;
 
 static pthread_mutex_t lock_start_mutex;
 static volatile int lock_start_flag;
@@ -114,6 +118,9 @@
     client->callback = callback;
     add_client(client);
 
+    /* Set Close-on-exec */
+    fcntl(fd, F_SETFD, 1);
+
     return 0;
 }
 
@@ -129,12 +136,11 @@
     exit(0);
 }
 
-static void sighup_handler(int sig)
+static void _reread_config(void)
 {
-    DEBUGLOG("got SIGHUP\n");
-
-    /* Re-read CCS node list */
-    get_all_cluster_nodes();
+        /* Re-read CCS node list */
+	DEBUGLOG("Re-reading CCS config\n");
+	get_all_cluster_nodes();
 }
 
 static int _init_cluster(void)
@@ -224,7 +230,7 @@
 	exit(status);
     }
 
-    /* Request a list of nodes, we can;t really do anything until
+    /* Request a list of nodes, we can't really do anything until
        this comes back */
     status = lg_core_nodelist(gulm_if);
     if (status)
@@ -237,15 +243,14 @@
     signal(SIGINT, badsig_handler);
     signal(SIGTERM, badsig_handler);
 
-    /* Re-read the node list on SIGHUP */
-    signal(SIGHUP, sighup_handler);
-
     return 0;
 }
 
 static void _cluster_closedown(void)
 {
     DEBUGLOG("cluster_closedown\n");
+    in_shutdown = 1;
+    unlock_all();
     lg_lock_logout(gulm_if);
     lg_core_logout(gulm_if);
     lg_release(gulm_if);
@@ -258,6 +263,7 @@
     struct utsname nodeinfo;
     uint8_t mask[GIO_KEY_SIZE];
 
+    DEBUGLOG("Dropping expired locks for %s\n", nodename?nodename:"(null)");
     memset(mask, 0xff, GIO_KEY_SIZE);
 
     if (!nodename)
@@ -303,12 +309,16 @@
    if (error)
        exit(error);
 
-   current_corestate = corestate;
+   /* Get the current core state (for quorum) */
+   lg_core_corestate(gulm_if);
+
    return 0;
 }
 
 static void set_node_state(struct node_info *ninfo, char *csid, uint8_t nodestate)
 {
+    int oldstate = ninfo->state;
+
     if (nodestate == lg_core_Logged_in)
     {
 	/* Don't clobber NODE_CLVMD state */
@@ -330,11 +340,17 @@
 	    if (ninfo->state != NODE_DOWN)
 		num_nodes--;
 	    ninfo->state = NODE_DOWN;
-	    tcp_remove_client(csid);
 	}
     }
-    DEBUGLOG("set_node_state, '%s' state = %d, num_nodes=%d\n",
-	     ninfo->name, ninfo->state, num_nodes);
+    /* Gulm doesn't always send node DOWN events, so even if this a a node UP we must
+     * assume (ahem) that it prevously went down at some time. So we close
+     * the sockets here to make sure that we don't have any dead connections
+     * to that node.
+     */
+    tcp_remove_client(csid);
+
+    DEBUGLOG("set_node_state, '%s' state = %d (oldstate=%d), num_nodes=%d\n",
+	     ninfo->name, ninfo->state, oldstate, num_nodes);
 }
 
 static struct node_info *add_or_set_node(char *name, struct in6_addr *ip, uint8_t state)
@@ -391,7 +407,16 @@
 		char ourcsid[GULM_MAX_CSID_LEN];
 
 		DEBUGLOG("Got Nodelist, stop\n");
-		clvmd_cluster_init_completed();
+		if (gulm_quorate)
+		{
+			clvmd_cluster_init_completed();
+			init_state = INIT_DONE;
+		}
+		else
+		{
+			if (init_state == INIT_NOTDONE)
+				init_state = INIT_WAITQUORATE;
+		}
 
 		/* Mark ourself as up */
 		_get_our_csid(ourcsid);
@@ -409,10 +434,15 @@
 
 static int core_statechange(void *misc, uint8_t corestate, uint8_t quorate, struct in6_addr *masterip, char *mastername)
 {
-    DEBUGLOG("CORE Got statechange  corestate:%#x mastername:%s\n",
-	     corestate, mastername);
+    DEBUGLOG("CORE Got statechange. quorate:%d, corestate:%x mastername:%s\n",
+	     quorate, corestate, mastername);
 
-    current_corestate = corestate;
+    gulm_quorate = quorate;
+    if (quorate && init_state == INIT_WAITQUORATE)
+    {
+	    clvmd_cluster_init_completed();
+	    init_state = INIT_DONE;
+    }
     return 0;
 }
 
@@ -478,6 +508,10 @@
 
     DEBUGLOG("LOCK lock state: %s, error = %d\n", key, error);
 
+    /* No waiting process to wake up when we are shutting down */
+    if (in_shutdown)
+	    return 0;
+
     lwait = hash_lookup(lock_hash, key);
     if (!lwait)
     {
@@ -596,10 +630,17 @@
     struct node_info *ninfo;
 
     ninfo = hash_lookup_binary(node_hash, csid, GULM_MAX_CSID_LEN);
-    if (!ninfo)
+    if (!ninfo) {
+	    DEBUGLOG("gulm_add_up_node no node_hash entry for csid %s\n", print_csid(csid));
 	return;
+    }
+
+    DEBUGLOG("gulm_add_up_node %s\n", ninfo->name);
 
+    if (ninfo->state == NODE_DOWN)
+	    num_nodes++;
     ninfo->state = NODE_CLVMD;
+
     return;
 
 }
@@ -616,13 +657,14 @@
        running clvmd - gulm may set it DOWN quite soon */
     if (ninfo->state == NODE_CLVMD)
 	ninfo->state = NODE_UP;
+    drop_expired_locks(ninfo->name);
     return;
 
 }
 
 /* Call a callback for each node, so the caller knows whether it's up or down */
 static int _cluster_do_node_callback(struct local_client *master_client,
-			     void (*callback)(struct local_client *, char *csid, int node_up))
+				     void (*callback)(struct local_client *, char *csid, int node_up))
 {
     struct hash_node *hn;
     struct node_info *ninfo;
@@ -638,8 +680,19 @@
 	DEBUGLOG("down_callback. node %s, state = %d\n", ninfo->name, ninfo->state);
 
 	client = hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
-	if (client)
-	    callback(master_client, csid, ninfo->state == NODE_CLVMD);
+	if (!client)
+	{
+	    /* If it's up but not connected, try to make contact */
+	    if (ninfo->state == NODE_UP)
+		    gulm_connect_csid(csid, &client);
+
+	    client = hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
+
+	}
+	if (ninfo->state != NODE_DOWN)
+		callback(master_client, csid, ninfo->state == NODE_CLVMD);
+
+
     }
     return 0;
 }
@@ -650,15 +703,13 @@
     switch (gulm_ret)
     {
     case lg_err_TryFailed:
-	errno = EAGAIN;
-	break;
-
     case lg_err_AlreadyPend:
-	errno = EBUSY;
+	    errno = EAGAIN;
+	    break;
 
 	/* More?? */
     default:
-	errno = EINVAL;
+	    errno = EINVAL;
     }
 
     return gulm_ret ? -1 : 0;
@@ -729,6 +780,11 @@
 	return status;
     }
 
+    /* When we are shutting down, don't wait for unlocks
+       to be acknowledged, just do it. */
+    if (in_shutdown)
+	    return status;
+
     /* Wait for it to complete */
 
     pthread_cond_wait(&lwait.cond, &lwait.mutex);
@@ -765,7 +821,7 @@
 	if (status)
 	    goto out;
 
-	/* If we can't get this lock then bail out */
+	/* If we can't get this lock too then bail out */
 	status = _lock_resource(lock2, lg_lock_state_Exclusive, LCK_NONBLOCK, lockid);
         if (status == lg_err_TryFailed)
         {
@@ -777,10 +833,16 @@
 
     case LCK_READ:
 	status = _lock_resource(lock1, lg_lock_state_Shared, flags, lockid);
+	if (status)
+		goto out;
+	status = _unlock_resource(lock2, *lockid);
 	break;
 
     case LCK_WRITE:
 	status = _lock_resource(lock2, lg_lock_state_Exclusive, flags, lockid);
+	if (status)
+		goto out;
+	status = _unlock_resource(lock1, *lockid);
 	break;
 
     default:
@@ -807,36 +869,16 @@
 	   lockid == LCK_READ ||
 	   lockid == LCK_WRITE);
 
-    switch (lockid)
-    {
-    case LCK_EXCL:
-	status = _unlock_resource(lock1, lockid);
-	if (status)
-	    goto out;
-	status = _unlock_resource(lock2, lockid);
-	break;
-
-    case LCK_READ:
-	status = _unlock_resource(lock1, lockid);
-	break;
-
-    case LCK_WRITE:
-	status = _unlock_resource(lock2, lockid);
-	break;
-    }
+    status = _unlock_resource(lock1, lockid);
+    if (!status)
+	    status = _unlock_resource(lock2, lockid);
 
- out:
     return status;
 }
 
 static int _is_quorate()
 {
-    if (current_corestate == lg_core_Slave ||
-	current_corestate == lg_core_Master ||
-	current_corestate == lg_core_Client)
-	return 1;
-    else
-	return 0;
+	return gulm_quorate;
 }
 
 /* Get all the cluster node names & IPs from CCS and
@@ -940,6 +982,7 @@
 	.is_quorate               = _is_quorate,
 	.get_our_csid             = _get_our_csid,
 	.add_up_node              = gulm_add_up_node,
+	.reread_config            = _reread_config,
 	.cluster_closedown        = _cluster_closedown,
 	.sync_lock                = _sync_lock,
 	.sync_unlock              = _sync_unlock,

Modified: lvm2/trunk/daemons/clvmd/clvmd.c
==============================================================================
--- lvm2/trunk/daemons/clvmd/clvmd.c	(original)
+++ lvm2/trunk/daemons/clvmd/clvmd.c	Tue Jun 14 11:23:47 2005
@@ -87,8 +87,10 @@
 static pthread_t lvm_thread;
 static pthread_mutex_t lvm_thread_mutex;
 static pthread_cond_t lvm_thread_cond;
+static pthread_mutex_t lvm_start_mutex;
 static struct list lvm_cmd_head;
-static int quit = 0;
+static volatile sig_atomic_t quit = 0;
+static volatile sig_atomic_t reread_config = 0;
 static int child_pipe[2];
 
 /* Reasons the daemon failed initialisation */
@@ -100,6 +102,7 @@
 
 /* Prototypes for code further down */
 static void sigusr2_handler(int sig);
+static void sighup_handler(int sig);
 static void sigterm_handler(int sig);
 static void send_local_reply(struct local_client *client, int status,
 			     int clientid);
@@ -165,6 +168,7 @@
 	int debug = 0;
 	int cmd_timeout = DEFAULT_CMD_TIMEOUT;
 	sigset_t ss;
+	int using_gulm = 0;
 
 	/* Deal with command-line arguments */
 	opterr = 0;
@@ -220,8 +224,10 @@
 
 	/* Set up signal handlers, USR1 is for cluster change notifications (in cman)
 	   USR2 causes child threads to exit.
+	   HUP causes gulm version to re-read nodes list from CCS.
 	   PIPE should be ignored */
 	signal(SIGUSR2, sigusr2_handler);
+	signal(SIGHUP,  sighup_handler);
 	signal(SIGPIPE, SIG_IGN);
 
 	/* Block SIGUSR2 in the main process */
@@ -233,6 +239,7 @@
 	list_init(&lvm_cmd_head);
 	pthread_mutex_init(&lvm_thread_mutex, NULL);
 	pthread_cond_init(&lvm_thread_cond, NULL);
+	pthread_mutex_init(&lvm_start_mutex, NULL);
 	init_lvhash();
 
 	/* Start the cluster interface */
@@ -250,6 +257,7 @@
 			max_csid_len = GULM_MAX_CSID_LEN;
 			max_cluster_message = GULM_MAX_CLUSTER_MESSAGE;
 			max_cluster_member_name_len = GULM_MAX_CLUSTER_MEMBER_NAME_LEN;
+			using_gulm = 1;
 			syslog(LOG_NOTICE, "Cluster LVM daemon started - connected to GULM");
 		}
 #endif
@@ -276,6 +284,7 @@
 	        child_init_signal(DFAIL_MALLOC);
 
 	newfd->fd = local_sock;
+	newfd->removeme = 0;
 	newfd->type = LOCAL_RENDEZVOUS;
 	newfd->callback = local_rendezvous_callback;
 	newfd->next = local_client_head.next;
@@ -284,7 +293,7 @@
 	/* This needs to be started after cluster initialisation
 	   as it may need to take out locks */
 	DEBUGLOG("starting LVM thread\n");
-	pthread_create(&lvm_thread, NULL, lvm_thread_fn, nodeinfo.nodename);
+	pthread_create(&lvm_thread, NULL, lvm_thread_fn, (void *)using_gulm);
 
 	/* Tell the rest of the cluster our version number */
 	/* CMAN can do this immediately, gulm needs to wait until
@@ -342,6 +351,7 @@
 		newfd->fd = client_fd;
 		newfd->type = LOCAL_SOCK;
 		newfd->xid = 0;
+		newfd->removeme = 0;
 		newfd->callback = local_sock_callback;
 		newfd->bits.localsock.replies = NULL;
 		newfd->bits.localsock.expected_replies = 0;
@@ -508,13 +518,38 @@
 				FD_SET(thisfd->fd, &in);
 		}
 
-		if ((select_status = select(FD_SETSIZE, &in, NULL, NULL, &tv)) > 0) {
+		select_status = select(FD_SETSIZE, &in, NULL, NULL, &tv);
+
+		if (reread_config) {
+			int saved_errno = errno;
+
+			reread_config = 0;
+			if (clops->reread_config)
+				clops->reread_config();
+			errno = saved_errno;
+		}
+
+		if (select_status > 0) {
 			struct local_client *lastfd = NULL;
 			char csid[MAX_CSID_LEN];
 			char buf[max_cluster_message];
 
 			for (thisfd = &local_client_head; thisfd != NULL;
 			     thisfd = thisfd->next) {
+
+				if (thisfd->removeme) {
+					struct local_client *free_fd;
+					lastfd->next = thisfd->next;
+					free_fd = thisfd;
+					thisfd = lastfd;
+
+					DEBUGLOG("removeme set for fd %d\n", free_fd->fd);
+
+					/* Queue cleanup, this also frees the client struct */
+					add_to_lvmqueue(free_fd, NULL, 0, NULL);
+					break;
+				}
+
 				if (FD_ISSET(thisfd->fd, &in)) {
 					struct local_client *newfd;
 					int ret;
@@ -543,8 +578,10 @@
 						lastfd->next = thisfd->next;
 						free_fd = thisfd;
 						thisfd = lastfd;
-						cmd_client_cleanup(free_fd);
-						free(free_fd);
+						close(free_fd->fd);
+
+						/* Queue cleanup, this also frees the client struct */
+						add_to_lvmqueue(free_fd, NULL, 0, NULL);
 						break;
 					}
 
@@ -900,6 +937,7 @@
 		DEBUGLOG("creating pipe, [%d, %d]\n", comms_pipe[0],
 			 comms_pipe[1]);
 		newfd->fd = comms_pipe[0];
+		newfd->removeme = 0;
 		newfd->type = THREAD_PIPE;
 		newfd->callback = local_pipe_callback;
 		newfd->next = thisfd->next;
@@ -1056,8 +1094,8 @@
 	/* Get the node name as we /may/ need it later */
 	clops->name_from_csid(csid, nodename);
 
-	DEBUGLOG("process_remote_command %d for clientid 0x%x on node %s\n",
-		 msg->cmd, msg->clientid, nodename);
+	DEBUGLOG("process_remote_command %d for clientid 0x%x XID %d on node %s\n",
+		 msg->cmd, msg->clientid, msg->xid, nodename);
 
 	/* Is the data to be found in the system LV ? */
 	if (msg->flags & CLVMD_FLAG_SYSTEMLV) {
@@ -1190,9 +1228,8 @@
 
 				/* If System LV operation failed then report it as EFBIG but only do it
 				   if the data buffer has something in it. */
-				if (system_lv_write_data
-				    (aggreply,
-				     replylen + sizeof(struct clvm_header)) < 0
+				if (system_lv_write_data(aggreply,
+							 replylen + sizeof(struct clvm_header)) < 0
 				    && replylen > 0)
 					agghead->status = EFBIG;
 
@@ -1210,7 +1247,7 @@
 				agghead->node[0] = '\0';
 				send_message(aggreply,
 					     sizeof(struct clvm_header) +
-					     replylen + 2, csid, fd,
+					     replylen, csid, fd,
 					     "Error sending command reply");
 			}
 		} else {
@@ -1301,6 +1338,11 @@
 
 	DEBUGLOG("in sub thread: client = %p\n", client);
 
+	/* Don't start until the LVM thread is ready */
+	pthread_mutex_lock(&lvm_start_mutex);
+	pthread_mutex_unlock(&lvm_start_mutex);
+	DEBUGLOG("Sub thread ready for work.\n");
+
 	/* Ignore SIGUSR1 (handled by master process) but enable
 	   SIGUSR2 (kills subthreads) */
 	sigemptyset(&ss);
@@ -1532,6 +1574,7 @@
 	version_nums[1] = htonl(CLVMD_MINOR_VERSION);
 	version_nums[2] = htonl(CLVMD_PATCH_VERSION);
 
+	hton_clvm(msg);
 	clops->cluster_send_message(message, sizeof(message), NULL,
 			     "Error Sending version number");
 }
@@ -1544,7 +1587,7 @@
 
 	/* Send remote messages down the cluster socket */
 	if (csid == NULL || !ISLOCAL_CSID(csid)) {
-		hton_clvm((struct clvm_header *) buf);	/* Byte swap if necessary */
+		hton_clvm((struct clvm_header *) buf);
 		return clops->cluster_send_message(buf, msglen, csid, errtext);
 	} else {
 		int ptr = 0;
@@ -1565,6 +1608,14 @@
 
 static int process_work_item(struct lvm_thread_cmd *cmd)
 {
+	/* If msg is NULL then this is a cleanup request */
+	if (cmd->msg == NULL) {
+		DEBUGLOG("process_work_item: free fd %d\n", cmd->client->fd);
+		cmd_client_cleanup(cmd->client);
+		free(cmd->client);
+		return 0;
+	}
+
 	if (!cmd->remote) {
 		DEBUGLOG("process_work_item: local\n");
 		process_local_command(cmd->msg, cmd->msglen, cmd->client,
@@ -1584,9 +1635,12 @@
 {
 	struct list *cmdl, *tmp;
 	sigset_t ss;
+	int using_gulm = (int)arg;
+
+	/* Don't let anyone else to do work until we are started */
+	pthread_mutex_lock(&lvm_start_mutex);
 
 	DEBUGLOG("LVM thread function started\n");
-	pthread_mutex_lock(&lvm_thread_mutex);
 
 	/* Ignore SIGUSR1 & 2 */
 	sigemptyset(&ss);
@@ -1595,8 +1649,10 @@
 	pthread_sigmask(SIG_BLOCK, &ss, NULL);
 
 	/* Initialise the interface to liblvm */
-	init_lvm();
-	pthread_mutex_unlock(&lvm_thread_mutex);
+	init_lvm(using_gulm);
+
+	/* Allow others to get moving */
+	pthread_mutex_unlock(&lvm_start_mutex);
 
 	/* Now wait for some actual work */
 	for (;;) {
@@ -1615,7 +1671,8 @@
 			pthread_mutex_unlock(&lvm_thread_mutex);
 
 			process_work_item(cmd);
-			free(cmd->msg);
+			if (cmd->msg)
+				free(cmd->msg);
 			free(cmd);
 
 			pthread_mutex_lock(&lvm_thread_mutex);
@@ -1634,17 +1691,22 @@
 	if (!cmd)
 		return ENOMEM;
 
-	cmd->msg = malloc(msglen);
-	if (!cmd->msg) {
-		log_error("Unable to allocate buffer space\n");
-		free(cmd);
-		return -1;
+	if (msglen) {
+		cmd->msg = malloc(msglen);
+		if (!cmd->msg) {
+			log_error("Unable to allocate buffer space\n");
+			free(cmd);
+			return -1;
+		}
+		memcpy(cmd->msg, msg, msglen);
+	}
+	else {
+		cmd->msg = NULL;
 	}
-
 	cmd->client = client;
 	cmd->msglen = msglen;
 	cmd->xid = client->xid;
-	memcpy(cmd->msg, msg, msglen);
+
 	if (csid) {
 		memcpy(cmd->csid, csid, max_csid_len);
 		cmd->remote = 1;
@@ -1677,6 +1739,8 @@
 		log_error("Can't create local socket: %m");
 		return -1;
 	}
+	/* Set Close-on-exec */
+	fcntl(local_socket, F_SETFD, 1);
 
 	memset(&sockaddr, 0, sizeof(sockaddr));
 	memcpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(CLVMD_SOCKNAME));
@@ -1771,6 +1835,12 @@
 	return;
 }
 
+static void sighup_handler(int sig)
+{
+        DEBUGLOG("got SIGHUP\n");
+	reread_config = 1;
+}
+
 int sync_lock(const char *resource, int mode, int flags, int *lockid)
 {
 	return clops->sync_lock(resource, mode, flags, lockid);

Modified: lvm2/trunk/daemons/clvmd/clvmd.h
==============================================================================
--- lvm2/trunk/daemons/clvmd/clvmd.h	(original)
+++ lvm2/trunk/daemons/clvmd/clvmd.h	Tue Jun 14 11:23:47 2005
@@ -86,6 +86,7 @@
 	struct local_client *next;
 	unsigned short xid;
 	fd_callback_t callback;
+	uint8_t removeme;
 
 	union {
 		struct localsock_bits localsock;
@@ -93,9 +94,9 @@
 		struct netsock_bits net;
 	} bits;
 };
-#define DEBUG
+
 #ifdef DEBUG
-#define DEBUGLOG(fmt, args...) fprintf(stderr, "CLVMD[%d]: %ld ", getpid(), time(NULL) ); fprintf(stderr, fmt, ## args)
+#define DEBUGLOG(fmt, args...) {time_t P; time(&P); fprintf(stderr, "CLVMD[%x]: %.15s ", (int)pthread_self(), ctime(&P)+4 ); fprintf(stderr, fmt, ## args);}
 #else
 #define DEBUGLOG(fmt, args...)
 #endif

Modified: lvm2/trunk/daemons/clvmd/lvm-functions.c
==============================================================================
--- lvm2/trunk/daemons/clvmd/lvm-functions.c	(original)
+++ lvm2/trunk/daemons/clvmd/lvm-functions.c	Tue Jun 14 11:23:47 2005
@@ -388,6 +388,44 @@
 	return status == 1 ? 0 : EBUSY;
 }
 
+
+/* Only called at gulm startup. Drop any leftover VG or P_orphan locks
+   that might be hanging around if we died for any reason
+*/
+static void drop_vg_locks()
+{
+	char vg[128];
+	char line[255];
+	FILE *vgs =
+	    popen
+	    ("lvm pvs --nolocking --noheadings -o vg_name", "r");
+
+	sync_unlock("P_orphans", LCK_EXCL);
+
+	if (!vgs)
+		return;
+
+	while (fgets(line, sizeof(line), vgs)) {
+		char *vgend;
+		char *vgstart;
+
+		if (line[strlen(line)-1] == '\n')
+			line[strlen(line)-1] = '\0';
+
+		vgstart = line + strspn(line, " ");
+		vgend = vgstart + strcspn(vgstart, " ");
+		*vgend = '\0';
+
+		if (strncmp(vgstart, "WARNING:", 8) == 0)
+			continue;
+
+		sprintf(vg, "V_%s", vgstart);
+		sync_unlock(vg, LCK_EXCL);
+
+	}
+	fclose(vgs);
+}
+
 /*
  * Ideally, clvmd should be started before any LVs are active
  * but this may not be the case...
@@ -449,11 +487,11 @@
 		return;
 
 	if (locking_type == 2) { /* External library, check name */
-		char *libname;
+		const char *libname;
 
 		libname = find_config_str(cmd->cft->root, "global/locking_library",
 					  "");
-		if (!strcmp(libname, "liblvm2clusterlock.so"))
+		if (strstr(libname, "liblvm2clusterlock.so"))
 			return;
 
 		log_error("Incorrect LVM locking library specified in lvm.conf, cluster operations may not work.");
@@ -470,7 +508,7 @@
 }
 
 /* Called to initialise the LVM context of the daemon */
-int init_lvm(void)
+int init_lvm(int using_gulm)
 {
 	if (!(cmd = create_toolcontext(NULL))) {
 		log_error("Failed to allocate command context");
@@ -484,6 +522,10 @@
 	/* Check lvm.conf is setup for cluster-LVM */
 	check_config();
 
+	/* Remove any non-LV locks that may have been left around */
+	if (using_gulm)
+		drop_vg_locks();
+
 	get_initial_state();
 
 	return 1;

Modified: lvm2/trunk/daemons/clvmd/lvm-functions.h
==============================================================================
--- lvm2/trunk/daemons/clvmd/lvm-functions.h	(original)
+++ lvm2/trunk/daemons/clvmd/lvm-functions.h	Tue Jun 14 11:23:47 2005
@@ -25,7 +25,7 @@
 extern int post_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
 			char *resource);
 extern int do_check_lvm1(char *vgname);
-extern int init_lvm(void);
+extern int init_lvm(int using_gulm);
 extern void init_lvhash(void);
 
 extern int hold_unlock(char *resource);

Modified: lvm2/trunk/daemons/clvmd/tcp-comms.c
==============================================================================
--- lvm2/trunk/daemons/clvmd/tcp-comms.c	(original)
+++ lvm2/trunk/daemons/clvmd/tcp-comms.c	Tue Jun 14 11:23:47 2005
@@ -2,6 +2,7 @@
 *******************************************************************************
 **
 **  Copyright (C) Sistina Software, Inc.  2002-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
 **
 *******************************************************************************
 ******************************************************************************/
@@ -68,6 +69,7 @@
     {
 	int one = 1;
 	setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int));
+	setsockopt(listen_fd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(int));
     }
 
     memset(&addr, 0, sizeof(addr)); // Bind to INADDR_ANY
@@ -84,6 +86,9 @@
 
     listen(listen_fd, 5);
 
+    /* Set Close-on-exec */
+    fcntl(listen_fd, F_SETFD, 1);
+
     return 0;
 }
 
@@ -100,6 +105,8 @@
     if (client)
     {
 	hash_remove_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
+	client->removeme = 1;
+	close(client->fd);
     }
 
     /* Look for a mangled one too */
@@ -109,6 +116,8 @@
     if (client)
     {
 	hash_remove_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
+	client->removeme = 1;
+	close(client->fd);
     }
 
     /* Put it back as we found it */
@@ -221,13 +230,34 @@
     return newfd;
 }
 
+/* Try to get at least 'len' bytes from the socket */
+static int really_read(int fd, char *buf, int len)
+{
+	int got, offset;
+
+	got = offset = 0;
+
+	do {
+		got = read(fd, buf+offset, len-offset);
+		DEBUGLOG("really_read. got %d bytes\n", got);
+		offset += got;
+	} while (got > 0 && offset < len);
+
+	if (got < 0)
+		return got;
+	else
+		return offset;
+}
+
 
 static int read_from_tcpsock(struct local_client *client, char *buf, int len, char *csid,
 			     struct local_client **new_client)
 {
     struct sockaddr_in6 addr;
     socklen_t slen = sizeof(addr);
+    struct clvm_header *header = (struct clvm_header *)buf;
     int status;
+    uint32_t arglen;
 
     DEBUGLOG("read_from_tcpsock fd %d\n", client->fd);
     *new_client = NULL;
@@ -236,7 +266,26 @@
     getpeername(client->fd, (struct sockaddr *)&addr, &slen);
     memcpy(csid, &addr.sin6_addr, GULM_MAX_CSID_LEN);
 
-    status = read(client->fd, buf, len);
+    /* Read just the header first, then get the rest if there is any.
+     * Stream sockets, sigh.
+     */
+    status = really_read(client->fd, buf, sizeof(struct clvm_header));
+    if (status > 0)
+    {
+	    int status2;
+
+	    arglen = ntohl(header->arglen);
+
+	    /* Get the rest */
+	    if (arglen && arglen < GULM_MAX_CLUSTER_MESSAGE)
+	    {
+		    status2 = really_read(client->fd, buf+status, arglen);
+		    if (status2 > 0)
+			    status += status2;
+		    else
+			    status = status2;
+	    }
+    }
 
     DEBUGLOG("read_from_tcpsock, status = %d(errno = %d)\n", status, errno);
 
@@ -259,17 +308,19 @@
 	add_down_node(remcsid);
     }
     else {
+	    gulm_add_up_node(csid);
 	    /* Send it back to clvmd */
-	    process_message(client, buf, len, csid);
+	    process_message(client, buf, status, csid);
     }
     return status;
 }
 
-static int connect_csid(char *csid, struct local_client **newclient)
+int gulm_connect_csid(char *csid, struct local_client **newclient)
 {
     int fd;
     struct sockaddr_in6 addr;
     int status;
+    int one = 1;
 
     DEBUGLOG("Connecting socket\n");
     fd = socket(PF_INET6, SOCK_STREAM, 0);
@@ -299,6 +350,10 @@
 	return -1;
     }
 
+    /* Set Close-on-exec */
+    fcntl(fd, F_SETFD, 1);
+    setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(int));
+
     status = alloc_client(fd, csid, newclient);
     if (status)
 	close(fd);
@@ -329,7 +384,7 @@
     client = hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
     if (!client)
     {
-	status = connect_csid(csid, &client);
+	status = gulm_connect_csid(csid, &client);
 	if (status)
 	    return -1;
     }

Modified: lvm2/trunk/daemons/clvmd/tcp-comms.h
==============================================================================
--- lvm2/trunk/daemons/clvmd/tcp-comms.h	(original)
+++ lvm2/trunk/daemons/clvmd/tcp-comms.h	Tue Jun 14 11:23:47 2005
@@ -10,3 +10,4 @@
 int cluster_fd_gulm_callback(struct local_client *fd, char *buf, int len, char *csid, struct local_client **new_client);
 int gulm_cluster_send_message(void *buf, int msglen, char *csid, const char *errtext);
 void get_our_gulm_csid(char *csid);
+int gulm_connect_csid(char *csid, struct local_client **newclient);

Modified: lvm2/trunk/doc/example.conf
==============================================================================
--- lvm2/trunk/doc/example.conf	(original)
+++ lvm2/trunk/doc/example.conf	Tue Jun 14 11:23:47 2005
@@ -265,11 +265,10 @@
 #
 # metadata {
     # Default number of copies of metadata to hold on each PV.  0, 1 or 2.
-    # It's best to leave this at 2.
-    # You might want to override it from the command line with 0 or 1 
+    # You might want to override it from the command line with 0 
     # when running pvcreate on new PVs which are to be added to large VGs.
 
-    # pvmetadatacopies = 2
+    # pvmetadatacopies = 1
 
     # Approximate default size of on-disk metadata areas in sectors.
     # You should increase this if you have large volume groups or

Modified: lvm2/trunk/include/.symlinks
==============================================================================
--- lvm2/trunk/include/.symlinks	(original)
+++ lvm2/trunk/include/.symlinks	Tue Jun 14 11:23:47 2005
@@ -23,6 +23,7 @@
 ../lib/filters/filter.h
 ../lib/format1/format1.h
 ../lib/format_pool/format_pool.h
+../lib/format_text/archiver.h
 ../lib/format_text/format-text.h
 ../lib/format_text/text_export.h
 ../lib/format_text/text_import.h
@@ -31,6 +32,7 @@
 ../lib/log/log.h
 ../lib/metadata/lv_alloc.h
 ../lib/metadata/metadata.h
+../lib/metadata/pv_alloc.h
 ../lib/metadata/segtype.h
 ../lib/mm/dbg_malloc.h
 ../lib/mm/memlock.h

Modified: lvm2/trunk/lib/Makefile.in
==============================================================================
--- lvm2/trunk/lib/Makefile.in	(original)
+++ lvm2/trunk/lib/Makefile.in	Tue Jun 14 11:23:47 2005
@@ -54,6 +54,7 @@
 	filters/filter-md.c \
 	filters/filter.c \
 	format_text/archive.c \
+	format_text/archiver.c \
 	format_text/export.c \
 	format_text/flags.c \
 	format_text/format-text.c \
@@ -70,6 +71,7 @@
 	metadata/merge.c \
 	metadata/metadata.c \
 	metadata/mirror.c \
+	metadata/pv_manip.c \
 	metadata/pv_map.c \
 	metadata/segtype.c \
 	metadata/snapshot_manip.c \

Modified: lvm2/trunk/lib/activate/activate.c
==============================================================================
--- lvm2/trunk/lib/activate/activate.c	(original)
+++ lvm2/trunk/lib/activate/activate.c	Tue Jun 14 11:23:47 2005
@@ -517,17 +517,15 @@
  */
 int lvs_in_vg_activated(struct volume_group *vg)
 {
-	struct list *lvh;
-	struct logical_volume *lv;
+	struct lv_list *lvl;
 	int count = 0;
 
 	if (!activation())
 		return 0;
 
-	list_iterate(lvh, &vg->lvs) {
-		lv = list_item(lvh, struct lv_list)->lv;
-		if (lv->status & VISIBLE_LV)
-			count += (_lv_active(lv) == 1);
+	list_iterate_items(lvl, &vg->lvs) {
+		if (lvl->lv->status & VISIBLE_LV)
+			count += (_lv_active(lvl->lv) == 1);
 	}
 
 	return count;
@@ -535,17 +533,15 @@
 
 int lvs_in_vg_opened(struct volume_group *vg)
 {
-	struct list *lvh;
-	struct logical_volume *lv;
+	struct lv_list *lvl;
 	int count = 0;
 
 	if (!activation())
 		return 0;
 
-	list_iterate(lvh, &vg->lvs) {
-		lv = list_item(lvh, struct lv_list)->lv;
-		if (lv->status & VISIBLE_LV)
-			count += (_lv_open_count(lv) > 0);
+	list_iterate_items(lvl, &vg->lvs) {
+		if (lvl->lv->status & VISIBLE_LV)
+			count += (_lv_open_count(lvl->lv) > 0);
 	}
 
 	return count;

Modified: lvm2/trunk/lib/activate/dev_manager.c
==============================================================================
--- lvm2/trunk/lib/activate/dev_manager.c	(original)
+++ lvm2/trunk/lib/activate/dev_manager.c	Tue Jun 14 11:23:47 2005
@@ -727,6 +727,54 @@
 	return 1;
 }
 
+int compose_log_line(struct dev_manager *dm, struct lv_segment *seg,
+		     char *params, size_t paramsize, int *pos, int areas,
+		     uint32_t region_size)
+{
+	int tw;
+	char devbuf[10];
+	char *name;
+	struct dev_layer *dl;
+
+	if (!seg->log_lv)
+		tw = lvm_snprintf(params, paramsize, "core 1 %u %u ",
+				  region_size, areas);
+	else {
+		if (!(name = build_dm_name(dm->mem, seg->log_lv->vg->name,
+					   seg->log_lv->name, NULL))) {
+			stack;
+			return 0;
+		}
+
+		if (!(dl = hash_lookup(dm->layers, seg->log_lv->lvid.s))) {
+			log_error("device layer %s missing from hash",
+				  seg->log_lv->lvid.s);
+			return 0;
+		}
+
+		if (!dm_format_dev(devbuf, sizeof(devbuf), dl->info.major,
+				   dl->info.minor)) {
+			log_error("Failed to format device number as dm "
+				  "target (%u,%u)",
+				   dl->info.major, dl->info.minor);
+			return 0;
+		}
+
+		/* FIXME add sync parm? */
+		tw = lvm_snprintf(params, paramsize, "disk 2 %s %u %u ",
+				  devbuf, region_size, areas);
+	}
+
+	if (tw < 0) {
+		stack;
+		return -1;
+	}
+
+	*pos += tw;
+
+	return 1;
+}
+
 int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg,
 		       char *params, size_t paramsize, int *pos, int start_area,
 		       int areas)
@@ -740,24 +788,26 @@
 
 	for (s = start_area; s < areas; s++, *pos += tw) {
 		trailing_space = (areas - s - 1) ? " " : "";
-		if ((seg->area[s].type == AREA_PV &&
-		     (!seg->area[s].u.pv.pv || !seg->area[s].u.pv.pv->dev)) ||
-		    (seg->area[s].type == AREA_LV && !seg->area[s].u.lv.lv))
+		if ((seg_type(seg, s) == AREA_PV &&
+		     (!seg_pvseg(seg, s) ||
+		      !seg_pv(seg, s) ||
+		      !seg_dev(seg, s))) ||
+		    (seg_type(seg, s) == AREA_LV && !seg_lv(seg, s)))
 			tw = lvm_snprintf(params + *pos, paramsize - *pos,
 					  "%s 0%s", dm->stripe_filler,
 					  trailing_space);
-		else if (seg->area[s].type == AREA_PV)
+		else if (seg_type(seg, s) == AREA_PV)
 			tw = lvm_snprintf(params + *pos, paramsize - *pos,
 					  "%s %" PRIu64 "%s",
-					  dev_name(seg->area[s].u.pv.pv->dev),
-					  (seg->area[s].u.pv.pv->pe_start +
-					   (esize * seg->area[s].u.pv.pe)),
+					  dev_name(seg_dev(seg, s)),
+					  (seg_pv(seg, s)->pe_start +
+					   (esize * seg_pe(seg, s))),
 					  trailing_space);
 		else {
 			if (!(dl = hash_lookup(dm->layers,
-					       seg->area[s].u.lv.lv->lvid.s))) {
+					       seg_lv(seg, s)->lvid.s))) {
 				log_error("device layer %s missing from hash",
-					  seg->area[s].u.lv.lv->lvid.s);
+					  seg_lv(seg, s)->lvid.s);
 				return 0;
 			}
 			if (!dm_format_dev
@@ -770,7 +820,7 @@
 			}
 			tw = lvm_snprintf(params + *pos, paramsize - *pos,
 					  "%s %" PRIu64 "%s", devbuf,
-					  esize * seg->area[s].u.lv.le,
+					  esize * seg_le(seg, s),
 					  trailing_space);
 		}
 
@@ -818,14 +868,12 @@
 static int _populate_vanilla(struct dev_manager *dm,
 			     struct dm_task *dmt, struct dev_layer *dl)
 {
-	struct list *segh;
 	struct lv_segment *seg;
 	struct logical_volume *lv = dl->lv;
 
 	dm->pvmove_mirror_count = 0u;
 
-	list_iterate(segh, &lv->segments) {
-		seg = list_item(segh, struct lv_segment);
+	list_iterate_items(seg, &lv->segments) {
 		if (!_emit_target(dm, dmt, seg)) {
 			log_error("Unable to build table for '%s'", lv->name);
 			return 0;
@@ -875,22 +923,23 @@
 {
 	char *origin, *cow;
 	char params[PATH_MAX * 2 + 32];
-	struct snapshot *s;
+	struct lv_segment *snap_seg;
 	struct dev_layer *dlo, *dlc;
 	char devbufo[10], devbufc[10];
 	uint64_t size;
 
-	if (!(s = find_cow(dl->lv))) {
+	if (!(snap_seg = find_cow(dl->lv))) {
 		log_error("Couldn't find snapshot for '%s'.", dl->lv->name);
 		return 0;
 	}
 
-	if (!(origin = _build_dlid(dm->mem, s->origin->lvid.s, "real"))) {
+	if (!(origin = _build_dlid(dm->mem, snap_seg->origin->lvid.s,
+				   "real"))) {
 		stack;
 		return 0;
 	}
 
-	if (!(cow = _build_dlid(dm->mem, s->cow->lvid.s, "cow"))) {
+	if (!(cow = _build_dlid(dm->mem, snap_seg->cow->lvid.s, "cow"))) {
 		stack;
 		return 0;
 	}
@@ -909,24 +958,24 @@
 	if (!dm_format_dev(devbufo, sizeof(devbufo), dlo->info.major,
 			   dlo->info.minor)) {
 		log_error("Couldn't create origin device parameters for '%s'.",
-			  s->origin->name);
+			  snap_seg->origin->name);
 		return 0;
 	}
 
 	if (!dm_format_dev(devbufc, sizeof(devbufc), dlc->info.major,
 			   dlc->info.minor)) {
 		log_error("Couldn't create cow device parameters for '%s'.",
-			  s->cow->name);
+			  snap_seg->cow->name);
 		return 0;
 	}
 
 	if (lvm_snprintf(params, sizeof(params), "%s %s P %d",
-			 devbufo, devbufc, s->chunk_size) == -1) {
+			 devbufo, devbufc, snap_seg->chunk_size) == -1) {
 		stack;
 		return 0;
 	}
 
-	size = (uint64_t) s->le_count * s->origin->vg->extent_size;
+	size = (uint64_t) snap_seg->len * snap_seg->origin->vg->extent_size;
 
 	log_debug("Adding target: 0 %" PRIu64 " snapshot %s", size, params);
 	if (!dm_task_add_target(dmt, UINT64_C(0), size, "snapshot", params)) {
@@ -1176,7 +1225,6 @@
 	 * only one layer.
 	 */
 	struct dev_layer *dl, *dlr;
-	struct list *segh;
 	struct lv_segment *seg;
 	uint32_t s;
 
@@ -1194,14 +1242,22 @@
 		_set_flag(dl, TOPLEVEL);
 
 	/* Add dependencies for any LVs that segments refer to */
-	list_iterate(segh, &lv->segments) {
-		seg = list_item(segh, struct lv_segment);
+	list_iterate_items(seg, &lv->segments) {
+		if (seg->log_lv &&
+		    !str_list_add(dm->mem, &dl->pre_create,
+				  _build_dlid(dm->mem, seg->log_lv->lvid.s,
+					      NULL))) {
+			stack;
+			return 0;
+		}
+		// FIXME Check we don't want NOPROPAGATE here
+
 		for (s = 0; s < seg->area_count; s++) {
-			if (seg->area[s].type != AREA_LV)
+			if (seg_type(seg, s) != AREA_LV)
 				continue;
 			if (!str_list_add(dm->mem, &dl->pre_create,
 					  _build_dlid(dm->mem,
-						      seg->area[s].u.lv.lv->
+						      seg_lv(seg, s)->
 						      lvid.s, NULL))) {
 				stack;
 				return 0;
@@ -1274,16 +1330,16 @@
 static int _expand_origin(struct dev_manager *dm, struct logical_volume *lv)
 {
 	struct logical_volume *active;
-	struct snapshot *s;
-	struct list *sh;
+	struct lv_segment *snap_seg;
+	struct lv_list *lvl;
 
 	/*
 	 * We only need to create an origin layer if one of our
 	 * snapshots is in the active list
 	 */
-	list_iterate(sh, &dm->active_list) {
-		active = list_item(sh, struct lv_list)->lv;
-		if ((s = find_cow(active)) && (s->origin == lv))
+	list_iterate_items(lvl, &dm->active_list) {
+		active = lvl->lv;
+		if ((snap_seg = find_cow(active)) && (snap_seg->origin == lv))
 			return _expand_origin_real(dm, lv);
 	}
 
@@ -1294,7 +1350,7 @@
 }
 
 static int _expand_snapshot(struct dev_manager *dm, struct logical_volume *lv,
-			    struct snapshot *s)
+			    struct lv_segment *snap_seg)
 {
 	/*
 	 * snapshot(org, cow)
@@ -1331,13 +1387,15 @@
 
 	/* add the dependency on the real origin device */
 	if (!str_list_add(dm->mem, &dl->pre_create,
-			  _build_dlid(dm->mem, s->origin->lvid.s, "real"))) {
+			  _build_dlid(dm->mem, snap_seg->origin->lvid.s,
+				      "real"))) {
 		stack;
 		return 0;
 	}
 
 	/* add the dependency on the visible origin device */
-	if (!str_list_add(dm->mem, &dl->pre_suspend, s->origin->lvid.s)) {
+	if (!str_list_add(dm->mem, &dl->pre_suspend,
+			  snap_seg->origin->lvid.s)) {
 		stack;
 		return 0;
 	}
@@ -1350,13 +1408,13 @@
  */
 static int _expand_lv(struct dev_manager *dm, struct logical_volume *lv)
 {
-	struct snapshot *s;
+	struct lv_segment *snap_seg;
 
 	/*
 	 * FIXME: this doesn't cope with recursive snapshots yet.
 	 */
-	if ((s = find_cow(lv)))
-		return _expand_snapshot(dm, lv, s);
+	if ((snap_seg = find_cow(lv)))
+		return _expand_snapshot(dm, lv, snap_seg);
 
 	else if (lv_is_origin(lv))
 		return _expand_origin(dm, lv);
@@ -1384,12 +1442,12 @@
 static int _trace_layer_marks(struct dev_manager *dm, struct dev_layer *dl,
 			      int flag)
 {
-	struct list *sh;
+	struct str_list *strl;
 	const char *dlid;
 	struct dev_layer *dep;
 
-	list_iterate(sh, &dl->pre_create) {
-		dlid = list_item(sh, struct str_list)->str;
+	list_iterate_items(strl, &dl->pre_create) {
+		dlid = strl->str;
 
 		if (!(dep = hash_lookup(dm->layers, dlid))) {
 			log_error("Couldn't find device layer '%s'.", dlid);
@@ -1439,14 +1497,14 @@
  */
 static int _mark_lvs(struct dev_manager *dm, struct list *lvs, int flag)
 {
-	struct list *lvh;
-	struct logical_volume *lv;
+	struct lv_list *lvl;
 	struct dev_layer *dl;
 
-	list_iterate(lvh, lvs) {
-		lv = list_item(lvh, struct lv_list)->lv;
+	list_iterate_items(lvl, lvs) {
+		if (lvl->lv->status & SNAPSHOT)
+			continue;
 
-		if (!(dl = _lookup(dm, lv->lvid.s, NULL))) {
+		if (!(dl = _lookup(dm, lvl->lv->lvid.s, NULL))) {
 			stack;
 			return 0;
 		}
@@ -1464,12 +1522,12 @@
 
 static int _suspend_parents(struct dev_manager *dm, struct dev_layer *dl)
 {
-	struct list *sh;
+	struct str_list *strl;
 	struct dev_layer *dep;
 	const char *dlid;
 
-	list_iterate(sh, &dl->pre_suspend) {
-		dlid = list_item(sh, struct str_list)->str;
+	list_iterate_items(strl, &dl->pre_suspend) {
+		dlid = strl->str;
 
 		if (!(dep = hash_lookup(dm->layers, dlid))) {
 			log_debug("_suspend_parents couldn't find device "
@@ -1498,12 +1556,12 @@
 
 static int _resume_with_deps(struct dev_manager *dm, struct dev_layer *dl)
 {
-	struct list *sh;
+	struct str_list *strl;
 	struct dev_layer *dep;
 	const char *dlid;
 
-	list_iterate(sh, &dl->pre_create) {
-		dlid = list_item(sh, struct str_list)->str;
+	list_iterate_items(strl, &dl->pre_create) {
+		dlid = strl->str;
 
 		if (!(dep = hash_lookup(dm->layers, dlid))) {
 			log_debug("_resume_with_deps couldn't find device "
@@ -1536,7 +1594,7 @@
  */
 static int _create_rec(struct dev_manager *dm, struct dev_layer *dl)
 {
-	struct list *sh;
+	struct str_list *strl;
 	struct dev_layer *dep;
 	const char *dlid;
 	char *newname, *suffix;
@@ -1548,8 +1606,8 @@
 		return 0;
 	}
 
-	list_iterate(sh, &dl->pre_create) {
-		dlid = list_item(sh, struct str_list)->str;
+	list_iterate_items(strl, &dl->pre_create) {
+		dlid = strl->str;
 
 		if (!(dep = hash_lookup(dm->layers, dlid))) {
 			log_error("Couldn't find device layer '%s'.", dlid);
@@ -1605,15 +1663,15 @@
 
 static int _build_all_layers(struct dev_manager *dm, struct volume_group *vg)
 {
-	struct list *lvh;
-	struct logical_volume *lvt;
+	struct lv_list *lvl;
 
 	/*
 	 * Build layers for complete vg.
 	 */
-	list_iterate(lvh, &vg->lvs) {
-		lvt = list_item(lvh, struct lv_list)->lv;
-		if (!_expand_lv(dm, lvt)) {
+	list_iterate_items(lvl, &vg->lvs) {
+		if (lvl->lv->status & SNAPSHOT)
+			continue;
+		if (!_expand_lv(dm, lvl->lv)) {
 			stack;
 			return 0;
 		}
@@ -1653,15 +1711,15 @@
 {
 	struct hash_node *hn;
 	struct dev_layer *dl;
-	struct list *sh;
+	struct str_list *strl;
 	const char *dlid;
 	struct dev_layer *dep;
 
 	hash_iterate(hn, dm->layers) {
 		dl = hash_get_data(dm->layers, hn);
 
-		list_iterate(sh, &dl->pre_suspend) {
-			dlid = list_item(sh, struct str_list)->str;
+		list_iterate_items(strl, &dl->pre_suspend) {
+			dlid = strl->str;
 
 			if (!(dep = hash_lookup(dm->layers, dlid))) {
 				log_debug("_populate_pre_suspend_lists: "
@@ -1676,8 +1734,8 @@
 			}
 		}
 
-		list_iterate(sh, &dl->pre_create) {
-			dlid = list_item(sh, struct str_list)->str;
+		list_iterate_items(strl, &dl->pre_create) {
+			dlid = strl->str;
 
 			if (!(dep = hash_lookup(dm->layers, dlid))) {
 				log_debug("_populate_pre_suspend_lists: "
@@ -1702,6 +1760,7 @@
 static int _remove_old_layers(struct dev_manager *dm)
 {
 	int change;
+	struct dl_list *dll;
 	struct list *rh, *n;
 	struct dev_layer *dl;
 
@@ -1724,10 +1783,8 @@
 	} while (change);
 
 	if (!list_empty(&dm->remove_list)) {
-		list_iterate(rh, &dm->remove_list) {
-			dl = list_item(rh, struct dl_list)->dl;
-			log_error("Couldn't deactivate device %s", dl->name);
-		}
+		list_iterate_items(dll, &dm->remove_list)
+			log_error("Couldn't deactivate device %s", dll->dl->name);
 		return 0;
 	}
 
@@ -1914,14 +1971,14 @@
 static int _add_lvs(struct pool *mem,
 		    struct list *head, struct logical_volume *origin)
 {
-	struct logical_volume *lv;
-	struct snapshot *s;
-	struct list *lvh;
+	struct lv_segment *snap_seg;
+	struct lv_list *lvl;
 
-	list_iterate(lvh, &origin->vg->lvs) {
-		lv = list_item(lvh, struct lv_list)->lv;
-		if ((s = find_cow(lv)) && s->origin == origin)
-			if (!_add_lv(mem, head, lv))
+	list_iterate_items(lvl, &origin->vg->lvs) {
+		if (lvl->lv->status & SNAPSHOT)
+			continue;
+		if ((snap_seg = find_cow(lvl->lv)) && snap_seg->origin == origin)
+			if (!_add_lv(mem, head, lvl->lv))
 				return 0;
 	}
 
@@ -1930,13 +1987,11 @@
 
 static void _remove_lv(struct list *head, struct logical_volume *lv)
 {
-	struct list *lvh;
 	struct lv_list *lvl;
 
-	list_iterate(lvh, head) {
-		lvl = list_item(lvh, struct lv_list);
+	list_iterate_items(lvl, head) {
 		if (lvl->lv == lv) {
-			list_del(lvh);
+			list_del(&lvl->list);
 			break;
 		}
 	}
@@ -1945,30 +2000,32 @@
 static int _remove_lvs(struct dev_manager *dm, struct logical_volume *lv)
 {
 	struct logical_volume *active, *old_origin;
-	struct snapshot *s;
-	struct list *sh, *active_head;
+	struct lv_segment *snap_seg;
+	struct list *active_head;
+	struct lv_list *lvl;
 
 	active_head = &dm->active_list;
 
 	/* Remove any snapshots with given origin */
-	list_iterate(sh, active_head) {
-		active = list_item(sh, struct lv_list)->lv;
-		if ((s = find_cow(active)) && s->origin == lv) {
+	list_iterate_items(lvl, active_head) {
+		active = lvl->lv;
+		if ((snap_seg = find_cow(active)) && snap_seg->origin == lv) {
 			_remove_lv(active_head, active);
 		}
 	}
 
 	_remove_lv(active_head, lv);
 
-	if (!(s = find_cow(lv)))
+	if (!(snap_seg = find_cow(lv)))
 		return 1;
 
-	old_origin = s->origin;
+	old_origin = snap_seg->origin;
 
 	/* Was this the last active snapshot with this origin? */
-	list_iterate(sh, active_head) {
-		active = list_item(sh, struct lv_list)->lv;
-		if ((s = find_cow(active)) && s->origin == old_origin) {
+	list_iterate_items(lvl, active_head) {
+		active = lvl->lv;
+		if ((snap_seg = find_cow(active)) &&
+		    snap_seg->origin == old_origin) {
 			return 1;
 		}
 	}
@@ -1980,15 +2037,17 @@
 				 struct logical_volume *lv)
 {
 	struct logical_volume *suspended;
-	struct snapshot *s;
-	struct list *sh, *suspend_head;
+	struct lv_segment *snap_seg;
+	struct list *suspend_head;
+	struct lv_list *lvl;
 
 	suspend_head = &dm->suspend_list;
 
 	/* Remove from list any snapshots with given origin */
-	list_iterate(sh, suspend_head) {
-		suspended = list_item(sh, struct lv_list)->lv;
-		if ((s = find_cow(suspended)) && s->origin == lv) {
+	list_iterate_items(lvl, suspend_head) {
+		suspended = lvl->lv;
+		if ((snap_seg = find_cow(suspended)) &&
+		    snap_seg->origin == lv) {
 			_remove_lv(suspend_head, suspended);
 		}
 	}
@@ -2001,13 +2060,13 @@
 static int _targets_present(struct dev_manager *dm, struct list *lvs)
 {
 	struct logical_volume *lv;
-	struct list *lvh, *segh;
+	struct lv_list *lvl;
 	struct segment_type *segtype;
 	struct lv_segment *seg;
 	int snapshots = 0, mirrors = 0;
 
-	list_iterate(lvh, lvs) {
-		lv = list_item(lvh, struct lv_list)->lv;
+	list_iterate_items(lvl, lvs) {
+		lv = lvl->lv;
 
 		if (!snapshots)
 			if (lv_is_cow(lv) || lv_is_origin(lv))
@@ -2018,8 +2077,7 @@
 				mirrors = 1;
 
 		if (lv->status & VIRTUAL) {
-			list_iterate(segh, &lv->segments) {
-				seg = list_item(segh, struct lv_segment);
+			list_iterate_items(seg, &lv->segments) {
 				if (seg->segtype->ops->target_present &&
 				    !seg->segtype->ops->target_present()) {
 					log_error("Can't expand LV: %s target "
@@ -2068,14 +2126,14 @@
 static int _fill_in_active_list(struct dev_manager *dm, struct volume_group *vg)
 {
 	char *dlid;
-	struct list *lvh;
-	struct logical_volume *lv;
+	struct lv_list *lvl;
 	struct dev_layer *dl;
 
-	list_iterate(lvh, &vg->lvs) {
-		lv = list_item(lvh, struct lv_list)->lv;
+	list_iterate_items(lvl, &vg->lvs) {
+		if (lvl->lv->status & SNAPSHOT)
+			continue;
 
-		if (!(dlid = _build_dlid(dm->mem, lv->lvid.s, NULL))) {
+		if (!(dlid = _build_dlid(dm->mem, lvl->lv->lvid.s, NULL))) {
 			stack;
 			return 0;
 		}
@@ -2084,16 +2142,16 @@
 		pool_free(dm->mem, dlid);
 
 		if (dl) {
-			log_debug("Found active lv %s%s", lv->name,
+			log_debug("Found active lv %s%s", lvl->lv->name,
 				  dl->info.suspended ? " (suspended)" : "");
 
-			if (!_add_lv(dm->mem, &dm->active_list, lv)) {
+			if (!_add_lv(dm->mem, &dm->active_list, lvl->lv)) {
 				stack;
 				return 0;
 			}
 
 			if (dl->info.suspended) {
-				if (!_add_lv(dm->mem, &dm->suspend_list, lv)) {
+				if (!_add_lv(dm->mem, &dm->suspend_list, lvl->lv)) {
 					stack;
 					return 0;
 				}

Modified: lvm2/trunk/lib/activate/fs.c
==============================================================================
--- lvm2/trunk/lib/activate/fs.c	(original)
+++ lvm2/trunk/lib/activate/fs.c	Tue Jun 14 11:23:47 2005
@@ -65,7 +65,7 @@
 		return 0;
 	}
 
-	if (is_empty_dir(vg_path)) {
+	if (dir_exists(vg_path) && is_empty_dir(vg_path)) {
 		log_very_verbose("Removing directory %s", vg_path);
 		rmdir(vg_path);
 	}
@@ -180,7 +180,7 @@
 	}
 
 #ifdef HAVE_SELINUX
-        if (!set_selinux_context(lv_path)) {
+        if (!set_selinux_context(lv_path, S_IFLNK)) {
                 stack;
                 return 0;
         }

Modified: lvm2/trunk/lib/activate/targets.h
==============================================================================
--- lvm2/trunk/lib/activate/targets.h	(original)
+++ lvm2/trunk/lib/activate/targets.h	Tue Jun 14 11:23:47 2005
@@ -19,7 +19,12 @@
 struct dev_manager;
 struct lv_segment;
 
-int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg,                                 char *params, size_t paramsize, int *pos,
-		                        int start_area, int areas);
+int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg,
+		       char *params, size_t paramsize, int *pos,
+		       int start_area, int areas);
+
+int compose_log_line(struct dev_manager *dm, struct lv_segment *seg,
+		     char *params, size_t paramsize, int *pos, int areas,
+		     uint32_t region_size);
 
 #endif

Modified: lvm2/trunk/lib/cache/lvmcache.c
==============================================================================
--- lvm2/trunk/lib/cache/lvmcache.c	(original)
+++ lvm2/trunk/lib/cache/lvmcache.c	Tue Jun 14 11:23:47 2005
@@ -104,10 +104,31 @@
 const struct format_type *fmt_from_vgname(const char *vgname)
 {
 	struct lvmcache_vginfo *vginfo;
+	struct lvmcache_info *info;
+	struct label *label;
+	struct list *devh, *tmp;
+	struct list devs;
+	struct device_list *devl;
 
 	if (!(vginfo = vginfo_from_vgname(vgname)))
 		return NULL;
 
+	/* This function is normally called before reading metadata so
+ 	 * we check cached labels here. Unfortunately vginfo is volatile. */
+	list_init(&devs);
+	list_iterate_items(info, &vginfo->infos) {
+		devl = dbg_malloc(sizeof(*devl));
+		devl->dev = info->dev;
+		list_add(&devs, &devl->list);
+	}
+
+	list_iterate_safe(devh, tmp, &devs) {
+		devl = list_item(devh, struct device_list);
+		label_read(devl->dev, &label);
+		list_del(&devl->list);
+		dbg_free(devl);
+	}
+
 	return vginfo->fmt;
 }
 
@@ -166,7 +187,6 @@
 	struct label *label;
 	struct dev_iter *iter;
 	struct device *dev;
-	struct list *fmth;
 	struct format_type *fmt;
 
 	static int _scanning_in_progress = 0;
@@ -188,7 +208,7 @@
 		goto out;
 	}
 
-	if (!(iter = dev_iter_create(cmd->filter))) {
+	if (!(iter = dev_iter_create(cmd->filter, (full_scan == 2) ? 1: 0))) {
 		log_error("dev_iter creation failed");
 		goto out;
 	}
@@ -201,8 +221,7 @@
 	_has_scanned = 1;
 
 	/* Perform any format-specific scanning e.g. text files */
-	list_iterate(fmth, &cmd->formats) {
-		fmt = list_item(fmth, struct format_type);
+	list_iterate_items(fmt, &cmd->formats) {
 		if (fmt->ops->scan && !fmt->ops->scan(fmt))
 			goto out;
 	}
@@ -266,7 +285,7 @@
 	if (memlock())
 		return NULL;
 
-	lvmcache_label_scan(cmd, 1);
+	lvmcache_label_scan(cmd, 2);
 
 	/* Try again */
 	if ((info = info_from_pvid((char *) pvid))) {
@@ -403,23 +422,24 @@
 	/* FIXME Check consistency of list! */
 	vginfo->fmt = info->fmt;
 
+	log_debug("lvmcache: %s now %s%s", dev_name(info->dev),
+		  *vgname ? "in VG " : "orphaned", vgname);
+
 	return 1;
 }
 
 int lvmcache_update_vg(struct volume_group *vg)
 {
-	struct list *pvh;
-	struct physical_volume *pv;
+	struct pv_list *pvl;
 	struct lvmcache_info *info;
 	char pvid_s[ID_LEN + 1];
 	int vgid_updated = 0;
 
 	pvid_s[sizeof(pvid_s) - 1] = '\0';
 
-	list_iterate(pvh, &vg->pvs) {
-		pv = list_item(pvh, struct pv_list)->pv;
-		strncpy(pvid_s, (char *) &pv->id, sizeof(pvid_s) - 1);
-		/* FIXME Could pv->dev->pvid ever be different? */
+	list_iterate_items(pvl, &vg->pvs) {
+		strncpy(pvid_s, (char *) &pvl->pv->id, sizeof(pvid_s) - 1);
+		/* FIXME Could pvl->pv->dev->pvid ever be different? */
 		if ((info = info_from_pvid(pvid_s))) {
 			lvmcache_update_vgname(info, vg->name);
 			if (!vgid_updated) {
@@ -551,6 +571,8 @@
 
 void lvmcache_destroy(void)
 {
+	log_verbose("Wiping internal VG cache");
+
 	_has_scanned = 0;
 
 	if (_vgid_hash) {

Modified: lvm2/trunk/lib/cache/lvmcache.h
==============================================================================
--- lvm2/trunk/lib/cache/lvmcache.h	(original)
+++ lvm2/trunk/lib/cache/lvmcache.h	Tue Jun 14 11:23:47 2005
@@ -36,9 +36,10 @@
 struct lvmcache_vginfo {
 	struct list list;	/* Join these vginfos together */
 	struct list infos;	/* List head for lvmcache_infos */
+	const struct format_type *fmt;
 	char *vgname;		/* "" == orphan */
 	char vgid[ID_LEN + 1];
-	const struct format_type *fmt;
+	char _padding[7];
 };
 
 struct lvmcache_info {
@@ -56,7 +57,8 @@
 int lvmcache_init(void);
 void lvmcache_destroy(void);
 
-/* Set full_scan to 1 to reread every filtered device label */
+/* Set full_scan to 1 to reread every filtered device label or
+ * 2 to rescan /dev for new devices */
 int lvmcache_label_scan(struct cmd_context *cmd, int full_scan);
 
 /* Add/delete a device */

Modified: lvm2/trunk/lib/commands/toolcontext.c
==============================================================================
--- lvm2/trunk/lib/commands/toolcontext.c	(original)
+++ lvm2/trunk/lib/commands/toolcontext.c	Tue Jun 14 11:23:47 2005
@@ -35,6 +35,8 @@
 #include "str_list.h"
 #include "segtype.h"
 #include "lvmcache.h"
+#include "dev-cache.h"
+#include "archiver.h"
 
 #ifdef HAVE_LIBDL
 #include "sharedlib.h"
@@ -493,6 +495,24 @@
 		}
 	}
 
+	if (!(cn = find_config_node(cmd->cft->root, "devices/loopfiles")))
+		return 1;
+
+	for (cv = cn->v; cv; cv = cv->next) {
+		if (cv->type != CFG_STRING) {
+			log_error("Invalid string in config file: "
+				  "devices/loopfiles");
+			return 0;
+		}
+
+		if (!dev_cache_add_loopfile(cv->v.str)) {
+			log_error("Failed to add loopfile %s to internal "
+				  "device cache", cv->v.str);
+			return 0;
+		}
+	}
+
+
 	return 1;
 }
 
@@ -602,7 +622,6 @@
 	const char *format;
 
 	struct format_type *fmt;
-	struct list *fmth;
 
 #ifdef HAVE_LIBDL
 	const struct config_node *cn;
@@ -669,8 +688,7 @@
 	format = find_config_str(cmd->cft->root, "global/format",
 				 DEFAULT_FORMAT);
 
-	list_iterate(fmth, &cmd->formats) {
-		fmt = list_item(fmth, struct format_type);
+	list_iterate_items(fmt, &cmd->formats) {
 		if (!strcasecmp(fmt->name, format) ||
 		    (fmt->alias && !strcasecmp(fmt->alias, format))) {
 			cmd->default_settings.fmt = fmt;
@@ -795,6 +813,69 @@
 	return 1;
 }
 
+static int _init_backup(struct cmd_context *cmd)
+{
+	uint32_t days, min;
+	char default_dir[PATH_MAX];
+	const char *dir;
+
+	if (!cmd->sys_dir) {
+		log_warn("WARNING: Metadata changes will NOT be backed up");
+		backup_init(cmd, "");
+		archive_init(cmd, "", 0, 0);
+		return 1;
+	}
+
+	/* set up archiving */
+	cmd->default_settings.archive =
+	    find_config_bool(cmd->cft->root, "backup/archive",
+			     DEFAULT_ARCHIVE_ENABLED);
+
+	days = (uint32_t) find_config_int(cmd->cft->root, "backup/retain_days",
+					  DEFAULT_ARCHIVE_DAYS);
+
+	min = (uint32_t) find_config_int(cmd->cft->root, "backup/retain_min",
+					 DEFAULT_ARCHIVE_NUMBER);
+
+	if (lvm_snprintf
+	    (default_dir, sizeof(default_dir), "%s/%s", cmd->sys_dir,
+	     DEFAULT_ARCHIVE_SUBDIR) == -1) {
+		log_err("Couldn't create default archive path '%s/%s'.",
+			cmd->sys_dir, DEFAULT_ARCHIVE_SUBDIR);
+		return 0;
+	}
+
+	dir = find_config_str(cmd->cft->root, "backup/archive_dir",
+			      default_dir);
+
+	if (!archive_init(cmd, dir, days, min)) {
+		log_debug("backup_init failed.");
+		return 0;
+	}
+
+	/* set up the backup */
+	cmd->default_settings.backup =
+	    find_config_bool(cmd->cft->root, "backup/backup",
+			     DEFAULT_BACKUP_ENABLED);
+
+	if (lvm_snprintf
+	    (default_dir, sizeof(default_dir), "%s/%s", cmd->sys_dir,
+	     DEFAULT_BACKUP_SUBDIR) == -1) {
+		log_err("Couldn't create default backup path '%s/%s'.",
+			cmd->sys_dir, DEFAULT_BACKUP_SUBDIR);
+		return 0;
+	}
+
+	dir = find_config_str(cmd->cft->root, "backup/backup_dir", default_dir);
+
+	if (!backup_init(cmd, dir)) {
+		log_debug("backup_init failed.");
+		return 0;
+	}
+
+	return 1;
+}
+
 /* Entry point */
 struct cmd_context *create_toolcontext(struct arg *the_args)
 {
@@ -883,6 +964,9 @@
 	if (!_init_segtypes(cmd))
 		goto error;
 
+	if (!_init_backup(cmd))
+		goto error;
+
 	cmd->current_settings = cmd->default_settings;
 
 	cmd->config_valid = 1;
@@ -993,6 +1077,8 @@
 	if (cmd->dump_filter)
 		persistent_filter_dump(cmd->filter);
 
+	archive_exit(cmd);
+	backup_exit(cmd);
 	activation_exit();
 	lvmcache_destroy();
 	label_exit();

Modified: lvm2/trunk/lib/commands/toolcontext.h
==============================================================================
--- lvm2/trunk/lib/commands/toolcontext.h	(original)
+++ lvm2/trunk/lib/commands/toolcontext.h	Tue Jun 14 11:23:47 2005
@@ -32,20 +32,20 @@
 	int syslog;
 	int activation;
 	int suffix;
-	uint64_t unit_factor;
-	char unit_type;
-	const char *msg_prefix;
-	int cmd_name;		/* Show command name? */
-
 	int archive;		/* should we archive ? */
 	int backup;		/* should we backup ? */
-
+	const char *msg_prefix;
 	struct format_type *fmt;
-
+	uint64_t unit_factor;
+	int cmd_name;		/* Show command name? */
 	mode_t umask;
+	char unit_type;
+	char _padding[1];
 };
 
 struct config_tree;
+struct archive_params;
+struct backup_params;
 
 /* FIXME Split into tool & library contexts */
 /* command-instance-related variables needed by library */
@@ -75,6 +75,9 @@
 	struct config_info default_settings;
 	struct config_info current_settings;
 
+	struct archive_params *archive_params;
+	struct backup_params *backup_params;
+
 	/* List of defined tags */
 	struct list tags;
 	int hosttags;

Modified: lvm2/trunk/lib/config/config.c
==============================================================================
--- lvm2/trunk/lib/config/config.c	(original)
+++ lvm2/trunk/lib/config/config.c	Tue Jun 14 11:23:47 2005
@@ -235,7 +235,7 @@
 		return 1;
 	}
 
-	if (!(dev = dev_create_file(c->filename, NULL, NULL))) {
+	if (!(dev = dev_create_file(c->filename, NULL, NULL, 1))) {
 		stack;
 		return 0;
 	}

Modified: lvm2/trunk/lib/config/defaults.h
==============================================================================
--- lvm2/trunk/lib/config/defaults.h	(original)
+++ lvm2/trunk/lib/config/defaults.h	Tue Jun 14 11:23:47 2005
@@ -91,19 +91,22 @@
 #define DEFAULT_REP_HEADINGS 1
 #define DEFAULT_REP_SEPARATOR " "
 
-#define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,origin,snap_percent,move_pv,copy_percent"
+#define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,origin,snap_percent,move_pv,mirror_log,copy_percent"
 #define DEFAULT_VGS_COLS "vg_name,pv_count,lv_count,snap_count,vg_attr,vg_size,vg_free"
 #define DEFAULT_PVS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free"
 #define DEFAULT_SEGS_COLS "lv_name,vg_name,lv_attr,stripes,segtype,seg_size"
+#define DEFAULT_PVSEGS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size"
 
-#define DEFAULT_LVS_COLS_VERB "lv_name,vg_name,seg_count,lv_attr,lv_size,lv_major,lv_minor,lv_kernel_major,lv_kernel_minor,origin,snap_percent,move_pv,copy_percent,lv_uuid"
+#define DEFAULT_LVS_COLS_VERB "lv_name,vg_name,seg_count,lv_attr,lv_size,lv_major,lv_minor,lv_kernel_major,lv_kernel_minor,origin,snap_percent,move_pv,copy_percent,mirror_log,lv_uuid"
 #define DEFAULT_VGS_COLS_VERB "vg_name,vg_attr,vg_extent_size,pv_count,lv_count,snap_count,vg_size,vg_free,vg_uuid"
 #define DEFAULT_PVS_COLS_VERB "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,dev_size,pv_uuid"
 #define DEFAULT_SEGS_COLS_VERB "lv_name,vg_name,lv_attr,seg_start,seg_size,stripes,segtype,stripesize,chunksize"
+#define DEFAULT_PVSEGS_COLS_VERB "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size"
 
 #define DEFAULT_LVS_SORT "vg_name,lv_name"
 #define DEFAULT_VGS_SORT "vg_name"
 #define DEFAULT_PVS_SORT "pv_name"
 #define DEFAULT_SEGS_SORT "vg_name,lv_name,seg_start"
+#define DEFAULT_PVSEGS_SORT "pv_name,pvseg_start"
 
 #endif				/* _LVM_DEFAULTS_H */

Modified: lvm2/trunk/lib/datastruct/list.h
==============================================================================
--- lvm2/trunk/lib/datastruct/list.h	(original)
+++ lvm2/trunk/lib/datastruct/list.h	Tue Jun 14 11:23:47 2005
@@ -18,17 +18,30 @@
 
 #include <assert.h>
 
+/*
+ * A list consists of a list head plus elements.
+ * Each element has 'next' and 'previous' pointers.
+ * The list head's pointers point to the first and the last element.
+ */
+
 struct list {
 	struct list *n, *p;
 };
 
+/*
+ * Initialise a list before use.
+ * The list head's next and previous pointers point back to itself.
+ */
 #define LIST_INIT(name)	struct list name = { &(name), &(name) }
-
 static inline void list_init(struct list *head)
 {
 	head->n = head->p = head;
 }
 
+/*
+ * Insert an element before 'head'.
+ * If 'head' is the list head, this adds an element to the end of the list.
+ */
 static inline void list_add(struct list *head, struct list *elem)
 {
 	assert(head->n);
@@ -40,6 +53,10 @@
 	head->p = elem;
 }
 
+/*
+ * Insert an element after 'head'.
+ * If 'head' is the list head, this adds an element to the front of the list.
+ */
 static inline void list_add_h(struct list *head, struct list *elem)
 {
 	assert(head->n);
@@ -51,53 +68,162 @@
 	head->n = elem;
 }
 
+/*
+ * Delete an element from its list.
+ * Note that this doesn't change the element itself - it may still be safe
+ * to follow its pointers.
+ */
 static inline void list_del(struct list *elem)
 {
 	elem->n->p = elem->p;
 	elem->p->n = elem->n;
 }
 
+/*
+ * Is the list empty?
+ */
 static inline int list_empty(struct list *head)
 {
 	return head->n == head;
 }
 
+/*
+ * Is this the first element of the list?
+ */
+static inline int list_start(struct list *head, struct list *elem)
+{
+	return elem->p == head;
+}
+
+/*
+ * Is this the last element of the list?
+ */
 static inline int list_end(struct list *head, struct list *elem)
 {
 	return elem->n == head;
 }
 
-static inline struct list *list_next(struct list *head, struct list *elem)
+/*
+ * Return first element of the list or NULL if empty
+ */
+static inline struct list *list_first(struct list *head)
 {
-	return (list_end(head, elem) ? NULL : elem->n);
+	return (list_empty(head) ? NULL : head->n);
 }
 
-#define list_item(v, t) \
-    ((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->list))
+/*
+ * Return last element of the list or NULL if empty
+ */
+static inline struct list *list_last(struct list *head)
+{
+	return (list_empty(head) ? NULL : head->p);
+}
 
-#define list_struct_base(v, t, h) \
-    ((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->h))
+/*
+ * Return the previous element of the list, or NULL if we've reached the start.
+ */
+static inline struct list *list_prev(struct list *head, struct list *elem)
+{
+	return (list_start(head, elem) ? NULL : elem->p);
+}
+
+/*
+ * Return the next element of the list, or NULL if we've reached the end.
+ */
+static inline struct list *list_next(struct list *head, struct list *elem)
+{
+	return (list_end(head, elem) ? NULL : elem->n);
+}
 
-/* Given a known element in a known structure, locate another */
+/*
+ * Given the address v of an instance of 'struct list' called 'head' 
+ * contained in a structure of type t, return the containing structure.
+ */
+#define list_struct_base(v, t, head) \
+    ((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->head))
+
+/*
+ * Given the address v of an instance of 'struct list list' contained in
+ * a structure of type t, return the containing structure.
+ */
+#define list_item(v, t) list_struct_base((v), t, list)
+
+/*
+ * Given the address v of one known element e in a known structure of type t,
+ * return another element f.
+ */
 #define struct_field(v, t, e, f) \
     (((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->e))->f)
 
-/* Given a known element in a known structure, locate the list head */
+/*
+ * Given the address v of a known element e in a known structure of type t,
+ * return the list head 'list'
+ */
 #define list_head(v, t, e) struct_field(v, t, e, list)
 
+/*
+ * Set v to each element of a list in turn.
+ */
 #define list_iterate(v, head) \
 	for (v = (head)->n; v != head; v = v->n)
 
+/*
+ * Set v to each element in a list in turn, starting from the element 
+ * in front of 'start'.
+ * You can use this to 'unwind' a list_iterate and back out actions on
+ * already-processed elements.
+ * If 'start' is 'head' it walks the list backwards.
+ */
 #define list_uniterate(v, head, start) \
 	for (v = (start)->p; v != head; v = v->p)
 
+/*
+ * A safe way to walk a list and delete and free some elements along
+ * the way.
+ * t must be defined as a temporary variable of the same type as v.
+ */
 #define list_iterate_safe(v, t, head) \
 	for (v = (head)->n, t = v->n; v != head; v = t, t = v->n)
 
-#define list_iterate_items(v, head) \
-	for (v = list_item((head)->n, typeof(*v)); &v->list != (head); \
-	     v = list_item(v->list.n, typeof(*v)))
-
+/*
+ * Walk a list, setting 'v' in turn to the containing structure of each item.
+ * The containing structure should be the same type as 'v'.
+ * The 'struct list' variable within the containing structure is 'field'.
+ */
+#define list_iterate_items_gen(v, head, field) \
+	for (v = list_struct_base((head)->n, typeof(*v), field); \
+	     &v->field != (head); \
+	     v = list_struct_base(v->field.n, typeof(*v), field))
+
+/*
+ * Walk a list, setting 'v' in turn to the containing structure of each item.
+ * The containing structure should be the same type as 'v'.
+ * The list should be 'struct list list' within the containing structure.
+ */
+#define list_iterate_items(v, head) list_iterate_items_gen(v, (head), list)
+
+/*
+ * Walk a list backwards, setting 'v' in turn to the containing structure 
+ * of each item.
+ * The containing structure should be the same type as 'v'.
+ * The 'struct list' variable within the containing structure is 'field'.
+ */
+#define list_iterate_back_items_gen(v, head, field) \
+	for (v = list_struct_base((head)->p, typeof(*v), field); \
+	     &v->field != (head); \
+	     v = list_struct_base(v->field.p, typeof(*v), field))
+
+/*
+ * Walk a list backwards, setting 'v' in turn to the containing structure 
+ * of each item.
+ * The containing structure should be the same type as 'v'.
+ * The list should be 'struct list list' within the containing structure.
+ */
+#define list_iterate_back_items(v, head) list_iterate_back_items_gen(v, (head), list)
+
+/*
+ * Return the number of elements in a list by walking it.
+ */
 static inline unsigned int list_size(const struct list *head)
 {
 	unsigned int s = 0;

Modified: lvm2/trunk/lib/datastruct/lvm-types.h
==============================================================================
--- lvm2/trunk/lib/datastruct/lvm-types.h	(original)
+++ lvm2/trunk/lib/datastruct/lvm-types.h	Tue Jun 14 11:23:47 2005
@@ -22,7 +22,7 @@
 #include <inttypes.h>
 
 /* Define some portable printing types */
-#define PRIsize_t "Zu"
+#define PRIsize_t "zu"
 
 struct str_list {
 	struct list list;

Modified: lvm2/trunk/lib/device/dev-cache.c
==============================================================================
--- lvm2/trunk/lib/device/dev-cache.c	(original)
+++ lvm2/trunk/lib/device/dev-cache.c	Tue Jun 14 11:23:47 2005
@@ -21,6 +21,7 @@
 #include "lvm-types.h"
 #include "btree.h"
 #include "filter.h"
+#include "filter-persistent.h"
 
 #include <unistd.h>
 #include <sys/param.h>
@@ -43,39 +44,60 @@
 
 	int has_scanned;
 	struct list dirs;
+	struct list files;
 
 } _cache;
 
-#define _alloc(x) pool_alloc(_cache.mem, (x))
+#define _alloc(x) pool_zalloc(_cache.mem, (x))
 #define _free(x) pool_free(_cache.mem, (x))
+#define _strdup(x) pool_strdup(_cache.mem, (x))
 
 static int _insert(const char *path, int rec);
 
 struct device *dev_create_file(const char *filename, struct device *dev,
-			       struct str_list *alias)
+			       struct str_list *alias, int use_malloc)
 {
 	int allocate = !dev;
 
-	if (allocate && !(dev = dbg_malloc(sizeof(*dev)))) {
-		log_error("struct device allocation failed");
-		return NULL;
-	}
-	if (allocate && !(alias = dbg_malloc(sizeof(*alias)))) {
-		log_error("struct str_list allocation failed");
-		dbg_free(dev);
-		return NULL;
-	}
-	if (!(alias->str = dbg_strdup(filename))) {
-		log_error("filename strdup failed");
-		if (allocate) {
-			dbg_free(dev);
-			dbg_free(alias);
+	if (allocate) {
+		if (use_malloc) {
+			if (!(dev = dbg_malloc(sizeof(*dev)))) {
+				log_error("struct device allocation failed");
+				return NULL;
+			}
+			if (!(alias = dbg_malloc(sizeof(*alias)))) {
+				log_error("struct str_list allocation failed");
+				dbg_free(dev);
+				return NULL;
+			}
+			if (!(alias->str = dbg_strdup(filename))) {
+				log_error("filename strdup failed");
+				dbg_free(dev);
+				dbg_free(alias);
+				return NULL;
+			}
+			dev->flags = DEV_ALLOCED;
+		} else {
+			if (!(dev = _alloc(sizeof(*dev)))) {
+				log_error("struct device allocation failed");
+				return NULL;
+			}
+			if (!(alias = _alloc(sizeof(*alias)))) {
+				log_error("struct str_list allocation failed");
+				_free(dev);
+				return NULL;
+			}
+			if (!(alias->str = _strdup(filename))) {
+				log_error("filename strdup failed");
+				return NULL;
+			}
 		}
+	} else if (!(alias->str = dbg_strdup(filename))) {
+		log_error("filename strdup failed");
 		return NULL;
 	}
-	dev->flags = DEV_REGULAR;
-	if (allocate)
-		dev->flags |= DEV_ALLOCED;
+
+	dev->flags |= DEV_REGULAR;
 	list_init(&dev->aliases);
 	list_add(&dev->aliases, &alias->list);
 	dev->end = UINT64_C(0);
@@ -174,7 +196,7 @@
 static int _add_alias(struct device *dev, const char *path)
 {
 	struct str_list *sl = _alloc(sizeof(*sl));
-	struct list *ah;
+	struct str_list *strl;
 	const char *oldpath;
 	int prefer_old = 1;
 
@@ -184,9 +206,9 @@
 	}
 
 	/* Is name already there? */
-	list_iterate(ah, &dev->aliases) {
-		if (!strcmp(list_item(ah, struct str_list)->str, path)) {
-			stack;
+	list_iterate_items(strl, &dev->aliases) {
+		if (!strcmp(strl->str, path)) {
+			log_debug("%s: Already in device cache", path);
 			return 1;
 		}
 	}
@@ -220,12 +242,25 @@
 static int _insert_dev(const char *path, dev_t d)
 {
 	struct device *dev;
+	static dev_t loopfile_count = 0;
+	int loopfile = 0;
+
+	/* Generate pretend device numbers for loopfiles */
+	if (!d) {
+		d = ++loopfile_count;
+		loopfile = 1;
+	}
 
 	/* is this device already registered ? */
 	if (!(dev = (struct device *) btree_lookup(_cache.devices,
 						   (uint32_t) d))) {
 		/* create new device */
-		if (!(dev = _dev_create(d))) {
+		if (loopfile) {
+			if (!(dev = dev_create_file(path, NULL, NULL, 0))) {
+				stack;
+				return 0;
+			}
+		} else if (!(dev = _dev_create(d))) {
 			stack;
 			return 0;
 		}
@@ -237,7 +272,7 @@
 		}
 	}
 
-	if (!_add_alias(dev, path)) {
+	if (!loopfile && !_add_alias(dev, path)) {
 		log_err("Couldn't add alias to dev cache.");
 		return 0;
 	}
@@ -313,6 +348,28 @@
 	return r;
 }
 
+static int _insert_file(const char *path)
+{
+	struct stat info;
+
+	if (stat(path, &info) < 0) {
+		log_sys_very_verbose("stat", path);
+		return 0;
+	}
+
+	if (!S_ISREG(info.st_mode)) {
+		log_debug("%s: Not a regular file", path);
+		return 0;
+	}
+
+	if (!_insert_dev(path, 0)) {
+		stack;
+		return 0;
+	}
+
+	return 1;
+}
+
 static int _insert(const char *path, int rec)
 {
 	struct stat info;
@@ -355,19 +412,21 @@
 	return r;
 }
 
-static void _full_scan(void)
+static void _full_scan(int dev_scan)
 {
-	struct list *dh;
+	struct dir_list *dl;
 
-	if (_cache.has_scanned)
+	if (_cache.has_scanned && !dev_scan)
 		return;
 
-	list_iterate(dh, &_cache.dirs) {
-		struct dir_list *dl = list_item(dh, struct dir_list);
+	list_iterate_items(dl, &_cache.dirs)
 		_insert_dir(dl->dir);
-	};
+
+	list_iterate_items(dl, &_cache.files)
+		_insert_file(dl->dir);
 
 	_cache.has_scanned = 1;
+	init_full_scan_done(1);
 }
 
 int dev_cache_has_scanned(void)
@@ -379,15 +438,14 @@
 {
 	if (!do_scan)
 		_cache.has_scanned = 1;
-	else {
-		_cache.has_scanned = 0;
-		_full_scan();
-	}
+	else
+		_full_scan(1);
 }
 
 int dev_cache_init(void)
 {
 	_cache.names = NULL;
+	_cache.has_scanned = 0;
 
 	if (!(_cache.mem = pool_create("dev_cache", 10 * 1024))) {
 		stack;
@@ -407,6 +465,7 @@
 	}
 
 	list_init(&_cache.dirs);
+	list_init(&_cache.files);
 
 	return 1;
 
@@ -444,6 +503,7 @@
 	_cache.devices = NULL;
 	_cache.has_scanned = 0;
 	list_init(&_cache.dirs);
+	list_init(&_cache.files);
 }
 
 int dev_cache_add_dir(const char *path)
@@ -472,6 +532,32 @@
 	return 1;
 }
 
+int dev_cache_add_loopfile(const char *path)
+{
+	struct dir_list *dl;
+	struct stat st;
+
+	if (stat(path, &st)) {
+		log_error("Ignoring %s: %s", path, strerror(errno));
+		/* But don't fail */
+		return 1;
+	}
+
+	if (!S_ISREG(st.st_mode)) {
+		log_error("Ignoring %s: Not a regular file", path);
+		return 1;
+	}
+
+	if (!(dl = _alloc(sizeof(*dl) + strlen(path) + 1))) {
+		log_error("dir_list allocation failed for file");
+		return 0;
+	}
+
+	strcpy(dl->dir, path);
+	list_add(&_cache.files, &dl->list);
+	return 1;
+}
+
 /* Check cached device name is still valid before returning it */
 /* This should be a rare occurrence */
 /* set quiet if the cache is expected to be out-of-date */
@@ -482,6 +568,9 @@
 	const char *name;
 	int r;
 
+	if ((dev->flags & DEV_REGULAR))
+		return dev_name(dev);
+
 	while ((r = stat(name = list_item(dev->aliases.n,
 					  struct str_list)->str, &buf)) ||
 	       (buf.st_rdev != dev->dev)) {
@@ -526,6 +615,9 @@
 	struct stat buf;
 	struct device *d = (struct device *) hash_lookup(_cache.names, name);
 
+	if (d && (d->flags & DEV_REGULAR))
+		return d;
+
 	/* If the entry's wrong, remove it */
 	if (d && (stat(name, &buf) || (buf.st_rdev != d->dev))) {
 		hash_remove(_cache.names, name);
@@ -537,10 +629,11 @@
 		d = (struct device *) hash_lookup(_cache.names, name);
 	}
 
-	return (d && (!f || f->passes_filter(f, d))) ? d : NULL;
+	return (d && (!f || (d->flags & DEV_REGULAR) ||
+		      f->passes_filter(f, d))) ? d : NULL;
 }
 
-struct dev_iter *dev_iter_create(struct dev_filter *f)
+struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan)
 {
 	struct dev_iter *di = dbg_malloc(sizeof(*di));
 
@@ -549,7 +642,14 @@
 		return NULL;
 	}
 
-	_full_scan();
+
+	if (dev_scan) {
+		/* Flag gets reset between each command */
+		if (!full_scan_done())
+			persistent_filter_wipe(f); /* Calls _full_scan(1) */
+	} else
+		_full_scan(0);
+
 	di->current = btree_first(_cache.devices);
 	di->filter = f;
 
@@ -572,7 +672,7 @@
 {
 	while (iter->current) {
 		struct device *d = _iter_next(iter);
-		if (!iter->filter ||
+		if (!iter->filter || (d->flags & DEV_REGULAR) ||
 		    iter->filter->passes_filter(iter->filter, d))
 			return d;
 	}

Modified: lvm2/trunk/lib/device/dev-cache.h
==============================================================================
--- lvm2/trunk/lib/device/dev-cache.h	(original)
+++ lvm2/trunk/lib/device/dev-cache.h	Tue Jun 14 11:23:47 2005
@@ -39,13 +39,14 @@
 int dev_cache_has_scanned(void);
 
 int dev_cache_add_dir(const char *path);
+int dev_cache_add_loopfile(const char *path);
 struct device *dev_cache_get(const char *name, struct dev_filter *f);
 
 /*
  * Object for iterating through the cache.
  */
 struct dev_iter;
-struct dev_iter *dev_iter_create(struct dev_filter *f);
+struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan);
 void dev_iter_destroy(struct dev_iter *iter);
 struct device *dev_iter_get(struct dev_iter *iter);
 

Modified: lvm2/trunk/lib/device/dev-io.c
==============================================================================
--- lvm2/trunk/lib/device/dev-io.c	(original)
+++ lvm2/trunk/lib/device/dev-io.c	Tue Jun 14 11:23:47 2005
@@ -222,11 +222,25 @@
 	return 1;
 }
 
-/*-----------------------------------------------------------------
- * Public functions
- *---------------------------------------------------------------*/
+static int _dev_get_size_file(const struct device *dev, uint64_t *size)
+{
+	const char *name = dev_name(dev);
+	struct stat info;
 
-int dev_get_size(const struct device *dev, uint64_t *size)
+	if (stat(name, &info)) {
+		log_sys_error("stat", name);
+		return 0;
+	}
+
+	*size = info.st_size;
+	*size >>= SECTOR_SHIFT;	/* Convert to sectors */
+
+	log_very_verbose("%s: size is %" PRIu64 " sectors", name, *size);
+
+	return 1;
+}
+
+static int _dev_get_size_dev(const struct device *dev, uint64_t *size)
 {
 	int fd;
 	const char *name = dev_name(dev);
@@ -252,6 +266,18 @@
 	return 1;
 }
 
+/*-----------------------------------------------------------------
+ * Public functions
+ *---------------------------------------------------------------*/
+
+int dev_get_size(const struct device *dev, uint64_t *size)
+{
+	if ((dev->flags & DEV_REGULAR))
+		return _dev_get_size_file(dev, size);
+	else
+		return _dev_get_size_dev(dev, size);
+}
+
 /* FIXME Unused
 int dev_get_sectsize(struct device *dev, uint32_t *size)
 {
@@ -330,8 +356,13 @@
 	}
 
 #ifdef O_DIRECT_SUPPORT
-	if (direct)
-		flags |= O_DIRECT;
+	if (direct) {
+		if (!(dev->flags & DEV_O_DIRECT_TESTED))
+			dev->flags |= DEV_O_DIRECT;
+
+		if ((dev->flags & DEV_O_DIRECT))
+			flags |= O_DIRECT;
+	}
 #endif
 
 #ifdef O_NOATIME
@@ -343,12 +374,31 @@
 #endif
 
 	if ((dev->fd = open(name, flags, 0777)) < 0) {
-		log_sys_error("open", name);
+#ifdef O_DIRECT_SUPPORT
+		if (direct && !(dev->flags & DEV_O_DIRECT_TESTED)) {
+			flags &= ~O_DIRECT;
+			if ((dev->fd = open(name, flags, 0777)) >= 0) {
+				dev->flags &= ~DEV_O_DIRECT;
+				log_debug("%s: Not using O_DIRECT", name);
+				goto opened;
+			}
+		}
+#endif
+		if (quiet)
+			log_sys_debug("open", name);
+		else
+			log_sys_error("open", name);
 		return 0;
 	}
 
+#ifdef O_DIRECT_SUPPORT
+      opened:
+	if (direct)
+		dev->flags |= DEV_O_DIRECT_TESTED;
+#endif
 	dev->open_count++;
 	dev->flags &= ~DEV_ACCESSED_W;
+
 	if ((flags & O_ACCMODE) == O_RDWR)
 		dev->flags |= DEV_OPENED_RW;
 	else
@@ -372,8 +422,9 @@
 
 	list_add(&_open_devices, &dev->open_list);
 
-	log_debug("Opened %s %s", dev_name(dev),
-		  dev->flags & DEV_OPENED_RW ? "RW" : "RO");
+	log_debug("Opened %s %s%s", dev_name(dev),
+		  dev->flags & DEV_OPENED_RW ? "RW" : "RO",
+		  dev->flags & DEV_O_DIRECT ? " O_DIRECT" : "");
 
 	return 1;
 }

Modified: lvm2/trunk/lib/device/device.h
==============================================================================
--- lvm2/trunk/lib/device/device.h	(original)
+++ lvm2/trunk/lib/device/device.h	Tue Jun 14 11:23:47 2005
@@ -23,6 +23,8 @@
 #define DEV_REGULAR		0x00000002	/* Regular file? */
 #define DEV_ALLOCED		0x00000004	/* dbg_malloc used */
 #define DEV_OPENED_RW		0x00000008	/* Opened RW */
+#define DEV_O_DIRECT		0x00000010	/* Use O_DIRECT */
+#define DEV_O_DIRECT_TESTED	0x00000020	/* DEV_O_DIRECT is reliable */
 
 /*
  * All devices in LVM will be represented by one of these.
@@ -41,6 +43,7 @@
 	struct list open_list;
 
 	char pvid[ID_LEN + 1];
+	char _padding[7];
 };
 
 struct device_list {
@@ -63,7 +66,7 @@
 /* Use quiet version if device number could change e.g. when opening LV */
 int dev_open(struct device *dev);
 int dev_open_quiet(struct device *dev);
-int dev_open_flags(struct device *dev, int flags, int append, int quiet);
+int dev_open_flags(struct device *dev, int flags, int direct, int quiet);
 int dev_close(struct device *dev);
 int dev_close_immediate(struct device *dev);
 void dev_close_all(void);
@@ -80,7 +83,7 @@
 void dev_flush(struct device *dev);
 
 struct device *dev_create_file(const char *filename, struct device *dev,
-			       struct str_list *alias);
+			       struct str_list *alias, int use_malloc);
 
 static inline const char *dev_name(const struct device *dev)
 {

Modified: lvm2/trunk/lib/display/display.c
==============================================================================
--- lvm2/trunk/lib/display/display.c	(original)
+++ lvm2/trunk/lib/display/display.c	Tue Jun 14 11:23:47 2005
@@ -337,10 +337,9 @@
 		   void *handle)
 {
 	struct lvinfo info;
-	int inkernel, snap_active;
+	int inkernel, snap_active = 0;
 	char uuid[64];
-	struct snapshot *snap = NULL;
-	struct list *slh, *snaplist;
+	struct lv_segment *snap_seg = NULL;
 	float snap_percent;	/* fused, fsize; */
 
 	if (!id_write_format(&lv->lvid.id[1], uuid, sizeof(uuid))) {
@@ -364,27 +363,30 @@
 	if (lv_is_origin(lv)) {
 		log_print("LV snapshot status     source of");
 
-		snaplist = find_snapshots(lv);
-		list_iterate(slh, snaplist) {
-			snap = list_item(slh, struct snapshot_list)->snapshot;
-			snap_active = lv_snapshot_percent(snap->cow,
-							  &snap_percent);
-			if (!snap_active || snap_percent < 0 ||
-			    snap_percent >= 100) snap_active = 0;
+		list_iterate_items_gen(snap_seg, &lv->snapshot_segs,
+				       origin_list) {
+			if (inkernel &&
+			    (snap_active = lv_snapshot_percent(snap_seg->cow,
+							       &snap_percent)))
+				if (snap_percent < 0 || snap_percent >= 100)
+					snap_active = 0;
 			log_print("                       %s%s/%s [%s]",
 				  lv->vg->cmd->dev_dir, lv->vg->name,
-				  snap->cow->name,
+				  snap_seg->cow->name,
 				  (snap_active > 0) ? "active" : "INACTIVE");
 		}
-		snap = NULL;
-	} else if ((snap = find_cow(lv))) {
-		snap_active = lv_snapshot_percent(lv, &snap_percent);
-		if (!snap_active || snap_percent < 0 || snap_percent >= 100)
-			snap_active = 0;
+		snap_seg = NULL;
+	} else if ((snap_seg = find_cow(lv))) {
+		if (inkernel &&
+		    (snap_active = lv_snapshot_percent(snap_seg->cow,
+						       &snap_percent)))
+			if (snap_percent < 0 || snap_percent >= 100)
+				snap_active = 0;
+
 		log_print("LV snapshot status     %s destination for %s%s/%s",
 			  (snap_active > 0) ? "active" : "INACTIVE",
 			  lv->vg->cmd->dev_dir, lv->vg->name,
-			  snap->origin->name);
+			  snap_seg->origin->name);
 	}
 
 	if (inkernel && info.suspended)
@@ -402,15 +404,24 @@
 
 	log_print("LV Size                %s",
 		  display_size(cmd,
-			       snap ? snap->origin->size : lv->size,
+			       snap_seg ? snap_seg->origin->size : lv->size,
 			       SIZE_SHORT));
 
 	log_print("Current LE             %u",
-		  snap ? snap->origin->le_count : lv->le_count);
+		  snap_seg ? snap_seg->origin->le_count : lv->le_count);
+
+	if (snap_seg) {
+		log_print("COW-table size         %s",
+			  display_size(cmd, (uint64_t) lv->size, SIZE_SHORT));
+		log_print("COW-table LE           %u", lv->le_count);
+
+		if (snap_active)
+			log_print("Allocated to snapshot  %.2f%% ", snap_percent);	
 
-/********** FIXME allocation
-    log_print("Allocated LE           %u", lv->allocated_le);
-**********/
+		log_print("Snapshot chunk size    %s",
+			  display_size(cmd, (uint64_t) snap_seg->chunk_size,
+				       SIZE_SHORT));
+	}
 
 	log_print("Segments               %u", list_size(&lv->segments));
 
@@ -418,31 +429,6 @@
 	log_print("Stripe size (KByte)    %u", lv->stripesize / 2);
 ***********/
 
-	if (snap) {
-		if (snap_percent == -1)
-			snap_percent = 100;
-
-		log_print("Snapshot chunk size    %s",
-			  display_size(cmd, (uint64_t) snap->chunk_size,
-				       SIZE_SHORT));
-
-/*
-	size = display_size(lv->size, SIZE_SHORT);
-	sscanf(size, "%f", &fsize);
-	fused = fsize * snap_percent / 100;
-*/
-		log_print("Allocated to snapshot  %.2f%% ",	/* [%.2f/%s]", */
-			  snap_percent);	/*, fused, size); */
-		/* dbg_free(size); */
-	}
-
-/********** FIXME Snapshot
-	size = ???
-	log_print("Allocated to COW-table %s", size);
-	dbg_free(size);
-    }
-******************/
-
 	log_print("Allocation             %s", get_alloc_string(lv->alloc));
 	log_print("Read ahead sectors     %u", lv->read_ahead);
 
@@ -463,26 +449,28 @@
 
 void display_stripe(const struct lv_segment *seg, uint32_t s, const char *pre)
 {
-	switch (seg->area[s].type) {
+	switch (seg_type(seg, s)) {
 	case AREA_PV:
+		/* FIXME Re-check the conditions for 'Missing' */
 		log_print("%sPhysical volume\t%s", pre,
-			  seg->area[s].u.pv.pv ?
-			  dev_name(seg->area[s].u.pv.pv->dev) : "Missing");
+			  seg_pv(seg, s) ?
+			  dev_name(seg_dev(seg, s)) :
+			    "Missing");
 
-		if (seg->area[s].u.pv.pv)
+		if (seg_pv(seg, s))
 			log_print("%sPhysical extents\t%d to %d", pre,
-				  seg->area[s].u.pv.pe,
-				  seg->area[s].u.pv.pe + seg->area_len - 1);
+				  seg_pe(seg, s),
+				  seg_pe(seg, s) + seg->area_len - 1);
 		break;
 	case AREA_LV:
 		log_print("%sLogical volume\t%s", pre,
-			  seg->area[s].u.lv.lv ?
-			  seg->area[s].u.lv.lv->name : "Missing");
+			  seg_lv(seg, s) ?
+			  seg_lv(seg, s)->name : "Missing");
 
-		if (seg->area[s].u.lv.lv)
+		if (seg_lv(seg, s))
 			log_print("%sLogical extents\t%d to %d", pre,
-				  seg->area[s].u.lv.le,
-				  seg->area[s].u.lv.le + seg->area_len - 1);
+				  seg_le(seg, s),
+				  seg_le(seg, s) + seg->area_len - 1);
 
 	}
 }
@@ -550,7 +538,7 @@
 			  vg->status & SHARED ? "yes" : "no");
 	}
 	log_print("MAX LV                %u", vg->max_lv);
-	log_print("Cur LV                %u", vg->lv_count);
+	log_print("Cur LV                %u", vg->lv_count + vg->snapshot_count);
 	log_print("Open LV               %u", lvs_in_vg_opened(vg));
 /****** FIXME Max LV Size
       log_print ( "MAX LV Size           %s",

Modified: lvm2/trunk/lib/filters/filter-persistent.c
==============================================================================
--- lvm2/trunk/lib/filters/filter-persistent.c	(original)
+++ lvm2/trunk/lib/filters/filter-persistent.c	Tue Jun 14 11:23:47 2005
@@ -53,7 +53,9 @@
 {
 	struct pfilter *pf = (struct pfilter *) f->private;
 
+	log_verbose("Wiping cache of LVM-capable devices");
 	hash_wipe(pf->devices);
+
 	/* Trigger complete device scan */
 	dev_cache_scan(1);
 
@@ -202,16 +204,14 @@
 	struct pfilter *pf = (struct pfilter *) f->private;
 	void *l = hash_lookup(pf->devices, dev_name(dev));
 	struct str_list *sl;
-	struct list *ah;
 
 	if (!l) {
 		l = pf->real->passes_filter(pf->real, dev) ?
 		    PF_GOOD_DEVICE : PF_BAD_DEVICE;
 
-		list_iterate(ah, &dev->aliases) {
-			sl = list_item(ah, struct str_list);
+		list_iterate_items(sl, &dev->aliases)
 			hash_insert(pf->devices, sl->str, l);
-		}
+
 	} else if (l == PF_BAD_DEVICE)
 			log_debug("%s: Skipping (cached)", dev_name(dev));
 

Modified: lvm2/trunk/lib/filters/filter-regex.c
==============================================================================
--- lvm2/trunk/lib/filters/filter-regex.c	(original)
+++ lvm2/trunk/lib/filters/filter-regex.c	Tue Jun 14 11:23:47 2005
@@ -158,13 +158,11 @@
 
 static int _accept_p(struct dev_filter *f, struct device *dev)
 {
-	struct list *ah;
 	int m, first = 1, rejected = 0;
 	struct rfilter *rf = (struct rfilter *) f->private;
 	struct str_list *sl;
 
-	list_iterate(ah, &dev->aliases) {
-		sl = list_item(ah, struct str_list);
+	list_iterate_items(sl, &dev->aliases) {
 		m = matcher_run(rf->engine, sl->str);
 
 		if (m >= 0) {

Modified: lvm2/trunk/lib/filters/filter-sysfs.c
==============================================================================
--- lvm2/trunk/lib/filters/filter-sysfs.c	(original)
+++ lvm2/trunk/lib/filters/filter-sysfs.c	Tue Jun 14 11:23:47 2005
@@ -172,7 +172,7 @@
 	unsigned char dtype;
 	struct stat info;
 	char path[PATH_MAX];
-	dev_t dev;
+	dev_t dev = { 0 };
 	int r = 1;
 
         if (!(dr = opendir(dir))) {

Modified: lvm2/trunk/lib/filters/filter.c
==============================================================================
--- lvm2/trunk/lib/filters/filter.c	(original)
+++ lvm2/trunk/lib/filters/filter.c	Tue Jun 14 11:23:47 2005
@@ -70,6 +70,7 @@
 	{"i2o_block", 16},	/* i2o Block Disk */
 	{"iseries/vd", 8},	/* iSeries disks */
 	{"gnbd", 1},		/* Network block device */
+	{"ramdisk", 1},		/* RAM disk */
 	{NULL, 0}
 };
 
@@ -88,7 +89,7 @@
 	}
 
 	/* Check it's accessible */
-	if (!dev_open_flags(dev, O_RDONLY, 0, 0)) {
+	if (!dev_open_flags(dev, O_RDONLY, 0, 1)) {
 		log_debug("%s: Skipping: open failed", name);
 		return 0;
 	}

Modified: lvm2/trunk/lib/format1/disk-rep.c
==============================================================================
--- lvm2/trunk/lib/format1/disk-rep.c	(original)
+++ lvm2/trunk/lib/format1/disk-rep.c	Tue Jun 14 11:23:47 2005
@@ -424,11 +424,11 @@
 
 static void _add_pv_to_list(struct list *head, struct disk_list *data)
 {
-	struct list *pvdh;
 	struct pv_disk *pvd;
+	struct disk_list *diskl;
 
-	list_iterate(pvdh, head) {
-		pvd = &list_item(pvdh, struct disk_list)->pvd;
+	list_iterate_items(diskl, head) {
+		pvd = &diskl->pvd;
 		if (!strncmp(data->pvd.pv_uuid, pvd->pv_uuid,
 			     sizeof(pvd->pv_uuid))) {
 			if (MAJOR(data->dev->dev) != md_major()) {
@@ -439,7 +439,7 @@
 			}
 			log_very_verbose("Duplicate PV %s - using md %s",
 					 pvd->pv_uuid, dev_name(data->dev));
-			list_del(pvdh);
+			list_del(&diskl->list);
 			break;
 		}
 	}
@@ -458,14 +458,14 @@
 	struct dev_iter *iter;
 	struct device *dev;
 	struct disk_list *data = NULL;
-	struct list *vgih;
 	struct lvmcache_vginfo *vginfo;
+	struct lvmcache_info *info;
 
 	/* Fast path if we already saw this VG and cached the list of PVs */
 	if (vg_name && (vginfo = vginfo_from_vgname(vg_name)) &&
 	    vginfo->infos.n) {
-		list_iterate(vgih, &vginfo->infos) {
-			dev = list_item(vgih, struct lvmcache_info)->dev;
+		list_iterate_items(info, &vginfo->infos) {
+			dev = info->dev;
 			if (dev && !(data = read_disk(fmt, dev, mem, vg_name)))
 				break;
 			_add_pv_to_list(head, data);
@@ -482,7 +482,7 @@
 		/* vgcache_del(vg_name); */
 	}
 
-	if (!(iter = dev_iter_create(filter))) {
+	if (!(iter = dev_iter_create(filter, 1))) {
 		log_error("read_pvs_in_vg: dev_iter_create failed");
 		return 0;
 	}
@@ -518,18 +518,16 @@
 static int _write_uuids(struct disk_list *data)
 {
 	struct uuid_list *ul;
-	struct list *uh;
 	uint64_t pos = data->pvd.pv_uuidlist_on_disk.base;
 	uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size;
 
-	list_iterate(uh, &data->uuids) {
+	list_iterate_items(ul, &data->uuids) {
 		if (pos >= end) {
 			log_error("Too many uuids to fit on %s",
 				  dev_name(data->dev));
 			return 0;
 		}
 
-		ul = list_item(uh, struct uuid_list);
 		if (!dev_write(data->dev, pos, NAME_LEN, ul->uuid))
 			fail;
 
@@ -552,7 +550,7 @@
 
 static int _write_lvs(struct disk_list *data)
 {
-	struct list *lvh;
+	struct lvd_list *ll;
 	uint64_t pos, offset;
 
 	pos = data->pvd.lv_on_disk.base;
@@ -563,9 +561,7 @@
 		return 0;
 	}
 
-	list_iterate(lvh, &data->lvds) {
-		struct lvd_list *ll = list_item(lvh, struct lvd_list);
-
+	list_iterate_items(ll, &data->lvds) {
 		offset = sizeof(struct lv_disk) * ll->lvd.lv_number;
 		if (offset + sizeof(struct lv_disk) > data->pvd.lv_on_disk.size) {
 			log_error("lv_number %d too large", ll->lvd.lv_number);
@@ -704,11 +700,9 @@
  */
 int write_disks(const struct format_type *fmt, struct list *pvs)
 {
-	struct list *pvh;
 	struct disk_list *dl;
 
-	list_iterate(pvh, pvs) {
-		dl = list_item(pvh, struct disk_list);
+	list_iterate_items(dl, pvs) {
 		if (!(_write_all_pvd(fmt, dl)))
 			fail;
 

Modified: lvm2/trunk/lib/format1/format1.c
==============================================================================
--- lvm2/trunk/lib/format1/format1.c	(original)
+++ lvm2/trunk/lib/format1/format1.c	Tue Jun 14 11:23:47 2005
@@ -46,9 +46,7 @@
 	 * This means an active VG won't be affected if disks are inserted
 	 * bearing an exported VG with the same name.
 	 */
-	list_iterate(pvh, pvs) {
-		dl = list_item(pvh, struct disk_list);
-
+	list_iterate_items(dl, pvs) {
 		if (first_time) {
 			exported = dl->pvd.pv_status & VG_EXPORTED;
 			first_time = 0;
@@ -148,7 +146,6 @@
 	vg->seqno = 0;
 	list_init(&vg->pvs);
 	list_init(&vg->lvs);
-	list_init(&vg->snapshots);
 	list_init(&vg->tags);
 
 	if (!_check_vgs(pvs, &partial))
@@ -247,13 +244,10 @@
 		       struct list *pvds, const char *dev_dir,
 		       struct dev_filter *filter)
 {
-	struct list *pvh;
 	struct pv_list *pvl;
 	struct disk_list *data;
 
-	list_iterate(pvh, &vg->pvs) {
-		pvl = list_item(pvh, struct pv_list);
-
+	list_iterate_items(pvl, &vg->pvs) {
 		if (!(data = _flatten_pv(fid, mem, vg, pvl->pv, dev_dir))) {
 			stack;
 			return 0;

Modified: lvm2/trunk/lib/format1/import-export.c
==============================================================================
--- lvm2/trunk/lib/format1/import-export.c	(original)
+++ lvm2/trunk/lib/format1/import-export.c	Tue Jun 14 11:23:47 2005
@@ -26,6 +26,7 @@
 #include "filter.h"
 #include "toolcontext.h"
 #include "segtype.h"
+#include "pv_alloc.h"
 
 #include <time.h>
 
@@ -86,9 +87,15 @@
 	pv->pe_size = pvd->pe_size;
 	pv->pe_start = pvd->pe_start;
 	pv->pe_count = pvd->pe_total;
-	pv->pe_alloc_count = pvd->pe_allocated;
+	pv->pe_alloc_count = 0;
 
 	list_init(&pv->tags);
+	list_init(&pv->segments);
+
+	if (!alloc_pv_segment_whole_pv(mem, pv)) {
+		stack;
+		return 0;
+	}
 
 	return 1;
 }
@@ -323,6 +330,8 @@
 	lv->size = lvd->lv_size;
 	lv->le_count = lvd->lv_allocated_le;
 
+	lv->snapshot = NULL;
+	list_init(&lv->snapshot_segs);
 	list_init(&lv->segments);
 	list_init(&lv->tags);
 
@@ -373,14 +382,11 @@
 int export_extents(struct disk_list *dl, uint32_t lv_num,
 		   struct logical_volume *lv, struct physical_volume *pv)
 {
-	struct list *segh;
 	struct pe_disk *ped;
 	struct lv_segment *seg;
 	uint32_t pe, s;
 
-	list_iterate(segh, &lv->segments) {
-		seg = list_item(segh, struct lv_segment);
-
+	list_iterate_items(seg, &lv->segments) {
 		for (s = 0; s < seg->area_count; s++) {
 			if (!(seg->segtype->flags & SEG_FORMAT1_SUPPORT)) {
 				log_error("Segment type %s in LV %s: "
@@ -388,16 +394,16 @@
 					  seg->segtype->name, lv->name);
 				return 0;
 			}
-			if (seg->area[s].type != AREA_PV) {
+			if (seg_type(seg, s) != AREA_PV) {
 				log_error("LV stripe found in LV %s: "
 					  "unsupported by format1", lv->name);
 				return 0;
 			}
-			if (seg->area[s].u.pv.pv != pv)
+			if (seg_pv(seg, s) != pv)
 				continue;	/* not our pv */
 
 			for (pe = 0; pe < (seg->len / seg->area_count); pe++) {
-				ped = &dl->extents[pe + seg->area[s].u.pv.pe];
+				ped = &dl->extents[pe + seg_pe(seg, s)];
 				ped->lv_num = lv_num;
 				ped->le_num = (seg->le / seg->area_count) + pe +
 				    s * (lv->le_count / seg->area_count);
@@ -412,15 +418,11 @@
 	       struct volume_group *vg,
 	       struct list *pvds, struct list *results, int *count)
 {
-	struct list *pvdh;
 	struct disk_list *dl;
 	struct pv_list *pvl;
 
 	*count = 0;
-	list_iterate(pvdh, pvds) {
-
-		dl = list_item(pvdh, struct disk_list);
-
+	list_iterate_items(dl, pvds) {
 		if (!(pvl = pool_zalloc(mem, sizeof(*pvl))) ||
 		    !(pvl->pv = pool_alloc(mem, sizeof(*pvl->pv)))) {
 			stack;
@@ -471,12 +473,9 @@
 	struct disk_list *dl;
 	struct lvd_list *ll;
 	struct lv_disk *lvd;
-	struct list *pvdh, *lvdh;
 
-	list_iterate(pvdh, pvds) {
-		dl = list_item(pvdh, struct disk_list);
-		list_iterate(lvdh, &dl->lvds) {
-			ll = list_item(lvdh, struct lvd_list);
+	list_iterate_items(dl, pvds) {
+		list_iterate_items(ll, &dl->lvds) {
 			lvd = &ll->lvd;
 
 			if (!find_lv(vg, lvd->lv_name) &&
@@ -495,7 +494,6 @@
 	       struct physical_volume *pv, const char *dev_dir)
 {
 	int r = 0;
-	struct list *lvh, *sh;
 	struct lv_list *ll;
 	struct lvd_list *lvdl;
 	size_t len;
@@ -522,8 +520,10 @@
 	}
 	memset(dl->extents, 0, len);
 
-	list_iterate(lvh, &vg->lvs) {
-		ll = list_item(lvh, struct lv_list);
+	list_iterate_items(ll, &vg->lvs) {
+		if (ll->lv->status & SNAPSHOT)
+			continue;
+
 		if (!(lvdl = pool_alloc(dl->mem, sizeof(*lvdl)))) {
 			stack;
 			goto out;
@@ -532,7 +532,6 @@
 		_export_lv(&lvdl->lvd, vg, ll->lv, dev_dir);
 
 		lv_num = lvnum_from_lvid(&ll->lv->lvid);
-
 		lvdl->lvd.lv_number = lv_num;
 
 		if (!hash_insert(lvd_hash, ll->lv->name, &lvdl->lvd)) {
@@ -545,35 +544,18 @@
 			goto out;
 		}
 
-		list_add(&dl->lvds, &lvdl->list);
-		dl->pvd.lv_cur++;
-	}
+		if (lv_is_origin(ll->lv))
+			lvdl->lvd.lv_access |= LV_SNAPSHOT_ORG;
 
-	/*
-	 * Now we need to run through the snapshots, exporting
-	 * the SNAPSHOT_ORG flags etc.
-	 */
-	list_iterate(sh, &vg->snapshots) {
-		struct lv_disk *org, *cow;
-		struct snapshot *s = list_item(sh,
-					       struct snapshot_list)->snapshot;
-
-		if (!(org = hash_lookup(lvd_hash, s->origin->name))) {
-			log_err("Couldn't find snapshot origin '%s'.",
-				s->origin->name);
-			goto out;
+		if (lv_is_cow(ll->lv)) {
+			lvdl->lvd.lv_access |= LV_SNAPSHOT;
+			lvdl->lvd.lv_chunk_size = ll->lv->snapshot->chunk_size;
+			lvdl->lvd.lv_snapshot_minor =
+			    lvnum_from_lvid(&ll->lv->snapshot->origin->lvid);
 		}
 
-		if (!(cow = hash_lookup(lvd_hash, s->cow->name))) {
-			log_err("Couldn't find snapshot cow store '%s'.",
-				s->cow->name);
-			goto out;
-		}
-
-		org->lv_access |= LV_SNAPSHOT_ORG;
-		cow->lv_access |= LV_SNAPSHOT;
-		cow->lv_snapshot_minor = org->lv_number;
-		cow->lv_chunk_size = s->chunk_size;
+		list_add(&dl->lvds, &lvdl->list);
+		dl->pvd.lv_cur++;
 	}
 
 	r = 1;
@@ -590,19 +572,17 @@
 		     struct list *pvds)
 {
 	struct logical_volume *lvs[MAX_LV];
-	struct list *pvdh, *lvdh;
 	struct disk_list *dl;
+	struct lvd_list *ll;
 	struct lv_disk *lvd;
 	int lvnum;
 	struct logical_volume *org, *cow;
 
 	/* build an index of lv numbers */
 	memset(lvs, 0, sizeof(lvs));
-	list_iterate(pvdh, pvds) {
-		dl = list_item(pvdh, struct disk_list);
-
-		list_iterate(lvdh, &dl->lvds) {
-			lvd = &(list_item(lvdh, struct lvd_list)->lvd);
+	list_iterate_items(dl, pvds) {
+		list_iterate_items(ll, &dl->lvds) {
+			lvd = &ll->lvd;
 
 			lvnum = lvd->lv_number;
 
@@ -624,11 +604,9 @@
 	/*
 	 * Now iterate through yet again adding the snapshots.
 	 */
-	list_iterate(pvdh, pvds) {
-		dl = list_item(pvdh, struct disk_list);
-
-		list_iterate(lvdh, &dl->lvds) {
-			lvd = &(list_item(lvdh, struct lvd_list)->lvd);
+	list_iterate_items(dl, pvds) {
+		list_iterate_items(ll, &dl->lvds) {
+			lvd = &ll->lvd;
 
 			if (!(lvd->lv_access & LV_SNAPSHOT))
 				continue;
@@ -646,7 +624,8 @@
 				continue;
 
 			/* insert the snapshot */
-			if (!vg_add_snapshot(org, cow, 1, NULL, org->le_count, 
+			if (!vg_add_snapshot(vg->fid, NULL, org, cow, NULL,
+					     org->le_count, 
 					     lvd->lv_chunk_size)) {
 				log_err("Couldn't add snapshot.");
 				return 0;
@@ -661,10 +640,8 @@
 {
 	struct uuid_list *ul;
 	struct pv_list *pvl;
-	struct list *pvh;
 
-	list_iterate(pvh, &vg->pvs) {
-		pvl = list_item(pvh, struct pv_list);
+	list_iterate_items(pvl, &vg->pvs) {
 		if (!(ul = pool_alloc(dl->mem, sizeof(*ul)))) {
 			stack;
 			return 0;
@@ -684,14 +661,11 @@
  */
 void export_numbers(struct list *pvds, struct volume_group *vg)
 {
-	struct list *pvdh;
 	struct disk_list *dl;
 	int pv_num = 1;
 
-	list_iterate(pvdh, pvds) {
-		dl = list_item(pvdh, struct disk_list);
+	list_iterate_items(dl, pvds)
 		dl->pvd.pv_number = pv_num++;
-	}
 }
 
 /*
@@ -699,26 +673,20 @@
  */
 void export_pv_act(struct list *pvds)
 {
-	struct list *pvdh;
 	struct disk_list *dl;
 	int act = 0;
 
-	list_iterate(pvdh, pvds) {
-		dl = list_item(pvdh, struct disk_list);
+	list_iterate_items(dl, pvds)
 		if (dl->pvd.pv_status & PV_ACTIVE)
 			act++;
-	}
 
-	list_iterate(pvdh, pvds) {
-		dl = list_item(pvdh, struct disk_list);
+	list_iterate_items(dl, pvds)
 		dl->vgd.pv_act = act;
-	}
 }
 
 int export_vg_number(struct format_instance *fid, struct list *pvds,
 		     const char *vg_name, struct dev_filter *filter)
 {
-	struct list *pvdh;
 	struct disk_list *dl;
 	int vg_num;
 
@@ -727,10 +695,8 @@
 		return 0;
 	}
 
-	list_iterate(pvdh, pvds) {
-		dl = list_item(pvdh, struct disk_list);
+	list_iterate_items(dl, pvds)
 		dl->vgd.vg_number = vg_num;
-	}
 
 	return 1;
 }

Modified: lvm2/trunk/lib/format1/import-extents.c
==============================================================================
--- lvm2/trunk/lib/format1/import-extents.c	(original)
+++ lvm2/trunk/lib/format1/import-extents.c	Tue Jun 14 11:23:47 2005
@@ -48,7 +48,6 @@
 					  struct volume_group *vg)
 {
 	struct hash_table *maps = hash_create(32);
-	struct list *llh;
 	struct lv_list *ll;
 	struct lv_map *lvm;
 
@@ -58,8 +57,9 @@
 		return NULL;
 	}
 
-	list_iterate(llh, &vg->lvs) {
-		ll = list_item(llh, struct lv_list);
+	list_iterate_items(ll, &vg->lvs) {
+		if (ll->lv->status & SNAPSHOT)
+			continue;
 
 		if (!(lvm = pool_alloc(mem, sizeof(*lvm)))) {
 			stack;
@@ -89,13 +89,12 @@
 static int _fill_lv_array(struct lv_map **lvs,
 			  struct hash_table *maps, struct disk_list *dl)
 {
-	struct list *lvh;
+	struct lvd_list *ll;
 	struct lv_map *lvm;
 
 	memset(lvs, 0, sizeof(*lvs) * MAX_LV);
-	list_iterate(lvh, &dl->lvds) {
-		struct lvd_list *ll = list_item(lvh, struct lvd_list);
 
+	list_iterate_items(ll, &dl->lvds) {
 		if (!(lvm = hash_lookup(maps, strrchr(ll->lvd.lv_name, '/')
 					+ 1))) {
 			log_err("Physical volume (%s) contains an "
@@ -116,15 +115,13 @@
 static int _fill_maps(struct hash_table *maps, struct volume_group *vg,
 		      struct list *pvds)
 {
-	struct list *pvdh;
 	struct disk_list *dl;
 	struct physical_volume *pv;
 	struct lv_map *lvms[MAX_LV], *lvm;
 	struct pe_disk *e;
 	uint32_t i, lv_num, le;
 
-	list_iterate(pvdh, pvds) {
-		dl = list_item(pvdh, struct disk_list);
+	list_iterate_items(dl, pvds) {
 		pv = find_pv(vg, dl->dev);
 		e = dl->extents;
 
@@ -205,58 +202,59 @@
 
 static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
 {
-	uint32_t le = 0;
+	uint32_t le = 0, len;
 	struct lv_segment *seg;
+	struct segment_type *segtype;
+
+	if (!(segtype = get_segtype_from_string(cmd, "striped"))) {
+		stack;
+		return 0;
+	}
 
 	while (le < lvm->lv->le_count) {
-		seg = alloc_lv_segment(cmd->mem, 1);
+		len = 0;
 
-		seg->lv = lvm->lv;
-		if (!(seg->segtype = get_segtype_from_string(cmd, "striped"))) {
+		do
+			len++;
+		while ((lvm->map[le + len].pv == lvm->map[le].pv) &&
+			 (lvm->map[le].pv &&
+			  lvm->map[le + len].pe == lvm->map[le].pe + len));
+
+		if (!(seg = alloc_lv_segment(cmd->mem, segtype, lvm->lv, le,
+					     len, 0, 0, NULL, 1, len, 0, 0, 0))) {
+			log_error("Failed to allocate linear segment.");
+			return 0;
+		}
+
+		if (!set_lv_segment_area_pv(seg, 0, lvm->map[le].pv,
+					    lvm->map[le].pe)) {
 			stack;
 			return 0;
 		}
 
-		seg->le = le;
-		seg->len = 0;
-		seg->area_len = 0;
-		seg->stripe_size = 0;
-
-		seg->area[0].type = AREA_PV;
-		seg->area[0].u.pv.pv = lvm->map[le].pv;
-		seg->area[0].u.pv.pe = lvm->map[le].pe;
-
-		do {
-			seg->len++;
-			seg->area_len++;
-		} while ((lvm->map[le + seg->len].pv == seg->area[0].u.pv.pv) &&
-			 (seg->area[0].u.pv.pv &&
-			  lvm->map[le + seg->len].pe == seg->area[0].u.pv.pe +
-			  seg->len));
+		list_add(&lvm->lv->segments, &seg->list);
 
 		le += seg->len;
-
-		list_add(&lvm->lv->segments, &seg->list);
 	}
 
 	return 1;
 }
 
-static int _check_stripe(struct lv_map *lvm, struct lv_segment *seg,
-			 uint32_t base_le, uint32_t len)
+static int _check_stripe(struct lv_map *lvm, uint32_t area_count,
+			 uint32_t seg_len, uint32_t base_le, uint32_t len)
 {
-	uint32_t le, st;
-
-	le = base_le + seg->len;
+	uint32_t st;
 
 	/*
 	 * Is the next physical extent in every stripe adjacent to the last?
 	 */
-	for (st = 0; st < seg->area_count; st++)
-		if ((lvm->map[le + st * len].pv != seg->area[st].u.pv.pv) ||
-		    (seg->area[st].u.pv.pv &&
-		     lvm->map[le + st * len].pe !=
-		     seg->area[st].u.pv.pe + seg->len)) return 0;
+	for (st = 0; st < area_count; st++)
+		if ((lvm->map[base_le + st * len + seg_len].pv !=
+		     lvm->map[base_le + st * len].pv) ||
+		    (lvm->map[base_le + st * len].pv &&
+		     lvm->map[base_le + st * len + seg_len].pe !=
+		     lvm->map[base_le + st * len].pe + seg_len))
+			return 0;
 
 	return 1;
 }
@@ -264,7 +262,9 @@
 static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
 {
 	uint32_t st, le = 0, len;
+	uint32_t area_len;
 	struct lv_segment *seg;
+	struct segment_type *segtype;
 
 	/*
 	 * Work out overall striped length
@@ -276,43 +276,46 @@
 	}
 	len = lvm->lv->le_count / lvm->stripes;
 
+	if (!(segtype = get_segtype_from_string(cmd, "striped"))) {
+		stack;
+		return 0;
+	}
+
 	while (le < len) {
-		if (!(seg = alloc_lv_segment(cmd->mem, lvm->stripes))) {
-			stack;
-			return 0;
-		}
+		area_len = 1;
 
-		seg->lv = lvm->lv;
-		if (!(seg->segtype = get_segtype_from_string(cmd, "striped"))) {
-			stack;
+		/* 
+		 * Find how many blocks are contiguous in all stripes
+		 * and so can form part of this segment
+		 */
+		while (_check_stripe(lvm, lvm->stripes,
+				     area_len * lvm->stripes, le, len))
+			area_len++;
+
+		if (!(seg = alloc_lv_segment(cmd->mem, segtype, lvm->lv,
+					     lvm->stripes * le,
+					     lvm->stripes * area_len,
+					     0, lvm->stripe_size, NULL,
+					     lvm->stripes,
+					     area_len, 0, 0, 0))) {
+			log_error("Failed to allocate striped segment.");
 			return 0;
 		}
-		seg->stripe_size = lvm->stripe_size;
-		seg->le = seg->area_count * le;
-		seg->len = 1;
-		seg->area_len = 1;
 
 		/*
 		 * Set up start positions of each stripe in this segment
 		 */
-		for (st = 0; st < seg->area_count; st++) {
-			seg->area[st].u.pv.pv = lvm->map[le + st * len].pv;
-			seg->area[st].u.pv.pe = lvm->map[le + st * len].pe;
-		}
+		for (st = 0; st < seg->area_count; st++)
+			if (!set_lv_segment_area_pv(seg, st,
+						    lvm->map[le + st * len].pv,
+						    lvm->map[le + st * len].pe)) {
+				stack;
+				return 0;
+			}
 
-		/* 
-		 * Find how many blocks are contiguous in all stripes
-		 * and so can form part of this segment
-		 */
-		while (_check_stripe(lvm, seg, le, len)) {
-			seg->len++;
-			seg->area_len++;
-		}
+		list_add(&lvm->lv->segments, &seg->list);
 
 		le += seg->len;
-		seg->len *= seg->area_count;
-
-		list_add(&lvm->lv->segments, &seg->list);
 	}
 
 	return 1;

Modified: lvm2/trunk/lib/format1/vg_number.c
==============================================================================
--- lvm2/trunk/lib/format1/vg_number.c	(original)
+++ lvm2/trunk/lib/format1/vg_number.c	Tue Jun 14 11:23:47 2005
@@ -27,7 +27,6 @@
 int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
 		       const char *candidate_vg, int *result)
 {
-	struct list *pvh;
 	struct list all_pvs;
 	struct disk_list *dl;
 	struct pool *mem = pool_create("lvm1 vg_number", 10 * 1024);
@@ -47,8 +46,7 @@
 
 	memset(numbers, 0, sizeof(numbers));
 
-	list_iterate(pvh, &all_pvs) {
-		dl = list_item(pvh, struct disk_list);
+	list_iterate_items(dl, &all_pvs) {
 		if (!*dl->pvd.vg_name || !strcmp(dl->pvd.vg_name, candidate_vg))
 			continue;
 

Modified: lvm2/trunk/lib/format_pool/disk_rep.c
==============================================================================
--- lvm2/trunk/lib/format_pool/disk_rep.c	(original)
+++ lvm2/trunk/lib/format_pool/disk_rep.c	Tue Jun 14 11:23:47 2005
@@ -57,12 +57,9 @@
 
 static void _add_pl_to_list(struct list *head, struct pool_list *data)
 {
-	struct list *pvdh;
 	struct pool_list *pl;
 
-	list_iterate(pvdh, head) {
-		pl = list_item(pvdh, struct pool_list);
-
+	list_iterate_items(pl, head) {
 		if (id_equal(&data->pv_uuid, &pl->pv_uuid)) {
 			char uuid[ID_LEN + 7];
 
@@ -76,7 +73,7 @@
 			}
 			log_very_verbose("Duplicate PV %s - using md %s",
 					 uuid, dev_name(data->dev));
-			list_del(pvdh);
+			list_del(&pl->list);
 			break;
 		}
 	}
@@ -247,11 +244,9 @@
 			struct lvmcache_vginfo *vginfo, struct list *head,
 			uint32_t *devcount)
 {
-
-	struct list *vgih = NULL;
-	struct device *dev;
-	struct pool_list *pl = NULL;
-	struct pool *tmpmem = NULL;
+	struct lvmcache_info *info;
+	struct pool_list *pl;
+	struct pool *tmpmem;
 
 	uint32_t sp_count = 0;
 	uint32_t *sp_devs = NULL;
@@ -264,16 +259,16 @@
 		return 0;
 	}
 
-	list_iterate(vgih, &vginfo->infos) {
-		dev = list_item(vgih, struct lvmcache_info)->dev;
-		if (dev &&
-		    !(pl = read_pool_disk(fmt, dev, mem, vginfo->vgname)))
+	list_iterate_items(info, &vginfo->infos) {
+		if (info->dev &&
+		    !(pl = read_pool_disk(fmt, info->dev, mem, vginfo->vgname)))
 			    break;
 		/*
 		 * We need to keep track of the total expected number
 		 * of devices per subpool
 		 */
 		if (!sp_count) {
+			/* FIXME pl left uninitialised if !info->dev */
 			sp_count = pl->pd.pl_subpools;
 			if (!(sp_devs =
 			      pool_zalloc(tmpmem,
@@ -298,9 +293,8 @@
 	}
 
 	*devcount = 0;
-	for (i = 0; i < sp_count; i++) {
+	for (i = 0; i < sp_count; i++)
 		*devcount += sp_devs[i];
-	}
 
 	pool_destroy(tmpmem);
 

Modified: lvm2/trunk/lib/format_pool/format_pool.c
==============================================================================
--- lvm2/trunk/lib/format_pool/format_pool.c	(original)
+++ lvm2/trunk/lib/format_pool/format_pool.c	Tue Jun 14 11:23:47 2005
@@ -33,8 +33,6 @@
 static struct user_subpool *_build_usp(struct list *pls, struct pool *mem,
 				       int *sps)
 {
-
-	struct list *plhs;
 	struct pool_list *pl;
 	struct user_subpool *usp = NULL, *cur_sp = NULL;
 	struct user_device *cur_dev = NULL;
@@ -43,9 +41,7 @@
 	 * FIXME: Need to do some checks here - I'm tempted to add a
 	 * user_pool structure and build the entire thing to check against.
 	 */
-	list_iterate(plhs, pls) {
-		pl = list_item(plhs, struct pool_list);
-
+	list_iterate_items(pl, pls) {
 		*sps = pl->pd.pl_subpools;
 		if (!usp && (!(usp = pool_zalloc(mem, sizeof(*usp) * (*sps))))) {
 			log_error("Unable to allocate %d subpool structures",
@@ -72,13 +68,13 @@
 				  "structures", pl->pd.pl_sp_devs);
 			return 0;
 		}
+
 		cur_dev = &cur_sp->devs[pl->pd.pl_sp_devid];
 		cur_dev->sp_id = cur_sp->id;
 		cur_dev->devid = pl->pd.pl_sp_id;
 		cur_dev->blocks = pl->pd.pl_blocks;
 		cur_dev->pv = pl->pv;
 		cur_dev->initialized = 1;
-
 	}
 
 	return usp;
@@ -132,7 +128,6 @@
 	vg->system_id = NULL;
 	list_init(&vg->pvs);
 	list_init(&vg->lvs);
-	list_init(&vg->snapshots);
 	list_init(&vg->tags);
 
 	if (!import_pool_vg(vg, smem, pds)) {

Modified: lvm2/trunk/lib/format_pool/import_export.c
==============================================================================
--- lvm2/trunk/lib/format_pool/import_export.c	(original)
+++ lvm2/trunk/lib/format_pool/import_export.c	Tue Jun 14 11:23:47 2005
@@ -21,6 +21,7 @@
 #include "disk_rep.h"
 #include "sptype_names.h"
 #include "lv_alloc.h"
+#include "pv_alloc.h"
 #include "str_list.h"
 #include "display.h"
 #include "segtype.h"
@@ -29,12 +30,9 @@
 
 int import_pool_vg(struct volume_group *vg, struct pool *mem, struct list *pls)
 {
-	struct list *plhs;
 	struct pool_list *pl;
 
-	list_iterate(plhs, pls) {
-		pl = list_item(plhs, struct pool_list);
-
+	list_iterate_items(pl, pls) {
 		vg->extent_count +=
 		    ((pl->pd.pl_blocks) / POOL_PE_SIZE);
 
@@ -60,7 +58,6 @@
 int import_pool_lvs(struct volume_group *vg, struct pool *mem, struct list *pls)
 {
 	struct pool_list *pl;
-	struct list *plhs;
 	struct lv_list *lvl = pool_zalloc(mem, sizeof(*lvl));
 	struct logical_volume *lv;
 
@@ -82,12 +79,12 @@
 	lv->name = NULL;
 	lv->le_count = 0;
 	lv->read_ahead = 0;
+	lv->snapshot = NULL;
+	list_init(&lv->snapshot_segs);
 	list_init(&lv->segments);
 	list_init(&lv->tags);
 
-	list_iterate(plhs, pls) {
-		pl = list_item(plhs, struct pool_list);
-
+	list_iterate_items(pl, pls) {
 		lv->size += pl->pd.pl_blocks;
 
 		if (lv->name)
@@ -112,6 +109,8 @@
 		} else {
 			lv->minor = -1;
 		}
+		lv->snapshot = NULL;
+		list_init(&lv->snapshot_segs);
 		list_init(&lv->segments);
 		list_init(&lv->tags);
 	}
@@ -129,11 +128,8 @@
 {
 	struct pv_list *pvl;
 	struct pool_list *pl;
-	struct list *plhs;
-
-	list_iterate(plhs, pls) {
-		pl = list_item(plhs, struct pool_list);
 
+	list_iterate_items(pl, pls) {
 		if (!(pvl = pool_zalloc(mem, sizeof(*pvl)))) {
 			log_error("Unable to allocate pv list structure");
 			return 0;
@@ -175,9 +171,15 @@
 	pv->pe_size = POOL_PE_SIZE;
 	pv->pe_start = POOL_PE_START;
 	pv->pe_count = pv->size / POOL_PE_SIZE;
-	pv->pe_alloc_count = pv->pe_count;
+	pv->pe_alloc_count = 0;
 
 	list_init(&pv->tags);
+	list_init(&pv->segments);
+
+	if (!alloc_pv_segment_whole_pv(mem, pv)) {
+		stack;
+		return 0;
+	}
 
 	return 1;
 }
@@ -200,40 +202,44 @@
 			   uint32_t *le_cur)
 {
 	struct lv_segment *seg;
+	struct segment_type *segtype;
 	int j;
+	uint32_t area_len;
 
-	if (!(seg = alloc_lv_segment(mem, usp->num_devs))) {
-		log_error("Unable to allocate striped lv_segment structure");
+	if (usp->striping & (usp->striping - 1)) {
+		log_error("Stripe size must be a power of 2");
 		return 0;
 	}
-	if(usp->striping & (usp->striping - 1)) {
-		log_error("Stripe size must be a power of 2");
+
+	area_len = (usp->devs[0].blocks) / POOL_PE_SIZE;
+
+	if (!(segtype = get_segtype_from_string(lv->vg->cmd,
+						     "striped"))) {
+		stack;
 		return 0;
 	}
-	seg->stripe_size = usp->striping;
-	seg->status |= 0;
-	seg->le += *le_cur;
 
-	/* add the subpool type to the segment tag list */
-	str_list_add(mem, &seg->tags, _cvt_sptype(usp->type));
+	if (!(seg = alloc_lv_segment(mem, segtype, lv, *le_cur, 
+				     area_len * usp->num_devs, 0,
+				     usp->striping, NULL, usp->num_devs,
+				     area_len, 0, 0, 0))) {
+		log_error("Unable to allocate striped lv_segment structure");
+		return 0;
+	}
 
-	for (j = 0; j < usp->num_devs; j++) {
-		if (!(seg->segtype = get_segtype_from_string(lv->vg->cmd,
-							     "striped"))) {
+	for (j = 0; j < usp->num_devs; j++)
+		if (!set_lv_segment_area_pv(seg, j, usp->devs[j].pv, 0)) {
 			stack;
 			return 0;
 		}
 
-		seg->area_len = (usp->devs[j].blocks) / POOL_PE_SIZE;
-		seg->len += seg->area_len;
-		*le_cur += seg->area_len;
-		seg->lv = lv;
-
-		seg->area[j].type = AREA_PV;
-		seg->area[j].u.pv.pv = usp->devs[j].pv;
-		seg->area[j].u.pv.pe = 0;
-	}
+	/* add the subpool type to the segment tag list */
+	str_list_add(mem, &seg->tags, _cvt_sptype(usp->type));
+
 	list_add(&lv->segments, &seg->list);
+
+	*le_cur += seg->len;
+
 	return 1;
 }
 
@@ -242,54 +248,56 @@
 			   uint32_t *le_cur)
 {
 	struct lv_segment *seg;
+	struct segment_type *segtype;
 	int j;
+	uint32_t area_len;
+
+	if (!(segtype = get_segtype_from_string(lv->vg->cmd, "striped"))) {
+		stack;
+		return 0;
+	}
 
 	for (j = 0; j < usp->num_devs; j++) {
-		/* linear segments only have 1 data area */
-		if (!(seg = alloc_lv_segment(mem, 1))) {
+		area_len = (usp->devs[j].blocks) / POOL_PE_SIZE;
+
+		if (!(seg = alloc_lv_segment(mem, segtype, lv, *le_cur,
+					     area_len, 0, usp->striping,
+					     NULL, 1, area_len,
+					     POOL_PE_SIZE, 0, 0))) {
 			log_error("Unable to allocate linear lv_segment "
 				  "structure");
 			return 0;
 		}
-		seg->stripe_size = usp->striping;
-		seg->le += *le_cur;
-		seg->chunk_size = POOL_PE_SIZE;
-		seg->status |= 0;
-		if (!(seg->segtype = get_segtype_from_string(lv->vg->cmd,
-							     "striped"))) {
-			stack;
-			return 0;
-		}
+
 		/* add the subpool type to the segment tag list */
 		str_list_add(mem, &seg->tags, _cvt_sptype(usp->type));
 
-		seg->lv = lv;
+		if (!set_lv_segment_area_pv(seg, 0, usp->devs[j].pv, 0)) {
+			stack;
+			return 0;
+		}
+		list_add(&lv->segments, &seg->list);
 
-		seg->area_len = (usp->devs[j].blocks) / POOL_PE_SIZE;
-		seg->len = seg->area_len;
 		*le_cur += seg->len;
-		seg->area[0].type = AREA_PV;
-		seg->area[0].u.pv.pv = usp->devs[j].pv;
-		seg->area[0].u.pv.pe = 0;
-		list_add(&lv->segments, &seg->list);
 	}
+
 	return 1;
 }
 
 int import_pool_segments(struct list *lvs, struct pool *mem,
 			 struct user_subpool *usp, int subpools)
 {
-
-	struct list *lvhs;
 	struct lv_list *lvl;
 	struct logical_volume *lv;
 	uint32_t le_cur = 0;
 	int i;
 
-	list_iterate(lvhs, lvs) {
-		lvl = list_item(lvhs, struct lv_list);
-
+	list_iterate_items(lvl, lvs) {
 		lv = lvl->lv;
+
+		if (lv->status & SNAPSHOT)
+			continue;
+
 		for (i = 0; i < subpools; i++) {
 			if (usp[i].striping) {
 				if (!_add_stripe_seg(mem, &usp[i], lv, &le_cur)) {
@@ -306,5 +314,4 @@
 	}
 
 	return 1;
-
 }

Modified: lvm2/trunk/lib/format_text/archive.c
==============================================================================
--- lvm2/trunk/lib/format_text/archive.c	(original)
+++ lvm2/trunk/lib/format_text/archive.c	Tue Jun 14 11:23:47 2005
@@ -53,7 +53,7 @@
 	struct list list;
 
 	char *path;
-	int index;
+	uint32_t index;
 };
 
 /*
@@ -91,7 +91,6 @@
 
 static void _insert_file(struct list *head, struct archive_file *b)
 {
-	struct list *bh;
 	struct archive_file *bf = NULL;
 
 	if (list_empty(head)) {
@@ -99,11 +98,9 @@
 		return;
 	}
 
-	/* index increases through list */
-	list_iterate(bh, head) {
-		bf = list_item(bh, struct archive_file);
-
-		if (bf->index > b->index) {
+	/* index reduces through list */
+	list_iterate_items(bf, head) {
+		if (b->index > bf->index) {
 			list_add(&bf->list, &b->list);
 			return;
 		}
@@ -132,7 +129,8 @@
 static struct list *_scan_archive(struct pool *mem,
 				  const char *vgname, const char *dir)
 {
-	int i, count, ix;
+	int i, count;
+	uint32_t ix;
 	char vgname_found[64], *path;
 	struct dirent **dirent;
 	struct archive_file *af;
@@ -147,13 +145,13 @@
 
 	/* Sort fails beyond 5-digit indexes */
 	if ((count = scandir(dir, &dirent, NULL, alphasort)) < 0) {
-		log_err("Couldn't scan archive directory.");
+		log_err("Couldn't scan the archive directory (%s).", dir);
 		return 0;
 	}
 
 	for (i = 0; i < count; i++) {
-		/* ignore dot files */
-		if (dirent[i]->d_name[0] == '.')
+		if (!strcmp(dirent[i]->d_name, ".") ||
+		    !strcmp(dirent[i]->d_name, ".."))
 			continue;
 
 		/* check the name is the correct format */
@@ -199,7 +197,6 @@
 static void _remove_expired(struct list *archives, uint32_t archives_size,
 			    uint32_t retain_days, uint32_t min_archive)
 {
-	struct list *bh;
 	struct archive_file *bf;
 	struct stat sb;
 	time_t retain_time;
@@ -213,9 +210,7 @@
 	retain_time = time(NULL) - (time_t) retain_days *SECS_PER_DAY;
 
 	/* Assume list is ordered oldest first (by index) */
-	list_iterate(bh, archives) {
-		bf = list_item(bh, struct archive_file);
-
+	list_iterate_items(bf, archives) {
 		/* Get the mtime of the file and unlink if too old */
 		if (stat(bf->path, &sb)) {
 			log_sys_error("stat", bf->path);
@@ -240,7 +235,7 @@
 	       uint32_t retain_days, uint32_t min_archive)
 {
 	int i, fd, renamed = 0;
-	unsigned int ix = 0;
+	uint32_t ix = 0;
 	struct archive_file *last;
 	FILE *fp = NULL;
 	char temp_file[PATH_MAX], archive_name[PATH_MAX];
@@ -272,20 +267,20 @@
 	 * Now we want to rename this file to <vg>_index.vg.
 	 */
 	if (!(archives = _scan_archive(vg->cmd->mem, vg->name, dir))) {
-		log_err("Couldn't scan the archive directory (%s).", dir);
+		stack;
 		return 0;
 	}
 
 	if (list_empty(archives))
 		ix = 0;
 	else {
-		last = list_item(archives->p, struct archive_file);
+		last = list_item(list_first(archives), struct archive_file);
 		ix = last->index + 1;
 	}
 
 	for (i = 0; i < 10; i++) {
 		if (lvm_snprintf(archive_name, sizeof(archive_name),
-				 "%s/%s_%05d.vg", dir, vg->name, ix) < 0) {
+				 "%s/%s_%05u.vg", dir, vg->name, ix) < 0) {
 			log_error("Archive file name too long.");
 			return 0;
 		}
@@ -344,22 +339,19 @@
 
 int archive_list(struct cmd_context *cmd, const char *dir, const char *vgname)
 {
-	struct list *archives, *ah;
+	struct list *archives;
 	struct archive_file *af;
 
 	if (!(archives = _scan_archive(cmd->mem, vgname, dir))) {
-		log_err("Couldn't scan the archive directory (%s).", dir);
+		stack;
 		return 0;
 	}
 
 	if (list_empty(archives))
 		log_print("No archives found in %s.", dir);
 
-	list_iterate(ah, archives) {
-		af = list_item(ah, struct archive_file);
-
+	list_iterate_back_items(af, archives)
 		_display_archive(cmd, af);
-	}
 
 	pool_free(cmd->mem, archives);
 

Added: lvm2/trunk/lib/format_text/archiver.c
==============================================================================
--- (empty file)
+++ lvm2/trunk/lib/format_text/archiver.c	Tue Jun 14 11:23:47 2005
@@ -0,0 +1,418 @@
+/*
+ * 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 "lib.h"
+#include "archiver.h"
+#include "format-text.h"
+#include "lvm-file.h"
+#include "lvm-string.h"
+#include "lvmcache.h"
+#include "toolcontext.h"
+
+#include <unistd.h>
+
+struct archive_params {
+	int enabled;
+	char *dir;
+	unsigned int keep_days;
+	unsigned int keep_number;
+};
+
+struct backup_params {
+	int enabled;
+	char *dir;
+};
+
+int archive_init(struct cmd_context *cmd, const char *dir,
+		 unsigned int keep_days, unsigned int keep_min)
+{
+	if (!(cmd->archive_params = pool_zalloc(cmd->libmem,
+						sizeof(*cmd->archive_params)))) {
+		log_error("archive_params alloc failed");
+		return 0;
+	}
+
+	cmd->archive_params->dir = NULL;
+
+	if (!*dir)
+		return 1;
+
+	if (!(cmd->archive_params->dir = dbg_strdup(dir))) {
+		log_error("Couldn't copy archive directory name.");
+		return 0;
+	}
+
+	cmd->archive_params->keep_days = keep_days;
+	cmd->archive_params->keep_number = keep_min;
+	cmd->archive_params->enabled = 1;
+
+	return 1;
+}
+
+void archive_exit(struct cmd_context *cmd)
+{
+	if (cmd->archive_params->dir)
+		dbg_free(cmd->archive_params->dir);
+	memset(cmd->archive_params, 0, sizeof(*cmd->archive_params));
+}
+
+void archive_enable(struct cmd_context *cmd, int flag)
+{
+	cmd->archive_params->enabled = flag;
+}
+
+static char *_build_desc(struct pool *mem, const char *line, int before)
+{
+	size_t len = strlen(line) + 32;
+	char *buffer;
+
+	if (!(buffer = pool_zalloc(mem, strlen(line) + 32))) {
+		stack;
+		return NULL;
+	}
+
+	if (snprintf(buffer, len,
+		     "Created %s executing '%s'",
+		     before ? "*before*" : "*after*", line) < 0) {
+		stack;
+		return NULL;
+	}
+
+	return buffer;
+}
+
+static int __archive(struct volume_group *vg)
+{
+	char *desc;
+
+	if (!(desc = _build_desc(vg->cmd->mem, vg->cmd->cmd_line, 1))) {
+		stack;
+		return 0;
+	}
+
+	return archive_vg(vg, vg->cmd->archive_params->dir, desc,
+			  vg->cmd->archive_params->keep_days,
+			  vg->cmd->archive_params->keep_number);
+}
+
+int archive(struct volume_group *vg)
+{
+	if (!vg->cmd->archive_params->enabled || !vg->cmd->archive_params->dir)
+		return 1;
+
+	if (test_mode()) {
+		log_verbose("Test mode: Skipping archiving of volume group.");
+		return 1;
+	}
+
+	if (!create_dir(vg->cmd->archive_params->dir))
+		return 0;
+
+	/* Trap a read-only file system */
+        if ((access(vg->cmd->archive_params->dir, R_OK | W_OK | X_OK) == -1) &&
+	     (errno == EROFS))
+                return 0;
+
+	log_verbose("Archiving volume group \"%s\" metadata (seqno %u).", vg->name,
+		    vg->seqno);
+	if (!__archive(vg)) {
+		log_error("Volume group \"%s\" metadata archive failed.",
+			  vg->name);
+		return 0;
+	}
+
+	return 1;
+}
+
+int archive_display(struct cmd_context *cmd, const char *vg_name)
+{
+	int r1, r2;
+
+	init_partial(1);
+	r1 = archive_list(cmd, cmd->archive_params->dir, vg_name);
+	r2 = backup_list(cmd, cmd->backup_params->dir, vg_name);
+	init_partial(0);
+
+	return r1 && r2;
+}
+
+int backup_init(struct cmd_context *cmd, const char *dir)
+{
+	if (!(cmd->backup_params = pool_zalloc(cmd->libmem,
+					       sizeof(*cmd->archive_params)))) {
+		log_error("archive_params alloc failed");
+		return 0;
+	}
+
+	cmd->backup_params->dir = NULL;
+	if (!*dir)
+		return 1;
+
+	if (!(cmd->backup_params->dir = dbg_strdup(dir))) {
+		log_error("Couldn't copy backup directory name.");
+		return 0;
+	}
+
+	return 1;
+}
+
+void backup_exit(struct cmd_context *cmd)
+{
+	if (cmd->backup_params->dir)
+		dbg_free(cmd->backup_params->dir);
+	memset(cmd->backup_params, 0, sizeof(*cmd->backup_params));
+}
+
+void backup_enable(struct cmd_context *cmd, int flag)
+{
+	cmd->backup_params->enabled = flag;
+}
+
+static int __backup(struct volume_group *vg)
+{
+	char name[PATH_MAX];
+	char *desc;
+
+	if (!(desc = _build_desc(vg->cmd->mem, vg->cmd->cmd_line, 0))) {
+		stack;
+		return 0;
+	}
+
+	if (lvm_snprintf(name, sizeof(name), "%s/%s",
+			 vg->cmd->backup_params->dir, vg->name) < 0) {
+		log_error("Failed to generate volume group metadata backup "
+			  "filename.");
+		return 0;
+	}
+
+	return backup_to_file(name, desc, vg);
+}
+
+int backup(struct volume_group *vg)
+{
+	if (!vg->cmd->backup_params->enabled || !vg->cmd->backup_params->dir) {
+		log_print("WARNING: This metadata update is NOT backed up");
+		return 1;
+	}
+
+	if (test_mode()) {
+		log_verbose("Test mode: Skipping volume group backup.");
+		return 1;
+	}
+
+	if (!create_dir(vg->cmd->backup_params->dir))
+		return 0;
+
+	/* Trap a read-only file system */
+        if ((access(vg->cmd->backup_params->dir, R_OK | W_OK | X_OK) == -1) &&
+	    (errno == EROFS))
+                return 0;
+
+	if (!__backup(vg)) {
+		log_error("Backup of volume group %s metadata failed.",
+			  vg->name);
+		return 0;
+	}
+
+	return 1;
+}
+
+int backup_remove(struct cmd_context *cmd, const char *vg_name)
+{
+	char path[PATH_MAX];
+
+	if (lvm_snprintf(path, sizeof(path), "%s/%s",
+			 cmd->backup_params->dir, vg_name) < 0) {
+		log_err("Failed to generate backup filename (for removal).");
+		return 0;
+	}
+
+	/*
+	 * Let this fail silently.
+	 */
+	unlink(path);
+	return 1;
+}
+
+struct volume_group *backup_read_vg(struct cmd_context *cmd,
+				    const char *vg_name, const char *file)
+{
+	struct volume_group *vg = NULL;
+	struct format_instance *tf;
+	struct metadata_area *mda;
+	void *context;
+
+	if (!(context = create_text_context(cmd, file,
+					    cmd->cmd_line)) ||
+	    !(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
+							 context))) {
+		log_error("Couldn't create text format object.");
+		return NULL;
+	}
+
+	list_iterate_items(mda, &tf->metadata_areas) {
+		if (!(vg = mda->ops->vg_read(tf, vg_name, mda)))
+			stack;
+		break;
+	}
+
+	tf->fmt->ops->destroy_instance(tf);
+	return vg;
+}
+
+/* ORPHAN and VG locks held before calling this */
+int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg)
+{
+	struct pv_list *pvl;
+	struct physical_volume *pv;
+	struct lvmcache_info *info;
+
+	/*
+	 * FIXME: Check that the PVs referenced in the backup are
+	 * not members of other existing VGs.
+	 */
+
+	/* Attempt to write out using currently active format */
+	if (!(vg->fid = cmd->fmt->ops->create_instance(cmd->fmt, vg->name,
+						       NULL))) {
+		log_error("Failed to allocate format instance");
+		return 0;
+	}
+
+	/* Add any metadata areas on the PVs */
+	list_iterate_items(pvl, &vg->pvs) {
+		pv = pvl->pv;
+		if (!(info = info_from_pvid(pv->dev->pvid))) {
+			log_error("PV %s missing from cache",
+				  dev_name(pv->dev));
+			return 0;
+		}
+		if (cmd->fmt != info->fmt) {
+			log_error("PV %s is a different format (seqno %s)",
+				  dev_name(pv->dev), info->fmt->name);
+			return 0;
+		}
+		if (!vg->fid->fmt->ops->
+		    pv_setup(vg->fid->fmt, UINT64_C(0), 0, 0, 0,
+			     UINT64_C(0), &vg->fid->metadata_areas, pv, vg)) {
+			log_error("Format-specific setup for %s failed",
+				  dev_name(pv->dev));
+			return 0;
+		}
+	}
+
+	if (!vg_write(vg) || !vg_commit(vg)) {
+		stack;
+		return 0;
+	}
+
+	return 1;
+}
+
+/* ORPHAN and VG locks held before calling this */
+int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name,
+			     const char *file)
+{
+	struct volume_group *vg;
+
+	/*
+	 * Read in the volume group from the text file.
+	 */
+	if (!(vg = backup_read_vg(cmd, vg_name, file))) {
+		stack;
+		return 0;
+	}
+
+	return backup_restore_vg(cmd, vg);
+}
+
+int backup_restore(struct cmd_context *cmd, const char *vg_name)
+{
+	char path[PATH_MAX];
+
+	if (lvm_snprintf(path, sizeof(path), "%s/%s",
+			 cmd->backup_params->dir, vg_name) < 0) {
+		log_err("Failed to generate backup filename (for restore).");
+		return 0;
+	}
+
+	return backup_restore_from_file(cmd, vg_name, path);
+}
+
+int backup_to_file(const char *file, const char *desc, struct volume_group *vg)
+{
+	int r = 0;
+	struct format_instance *tf;
+	struct metadata_area *mda;
+	void *context;
+	struct cmd_context *cmd;
+
+	cmd = vg->cmd;
+
+	log_verbose("Creating volume group backup \"%s\" (seqno %u).", file, vg->seqno);
+
+	if (!(context = create_text_context(cmd, file, desc)) ||
+	    !(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
+							 context))) {
+		log_error("Couldn't create backup object.");
+		return 0;
+	}
+
+	/* Write and commit the metadata area */
+	list_iterate_items(mda, &tf->metadata_areas) {
+		if (!(r = mda->ops->vg_write(tf, vg, mda))) {
+			stack;
+			continue;
+		}
+		if (mda->ops->vg_commit &&
+		    !(r = mda->ops->vg_commit(tf, vg, mda))) {
+			stack;
+		}
+	}
+
+	tf->fmt->ops->destroy_instance(tf);
+	return r;
+}
+
+/*
+ * Update backup (and archive) if they're out-of-date or don't exist.
+ */
+void check_current_backup(struct volume_group *vg)
+{
+	char path[PATH_MAX];
+	struct volume_group *vg_backup;
+
+	if ((vg->status & PARTIAL_VG) || (vg->status & EXPORTED_VG))
+		return;
+
+	if (lvm_snprintf(path, sizeof(path), "%s/%s",
+			 vg->cmd->backup_params->dir, vg->name) < 0) {
+		log_debug("Failed to generate backup filename.");
+		return;
+	}
+
+	log_suppress(1);
+	/* Up-to-date backup exists? */
+	if ((vg_backup = backup_read_vg(vg->cmd, vg->name, path)) &&
+	    (vg->seqno == vg_backup->seqno) &&
+	    (id_equal(&vg->id, &vg_backup->id)))
+		return;
+	log_suppress(0);
+
+	if (vg_backup)
+		archive(vg_backup);
+	archive(vg);
+	backup(vg);
+}

Added: lvm2/trunk/lib/format_text/archiver.h
==============================================================================
--- (empty file)
+++ lvm2/trunk/lib/format_text/archiver.h	Tue Jun 14 11:23:47 2005
@@ -0,0 +1,60 @@
+/*
+ * 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
+ */
+
+#ifndef _LVM_TOOL_ARCHIVE_H
+#define _LVM_TOOL_ARCHIVE_H
+
+#include "metadata.h"
+
+/*
+ * There are two operations that come under the general area of
+ * backups.  'Archiving' occurs just before a volume group
+ * configuration is changed.  The user may configure when
+ * archived files are expired.  Typically archives will be stored
+ * in /etc/lvm/archive.
+ *
+ * A 'backup' is a redundant copy of the *current* volume group
+ * configuration.  As such it should be taken just after the
+ * volume group is changed.  Only 1 backup file will exist.
+ * Typically backups will be stored in /etc/lvm/backups.
+ */
+
+int archive_init(struct cmd_context *cmd, const char *dir,
+		 unsigned int keep_days, unsigned int keep_min);
+void archive_exit(struct cmd_context *cmd);
+
+void archive_enable(struct cmd_context *cmd, int flag);
+int archive(struct volume_group *vg);
+int archive_display(struct cmd_context *cmd, const char *vg_name);
+
+int backup_init(struct cmd_context *cmd, const char *dir);
+void backup_exit(struct cmd_context *cmd);
+
+void backup_enable(struct cmd_context *cmd, int flag);
+int backup(struct volume_group *vg);
+int backup_remove(struct cmd_context *cmd, const char *vg_name);
+
+struct volume_group *backup_read_vg(struct cmd_context *cmd,
+				    const char *vg_name, const char *file);
+int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg);
+int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name,
+			     const char *file);
+int backup_restore(struct cmd_context *cmd, const char *vg_name);
+
+int backup_to_file(const char *file, const char *desc, struct volume_group *vg);
+
+void check_current_backup(struct volume_group *vg);
+
+#endif

Modified: lvm2/trunk/lib/format_text/export.c
==============================================================================
--- lvm2/trunk/lib/format_text/export.c	(original)
+++ lvm2/trunk/lib/format_text/export.c	Tue Jun 14 11:23:47 2005
@@ -30,7 +30,7 @@
 struct formatter;
 typedef int (*out_with_comment_fn) (struct formatter * f, const char *comment,
 				    const char *fmt, va_list ap);
-typedef void (*nl_fn) (struct formatter * f);
+typedef int (*nl_fn) (struct formatter * f);
 /*
  * The first half of this file deals with
  * exporting the vg, ie. writing it to a file.
@@ -42,7 +42,7 @@
 	union {
 		FILE *fp;	/* where we're writing to */
 		struct {
-			char *buf;
+			char *start;
 			uint32_t size;
 			uint32_t used;
 		} buf;
@@ -95,22 +95,34 @@
 /*
  * Newline function for prettier layout.
  */
-static void _nl_file(struct formatter *f)
+static int _nl_file(struct formatter *f)
 {
 	fprintf(f->data.fp, "\n");
+
+	return 1;
 }
 
-static void _nl_raw(struct formatter *f)
+static int _nl_raw(struct formatter *f)
 {
-	if (f->data.buf.used >= f->data.buf.size - 1)
-		return;
+	char *newbuf;
+
+	/* If metadata doesn't fit, double the buffer size */
+	if (f->data.buf.used + 2 > f->data.buf.size) {
+		if (!(newbuf = dbg_realloc(f->data.buf.start,
+					   f->data.buf.size * 2))) {
+			stack;
+			return 0;
+		}
+		f->data.buf.start = newbuf;
+		f->data.buf.size *= 2;
+	}
 
-	*f->data.buf.buf = '\n';
-	f->data.buf.buf += 1;
+	*(f->data.buf.start + f->data.buf.used) = '\n';
 	f->data.buf.used += 1;
-	*f->data.buf.buf = '\0';
 
-	return;
+	*(f->data.buf.start + f->data.buf.used) = '\0';
+
+	return 1;
 }
 
 #define COMMENT_TAB 6
@@ -153,17 +165,27 @@
 				 const char *fmt, va_list ap)
 {
 	int n;
+	char *newbuf;
 
-	n = vsnprintf(f->data.buf.buf, f->data.buf.size - f->data.buf.used,
-		      fmt, ap);
-
-	if (n < 0 || (n > f->data.buf.size - f->data.buf.used - 1))
-		return 0;
+      retry:
+	n = vsnprintf(f->data.buf.start + f->data.buf.used,
+		      f->data.buf.size - f->data.buf.used, fmt, ap);
+
+	/* If metadata doesn't fit, double the buffer size */
+	if (n < 0 || (n + f->data.buf.used + 2 > f->data.buf.size)) {
+		if (!(newbuf = dbg_realloc(f->data.buf.start,
+					   f->data.buf.size * 2))) {
+			stack;
+			return 0;
+		}
+		f->data.buf.start = newbuf;
+		f->data.buf.size *= 2;
+		goto retry;
+	}
 
-	f->data.buf.buf += n;
 	f->data.buf.used += n;
 
-	f->nl(f);
+	outnl(f);
 
 	return 1;
 }
@@ -257,10 +279,10 @@
 	outf(f, "# Generated by LVM2: %s", ctime(&t));
 	outf(f, CONTENTS_FIELD " = \"" CONTENTS_VALUE "\"");
 	outf(f, FORMAT_VERSION_FIELD " = %d", FORMAT_VERSION_VALUE);
-	f->nl(f);
+	outnl(f);
 
 	outf(f, "description = \"%s\"", desc);
-	f->nl(f);
+	outnl(f);
 	outf(f, "creation_host = \"%s\"\t# %s %s %s %s %s", _utsname.nodename,
 	     _utsname.sysname, _utsname.nodename, _utsname.release,
 	     _utsname.version, _utsname.machine);
@@ -309,7 +331,7 @@
 
 	/* Default policy is NORMAL; INHERIT is meaningless */
 	if (vg->alloc != ALLOC_NORMAL && vg->alloc != ALLOC_INHERIT) {
-		f->nl(f);
+		outnl(f);
 		outf(f, "allocation_policy = \"%s\"",
 		     get_alloc_string(vg->alloc));
 	}
@@ -330,7 +352,7 @@
 
 static int _print_pvs(struct formatter *f, struct volume_group *vg)
 {
-	struct list *pvh;
+	struct pv_list *pvl;
 	struct physical_volume *pv;
 	char buffer[4096];
 	const char *name;
@@ -338,15 +360,15 @@
 	outf(f, "physical_volumes {");
 	_inc_indent(f);
 
-	list_iterate(pvh, &vg->pvs) {
-		pv = list_item(pvh, struct pv_list)->pv;
+	list_iterate_items(pvl, &vg->pvs) {
+		pv = pvl->pv;
 
 		if (!(name = _get_pv_name(f, pv))) {
 			stack;
 			return 0;
 		}
 
-		f->nl(f);
+		outnl(f);
 		outf(f, "%s {", name);
 		_inc_indent(f);
 
@@ -360,7 +382,7 @@
 			stack;
 			return 0;
 		}
-		f->nl(f);
+		outnl(f);
 
 		if (!print_flags(pv->status, PV_FLAGS, buffer, sizeof(buffer))) {
 			stack;
@@ -407,7 +429,7 @@
 		return 0;
 	}
 
-	f->nl(f);
+	outnl(f);
 	outf(f, "type = \"%s\"", seg->segtype->name);
 
 	if (!list_empty(&seg->tags)) {
@@ -436,27 +458,27 @@
 	const char *name;
 	unsigned int s;
 
-	f->nl(f);
+	outnl(f);
 
 	outf(f, "%ss = [", type);
 	_inc_indent(f);
 
 	for (s = 0; s < seg->area_count; s++) {
-		switch (seg->area[s].type) {
+		switch (seg_type(seg, s)) {
 		case AREA_PV:
-			if (!(name = _get_pv_name(f, seg->area[s].u.pv.pv))) {
+			if (!(name = _get_pv_name(f, seg_pv(seg, s)))) {
 				stack;
 				return 0;
 			}
 
 			outf(f, "\"%s\", %u%s", name,
-			     seg->area[s].u.pv.pe,
+			     seg_pe(seg, s),
 			     (s == seg->area_count - 1) ? "" : ",");
 			break;
 		case AREA_LV:
 			outf(f, "\"%s\", %u%s",
-			     seg->area[s].u.lv.lv->name,
-			     seg->area[s].u.lv.le,
+			     seg_lv(seg, s)->name,
+			     seg_le(seg, s),
 			     (s == seg->area_count - 1) ? "" : ",");
 		}
 	}
@@ -466,105 +488,68 @@
 	return 1;
 }
 
-static int _count_segments(struct logical_volume *lv)
-{
-	int r = 0;
-	struct list *segh;
-
-	list_iterate(segh, &lv->segments)
-	    r++;
-
-	return r;
-}
-
-static int _print_snapshot(struct formatter *f, struct snapshot *snap,
-			   unsigned int count)
+static int _print_lv(struct formatter *f, struct logical_volume *lv)
 {
-	char buffer[256];
-	struct lv_segment seg;
-
-	f->nl(f);
+	struct lv_segment *seg;
+	char buffer[4096];
+	int seg_count;
 
-	outf(f, "snapshot%u {", count);
+	outnl(f);
+	outf(f, "%s {", lv->name);
 	_inc_indent(f);
 
-	if (!id_write_format(&snap->id, buffer, sizeof(buffer))) {
+	/* FIXME: Write full lvid */
+	if (!id_write_format(&lv->lvid.id[1], buffer, sizeof(buffer))) {
 		stack;
 		return 0;
 	}
 
 	outf(f, "id = \"%s\"", buffer);
 
-	seg.status = LVM_READ | LVM_WRITE | VISIBLE_LV;
-	if (!print_flags(seg.status, LV_FLAGS, buffer, sizeof(buffer))) {
+	if (!print_flags(lv->status, LV_FLAGS, buffer, sizeof(buffer))) {
 		stack;
 		return 0;
 	}
-
 	outf(f, "status = %s", buffer);
-	outf(f, "segment_count = 1");
-
-	f->nl(f);
-
-	if (!(seg.segtype = get_segtype_from_string(snap->origin->vg->cmd,
-						    "snapshot"))) {
-		stack;
-		return 0;
-	}
-
-	seg.le = 0;
-	seg.len = snap->le_count;
-	seg.origin = snap->origin;
-	seg.cow = snap->cow;
-	seg.chunk_size = snap->chunk_size;
 
-	/* FIXME Dummy values */
-	list_init(&seg.list);
-	seg.lv = snap->cow;
-	seg.stripe_size = 0;
-	seg.area_count = 0;
-	seg.area_len = 0;
-	seg.extents_copied = 0;
-
-	/* Can't tag a snapshot independently of its origin */
-	list_init(&seg.tags);
-
-	if (!_print_segment(f, snap->origin->vg, 1, &seg)) {
-		stack;
-		return 0;
+	if (!list_empty(&lv->tags)) {
+		if (!print_tags(&lv->tags, buffer, sizeof(buffer))) {
+			stack;
+			return 0;
+		}
+		outf(f, "tags = %s", buffer);
 	}
 
-	_dec_indent(f);
-	outf(f, "}");
-
-	return 1;
-}
-
-static int _print_snapshots(struct formatter *f, struct volume_group *vg)
-{
-	struct list *sh;
-	struct snapshot *s;
-	unsigned int count = 0;
-
-	list_iterate(sh, &vg->snapshots) {
-		s = list_item(sh, struct snapshot_list)->snapshot;
+	if (lv->alloc != ALLOC_INHERIT)
+		outf(f, "allocation_policy = \"%s\"",
+		     get_alloc_string(lv->alloc));
 
-		if (!_print_snapshot(f, s, count++)) {
+	if (lv->read_ahead)
+		outf(f, "read_ahead = %u", lv->read_ahead);
+	if (lv->major >= 0)
+		outf(f, "major = %d", lv->major);
+	if (lv->minor >= 0)
+		outf(f, "minor = %d", lv->minor);
+	outf(f, "segment_count = %u", list_size(&lv->segments));
+	outnl(f);
+
+	seg_count = 1;
+	list_iterate_items(seg, &lv->segments) {
+		if (!_print_segment(f, lv->vg, seg_count++, seg)) {
 			stack;
 			return 0;
 		}
 	}
 
+	_dec_indent(f);
+	outf(f, "}");
+
 	return 1;
 }
 
 static int _print_lvs(struct formatter *f, struct volume_group *vg)
 {
-	struct list *lvh;
-	struct logical_volume *lv;
-	struct lv_segment *seg;
-	char buffer[4096];
-	int seg_count;
+	struct lv_list *lvl;
 
 	/*
 	 * Don't bother with an lv section if there are no lvs.
@@ -575,63 +560,25 @@
 	outf(f, "logical_volumes {");
 	_inc_indent(f);
 
-	list_iterate(lvh, &vg->lvs) {
-		lv = list_item(lvh, struct lv_list)->lv;
-
-		f->nl(f);
-		outf(f, "%s {", lv->name);
-		_inc_indent(f);
-
-		/* FIXME: Write full lvid */
-		if (!id_write_format(&lv->lvid.id[1], buffer, sizeof(buffer))) {
+	/*
+	 * Write visible LVs first
+	 */
+	list_iterate_items(lvl, &vg->lvs) {
+		if (!(lvl->lv->status & VISIBLE_LV))
+			continue;
+		if (!_print_lv(f, lvl->lv)) {
 			stack;
 			return 0;
 		}
+	}
 
-		outf(f, "id = \"%s\"", buffer);
-
-		if (!print_flags(lv->status, LV_FLAGS, buffer, sizeof(buffer))) {
+	list_iterate_items(lvl, &vg->lvs) {
+		if ((lvl->lv->status & VISIBLE_LV))
+			continue;
+		if (!_print_lv(f, lvl->lv)) {
 			stack;
 			return 0;
 		}
-		outf(f, "status = %s", buffer);
-
-		if (!list_empty(&lv->tags)) {
-			if (!print_tags(&lv->tags, buffer, sizeof(buffer))) {
-				stack;
-				return 0;
-			}
-			outf(f, "tags = %s", buffer);
-		}
-
-		if (lv->alloc != ALLOC_INHERIT)
-			outf(f, "allocation_policy = \"%s\"",
-			     get_alloc_string(lv->alloc));
-
-		if (lv->read_ahead)
-			outf(f, "read_ahead = %u", lv->read_ahead);
-		if (lv->major >= 0)
-			outf(f, "major = %d", lv->major);
-		if (lv->minor >= 0)
-			outf(f, "minor = %d", lv->minor);
-		outf(f, "segment_count = %u", _count_segments(lv));
-		f->nl(f);
-
-		seg_count = 1;
-		list_iterate_items(seg, &lv->segments) {
-			if (!_print_segment(f, vg, seg_count++, seg)) {
-				stack;
-				return 0;
-			}
-		}
-
-		_dec_indent(f);
-		outf(f, "}");
-	}
-
-	if (!_print_snapshots(f, vg)) {
-		stack;
-		return 0;
 	}
 
 	_dec_indent(f);
@@ -648,7 +595,7 @@
 static int _build_pv_names(struct formatter *f, struct volume_group *vg)
 {
 	int count = 0;
-	struct list *pvh;
+	struct pv_list *pvl;
 	struct physical_volume *pv;
 	char buffer[32], *name;
 
@@ -662,8 +609,8 @@
 		goto bad;
 	}
 
-	list_iterate(pvh, &vg->pvs) {
-		pv = list_item(pvh, struct pv_list)->pv;
+	list_iterate_items(pvl, &vg->pvs) {
+		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) {
@@ -716,11 +663,11 @@
 	if (!_print_vg(f, vg))
 		fail;
 
-	f->nl(f);
+	outnl(f);
 	if (!_print_pvs(f, vg))
 		fail;
 
-	f->nl(f);
+	outnl(f);
 	if (!_print_lvs(f, vg))
 		fail;
 
@@ -771,11 +718,10 @@
 }
 
 /* Returns amount of buffer used incl. terminating NUL */
-int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf,
-		       uint32_t size)
+int text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf)
 {
 	struct formatter *f;
-	int r;
+	int r = 0;
 
 	_init();
 
@@ -785,8 +731,13 @@
 	}
 
 	memset(f, 0, sizeof(*f));
-	f->data.buf.buf = buf;
-	f->data.buf.size = size;
+
+	f->data.buf.size = 65536;	/* Initial metadata limit */
+	if (!(f->data.buf.start = dbg_malloc(f->data.buf.size))) {
+		log_error("text_export buffer allocation failed");
+		goto out;
+	}
+
 	f->indent = 0;
 	f->header = 0;
 	f->out_with_comment = &_out_with_comment_raw;
@@ -794,11 +745,12 @@
 
 	if (!_text_vg_export(f, vg, desc)) {
 		stack;
-		r = 0;
+		dbg_free(f->data.buf.start);
 		goto out;
 	}
 
 	r = f->data.buf.used + 1;
+	*buf = f->data.buf.start;
 
       out:
 	dbg_free(f);
@@ -806,3 +758,4 @@
 }
 
 #undef outf
+#undef outnl

Modified: lvm2/trunk/lib/format_text/flags.c
==============================================================================
--- lvm2/trunk/lib/format_text/flags.c	(original)
+++ lvm2/trunk/lib/format_text/flags.c	Tue Jun 14 11:23:47 2005
@@ -52,8 +52,11 @@
 	{VISIBLE_LV, "VISIBLE"},
 	{PVMOVE, "PVMOVE"},
 	{LOCKED, "LOCKED"},
+	{MIRROR_IMAGE, NULL},
+	{MIRROR_LOG, NULL},
 	{MIRRORED, NULL},
 	{VIRTUAL, NULL},
+	{SNAPSHOT, NULL},
 	{0, NULL}
 };
 

Modified: lvm2/trunk/lib/format_text/format-text.c
==============================================================================
--- lvm2/trunk/lib/format_text/format-text.c	(original)
+++ lvm2/trunk/lib/format_text/format-text.c	Tue Jun 14 11:23:47 2005
@@ -183,57 +183,74 @@
 
 static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area,
 				       struct mda_header *mdah,
-				       const char *vgname)
+				       const char *vgname,
+				       int precommit)
 {
 	size_t len;
 	char vgnamebuf[NAME_LEN + 2];
 	struct raw_locn *rlocn;
+	struct lvmcache_info *info;
 
-	rlocn = mdah->raw_locns;
+	rlocn = mdah->raw_locns;	/* Slot 0 */
+
+	if (precommit)
+		rlocn++;		/* Slot 1 */
 
+	/* FIXME Loop through rlocns two-at-a-time.  List null-terminated. */
 	/* FIXME Ignore if checksum incorrect!!! */
-	while (rlocn->offset) {
-		if (!dev_read(dev_area->dev, dev_area->start + rlocn->offset,
-			      sizeof(vgnamebuf), vgnamebuf)) {
-			stack;
-			return NULL;
-		}
-		if (!strncmp(vgnamebuf, vgname, len = strlen(vgname)) &&
-		    (isspace(vgnamebuf[len]) || vgnamebuf[len] == '{')) {
-			return rlocn;
-		}
-		rlocn++;
+	if (!dev_read(dev_area->dev, dev_area->start + rlocn->offset,
+		      sizeof(vgnamebuf), vgnamebuf)) {
+		stack;
+		goto error;
 	}
 
+	if (!strncmp(vgnamebuf, vgname, len = strlen(vgname)) &&
+	    (isspace(vgnamebuf[len]) || vgnamebuf[len] == '{')) {
+		return rlocn;
+	}
+
+      error:
+	if ((info = info_from_pvid(dev_area->dev->pvid)))
+		lvmcache_update_vgname(info, ORPHAN);
+
 	return NULL;
 }
 
-static struct raw_locn *_vg_posn(struct format_instance *fid,
-				 struct device_area *dev_area,
-				 const char *vgname)
+/*
+ * Determine offset for uncommitted metadata
+ */
+static uint64_t _next_rlocn_offset(struct raw_locn *rlocn,
+				   struct mda_header *mdah)
 {
+	if (!rlocn)
+		/* Find an empty slot */
+		/* FIXME Assume only one VG per mdah for now */
+		return MDA_HEADER_SIZE;
 
-	struct mda_header *mdah;
-
-	if (!(mdah = _raw_read_mda_header(fid->fmt, dev_area))) {
-		stack;
-		return NULL;
-	}
-
-	return _find_vg_rlocn(dev_area, mdah, vgname);
+	/* Start of free space - round up to next sector; circular */
+	return ((rlocn->offset + rlocn->size +
+		(SECTOR_SIZE - rlocn->size % SECTOR_SIZE) -
+		MDA_HEADER_SIZE) % (mdah->size - MDA_HEADER_SIZE))
+	       + MDA_HEADER_SIZE;
 }
 
 static int _raw_holds_vgname(struct format_instance *fid,
 			     struct device_area *dev_area, const char *vgname)
 {
 	int r = 0;
+	struct mda_header *mdah;
 
 	if (!dev_open(dev_area->dev)) {
 		stack;
 		return 0;
 	}
 
-	if (_vg_posn(fid, dev_area, vgname))
+	if (!(mdah = _raw_read_mda_header(fid->fmt, dev_area))) {
+		stack;
+		return 0;
+	}
+
+	if (_find_vg_rlocn(dev_area, mdah, vgname, 0))
 		r = 1;
 
 	if (!dev_close(dev_area->dev))
@@ -244,7 +261,8 @@
 
 static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
 					      const char *vgname,
-					      struct device_area *area)
+					      struct device_area *area,
+					      int precommit)
 {
 	struct volume_group *vg = NULL;
 	struct raw_locn *rlocn;
@@ -263,8 +281,8 @@
 		goto out;
 	}
 
-	if (!(rlocn = _vg_posn(fid, area, vgname))) {
-		stack;
+	if (!(rlocn = _find_vg_rlocn(area, mdah, vgname, precommit))) {
+		log_debug("VG %s not found on %s", vgname, dev_name(area->dev));
 		goto out;
 	}
 
@@ -287,8 +305,9 @@
 		stack;
 		goto out;
 	}
-	log_debug("Read %s metadata (%u) from %s at %" PRIu64 " size %" PRIu64,
-		  vg->name, vg->seqno, dev_name(area->dev),
+	log_debug("Read %s %smetadata (%u) from %s at %" PRIu64 " size %"
+		  PRIu64, vg->name, precommit ? "pre-commit " : "",
+		  vg->seqno, dev_name(area->dev),
 		  area->start + rlocn->offset, rlocn->size);
 
       out:
@@ -304,7 +323,16 @@
 {
 	struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
 
-	return _vg_read_raw_area(fid, vgname, &mdac->area);
+	return _vg_read_raw_area(fid, vgname, &mdac->area, 0);
+}
+
+static struct volume_group *_vg_read_precommit_raw(struct format_instance *fid,
+						   const char *vgname,
+						   struct metadata_area *mda)
+{
+	struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
+
+	return _vg_read_raw_area(fid, vgname, &mdac->area, 1);
 }
 
 static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
@@ -313,19 +341,15 @@
 	struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
 	struct raw_locn *rlocn;
 	struct mda_header *mdah;
-	struct physical_volume *pv;
-	struct list *pvh;
+	struct pv_list *pvl;
 	int r = 0;
 	uint32_t new_wrap = 0, old_wrap = 0;
-
-	/* FIXME Essential fix! Make dynamic (realloc? pool?) */
-	char buf[65536];
+	char *buf = NULL;
 	int found = 0;
 
 	/* Ignore any mda on a PV outside the VG. vgsplit relies on this */
-	list_iterate(pvh, &vg->pvs) {
-		pv = list_item(pvh, struct pv_list)->pv;
-		if (pv->dev == mdac->area.dev) {
+	list_iterate_items(pvl, &vg->pvs) {
+		if (pvl->pv->dev == mdac->area.dev) {
 			found = 1;
 			break;
 		}
@@ -344,20 +368,10 @@
 		goto out;
 	}
 
-	if ((rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name))) {
-		/* Start of free space - round up to next sector; circular */
-		mdac->rlocn.offset =
-		    ((rlocn->offset + rlocn->size +
-		      (SECTOR_SIZE - rlocn->size % SECTOR_SIZE) -
-		      MDA_HEADER_SIZE) % (mdah->size - MDA_HEADER_SIZE))
-		    + MDA_HEADER_SIZE;
-	} else {
-		/* Find an empty slot */
-		/* FIXME Assume only one VG per mdah for now */
-		mdac->rlocn.offset = MDA_HEADER_SIZE;
-	}
+	rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name, 0);
+	mdac->rlocn.offset = _next_rlocn_offset(rlocn, mdah);
 
-	if (!(mdac->rlocn.size = text_vg_export_raw(vg, "", buf, sizeof(buf)))) {
+	if (!(mdac->rlocn.size = text_vg_export_raw(vg, "", &buf))) {
 		log_error("VG %s metadata writing failed", vg->name);
 		goto out;
 	}
@@ -417,24 +431,26 @@
 	if (!r && !dev_close(mdac->area.dev))
 		stack;
 
+	if (buf)
+		dbg_free(buf);
 	return r;
 }
 
-static int _vg_commit_raw(struct format_instance *fid, struct volume_group *vg,
-			  struct metadata_area *mda)
+static int _vg_commit_raw_rlocn(struct format_instance *fid,
+				struct volume_group *vg,
+				struct metadata_area *mda,
+				int precommit)
 {
 	struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
 	struct mda_header *mdah;
 	struct raw_locn *rlocn;
-	struct physical_volume *pv;
-	struct list *pvh;
+	struct pv_list *pvl;
 	int r = 0;
 	int found = 0;
 
 	/* Ignore any mda on a PV outside the VG. vgsplit relies on this */
-	list_iterate(pvh, &vg->pvs) {
-		pv = list_item(pvh, struct pv_list)->pv;
-		if (pv->dev == mdac->area.dev) {
+	list_iterate_items(pvl, &vg->pvs) {
+		if (pvl->pv->dev == mdac->area.dev) {
 			found = 1;
 			break;
 		}
@@ -448,18 +464,23 @@
 		goto out;
 	}
 
-	if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name))) {
-		rlocn = &mdah->raw_locns[0];
+	if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name, 0))) {
+		mdah->raw_locns[0].offset = 0;
 		mdah->raw_locns[1].offset = 0;
+		mdah->raw_locns[2].offset = 0;
+		rlocn = &mdah->raw_locns[0];
 	}
 
+	if (precommit)
+		rlocn++;
+
 	rlocn->offset = mdac->rlocn.offset;
 	rlocn->size = mdac->rlocn.size;
 	rlocn->checksum = mdac->rlocn.checksum;
 
-	log_debug("Committing %s metadata (%u) to %s header at %" PRIu64,
-		  vg->name, vg->seqno, dev_name(mdac->area.dev),
-		  mdac->area.start);
+	log_debug("%sCommitting %s metadata (%u) to %s header at %" PRIu64,
+		  precommit ? "Pre-" : "", vg->name, vg->seqno,
+		  dev_name(mdac->area.dev), mdac->area.start);
 	if (!_raw_write_mda_header(fid->fmt, mdac->area.dev, mdac->area.start,
 				   mdah)) {
 		log_error("Failed to write metadata area header");
@@ -469,25 +490,36 @@
 	r = 1;
 
       out:
-	if (!dev_close(mdac->area.dev))
+	if (!precommit && !dev_close(mdac->area.dev))
 		stack;
 
 	return r;
 }
 
+static int _vg_commit_raw(struct format_instance *fid, struct volume_group *vg,
+			  struct metadata_area *mda)
+{
+	return _vg_commit_raw_rlocn(fid, vg, mda, 0);
+}
+
+static int _vg_precommit_raw(struct format_instance *fid,
+			     struct volume_group *vg,
+			     struct metadata_area *mda)
+{
+	return _vg_commit_raw_rlocn(fid, vg, mda, 1);
+}
+
 /* Close metadata area devices */
 static int _vg_revert_raw(struct format_instance *fid, struct volume_group *vg,
 			  struct metadata_area *mda)
 {
 	struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
-	struct physical_volume *pv;
-	struct list *pvh;
+	struct pv_list *pvl;
 	int found = 0;
 
 	/* Ignore any mda on a PV outside the VG. vgsplit relies on this */
-	list_iterate(pvh, &vg->pvs) {
-		pv = list_item(pvh, struct pv_list)->pv;
-		if (pv->dev == mdac->area.dev) {
+	list_iterate_items(pvl, &vg->pvs) {
+		if (pvl->pv->dev == mdac->area.dev) {
 			found = 1;
 			break;
 		}
@@ -520,7 +552,7 @@
 		goto out;
 	}
 
-	if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name))) {
+	if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name, 0))) {
 		rlocn = &mdah->raw_locns[0];
 		mdah->raw_locns[1].offset = 0;
 	}
@@ -546,13 +578,13 @@
 
 static struct volume_group *_vg_read_file_name(struct format_instance *fid,
 					       const char *vgname,
-					       const char *path_live)
+					       const char *read_path)
 {
 	struct volume_group *vg;
 	time_t when;
 	char *desc;
 
-	if (!(vg = text_vg_import_file(fid, path_live, &when, &desc))) {
+	if (!(vg = text_vg_import_file(fid, read_path, &when, &desc))) {
 		stack;
 		return NULL;
 	}
@@ -565,10 +597,10 @@
 	if (vgname && strcmp(vgname, vg->name)) {
 		pool_free(fid->fmt->cmd->mem, vg);
 		log_err("'%s' does not contain volume group '%s'.",
-			path_live, vgname);
+			read_path, vgname);
 		return NULL;
 	} else
-		log_debug("Read volume group %s from %s", vg->name, path_live);
+		log_debug("Read volume group %s from %s", vg->name, read_path);
 
 	return vg;
 }
@@ -582,6 +614,15 @@
 	return _vg_read_file_name(fid, vgname, tc->path_live);
 }
 
+static struct volume_group *_vg_read_precommit_file(struct format_instance *fid,
+						    const char *vgname,
+						    struct metadata_area *mda)
+{
+	struct text_context *tc = (struct text_context *) mda->metadata_locn;
+
+	return _vg_read_file_name(fid, vgname, tc->path_edit);
+}
+
 static int _vg_write_file(struct format_instance *fid, struct volume_group *vg,
 			  struct metadata_area *mda)
 {
@@ -737,7 +778,7 @@
 {
 	struct dirent *dirent;
 	struct dir_list *dl;
-	struct list *dlh, *dir_list;
+	struct list *dir_list;
 	char *tmp;
 	DIR *d;
 	struct volume_group *vg;
@@ -747,8 +788,7 @@
 
 	dir_list = &((struct mda_lists *) fmt->private)->dirs;
 
-	list_iterate(dlh, dir_list) {
-		dl = list_item(dlh, struct dir_list);
+	list_iterate_items(dl, dir_list) {
 		if (!(d = opendir(dl->dir))) {
 			log_sys_error("opendir", dl->dir);
 			continue;
@@ -836,7 +876,7 @@
 static int _scan_raw(const struct format_type *fmt)
 {
 	struct raw_list *rl;
-	struct list *rlh, *raw_list;
+	struct list *raw_list;
 	char vgnamebuf[NAME_LEN + 2];
 	struct volume_group *vg;
 	struct format_instance fid;
@@ -846,14 +886,12 @@
 	fid.fmt = fmt;
 	list_init(&fid.metadata_areas);
 
-	list_iterate(rlh, raw_list) {
-		rl = list_item(rlh, struct raw_list);
-
+	list_iterate_items(rl, raw_list) {
 		/* FIXME We're reading mdah twice here... */
 		if (vgname_from_mda(fmt, &rl->dev_area, vgnamebuf,
 				    sizeof(vgnamebuf))) {
 			if ((vg = _vg_read_raw_area(&fid, vgnamebuf,
-						    &rl->dev_area)))
+						    &rl->dev_area, 0)))
 				lvmcache_update_vg(vg);
 		}
 	}
@@ -878,6 +916,7 @@
 	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();
 
 	if (!pvmetadatacopies) {
 		/* Space available for PEs */
@@ -905,10 +944,21 @@
 	/* Place mda straight after label area at start of disk */
 	start1 = LABEL_SCAN_SIZE;
 
+	/* Unless the space available is tiny, round to PAGE_SIZE boundary */
+	if ((!pe_start && !pe_end) ||
+	    ((pe_start > start1) && (pe_start - start1 >= MDA_SIZE_MIN))) {
+		mda_adjustment = start1 % pagesize;
+		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! */
-	if (mda_size1 > disk_size) {
-		log_print("Warning: metadata area fills disk %s",
-			  dev_name(pv->dev));
+	if (start1 + mda_size1 > disk_size) {
+		log_print("Warning: metadata area fills disk leaving no "
+			  "space for data on %s.", dev_name(pv->dev));
 		/* Leave some free space for rounding */
 		/* Avoid empty data area as could cause tools problems */
 		mda_size1 = disk_size - start1 - alignment * 2;
@@ -1001,7 +1051,6 @@
 	struct label *label;
 	struct lvmcache_info *info;
 	struct mda_context *mdac;
-	struct list *mdash;
 	struct metadata_area *mda;
 	char buf[MDA_HEADER_SIZE];
 	struct mda_header *mdah = (struct mda_header *) buf;
@@ -1029,8 +1078,7 @@
 			del_mdas(&info->mdas);
 		else
 			list_init(&info->mdas);
-		list_iterate(mdash, mdas) {
-			mda = list_item(mdash, struct metadata_area);
+		list_iterate_items(mda, mdas) {
 			mdac = mda->metadata_locn;
 			log_debug("Creating metadata area on %s at sector %"
 				  PRIu64 " size %" PRIu64 " sectors",
@@ -1053,8 +1101,7 @@
 	/* Set pe_start to first aligned sector after any metadata 
 	 * areas that begin before pe_start */
 	pv->pe_start = PE_ALIGN;
-	list_iterate(mdash, &info->mdas) {
-		mda = list_item(mdash, struct metadata_area);
+	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)) &&
@@ -1078,8 +1125,7 @@
 		return 0;
 	}
 
-	list_iterate(mdash, &info->mdas) {
-		mda = list_item(mdash, struct metadata_area);
+	list_iterate_items(mda, &info->mdas) {
 		mdac = mda->metadata_locn;
 		memset(&buf, 0, sizeof(buf));
 		mdah->size = mdac->area.size;
@@ -1102,45 +1148,16 @@
 	return 1;
 }
 
-static int _get_pv_from_vg(const struct format_type *fmt, const char *vg_name,
-			   const char *id, struct physical_volume *pv)
-{
-	struct volume_group *vg;
-	struct list *pvh;
-	struct pv_list *pvl;
-	int consistent = 0;
-
-	if (!(vg = vg_read(fmt->cmd, vg_name, &consistent))) {
-		log_error("format_text: _vg_read failed to read VG %s",
-			  vg_name);
-		return 0;
-	}
-
-	if (!consistent)
-		log_error("Warning: Volume group %s is not consistent",
-			  vg_name);
-
-	list_iterate(pvh, &vg->pvs) {
-		pvl = list_item(pvh, struct pv_list);
-		if (id_equal(&pvl->pv->id, (const struct id *) id)) {
-			memcpy(pv, pvl->pv, sizeof(*pv));
-			return 1;
-		}
-	}
-	return 0;
-}
-
 static int _add_raw(struct list *raw_list, struct device_area *dev_area)
 {
 	struct raw_list *rl;
-	struct list *rlh;
 
 	/* Already present? */
-	list_iterate(rlh, raw_list) {
-		rl = list_item(rlh, struct raw_list);
+	list_iterate_items(rl, raw_list) {
 		/* FIXME Check size/overlap consistency too */
 		if (rl->dev_area.dev == dev_area->dev &&
-		    rl->dev_area.start == dev_area->start) return 1;
+		    rl->dev_area.start == dev_area->start)
+			return 1;
 	}
 
 	if (!(rl = dbg_malloc(sizeof(struct raw_list)))) {
@@ -1161,7 +1178,6 @@
 	struct lvmcache_info *info;
 	struct metadata_area *mda, *mda_new;
 	struct mda_context *mdac, *mdac_new;
-	struct list *mdah, *dah;
 	struct data_area_list *da;
 
 	if (!(dev = dev_cache_get(pv_name, fmt->cmd->filter))) {
@@ -1178,19 +1194,19 @@
 
 	/* Have we already cached vgname? */
 	if (info->vginfo && info->vginfo->vgname && *info->vginfo->vgname &&
-	    _get_pv_from_vg(info->fmt, info->vginfo->vgname, info->dev->pvid,
-			    pv)) {
+	    get_pv_from_vg_by_id(info->fmt, info->vginfo->vgname,
+				 info->dev->pvid, pv)) {
 		return 1;
 	}
 
-	/* Perform full scan and try again */
-	if (!memlock()) {
-		lvmcache_label_scan(fmt->cmd, 1);
+	/* Perform full scan (just the first time) and try again */
+	if (!memlock() && !full_scan_done()) {
+		lvmcache_label_scan(fmt->cmd, 2);
 
 		if (info->vginfo && info->vginfo->vgname &&
 		    *info->vginfo->vgname &&
-		    _get_pv_from_vg(info->fmt, info->vginfo->vgname,
-				    info->dev->pvid, pv)) {
+		    get_pv_from_vg_by_id(info->fmt, info->vginfo->vgname,
+					 info->dev->pvid, pv)) {
 			return 1;
 		}
 	}
@@ -1208,17 +1224,15 @@
 			  list_size(&info->das), dev_name(dev));
 		return 0;
 	}
-	list_iterate(dah, &info->das) {
-		da = list_item(dah, struct data_area_list);
+
+	list_iterate_items(da, &info->das)
 		pv->pe_start = da->disk_locn.offset >> SECTOR_SHIFT;
-	}
 
 	if (!mdas)
 		return 1;
 
 	/* Add copy of mdas to supplied list */
-	list_iterate(mdah, &info->mdas) {
-		mda = list_item(mdah, struct metadata_area);
+	list_iterate_items(mda, &info->mdas) {
 		mdac = (struct mda_context *) mda->metadata_locn;
 		if (!(mda_new = pool_alloc(fmt->cmd->mem, sizeof(*mda_new)))) {
 			log_error("metadata_area allocation failed");
@@ -1275,6 +1289,7 @@
 
 static struct metadata_area_ops _metadata_text_file_ops = {
 	vg_read:_vg_read_file,
+	vg_read_precommit:_vg_read_precommit_file,
 	vg_write:_vg_write_file,
 	vg_remove:_vg_remove_file,
 	vg_commit:_vg_commit_file
@@ -1289,8 +1304,10 @@
 
 static struct metadata_area_ops _metadata_text_raw_ops = {
 	vg_read:_vg_read_raw,
+	vg_read_precommit:_vg_read_precommit_raw,
 	vg_write:_vg_write_raw,
 	vg_remove:_vg_remove_raw,
+	vg_precommit:_vg_precommit_raw,
 	vg_commit:_vg_commit_raw,
 	vg_revert:_vg_revert_raw
 };
@@ -1305,7 +1322,7 @@
 {
 	struct metadata_area *mda, *mda_new, *mda2;
 	struct mda_context *mdac, *mdac_new, *mdac2;
-	struct list *pvmdas, *pvmdash, *mdash;
+	struct list *pvmdas;
 	struct lvmcache_info *info;
 	int found;
 	uint64_t pe_end = 0;
@@ -1320,8 +1337,7 @@
 		/* Iterate through all mdas on this PV */
 		if ((info = info_from_pvid(pv->dev->pvid))) {
 			pvmdas = &info->mdas;
-			list_iterate(pvmdash, pvmdas) {
-				mda = list_item(pvmdash, struct metadata_area);
+			list_iterate_items(mda, pvmdas) {
 				mdac =
 				    (struct mda_context *) mda->metadata_locn;
 
@@ -1329,10 +1345,7 @@
 
 				/* Ensure it isn't already on list */
 				found = 0;
-				list_iterate(mdash, mdas) {
-					mda2 =
-					    list_item(mdash,
-						      struct metadata_area);
+				list_iterate_items(mda2, mdas) {
 					if (mda2->ops !=
 					    &_metadata_text_raw_ops) continue;
 					mdac2 =
@@ -1394,9 +1407,10 @@
 	struct mda_context *mdac, *mdac_new;
 	struct dir_list *dl;
 	struct raw_list *rl;
-	struct list *dlh, *dir_list, *rlh, *raw_list, *mdas, *mdash, *infoh;
+	struct list *dir_list, *raw_list, *mdas;
 	char path[PATH_MAX];
 	struct lvmcache_vginfo *vginfo;
+	struct lvmcache_info *info;
 
 	if (!(fid = pool_alloc(fmt->cmd->mem, sizeof(*fid)))) {
 		log_error("Couldn't allocate format instance object.");
@@ -1418,8 +1432,7 @@
 	} else {
 		dir_list = &((struct mda_lists *) fmt->private)->dirs;
 
-		list_iterate(dlh, dir_list) {
-			dl = list_item(dlh, struct dir_list);
+		list_iterate_items(dl, dir_list) {
 			if (lvm_snprintf(path, PATH_MAX, "%s/%s",
 					 dl->dir, vgname) < 0) {
 				log_error("Name too long %s/%s", dl->dir,
@@ -1439,9 +1452,7 @@
 
 		raw_list = &((struct mda_lists *) fmt->private)->raws;
 
-		list_iterate(rlh, raw_list) {
-			rl = list_item(rlh, struct raw_list);
-
+		list_iterate_items(rl, raw_list) {
 			/* FIXME Cache this; rescan below if some missing */
 			if (!_raw_holds_vgname(fid, &rl->dev_area, vgname))
 				continue;
@@ -1469,10 +1480,9 @@
 			stack;
 			goto out;
 		}
-		list_iterate(infoh, &vginfo->infos) {
-			mdas = &(list_item(infoh, struct lvmcache_info)->mdas);
-			list_iterate(mdash, mdas) {
-				mda = list_item(mdash, struct metadata_area);
+		list_iterate_items(info, &vginfo->infos) {
+			mdas = &info->mdas;
+			list_iterate_items(mda, mdas) {
 				mdac =
 				    (struct mda_context *) mda->metadata_locn;
 
@@ -1646,7 +1656,8 @@
 	fmt->ops = &_text_handler;
 	fmt->name = FMT_TEXT_NAME;
 	fmt->alias = FMT_TEXT_ALIAS;
-	fmt->features = FMT_SEGMENTS | FMT_MDAS | FMT_TAGS | FMT_UNLIMITED_VOLS;
+	fmt->features = FMT_SEGMENTS | FMT_MDAS | FMT_TAGS | FMT_PRECOMMIT |
+			FMT_UNLIMITED_VOLS;
 
 	if (!(mda_lists = dbg_malloc(sizeof(struct mda_lists)))) {
 		log_error("Failed to allocate dir_list");

Modified: lvm2/trunk/lib/format_text/import-export.h
==============================================================================
--- lvm2/trunk/lib/format_text/import-export.h	(original)
+++ lvm2/trunk/lib/format_text/import-export.h	Tue Jun 14 11:23:47 2005
@@ -59,8 +59,7 @@
 int read_tags(struct pool *mem, struct list *tags, struct config_value *cv);
 
 int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp);
-int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf,
-		       uint32_t size);
+int text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf);
 struct volume_group *text_vg_import_file(struct format_instance *fid,
 					 const char *file,
 					 time_t *when, char **desc);

Modified: lvm2/trunk/lib/format_text/import_vsn1.c
==============================================================================
--- lvm2/trunk/lib/format_text/import_vsn1.c	(original)
+++ lvm2/trunk/lib/format_text/import_vsn1.c	Tue Jun 14 11:23:47 2005
@@ -22,6 +22,7 @@
 #include "toolcontext.h"
 #include "lvmcache.h"
 #include "lv_alloc.h"
+#include "pv_alloc.h"
 #include "segtype.h"
 #include "text_import.h"
 
@@ -31,7 +32,7 @@
 			   struct hash_table * pv_hash);
 
 #define _read_int32(root, path, result) \
-	get_config_uint32(root, path, result)
+	get_config_uint32(root, path, (uint32_t *) result)
 
 #define _read_uint32(root, path, result) \
 	get_config_uint32(root, path, result)
@@ -190,6 +191,7 @@
 	}
 
 	list_init(&pv->tags);
+	list_init(&pv->segments);
 
 	/* Optional tags */
 	if ((cn = find_config_node(pvn, "tags")) &&
@@ -208,6 +210,11 @@
 	pv->pe_alloc_count = 0;
 	pv->fmt = fid->fmt;
 
+	if (!alloc_pv_segment_whole_pv(mem, pv)) {
+		stack;
+		return 0;
+	}
+
 	vg->pv_count++;
 	list_add(&vg->pvs, &pvl->list);
 
@@ -216,12 +223,9 @@
 
 static void _insert_segment(struct logical_volume *lv, struct lv_segment *seg)
 {
-	struct list *segh;
 	struct lv_segment *comp;
 
-	list_iterate(segh, &lv->segments) {
-		comp = list_item(segh, struct lv_segment);
-
+	list_iterate_items(comp, &lv->segments) {
 		if (comp->le > seg->le) {
 			list_add(&comp->list, &seg->list);
 			return;
@@ -283,19 +287,13 @@
 		return 0;
 	}
 
-	if (!(seg = alloc_lv_segment(mem, area_count))) {
+	if (!(seg = alloc_lv_segment(mem, segtype, lv, start_extent,
+				     extent_count, 0, 0, NULL, area_count,
+				     extent_count, 0, 0, 0))) {
 		log_error("Segment allocation failed");
 		return 0;
 	}
 
-	seg->lv = lv;
-	seg->le = start_extent;
-	seg->len = extent_count;
-	seg->area_len = extent_count;
-	seg->status = 0u;
-	seg->segtype = segtype;
-	seg->extents_copied = 0u;
-
 	if (seg->segtype->ops->text_import &&
 	    !seg->segtype->ops->text_import(seg, sn, pv_hash)) {
 		stack;
@@ -315,17 +313,18 @@
 	 */
 	_insert_segment(lv, seg);
 
-	if (seg->segtype->flags & SEG_AREAS_MIRRORED)
+	if (seg_is_mirrored(seg))
 		lv->status |= MIRRORED;
 
-	if (seg->segtype->flags & SEG_VIRTUAL)
+	if (seg_is_virtual(seg))
 		lv->status |= VIRTUAL;
 
 	return 1;
 }
 
 int text_import_areas(struct lv_segment *seg, const struct config_node *sn,
-		      const struct config_node *cn, struct hash_table *pv_hash)
+		      const struct config_node *cn, struct hash_table *pv_hash,
+		      uint32_t flags)
 {
 	unsigned int s;
 	struct config_value *cv;
@@ -361,19 +360,17 @@
 
 		/* FIXME Cope if LV not yet read in */
 		if ((pv = hash_lookup(pv_hash, cv->v.str))) {
-			seg->area[s].type = AREA_PV;
-			seg->area[s].u.pv.pv = pv;
-			seg->area[s].u.pv.pe = cv->next->v.i;
+			if (!set_lv_segment_area_pv(seg, s, pv, cv->next->v.i)) {
+				stack;
+				return 0;
+			}
 			/*
 			 * Adjust extent counts in the pv and vg.
 			 */
-			pv->pe_alloc_count += seg->area_len;
 			seg->lv->vg->free_count -= seg->area_len;
-
 		} else if ((lv1 = find_lv(seg->lv->vg, cv->v.str))) {
-			seg->area[s].type = AREA_LV;
-			seg->area[s].u.lv.lv = lv1;
-			seg->area[s].u.lv.le = cv->next->v.i;
+			set_lv_segment_area_lv(seg, s, lv1, cv->next->v.i,
+					       flags);
 		} else {
 			log_error("Couldn't find volume '%s' "
 				  "for segment '%s'.",
@@ -437,7 +434,7 @@
 	/*
 	 * Check there are no gaps or overlaps in the lv.
 	 */
-	if (!lv_check_segments(lv)) {
+	if (!check_lv_segments(lv)) {
 		stack;
 		return 0;
 	}
@@ -508,6 +505,8 @@
 	if (!_read_int32(lvn, "read_ahead", &lv->read_ahead))
 		lv->read_ahead = 0;
 
+	lv->snapshot = NULL;
+	list_init(&lv->snapshot_segs);
 	list_init(&lv->segments);
 	list_init(&lv->tags);
 
@@ -561,24 +560,29 @@
 
 	lv->size = (uint64_t) lv->le_count * (uint64_t) vg->extent_size;
 
-	/* Skip this for now for snapshots */
-	if (!(lv->status & SNAPSHOT)) {
-		lv->minor = -1;
-		if ((lv->status & FIXED_MINOR) &&
-		    !_read_int32(lvn, "minor", &lv->minor)) {
-			log_error("Couldn't read minor number for logical "
-				  "volume %s.", lv->name);
-			return 0;
-		}
-		lv->major = -1;
-		if ((lv->status & FIXED_MINOR) &&
-		    !_read_int32(lvn, "major", &lv->major)) {
-			log_error("Couldn't read major number for logical "
-				  "volume %s.", lv->name);
-		}
-	} else {
+	/*
+	 * FIXME We now have 2 LVs for each snapshot. The real one was
+	 * created by vg_add_snapshot from the segment text_import.
+	 */
+	if (lv->status & SNAPSHOT) {
 		vg->lv_count--;
 		list_del(&lvl->list);
+		return 1;
+	}
+
+	lv->minor = -1;
+	if ((lv->status & FIXED_MINOR) &&
+	    !_read_int32(lvn, "minor", &lv->minor)) {
+		log_error("Couldn't read minor number for logical "
+			  "volume %s.", lv->name);
+		return 0;
+	}
+
+	lv->major = -1;
+	if ((lv->status & FIXED_MINOR) &&
+	    !_read_int32(lvn, "major", &lv->major)) {
+		log_error("Couldn't read major number for logical "
+			  "volume %s.", lv->name);
 	}
 
 	return 1;
@@ -736,7 +740,6 @@
 	}
 
 	list_init(&vg->lvs);
-	list_init(&vg->snapshots);
 	list_init(&vg->tags);
 
 	/* Optional tags */

Modified: lvm2/trunk/lib/format_text/layout.h
==============================================================================
--- lvm2/trunk/lib/format_text/layout.h	(original)
+++ lvm2/trunk/lib/format_text/layout.h	Tue Jun 14 11:23:47 2005
@@ -81,5 +81,6 @@
 #define FMTT_VERSION 1
 #define MDA_HEADER_SIZE 512
 #define LVM2_LABEL "LVM2 001"
+#define MDA_SIZE_MIN (8 * getpagesize())
 
 #endif

Modified: lvm2/trunk/lib/format_text/text_export.h
==============================================================================
--- lvm2/trunk/lib/format_text/text_export.h	(original)
+++ lvm2/trunk/lib/format_text/text_export.h	Tue Jun 14 11:23:47 2005
@@ -17,6 +17,7 @@
 #define _LVM_TEXT_EXPORT_H
 
 #define outf(args...) do {if (!out_text(args)) {stack; return 0;}} while (0)
+#define outnl(f) do {if (!f->nl(f)) {stack; return 0;}} while (0)
 
 struct formatter;
 struct lv_segment;

Modified: lvm2/trunk/lib/format_text/text_import.h
==============================================================================
--- lvm2/trunk/lib/format_text/text_import.h	(original)
+++ lvm2/trunk/lib/format_text/text_import.h	Tue Jun 14 11:23:47 2005
@@ -20,6 +20,7 @@
 struct config_node;
 
 int text_import_areas(struct lv_segment *seg, const struct config_node *sn,
-		      const struct config_node *cn, struct hash_table *pv_hash);
+		      const struct config_node *cn, struct hash_table *pv_hash,
+		      uint32_t flags);
 
 #endif

Modified: lvm2/trunk/lib/format_text/text_label.c
==============================================================================
--- lvm2/trunk/lib/format_text/text_label.c	(original)
+++ lvm2/trunk/lib/format_text/text_label.c	Tue Jun 14 11:23:47 2005
@@ -39,7 +39,6 @@
 	struct pv_header *pvhdr;
 	struct lvmcache_info *info;
 	struct disk_locn *pvh_dlocn_xl;
-	struct list *mdash, *dash;
 	struct metadata_area *mda;
 	struct mda_context *mdac;
 	struct data_area_list *da;
@@ -57,9 +56,7 @@
 	pvh_dlocn_xl = &pvhdr->disk_areas_xl[0];
 
 	/* List of data areas (holding PEs) */
-	list_iterate(dash, &info->das) {
-		da = list_item(dash, struct data_area_list);
-
+	list_iterate_items(da, &info->das) {
 		pvh_dlocn_xl->offset = xlate64(da->disk_locn.offset);
 		pvh_dlocn_xl->size = xlate64(da->disk_locn.size);
 		pvh_dlocn_xl++;
@@ -71,8 +68,7 @@
 	pvh_dlocn_xl++;
 
 	/* List of metadata area header locations */
-	list_iterate(mdash, &info->mdas) {
-		mda = list_item(mdash, struct metadata_area);
+	list_iterate_items(mda, &info->mdas) {
 		mdac = (struct mda_context *) mda->metadata_locn;
 
 		if (mdac->area.dev != info->dev)
@@ -198,7 +194,6 @@
 	struct lvmcache_info *info;
 	struct disk_locn *dlocn_xl;
 	uint64_t offset;
-	struct list *mdah;
 	struct metadata_area *mda;
 	char vgnamebuf[NAME_LEN + 2];
 	struct mda_context *mdac;
@@ -235,8 +230,7 @@
 		dlocn_xl++;
 	}
 
-	list_iterate(mdah, &info->mdas) {
-		mda = list_item(mdah, struct metadata_area);
+	list_iterate_items(mda, &info->mdas) {
 		mdac = (struct mda_context *) mda->metadata_locn;
 		if (vgname_from_mda(info->fmt, &mdac->area, vgnamebuf,
 				    sizeof(vgnamebuf))) {

Modified: lvm2/trunk/lib/label/label.c
==============================================================================
--- lvm2/trunk/lib/label/label.c	(original)
+++ lvm2/trunk/lib/label/label.c	Tue Jun 14 11:23:47 2005
@@ -98,14 +98,11 @@
 
 struct labeller *label_get_handler(const char *name)
 {
-	struct list *lih;
 	struct labeller_i *li;
 
-	list_iterate(lih, &_labellers) {
-		li = list_item(lih, struct labeller_i);
+	list_iterate_items(li, &_labellers)
 		if (!strcmp(li->name, name))
 			return li->l;
-	}
 
 	return NULL;
 }
@@ -113,16 +110,20 @@
 static struct labeller *_find_labeller(struct device *dev, char *buf,
 				       uint64_t *label_sector)
 {
-	struct list *lih;
 	struct labeller_i *li;
 	struct labeller *r = NULL;
 	struct label_header *lh;
+	struct lvmcache_info *info;
 	uint64_t sector;
 	int found = 0;
 	char readbuf[LABEL_SCAN_SIZE];
 
 	if (!dev_open(dev)) {
 		stack;
+
+		if ((info = info_from_pvid(dev->pvid)))
+			lvmcache_update_vgname(info, ORPHAN);
+
 		return NULL;
 	}
 
@@ -161,8 +162,7 @@
 				continue;
 		}
 
-		list_iterate(lih, &_labellers) {
-			li = list_item(lih, struct labeller_i);
+		list_iterate_items(li, &_labellers) {
 			if (li->l->ops->can_handle(li->l, (char *) lh, sector)) {
 				log_very_verbose("%s: %s label detected",
 						 dev_name(dev), li->name);
@@ -182,10 +182,13 @@
 		}
 	}
 
-	if (!found)
+      out:
+	if (!found) {
+		if ((info = info_from_pvid(dev->pvid)))
+			lvmcache_update_vgname(info, ORPHAN);
 		log_very_verbose("%s: No label detected", dev_name(dev));
+	}
 
-      out:
 	if (!dev_close(dev))
 		stack;
 
@@ -200,7 +203,6 @@
 	int r = 1;
 	uint64_t sector;
 	int wipe;
-	struct list *lih;
 	struct labeller_i *li;
 	struct label_header *lh;
 
@@ -236,8 +238,7 @@
 			if (xlate64(lh->sector_xl) == sector)
 				wipe = 1;
 		} else {
-			list_iterate(lih, &_labellers) {
-				li = list_item(lih, struct labeller_i);
+			list_iterate_items(li, &_labellers) {
 				if (li->l->ops->can_handle(li->l, (char *) lh,
 							   sector)) {
 					wipe = 1;
@@ -279,7 +280,7 @@
 		return 0;
 	}
 
-	if ((r = l->ops->read(l, dev, buf, result)) && result && *result)
+	if ((r = (l->ops->read)(l, dev, buf, result)) && result && *result)
 		(*result)->sector = sector;
 
 	return r;
@@ -309,7 +310,7 @@
 	lh->sector_xl = xlate64(label->sector);
 	lh->offset_xl = xlate32(sizeof(*lh));
 
-	if (!label->labeller->ops->write(label, buf)) {
+	if (!(label->labeller->ops->write)(label, buf)) {
 		stack;
 		return 0;
 	}

Modified: lvm2/trunk/lib/locking/cluster_locking.c
==============================================================================
--- lvm2/trunk/lib/locking/cluster_locking.c	(original)
+++ lvm2/trunk/lib/locking/cluster_locking.c	Tue Jun 14 11:23:47 2005
@@ -446,7 +446,7 @@
 	locking->lock_resource = _lock_resource;
 	locking->fin_locking = _locking_end;
 	locking->reset_locking = _reset_locking;
-	locking->flags = LCK_PRE_MEMLOCK;
+	locking->flags = LCK_PRE_MEMLOCK | LCK_CLUSTERED;
 
 	_clvmd_sock = _open_local_sock();
 	if (_clvmd_sock == -1)
@@ -463,6 +463,7 @@
 
 	/* Ask LVM to lock memory before calling us */
 	*flags |= LCK_PRE_MEMLOCK;
+	*flags |= LCK_CLUSTERED;
 
 	return 1;
 }

Modified: lvm2/trunk/lib/locking/file_locking.c
==============================================================================
--- lvm2/trunk/lib/locking/file_locking.c	(original)
+++ lvm2/trunk/lib/locking/file_locking.c	Tue Jun 14 11:23:47 2005
@@ -41,7 +41,7 @@
 
 static sig_t _oldhandler;
 static sigset_t _fullsigset, _intsigset;
-static int _handler_installed;
+static volatile sig_atomic_t _handler_installed;
 
 static int _release_lock(const char *file, int unlock)
 {
@@ -95,38 +95,40 @@
 static void _remove_ctrl_c_handler()
 {
 	siginterrupt(SIGINT, 0);
-	if (!_handler_installed || _oldhandler == SIG_ERR)
+	if (!_handler_installed)
 		return;
 
+	_handler_installed = 0;
+
 	sigprocmask(SIG_SETMASK, &_fullsigset, NULL);
 	if (signal(SIGINT, _oldhandler) == SIG_ERR)
 		log_sys_error("signal", "_remove_ctrl_c_handler");
-
-	_handler_installed = 0;
 }
 
 static void _trap_ctrl_c(int sig)
 {
 	_remove_ctrl_c_handler();
 	log_error("CTRL-c detected: giving up waiting for lock");
-	return;
 }
 
 static void _install_ctrl_c_handler()
 {
-	if ((_oldhandler = signal(SIGINT, _trap_ctrl_c)) == SIG_ERR)
+	_handler_installed = 1;
+
+	if ((_oldhandler = signal(SIGINT, _trap_ctrl_c)) == SIG_ERR) {
+		_handler_installed = 0;
 		return;
+	}
 
 	sigprocmask(SIG_SETMASK, &_intsigset, NULL);
 	siginterrupt(SIGINT, 1);
-
-	_handler_installed = 1;
 }
 
 static int _lock_file(const char *file, int flags)
 {
 	int operation;
 	int r = 1;
+	int old_errno;
 
 	struct lock_list *ll;
 	struct stat buf1, buf2;
@@ -176,10 +178,12 @@
 			_install_ctrl_c_handler();
 
 		r = flock(ll->lf, operation);
+		old_errno = errno;
 		if (!(flags & LCK_NONBLOCK))
 			_remove_ctrl_c_handler();
 
 		if (r) {
+			errno = old_errno;
 			log_sys_error("flock", ll->res);
 			goto err;
 		}

Modified: lvm2/trunk/lib/locking/locking.c
==============================================================================
--- lvm2/trunk/lib/locking/locking.c	(original)
+++ lvm2/trunk/lib/locking/locking.c	Tue Jun 14 11:23:47 2005
@@ -124,6 +124,8 @@
  */
 int init_locking(int type, struct config_tree *cft)
 {
+	init_lockingfailed(0);
+
 	switch (type) {
 	case 0:
 		init_no_locking(&_locking, cft);
@@ -165,6 +167,7 @@
 	log_verbose("Locking disabled - only read operations permitted.");
 
 	init_no_locking(&_locking, cft);
+	init_lockingfailed(1);
 
 	return 1;
 }
@@ -262,13 +265,10 @@
 /* Unlock list of LVs */
 int resume_lvs(struct cmd_context *cmd, struct list *lvs)
 {
-	struct list *lvh;
-	struct logical_volume *lv;
+	struct lv_list *lvl;
 
-	list_iterate(lvh, lvs) {
-		lv = list_item(lvh, struct lv_list)->lv;
-		resume_lv(cmd, lv->lvid.s);
-	}
+	list_iterate_items(lvl, lvs)
+		resume_lv(cmd, lvl->lv->lvid.s);
 
 	return 1;
 }
@@ -277,15 +277,14 @@
 int suspend_lvs(struct cmd_context *cmd, struct list *lvs)
 {
 	struct list *lvh;
-	struct logical_volume *lv;
+	struct lv_list *lvl;
 
-	list_iterate(lvh, lvs) {
-		lv = list_item(lvh, struct lv_list)->lv;
-		if (!suspend_lv(cmd, lv->lvid.s)) {
-			log_error("Failed to suspend %s", lv->name);
-			list_uniterate(lvh, lvs, lvh) {
-				lv = list_item(lvh, struct lv_list)->lv;
-				resume_lv(cmd, lv->lvid.s);
+	list_iterate_items(lvl, lvs) {
+		if (!suspend_lv(cmd, lvl->lv->lvid.s)) {
+			log_error("Failed to suspend %s", lvl->lv->name);
+			list_uniterate(lvh, lvs, &lvl->list) {
+				lvl = list_item(lvh, struct lv_list);
+				resume_lv(cmd, lvl->lv->lvid.s);
 			}
 
 			return 0;
@@ -299,15 +298,14 @@
 int activate_lvs_excl(struct cmd_context *cmd, struct list *lvs)
 {
 	struct list *lvh;
-	struct logical_volume *lv;
+	struct lv_list *lvl;
 
-	list_iterate(lvh, lvs) {
-		lv = list_item(lvh, struct lv_list)->lv;
-		if (!activate_lv_excl(cmd, lv->lvid.s)) {
-			log_error("Failed to activate %s", lv->name);
-			list_uniterate(lvh, lvs, lvh) {
-				lv = list_item(lvh, struct lv_list)->lv;
-				activate_lv(cmd, lv->lvid.s);
+	list_iterate_items(lvl, lvs) {
+		if (!activate_lv_excl(cmd, lvl->lv->lvid.s)) {
+			log_error("Failed to activate %s", lvl->lv->name);
+			list_uniterate(lvh, lvs, &lvl->list) {
+				lvl = list_item(lvh, struct lv_list);
+				activate_lv(cmd, lvl->lv->lvid.s);
 			}
 
 			return 0;
@@ -321,3 +319,9 @@
 {
 	return _vg_write_lock_held;
 }
+
+int locking_is_clustered(void)
+{
+	return (_locking.flags & LCK_CLUSTERED) ? 1 : 0;
+}
+

Modified: lvm2/trunk/lib/locking/locking.h
==============================================================================
--- lvm2/trunk/lib/locking/locking.h	(original)
+++ lvm2/trunk/lib/locking/locking.h	Tue Jun 14 11:23:47 2005
@@ -20,6 +20,7 @@
 void fin_locking(void);
 void reset_locking(void);
 int vg_write_lock_held(void);
+int locking_is_clustered(void);
 
 /*
  * LCK_VG:

Modified: lvm2/trunk/lib/locking/locking_types.h
==============================================================================
--- lvm2/trunk/lib/locking/locking_types.h	(original)
+++ lvm2/trunk/lib/locking/locking_types.h	Tue Jun 14 11:23:47 2005
@@ -23,6 +23,7 @@
 typedef void (*reset_lock_fn) (void);
 
 #define LCK_PRE_MEMLOCK	0x00000001	/* Is memlock() needed before calls? */
+#define LCK_CLUSTERED	0x00000002
 
 struct locking_type {
 	uint32_t flags;
@@ -40,4 +41,5 @@
 int init_file_locking(struct locking_type *locking, struct config_tree *cf);
 
 int init_external_locking(struct locking_type *locking, struct config_tree *cf);
+
 int init_cluster_locking(struct locking_type *locking, struct config_tree *cf);

Modified: lvm2/trunk/lib/log/log.c
==============================================================================
--- lvm2/trunk/lib/log/log.c	(original)
+++ lvm2/trunk/lib/log/log.c	Tue Jun 14 11:23:47 2005
@@ -30,6 +30,7 @@
 static int _partial = 0;
 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 _debug_level = 0;
 static int _syslog = 0;
 static int _log_to_file = 0;
@@ -39,6 +40,7 @@
 static int _log_cmd_name = 0;
 static int _log_suppress = 0;
 static int _ignorelockingfailure = 0;
+static int _lockingfailed = 0;
 static int _security_level = SECURITY_LEVEL;
 static char _cmd_name[30] = "";
 static char _msg_prefix[30] = "  ";
@@ -70,7 +72,7 @@
 {
 	int open_flags = append ? 0 : O_TRUNC;
 
-	dev_create_file(log_file, &_log_dev, &_log_dev_alias);
+	dev_create_file(log_file, &_log_dev, &_log_dev_alias, 1);
 	if (!dev_open_flags(&_log_dev, O_RDWR | O_CREAT | open_flags, 1, 0))
 		return;
 
@@ -149,11 +151,21 @@
 	_pvmove = level;
 }
 
+void init_full_scan_done(int level)
+{
+	_full_scan_done = level;
+}
+
 void init_ignorelockingfailure(int level)
 {
 	_ignorelockingfailure = level;
 }
 
+void init_lockingfailed(int level)
+{
+	_lockingfailed = level;
+}
+
 void init_security_level(int level)
 {
 	_security_level = level;
@@ -203,6 +215,16 @@
 	return _pvmove;
 }
 
+int full_scan_done()
+{
+	return _full_scan_done;
+}
+
+int lockingfailed()
+{
+	return _lockingfailed;
+}
+
 int ignorelockingfailure()
 {
 	return _ignorelockingfailure;

Modified: lvm2/trunk/lib/log/log.h
==============================================================================
--- lvm2/trunk/lib/log/log.h	(original)
+++ lvm2/trunk/lib/log/log.h	Tue Jun 14 11:23:47 2005
@@ -65,11 +65,13 @@
 void init_partial(int level);
 void init_md_filtering(int level);
 void init_pvmove(int level);
+void init_full_scan_done(int level);
 void init_debug(int level);
 void init_cmd_name(int status);
 void init_msg_prefix(const char *prefix);
 void init_indent(int indent);
 void init_ignorelockingfailure(int level);
+void init_lockingfailed(int level);
 void init_security_level(int level);
 
 void set_cmd_name(const char *cmd_name);
@@ -78,8 +80,10 @@
 int partial_mode(void);
 int md_filtering(void);
 int pvmove_mode(void);
+int full_scan_done(void);
 int debug_level(void);
 int ignorelockingfailure(void);
+int lockingfailed(void);
 int security_level(void);
 
 /* Suppress messages to stdout/stderr */

Modified: lvm2/trunk/lib/metadata/lv_alloc.h
==============================================================================
--- lvm2/trunk/lib/metadata/lv_alloc.h	(original)
+++ lvm2/trunk/lib/metadata/lv_alloc.h	Tue Jun 14 11:23:47 2005
@@ -16,5 +16,64 @@
 #ifndef _LVM_LV_ALLOC_H
 #include "pool.h"
 
-struct lv_segment *alloc_lv_segment(struct pool *mem, uint32_t num_areas);
+struct lv_segment *alloc_lv_segment(struct pool *mem,
+				    struct segment_type *segtype,
+				    struct logical_volume *lv,
+				    uint32_t le, uint32_t len,
+				    uint32_t status,
+				    uint32_t stripe_size,
+				    struct logical_volume *log_lv,
+				    uint32_t area_count,
+				    uint32_t area_len,
+				    uint32_t chunk_size,
+				    uint32_t region_size,
+				    uint32_t extents_copied);
+
+struct lv_segment *alloc_snapshot_seg(struct logical_volume *lv,
+				      uint32_t status, uint32_t old_le_count);
+
+int set_lv_segment_area_pv(struct lv_segment *seg, uint32_t area_num,
+			   struct physical_volume *pv, uint32_t pe);
+void set_lv_segment_area_lv(struct lv_segment *seg, uint32_t area_num,
+			    struct logical_volume *lv, uint32_t le,
+			    uint32_t flags);
+
+struct alloc_handle;
+struct alloc_handle *allocate_extents(struct volume_group *vg,
+				      struct logical_volume *lv,
+                                      struct segment_type *segtype,
+                                      uint32_t stripes,
+                                      uint32_t mirrors, uint32_t log_count,
+				      uint32_t extents,
+                                      struct physical_volume *mirrored_pv,
+                                      uint32_t mirrored_pe,
+                                      uint32_t status,
+                                      struct list *allocatable_pvs,
+                                      alloc_policy_t alloc);
+
+int lv_add_segment(struct alloc_handle *ah,
+		   uint32_t first_area, uint32_t num_areas,
+		   struct logical_volume *lv,
+                   struct segment_type *segtype,
+                   uint32_t stripe_size,
+                   struct physical_volume *mirrored_pv,
+                   uint32_t mirrored_pe,
+                   uint32_t status,   
+		   uint32_t region_size,
+                   struct logical_volume *log_lv);
+
+int lv_add_log_segment(struct alloc_handle *ah, struct logical_volume *log_lv);
+int lv_add_virtual_segment(struct logical_volume *lv, uint32_t status,
+                           uint32_t extents, struct segment_type *segtype);
+int lv_add_mirror_segment(struct alloc_handle *ah,
+			  struct logical_volume *lv,
+			  struct logical_volume **sub_lvs,
+			  uint32_t mirrors,
+			  struct segment_type *segtype,
+			  uint32_t status,
+			  uint32_t region_size,
+			  struct logical_volume *log_lv);
+
+void alloc_destroy(struct alloc_handle *ah);
+
 #endif

Modified: lvm2/trunk/lib/metadata/lv_manip.c
==============================================================================
--- lvm2/trunk/lib/metadata/lv_manip.c	(original)
+++ lvm2/trunk/lib/metadata/lv_manip.c	Tue Jun 14 11:23:47 2005
@@ -20,514 +20,1020 @@
 #include "lvm-string.h"
 #include "toolcontext.h"
 #include "lv_alloc.h"
+#include "pv_alloc.h"
 #include "display.h"
 #include "segtype.h"
 
 /*
- * These functions adjust the pe counts in pv's
- * after we've added or removed segments.
+ * Find first unused LV number.
  */
-static void _get_extents(struct lv_segment *seg)
+uint32_t find_free_lvnum(struct logical_volume *lv)
 {
-	unsigned int s, count;
-	struct physical_volume *pv;
+	int lvnum_used[MAX_RESTRICTED_LVS + 1];
+	uint32_t i = 0;
+	struct lv_list *lvl;
+	int lvnum;
 
-	for (s = 0; s < seg->area_count; s++) {
-		if (seg->area[s].type != AREA_PV)
-			continue;
+	memset(&lvnum_used, 0, sizeof(lvnum_used));
 
-		pv = seg->area[s].u.pv.pv;
-		count = seg->area_len;
-		pv->pe_alloc_count += count;
+	list_iterate_items(lvl, &lv->vg->lvs) {
+		lvnum = lvnum_from_lvid(&lvl->lv->lvid);
+		if (lvnum <= MAX_RESTRICTED_LVS)
+			lvnum_used[lvnum] = 1;
 	}
-}
-
-static void _put_extents(struct lv_segment *seg)
-{
-	unsigned int s, count;
-	struct physical_volume *pv;
 
-	for (s = 0; s < seg->area_count; s++) {
-		if (seg->area[s].type != AREA_PV)
-			continue;
+	while (lvnum_used[i])
+		i++;
 
-		pv = seg->area[s].u.pv.pv;
+	/* FIXME What if none are free? */
 
-		if (pv) {
-			count = seg->area_len;
-			assert(pv->pe_alloc_count >= count);
-			pv->pe_alloc_count -= count;
-		}
-	}
+	return i;
 }
 
-struct lv_segment *alloc_lv_segment(struct pool *mem, uint32_t num_areas)
+/*
+ * All lv_segments get created here.
+ */
+struct lv_segment *alloc_lv_segment(struct pool *mem,
+				    struct segment_type *segtype,
+				    struct logical_volume *lv,
+				    uint32_t le, uint32_t len,
+				    uint32_t status,
+				    uint32_t stripe_size,
+				    struct logical_volume *log_lv,
+				    uint32_t area_count,
+				    uint32_t area_len,
+				    uint32_t chunk_size,
+				    uint32_t region_size,
+				    uint32_t extents_copied)
 {
 	struct lv_segment *seg;
-	uint32_t len = sizeof(*seg) + (num_areas * sizeof(seg->area[0]));
+	uint32_t sz = sizeof(*seg) + (area_count * sizeof(seg->area[0]));
 
-	if (!(seg = pool_zalloc(mem, len))) {
+	if (!(seg = pool_zalloc(mem, sz))) {
 		stack;
 		return NULL;
 	}
 
-	seg->area_count = num_areas;
+	if (!segtype) {
+		log_error("alloc_lv_segment: Missing segtype.");
+		return NULL;
+	}
+
+	seg->segtype = segtype;
+	seg->lv = lv;
+	seg->le = le;
+	seg->len = len;
+	seg->status = status;
+	seg->stripe_size = stripe_size;
+	seg->area_count = area_count;
+	seg->area_len = area_len;
+	seg->chunk_size = chunk_size;
+	seg->region_size = region_size;
+	seg->extents_copied = extents_copied;
+	seg->log_lv = log_lv;
 	list_init(&seg->tags);
 
+	if (log_lv)
+		log_lv->status |= MIRROR_LOG;
+
 	return seg;
 }
 
-static int _alloc_parallel_area(struct logical_volume *lv, uint32_t area_count,
-				uint32_t stripe_size,
-				struct segment_type *segtype,
-				struct pv_area **areas, uint32_t *ix)
+struct lv_segment *alloc_snapshot_seg(struct logical_volume *lv,
+				      uint32_t status, uint32_t old_le_count)
 {
-	uint32_t count, area_len, smallest;
-	uint32_t s;
 	struct lv_segment *seg;
-	int striped = 0;
+	struct segment_type *segtype;
 
-	/* Striped or mirrored? */
-	if (segtype->flags & SEG_AREAS_STRIPED)
-		striped = 1;
+	segtype = get_segtype_from_string(lv->vg->cmd, "snapshot");
+	if (!segtype) {
+		log_error("Failed to find snapshot segtype");
+		return NULL;
+	}
 
-	count = lv->le_count - *ix;
-	area_len = count / (striped ? area_count : 1);
-	smallest = areas[area_count - 1]->count;
+	if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv, old_le_count,
+				     lv->le_count - old_le_count, status, 0,
+				     NULL, 0, lv->le_count - old_le_count,
+				     0, 0, 0))) {
+		log_error("Couldn't allocate new snapshot segment.");
+		return NULL;
+	}
 
-	if (smallest < area_len)
-		area_len = smallest;
+	list_add(&lv->segments, &seg->list);
+	lv->status |= VIRTUAL;
+
+	return seg;
+}
+
+/*
+ * Link part of a PV to an LV segment.
+ */
+int set_lv_segment_area_pv(struct lv_segment *seg, uint32_t area_num,
+			   struct physical_volume *pv, uint32_t pe)
+{
+	seg->area[area_num].type = AREA_PV;
+	pv->pe_alloc_count += seg->area_len;
 
-	if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, area_count))) {
-		log_err("Couldn't allocate new parallel segment.");
+	if (!(seg_pvseg(seg, area_num) =
+	      assign_peg_to_lvseg(pv, pe, seg->area_len, seg, area_num))) {
+		stack;
 		return 0;
 	}
 
-	seg->lv = lv;
-	seg->segtype = segtype;
-	seg->le = *ix;
-	seg->len = area_len * (striped ? area_count : 1);
-	seg->area_len = area_len;
-	seg->stripe_size = stripe_size;
-	seg->extents_copied = 0u;
+	return 1;
+}
 
-	for (s = 0; s < area_count; s++) {
-		struct pv_area *pva = areas[s];
-		seg->area[s].type = AREA_PV;
-		seg->area[s].u.pv.pv = pva->map->pvl->pv;
-		seg->area[s].u.pv.pe = pva->start;
-		consume_pv_area(pva, area_len);
-	}
+/*
+ * Link one LV segment to another.  Assumes sizes already match.
+ */
+void set_lv_segment_area_lv(struct lv_segment *seg, uint32_t area_num,
+			    struct logical_volume *lv, uint32_t le,
+			    uint32_t flags)
+{
+	seg->area[area_num].type = AREA_LV;
+	seg_lv(seg, area_num) = lv;
+	seg_le(seg, area_num) = le;
+	lv->status |= flags;
+}
 
-	list_add(&lv->segments, &seg->list);
-	*ix += seg->len;
+/*
+ * Reduce the size of an lv_segment.  New size can be zero.
+ */
+static int _lv_segment_reduce(struct lv_segment *seg, uint32_t reduction)
+{
+	uint32_t area_reduction, s;
 
-	if (!striped)
-		lv->status |= MIRRORED;
+	/* Caller must ensure exact divisibility */
+	if (seg_is_striped(seg)) {
+		if (reduction % seg->area_count) {
+			log_error("Segment extent reduction %" PRIu32
+				  "not divisible by #stripes %" PRIu32,
+				  reduction, seg->area_count);
+			return 0;
+		}
+		area_reduction = (reduction / seg->area_count);
+	} else
+		area_reduction = reduction;
+
+	seg->len -= reduction;
+	seg->area_len -= area_reduction;
+
+	for (s = 0; s < seg->area_count; s++) {
+		if (seg_type(seg, s) == AREA_PV) {
+			release_pv_segment(seg_pvseg(seg, s), area_reduction);
+			seg->lv->vg->free_count += area_reduction;
+		} else if (seg_lv(seg, s)->status & MIRROR_IMAGE)
+			lv_reduce(seg_lv(seg, s), area_reduction);	
+	}
 
 	return 1;
 }
 
-static int _comp_area(const void *l, const void *r)
+/*
+ * Entry point for all LV reductions in size.
+ */
+int lv_reduce(struct logical_volume *lv, uint32_t extents)
 {
-	const struct pv_area *lhs = *((const struct pv_area **) l);
-	const struct pv_area *rhs = *((const struct pv_area **) r);
+	struct lv_list *lvl;
+	struct lv_segment *seg;
+	uint32_t count = extents;
+	uint32_t reduction;
 
-	if (lhs->count < rhs->count)
-		return 1;
+	list_iterate_back_items(seg, &lv->segments) {
+		if (!count)
+			break;
 
-	else if (lhs->count > rhs->count)
-		return -1;
+		if (seg->len <= count) {
+			/* remove this segment completely */
+			/* FIXME Check this is safe */
+			if (seg->log_lv && !lv_remove(seg->log_lv)) {
+				stack;
+				return 0;
+			}
+			list_del(&seg->list);
+			reduction = seg->len;
+		} else
+			reduction = count;
 
-	return 0;
+		if (!_lv_segment_reduce(seg, reduction)) {
+			stack;
+			return 0;
+		}
+		count -= reduction;
+	}
+
+	lv->le_count -= extents;
+	lv->size = (uint64_t) lv->le_count * lv->vg->extent_size;
+
+	/* Remove the LV if it is now empty */
+	if (!lv->le_count) {
+		if (!(lvl = find_lv_in_vg(lv->vg, lv->name))) {
+			stack;
+			return 0;
+		}
+
+		list_del(&lvl->list);
+
+		lv->vg->lv_count--;
+	} else if (lv->vg->fid->fmt->ops->lv_setup &&
+		   !lv->vg->fid->fmt->ops->lv_setup(lv->vg->fid, lv)) {
+		stack;
+		return 0;
+	}
+
+	return 1;
 }
 
-static int _alloc_parallel(struct logical_volume *lv,
-			   struct list *pvms, uint32_t allocated,
-			   uint32_t stripes, uint32_t stripe_size,
-			   uint32_t mirrors, struct segment_type *segtype)
+/*
+ * Completely remove an LV.
+ */
+int lv_remove(struct logical_volume *lv)
 {
-	int r = 0;
-	struct list *pvmh;
-	struct pv_area **areas;
-	unsigned int pv_count = 0, ix;
-	struct pv_map *pvm;
-	size_t len;
-	uint32_t area_count;
 
-	if (stripes > 1 && mirrors > 1) {
-		log_error("striped mirrors are not supported yet");
+	if (!lv_reduce(lv, lv->le_count)) {
+		stack;
 		return 0;
 	}
 
-	if (stripes > 1)
-		area_count = stripes;
-	else
+	return 1;
+}
+
+/*
+ * A set of contiguous physical extents allocated
+ */
+struct alloced_area {
+	struct list list;
+
+	struct physical_volume *pv;
+	uint32_t pe;
+	uint32_t len;
+};
+
+/*
+ * Details of an allocation attempt
+ */
+struct alloc_handle {
+	struct pool *mem;
+
+	alloc_policy_t alloc;		/* Overall policy */
+	uint32_t area_count;		/* Number of parallel areas */
+	uint32_t area_multiple;		/* seg->len = area_len * area_multiple */
+	uint32_t log_count;		/* Number of parallel 1-extent logs */
+	uint32_t total_area_len;	/* Total number of parallel extents */
+
+	struct alloced_area log_area;	/* Extent used for log */
+	struct list alloced_areas[0];	/* Lists of areas in each stripe */
+};
+
+/*
+ * Preparation for a specific allocation attempt
+ */
+static struct alloc_handle *_alloc_init(struct pool *mem,
+					struct segment_type *segtype,
+					alloc_policy_t alloc,
+					uint32_t mirrors,
+					uint32_t stripes,
+					uint32_t log_count,
+					struct physical_volume *mirrored_pv)
+{
+	struct alloc_handle *ah;
+	uint32_t s, area_count;
+
+	if (stripes > 1 && mirrors > 1) {
+		log_error("Striped mirrors are not supported yet");
+		return NULL;
+	}
+
+	if ((stripes > 1 || mirrors > 1) && mirrored_pv) {
+		log_error("Can't mix striping or mirroring with "
+			  "creation of a mirrored PV yet");
+		return NULL;
+	}
+
+	if (log_count && (stripes > 1 || mirrored_pv)) {
+		log_error("Can't mix striping or pvmove with "
+			  "a mirror log yet.");
+		return NULL;
+	}
+
+	if (segtype_is_virtual(segtype))
+		area_count = 0;
+	else if (mirrors > 1)
 		area_count = mirrors;
+	else if (mirrored_pv)
+		area_count = 1;
+	else
+		area_count = stripes;
+
+	if (!(ah = pool_zalloc(mem, sizeof(*ah) + sizeof(ah->alloced_areas[0]) * area_count))) {
+		log_error("allocation handle allocation failed");
+		return NULL;
+	}
 
-	list_iterate(pvmh, pvms)
-	    pv_count++;
+	if (segtype_is_virtual(segtype))
+		return ah;
 
-	/* allocate an array of pv_areas, one candidate per pv */
-	len = sizeof(*areas) * pv_count;
-	if (!(areas = dbg_malloc(sizeof(*areas) * pv_count))) {
-		log_err("Couldn't allocate areas array.");
-		return 0;
+	if (!(ah->mem = pool_create("allocation", 1024))) {
+		log_error("allocation pool creation failed");
+		return NULL;
 	}
 
-	while (allocated != lv->le_count) {
+	ah->area_count = area_count;
+	ah->log_count = log_count;
+	ah->alloc = alloc;
+	ah->area_multiple = segtype_is_striped(segtype) ? ah->area_count : 1;
 
-		ix = 0;
-		list_iterate(pvmh, pvms) {
-			pvm = list_item(pvmh, struct pv_map);
+	list_init(&ah->alloced_areas[0]);
 
-			if (list_empty(&pvm->areas))
-				continue;
+	for (s = 0; s < ah->area_count; s++)
+		list_init(&ah->alloced_areas[s]);
+
+	return ah;
+}
+
+void alloc_destroy(struct alloc_handle *ah)
+{
+	if (ah->mem)
+		pool_destroy(ah->mem);
+}
 
-			areas[ix++] = list_item(pvm->areas.n, struct pv_area);
+static int _setup_alloced_segment(struct logical_volume *lv, uint32_t status,
+				  uint32_t area_count,
+				  uint32_t stripe_size,
+				  struct segment_type *segtype,
+				  struct alloced_area *aa,
+				  struct physical_volume *mirrored_pv,
+				  uint32_t mirrored_pe,
+				  uint32_t region_size,
+				  struct logical_volume *log_lv)
+{
+	uint32_t s, extents, area_multiple, extra_areas = 0;
+	struct lv_segment *seg;
+
+	if (mirrored_pv)
+		extra_areas = 1;
+
+	area_multiple = segtype_is_striped(segtype) ? area_count : 1;
+
+	if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv,
+				     lv->le_count,
+				     aa[0].len * area_multiple,
+				     status, stripe_size, log_lv,
+				     area_count + extra_areas,
+				     aa[0].len, 0u, region_size, 0u))) {
+		log_error("Couldn't allocate new LV segment.");
+		return 0;
+	}
+
+	if (extra_areas) {
+		if (!set_lv_segment_area_pv(seg, 0, mirrored_pv, mirrored_pe)) {
+			stack;
+			return 0;
 		}
+	}
 
-		if (ix < area_count) {
-			log_error("Insufficient allocatable extents suitable "
-				  "for parallel use for logical volume "
-				  "%s: %u required", lv->name, lv->le_count);
-			goto out;
+	for (s = 0; s < area_count; s++) {
+		if (!set_lv_segment_area_pv(seg, s + extra_areas, aa[s].pv,
+					    aa[s].pe)) {
+			stack;
+			return 0;
 		}
+	}
 
-		/* sort the areas so we allocate from the biggest */
-		qsort(areas, ix, sizeof(*areas), _comp_area);
+	list_add(&lv->segments, &seg->list);
+
+	extents = aa[0].len * area_multiple;
+	lv->le_count += extents;
+	lv->size += (uint64_t) extents *lv->vg->extent_size;
+
+	lv->vg->free_count -= aa[0].len * area_count;
+
+	if (segtype_is_mirrored(segtype))
+		lv->status |= MIRRORED;
 
-		if (!_alloc_parallel_area(lv, area_count, stripe_size, segtype,
-					  areas, &allocated)) {
+	return 1;
+}
+
+static int _setup_alloced_segments(struct logical_volume *lv,
+				   struct list *alloced_areas,
+				   uint32_t area_count,
+				   uint32_t status,
+				   uint32_t stripe_size,
+				   struct segment_type *segtype,
+				   struct physical_volume *mirrored_pv,
+				   uint32_t mirrored_pe,
+				   uint32_t region_size,
+				   struct logical_volume *log_lv)
+{
+	struct alloced_area *aa;
+
+	list_iterate_items(aa, &alloced_areas[0]) {
+		if (!_setup_alloced_segment(lv, status, area_count,
+					    stripe_size, segtype, aa,
+					    mirrored_pv, mirrored_pe,
+					    region_size, log_lv)) {
 			stack;
-			goto out;
+			return 0;
 		}
 	}
-	r = 1;
 
-      out:
-	dbg_free(areas);
-	return r;
+	return 1;
 }
 
 /*
- * The heart of the allocation code.  This function takes a
- * pv_area and allocates it to the lv.  If the lv doesn't need
- * the complete area then the area is split, otherwise the area
- * is unlinked from the pv_map.
+ * This function takes a list of pv_areas and adds them to allocated_areas.
+ * If the complete area is not needed then it gets split.
+ * The part used is removed from the pv_map so it can't be allocated twice.
  */
-static int _alloc_linear_area(struct logical_volume *lv, uint32_t *ix,
-			      struct pv_map *map, struct pv_area *pva)
+static int _alloc_parallel_area(struct alloc_handle *ah, uint32_t needed,
+				struct pv_area **areas,
+				uint32_t *ix, struct pv_area *log_area)
 {
-	uint32_t count, remaining;
-	struct lv_segment *seg;
+	uint32_t area_len, smallest, remaining;
+	uint32_t s;
+	struct alloced_area *aa;
+
+	remaining = needed - *ix;
+	area_len = remaining / ah->area_multiple;
 
-	count = pva->count;
-	remaining = lv->le_count - *ix;
-	if (count > remaining)
-		count = remaining;
+	smallest = areas[ah->area_count - 1]->count;
 
-	if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, 1))) {
-		log_err("Couldn't allocate new stripe segment.");
+	if (area_len > smallest)
+		area_len = smallest;
+
+	if (!(aa = pool_alloc(ah->mem, sizeof(*aa) *
+			      (ah->area_count + (log_area ? 1 : 0))))) {
+		log_error("alloced_area allocation failed");
 		return 0;
 	}
 
-	seg->lv = lv;
-	if (!(seg->segtype = get_segtype_from_string(lv->vg->cmd, "striped"))) {
-		stack;
-		return 0;
+	for (s = 0; s < ah->area_count; s++) {
+		aa[s].pv = areas[s]->map->pv;
+		aa[s].pe = areas[s]->start;
+		aa[s].len = area_len;
+		list_add(&ah->alloced_areas[s], &aa[s].list);
 	}
-	seg->le = *ix;
-	seg->len = count;
-	seg->area_len = count;
-	seg->stripe_size = 0;
-	seg->area[0].type = AREA_PV;
-	seg->area[0].u.pv.pv = map->pvl->pv;
-	seg->area[0].u.pv.pe = pva->start;
 
-	list_add(&lv->segments, &seg->list);
+	ah->total_area_len += area_len;
+
+	for (s = 0; s < ah->area_count; s++)
+		consume_pv_area(areas[s], area_len);
+
+	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 */
+		consume_pv_area(log_area, ah->log_area.len);
+	}
+
+	*ix += area_len * ah->area_multiple;
 
-	consume_pv_area(pva, count);
-	*ix += count;
 	return 1;
 }
 
-static int _alloc_mirrored_area(struct logical_volume *lv, uint32_t *ix,
-				struct pv_map *map, struct pv_area *pva,
-				struct segment_type *segtype,
-				struct physical_volume *mirrored_pv,
-				uint32_t mirrored_pe)
+static int _comp_area(const void *l, const void *r)
 {
-	uint32_t count, remaining;
-	struct lv_segment *seg;
-
-	count = pva->count;
-	remaining = lv->le_count - *ix;
-	if (count > remaining)
-		count = remaining;
+	const struct pv_area *lhs = *((const struct pv_area **) l);
+	const struct pv_area *rhs = *((const struct pv_area **) r);
 
-	if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, 2))) {
-		log_err("Couldn't allocate new mirrored segment.");
-		return 0;
-	}
+	if (lhs->count < rhs->count)
+		return 1;
 
-	seg->lv = lv;
-	seg->segtype = segtype;
-	seg->le = *ix;
-	seg->status = 0u;
-	seg->len = count;
-	seg->area_len = count;
-	seg->stripe_size = 0;
-	seg->extents_copied = 0u;
-	/* FIXME Remove AREA_PV restriction here? */
-	seg->area[0].type = AREA_PV;
-	seg->area[0].u.pv.pv = mirrored_pv;
-	seg->area[0].u.pv.pe = mirrored_pe;
-	seg->area[1].type = AREA_PV;
-	seg->area[1].u.pv.pv = map->pvl->pv;
-	seg->area[1].u.pv.pe = pva->start;
-	list_add(&lv->segments, &seg->list);
+	else if (lhs->count > rhs->count)
+		return -1;
 
-	consume_pv_area(pva, count);
-	*ix += count;
-	return 1;
+	return 0;
 }
 
 /*
- * Only one area per pv is allowed, so we search
- * for the biggest area, or the first area that
- * can complete the allocation.
+ * Is pva contiguous to any existing areas or 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)
+{
+	struct pv_segment *prev_pvseg;
+	uint32_t s;
+
+	for (s = 0; s < prev_lvseg->area_count; s++) {
+		if (seg_type(prev_lvseg, s) != AREA_PV)
+			continue;	/* FIXME Broken */
+
+		if (!(prev_pvseg = seg_pvseg(prev_lvseg, s)))
+			continue; /* FIXME Broken */
+
+		if ((prev_pvseg->pv != pv))
+			continue;
+
+		if (prev_pvseg->pe + prev_pvseg->len == pva->start) {
+			areas[s] = pva;
+			return 1;
+		}
+	}
+
+	return 0;
+}
 
 /*
- * FIXME: subsequent lvextends may not be contiguous.
+ * Choose sets of parallel areas to use, respecting any constraints.
  */
-static int _alloc_contiguous(struct logical_volume *lv,
-			     struct list *pvms, uint32_t allocated)
+/* FIXME Also accept existing areas new space must be parallel to */
+static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
+				struct list *pvms, struct pv_area **areas,
+				uint32_t areas_size, unsigned can_split,
+				struct lv_segment *prev_lvseg,
+				uint32_t *allocated, uint32_t needed)
 {
-	struct list *tmp1;
 	struct pv_map *pvm;
 	struct pv_area *pva;
+	unsigned already_found_one = 0;
+	unsigned contiguous = 0, contiguous_count = 0;
+	unsigned ix;
+	unsigned ix_offset = 0;	/* Offset for non-contiguous allocations */
+
+	/* FIXME Do calculations on free extent counts before selecting space */
+	/* FIXME Select log PV appropriately if there isn't one yet */
+
+	if ((alloc == ALLOC_CONTIGUOUS)) {
+		contiguous = 1;
+		if (prev_lvseg)
+			ix_offset = prev_lvseg->area_count;
+		else
+			ix_offset = ah->area_count;
+	}
+
+	/* FIXME This algorithm needs a lot of cleaning up! */
+	/* FIXME anywhere doesn't find all space yet */
+	/* ix_offset holds the number of allocations that must be contiguous */
+	/* ix holds the number of areas found on other PVs */
+	do {
+		ix = 0;
 
-	list_iterate(tmp1, pvms) {
-		pvm = list_item(tmp1, struct pv_map);
+		/*
+		 * Put the smallest area of each PV that is at least the
+		 * size we need into areas array.  If there isn't one
+		 * that fits completely and we're allowed more than one
+		 * LV segment, then take the largest remaining instead.
+		 */
+		list_iterate_items(pvm, pvms) {
+			if (list_empty(&pvm->areas))
+				continue;	/* Next PV */
 
-		if (list_empty(&pvm->areas))
-			continue;
+			/* Don't allocate onto the log pv */
+			if ((alloc != ALLOC_ANYWHERE) && ah->log_count &&
+			    (pvm->pv == ah->log_area.pv))
+				continue;	/* Next PV */
+
+			already_found_one = 0;
+			/* First area in each list is the largest */
+			list_iterate_items(pva, &pvm->areas) {
+				if (contiguous) {
+					if (prev_lvseg &&
+					    _check_contiguous(prev_lvseg,
+							      pvm->pv,
+							      pva, areas)) {
+						contiguous_count++;
+						break; /* Next PV */
+					}
+					continue;
+				}
+
+				/* Is it big enough on its own? */
+				if ((pva->count < needed - *allocated) &&
+				    ((!can_split && !ah->log_count) ||
+				     (already_found_one &&
+				      !(alloc == ALLOC_ANYWHERE))))
+					break;	/* Next PV */
+
+				if (!already_found_one ||
+				    alloc == ALLOC_ANYWHERE) {
+					ix++;
+					already_found_one = 1;
+				}
 
-		/* first item in the list is the biggest */
-		pva = list_item(pvm->areas.n, struct pv_area);
-		if (pva->count < lv->le_count)
-			continue;
+				areas[ix + ix_offset -1] = pva;
+
+				break;	/* Next PV */
+			}
+			if (ix >= areas_size)
+				break;
+		}
 
-		if (!_alloc_linear_area(lv, &allocated, pvm, pva)) {
+		if (contiguous && (contiguous_count < ix_offset))
+			break;
+
+		/* Only allocate log_area the first time around */
+		if (ix + ix_offset < ah->area_count +
+			    (ah->log_count && !ah->log_area.len) ?
+				ah->log_count : 0)
+			/* FIXME With ALLOC_ANYWHERE, need to split areas */
+			break;
+
+		/* sort the areas so we allocate from the biggest */
+		if (ix > 1)
+			qsort(areas + ix_offset, ix, sizeof(*areas),
+			      _comp_area);
+
+		/* First time around, use smallest area as log_area */
+		/* FIXME decide which PV to use at top of function instead */
+		if (!_alloc_parallel_area(ah, needed, areas,
+					  allocated,
+					  (ah->log_count && !ah->log_area.len) ?
+						*(areas + ix_offset + ix - 1) :
+						NULL)) {
 			stack;
 			return 0;
 		}
 
-		break;
-	}
-
-	if (allocated != lv->le_count) {
-		log_error("Insufficient allocatable extents (%u) "
-			  "for logical volume %s: %u required",
-			  allocated, lv->name, lv->le_count);
-		return 0;
-	}
+	} while (*allocated != needed && can_split);
 
 	return 1;
 }
 
-/* FIXME Contiguous depends on *segment* (i.e. stripe) not LV */
-static int _alloc_mirrored(struct logical_volume *lv,
-			   struct list *pvms, uint32_t allocated,
+/*
+ * Allocate several segments, each the same size, in parallel.
+ * If mirrored_pv and mirrored_pe are supplied, it is used as
+ * the first area, and additional areas are allocated parallel to it.
+ */
+static int _allocate(struct alloc_handle *ah,
+		     struct volume_group *vg,
+			   struct logical_volume *lv, uint32_t status,
+			   uint32_t new_extents,
+			   struct list *allocatable_pvs,
+			   uint32_t stripes, uint32_t mirrors,
 			   struct segment_type *segtype,
 			   struct physical_volume *mirrored_pv,
 			   uint32_t mirrored_pe)
 {
-	struct list *tmp1;
-	struct pv_map *pvm;
-	struct pv_area *pva;
-	uint32_t max_found = 0;
+	struct pv_area **areas;
+	uint32_t allocated = lv ? lv->le_count : 0;
+	uint32_t old_allocated;
+	struct lv_segment *prev_lvseg = NULL;
+	unsigned can_split = 1;	/* Are we allowed more than one segment? */
+	int r = 0;
+	struct list *pvms;
+	uint32_t areas_size;
 
-	/* Try each PV in turn */
-	list_iterate(tmp1, pvms) {
-		pvm = list_item(tmp1, struct pv_map);
+	if (allocated >= new_extents) {
+		log_error("_allocate called with no work to do!");
+		return 1;
+	}
 
-		if (list_empty(&pvm->areas))
-			continue;
+	if (mirrored_pv || (ah->alloc == ALLOC_CONTIGUOUS))
+		can_split = 0;
 
-		/* first item in the list is the biggest */
-		pva = list_item(pvm->areas.n, struct pv_area);
-		if (pva->count < lv->le_count - allocated) {
-			max_found = pva->count;
-			continue;
-		}
+	if (lv && !list_empty(&lv->segments))
+		prev_lvseg = list_item(list_last(&lv->segments),
+				       struct lv_segment);
+	/*
+	 * Build the sets of available areas on the pv's.
+	 */
+	if (!(pvms = create_pv_maps(ah->mem, vg, allocatable_pvs))) {
+		stack;
+		return 0;
+	}
 
-		if (!_alloc_mirrored_area(lv, &allocated, pvm, pva, segtype,
-					  mirrored_pv, mirrored_pe)) {
-			stack;
+	areas_size = list_size(pvms);
+	if (areas_size < ah->area_count + ah->log_count) {
+		if (ah->alloc != ALLOC_ANYWHERE) {
+			log_error("Not enough PVs with free space available "
+				  "for parallel allocation.");
+			log_error("Consider --alloc anywhere if desperate.");
 			return 0;
 		}
+		areas_size = ah->area_count + ah->log_count;
+	}
+
+	/* Allocate an array of pv_areas to hold the largest space on each PV */
+	if (!(areas = dbg_malloc(sizeof(*areas) * areas_size))) {
+		log_err("Couldn't allocate areas array.");
+		return 0;
+	}
+
+	old_allocated = allocated;
+	if (!_find_parallel_space(ah, ALLOC_CONTIGUOUS, pvms, areas,
+				  areas_size, can_split,
+				  prev_lvseg, &allocated, new_extents)) {
+		stack;
+		goto out;
+	}
 
-		break;
+	if ((allocated == new_extents) || (ah->alloc == ALLOC_CONTIGUOUS) ||
+	    (!can_split && (allocated != old_allocated)))
+		goto finished;
+
+	old_allocated = allocated;
+	if (!_find_parallel_space(ah, ALLOC_NORMAL, pvms, areas,
+				  areas_size, can_split,
+				  prev_lvseg, &allocated, new_extents)) {
+		stack;
+		goto out;
 	}
 
-	if (allocated != lv->le_count) {
-		log_error("Insufficient contiguous allocatable extents (%u) "
-			  "for logical volume %s: %u required",
-			  allocated + max_found, lv->name, lv->le_count);
+	if ((allocated == new_extents) || (ah->alloc == ALLOC_NORMAL) ||
+	    (!can_split && (allocated != old_allocated)))
+		goto finished;
+
+	if (!_find_parallel_space(ah, ALLOC_ANYWHERE, pvms, areas,
+				  areas_size, can_split,
+				  prev_lvseg, &allocated, new_extents)) {
+		stack;
+		goto out;
+	}
+
+      finished:
+	if (allocated != new_extents) {
+		log_error("Insufficient suitable %sallocatable extents "
+			  "for logical volume %s: %u more required",
+			  can_split ? "" : "contiguous ",
+			  lv ? lv->name : "",
+			  (new_extents - allocated) * ah->area_count
+			  / ah->area_multiple);
+		goto out;
+	}
+
+	r = 1;
+
+      out:
+	dbg_free(areas);
+	return r;
+}
+
+int lv_add_virtual_segment(struct logical_volume *lv, uint32_t status,
+			   uint32_t extents, struct segment_type *segtype)
+{
+	struct lv_segment *seg;
+
+	if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv,
+				     lv->le_count, extents, status, 0,
+				     NULL, 0, extents, 0, 0, 0))) {
+		log_error("Couldn't allocate new zero segment.");
 		return 0;
 	}
 
+	list_add(&lv->segments, &seg->list);
+
+	lv->le_count += extents;
+	lv->size += (uint64_t) extents *lv->vg->extent_size;
+
+	lv->status |= VIRTUAL;
+
 	return 1;
 }
 
 /*
- * Areas just get allocated in order until the lv
- * is full.
+ * Entry point for all extent allocations.
  */
-static int _alloc_next_free(struct logical_volume *lv,
-			    struct list *pvms, uint32_t allocated)
+struct alloc_handle *allocate_extents(struct volume_group *vg,
+				      struct logical_volume *lv,
+				      struct segment_type *segtype,
+				      uint32_t stripes,
+				      uint32_t mirrors, uint32_t log_count,
+				      uint32_t extents,
+				      struct physical_volume *mirrored_pv,
+				      uint32_t mirrored_pe,
+				      uint32_t status,
+				      struct list *allocatable_pvs,
+				      alloc_policy_t alloc)
 {
-	struct list *tmp1, *tmp2;
-	struct pv_map *pvm;
-	struct pv_area *pva;
+	struct alloc_handle *ah;
 
-	list_iterate(tmp1, pvms) {
-		pvm = list_item(tmp1, struct pv_map);
+	if (segtype_is_virtual(segtype)) {
+		log_error("allocate_extents does not handle virtual segments");
+		return NULL;
+	}
 
-		list_iterate(tmp2, &pvm->areas) {
-			pva = list_item(tmp2, struct pv_area);
-			if (!_alloc_linear_area(lv, &allocated, pvm, pva) ||
-			    (allocated == lv->le_count))
-				goto done;
-		}
+	if (vg->fid->fmt->ops->segtype_supported &&
+	    !vg->fid->fmt->ops->segtype_supported(vg->fid, segtype)) {
+		log_error("Metadata format (%s) does not support required "
+			  "LV segment type (%s).", vg->fid->fmt->name,
+			  segtype->name);
+		log_error("Consider changing the metadata format by running "
+			  "vgconvert.");
+		return NULL;
 	}
 
-      done:
-	if (allocated != lv->le_count) {
-		log_error("Insufficient allocatable logical extents (%u) "
-			  "for logical volume %s: %u required",
-			  allocated, lv->name, lv->le_count);
-		return 0;
+	if (alloc == ALLOC_INHERIT)
+		alloc = vg->alloc;
+
+	if (!(ah = _alloc_init(vg->cmd->mem, segtype, alloc, mirrors,
+			       stripes, log_count, mirrored_pv))) {
+		stack;
+		return NULL;
 	}
 
-	return 1;
+	if (!segtype_is_virtual(segtype) &&
+	    !_allocate(ah, vg, lv, status, (lv ? lv->le_count : 0) + extents,
+		       allocatable_pvs,
+		       stripes, mirrors, segtype, mirrored_pv, mirrored_pe)) {
+		stack;
+		alloc_destroy(ah);
+		return NULL;
+	}
+
+	return ah;
 }
 
-static int _alloc_virtual(struct logical_volume *lv,
-			  uint32_t allocated, struct segment_type *segtype)
+/*
+ * Add new segments to an LV from supplied list of areas.
+ */
+int lv_add_segment(struct alloc_handle *ah,
+		   uint32_t first_area, uint32_t num_areas,
+		   struct logical_volume *lv,
+		   struct segment_type *segtype,
+		   uint32_t stripe_size,
+		   struct physical_volume *mirrored_pv,
+		   uint32_t mirrored_pe,
+		   uint32_t status,
+		   uint32_t region_size,
+		   struct logical_volume *log_lv)
 {
-	struct lv_segment *seg;
+	if (!segtype) {
+		log_error("Missing segtype in lv_add_segment().");
+		return 0;
+	}
 
-	if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, 0))) {
-		log_err("Couldn't allocate new zero segment.");
+	if (segtype_is_virtual(segtype)) {
+		log_error("lv_add_segment cannot handle virtual segments");
 		return 0;
 	}
 
-	seg->lv = lv;
-	seg->segtype = segtype;
-	seg->status = 0u;
-	seg->le = allocated;
-	seg->len = lv->le_count - allocated;
-	seg->area_len = seg->len;
-	seg->stripe_size = 0;
-	seg->extents_copied = 0u;
-	list_add(&lv->segments, &seg->list);
-	lv->status |= VIRTUAL;
+	if (!_setup_alloced_segments(lv, &ah->alloced_areas[first_area],
+				     num_areas, status,
+				     stripe_size, segtype,
+				     mirrored_pv, mirrored_pe,
+				     region_size, log_lv)) {
+		stack;
+		return 0;
+	}
+
+	if ((segtype->flags & SEG_CAN_SPLIT) && !lv_merge_segments(lv)) {
+		log_err("Couldn't merge segments after extending "
+			"logical volume.");
+		return 0;
+	}
+
+	if (lv->vg->fid->fmt->ops->lv_setup &&
+	    !lv->vg->fid->fmt->ops->lv_setup(lv->vg->fid, lv)) {
+		stack;
+		return 0;
+	}
 
 	return 1;
 }
 
 /*
- * Chooses a correct allocation policy.
+ * Turn an empty LV into a mirror log.
  */
-static int _allocate(struct volume_group *vg, struct logical_volume *lv,
-		     struct list *allocatable_pvs, uint32_t allocated,
-		     alloc_policy_t alloc, struct segment_type *segtype,
-		     uint32_t stripes, uint32_t stripe_size, uint32_t mirrors,
-		     struct physical_volume *mirrored_pv, uint32_t mirrored_pe,
-		     uint32_t status)
+int lv_add_log_segment(struct alloc_handle *ah, struct logical_volume *log_lv)
 {
-	int r = 0;
-	struct pool *scratch;
-	struct list *pvms, *old_tail = lv->segments.p, *segh;
 	struct lv_segment *seg;
 
-	if (segtype->flags & SEG_VIRTUAL)
-		return _alloc_virtual(lv, allocated, segtype);
+	if (list_size(&log_lv->segments)) {
+		log_error("Log segments can only be added to an empty LV");
+		return 0;
+	}
+
+	if (!(seg = alloc_lv_segment(log_lv->vg->cmd->mem,
+				     get_segtype_from_string(log_lv->vg->cmd,
+							     "striped"),
+				     log_lv, 0, ah->log_area.len, MIRROR_LOG,
+				     0, NULL, 1, ah->log_area.len, 0, 0, 0))) {
+		log_error("Couldn't allocate new mirror log segment.");
+		return 0;
+	}
 
-	if (!(scratch = pool_create("allocation", 1024))) {
+	if (!set_lv_segment_area_pv(seg, 0, ah->log_area.pv, ah->log_area.pe)) {
 		stack;
 		return 0;
 	}
 
-	if (alloc == ALLOC_INHERIT)
-		alloc = vg->alloc;
+	list_add(&log_lv->segments, &seg->list);
+	log_lv->le_count += ah->log_area.len;
+	log_lv->size += (uint64_t) log_lv->le_count *log_lv->vg->extent_size;
 
-	/*
-	 * Build the sets of available areas on the pv's.
-	 */
-	if (!(pvms = create_pv_maps(scratch, vg, allocatable_pvs)))
-		goto out;
+	log_lv->vg->free_count--;
 
-	if (stripes > 1 || mirrors > 1)
-		r = _alloc_parallel(lv, pvms, allocated, stripes, stripe_size,
-				    mirrors, segtype);
+	if (log_lv->vg->fid->fmt->ops->lv_setup &&
+	    !log_lv->vg->fid->fmt->ops->lv_setup(log_lv->vg->fid, log_lv)) {
+		stack;
+		return 0;
+	}
 
-	else if (mirrored_pv)
-		r = _alloc_mirrored(lv, pvms, allocated, segtype, mirrored_pv,
-				    mirrored_pe);
+	return 1;
+}
 
-	else if (alloc == ALLOC_CONTIGUOUS)
-		r = _alloc_contiguous(lv, pvms, allocated);
+/*
+ * Add a mirror segment
+ */
+int lv_add_mirror_segment(struct alloc_handle *ah,
+			  struct logical_volume *lv,
+			  struct logical_volume **sub_lvs,
+			  uint32_t mirrors,
+			  struct segment_type *segtype,
+			  uint32_t status,
+			  uint32_t region_size,
+			  struct logical_volume *log_lv)
+{
+	struct lv_segment *seg;
+	uint32_t m;
 
-	else if (alloc == ALLOC_NORMAL || alloc == ALLOC_ANYWHERE)
-		r = _alloc_next_free(lv, pvms, allocated);
+	if (list_empty(&log_lv->segments)) {
+		log_error("Log LV %s is empty.", log_lv->name);
+		return 0;
+	}
 
-	else {
-		log_error("Unrecognised allocation policy: "
-			  "unable to set up logical volume.");
-		goto out;
+	if (!(seg = alloc_lv_segment(lv->vg->cmd->mem,
+				     get_segtype_from_string(lv->vg->cmd,
+							     "mirror"),
+				     lv, lv->le_count, ah->total_area_len, 0,
+				     0, log_lv, mirrors, ah->total_area_len, 0,
+				     region_size, 0))) {
+		log_error("Couldn't allocate new mirror segment.");
+		return 0;
 	}
 
-	if (r) {
-		vg->free_count -= lv->le_count - allocated;
+	for (m = 0; m < mirrors; m++)
+		set_lv_segment_area_lv(seg, m, sub_lvs[m], 0, MIRROR_IMAGE);
 
-		/*
-		 * Iterate through the new segments, updating pe
-		 * counts in pv's.
-		 */
-		for (segh = lv->segments.p; segh != old_tail; segh = segh->p) {
-			seg = list_item(segh, struct lv_segment);
-			_get_extents(seg);
-			seg->status = status;
+	list_add(&lv->segments, &seg->list);
+	lv->le_count += ah->total_area_len;
+	lv->size += (uint64_t) lv->le_count *lv->vg->extent_size;
+
+	if (lv->vg->fid->fmt->ops->lv_setup &&
+	    !lv->vg->fid->fmt->ops->lv_setup(lv->vg->fid, lv)) {
+		stack;
+		return 0;
+	}
+
+	return 1;
+}
+
+
+/*
+ * Entry point for single-step LV allocation + extension.
+ */
+int lv_extend(struct logical_volume *lv,
+	      struct segment_type *segtype,
+	      uint32_t stripes, uint32_t stripe_size,
+	      uint32_t mirrors, uint32_t extents,
+	      struct physical_volume *mirrored_pv, uint32_t mirrored_pe,
+	      uint32_t status, struct list *allocatable_pvs,
+	      alloc_policy_t alloc)
+{
+	int r = 1;
+	uint32_t m;
+	struct alloc_handle *ah;
+	struct lv_segment *first_seg;
+
+	if (segtype_is_virtual(segtype))
+		return lv_add_virtual_segment(lv, status, extents, segtype);
+
+	if (!(ah = allocate_extents(lv->vg, lv, segtype, stripes, mirrors, 0,
+				    extents, mirrored_pv, mirrored_pe, status,
+				    allocatable_pvs, alloc))) {
+		stack;
+		return 0;
+	}
+
+	if (mirrors < 2) {
+		if (!lv_add_segment(ah, 0, ah->area_count, lv, segtype, stripe_size,
+			    mirrored_pv, mirrored_pe, status, 0, NULL)) {
+			stack;
+			goto out;
 		}
 	} else {
-		/*
-		 * Put the segment list back how we found it.
-		 */
-		old_tail->n = &lv->segments;
-		lv->segments.p = old_tail;
+		list_iterate_items(first_seg, &lv->segments)
+			break;
+		for (m = 0; m < mirrors; m++) {
+			if (!lv_add_segment(ah, m, 1, seg_lv(first_seg, m),
+					    get_segtype_from_string(lv->vg->cmd,
+								    "striped"),
+					    0, NULL, 0, 0, 0, NULL)) {
+				log_error("Aborting. Failed to extend %s.",
+					  seg_lv(first_seg, m)->name);
+				return 0;
+                	}
+		}
+		first_seg->area_len += extents;
+		first_seg->len += extents;
+		lv->le_count += extents;
+		lv->size += (uint64_t) extents *lv->vg->extent_size;
 	}
 
       out:
-	pool_destroy(scratch);
+	alloc_destroy(ah);
 	return r;
 }
 
-static char *_generate_lv_name(struct volume_group *vg, const char *format,
-			       char *buffer, size_t len)
+char *generate_lv_name(struct volume_group *vg, const char *format,
+		       char *buffer, size_t len)
 {
-	struct list *lvh;
-	struct logical_volume *lv;
+	struct lv_list *lvl;
 	int high = -1, i;
 
-	list_iterate(lvh, &vg->lvs) {
-		lv = (list_item(lvh, struct lv_list)->lv);
-
-		if (sscanf(lv->name, format, &i) != 1)
+	list_iterate_items(lvl, &vg->lvs) {
+		if (sscanf(lvl->lv->name, format, &i) != 1)
 			continue;
 
 		if (i > high)
@@ -540,11 +1046,15 @@
 	return buffer;
 }
 
+/*
+ * Create a new empty LV.
+ */
 struct logical_volume *lv_create_empty(struct format_instance *fi,
 				       const char *name,
-				       const char *name_format,
+				       union lvid *lvid,
 				       uint32_t status,
 				       alloc_policy_t alloc,
+				       int import,
 				       struct volume_group *vg)
 {
 	struct cmd_context *cmd = vg->cmd;
@@ -558,14 +1068,15 @@
 		return NULL;
 	}
 
-	if (!name && !(name = _generate_lv_name(vg, name_format, dname,
-						sizeof(dname)))) {
+	if (strstr(name, "%d") &&
+	    !(name = generate_lv_name(vg, name, dname, sizeof(dname)))) {
 		log_error("Failed to generate unique name for the new "
 			  "logical volume");
 		return NULL;
 	}
 
-	log_verbose("Creating logical volume %s", name);
+	if (!import)
+		log_verbose("Creating logical volume %s", name);
 
 	if (!(ll = pool_zalloc(cmd->mem, sizeof(*ll))) ||
 	    !(ll->lv = pool_zalloc(cmd->mem, sizeof(*ll->lv)))) {
@@ -592,9 +1103,14 @@
 	lv->minor = -1;
 	lv->size = UINT64_C(0);
 	lv->le_count = 0;
+	lv->snapshot = NULL;
+	list_init(&lv->snapshot_segs);
 	list_init(&lv->segments);
 	list_init(&lv->tags);
 
+	if (lvid)
+		lv->lvid = *lvid;
+
 	if (fi->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv)) {
 		stack;
 		if (ll)
@@ -602,150 +1118,10 @@
 		return NULL;
 	}
 
-	vg->lv_count++;
+	if (!import)
+		vg->lv_count++;
+
 	list_add(&vg->lvs, &ll->list);
 
 	return lv;
 }
-
-int lv_extend(struct format_instance *fid,
-	      struct logical_volume *lv,
-	      struct segment_type *segtype,
-	      uint32_t stripes, uint32_t stripe_size,
-	      uint32_t mirrors, uint32_t extents,
-	      struct physical_volume *mirrored_pv, uint32_t mirrored_pe,
-	      uint32_t status, struct list *allocatable_pvs,
-	      alloc_policy_t alloc)
-{
-	uint32_t old_le_count = lv->le_count;
-	uint64_t old_size = lv->size;
-
-	lv->le_count += extents;
-	lv->size += (uint64_t) extents *lv->vg->extent_size;
-
-	if (fid->fmt->ops->segtype_supported &&
-	    !fid->fmt->ops->segtype_supported(fid, segtype)) {
-		log_error("Metadata format (%s) does not support required "
-			  "LV segment type (%s).", fid->fmt->name,
-			  segtype->name);
-		log_error("Consider changing the metadata format by running "
-			  "vgconvert.");
-		return 0;
-	}
-
-	if (!_allocate(lv->vg, lv, allocatable_pvs, old_le_count, alloc,
-		       segtype, stripes, stripe_size, mirrors, mirrored_pv,
-		       mirrored_pe, status)) {
-		lv->le_count = old_le_count;
-		lv->size = old_size;
-		stack;
-		return 0;
-	}
-
-	if ((segtype->flags & SEG_CAN_SPLIT) && !lv_merge_segments(lv)) {
-		log_err("Couldn't merge segments after extending "
-			"logical volume.");
-		return 0;
-	}
-
-	if (fid->fmt->ops->lv_setup && !fid->fmt->ops->lv_setup(fid, lv)) {
-		stack;
-		return 0;
-	}
-
-	return 1;
-}
-
-int lv_reduce(struct format_instance *fi,
-	      struct logical_volume *lv, uint32_t extents)
-{
-	struct list *segh;
-	struct lv_segment *seg;
-	uint32_t count = extents;
-	int striped;
-
-	for (segh = lv->segments.p;
-	     (segh != &lv->segments) && count; segh = segh->p) {
-		seg = list_item(segh, struct lv_segment);
-
-		if (seg->len <= count) {
-			/* remove this segment completely */
-			count -= seg->len;
-			_put_extents(seg);
-			list_del(segh);
-		} else {
-			/* reduce this segment */
-			_put_extents(seg);
-			seg->len -= count;
-			striped = seg->segtype->flags & SEG_AREAS_STRIPED;
-			/* Caller must ensure exact divisibility */
-			if (striped && (count % seg->area_count)) {
-				log_error("Segment extent reduction %" PRIu32
-					  "not divisible by #stripes %" PRIu32,
-					  count, seg->area_count);
-				return 0;
-			}
-			seg->area_len -=
-			    count / (striped ? seg->area_count : 1);
-			_get_extents(seg);
-			count = 0;
-		}
-	}
-
-	lv->le_count -= extents;
-	lv->size = (uint64_t) lv->le_count * lv->vg->extent_size;
-	lv->vg->free_count += extents;
-
-	if (fi->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv)) {
-		stack;
-		return 0;
-	}
-
-	return 1;
-}
-
-int lv_remove(struct volume_group *vg, struct logical_volume *lv)
-{
-	struct list *segh;
-	struct lv_list *lvl;
-
-	/* find the lv list */
-	if (!(lvl = find_lv_in_vg(vg, lv->name))) {
-		stack;
-		return 0;
-	}
-
-	/* iterate through the lv's segments freeing off the pe's */
-	list_iterate(segh, &lv->segments)
-	    _put_extents(list_item(segh, struct lv_segment));
-
-	vg->lv_count--;
-	vg->free_count += lv->le_count;
-
-	list_del(&lvl->list);
-
-	return 1;
-}
-
-uint32_t find_free_lvnum(struct logical_volume *lv)
-{
-	int lvnum_used[MAX_RESTRICTED_LVS + 1];
-	uint32_t i = 0;
-	struct list *lvh;
-	struct lv_list *lvl;
-	int lvnum;
-
-	memset(&lvnum_used, 0, sizeof(lvnum_used));
-
-	list_iterate(lvh, &lv->vg->lvs) {
-		lvl = list_item(lvh, struct lv_list);
-		lvnum = lvnum_from_lvid(&lvl->lv->lvid);
-		if (lvnum <= MAX_RESTRICTED_LVS)
-			lvnum_used[lvnum] = 1;
-	}
-
-	while (lvnum_used[i])
-		i++;
-
-	return i;
-}

Modified: lvm2/trunk/lib/metadata/merge.c
==============================================================================
--- lvm2/trunk/lib/metadata/merge.c	(original)
+++ lvm2/trunk/lib/metadata/merge.c	Tue Jun 14 11:23:47 2005
@@ -17,6 +17,7 @@
 #include "metadata.h"
 #include "toolcontext.h"
 #include "lv_alloc.h"
+#include "pv_alloc.h"
 #include "str_list.h"
 #include "segtype.h"
 
@@ -57,11 +58,13 @@
 /*
  * Verify that an LV's segments are consecutive, complete and don't overlap.
  */
-int lv_check_segments(struct logical_volume *lv)
+int check_lv_segments(struct logical_volume *lv)
 {
 	struct lv_segment *seg;
 	uint32_t le = 0;
 	unsigned seg_count = 0;
+	int r = 1;
+	uint32_t area_multiplier, s;
 
 	list_iterate_items(seg, &lv->segments) {
 		seg_count++;
@@ -69,13 +72,58 @@
 			log_error("LV %s invalid: segment %u should begin at "
 				  "LE %" PRIu32 " (found %" PRIu32 ").",
 				  lv->name, seg_count, le, seg->le);
-			return 0;
+			r = 0;
+		}
+
+		area_multiplier = segtype_is_striped(seg->segtype) ? 
+					seg->area_count : 1;
+
+		if (seg->area_len * area_multiplier != seg->len) {
+			log_error("LV %s: segment %u has inconsistent "
+				  "area_len %u",
+				  lv->name, seg_count, seg->area_len);
+			r = 0;
+		}
+
+		for (s = 0; s < seg->area_count; s++) {
+			if (seg_type(seg, s) == AREA_PV) {
+				if (!seg_pvseg(seg, s) ||
+				    seg_pvseg(seg, s)->lvseg != seg ||
+				    seg_pvseg(seg, s)->lv_area != s) {
+					log_error("LV %s: segment %u has "
+						  "inconsistent PV area %u",
+						  lv->name, seg_count, s);
+					r = 0;
+				}
+			} else {
+				if (!seg_lv(seg, s) ||
+				    seg_lv(seg, s)->vg != lv->vg ||
+				    seg_lv(seg, s) == lv) {
+					log_error("LV %s: segment %u has "
+						  "inconsistent LV area %u",
+						  lv->name, seg_count, s);
+					r = 0;
+				}
+				if (seg_le(seg, s) != le) {
+					log_error("LV %s: segment %u has "
+						  "inconsistent LV area %u "
+						  "size",
+						  lv->name, seg_count, s);
+					r = 0;
+				}
+			}
 		}
 
 		le += seg->len;
 	}
 
-	return 1;
+	if (le != lv->le_count) {
+		log_error("LV %s: inconsistent LE count %u != %u",
+			  lv->name, le, lv->le_count);
+		r = 0;
+	}
+
+	return r;
 }
 
 /*
@@ -85,27 +133,29 @@
 static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
 			     uint32_t le)
 {
-	size_t len;
 	struct lv_segment *split_seg;
 	uint32_t s;
 	uint32_t offset = le - seg->le;
 	uint32_t area_offset;
 
-	if (!(seg->segtype->flags & SEG_CAN_SPLIT)) {
+	if (!seg_can_split(seg)) {
 		log_error("Unable to split the %s segment at LE %" PRIu32
 			  " in LV %s", seg->segtype->name, le, lv->name);
 		return 0;
 	}
 
 	/* Clone the existing segment */
-	if (!(split_seg = alloc_lv_segment(lv->vg->cmd->mem, seg->area_count))) {
-		log_error("Couldn't allocate new LV segment.");
+	if (!(split_seg = alloc_lv_segment(lv->vg->cmd->mem, seg->segtype,
+					   seg->lv, seg->le, seg->len,
+					   seg->status, seg->stripe_size,
+					   seg->log_lv,
+					   seg->area_count, seg->area_len,
+					   seg->chunk_size, seg->region_size,
+					   seg->extents_copied))) {
+		log_error("Couldn't allocate cloned LV segment.");
 		return 0;
 	}
 
-	len = sizeof(*seg) + (seg->area_count * sizeof(seg->area[0]));
-	memcpy(split_seg, seg, len);
-
 	if (!str_list_dup(lv->vg->cmd->mem, &split_seg->tags, &seg->tags)) {
 		log_error("LV segment tags duplication failed");
 		return 0;
@@ -113,45 +163,55 @@
 
 	/* In case of a striped segment, the offset has to be / stripes */
 	area_offset = offset;
-	if (seg->segtype->flags & SEG_AREAS_STRIPED)
+	if (seg_is_striped(seg))
 		area_offset /= seg->area_count;
 
+	split_seg->area_len -= area_offset;
+	seg->area_len = area_offset;
+
+	split_seg->len -= offset;
+	seg->len = offset;
+
+	split_seg->le = seg->le + seg->len;
+
 	/* Adjust the PV mapping */
 	for (s = 0; s < seg->area_count; s++) {
+		seg_type(split_seg, s) = seg_type(seg, s);
+
 		/* Split area at the offset */
-		switch (seg->area[s].type) {
+		switch (seg_type(seg, s)) {
 		case AREA_LV:
-			split_seg->area[s].u.lv.le =
-			    seg->area[s].u.lv.le + area_offset;
+			seg_lv(split_seg, s) = seg_lv(seg, s);
+			seg_le(split_seg, s) =
+			    seg_le(seg, s) + seg->area_len;
 			log_debug("Split %s:%u[%u] at %u: %s LE %u", lv->name,
-				  seg->le, s, le, seg->area[s].u.lv.lv->name,
-				  split_seg->area[s].u.lv.le);
+				  seg->le, s, le, seg_lv(seg, s)->name,
+				  seg_le(split_seg, s));
 			break;
 
 		case AREA_PV:
-			split_seg->area[s].u.pv.pe =
-			    seg->area[s].u.pv.pe + area_offset;
+			if (!assign_peg_to_lvseg(seg_pv(seg, s),
+						 seg_pe(seg, s) +
+						     seg->area_len,
+						 seg_pvseg(seg, s)->len -
+						     seg->area_len,
+						 split_seg, s)) {
+				stack;
+				return 0;
+			}
 			log_debug("Split %s:%u[%u] at %u: %s PE %u", lv->name,
 				  seg->le, s, le,
-				  dev_name(seg->area[s].u.pv.pv->dev),
-				  split_seg->area[s].u.pv.pe);
+				  dev_name(seg_dev(seg, s)),
+				  seg_pe(split_seg, s));
 			break;
 
 		default:
 			log_error("Unrecognised segment type %u",
-				  seg->area[s].type);
+				  seg_type(seg, s));
 			return 0;
 		}
 	}
 
-	split_seg->area_len -= area_offset;
-	seg->area_len = area_offset;
-
-	split_seg->len -= offset;
-	seg->len = offset;
-
-	split_seg->le = seg->le + seg->len;
-
 	/* Add split off segment to the list _after_ the original one */
 	list_add_h(&seg->list, &split_seg->list);
 

Modified: lvm2/trunk/lib/metadata/metadata.c
==============================================================================
--- lvm2/trunk/lib/metadata/metadata.c	(original)
+++ lvm2/trunk/lib/metadata/metadata.c	Tue Jun 14 11:23:47 2005
@@ -21,6 +21,8 @@
 #include "lvm-string.h"
 #include "lvmcache.h"
 #include "memlock.h"
+#include "str_list.h"
+#include "pv_alloc.h"
 
 static int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg,
 			 const char *pv_name)
@@ -99,9 +101,14 @@
 		return 0;
 	}
 
-	pvl->pv = pv;
+	if (!alloc_pv_segment_whole_pv(mem, pv)) {
+		stack;
+		return 0;
+	}
 
+	pvl->pv = pv;
 	list_add(&vg->pvs, &pvl->list);
+
 	vg->pv_count++;
 	vg->extent_count += pv->pe_count;
 	vg->free_count += pv->pe_count;
@@ -109,23 +116,70 @@
 	return 1;
 }
 
+static int _copy_pv(struct physical_volume *pv_to,
+		    struct physical_volume *pv_from)
+{
+	memcpy(pv_to, pv_from, sizeof(*pv_to));
+
+	if (!str_list_dup(pv_to->fmt->cmd->mem, &pv_to->tags, &pv_from->tags)) {
+		log_error("PV tags duplication failed");
+		return 0;
+	}
+
+	if (!peg_dup(pv_to->fmt->cmd->mem, &pv_to->segments,
+		     &pv_from->segments)) {
+		stack;
+		return 0;
+	}
+
+	return 1;
+}
+
+int get_pv_from_vg_by_id(const struct format_type *fmt, const char *vg_name,
+			 const char *id, struct physical_volume *pv)
+{
+	struct volume_group *vg;
+	struct pv_list *pvl;
+	int consistent = 0;
+
+	if (!(vg = vg_read(fmt->cmd, vg_name, &consistent))) {
+		log_error("get_pv_from_vg_by_id: vg_read failed to read VG %s",
+			  vg_name);
+		return 0;
+	}
+
+	if (!consistent)
+		log_error("Warning: Volume group %s is not consistent",
+			  vg_name);
+
+	list_iterate_items(pvl, &vg->pvs) {
+		if (id_equal(&pvl->pv->id, (const struct id *) id)) {
+			if (!_copy_pv(pv, pvl->pv)) {
+				stack;
+				return 0;
+			}
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
 int vg_rename(struct cmd_context *cmd, struct volume_group *vg,
 	      const char *new_name)
 {
 	struct pool *mem = cmd->mem;
-	struct physical_volume *pv;
-	struct list *pvh;
+	struct pv_list *pvl;
 
 	if (!(vg->name = pool_strdup(mem, new_name))) {
 		log_error("vg->name allocation failed for '%s'", new_name);
 		return 0;
 	}
 
-	list_iterate(pvh, &vg->pvs) {
-		pv = list_item(pvh, struct pv_list)->pv;
-		if (!(pv->vg_name = pool_strdup(mem, new_name))) {
+	list_iterate_items(pvl, &vg->pvs) {
+		if (!(pvl->pv->vg_name = pool_strdup(mem, new_name))) {
 			log_error("pv->vg_name allocation failed for '%s'",
-				  dev_name(pv->dev));
+				  dev_name(pvl->pv->dev));
 			return 0;
 		}
 	}
@@ -221,7 +275,6 @@
 	list_init(&vg->lvs);
 
 	vg->snapshot_count = 0;
-	list_init(&vg->snapshots);
 
 	list_init(&vg->tags);
 
@@ -249,6 +302,182 @@
 	return NULL;
 }
 
+static int _recalc_extents(uint32_t *extents, const char *desc1,
+			   const char *desc2, uint32_t old_size,
+			   uint32_t new_size)
+{
+	uint64_t size = (uint64_t) old_size * (*extents);
+
+	if (size % new_size) {
+		log_error("New size %" PRIu64 " for %s%s not an exact number "
+			  "of new extents.", size, desc1, desc2);
+		return 0;
+	}
+
+	size /= new_size;
+
+	if (size > UINT32_MAX) {
+		log_error("New extent count %" PRIu64 " for %s%s exceeds "
+			  "32 bits.", size, desc1, desc2);
+		return 0;
+	}
+
+	*extents = (uint32_t) size;
+
+	return 1;
+}
+
+int vg_change_pesize(struct cmd_context *cmd, struct volume_group *vg,
+		     uint32_t new_size)
+{
+	uint32_t old_size = vg->extent_size;
+	struct pv_list *pvl;
+	struct lv_list *lvl;
+	struct physical_volume *pv;
+	struct logical_volume *lv;
+	struct lv_segment *seg;
+	struct pv_segment *pvseg;
+	uint32_t s;
+
+	vg->extent_size = new_size;
+
+	if (vg->fid->fmt->ops->vg_setup &&
+	    !vg->fid->fmt->ops->vg_setup(vg->fid, vg)) {
+		stack;
+		return 0;
+	}
+
+	if (!_recalc_extents(&vg->extent_count, vg->name, "", old_size,
+			     new_size)) {
+		stack;
+		return 0;
+	}
+
+	if (!_recalc_extents(&vg->free_count, vg->name, " free space",
+			     old_size, new_size)) {
+		stack;
+		return 0;
+	}
+
+	/* foreach PV */
+	list_iterate_items(pvl, &vg->pvs) {
+		pv = pvl->pv;
+
+		pv->pe_size = new_size;
+		if (!_recalc_extents(&pv->pe_count, dev_name(pv->dev), "",
+				     old_size, new_size)) {
+			stack;
+			return 0;
+		}
+
+		if (!_recalc_extents(&pv->pe_alloc_count, dev_name(pv->dev),
+				     " allocated space", old_size, new_size)) {
+			stack;
+			return 0;
+		}
+
+		/* foreach free PV Segment */
+		list_iterate_items(pvseg, &pv->segments) {
+			if (pvseg->lvseg)
+				continue;
+
+			if (!_recalc_extents(&pvseg->pe, dev_name(pv->dev),
+					     " PV segment start", old_size,
+					     new_size)) {
+				stack;
+				return 0;
+			}
+			if (!_recalc_extents(&pvseg->len, dev_name(pv->dev),
+					     " PV segment length", old_size,
+					     new_size)) {
+				stack;
+				return 0;
+			}
+		}
+	}
+
+	/* foreach LV */
+	list_iterate_items(lvl, &vg->lvs) {
+		lv = lvl->lv;
+
+		if (!_recalc_extents(&lv->le_count, lv->name, "", old_size,
+				     new_size)) {
+			stack;
+			return 0;
+		}
+
+		list_iterate_items(seg, &lv->segments) {
+			if (!_recalc_extents(&seg->le, lv->name,
+					     " segment start", old_size,
+					     new_size)) {
+				stack;
+				return 0;
+			}
+
+			if (!_recalc_extents(&seg->len, lv->name,
+					     " segment length", old_size,
+					     new_size)) {
+				stack;
+				return 0;
+			}
+
+			if (!_recalc_extents(&seg->area_len, lv->name,
+					     " area length", old_size,
+					     new_size)) {
+				stack;
+				return 0;
+			}
+
+			if (!_recalc_extents(&seg->extents_copied, lv->name,
+					     " extents moved", old_size,
+					     new_size)) {
+				stack;
+				return 0;
+			}
+
+			/* foreach area */
+			for (s = 0; s < seg->area_count; s++) {
+				switch (seg_type(seg, s)) {
+				case AREA_PV:
+					if (!_recalc_extents
+					    (&seg_pe(seg, s),
+					     lv->name,
+					     " pvseg start", old_size,
+					     new_size)) {
+						stack;
+						return 0;
+					}
+					if (!_recalc_extents
+					    (&seg_pvseg(seg, s)->len,
+					     lv->name,
+					     " pvseg length", old_size,
+					     new_size)) {
+						stack;
+						return 0;
+					}
+					break;
+				case AREA_LV:
+					if (!_recalc_extents
+					    (&seg_le(seg, s), lv->name,
+					     " area start", old_size,
+					     new_size)) {
+						stack;
+						return 0;
+					}
+					break;
+				default:
+					log_error("Unrecognised segment type "
+						  "%u", seg_type(seg, s));
+					return 0;
+				}
+			}
+		}
+
+	}
+
+	return 1;
+}
+
 /* Sizes in sectors */
 struct physical_volume *pv_create(const struct format_type *fmt,
 				  struct device *dev,
@@ -311,6 +540,7 @@
 	pv->fmt = fmt;
 
 	list_init(&pv->tags);
+	list_init(&pv->segments);
 
 	if (!fmt->ops->pv_setup(fmt, pe_start, existing_extent_count,
 				existing_extent_size,
@@ -329,26 +559,22 @@
 
 struct pv_list *find_pv_in_vg(struct volume_group *vg, const char *pv_name)
 {
-	struct list *pvh;
 	struct pv_list *pvl;
 
-	list_iterate(pvh, &vg->pvs) {
-		pvl = list_item(pvh, struct pv_list);
+	list_iterate_items(pvl, &vg->pvs)
 		if (pvl->pv->dev == dev_cache_get(pv_name, vg->cmd->filter))
 			return pvl;
-	}
 
 	return NULL;
 }
 
 int pv_is_in_vg(struct volume_group *vg, struct physical_volume *pv)
 {
-	struct list *pvh;
+	struct pv_list *pvl;
 
-	list_iterate(pvh, &vg->pvs) {
-		if (pv == list_item(pvh, struct pv_list)->pv)
+	list_iterate_items(pvl, &vg->pvs)
+		if (pv == pvl->pv)
 			 return 1;
-	}
 
 	return 0;
 }
@@ -356,21 +582,17 @@
 struct physical_volume *find_pv_in_vg_by_uuid(struct volume_group *vg,
 					      struct id *id)
 {
-	struct list *pvh;
 	struct pv_list *pvl;
 
-	list_iterate(pvh, &vg->pvs) {
-		pvl = list_item(pvh, struct pv_list);
+	list_iterate_items(pvl, &vg->pvs)
 		if (id_equal(&pvl->pv->id, id))
 			return pvl->pv;
-	}
 
 	return NULL;
 }
 
 struct lv_list *find_lv_in_vg(struct volume_group *vg, const char *lv_name)
 {
-	struct list *lvh;
 	struct lv_list *lvl;
 	const char *ptr;
 
@@ -380,11 +602,9 @@
 	else
 		ptr = lv_name;
 
-	list_iterate(lvh, &vg->lvs) {
-		lvl = list_item(lvh, struct lv_list);
+	list_iterate_items(lvl, &vg->lvs)
 		if (!strcmp(lvl->lv->name, ptr))
 			return lvl;
-	}
 
 	return NULL;
 }
@@ -392,14 +612,11 @@
 struct lv_list *find_lv_in_vg_by_lvid(struct volume_group *vg,
 				      const union lvid *lvid)
 {
-	struct list *lvh;
 	struct lv_list *lvl;
 
-	list_iterate(lvh, &vg->lvs) {
-		lvl = list_item(lvh, struct lv_list);
+	list_iterate_items(lvl, &vg->lvs)
 		if (!strncmp(lvl->lv->lvid.s, lvid->s, sizeof(*lvid)))
 			return lvl;
-	}
 
 	return NULL;
 }
@@ -412,15 +629,12 @@
 
 struct physical_volume *find_pv(struct volume_group *vg, struct device *dev)
 {
-	struct list *pvh;
-	struct physical_volume *pv;
+	struct pv_list *pvl;
 
-	list_iterate(pvh, &vg->pvs) {
-		pv = list_item(pvh, struct pv_list)->pv;
+	list_iterate_items(pvl, &vg->pvs)
+		if (dev == pvl->pv->dev)
+			return pvl->pv;
 
-		if (dev == pv->dev)
-			return pv;
-	}
 	return NULL;
 }
 
@@ -445,27 +659,34 @@
 /* Find segment at a given logical extent in an LV */
 struct lv_segment *find_seg_by_le(struct logical_volume *lv, uint32_t le)
 {
-	struct list *segh;
 	struct lv_segment *seg;
 
-	list_iterate(segh, &lv->segments) {
-		seg = list_item(segh, struct lv_segment);
+	list_iterate_items(seg, &lv->segments)
 		if (le >= seg->le && le < seg->le + seg->len)
 			return seg;
-	}
+
+	return NULL;
+}
+
+/* Find segment at a given physical extent in a PV */
+struct pv_segment *find_peg_by_pe(struct physical_volume *pv, uint32_t pe)
+{
+	struct pv_segment *peg;
+
+	list_iterate_items(peg, &pv->segments)
+		if (pe >= peg->pe && pe < peg->pe + peg->len)
+			return peg;
 
 	return NULL;
 }
 
 int vg_remove(struct volume_group *vg)
 {
-	struct list *mdah;
 	struct metadata_area *mda;
 
 	/* FIXME Improve recovery situation? */
 	/* Remove each copy of the metadata */
-	list_iterate(mdah, &vg->fid->metadata_areas) {
-		mda = list_item(mdah, struct metadata_area);
+	list_iterate_items(mda, &vg->fid->metadata_areas) {
 		if (mda->ops->vg_remove &&
 		    !mda->ops->vg_remove(vg->fid, vg, mda)) {
 			stack;
@@ -482,8 +703,23 @@
  */
 int vg_write(struct volume_group *vg)
 {
-	struct list *mdah, *mdah2;
+	struct list *mdah;
 	struct metadata_area *mda;
+	struct lv_list *lvl;
+
+	if (!check_pv_segments(vg)) {
+		log_error("Internal error: PV segments corrupted in %s.",
+			  vg->name);
+		return 0;
+	}
+
+	list_iterate_items(lvl, &vg->lvs) {
+		if (!check_lv_segments(lvl->lv)) {
+			log_error("Internal error: LV segments corrupted in %s.",
+				  lvl->lv->name);
+			return 0;
+		}
+	}
 
 	if (vg->status & PARTIAL_VG) {
 		log_error("Cannot change metadata for partial volume group %s",
@@ -499,14 +735,14 @@
 	vg->seqno++;
 
 	/* Write to each copy of the metadata area */
-	list_iterate(mdah, &vg->fid->metadata_areas) {
-		mda = list_item(mdah, struct metadata_area);
+	list_iterate_items(mda, &vg->fid->metadata_areas) {
 		if (!mda->ops->vg_write) {
 			log_error("Format does not support writing volume"
 				  "group metadata areas");
 			/* Revert */
-			list_uniterate(mdah2, &vg->fid->metadata_areas, mdah) {
-				mda = list_item(mdah2, struct metadata_area);
+			list_uniterate(mdah, &vg->fid->metadata_areas, &mda->list) {
+				mda = list_item(mdah, struct metadata_area);
+
 				if (mda->ops->vg_revert &&
 				    !mda->ops->vg_revert(vg->fid, vg, mda)) {
 					stack;
@@ -517,8 +753,25 @@
 		if (!mda->ops->vg_write(vg->fid, vg, mda)) {
 			stack;
 			/* Revert */
-			list_uniterate(mdah2, &vg->fid->metadata_areas, mdah) {
-				mda = list_item(mdah2, struct metadata_area);
+			list_uniterate(mdah, &vg->fid->metadata_areas, &mda->list) {
+				mda = list_item(mdah, struct metadata_area);
+
+				if (mda->ops->vg_revert &&
+				    !mda->ops->vg_revert(vg->fid, vg, mda)) {
+					stack;
+				}
+			}
+			return 0;
+		}
+	}
+
+	/* Now pre-commit each copy of the new metadata */
+	list_iterate_items(mda, &vg->fid->metadata_areas) {
+		if (mda->ops->vg_precommit &&
+		    !mda->ops->vg_precommit(vg->fid, vg, mda)) {
+			stack;
+			/* Revert */
+			list_iterate_items(mda, &vg->fid->metadata_areas) {
 				if (mda->ops->vg_revert &&
 				    !mda->ops->vg_revert(vg->fid, vg, mda)) {
 					stack;
@@ -534,14 +787,12 @@
 /* Commit pending changes */
 int vg_commit(struct volume_group *vg)
 {
-	struct list *mdah;
 	struct metadata_area *mda;
 	int cache_updated = 0;
 	int failed = 0;
 
 	/* Commit to each copy of the metadata area */
-	list_iterate(mdah, &vg->fid->metadata_areas) {
-		mda = list_item(mdah, struct metadata_area);
+	list_iterate_items(mda, &vg->fid->metadata_areas) {
 		failed = 0;
 		if (mda->ops->vg_commit &&
 		    !mda->ops->vg_commit(vg->fid, vg, mda)) {
@@ -553,7 +804,6 @@
 			lvmcache_update_vg(vg);
 			cache_updated = 1;
 		}
-
 	}
 
 	/* If at least one mda commit succeeded, it was committed */
@@ -563,11 +813,9 @@
 /* Don't commit any pending changes */
 int vg_revert(struct volume_group *vg)
 {
-	struct list *mdah;
 	struct metadata_area *mda;
 
-	list_iterate(mdah, &vg->fid->metadata_areas) {
-		mda = list_item(mdah, struct metadata_area);
+	list_iterate_items(mda, &vg->fid->metadata_areas) {
 		if (mda->ops->vg_revert &&
 		    !mda->ops->vg_revert(vg->fid, vg, mda)) {
 			stack;
@@ -581,8 +829,7 @@
 static struct volume_group *_vg_read_orphans(struct cmd_context *cmd)
 {
 	struct lvmcache_vginfo *vginfo;
-	struct list *ih;
-	struct device *dev;
+	struct lvmcache_info *info;
 	struct pv_list *pvl;
 	struct volume_group *vg;
 	struct physical_volume *pv;
@@ -598,7 +845,6 @@
 	}
 	list_init(&vg->pvs);
 	list_init(&vg->lvs);
-	list_init(&vg->snapshots);
 	list_init(&vg->tags);
 	vg->cmd = cmd;
 	if (!(vg->name = pool_strdup(cmd->mem, ORPHAN))) {
@@ -606,9 +852,8 @@
 		return NULL;
 	}
 
-	list_iterate(ih, &vginfo->infos) {
-		dev = list_item(ih, struct lvmcache_info)->dev;
-		if (!(pv = pv_read(cmd, dev_name(dev), NULL, NULL, 1))) {
+	list_iterate_items(info, &vginfo->infos) {
+		if (!(pv = pv_read(cmd, dev_name(info->dev), NULL, NULL, 1))) {
 			continue;
 		}
 		if (!(pvl = pool_zalloc(cmd->mem, sizeof(*pvl)))) {
@@ -630,17 +875,22 @@
  * and take appropriate action if it isn't (e.g. abort; get write lock 
  * and call vg_read again).
  */
-struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
-			     int *consistent)
+static struct volume_group *_vg_read(struct cmd_context *cmd,
+				     const char *vgname,
+				     int *consistent, int precommitted)
 {
 	struct format_instance *fid;
 	const struct format_type *fmt;
 	struct volume_group *vg, *correct_vg = NULL;
-	struct list *mdah;
 	struct metadata_area *mda;
 	int inconsistent = 0;
 
 	if (!*vgname) {
+		if (precommitted) {
+			log_error("Internal error: vg_read requires vgname "
+				  "with pre-commit.");
+			return NULL;
+		}
 		*consistent = 1;
 		return _vg_read_orphans(cmd);
 	}
@@ -654,7 +904,7 @@
 				stack;
 				return NULL;
 			}
-			lvmcache_label_scan(cmd, 1);
+			lvmcache_label_scan(cmd, 2);
 			if (!(fmt = fmt_from_vgname(vgname))) {
 				stack;
 				return NULL;
@@ -662,6 +912,12 @@
 		}
 	}
 
+	if (precommitted && !(fmt->features & FMT_PRECOMMIT)) {
+		log_error("Internal error: %s doesn't support "
+			  "pre-commit", fmt->name);
+		return NULL;
+	}
+
 	/* create format instance with appropriate metadata area */
 	if (!(fid = fmt->ops->create_instance(fmt, vgname, NULL))) {
 		log_error("Failed to create format instance");
@@ -669,9 +925,11 @@
 	}
 
 	/* Ensure contents of all metadata areas match - else do recovery */
-	list_iterate(mdah, &fid->metadata_areas) {
-		mda = list_item(mdah, struct metadata_area);
-		if (!(vg = mda->ops->vg_read(fid, vgname, mda))) {
+	list_iterate_items(mda, &fid->metadata_areas) {
+		if ((precommitted &&
+		     !(vg = mda->ops->vg_read_precommit(fid, vgname, mda))) ||
+		    (!precommitted &&
+		     !(vg = mda->ops->vg_read(fid, vgname, mda)))) {
 			inconsistent = 1;
 			continue;
 		}
@@ -687,15 +945,66 @@
 		}
 	}
 
-	/* Failed to find VG */
+	/* Failed to find VG where we expected it - full scan and retry */
 	if (!correct_vg) {
-		stack;
-		return NULL;
+		inconsistent = 0;
+
+		lvmcache_label_scan(cmd, 2);
+		if (!(fmt = fmt_from_vgname(vgname))) {
+			stack;
+			return NULL;
+		}
+
+		if (precommitted && !(fmt->features & FMT_PRECOMMIT)) {
+			log_error("Internal error: %s doesn't support "
+				  "pre-commit", fmt->name);
+			return NULL;
+		}
+
+		/* create format instance with appropriate metadata area */
+		if (!(fid = fmt->ops->create_instance(fmt, vgname, NULL))) {
+			log_error("Failed to create format instance");
+			return NULL;
+		}
+
+		/* Ensure contents of all metadata areas match - else recover */
+		list_iterate_items(mda, &fid->metadata_areas) {
+			if ((precommitted &&
+			     !(vg = mda->ops->vg_read_precommit(fid, vgname,
+								mda))) ||
+			    (!precommitted &&
+			     !(vg = mda->ops->vg_read(fid, vgname, mda)))) {
+				inconsistent = 1;
+				continue;
+			}
+			if (!correct_vg) {
+				correct_vg = vg;
+				continue;
+			}
+			/* FIXME Also ensure contents same - checksums same? */
+			if (correct_vg->seqno != vg->seqno) {
+				inconsistent = 1;
+				if (vg->seqno > correct_vg->seqno)
+					correct_vg = vg;
+			}
+		}
+
+		/* Give up looking */
+		if (!correct_vg) {
+			stack;
+			return NULL;
+		}
 	}
 
 	lvmcache_update_vg(correct_vg);
 
 	if (inconsistent) {
+		if (precommitted) {
+			log_error("Inconsistent pre-commit metadata copies "
+				  "for volume group %s", vgname);
+			return NULL;
+		}
+
 		if (!*consistent)
 			return correct_vg;
 
@@ -733,6 +1042,19 @@
 	return correct_vg;
 }
 
+struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
+			     int *consistent)
+{
+	return _vg_read(cmd, vgname, consistent, 0);
+}
+
+struct volume_group *vg_read_precommitted(struct cmd_context *cmd,
+					  const char *vgname,
+					  int *consistent)
+{
+	return _vg_read(cmd, vgname, consistent, 1);
+}
+
 /* This is only called by lv_from_lvid, which is only called from 
  * activate.c so we know the appropriate VG lock is already held and 
  * the vg_read is therefore safe.
@@ -740,9 +1062,10 @@
 struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid)
 {
 	const char *vgname;
-	struct list *vgnames, *slh;
+	struct list *vgnames;
 	struct volume_group *vg;
 	struct lvmcache_vginfo *vginfo;
+	struct str_list *strl;
 	int consistent = 0;
 
 	/* Is corresponding vgname already cached? */
@@ -768,13 +1091,13 @@
 	 *       allowed to do a full scan here any more. */
 
 	// The slow way - full scan required to cope with vgrename 
-	if (!(vgnames = get_vgs(cmd, 1))) {
+	if (!(vgnames = get_vgs(cmd, 2))) {
 		log_error("vg_read_by_vgid: get_vgs failed");
 		return NULL;
 	}
 
-	list_iterate(slh, vgnames) {
-		vgname = list_item(slh, struct str_list)->str;
+	list_iterate_items(strl, vgnames) {
+		vgname = strl->str;
 		if (!vgname || !*vgname)
 			continue;	// FIXME Unnecessary? 
 		consistent = 0;
@@ -832,14 +1155,14 @@
 
 	if (!(dev = dev_cache_get(pv_name, cmd->filter))) {
 		stack;
-		return 0;
+		return NULL;
 	}
 
 	if (!(label_read(dev, &label))) {
 		if (warnings)
 			log_error("No physical volume label read from %s",
 				  pv_name);
-		return 0;
+		return NULL;
 	}
 
 	info = (struct lvmcache_info *) label->info;
@@ -848,22 +1171,28 @@
 
 	if (!(pv = pool_zalloc(cmd->mem, sizeof(*pv)))) {
 		log_error("pv allocation for '%s' failed", pv_name);
-		return 0;
+		return NULL;
 	}
 
 	list_init(&pv->tags);
+	list_init(&pv->segments);
 
 	/* FIXME Move more common code up here */
 	if (!(info->fmt->ops->pv_read(info->fmt, pv_name, pv, mdas))) {
 		log_error("Failed to read existing physical volume '%s'",
 			  pv_name);
-		return 0;
+		return NULL;
 	}
 
 	if (!pv->size)
 		return NULL;
-	else
-		return pv;
+	
+	if (!alloc_pv_segment_whole_pv(cmd->mem, pv)) {
+		stack;
+		return NULL;
+	}
+
+	return pv;
 }
 
 /* May return empty list */
@@ -874,10 +1203,11 @@
 
 struct list *get_pvs(struct cmd_context *cmd)
 {
+	struct str_list *strl;
 	struct list *results;
 	const char *vgname;
 	struct list *pvh, *tmp;
-	struct list *vgnames, *slh;
+	struct list *vgnames;
 	struct volume_group *vg;
 	int consistent = 0;
 	int old_partial;
@@ -904,8 +1234,8 @@
 	old_pvmove = pvmove_mode();
 	init_partial(1);
 	init_pvmove(1);
-	list_iterate(slh, vgnames) {
-		vgname = list_item(slh, struct str_list)->str;
+	list_iterate_items(strl, vgnames) {
+		vgname = strl->str;
 		if (!vgname)
 			continue;	/* FIXME Unnecessary? */
 		consistent = 0;

Modified: lvm2/trunk/lib/metadata/metadata.h
==============================================================================
--- lvm2/trunk/lib/metadata/metadata.h	(original)
+++ lvm2/trunk/lib/metadata/metadata.h	Tue Jun 14 11:23:47 2005
@@ -50,11 +50,13 @@
 #define VISIBLE_LV		0x00000040	/* LV */
 #define FIXED_MINOR		0x00000080	/* LV */
 /* FIXME Remove when metadata restructuring is completed */
-#define SNAPSHOT		0x00001000	/* LV - tmp internal use only */
+#define SNAPSHOT		0x00001000	/* LV - internal use only */
 #define PVMOVE			0x00002000	/* VG LV SEG */
 #define LOCKED			0x00004000	/* LV */
 #define MIRRORED		0x00008000	/* LV - internal use only */
 #define VIRTUAL			0x00010000	/* LV - internal use only */
+#define MIRROR_LOG		0x00020000	/* LV */
+#define MIRROR_IMAGE		0x00040000	/* LV */
 
 #define LVM_READ              	0x00000100	/* LV VG */
 #define LVM_WRITE             	0x00000200	/* LV VG */
@@ -68,6 +70,7 @@
 #define FMT_UNLIMITED_VOLS	0x00000008	/* Unlimited PVs/LVs? */
 #define FMT_RESTRICTED_LVIDS	0x00000010	/* LVID <= 255 */
 #define FMT_ORPHAN_ALLOCATABLE	0x00000020	/* Orphan PV allocatable? */
+#define FMT_PRECOMMIT		0x00000040	/* Supports pre-commit? */
 
 typedef enum {
 	ALLOC_INVALID,
@@ -98,6 +101,18 @@
 	void *private;
 };
 
+struct pv_segment {
+	struct list list;	/* Member of pv->segments: ordered list
+				 * covering entire data area on this PV */
+
+	struct physical_volume *pv;
+	uint32_t pe;
+	uint32_t len;
+
+	struct lv_segment *lvseg;	/* NULL if free space */
+	uint32_t lv_area;	/* Index to area in LV segment */
+};
+
 struct physical_volume {
 	struct id id;
 	struct device *dev;
@@ -113,6 +128,7 @@
 	uint32_t pe_count;
 	uint32_t pe_alloc_count;
 
+	struct list segments;	/* Ordered pv_segments covering complete PV */
 	struct list tags;
 };
 
@@ -124,6 +140,9 @@
 	struct volume_group *(*vg_read) (struct format_instance * fi,
 					 const char *vg_name,
 					 struct metadata_area * mda);
+	struct volume_group *(*vg_read_precommit) (struct format_instance * fi,
+					 const char *vg_name,
+					 struct metadata_area * mda);
 	/*
 	 * Write out complete VG metadata.  You must ensure internal
 	 * consistency before calling. eg. PEs can't refer to PVs not
@@ -140,6 +159,9 @@
 	 */
 	int (*vg_write) (struct format_instance * fid, struct volume_group * vg,
 			 struct metadata_area * mda);
+	int (*vg_precommit) (struct format_instance * fid,
+			     struct volume_group * vg,
+			     struct metadata_area * mda);
 	int (*vg_commit) (struct format_instance * fid,
 			  struct volume_group * vg, struct metadata_area * mda);
 	int (*vg_revert) (struct format_instance * fid,
@@ -184,11 +206,8 @@
 
 	/* logical volumes */
 	uint32_t lv_count;
-	struct list lvs;
-
-	/* snapshots */
 	uint32_t snapshot_count;
-	struct list snapshots;
+	struct list lvs;
 
 	struct list tags;
 };
@@ -210,8 +229,11 @@
 	uint32_t area_len;
 	struct logical_volume *origin;
 	struct logical_volume *cow;
-	uint32_t chunk_size;
+	struct list origin_list;
+	uint32_t chunk_size;	/* For snapshots - in sectors */
+	uint32_t region_size;	/* For mirrors - in sectors */
 	uint32_t extents_copied;
+	struct logical_volume *log_lv;
 
 	struct list tags;
 
@@ -220,8 +242,7 @@
 		area_type_t type;
 		union {
 			struct {
-				struct physical_volume *pv;
-				uint32_t pe;
+				struct pv_segment *pvseg;
 			} pv;
 			struct {
 				struct logical_volume *lv;
@@ -231,6 +252,14 @@
 	} area[0];
 };
 
+#define seg_type(seg, s)	(seg)->area[(s)].type
+#define seg_pvseg(seg, s)	(seg)->area[(s)].u.pv.pvseg
+#define seg_pv(seg, s)		(seg)->area[(s)].u.pv.pvseg->pv
+#define seg_dev(seg, s)		(seg)->area[(s)].u.pv.pvseg->pv->dev
+#define seg_pe(seg, s)		(seg)->area[(s)].u.pv.pvseg->pe
+#define seg_lv(seg, s)		(seg)->area[(s)].u.lv.lv
+#define seg_le(seg, s)		(seg)->area[(s)].u.lv.le
+
 struct logical_volume {
 	union lvid lvid;
 	char *name;
@@ -246,21 +275,14 @@
 	uint64_t size;
 	uint32_t le_count;
 
+	uint32_t origin_count;
+	struct list snapshot_segs;
+	struct lv_segment *snapshot;
+
 	struct list segments;
 	struct list tags;
 };
 
-struct snapshot {
-	struct id id;
-
-	int persistent;		/* boolean */
-	uint32_t chunk_size;	/* in 512 byte sectors */
-	uint32_t le_count;
-
-	struct logical_volume *origin;
-	struct logical_volume *cow;
-};
-
 struct name_list {
 	struct list list;
 	char *name;
@@ -284,15 +306,14 @@
 	struct logical_volume *lv;
 };
 
-struct snapshot_list {
+struct mda_list {
 	struct list list;
-
-	struct snapshot *snapshot;
+	struct device_area mda;
 };
 
-struct mda_list {
+struct peg_list {
 	struct list list;
-	struct device_area mda;
+	struct pv_segment *peg;
 };
 
 /*
@@ -374,6 +395,9 @@
 int vg_revert(struct volume_group *vg);
 struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name,
 			     int *consistent);
+struct volume_group *vg_read_precommitted(struct cmd_context *cmd,
+					  const char *vg_name,
+					  int *consistent);
 struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid);
 struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
 				struct list *mdas, uint64_t *label_sector,
@@ -407,20 +431,23 @@
 	      const char *new_name);
 int vg_extend(struct format_instance *fi, struct volume_group *vg,
 	      int pv_count, char **pv_names);
+int vg_change_pesize(struct cmd_context *cmd, struct volume_group *vg,
+		     uint32_t new_extent_size);
 
 /* Manipulate LVs */
 struct logical_volume *lv_create_empty(struct format_instance *fi,
 				       const char *name,
-				       const char *name_format,
+				       union lvid *lvid,
 				       uint32_t status,
 				       alloc_policy_t alloc,
+				       int import,
 				       struct volume_group *vg);
 
-int lv_reduce(struct format_instance *fi,
-	      struct logical_volume *lv, uint32_t extents);
+/* Entry point for all LV extent reductions */
+int lv_reduce(struct logical_volume *lv, uint32_t extents);
 
-int lv_extend(struct format_instance *fid,
-	      struct logical_volume *lv,
+/* Entry point for all LV extent allocations */
+int lv_extend(struct logical_volume *lv,
 	      struct segment_type *segtype,
 	      uint32_t stripes, uint32_t stripe_size,
 	      uint32_t mirrors, uint32_t extents,
@@ -428,8 +455,8 @@
 	      uint32_t status, struct list *allocatable_pvs,
 	      alloc_policy_t alloc);
 
-/* lv must be part of vg->lvs */
-int lv_remove(struct volume_group *vg, struct logical_volume *lv);
+/* lv must be part of lv->vg->lvs */
+int lv_remove(struct logical_volume *lv);
 
 /* Manipulate PV structures */
 int pv_add(struct volume_group *vg, struct physical_volume *pv);
@@ -440,6 +467,8 @@
 struct pv_list *find_pv_in_vg(struct volume_group *vg, const char *pv_name);
 struct physical_volume *find_pv_in_vg_by_uuid(struct volume_group *vg,
 					      struct id *id);
+int get_pv_from_vg_by_id(const struct format_type *fmt, const char *vg_name,
+			 const char *id, struct physical_volume *pv);
 
 /* Find an LV within a given VG */
 struct lv_list *find_lv_in_vg(struct volume_group *vg, const char *lv_name);
@@ -463,6 +492,9 @@
 /* Find LV segment containing given LE */
 struct lv_segment *find_seg_by_le(struct logical_volume *lv, uint32_t le);
 
+/* Find PV segment containing given LE */
+struct pv_segment *find_peg_by_pe(struct physical_volume *pv, uint32_t pe);
+
 /*
  * Remove a dev_dir if present.
  */
@@ -471,7 +503,7 @@
 /*
  * Checks that an lv has no gaps or overlapping segments.
  */
-int lv_check_segments(struct logical_volume *lv);
+int check_lv_segments(struct logical_volume *lv);
 
 /*
  * Sometimes (eg, after an lvextend), it is possible to merge two
@@ -493,24 +525,34 @@
 
 int pv_is_in_vg(struct volume_group *vg, struct physical_volume *pv);
 
-struct snapshot *find_cow(const struct logical_volume *lv);
-struct snapshot *find_origin(const struct logical_volume *lv);
-struct list *find_snapshots(const struct logical_volume *lv);
+struct lv_segment *find_cow(const struct logical_volume *lv);
 
-int vg_add_snapshot(struct logical_volume *origin, struct logical_volume *cow,
-		    int persistent, struct id *id, uint32_t extent_count,
+int vg_add_snapshot(struct format_instance *fid, const char *name,
+		    struct logical_volume *origin, struct logical_volume *cow,
+		    union lvid *lvid, uint32_t extent_count,
 		    uint32_t chunk_size);
 
-int vg_remove_snapshot(struct volume_group *vg, struct logical_volume *cow);
+int vg_remove_snapshot(struct logical_volume *cow);
+
 
 /*
  * Mirroring functions
  */
+struct alloc_handle;
+int create_mirror_layers(struct alloc_handle *ah,
+			 uint32_t first_area,
+			 uint32_t num_mirrors,
+			 struct logical_volume *lv,
+			 struct segment_type *segtype,
+			 uint32_t status,
+			 uint32_t region_size,
+			 struct logical_volume *log_lv);
 int insert_pvmove_mirrors(struct cmd_context *cmd,
 			  struct logical_volume *lv_mirr,
 			  struct list *source_pvl,
 			  struct logical_volume *lv,
 			  struct list *allocatable_pvs,
+			  alloc_policy_t alloc,
 			  struct list *lvs_changed);
 int remove_pvmove_mirrors(struct volume_group *vg,
 			  struct logical_volume *lv_mirr);
@@ -527,6 +569,8 @@
 			  struct logical_volume *lv);
 
 uint32_t find_free_lvnum(struct logical_volume *lv);
+char *generate_lv_name(struct volume_group *vg, const char *format,
+		       char *buffer, size_t len);
 
 static inline int validate_name(const char *n)
 {
@@ -540,6 +584,9 @@
 	if (*n == '-')
 		return 0;
 
+	if (!strcmp(n, ".") || !strcmp(n, ".."))
+		return 0;
+
 	while ((len++, c = *n++))
 		if (!isalnum(c) && c != '.' && c != '_' && c != '-' && c != '+')
 			return 0;

Modified: lvm2/trunk/lib/metadata/mirror.c
==============================================================================
--- lvm2/trunk/lib/metadata/mirror.c	(original)
+++ lvm2/trunk/lib/metadata/mirror.c	Tue Jun 14 11:23:47 2005
@@ -19,6 +19,142 @@
 #include "segtype.h"
 #include "display.h"
 #include "activate.h"
+#include "lv_alloc.h"
+#include "lvm-string.h"
+
+/*
+ * Reduce mirrored_seg to num_mirrors images.
+ */
+int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors)
+{
+	uint32_t m;
+
+	for (m = num_mirrors; m < mirrored_seg->area_count; m++) {
+		if (!lv_remove(seg_lv(mirrored_seg, m))) {
+			stack;
+			return 0;
+		}
+	}
+
+	mirrored_seg->area_count = num_mirrors;
+
+	return 1;
+}
+
+int remove_all_mirror_images(struct logical_volume *lv)
+{
+	struct lv_segment *first_seg, *seg;
+	struct logical_volume *lv1;
+
+	list_iterate_items(first_seg, &lv->segments)
+		break;
+
+	if (!remove_mirror_images(first_seg, 1)) {
+		stack;
+		return 0;
+	}
+
+	if (!lv_remove(first_seg->log_lv)) {
+		stack;
+		return 0;
+	}
+
+	lv1 = seg_lv(first_seg, 0);
+
+	lv->segments = lv1->segments;
+	lv->segments.n->p = &lv->segments;
+	lv->segments.p->n = &lv->segments;
+
+	list_init(&lv1->segments);
+	lv1->le_count = 0;
+	lv1->size = 0;
+	if (!lv_remove(lv1)) {
+		stack;
+		return 0;
+	}
+
+	lv->status &= ~MIRRORED;
+
+	list_iterate_items(seg, &lv->segments)
+		seg->lv = lv;
+
+	return 1;
+}
+
+/*
+ * Add mirror images to an existing mirror
+ */
+/* FIXME
+int add_mirror_images(struct alloc_handle *ah,
+		      uint32_t first_area,
+		      uint32_t num_areas,
+		      struct logical_volume *lv)
+{
+}
+*/
+
+int create_mirror_layers(struct alloc_handle *ah,
+			 uint32_t first_area,
+			 uint32_t num_mirrors,
+			 struct logical_volume *lv,
+			 struct segment_type *segtype,
+			 uint32_t status,
+			 uint32_t region_size,
+			 struct logical_volume *log_lv)
+{
+	uint32_t m;
+	struct logical_volume **img_lvs;
+	char *img_name;
+	size_t len;
+	
+	if (!(img_lvs = alloca(sizeof(*img_lvs) * num_mirrors))) {
+		log_error("img_lvs allocation failed. "
+			  "Remove new LV and retry.");
+		return 0;
+	}
+
+	len = strlen(lv->name) + 32;
+	if (!(img_name = alloca(len))) {
+		log_error("img_name allocation failed. "
+			  "Remove new LV and retry.");
+		return 0;
+	}
+
+	if (lvm_snprintf(img_name, len, "%s_mimage_%%d", lv->name) < 0) {
+		log_error("img_name allocation failed. "
+			  "Remove new LV and retry.");
+		return 0;
+	}
+
+	for (m = 0; m < num_mirrors; m++) {
+		if (!(img_lvs[m] = lv_create_empty(lv->vg->fid, img_name,
+					     NULL, LVM_READ | LVM_WRITE,
+					     ALLOC_INHERIT, 0, lv->vg))) {\
+			log_error("Aborting. Failed to create submirror LV. "
+				  "Remove new LV and retry.");
+			return 0;
+		}
+
+		if (!lv_add_segment(ah, m, 1, img_lvs[m],
+				    get_segtype_from_string(lv->vg->cmd,
+							    "striped"),
+				    0, NULL, 0, 0, 0, NULL)) {
+			log_error("Aborting. Failed to add submirror segment "
+				  "to %s. Remove new LV and retry.",
+				  img_lvs[m]->name);
+			return 0;
+		}
+	}
+
+	if (!lv_add_mirror_segment(ah, lv, img_lvs, num_mirrors, segtype,
+				   0, region_size, log_lv)) {
+		log_error("Aborting. Failed to add mirror segment. "
+			  "Remove new LV and retry.");
+		return 0;
+	}
+
+	return 1;
+}
 
 /* 
  * Replace any LV segments on given PV with temporary mirror.
@@ -29,9 +165,9 @@
 			  struct list *source_pvl,
 			  struct logical_volume *lv,
 			  struct list *allocatable_pvs,
+			  alloc_policy_t alloc,
 			  struct list *lvs_changed)
 {
-	struct list *segh;
 	struct lv_segment *seg;
 	struct lv_list *lvl;
 	struct pv_list *pvl;
@@ -57,16 +193,15 @@
         }
 
 	/* Split LV segments to match PE ranges */
-	list_iterate(segh, &lv->segments) {
-		seg = list_item(segh, struct lv_segment);
+	list_iterate_items(seg, &lv->segments) {
 		for (s = 0; s < seg->area_count; s++) {
-			if (seg->area[s].type != AREA_PV ||
-			    seg->area[s].u.pv.pv->dev != pvl->pv->dev)
+			if (seg_type(seg, s) != AREA_PV ||
+			    seg_dev(seg, s) != pvl->pv->dev)
 				continue;
 
 			/* Do these PEs need moving? */
 			list_iterate_items(per, pvl->pe_ranges) {
-				pe_start = seg->area[s].u.pv.pe;
+				pe_start = seg_pe(seg, s);
 				pe_end = pe_start + seg->area_len - 1;
 				per_end = per->start + per->count - 1;
 
@@ -75,7 +210,7 @@
 				    (pe_start > per_end))
 					continue;
 
-				if (seg->segtype->flags & SEG_AREAS_STRIPED)
+				if (seg_is_striped(seg))
 					stripe_multiplier = seg->area_count;
 				else
 					stripe_multiplier = 1;
@@ -102,14 +237,13 @@
 	}
 
 	/* Work through all segments on the supplied PV */
-	list_iterate(segh, &lv->segments) {
-		seg = list_item(segh, struct lv_segment);
+	list_iterate_items(seg, &lv->segments) {
 		for (s = 0; s < seg->area_count; s++) {
-			if (seg->area[s].type != AREA_PV ||
-			    seg->area[s].u.pv.pv->dev != pvl->pv->dev)
+			if (seg_type(seg, s) != AREA_PV ||
+			    seg_dev(seg, s) != pvl->pv->dev)
 				continue;
 
-			pe_start = seg->area[s].u.pv.pe;
+			pe_start = seg_pe(seg, s);
 
 			/* Do these PEs need moving? */
 			list_iterate_items(per, pvl->pe_ranges) {
@@ -121,8 +255,9 @@
 
 				log_debug("Matched PE range %u-%u against "
 					  "%s %u len %u", per->start, per_end,
-					  dev_name(seg->area[s].u.pv.pv->dev),
-					  seg->area[s].u.pv.pe, seg->area_len);
+					  dev_name(seg_dev(seg, s)),
+					  seg_pe(seg, s),
+					  seg->area_len);
 
 				/* First time, add LV to list of LVs affected */
 				if (!lv_used) {
@@ -137,25 +272,23 @@
 	
 				log_very_verbose("Moving %s:%u-%u of %s/%s",
 						 dev_name(pvl->pv->dev),
-						 seg->area[s].u.pv.pe,
-						 seg->area[s].u.pv.pe +
+						 seg_pe(seg, s),
+						 seg_pe(seg, s) +
 						     seg->area_len - 1,
 						 lv->vg->name, lv->name);
 
 				start_le = lv_mirr->le_count;
-				if (!lv_extend(lv->vg->fid, lv_mirr, segtype, 1,
+				if (!lv_extend(lv_mirr, segtype, 1,
 				       	seg->area_len, 0u, seg->area_len,
-				       	seg->area[s].u.pv.pv,
-				       	seg->area[s].u.pv.pe,
+				       	seg_pv(seg, s),
+				       	seg_pe(seg, s),
 				       	PVMOVE, allocatable_pvs,
-				       	lv->alloc)) {
+				       	alloc)) {
 					log_error("Unable to allocate "
 						  "temporary LV for pvmove.");
 					return 0;
 				}
-				seg->area[s].type = AREA_LV;
-				seg->area[s].u.lv.lv = lv_mirr;
-				seg->area[s].u.lv.le = start_le;
+				set_lv_segment_area_lv(seg, s, lv_mirr, start_le, 0);
 	
 				extent_count += seg->area_len;
 	
@@ -176,29 +309,27 @@
 int remove_pvmove_mirrors(struct volume_group *vg,
 			  struct logical_volume *lv_mirr)
 {
-	struct list *lvh, *segh;
+	struct lv_list *lvl;
 	struct logical_volume *lv1;
 	struct lv_segment *seg, *mir_seg;
 	uint32_t s, c;
 
 	/* Loop through all LVs except the temporary mirror */
-	list_iterate(lvh, &vg->lvs) {
-		lv1 = list_item(lvh, struct lv_list)->lv;
+	list_iterate_items(lvl, &vg->lvs) {
+		lv1 = lvl->lv;
 		if (lv1 == lv_mirr)
 			continue;
 
 		/* Find all segments that point at the temporary mirror */
-		list_iterate(segh, &lv1->segments) {
-			seg = list_item(segh, struct lv_segment);
+		list_iterate_items(seg, &lv1->segments) {
 			for (s = 0; s < seg->area_count; s++) {
-				if (seg->area[s].type != AREA_LV ||
-				    seg->area[s].u.lv.lv != lv_mirr)
+				if (seg_type(seg, s) != AREA_LV ||
+				    seg_lv(seg, s) != lv_mirr)
 					continue;
 
 				/* Find the mirror segment pointed at */
 				if (!(mir_seg = find_seg_by_le(lv_mirr,
-							       seg->area[s].
-							       u.lv.le))) {
+							       seg_le(seg, s)))) {
 					/* FIXME Error message */
 					log_error("No segment found with LE");
 					return 0;
@@ -206,10 +337,9 @@
 
 				/* Check the segment params are compatible */
 				/* FIXME Improve error mesg & remove restrcn */
-				if ((!(mir_seg->segtype->flags
-				       & SEG_AREAS_MIRRORED)) ||
+				if (!seg_is_mirrored(mir_seg) ||
 				    !(mir_seg->status & PVMOVE) ||
-				    mir_seg->le != seg->area[s].u.lv.le ||
+				    mir_seg->le != seg_le(seg, s) ||
 				    mir_seg->area_count != 2 ||
 				    mir_seg->area_len != seg->area_len) {
 					log_error("Incompatible segments");
@@ -225,9 +355,12 @@
 				else
 					c = 0;
 
-				seg->area[s].type = AREA_PV;
-				seg->area[s].u.pv.pv = mir_seg->area[c].u.pv.pv;
-				seg->area[s].u.pv.pe = mir_seg->area[c].u.pv.pe;
+				if (!set_lv_segment_area_pv(seg, s,
+					    seg_pv(mir_seg, c),
+					    seg_pe(mir_seg, c))) {
+					stack;
+					return 0;
+				}
 
 				/* Replace mirror with old area */
 				if (!
@@ -254,16 +387,14 @@
 
 const char *get_pvmove_pvname_from_lv_mirr(struct logical_volume *lv_mirr)
 {
-	struct list *segh;
 	struct lv_segment *seg;
 
-	list_iterate(segh, &lv_mirr->segments) {
-		seg = list_item(segh, struct lv_segment);
-		if (!(seg->segtype->flags & SEG_AREAS_MIRRORED))
+	list_iterate_items(seg, &lv_mirr->segments) {
+		if (!seg_is_mirrored(seg))
 			continue;
 		if (seg->area[0].type != AREA_PV)
 			continue;
-		return dev_name(seg->area[0].u.pv.pv->dev);
+		return dev_name(seg_dev(seg, 0));
 	}
 
 	return NULL;
@@ -271,16 +402,14 @@
 
 const char *get_pvmove_pvname_from_lv(struct logical_volume *lv)
 {
-	struct list *segh;
 	struct lv_segment *seg;
 	uint32_t s;
 
-	list_iterate(segh, &lv->segments) {
-		seg = list_item(segh, struct lv_segment);
+	list_iterate_items(seg, &lv->segments) {
 		for (s = 0; s < seg->area_count; s++) {
-			if (seg->area[s].type != AREA_LV)
+			if (seg_type(seg, s) != AREA_LV)
 				continue;
-			return get_pvmove_pvname_from_lv_mirr(seg->area[s].u.lv.lv);
+			return get_pvmove_pvname_from_lv_mirr(seg_lv(seg, s));
 		}
 	}
 
@@ -291,23 +420,22 @@
 				      struct device *dev,
 				      uint32_t lv_type)
 {
-	struct list *lvh, *segh;
+	struct lv_list *lvl;
 	struct logical_volume *lv;
 	struct lv_segment *seg;
 
 	/* Loop through all LVs */
-	list_iterate(lvh, &vg->lvs) {
-		lv = list_item(lvh, struct lv_list)->lv;
+	list_iterate_items(lvl, &vg->lvs) {
+		lv = lvl->lv;
 
 		if (!(lv->status & lv_type))
 			continue;
 
 		/* Check segment origins point to pvname */
-		list_iterate(segh, &lv->segments) {
-			seg = list_item(segh, struct lv_segment);
+		list_iterate_items(seg, &lv->segments) {
 			if (seg->area[0].type != AREA_PV)
 				continue;
-			if (seg->area[0].u.pv.pv->dev != dev)
+			if (seg_dev(seg, 0) != dev)
 				continue;
 			return lv;
 		}
@@ -334,9 +462,9 @@
 struct list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
 			  struct logical_volume *lv)
 {
-	struct list *lvh, *segh, *lvs;
+	struct list *lvs;
 	struct logical_volume *lv1;
-	struct lv_list *lvl;
+	struct lv_list *lvl, *lvl1;
 	struct lv_segment *seg;
 	uint32_t s;
 
@@ -348,17 +476,16 @@
 	list_init(lvs);
 
 	/* Loop through all LVs except the one supplied */
-	list_iterate(lvh, &vg->lvs) {
-		lv1 = list_item(lvh, struct lv_list)->lv;
+	list_iterate_items(lvl1, &vg->lvs) {
+		lv1 = lvl1->lv;
 		if (lv1 == lv)
 			continue;
 
 		/* Find whether any segment points at the supplied LV */
-		list_iterate(segh, &lv1->segments) {
-			seg = list_item(segh, struct lv_segment);
+		list_iterate_items(seg, &lv1->segments) {
 			for (s = 0; s < seg->area_count; s++) {
-				if (seg->area[s].type != AREA_LV ||
-				    seg->area[s].u.lv.lv != lv)
+				if (seg_type(seg, s) != AREA_LV ||
+				    seg_lv(seg, s) != lv)
 					continue;
 				if (!(lvl = pool_alloc(cmd->mem, sizeof(*lvl)))) {
 					log_error("lv_list alloc failed");
@@ -379,15 +506,12 @@
 float copy_percent(struct logical_volume *lv_mirr)
 {
 	uint32_t numerator = 0u, denominator = 0u;
-	struct list *segh;
 	struct lv_segment *seg;
 
-	list_iterate(segh, &lv_mirr->segments) {
-		seg = list_item(segh, struct lv_segment);
-
+	list_iterate_items(seg, &lv_mirr->segments) {
 		denominator += seg->area_len;
 
-		if (seg->segtype->flags & SEG_AREAS_MIRRORED)
+		if (seg_is_mirrored(seg))
 			numerator += seg->extents_copied;
 		else
 			numerator += seg->area_len;

Added: lvm2/trunk/lib/metadata/pv_alloc.h
==============================================================================
--- (empty file)
+++ lvm2/trunk/lib/metadata/pv_alloc.h	Tue Jun 14 11:23:47 2005
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 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_PV_ALLOC_H
+#include "pool.h"
+
+int alloc_pv_segment_whole_pv(struct pool *mem, struct physical_volume *pv);
+int peg_dup(struct pool *mem, struct list *peg_new, struct list *peg_old);
+struct pv_segment *assign_peg_to_lvseg(struct physical_volume *pv, uint32_t pe,
+				       uint32_t area_len,
+				       struct lv_segment *seg,
+				       uint32_t area_num);
+int pv_split_segment(struct physical_volume *pv, uint32_t pe);
+int release_pv_segment(struct pv_segment *peg, uint32_t area_reduction);
+int check_pv_segments(struct volume_group *vg);
+void merge_pv_segments(struct pv_segment *peg1, struct pv_segment *peg2);
+
+#endif

Added: lvm2/trunk/lib/metadata/pv_manip.c
==============================================================================
--- (empty file)
+++ lvm2/trunk/lib/metadata/pv_manip.c	Tue Jun 14 11:23:47 2005
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2003 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
+ */
+
+#include "lib.h"
+#include "pool.h"
+#include "metadata.h"
+#include "pv_alloc.h"
+#include "toolcontext.h"
+
+static struct pv_segment *_alloc_pv_segment(struct pool *mem,
+					    struct physical_volume *pv,
+					    uint32_t pe, uint32_t len,
+					    struct lv_segment *lvseg,
+					    uint32_t lv_area)
+{
+	struct pv_segment *peg;
+
+	if (!(peg = pool_zalloc(mem, sizeof(*peg)))) {
+		log_error("pv_segment allocation failed");
+		return NULL;
+	}
+
+	peg->pv = pv;
+	peg->pe = pe;
+	peg->len = len;
+	peg->lvseg = lvseg;
+	peg->lv_area = lv_area;
+
+	list_init(&peg->list);
+
+	return peg;
+}
+
+int alloc_pv_segment_whole_pv(struct pool *mem, struct physical_volume *pv)
+{
+	struct pv_segment *peg;
+
+	if (!pv->pe_count)
+		return 1;
+
+	/* FIXME Cope with holes in PVs */
+	if (!(peg = _alloc_pv_segment(mem, pv, 0, pv->pe_count, NULL, 0))) {
+		stack;
+		return 0;
+	}
+
+	list_add(&pv->segments, &peg->list);
+
+	return 1;
+}
+
+int peg_dup(struct pool *mem, struct list *peg_new, struct list *peg_old)
+{
+	struct pv_segment *peg, *pego;
+
+	list_init(peg_new);
+
+	list_iterate_items(pego, peg_old) {
+		if (!(peg = _alloc_pv_segment(mem, pego->pv, pego->pe,
+					      pego->len, pego->lvseg,
+					      pego->lv_area))) {
+			stack;
+			return 0;
+		} 
+		list_add(peg_new, &peg->list);
+	}
+
+	return 1;
+}
+
+/*
+ * Split peg at given extent.
+ * Second part is always deallocated.
+ */
+static int _pv_split_segment(struct physical_volume *pv, struct pv_segment *peg,
+			     uint32_t pe)
+{
+	struct pv_segment *peg_new;
+
+	if (!(peg_new = _alloc_pv_segment(pv->fmt->cmd->mem, peg->pv, pe,
+					  peg->len + peg->pe - pe,
+					  NULL, 0))) {
+		stack;
+		return 0;
+	}
+
+	peg->len = peg->len - peg_new->len;
+
+	list_add_h(&peg->list, &peg_new->list);
+
+	return 1;
+}
+
+/*
+ * Ensure there is a PV segment boundary at the given extent.
+ */
+int pv_split_segment(struct physical_volume *pv, uint32_t pe)
+{
+	struct pv_segment *peg;
+
+	if (pe == pv->pe_count)
+		return 1;
+
+	if (!(peg = find_peg_by_pe(pv, pe))) {
+		log_error("Segment with extent %" PRIu32 " in PV %s not found",
+			  pe, dev_name(pv->dev));
+		return 0;
+	}
+
+	/* This is a peg start already */
+	if (pe == peg->pe)
+		return 1;
+
+	if (!_pv_split_segment(pv, peg, pe)) {
+		stack;
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct pv_segment null_pv_segment = {
+	pv: NULL,
+	pe: 0
+};
+
+struct pv_segment *assign_peg_to_lvseg(struct physical_volume *pv,
+				       uint32_t pe, uint32_t area_len,
+				       struct lv_segment *seg,
+				       uint32_t area_num)
+{
+	struct pv_segment *peg;
+
+	/* Missing format1 PV */
+	if (!pv)
+		return &null_pv_segment;
+
+	if (!pv_split_segment(pv, pe) || 
+	    !pv_split_segment(pv, pe + area_len)) {
+		stack;
+		return NULL;
+	}
+
+	if (!(peg = find_peg_by_pe(pv, pe))) {
+		log_error("Missing PV segment on %s at %u.",
+			  dev_name(pv->dev), pe);
+		return NULL;
+	}
+
+	peg->lvseg = seg;
+	peg->lv_area = area_num;
+
+	return peg;
+}
+
+int release_pv_segment(struct pv_segment *peg, uint32_t area_reduction)
+{
+	peg->pv->pe_alloc_count -= area_reduction;
+
+	if (!peg->lvseg->area_len) {
+		peg->lvseg = NULL;
+		peg->lv_area = 0;
+
+		/* FIXME merge free space */
+
+		return 1;
+	}
+
+	if (!pv_split_segment(peg->pv, peg->pe + peg->lvseg->area_len)) {
+		stack;
+		return 0;
+	}
+
+	return 1;
+}
+
+/*
+ * Only for use by lv_segment merging routines.
+ */
+void merge_pv_segments(struct pv_segment *peg1, struct pv_segment *peg2)
+{
+	peg1->len += peg2->len;
+
+	list_del(&peg2->list);
+}
+
+/*
+ * Check all pv_segments in VG for consistency
+ */
+int check_pv_segments(struct volume_group *vg)
+{
+	struct physical_volume *pv;
+	struct pv_list *pvl;
+	struct pv_segment *peg;
+	unsigned s, segno;
+	uint32_t start_pe, alloced;
+	uint32_t pv_count = 0, free_count = 0, extent_count = 0;
+	int ret = 1;
+
+	list_iterate_items(pvl, &vg->pvs) {
+		pv = pvl->pv;
+		segno = 0;
+		start_pe = 0;
+		alloced = 0;
+		pv_count++;
+
+		list_iterate_items(peg, &pv->segments) {
+			s = peg->lv_area;
+
+			/* FIXME Remove this next line eventually */
+			log_debug("%s %u: %6u %6u: %s(%u:%u)",
+				  dev_name(pv->dev), segno++, peg->pe, peg->len,
+				  peg->lvseg ? peg->lvseg->lv->name : "NULL",
+				  peg->lvseg ? peg->lvseg->le : 0, s);
+			/* FIXME Add details here on failure instead */
+			if (start_pe != peg->pe) {
+				log_error("Gap in pvsegs: %u, %u",
+					  start_pe, peg->pe);
+				ret = 0;
+			}
+			if (peg->lvseg) {
+				if (seg_type(peg->lvseg, s) != AREA_PV) {
+					log_error("Wrong lvseg area type");
+					ret = 0;
+				}
+				if (seg_pvseg(peg->lvseg, s) != peg) {
+					log_error("Inconsistent pvseg pointers");
+					ret = 0;
+				}
+				if (peg->lvseg->area_len != peg->len) {
+					log_error("Inconsistent length: %u %u",
+						  peg->len,
+						  peg->lvseg->area_len);
+					ret = 0;
+				}
+				alloced += peg->len;
+			}
+			start_pe += peg->len;
+		}
+
+		if (start_pe != pv->pe_count) {
+			log_error("PV segment pe_count mismatch: %u != %u",
+				  start_pe, pv->pe_count);
+			ret = 0;
+		}
+
+		if (alloced != pv->pe_alloc_count) {
+			log_error("PV segment pe_alloc_count mismatch: "
+				  "%u != %u", alloced, pv->pe_alloc_count);
+			ret = 0;
+		}
+
+		extent_count += start_pe;
+		free_count += (start_pe - alloced);
+	}
+
+	if (pv_count != vg->pv_count) {
+		log_error("PV segment VG pv_count mismatch: %u != %u",
+			  pv_count, vg->pv_count);
+		ret = 0;
+	}
+
+	if (free_count != vg->free_count) {
+		log_error("PV segment VG free_count mismatch: %u != %u",
+			  free_count, vg->free_count);
+		ret = 0;
+	}
+
+	if (extent_count != vg->extent_count) {
+		log_error("PV segment VG extent_count mismatch: %u != %u",
+			  extent_count, vg->extent_count);
+		ret = 0;
+	}
+
+	return ret;
+}

Modified: lvm2/trunk/lib/metadata/pv_map.c
==============================================================================
--- lvm2/trunk/lib/metadata/pv_map.c	(original)
+++ lvm2/trunk/lib/metadata/pv_map.c	Tue Jun 14 11:23:47 2005
@@ -16,213 +16,107 @@
 #include "lib.h"
 #include "pv_map.h"
 #include "hash.h"
-
-static int _create_maps(struct pool *mem, struct list *pvs, struct list *maps)
-{
-	struct list *tmp;
-	struct pv_map *pvm;
-	struct pv_list *pvl;
-
-	list_iterate(tmp, pvs) {
-		pvl = list_item(tmp, struct pv_list);
-
-		if (!(pvl->pv->status & ALLOCATABLE_PV))
-			continue;
-
-		if (!(pvm = pool_zalloc(mem, sizeof(*pvm)))) {
-			stack;
-			return 0;
-		}
-
-		pvm->pvl = pvl;
-		if (!(pvm->allocated_extents =
-		      bitset_create(mem, pvl->pv->pe_count))) {
-			stack;
-			return 0;
-		}
-
-		list_init(&pvm->areas);
-		list_add(maps, &pvm->list);
-	}
-
-	return 1;
-}
-
-static int _set_allocd(struct hash_table *hash,
-		       struct physical_volume *pv, uint32_t pe)
-{
-	struct pv_map *pvm;
-
-	if (!(pvm = (struct pv_map *) hash_lookup(hash, dev_name(pv->dev)))) {
-		/*
-		 * it doesn't matter that this fails, it just
-		 * means this part of the lv is on a pv that
-		 * we're not interested in allocating to.
-		 */
-		return 1;
-	}
-
-	/* sanity check */
-	if (bit(pvm->allocated_extents, pe)) {
-		log_error("Physical extent %d of %s referenced by more than "
-			  "one logical volume", pe, dev_name(pv->dev));
-		return 0;
-	}
-
-	bit_set(pvm->allocated_extents, pe);
-	return 1;
-}
-
-static int _fill_bitsets(struct volume_group *vg, struct list *maps)
-{
-	struct list *lvh, *pvmh, *segh;
-	struct logical_volume *lv;
-	struct pv_map *pvm;
-	uint32_t s, pe;
-	struct hash_table *hash;
-	struct lv_segment *seg;
-	int r = 0;
-
-	if (!(hash = hash_create(128))) {
-		log_err("Couldn't create hash table for pv maps.");
-		return 0;
-	}
-
-	/* populate the hash table */
-	list_iterate(pvmh, maps) {
-		pvm = list_item(pvmh, struct pv_map);
-		if (!hash_insert(hash, dev_name(pvm->pvl->pv->dev), pvm)) {
-			stack;
-			goto out;
-		}
-	}
-
-	/* iterate through all the lv's setting bit's for used pe's */
-	list_iterate(lvh, &vg->lvs) {
-		lv = list_item(lvh, struct lv_list)->lv;
-
-		list_iterate(segh, &lv->segments) {
-			seg = list_item(segh, struct lv_segment);
-
-			for (s = 0u; s < seg->area_count; s++) {
-				for (pe = 0u; pe < seg->area_len; pe++) {
-					if (seg->area[s].type != AREA_PV)
-						continue;
-					if (!_set_allocd(hash,
-							 seg->area[s].u.pv.pv,
-							 seg->area[s].u.pv.pe
-							 + pe)) {
-						stack;
-						goto out;
-					}
-				}
-			}
-		}
-	}
-	r = 1;
-
-      out:
-	hash_destroy(hash);
-	return r;
-}
+#include "pv_alloc.h"
 
 /*
- * Areas are maintained in size order.
+ * Areas are maintained in size order, largest first.
  */
 static void _insert_area(struct list *head, struct pv_area *a)
 {
-	struct list *pvah;
-	struct pv_area *pva = NULL;
-
-	if (list_empty(head)) {
-		list_add(head, &a->list);
-		return;
-	}
-
-	list_iterate(pvah, head) {
-		pva = list_item(pvah, struct pv_area);
+	struct pv_area *pva;
 
-		if (pva->count < a->count)
+	list_iterate_items(pva, head) {
+		if (a->count > pva->count)
 			break;
 	}
 
-	list_add_h(&pva->list, &a->list);
+	list_add(&pva->list, &a->list);
 }
 
 static int _create_single_area(struct pool *mem, struct pv_map *pvm,
-			       uint32_t end, uint32_t *extent)
+			       uint32_t start, uint32_t length)
 {
-	uint32_t e = *extent, b;
 	struct pv_area *pva;
 
-	while (e <= end && bit(pvm->allocated_extents, e))
-		e++;
-
-	if (e > end) {
-		*extent = e;
-		return 1;
-	}
-
-	b = e++;
-
-	while (e <= end && !bit(pvm->allocated_extents, e))
-		e++;
-
 	if (!(pva = pool_zalloc(mem, sizeof(*pva)))) {
 		stack;
 		return 0;
 	}
 
 	log_debug("Allowing allocation on %s start PE %" PRIu32 " length %"
-		  PRIu32, dev_name(pvm->pvl->pv->dev), b, e - b);
+		  PRIu32, dev_name(pvm->pv->dev), start, length);
 	pva->map = pvm;
-	pva->start = b;
-	pva->count = e - b;
+	pva->start = start;
+	pva->count = length;
 	_insert_area(&pvm->areas, pva);
-	*extent = e;
 
 	return 1;
 }
 
-static int _create_areas(struct pool *mem, struct pv_map *pvm, uint32_t start,
-			 uint32_t count)
+static int _create_alloc_areas_for_pv(struct pool *mem, struct pv_map *pvm,
+				      uint32_t start, uint32_t count)
 {
-	uint32_t pe, end;
+        struct pv_segment *peg;
+	uint32_t pe, end, area_len;
 
+	/* Only select extents from start to end inclusive */
 	end = start + count - 1;
-	if (end > pvm->pvl->pv->pe_count - 1)
-		end = pvm->pvl->pv->pe_count - 1;
+	if (end > pvm->pv->pe_count - 1)
+		end = pvm->pv->pe_count - 1;
 
 	pe = start;
-	while (pe <= end)
-		if (!_create_single_area(mem, pvm, end, &pe)) {
+
+	/* Walk through complete ordered list of device segments */
+        list_iterate_items(peg, &pvm->pv->segments) {
+		/* pe holds the next extent we want to check */
+
+		/* Beyond the range we're interested in? */
+		if (pe > end)
+			break;
+
+		/* Skip if we haven't reached the first seg we want yet */
+		if (pe > peg->pe + peg->len - 1)
+			continue;
+
+		/* Free? */
+		if (peg->lvseg)
+			goto next;
+
+		/* How much of this peg do we need? */
+		area_len = (end >= peg->pe + peg->len - 1) ?
+			   peg->len - (pe - peg->pe) : end - pe + 1;
+
+		if (!_create_single_area(mem, pvm, pe, area_len)) {
 			stack;
 			return 0;
 		}
 
+      next:
+		pe = peg->pe + peg->len;
+        }
+
 	return 1;
 }
 
-static int _create_allocatable_areas(struct pool *mem, struct pv_map *pvm)
+static int _create_all_areas_for_pv(struct pool *mem, struct pv_map *pvm,
+				    struct list *pe_ranges)
 {
-	struct list *alloc_areas, *aah;
 	struct pe_range *aa;
 
-	alloc_areas = pvm->pvl->pe_ranges;
+	if (!pe_ranges) {
+		/* Use whole PV */
+		if (!_create_alloc_areas_for_pv(mem, pvm, UINT32_C(0),
+						pvm->pv->pe_count)) {
+			stack;
+			return 0;
+		}
 
-	if (alloc_areas) {
-		list_iterate(aah, alloc_areas) {
-			aa = list_item(aah, struct pe_range);
-			if (!_create_areas(mem, pvm, aa->start, aa->count)) {
-				stack;
-				return 0;
-			}
+		return 1;
+	}
 
-		}
-	} else {
-		/* Use whole PV */
-		if (!_create_areas(mem, pvm, UINT32_C(0),
-				   pvm->pvl->pv->pe_count)) {
+	list_iterate_items(aa, pe_ranges) {
+		if (!_create_alloc_areas_for_pv(mem, pvm, aa->start,
+						aa->count)) {
 			stack;
 			return 0;
 		}
@@ -231,16 +125,26 @@
 	return 1;
 }
 
-static int _create_all_areas(struct pool *mem, struct list *maps,
-			     struct list *pvs)
+static int _create_maps(struct pool *mem, struct list *pvs, struct list *pvms)
 {
-	struct list *tmp;
 	struct pv_map *pvm;
+	struct pv_list *pvl;
+
+	list_iterate_items(pvl, pvs) {
+		if (!(pvl->pv->status & ALLOCATABLE_PV))
+			continue;
+
+		if (!(pvm = pool_zalloc(mem, sizeof(*pvm)))) {
+			stack;
+			return 0;
+		}
 
-	list_iterate(tmp, maps) {
-		pvm = list_item(tmp, struct pv_map);
+		pvm->pv = pvl->pv;
 
-		if (!_create_allocatable_areas(mem, pvm)) {
+		list_init(&pvm->areas);
+		list_add(pvms, &pvm->list);
+
+		if (!_create_all_areas_for_pv(mem, pvm, pvl->pe_ranges)) {
 			stack;
 			return 0;
 		}
@@ -249,40 +153,29 @@
 	return 1;
 }
 
+/*
+ * Create list of PV areas available for this particular allocation
+ */
 struct list *create_pv_maps(struct pool *mem, struct volume_group *vg,
-			    struct list *pvs)
+			    struct list *allocatable_pvs)
 {
-	struct list *maps = pool_zalloc(mem, sizeof(*maps));
+	struct list *pvms;
 
-	if (!maps) {
-		stack;
+	if (!(pvms = pool_zalloc(mem, sizeof(*pvms)))) {
+		log_error("create_pv_maps alloc failed");
 		return NULL;
 	}
 
-	list_init(maps);
+	list_init(pvms);
 
-	if (!_create_maps(mem, pvs, maps)) {
+	if (!_create_maps(mem, allocatable_pvs, pvms)) {
 		log_error("Couldn't create physical volume maps in %s",
 			  vg->name);
-		goto bad;
-	}
-
-	if (!_fill_bitsets(vg, maps)) {
-		log_error("Couldn't fill extent allocation bitmaps in %s",
-			  vg->name);
-		goto bad;
-	}
-
-	if (!_create_all_areas(mem, maps, pvs)) {
-		log_error("Couldn't create area maps in %s", vg->name);
-		goto bad;
+		pool_free(mem, pvms);
+		return NULL;
 	}
 
-	return maps;
-
-      bad:
-	pool_free(mem, maps);
-	return NULL;
+	return pvms;
 }
 
 void consume_pv_area(struct pv_area *pva, uint32_t to_go)

Modified: lvm2/trunk/lib/metadata/pv_map.h
==============================================================================
--- lvm2/trunk/lib/metadata/pv_map.h	(original)
+++ lvm2/trunk/lib/metadata/pv_map.h	Tue Jun 14 11:23:47 2005
@@ -33,19 +33,21 @@
 	uint32_t start;
 	uint32_t count;
 
-	struct list list;
+	struct list list;		/* pv_map.areas */
 };
 
 struct pv_map {
-	struct pv_list *pvl;
-	bitset_t allocated_extents;
-	struct list areas;
+	struct physical_volume *pv;
+	struct list areas;		/* struct pv_areas */
 
 	struct list list;
 };
 
-struct list *create_pv_maps(struct pool *mem,
-			    struct volume_group *vg, struct list *pvs);
+/*
+ * Find intersection between available_pvs and free space in VG
+ */
+struct list *create_pv_maps(struct pool *mem, struct volume_group *vg,
+			    struct list *allocatable_pvs);
 
 void consume_pv_area(struct pv_area *area, uint32_t to_go);
 

Modified: lvm2/trunk/lib/metadata/segtype.h
==============================================================================
--- lvm2/trunk/lib/metadata/segtype.h	(original)
+++ lvm2/trunk/lib/metadata/segtype.h	Tue Jun 14 11:23:47 2005
@@ -33,6 +33,16 @@
 #define SEG_FORMAT1_SUPPORT	0x00000010
 #define SEG_VIRTUAL		0x00000020
 
+#define seg_is_mirrored(seg)	((seg)->segtype->flags & SEG_AREAS_MIRRORED ? 1 : 0)
+#define seg_is_striped(seg)	((seg)->segtype->flags & SEG_AREAS_STRIPED ? 1 : 0)
+#define seg_is_snapshot(seg)	((seg)->segtype->flags & SEG_SNAPSHOT ? 1 : 0)
+#define seg_is_virtual(seg)	((seg)->segtype->flags & SEG_VIRTUAL ? 1 : 0)
+#define seg_can_split(seg)	((seg)->segtype->flags & SEG_CAN_SPLIT ? 1 : 0)
+
+#define segtype_is_striped(segtype)	((segtype)->flags & SEG_AREAS_STRIPED ? 1 : 0)
+#define segtype_is_mirrored(segtype)	((segtype)->flags & SEG_AREAS_MIRRORED ? 1 : 0)
+#define segtype_is_virtual(segtype)	((segtype)->flags & SEG_VIRTUAL ? 1 : 0)
+
 struct segment_type {
 	struct list list;
 	struct cmd_context *cmd;

Modified: lvm2/trunk/lib/metadata/snapshot_manip.c
==============================================================================
--- lvm2/trunk/lib/metadata/snapshot_manip.c	(original)
+++ lvm2/trunk/lib/metadata/snapshot_manip.c	Tue Jun 14 11:23:47 2005
@@ -16,101 +16,31 @@
 #include "lib.h"
 #include "metadata.h"
 #include "toolcontext.h"
+#include "lv_alloc.h"
 
 int lv_is_origin(const struct logical_volume *lv)
 {
-	struct list *slh;
-	struct snapshot *s;
-
-	list_iterate(slh, &lv->vg->snapshots) {
-		s = list_item(slh, struct snapshot_list)->snapshot;
-		if (s->origin == lv)
-			return 1;
-	}
-
-	return 0;
+	return lv->origin_count ? 1 : 0;
 }
 
 int lv_is_cow(const struct logical_volume *lv)
 {
-	struct list *slh;
-	struct snapshot *s;
-
-	list_iterate(slh, &lv->vg->snapshots) {
-		s = list_item(slh, struct snapshot_list)->snapshot;
-		if (s->cow == lv)
-			return 1;
-	}
-
-	return 0;
-}
-
-struct snapshot *find_origin(const struct logical_volume *lv)
-{
-	struct list *slh;
-	struct snapshot *s;
-
-	list_iterate(slh, &lv->vg->snapshots) {
-		s = list_item(slh, struct snapshot_list)->snapshot;
-		if (s->origin == lv)
-			return s;
-	}
-
-	return NULL;
+	return lv->snapshot ? 1 : 0;
 }
 
-struct snapshot *find_cow(const struct logical_volume *lv)
+/* Given a cow LV, return the snapshot lv_segment that uses it */
+struct lv_segment *find_cow(const struct logical_volume *lv)
 {
-	struct list *slh;
-	struct snapshot *s;
-
-	list_iterate(slh, &lv->vg->snapshots) {
-		s = list_item(slh, struct snapshot_list)->snapshot;
-		if (s->cow == lv)
-			return s;
-	}
-
-	return NULL;
+	return lv->snapshot;
 }
 
-struct list *find_snapshots(const struct logical_volume *lv)
+int vg_add_snapshot(struct format_instance *fid, const char *name,
+		    struct logical_volume *origin,
+		    struct logical_volume *cow, union lvid *lvid,
+		    uint32_t extent_count, uint32_t chunk_size)
 {
-	struct list *slh;
-	struct list *snaplist;
-	struct snapshot *s;
-	struct snapshot_list *newsl;
-	struct pool *mem = lv->vg->cmd->mem;
-
-	if (!(snaplist = pool_alloc(mem, sizeof(*snaplist)))) {
-		log_error("snapshot name list allocation failed");
-		return NULL;
-	}
-
-	list_init(snaplist);
-
-	list_iterate(slh, &lv->vg->snapshots) {
-		s = list_item(slh, struct snapshot_list)->snapshot;
-		if (!(s->origin == lv))
-			continue;
-		if (!(newsl = pool_alloc(mem, sizeof(*newsl)))) {
-			log_error("snapshot_list structure allocation failed");
-			pool_free(mem, snaplist);
-			return NULL;
-		}
-		newsl->snapshot = s;
-		list_add(snaplist, &newsl->list);
-	}
-
-	return snaplist;
-}
-
-int vg_add_snapshot(struct logical_volume *origin, struct logical_volume *cow,
-		    int persistent, struct id *id, uint32_t extent_count,
-		    uint32_t chunk_size)
-{
-	struct snapshot *s;
-	struct snapshot_list *sl;
-	struct pool *mem = origin->vg->cmd->mem;
+	struct logical_volume *snap;
+	struct lv_segment *seg;
 
 	/*
 	 * Is the cow device already being used ?
@@ -120,55 +50,53 @@
 		return 0;
 	}
 
-	if (!(s = pool_alloc(mem, sizeof(*s)))) {
+	if (!(snap = lv_create_empty(fid, name ? name : "snapshot%d",
+				     lvid, LVM_READ | LVM_WRITE | VISIBLE_LV,
+				     ALLOC_INHERIT, 1, origin->vg))) {
 		stack;
 		return 0;
 	}
 
-	s->persistent = persistent;
-	s->chunk_size = chunk_size;
-	s->le_count = extent_count;
-	s->origin = origin;
-	s->cow = cow;
-
-	if (id)
-		s->id = *id;
-	else if (!id_create(&s->id)) {
-		log_error("Random UUID creation failed for snapshot %s.",
-			  cow->name);
-		return 0;
-	}
+	snap->le_count = extent_count;
 
-	if (!(sl = pool_alloc(mem, sizeof(*sl)))) {
+	if (!(seg = alloc_snapshot_seg(snap, 0, 0))) {
 		stack;
-		pool_free(mem, s);
 		return 0;
 	}
 
-	cow->status &= ~VISIBLE_LV;
-	sl->snapshot = s;
-	list_add(&origin->vg->snapshots, &sl->list);
+	seg->chunk_size = chunk_size;
+	seg->origin = origin;
+	seg->cow = cow;
+	seg->lv->status |= SNAPSHOT;
+
+	origin->origin_count++;
 	origin->vg->snapshot_count++;
+	origin->vg->lv_count--;
+	cow->snapshot = seg;
+
+	cow->status &= ~VISIBLE_LV;
+
+	list_add(&origin->snapshot_segs, &seg->origin_list);
 
 	return 1;
 }
 
-int vg_remove_snapshot(struct volume_group *vg, struct logical_volume *cow)
+int vg_remove_snapshot(struct logical_volume *cow)
 {
-	struct list *slh;
-	struct snapshot_list *sl;
-
-	list_iterate(slh, &vg->snapshots) {
-		sl = list_item(slh, struct snapshot_list);
+	list_del(&cow->snapshot->origin_list);
+	cow->snapshot->origin->origin_count--;
 
-		if (sl->snapshot->cow == cow) {
-			list_del(slh);
-			vg->snapshot_count--;
-			return 1;
-		}
+	if (!lv_remove(cow->snapshot->lv)) {
+		log_error("Failed to remove internal snapshot LV %s",
+			  cow->snapshot->lv->name);
+		return 0;
 	}
 
-	/* fail */
-	log_err("Asked to remove an unknown snapshot.");
-	return 0;
+	cow->snapshot = NULL;
+
+	cow->vg->snapshot_count--;
+	cow->vg->lv_count++;
+	cow->status |= VISIBLE_LV;
+
+	return 1;
 }

Modified: lvm2/trunk/lib/mirror/mirrored.c
==============================================================================
--- lvm2/trunk/lib/mirror/mirrored.c	(original)
+++ lvm2/trunk/lib/mirror/mirrored.c	Tue Jun 14 11:23:47 2005
@@ -35,7 +35,7 @@
 };
 
 struct mirror_state {
-	uint32_t region_size;
+	uint32_t default_region_size;
 };
 
 static const char *_name(const struct lv_segment *seg)
@@ -45,14 +45,25 @@
 
 static void _display(const struct lv_segment *seg)
 {
+	const char *size;
+
 	log_print("  Mirrors\t\t%u", seg->area_count);
 	log_print("  Mirror size\t\t%u", seg->area_len);
+	if (seg->log_lv)
+		log_print("  Mirror log volume\t%s", seg->log_lv->name);
+
+	if (seg->region_size) {
+		size = display_size(seg->lv->vg->cmd,
+				    (uint64_t) seg->region_size,
+				    SIZE_SHORT);
+		log_print("  Mirror region size\t%s", size);
+	}
+
 	log_print("  Mirror original:");
 	display_stripe(seg, 0, "    ");
 	log_print("  Mirror destination:");
 	display_stripe(seg, 1, "    ");
 	log_print(" ");
-
 }
 
 static int _text_import_area_count(struct config_node *sn, uint32_t *area_count)
@@ -70,6 +81,7 @@
 			struct hash_table *pv_hash)
 {
 	const struct config_node *cn;
+	char *logname = NULL;
 
 	if (find_config_node(sn, "extents_moved")) {
 		if (get_config_uint32(sn, "extents_moved",
@@ -82,13 +94,42 @@
 		}
 	}
 
+	if (find_config_node(sn, "region_size")) {
+		if (!get_config_uint32(sn, "region_size",
+				      &seg->region_size)) {
+			log_error("Couldn't read 'region_size' for "
+				  "segment '%s'.", sn->key);
+			return 0;
+		}
+	}
+
+        if ((cn = find_config_node(sn, "mirror_log"))) {
+                if (!cn->v || !cn->v->v.str) {
+                        log_error("Mirror log type must be a string.");
+                        return 0;
+                }
+                logname = cn->v->v.str;
+		if (!(seg->log_lv = find_lv(seg->lv->vg, logname))) {
+			log_error("Unrecognised mirror log in segment %s.",
+				  sn->key);
+			return 0;
+		}
+		seg->log_lv->status |= MIRROR_LOG;
+        }
+
+	if (logname && !seg->region_size) {
+		log_error("Missing region size for mirror log for segment "
+			  "'%s'.", sn->key);
+		return 0;
+	}
+
 	if (!(cn = find_config_node(sn, "mirrors"))) {
 		log_error("Couldn't find mirrors array for segment "
 			  "'%s'.", sn->key);
 		return 0;
 	}
 
-	return text_import_areas(seg, sn, cn, pv_hash);
+	return text_import_areas(seg, sn, cn, pv_hash, MIRROR_IMAGE);
 }
 
 static int _text_export(const struct lv_segment *seg, struct formatter *f)
@@ -96,7 +137,11 @@
 	outf(f, "mirror_count = %u", seg->area_count);
 	if (seg->status & PVMOVE)
 		out_size(f, (uint64_t) seg->extents_copied * seg->lv->vg->extent_size,
-			 "extents_moved = %u", seg->extents_copied);
+			 "extents_moved = %" PRIu32, seg->extents_copied);
+	if (seg->log_lv)
+		outf(f, "mirror_log = \"%s\"", seg->log_lv->name);
+	if (seg->region_size)
+		outf(f, "region_size = %" PRIu32, seg->region_size);
 
 	return out_areas(f, seg, "mirror");
 }
@@ -112,7 +157,7 @@
 		return NULL;
 	}
 
-	mirr_state->region_size = 2 *
+	mirr_state->default_region_size = 2 *
 	    find_config_int(cft->root,
 			    "activation/mirror_region_size",
 			    DEFAULT_MIRROR_REGION_SIZE);
@@ -131,6 +176,7 @@
 	int areas = seg->area_count;
 	int start_area = 0u;
 	uint32_t region_size, region_max;
+	int ret;
 
 	if (!*target_state)
 		*target_state = _init_target(mem, cft);
@@ -155,21 +201,29 @@
 	} else {
 		*target = "mirror";
 
-		/* Find largest power of 2 region size unit we can use */
-		region_max = (1 << (ffs(seg->area_len) - 1)) *
+		if (!(seg->status & PVMOVE)) {
+			if (!seg->region_size) {
+				log_error("Missing region size for mirror segment.");
+				return 0;
+			}
+			region_size = seg->region_size;
+		} else {
+			/* Find largest power of 2 region size unit we can use */
+			region_max = (1 << (ffs(seg->area_len) - 1)) *
 			      seg->lv->vg->extent_size;
 
-		region_size = mirr_state->region_size;
-		if (region_max < region_size) {
-			region_size = region_max;
-			log_verbose("Using reduced mirror region size of %u sectors",
-				    region_size);
+			region_size = mirr_state->default_region_size;
+			if (region_max < region_size) {
+				region_size = region_max;
+				log_verbose("Using reduced mirror region size of %u sectors",
+					    region_size);
+			}
 		}
 
-		if ((*pos = lvm_snprintf(params, paramsize, "core 1 %u %u ",
-					 region_size, areas)) < 0) {
+		if ((ret = compose_log_line(dm, seg, params, paramsize, pos,
+					    areas, region_size)) <= 0) {
 			stack;
-			return -1;
+			return ret;
 		}
 	}
 

Modified: lvm2/trunk/lib/misc/lvm-file.c
==============================================================================
--- lvm2/trunk/lib/misc/lvm-file.c	(original)
+++ lvm2/trunk/lib/misc/lvm-file.c	Tue Jun 14 11:23:47 2005
@@ -86,7 +86,11 @@
 {
 	struct stat buf;
 
-	link(old, new);
+	if (link(old, new)) {
+		log_error("%s: rename to %s failed: %s", old, new,
+			  strerror(errno));
+		return 0;
+	}
 
 	if (stat(old, &buf)) {
 		log_sys_error("stat", old);
@@ -148,7 +152,8 @@
 		if (*orig) {
 			rc = mkdir(orig, 0777);
 			if (rc < 0 && errno != EEXIST) {
-				log_sys_error("mkdir", orig);
+				if (errno != EROFS)
+					log_sys_error("mkdir", orig);
 				dbg_free(orig);
 				return 0;
 			}
@@ -160,7 +165,8 @@
 	/* Create final directory */
 	rc = mkdir(dir, 0777);
 	if (rc < 0 && errno != EEXIST) {
-		log_sys_error("mkdir", dir);
+		if (errno != EROFS)
+			log_sys_error("mkdir", dir);
 		return 0;
 	}
 	return 1;

Modified: lvm2/trunk/lib/misc/selinux.c
==============================================================================
--- lvm2/trunk/lib/misc/selinux.c	(original)
+++ lvm2/trunk/lib/misc/selinux.c	Tue Jun 14 11:23:47 2005
@@ -18,25 +18,28 @@
 
 #include <selinux/selinux.h>
 
-int set_selinux_context(const char *path)
+int set_selinux_context(const char *path, mode_t mode)
 {
 	security_context_t scontext;
 
-	log_very_verbose("Setting SELinux context for %s", path);
 	if (is_selinux_enabled() <= 0)
 		return 1;
 
-	if (matchpathcon(path, 0, &scontext) < 0) {
-		log_sys_error("matchpathcon", path);
+	if (matchpathcon(path, mode, &scontext) < 0) {
+		log_error("%s: matchpathcon %07o failed: %s", path, mode,
+			  strerror(errno));
 		return 0;
 	}
 
+	log_very_verbose("Setting SELinux context for %s to %s.",
+			 path, scontext);
+
 	if ((lsetfilecon(path, scontext) < 0) && (errno != ENOTSUP)) {
 		log_sys_error("lsetfilecon", path);
-		free(scontext);
+		freecon(scontext);
 		return 0;
 	}
 
-	free(scontext);
+	freecon(scontext);
 	return 1;
 }

Modified: lvm2/trunk/lib/misc/selinux.h
==============================================================================
--- lvm2/trunk/lib/misc/selinux.h	(original)
+++ lvm2/trunk/lib/misc/selinux.h	Tue Jun 14 11:23:47 2005
@@ -15,6 +15,8 @@
 #ifndef _LVM_SELINUX_H
 #define _LVM_SELINUX_H
 
-int set_selinux_context(const char * path);
+#include <sys/types.h>
+
+int set_selinux_context(const char * path, mode_t mode);
 
 #endif

Modified: lvm2/trunk/lib/mm/dbg_malloc.c
==============================================================================
--- lvm2/trunk/lib/mm/dbg_malloc.c	(original)
+++ lvm2/trunk/lib/mm/dbg_malloc.c	Tue Jun 14 11:23:47 2005
@@ -19,6 +19,16 @@
 
 #include <stdarg.h>
 
+char *dbg_strdup(const char *str)
+{
+	char *ret = dbg_malloc(strlen(str) + 1);
+
+	if (ret)
+		strcpy(ret, str);
+
+	return ret;
+}
+
 #ifdef DEBUG_MEM
 
 struct memblock {
@@ -102,6 +112,9 @@
 	if (_mem_stats.bytes > _mem_stats.mbytes)
 		_mem_stats.mbytes = _mem_stats.bytes;
 
+	/* log_debug("Allocated: %u %u %u", nb->id, _mem_stats.blocks_allocated,
+		  _mem_stats.bytes); */
+
 	return nb + 1;
 }
 
@@ -183,6 +196,8 @@
 		for (c = 0; c < sizeof(str) - 1; c++) {
 			if (c >= mb->length)
 				str[c] = ' ';
+			else if (*(char *)(mb->magic + c) == '\0')
+				str[c] = '\0';
 			else if (*(char *)(mb->magic + c) < ' ')
 				str[c] = '?';
 			else

Modified: lvm2/trunk/lib/mm/dbg_malloc.h
==============================================================================
--- lvm2/trunk/lib/mm/dbg_malloc.h	(original)
+++ lvm2/trunk/lib/mm/dbg_malloc.h	Tue Jun 14 11:23:47 2005
@@ -21,7 +21,9 @@
 #include <string.h>
 
 void *malloc_aux(size_t s, const char *file, int line);
-#  define dbg_malloc(s) malloc_aux((s), __FILE__, __LINE__)
+#define dbg_malloc(s) malloc_aux((s), __FILE__, __LINE__)
+
+char *dbg_strdup(const char *str);
 
 #ifdef DEBUG_MEM
 
@@ -42,14 +44,4 @@
 
 #endif
 
-static inline char *dbg_strdup(const char *str)
-{
-	char *ret = dbg_malloc(strlen(str) + 1);
-
-	if (ret)
-		strcpy(ret, str);
-
-	return ret;
-}
-
 #endif

Modified: lvm2/trunk/lib/report/columns.h
==============================================================================
--- lvm2/trunk/lib/report/columns.h	(original)
+++ lvm2/trunk/lib/report/columns.h	Tue Jun 14 11:23:47 2005
@@ -19,7 +19,7 @@
 
 /* *INDENT-OFF* */
 FIELD(LVS, lv, STR, "LV UUID", lvid.id[1], 38, uuid, "lv_uuid")
-FIELD(LVS, lv, STR, "LV", name, 4, string, "lv_name")
+FIELD(LVS, lv, STR, "LV", lvid, 4, lvname, "lv_name")
 FIELD(LVS, lv, STR, "Attr", lvid, 4, lvstatus, "lv_attr")
 FIELD(LVS, lv, NUM, "Maj", major, 3, int32, "lv_major")
 FIELD(LVS, lv, NUM, "Min", minor, 3, int32, "lv_minor")
@@ -32,6 +32,7 @@
 FIELD(LVS, lv, NUM, "Copy%", lvid, 6, copypercent, "copy_percent")
 FIELD(LVS, lv, STR, "Move", lvid, 4, movepv, "move_pv")
 FIELD(LVS, lv, STR, "LV Tags", tags, 7, tags, "lv_tags")
+FIELD(LVS, lv, STR, "Log", lvid, 3, loglv, "mirror_log")
 
 FIELD(PVS, pv, STR, "Fmt", id, 3, pvfmt, "pv_fmt")
 FIELD(PVS, pv, STR, "PV UUID", id, 38, uuid, "pv_uuid")
@@ -67,8 +68,12 @@
 FIELD(SEGS, seg, NUM, "#Str", area_count, 4, uint32, "stripes")
 FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripesize")
 FIELD(SEGS, seg, NUM, "Chunk", chunk_size, 5, size32, "chunksize")
+FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "regionsize")
 FIELD(SEGS, seg, NUM, "Start", list, 5, segstart, "seg_start")
 FIELD(SEGS, seg, NUM, "SSize", list, 5, segsize, "seg_size")
 FIELD(SEGS, seg, STR, "Seg Tags", tags, 8, tags, "seg_tags")
 FIELD(SEGS, seg, STR, "Devices", list, 5, devices, "devices")
+
+FIELD(PVSEGS, pvseg, NUM, "Start", pe, 5, uint32, "pvseg_start")
+FIELD(PVSEGS, pvseg, NUM, "SSize", len, 5, uint32, "pvseg_size")
 /* *INDENT-ON* */

Modified: lvm2/trunk/lib/report/report.c
==============================================================================
--- lvm2/trunk/lib/report/report.c	(original)
+++ lvm2/trunk/lib/report/report.c	Tue Jun 14 11:23:47 2005
@@ -31,6 +31,7 @@
 	struct logical_volume _lv;
 	struct volume_group _vg;
 	struct lv_segment _seg;
+	struct pv_segment _pvseg;
 } _dummy;
 
 /*
@@ -153,14 +154,14 @@
 	}
 
 	for (s = 0; s < seg->area_count; s++) {
-		switch (seg->area[s].type) {
+		switch (seg_type(seg, s)) {
 		case AREA_LV:
-			name = seg->area[s].u.lv.lv->name;
-			extent = seg->area[s].u.lv.le;
+			name = seg_lv(seg, s)->name;
+			extent = seg_le(seg, s);
 			break;
 		case AREA_PV:
-			name = dev_name(seg->area[s].u.pv.pv->dev);
-			extent = seg->area[s].u.pv.pe;
+			name = dev_name(seg_dev(seg, s));
+			extent = seg_pe(seg, s);
 			break;
 		default:
 			name = "unknown";
@@ -324,7 +325,7 @@
 	const struct logical_volume *lv = (const struct logical_volume *) data;
 	struct lvinfo info;
 	char *repstr;
-	struct snapshot *snap;
+	struct lv_segment *snap_seg;
 	float snap_percent;
 
 	if (!(repstr = pool_zalloc(rh->mem, 7))) {
@@ -336,6 +337,10 @@
 		repstr[0] = 'p';
 	else if (lv->status & MIRRORED)
 		repstr[0] = 'm';
+	else if (lv->status & MIRROR_IMAGE)
+		repstr[0] = 'i';
+	else if (lv->status & MIRROR_LOG)
+		repstr[0] = 'l';
 	else if (lv->status & VIRTUAL)
 		repstr[0] = 'v';
 	else if (lv_is_origin(lv))
@@ -373,8 +378,8 @@
 			repstr[5] = '-';
 
 		/* Snapshot dropped? */
-		if ((snap = find_cow(lv)) &&
-		    (!lv_snapshot_percent(snap->cow, &snap_percent) ||
+		if ((snap_seg = find_cow(lv)) &&
+		    (!lv_snapshot_percent(snap_seg->cow, &snap_percent) ||
 		     snap_percent < 0 || snap_percent >= 100)) {
 			repstr[0] = toupper(repstr[0]);
 			if (info.suspended)
@@ -478,10 +483,10 @@
 			const void *data)
 {
 	const struct logical_volume *lv = (const struct logical_volume *) data;
-	struct snapshot *snap;
+	struct lv_segment *snap_seg;
 
-	if ((snap = find_cow(lv)))
-		return _string_disp(rh, field, &snap->origin->name);
+	if ((snap_seg = find_cow(lv)))
+		return _string_disp(rh, field, &snap_seg->origin->name);
 
 	field->report_string = "";
 	field->sort_value = (const void *) field->report_string;
@@ -489,19 +494,68 @@
 	return 1;
 }
 
+static int _loglv_disp(struct report_handle *rh, struct field *field,
+		       const void *data)
+{
+	const struct logical_volume *lv = (const struct logical_volume *) data;
+	struct lv_segment *seg;
+
+	list_iterate_items(seg, &lv->segments) {
+		if (!seg_is_mirrored(seg) || !seg->log_lv)
+			continue;
+		return _string_disp(rh, field, &seg->log_lv->name);
+	}
+
+	field->report_string = "";
+	field->sort_value = (const void *) field->report_string;
+
+	return 1;
+}
+
+static int _lvname_disp(struct report_handle *rh, struct field *field,
+			const void *data)
+{
+	const struct logical_volume *lv = (const struct logical_volume *) data;
+	char *repstr;
+	size_t len;
+
+	if (lv->status & VISIBLE_LV) {
+		repstr = lv->name;
+		return _string_disp(rh, field, &repstr);
+	}
+
+	len = strlen(lv->name) + 3;
+	if (!(repstr = pool_zalloc(rh->mem, len))) {
+		log_error("pool_alloc failed");
+		return 0;
+	}
+
+	if (lvm_snprintf(repstr, len, "[%s]", lv->name) < 0) {
+		log_error("lvname snprintf failed");
+		return 0;
+	}
+
+	field->report_string = repstr;
+
+	if (!(field->sort_value = pool_strdup(rh->mem, lv->name))) {
+		log_error("pool_strdup failed");
+		return 0;
+	}
+
+	return 1;
+}
+
 static int _movepv_disp(struct report_handle *rh, struct field *field,
 			const void *data)
 {
 	const struct logical_volume *lv = (const struct logical_volume *) data;
 	const char *name;
-	struct list *segh;
 	struct lv_segment *seg;
 
-	list_iterate(segh, &lv->segments) {
-		seg = list_item(segh, struct lv_segment);
+	list_iterate_items(seg, &lv->segments) {
 		if (!(seg->status & PVMOVE))
 			continue;
-		name = dev_name(seg->area[0].u.pv.pv->dev);
+		name = dev_name(seg_dev(seg, 0));
 		return _string_disp(rh, field, &name);
 	}
 
@@ -762,7 +816,7 @@
 			   const void *data)
 {
 	const struct logical_volume *lv = (const struct logical_volume *) data;
-	struct snapshot *snap;
+	struct lv_segment *snap_seg;
 	struct lvinfo info;
 	float snap_percent;
 	uint64_t *sortval;
@@ -773,15 +827,16 @@
 		return 0;
 	}
 
-	if (!(snap = find_cow(lv)) ||
-	    (lv_info(snap->cow, &info, 0) && !info.exists)) {
+	if (!(snap_seg = find_cow(lv)) ||
+	    (lv_info(snap_seg->cow, &info, 0) && !info.exists)) {
 		field->report_string = "";
 		*sortval = UINT64_C(0);
 		field->sort_value = sortval;
 		return 1;
 	}
 
-	if (!lv_snapshot_percent(snap->cow, &snap_percent) || snap_percent < 0) {
+	if (!lv_snapshot_percent(snap_seg->cow, &snap_percent)
+	    || snap_percent < 0) {
 		field->report_string = "100.00";
 		*sortval = UINT64_C(100);
 		field->sort_value = sortval;
@@ -855,9 +910,9 @@
 
 static struct {
 	report_type_t type;
-	const char id[30];
+	const char id[32];
 	off_t offset;
-	const char heading[30];
+	const char heading[32];
 	int width;
 	uint32_t flags;
 	field_report_fn report_fn;
@@ -915,12 +970,9 @@
 static int _add_sort_key(struct report_handle *rh, uint32_t field_num,
 			 uint32_t flags)
 {
-	struct list *fh;
 	struct field_properties *fp, *found = NULL;
 
-	list_iterate(fh, &rh->field_props) {
-		fp = list_item(fh, struct field_properties);
-
+	list_iterate_items(fp, &rh->field_props) {
 		if (fp->field_num == field_num) {
 			found = fp;
 			break;
@@ -1077,6 +1129,9 @@
 	case SEGS:
 		rh->field_prefix = "seg_";
 		break;
+	case PVSEGS:
+		rh->field_prefix = "pvseg_";
+		break;
 	default:
 		rh->field_prefix = "";
 	}
@@ -1096,6 +1151,8 @@
 	/* Ensure options selected are compatible */
 	if (rh->type & SEGS)
 		rh->type |= LVS;
+	if (rh->type & PVSEGS)
+		rh->type |= PVS;
 	if ((rh->type & LVS) && (rh->type & PVS)) {
 		log_error("Can't report LV and PV fields at the same time");
 		return NULL;
@@ -1106,6 +1163,8 @@
 		*report_type = SEGS;
 	else if (rh->type & LVS)
 		*report_type = LVS;
+	else if (rh->type & PVSEGS)
+		*report_type = PVSEGS;
 	else if (rh->type & PVS)
 		*report_type = PVS;
 
@@ -1126,10 +1185,9 @@
  */
 int report_object(void *handle, struct volume_group *vg,
 		  struct logical_volume *lv, struct physical_volume *pv,
-		  struct lv_segment *seg)
+		  struct lv_segment *seg, struct pv_segment *pvseg)
 {
 	struct report_handle *rh = handle;
-	struct list *fh;
 	struct field_properties *fp;
 	struct row *row;
 	struct field *field;
@@ -1159,9 +1217,7 @@
 	list_add(&rh->rows, &row->list);
 
 	/* For each field to be displayed, call its report_fn */
-	list_iterate(fh, &rh->field_props) {
-		fp = list_item(fh, struct field_properties);
-
+	list_iterate_items(fp, &rh->field_props) {
 		skip = 0;
 
 		if (!(field = pool_zalloc(rh->mem, sizeof(*field)))) {
@@ -1186,6 +1242,9 @@
 			break;
 		case SEGS:
 			data = (void *) seg + _fields[fp->field_num].offset;
+			break;
+		case PVSEGS:
+			data = (void *) pvseg + _fields[fp->field_num].offset;
 		}
 
 		if (skip) {
@@ -1219,7 +1278,6 @@
 static int _report_headings(void *handle)
 {
 	struct report_handle *rh = handle;
-	struct list *fh;
 	struct field_properties *fp;
 	const char *heading;
 	char buf[1024];
@@ -1238,8 +1296,7 @@
 	}
 
 	/* First heading line */
-	list_iterate(fh, &rh->field_props) {
-		fp = list_item(fh, struct field_properties);
+	list_iterate_items(fp, &rh->field_props) {
 		if (fp->flags & FLD_HIDDEN)
 			continue;
 
@@ -1256,7 +1313,7 @@
 		} else if (!pool_grow_object(rh->mem, heading, strlen(heading)))
 			goto bad;
 
-		if (!list_end(&rh->field_props, fh))
+		if (!list_end(&rh->field_props, &fp->list))
 			if (!pool_grow_object(rh->mem, rh->separator,
 					      strlen(rh->separator)))
 				goto bad;
@@ -1324,7 +1381,6 @@
 static int _sort_rows(struct report_handle *rh)
 {
 	struct row *(*rows)[];
-	struct list *rowh;
 	uint32_t count = 0;
 	struct row *row;
 
@@ -1334,10 +1390,8 @@
 		return 0;
 	}
 
-	list_iterate(rowh, &rh->rows) {
-		row = list_item(rowh, struct row);
+	list_iterate_items(row, &rh->rows)
 		(*rows)[count++] = row;
-	}
 
 	qsort(rows, count, sizeof(**rows), _row_compare);
 

Modified: lvm2/trunk/lib/report/report.h
==============================================================================
--- lvm2/trunk/lib/report/report.h	(original)
+++ lvm2/trunk/lib/report/report.h	Tue Jun 14 11:23:47 2005
@@ -18,7 +18,7 @@
 
 #include "metadata.h"
 
-typedef enum { LVS = 1, PVS = 2, VGS = 4, SEGS = 8 } report_type_t;
+typedef enum { LVS = 1, PVS = 2, VGS = 4, SEGS = 8, PVSEGS = 16 } report_type_t;
 
 struct field;
 struct report_handle;
@@ -32,7 +32,7 @@
 void report_free(void *handle);
 int report_object(void *handle, struct volume_group *vg,
 		  struct logical_volume *lv, struct physical_volume *pv,
-		  struct lv_segment *seg);
+		  struct lv_segment *seg, struct pv_segment *pvseg);
 int report_output(void *handle);
 
 #endif

Modified: lvm2/trunk/lib/snapshot/snapshot.c
==============================================================================
--- lvm2/trunk/lib/snapshot/snapshot.c	(original)
+++ lvm2/trunk/lib/snapshot/snapshot.c	Tue Jun 14 11:23:47 2005
@@ -70,8 +70,8 @@
 		return 0;
 	}
 
-	if (!vg_add_snapshot(org, cow, 1, &seg->lv->lvid.id[1], seg->len,
-			     chunk_size)) {
+	if (!vg_add_snapshot(seg->lv->vg->fid, seg->lv->name, org, cow,
+			     &seg->lv->lvid, seg->len, chunk_size)) {
 		stack;
 		return 0;
 	}

Modified: lvm2/trunk/lib/striped/striped.c
==============================================================================
--- lvm2/trunk/lib/striped/striped.c	(original)
+++ lvm2/trunk/lib/striped/striped.c	Tue Jun 14 11:23:47 2005
@@ -26,6 +26,7 @@
 #include "targets.h"
 #include "lvm-string.h"
 #include "activate.h"
+#include "pv_alloc.h"
 
 static const char *_name(const struct lv_segment *seg)
 {
@@ -81,7 +82,7 @@
 
 	seg->area_len /= seg->area_count;
 
-	return text_import_areas(seg, sn, cn, pv_hash);
+	return text_import_areas(seg, sn, cn, pv_hash, 0);
 }
 
 static int _text_export(const struct lv_segment *seg, struct formatter *f)
@@ -118,8 +119,10 @@
 
 		width = first->area_len;
 
-		if ((first->area[s].u.pv.pv != second->area[s].u.pv.pv) ||
-		    (first->area[s].u.pv.pe + width != second->area[s].u.pv.pe))
+		if ((seg_pv(first, s) !=
+		     seg_pv(second, s)) ||
+		    (seg_pe(first, s) + width !=
+		     seg_pe(second, s)))
 			return 0;
 	}
 
@@ -131,12 +134,19 @@
 
 static int _merge_segments(struct lv_segment *seg1, struct lv_segment *seg2)
 {
+	uint32_t s;
+
 	if (!_segments_compatible(seg1, seg2))
 		return 0;
 
 	seg1->len += seg2->len;
 	seg1->area_len += seg2->area_len;
 
+	for (s = 0; s < seg1->area_count; s++)
+		if (seg1->area[s].type == AREA_PV)
+			merge_pv_segments(seg_pvseg(seg1, s),
+					  seg_pvseg(seg2, s));
+
 	return 1;
 }
 

Modified: lvm2/trunk/lib/uuid/uuid.h
==============================================================================
--- lvm2/trunk/lib/uuid/uuid.h	(original)
+++ lvm2/trunk/lib/uuid/uuid.h	Tue Jun 14 11:23:47 2005
@@ -25,11 +25,11 @@
 
 /*
  * Unique logical volume identifier
- * With format1 this is VG uuid + LV uuid + '\0'
+ * With format1 this is VG uuid + LV uuid + '\0' + padding
  */
 union lvid {
 	struct id id[2];
-	char s[2 * sizeof(struct id) + 1];
+	char s[2 * sizeof(struct id) + 1 + 7];
 };
 
 int lvid_from_lvnum(union lvid *lvid, struct id *vgid, uint32_t lv_num);

Modified: lvm2/trunk/man/pvcreate.8
==============================================================================
--- lvm2/trunk/man/pvcreate.8	(original)
+++ lvm2/trunk/man/pvcreate.8	Tue Jun 14 11:23:47 2005
@@ -91,10 +91,10 @@
 .BR \-\-metadatacopies " copies"
 The number of metadata areas to set aside on each PV.  Currently
 this can be 0, 1 or 2.  
-If set to 2 (the default), two copies of the volume group metadata 
+If set to 2, two copies of the volume group metadata 
 are held on the PV, one at the front of the PV and one at the end.  
-If set to 1, one copy is kept at the front of the PV (starting in the
-5th sector).
+If set to 1 (the default), one copy is kept at the front of the PV 
+(starting in the 5th sector).
 If set to 0, no copies are kept on this PV - you might wish to use this
 with VGs containing large numbers of PVs.  But if you do this and
 then later use \fBvgsplit\fP you must ensure that each VG is still going 

Modified: lvm2/trunk/po/lvm2.po
==============================================================================
--- lvm2/trunk/po/lvm2.po	(original)
+++ lvm2/trunk/po/lvm2.po	Tue Jun 14 11:23:47 2005
@@ -7,7 +7,7 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
-"POT-Creation-Date: 2005-02-01 16:32+0000\n"
+"POT-Creation-Date: 2005-06-13 15:43+0100\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL at ADDRESS>\n"
 "Language-Team: LANGUAGE <LL at li.org>\n"
@@ -53,9 +53,9 @@
 #: activate/activate.c:418 activate/activate.c:426 activate/activate.c:431
 #: activate/activate.c:443 activate/activate.c:455 activate/activate.c:469
 #: activate/activate.c:474 activate/activate.c:486 activate/activate.c:491
-#: activate/activate.c:503 activate/activate.c:508 activate/activate.c:572
-#: activate/activate.c:618 activate/activate.c:663 activate/activate.c:732
-#: activate/activate.c:771 activate/dev_manager.c:179
+#: activate/activate.c:503 activate/activate.c:508 activate/activate.c:568
+#: activate/activate.c:614 activate/activate.c:659 activate/activate.c:728
+#: activate/activate.c:767 activate/dev_manager.c:179
 #: activate/dev_manager.c:197 activate/dev_manager.c:225
 #: activate/dev_manager.c:234 activate/dev_manager.c:239
 #: activate/dev_manager.c:245 activate/dev_manager.c:286
@@ -67,238 +67,269 @@
 #: activate/dev_manager.c:555 activate/dev_manager.c:615
 #: activate/dev_manager.c:621 activate/dev_manager.c:628
 #: activate/dev_manager.c:657 activate/dev_manager.c:714
-#: activate/dev_manager.c:723 activate/dev_manager.c:778
-#: activate/dev_manager.c:803 activate/dev_manager.c:846
-#: activate/dev_manager.c:866 activate/dev_manager.c:889
-#: activate/dev_manager.c:894 activate/dev_manager.c:925
-#: activate/dev_manager.c:933 activate/dev_manager.c:950
-#: activate/dev_manager.c:955 activate/dev_manager.c:970
-#: activate/dev_manager.c:975 activate/dev_manager.c:1008
-#: activate/dev_manager.c:1018 activate/dev_manager.c:1034
-#: activate/dev_manager.c:1044 activate/dev_manager.c:1066
-#: activate/dev_manager.c:1075 activate/dev_manager.c:1089
-#: activate/dev_manager.c:1097 activate/dev_manager.c:1110
-#: activate/dev_manager.c:1130 activate/dev_manager.c:1135
-#: activate/dev_manager.c:1141 activate/dev_manager.c:1163
-#: activate/dev_manager.c:1184 activate/dev_manager.c:1206
-#: activate/dev_manager.c:1218 activate/dev_manager.c:1230
-#: activate/dev_manager.c:1244 activate/dev_manager.c:1257
-#: activate/dev_manager.c:1267 activate/dev_manager.c:1307
-#: activate/dev_manager.c:1318 activate/dev_manager.c:1328
-#: activate/dev_manager.c:1335 activate/dev_manager.c:1341
-#: activate/dev_manager.c:1409 activate/dev_manager.c:1428
-#: activate/dev_manager.c:1450 activate/dev_manager.c:1458
-#: activate/dev_manager.c:1486 activate/dev_manager.c:1491
-#: activate/dev_manager.c:1520 activate/dev_manager.c:1526
-#: activate/dev_manager.c:1547 activate/dev_manager.c:1565
-#: activate/dev_manager.c:1579 activate/dev_manager.c:1589
-#: activate/dev_manager.c:1599 activate/dev_manager.c:1617
-#: activate/dev_manager.c:1640 activate/dev_manager.c:1674
-#: activate/dev_manager.c:1690 activate/dev_manager.c:1748
-#: activate/dev_manager.c:1757 activate/dev_manager.c:1766
-#: activate/dev_manager.c:1775 activate/dev_manager.c:1780
-#: activate/dev_manager.c:1785 activate/dev_manager.c:1797
-#: activate/dev_manager.c:1807 activate/dev_manager.c:1813
-#: activate/dev_manager.c:1849 activate/dev_manager.c:1854
-#: activate/dev_manager.c:1886 activate/dev_manager.c:1904
-#: activate/dev_manager.c:2079 activate/dev_manager.c:2091
-#: activate/dev_manager.c:2097 activate/dev_manager.c:2111
-#: activate/dev_manager.c:2116 activate/dev_manager.c:2123
-#: activate/dev_manager.c:2131 activate/dev_manager.c:2139
-#: activate/dev_manager.c:2145 activate/dev_manager.c:2152
-#: activate/dev_manager.c:2157 activate/dev_manager.c:2185 activate/fs.c:234
-#: activate/fs.c:241 activate/fs.c:248 activate/fs.c:251 activate/fs.c:325
-#: archiver.c:71 archiver.c:78 archiver.c:90 archiver.c:166 archiver.c:236
-#: archiver.c:286 archiver.c:303 archiver.c:345 archiver.c:350
-#: cache/lvmcache.c:454 cache/lvmcache.c:495 cache/lvmcache.c:526
-#: commands/toolcontext.c:274 commands/toolcontext.c:293
-#: commands/toolcontext.c:300 commands/toolcontext.c:377
-#: commands/toolcontext.c:392 commands/toolcontext.c:416
-#: commands/toolcontext.c:467 commands/toolcontext.c:643
-#: commands/toolcontext.c:740 config/config.c:105 config/config.c:110
-#: config/config.c:140 config/config.c:161 config/config.c:192
-#: config/config.c:239 config/config.c:244 config/config.c:406
-#: config/config.c:424 config/config.c:429 config/config.c:439
-#: config/config.c:453 config/config.c:469 config/config.c:525
-#: config/config.c:708 datastruct/btree.c:90 datastruct/hash.c:96
-#: datastruct/hash.c:109 datastruct/str_list.c:24 datastruct/str_list.c:38
-#: datastruct/str_list.c:47 datastruct/str_list.c:77 device/dev-cache.c:182
-#: device/dev-cache.c:189 device/dev-cache.c:195 device/dev-cache.c:229
-#: device/dev-cache.c:300 device/dev-cache.c:348 device/dev-cache.c:393
-#: device/dev-cache.c:398 device/dev-io.c:174 device/dev-io.c:204
-#: device/dev-io.c:322 device/dev-io.c:465 device/dev-io.c:486
-#: device/dev-io.c:504 device/dev-io.c:523 device/dev-io.c:551
-#: device/dev-md.c:41 device/dev-md.c:49 device/dev-md.c:64 device/device.c:61
-#: device/device.c:66 device/device.c:90 display/display.c:211
-#: display/display.c:242 display/display.c:300 display/display.c:347
-#: display/display.c:587 display/display.c:623 error/errseg.c:90
-#: filters/filter-composite.c:54 filters/filter-persistent.c:45
-#: filters/filter-persistent.c:103 filters/filter-persistent.c:108
-#: filters/filter-persistent.c:239 filters/filter-persistent.c:245
-#: filters/filter-persistent.c:257 filters/filter-regex.c:78
-#: filters/filter-regex.c:105 filters/filter-regex.c:126
-#: filters/filter-regex.c:151 filters/filter-regex.c:212
-#: filters/filter-regex.c:217 filters/filter-regex.c:224
-#: filters/filter-regex.c:229 filters/filter-sysfs.c:285 filters/filter.c:253
-#: format1/disk-rep.c:220 format1/disk-rep.c:232 format1/disk-rep.c:237
-#: format1/disk-rep.c:256 format1/disk-rep.c:259 format1/disk-rep.c:290
-#: format1/disk-rep.c:293 format1/disk-rep.c:312 format1/disk-rep.c:315
-#: format1/disk-rep.c:332 format1/disk-rep.c:342 format1/disk-rep.c:348
-#: format1/disk-rep.c:413 format1/disk-rep.c:420 format1/disk-rep.c:511
-#: format1/disk-rep.c:534 format1/disk-rep.c:546 format1/disk-rep.c:576
-#: format1/disk-rep.c:590 format1/disk-rep.c:623 format1/disk-rep.c:688
-#: format1/disk-rep.c:695 format1/disk-rep.c:713 format1/format1.c:177
-#: format1/format1.c:192 format1/format1.c:201 format1/format1.c:206
-#: format1/format1.c:223 format1/format1.c:237 format1/format1.c:258
-#: format1/format1.c:269 format1/format1.c:284 format1/format1.c:310
-#: format1/format1.c:315 format1/format1.c:320 format1/format1.c:325
-#: format1/format1.c:362 format1/format1.c:409 format1/format1.c:425
-#: format1/format1.c:430 format1/format1.c:437 format1/format1.c:449
-#: format1/format1.c:500 format1/format1.c:520 format1/format1.c:529
-#: format1/format1.c:573 format1/import-export.c:61
-#: format1/import-export.c:121 format1/import-export.c:141
-#: format1/import-export.c:158 format1/import-export.c:166
-#: format1/import-export.c:201 format1/import-export.c:206
-#: format1/import-export.c:211 format1/import-export.c:289
-#: format1/import-export.c:426 format1/import-export.c:431
-#: format1/import-export.c:452 format1/import-export.c:459
-#: format1/import-export.c:484 format1/import-export.c:506
-#: format1/import-export.c:511 format1/import-export.c:520
-#: format1/import-export.c:528 format1/import-export.c:539
-#: format1/import-export.c:544 format1/import-export.c:669
-#: format1/import-export.c:726 format1/import-extents.c:65
+#: activate/dev_manager.c:723 activate/dev_manager.c:745
+#: activate/dev_manager.c:769 activate/dev_manager.c:828
+#: activate/dev_manager.c:853 activate/dev_manager.c:894
+#: activate/dev_manager.c:914 activate/dev_manager.c:938
+#: activate/dev_manager.c:943 activate/dev_manager.c:974
+#: activate/dev_manager.c:982 activate/dev_manager.c:999
+#: activate/dev_manager.c:1004 activate/dev_manager.c:1019
+#: activate/dev_manager.c:1024 activate/dev_manager.c:1057
+#: activate/dev_manager.c:1067 activate/dev_manager.c:1083
+#: activate/dev_manager.c:1093 activate/dev_manager.c:1115
+#: activate/dev_manager.c:1124 activate/dev_manager.c:1138
+#: activate/dev_manager.c:1146 activate/dev_manager.c:1159
+#: activate/dev_manager.c:1179 activate/dev_manager.c:1184
+#: activate/dev_manager.c:1190 activate/dev_manager.c:1212
+#: activate/dev_manager.c:1232 activate/dev_manager.c:1250
+#: activate/dev_manager.c:1262 activate/dev_manager.c:1274
+#: activate/dev_manager.c:1286 activate/dev_manager.c:1300
+#: activate/dev_manager.c:1313 activate/dev_manager.c:1323
+#: activate/dev_manager.c:1363 activate/dev_manager.c:1374
+#: activate/dev_manager.c:1384 activate/dev_manager.c:1392
+#: activate/dev_manager.c:1399 activate/dev_manager.c:1467
+#: activate/dev_manager.c:1486 activate/dev_manager.c:1508
+#: activate/dev_manager.c:1516 activate/dev_manager.c:1544
+#: activate/dev_manager.c:1549 activate/dev_manager.c:1578
+#: activate/dev_manager.c:1584 activate/dev_manager.c:1605
+#: activate/dev_manager.c:1623 activate/dev_manager.c:1637
+#: activate/dev_manager.c:1647 activate/dev_manager.c:1657
+#: activate/dev_manager.c:1675 activate/dev_manager.c:1698
+#: activate/dev_manager.c:1732 activate/dev_manager.c:1748
+#: activate/dev_manager.c:1805 activate/dev_manager.c:1814
+#: activate/dev_manager.c:1823 activate/dev_manager.c:1832
+#: activate/dev_manager.c:1837 activate/dev_manager.c:1842
+#: activate/dev_manager.c:1854 activate/dev_manager.c:1864
+#: activate/dev_manager.c:1870 activate/dev_manager.c:1906
+#: activate/dev_manager.c:1911 activate/dev_manager.c:1943
+#: activate/dev_manager.c:1961 activate/dev_manager.c:2137
+#: activate/dev_manager.c:2149 activate/dev_manager.c:2155
+#: activate/dev_manager.c:2169 activate/dev_manager.c:2174
+#: activate/dev_manager.c:2181 activate/dev_manager.c:2189
+#: activate/dev_manager.c:2197 activate/dev_manager.c:2203
+#: activate/dev_manager.c:2210 activate/dev_manager.c:2215
+#: activate/dev_manager.c:2243 activate/fs.c:234 activate/fs.c:241
+#: activate/fs.c:248 activate/fs.c:251 activate/fs.c:325 archiver.c:68
+#: archiver.c:75 archiver.c:87 archiver.c:163 archiver.c:236 archiver.c:286
+#: archiver.c:303 archiver.c:345 archiver.c:350 cache/lvmcache.c:474
+#: cache/lvmcache.c:515 cache/lvmcache.c:546 commands/toolcontext.c:276
+#: commands/toolcontext.c:295 commands/toolcontext.c:302
+#: commands/toolcontext.c:379 commands/toolcontext.c:394
+#: commands/toolcontext.c:418 commands/toolcontext.c:469
+#: commands/toolcontext.c:662 commands/toolcontext.c:758 config/config.c:105
+#: config/config.c:110 config/config.c:140 config/config.c:161
+#: config/config.c:192 config/config.c:239 config/config.c:244
+#: config/config.c:406 config/config.c:424 config/config.c:429
+#: config/config.c:439 config/config.c:453 config/config.c:469
+#: config/config.c:525 config/config.c:708 datastruct/btree.c:90
+#: datastruct/hash.c:96 datastruct/hash.c:109 datastruct/str_list.c:24
+#: datastruct/str_list.c:38 datastruct/str_list.c:47 datastruct/str_list.c:77
+#: device/dev-cache.c:204 device/dev-cache.c:217 device/dev-cache.c:260
+#: device/dev-cache.c:264 device/dev-cache.c:335 device/dev-cache.c:366
+#: device/dev-cache.c:405 device/dev-cache.c:451 device/dev-cache.c:456
+#: device/dev-io.c:174 device/dev-io.c:204 device/dev-io.c:348
+#: device/dev-io.c:516 device/dev-io.c:537 device/dev-io.c:555
+#: device/dev-io.c:574 device/dev-io.c:602 device/dev-md.c:41
+#: device/dev-md.c:49 device/dev-md.c:64 device/device.c:61 device/device.c:66
+#: device/device.c:90 display/display.c:211 display/display.c:242
+#: display/display.c:300 display/display.c:346 display/display.c:575
+#: display/display.c:611 error/errseg.c:90 filters/filter-composite.c:54
+#: filters/filter-persistent.c:45 filters/filter-persistent.c:105
+#: filters/filter-persistent.c:110 filters/filter-persistent.c:239
+#: filters/filter-persistent.c:245 filters/filter-persistent.c:257
+#: filters/filter-regex.c:78 filters/filter-regex.c:105
+#: filters/filter-regex.c:126 filters/filter-regex.c:151
+#: filters/filter-regex.c:210 filters/filter-regex.c:215
+#: filters/filter-regex.c:222 filters/filter-regex.c:227
+#: filters/filter-sysfs.c:285 filters/filter.c:254 format1/disk-rep.c:220
+#: format1/disk-rep.c:232 format1/disk-rep.c:237 format1/disk-rep.c:256
+#: format1/disk-rep.c:259 format1/disk-rep.c:290 format1/disk-rep.c:293
+#: format1/disk-rep.c:312 format1/disk-rep.c:315 format1/disk-rep.c:332
+#: format1/disk-rep.c:342 format1/disk-rep.c:348 format1/disk-rep.c:413
+#: format1/disk-rep.c:420 format1/disk-rep.c:511 format1/disk-rep.c:532
+#: format1/disk-rep.c:544 format1/disk-rep.c:572 format1/disk-rep.c:586
+#: format1/disk-rep.c:619 format1/disk-rep.c:684 format1/disk-rep.c:691
+#: format1/disk-rep.c:707 format1/format1.c:174 format1/format1.c:189
+#: format1/format1.c:198 format1/format1.c:203 format1/format1.c:220
+#: format1/format1.c:234 format1/format1.c:252 format1/format1.c:263
+#: format1/format1.c:278 format1/format1.c:304 format1/format1.c:309
+#: format1/format1.c:314 format1/format1.c:319 format1/format1.c:356
+#: format1/format1.c:403 format1/format1.c:419 format1/format1.c:424
+#: format1/format1.c:431 format1/format1.c:443 format1/format1.c:494
+#: format1/format1.c:514 format1/format1.c:523 format1/format1.c:567
+#: format1/import-export.c:62 format1/import-export.c:96
+#: format1/import-export.c:128 format1/import-export.c:148
+#: format1/import-export.c:165 format1/import-export.c:173
+#: format1/import-export.c:208 format1/import-export.c:213
+#: format1/import-export.c:218 format1/import-export.c:296
+#: format1/import-export.c:428 format1/import-export.c:433
+#: format1/import-export.c:454 format1/import-export.c:461
+#: format1/import-export.c:483 format1/import-export.c:504
+#: format1/import-export.c:509 format1/import-export.c:518
+#: format1/import-export.c:528 format1/import-export.c:538
+#: format1/import-export.c:543 format1/import-export.c:646
+#: format1/import-export.c:694 format1/import-extents.c:65
 #: format1/import-extents.c:72 format1/import-extents.c:77
-#: format1/import-extents.c:133 format1/import-extents.c:199
-#: format1/import-extents.c:216 format1/import-extents.c:281
-#: format1/import-extents.c:287 format1/import-extents.c:335
-#: format1/import-extents.c:351 format1/import-extents.c:366
-#: format1/layout.c:124 format1/lvm1-label.c:66 format1/vg_number.c:39
-#: format1/vg_number.c:44 format_pool/disk_rep.c:51 format_pool/disk_rep.c:107
-#: format_pool/disk_rep.c:263 format_pool/disk_rep.c:366
-#: format_pool/disk_rep.c:376 format_pool/disk_rep.c:381
+#: format1/import-extents.c:130 format1/import-extents.c:196
+#: format1/import-extents.c:210 format1/import-extents.c:231
+#: format1/import-extents.c:280 format1/import-extents.c:312
+#: format1/import-extents.c:338 format1/import-extents.c:354
+#: format1/import-extents.c:369 format1/layout.c:124 format1/lvm1-label.c:66
+#: format1/vg_number.c:38 format1/vg_number.c:43 format_pool/disk_rep.c:51
+#: format_pool/disk_rep.c:104 format_pool/disk_rep.c:258
+#: format_pool/disk_rep.c:360 format_pool/disk_rep.c:370
+#: format_pool/disk_rep.c:375 format_pool/format_pool.c:134
 #: format_pool/format_pool.c:139 format_pool/format_pool.c:144
-#: format_pool/format_pool.c:149 format_pool/format_pool.c:159
-#: format_pool/format_pool.c:168 format_pool/format_pool.c:173
-#: format_pool/format_pool.c:193 format_pool/format_pool.c:202
-#: format_pool/format_pool.c:208 format_pool/format_pool.c:238
-#: format_pool/format_pool.c:243 format_pool/format_pool.c:253
-#: format_pool/format_pool.c:258 format_pool/import_export.c:97
-#: format_pool/import_export.c:223 format_pool/import_export.c:260
-#: format_pool/import_export.c:296 format_pool/import_export.c:301
-#: format_text/archive.c:122 format_text/archive.c:142
-#: format_text/archive.c:169 format_text/archive.c:264
-#: format_text/archive.c:374 format_text/export.c:257 format_text/export.c:258
-#: format_text/export.c:259 format_text/export.c:262 format_text/export.c:264
-#: format_text/export.c:267 format_text/export.c:277 format_text/export.c:281
-#: format_text/export.c:283 format_text/export.c:286 format_text/export.c:289
-#: format_text/export.c:293 format_text/export.c:296 format_text/export.c:300
-#: format_text/export.c:304 format_text/export.c:307 format_text/export.c:308
-#: format_text/export.c:313 format_text/export.c:338 format_text/export.c:345
-#: format_text/export.c:350 format_text/export.c:354 format_text/export.c:358
-#: format_text/export.c:360 format_text/export.c:366 format_text/export.c:369
-#: format_text/export.c:373 format_text/export.c:376 format_text/export.c:379
-#: format_text/export.c:382 format_text/export.c:387 format_text/export.c:391
-#: format_text/export.c:400 format_text/export.c:403 format_text/export.c:406
-#: format_text/export.c:411 format_text/export.c:415 format_text/export.c:418
-#: format_text/export.c:423 format_text/export.c:428 format_text/export.c:441
-#: format_text/export.c:448 format_text/export.c:452 format_text/export.c:457
-#: format_text/export.c:465 format_text/export.c:488 format_text/export.c:492
-#: format_text/export.c:496 format_text/export.c:500 format_text/export.c:504
-#: format_text/export.c:505 format_text/export.c:511 format_text/export.c:533
-#: format_text/export.c:538 format_text/export.c:553 format_text/export.c:575
-#: format_text/export.c:582 format_text/export.c:587 format_text/export.c:591
-#: format_text/export.c:594 format_text/export.c:597 format_text/export.c:601
-#: format_text/export.c:604 format_text/export.c:608 format_text/export.c:612
-#: format_text/export.c:614 format_text/export.c:616 format_text/export.c:617
-#: format_text/export.c:623 format_text/export.c:629 format_text/export.c:633
-#: format_text/export.c:638 format_text/export.c:656 format_text/export.c:661
-#: format_text/export.c:670 format_text/export.c:675 format_text/export.c:680
-#: format_text/export.c:703 format_text/export.c:709 format_text/export.c:712
-#: format_text/export.c:717 format_text/export.c:721 format_text/export.c:725
-#: format_text/export.c:729 format_text/export.c:732 format_text/export.c:755
-#: format_text/export.c:783 format_text/export.c:796 format_text/flags.c:88
-#: format_text/flags.c:132 format_text/format-text.c:128
-#: format_text/format-text.c:176 format_text/format-text.c:198
-#: format_text/format-text.c:219 format_text/format-text.c:232
-#: format_text/format-text.c:240 format_text/format-text.c:257
-#: format_text/format-text.c:262 format_text/format-text.c:267
-#: format_text/format-text.c:287 format_text/format-text.c:296
-#: format_text/format-text.c:338 format_text/format-text.c:343
-#: format_text/format-text.c:388 format_text/format-text.c:401
-#: format_text/format-text.c:418 format_text/format-text.c:447
-#: format_text/format-text.c:473 format_text/format-text.c:500
-#: format_text/format-text.c:514 format_text/format-text.c:519
-#: format_text/format-text.c:542 format_text/format-text.c:556
-#: format_text/format-text.c:793 format_text/format-text.c:798
-#: format_text/format-text.c:807 format_text/format-text.c:818
-#: format_text/format-text.c:831 format_text/format-text.c:1014
-#: format_text/format-text.c:1072 format_text/format-text.c:1077
-#: format_text/format-text.c:1088 format_text/format-text.c:1090
-#: format_text/format-text.c:1098 format_text/format-text.c:1168
-#: format_text/format-text.c:1174 format_text/format-text.c:1353
-#: format_text/format-text.c:1359 format_text/format-text.c:1378
-#: format_text/format-text.c:1412 format_text/format-text.c:1432
-#: format_text/format-text.c:1450 format_text/format-text.c:1455
-#: format_text/format-text.c:1469 format_text/format-text.c:1482
-#: format_text/format-text.c:1488 format_text/format-text.c:1519
-#: format_text/format-text.c:1524 format_text/format-text.c:1529
-#: format_text/format-text.c:1538 format_text/format-text.c:1641
+#: format_pool/format_pool.c:154 format_pool/format_pool.c:163
+#: format_pool/format_pool.c:168 format_pool/format_pool.c:188
+#: format_pool/format_pool.c:197 format_pool/format_pool.c:203
+#: format_pool/format_pool.c:233 format_pool/format_pool.c:238
+#: format_pool/format_pool.c:248 format_pool/format_pool.c:253
+#: format_pool/import_export.c:94 format_pool/import_export.c:180
+#: format_pool/import_export.c:218 format_pool/import_export.c:232
+#: format_pool/import_export.c:256 format_pool/import_export.c:276
+#: format_pool/import_export.c:304 format_pool/import_export.c:309
+#: format_text/archive.c:119 format_text/archive.c:140
+#: format_text/archive.c:167 format_text/archive.c:259
+#: format_text/archive.c:270 format_text/archive.c:346
+#: format_text/archive.c:366 format_text/archiver.c:82
+#: format_text/archiver.c:89 format_text/archiver.c:101
+#: format_text/archiver.c:189 format_text/archiver.c:267
+#: format_text/archiver.c:317 format_text/archiver.c:334
+#: format_text/archiver.c:376 format_text/archiver.c:381
+#: format_text/export.c:113 format_text/export.c:178 format_text/export.c:188
+#: format_text/export.c:279 format_text/export.c:280 format_text/export.c:281
+#: format_text/export.c:282 format_text/export.c:284 format_text/export.c:285
+#: format_text/export.c:286 format_text/export.c:289 format_text/export.c:299
+#: format_text/export.c:303 format_text/export.c:305 format_text/export.c:308
+#: format_text/export.c:311 format_text/export.c:315 format_text/export.c:318
+#: format_text/export.c:322 format_text/export.c:326 format_text/export.c:329
+#: format_text/export.c:330 format_text/export.c:334 format_text/export.c:335
+#: format_text/export.c:360 format_text/export.c:367 format_text/export.c:371
+#: format_text/export.c:372 format_text/export.c:376 format_text/export.c:380
+#: format_text/export.c:382 format_text/export.c:385 format_text/export.c:388
+#: format_text/export.c:391 format_text/export.c:395 format_text/export.c:398
+#: format_text/export.c:401 format_text/export.c:404 format_text/export.c:409
+#: format_text/export.c:413 format_text/export.c:422 format_text/export.c:425
+#: format_text/export.c:428 format_text/export.c:432 format_text/export.c:433
+#: format_text/export.c:437 format_text/export.c:440 format_text/export.c:445
+#: format_text/export.c:450 format_text/export.c:461 format_text/export.c:463
+#: format_text/export.c:470 format_text/export.c:474 format_text/export.c:479
+#: format_text/export.c:487 format_text/export.c:497 format_text/export.c:498
+#: format_text/export.c:503 format_text/export.c:507 format_text/export.c:510
+#: format_text/export.c:513 format_text/export.c:517 format_text/export.c:520
+#: format_text/export.c:524 format_text/export.c:528 format_text/export.c:530
+#: format_text/export.c:532 format_text/export.c:533 format_text/export.c:534
+#: format_text/export.c:539 format_text/export.c:545 format_text/export.c:560
+#: format_text/export.c:570 format_text/export.c:579 format_text/export.c:585
+#: format_text/export.c:603 format_text/export.c:608 format_text/export.c:617
+#: format_text/export.c:622 format_text/export.c:627 format_text/export.c:650
+#: format_text/export.c:656 format_text/export.c:659 format_text/export.c:664
+#: format_text/export.c:666 format_text/export.c:668 format_text/export.c:670
+#: format_text/export.c:672 format_text/export.c:676 format_text/export.c:679
+#: format_text/export.c:702 format_text/export.c:729 format_text/export.c:747
+#: format_text/flags.c:91 format_text/flags.c:135
+#: format_text/format-text.c:128 format_text/format-text.c:176
+#: format_text/format-text.c:203 format_text/format-text.c:244
+#: format_text/format-text.c:249 format_text/format-text.c:257
+#: format_text/format-text.c:275 format_text/format-text.c:280
+#: format_text/format-text.c:305 format_text/format-text.c:315
+#: format_text/format-text.c:362 format_text/format-text.c:367
+#: format_text/format-text.c:402 format_text/format-text.c:415
+#: format_text/format-text.c:432 format_text/format-text.c:463
+#: format_text/format-text.c:494 format_text/format-text.c:532
+#: format_text/format-text.c:546 format_text/format-text.c:551
+#: format_text/format-text.c:574 format_text/format-text.c:588
+#: format_text/format-text.c:833 format_text/format-text.c:838
+#: format_text/format-text.c:847 format_text/format-text.c:858
+#: format_text/format-text.c:871 format_text/format-text.c:1063
+#: format_text/format-text.c:1119 format_text/format-text.c:1124
+#: format_text/format-text.c:1134 format_text/format-text.c:1136
+#: format_text/format-text.c:1144 format_text/format-text.c:1184
+#: format_text/format-text.c:1190 format_text/format-text.c:1366
+#: format_text/format-text.c:1372 format_text/format-text.c:1391
+#: format_text/format-text.c:1426 format_text/format-text.c:1445
+#: format_text/format-text.c:1461 format_text/format-text.c:1466
+#: format_text/format-text.c:1480 format_text/format-text.c:1492
+#: format_text/format-text.c:1498 format_text/format-text.c:1529
+#: format_text/format-text.c:1534 format_text/format-text.c:1539
+#: format_text/format-text.c:1548 format_text/format-text.c:1651
 #: format_text/import.c:53 format_text/import.c:72
-#: format_text/import_vsn1.c:123 format_text/import_vsn1.c:134
-#: format_text/import_vsn1.c:167 format_text/import_vsn1.c:276
-#: format_text/import_vsn1.c:282 format_text/import_vsn1.c:301
-#: format_text/import_vsn1.c:413 format_text/import_vsn1.c:441
-#: format_text/import_vsn1.c:449 format_text/import_vsn1.c:466
-#: format_text/import_vsn1.c:473 format_text/import_vsn1.c:502
-#: format_text/import_vsn1.c:558 format_text/import_vsn1.c:606
-#: format_text/import_vsn1.c:631 format_text/import_vsn1.c:641
-#: format_text/import_vsn1.c:646 format_text/import_vsn1.c:716
+#: format_text/import_vsn1.c:124 format_text/import_vsn1.c:135
+#: format_text/import_vsn1.c:168 format_text/import_vsn1.c:214
+#: format_text/import_vsn1.c:280 format_text/import_vsn1.c:286
+#: format_text/import_vsn1.c:299 format_text/import_vsn1.c:364
+#: format_text/import_vsn1.c:410 format_text/import_vsn1.c:438
+#: format_text/import_vsn1.c:446 format_text/import_vsn1.c:463
+#: format_text/import_vsn1.c:470 format_text/import_vsn1.c:499
+#: format_text/import_vsn1.c:557 format_text/import_vsn1.c:610
+#: format_text/import_vsn1.c:635 format_text/import_vsn1.c:645
+#: format_text/import_vsn1.c:650 format_text/import_vsn1.c:720
 #: format_text/tags.c:29 format_text/tags.c:36 format_text/tags.c:43
 #: format_text/tags.c:49 format_text/tags.c:68 label/label.c:91
-#: label/label.c:125 label/label.c:190 label/label.c:212 label/label.c:264
-#: label/label.c:278 label/label.c:313 label/label.c:321 label/label.c:333
-#: label/label.c:345 locking/cluster_locking.c:85
+#: label/label.c:122 label/label.c:193 label/label.c:214 label/label.c:265
+#: label/label.c:279 label/label.c:314 label/label.c:322 label/label.c:334
+#: label/label.c:346 locking/cluster_locking.c:85
 #: locking/cluster_locking.c:424 locking/cluster_locking.c:436
 #: locking/cluster_locking.c:440 locking/external_locking.c:76 lvchange.c:49
-#: lvchange.c:87 lvchange.c:93 lvchange.c:101 lvchange.c:108 lvchange.c:115
-#: lvchange.c:165 lvchange.c:173 lvchange.c:207 lvchange.c:292 lvchange.c:350
-#: lvchange.c:358 lvcreate.c:265 lvcreate.c:436 lvcreate.c:517 lvcreate.c:523
-#: lvcreate.c:564 lvcreate.c:571 lvcreate.c:656 lvmcmdline.c:1004
-#: lvremove.c:74 lvrename.c:146 lvrename.c:157 lvrename.c:164 lvrename.c:169
-#: lvresize.c:360 lvresize.c:417 lvresize.c:424 lvresize.c:431 lvresize.c:443
-#: lvresize.c:450 lvresize.c:456 lvresize.c:475 lvresize.c:489 lvresize.c:514
-#: metadata/lv_manip.c:70 metadata/lv_manip.c:202 metadata/lv_manip.c:237
-#: metadata/lv_manip.c:324 metadata/lv_manip.c:369 metadata/lv_manip.c:462
-#: metadata/lv_manip.c:599 metadata/lv_manip.c:641 metadata/lv_manip.c:652
-#: metadata/lv_manip.c:700 metadata/lv_manip.c:714 metadata/merge.c:179
-#: metadata/metadata.c:174 metadata/metadata.c:198 metadata/metadata.c:266
-#: metadata/metadata.c:281 metadata/metadata.c:471 metadata/metadata.c:512
-#: metadata/metadata.c:518 metadata/metadata.c:524 metadata/metadata.c:548
-#: metadata/metadata.c:573 metadata/metadata.c:591 metadata/metadata.c:654
-#: metadata/metadata.c:659 metadata/metadata.c:692 metadata/metadata.c:834
-#: metadata/metadata.c:913 metadata/metadata.c:946 metadata/mirror.c:48
-#: metadata/mirror.c:88 metadata/mirror.c:97 metadata/mirror.c:247
-#: metadata/mirror.c:327 metadata/pv_map.c:33 metadata/pv_map.c:40
-#: metadata/pv_map.c:95 metadata/pv_map.c:115 metadata/pv_map.c:172
-#: metadata/pv_map.c:199 metadata/pv_map.c:217 metadata/pv_map.c:226
-#: metadata/pv_map.c:244 metadata/pv_map.c:258 metadata/snapshot_manip.c:124
-#: metadata/snapshot_manip.c:143 mirror/mirrored.c:96 mirror/mirrored.c:171
-#: mirror/mirrored.c:251 misc/lvm-string.c:152 pvmove.c:98 pvmove.c:103
-#: pvmove.c:179 pvmove.c:207 pvmove.c:214 pvmove.c:278 pvmove.c:285
-#: pvmove.c:294 pvmove.c:323 pvmove.c:336 pvmove.c:343 pvmove.c:350
-#: pvmove.c:358 pvmove.c:370 pvmove.c:511 pvscan.c:54 regex/matcher.c:182
+#: lvchange.c:87 lvchange.c:93 lvchange.c:107 lvchange.c:114 lvchange.c:121
+#: lvchange.c:171 lvchange.c:179 lvchange.c:213 lvchange.c:298 lvchange.c:356
+#: lvchange.c:364 lvconvert.c:43 lvconvert.c:73 lvconvert.c:90 lvconvert.c:219
+#: lvcreate.c:141 lvcreate.c:309 lvcreate.c:333 lvcreate.c:349 lvcreate.c:511
+#: lvcreate.c:599 lvcreate.c:653 lvcreate.c:660 lvcreate.c:665 lvcreate.c:671
+#: lvcreate.c:678 lvcreate.c:705 lvcreate.c:745 lvcreate.c:753 lvcreate.c:759
+#: lvcreate.c:766 lvcreate.c:856 lvmcmdline.c:946 lvremove.c:86 lvrename.c:87
+#: lvrename.c:144 lvrename.c:155 lvrename.c:162 lvrename.c:167 lvresize.c:417
+#: lvresize.c:474 lvresize.c:481 lvresize.c:488 lvresize.c:500 lvresize.c:507
+#: lvresize.c:513 lvresize.c:532 lvresize.c:546 lvresize.c:571
+#: metadata/lv_manip.c:73 metadata/lv_manip.c:139 metadata/lv_manip.c:210
+#: metadata/lv_manip.c:219 metadata/lv_manip.c:231 metadata/lv_manip.c:240
+#: metadata/lv_manip.c:254 metadata/lv_manip.c:390 metadata/lv_manip.c:398
+#: metadata/lv_manip.c:435 metadata/lv_manip.c:644 metadata/lv_manip.c:692
+#: metadata/lv_manip.c:717 metadata/lv_manip.c:729 metadata/lv_manip.c:740
+#: metadata/lv_manip.c:821 metadata/lv_manip.c:829 metadata/lv_manip.c:866
+#: metadata/lv_manip.c:878 metadata/lv_manip.c:907 metadata/lv_manip.c:919
+#: metadata/lv_manip.c:965 metadata/lv_manip.c:995 metadata/lv_manip.c:1002
+#: metadata/lv_manip.c:1115 metadata/merge.c:199 metadata/merge.c:239
+#: metadata/metadata.c:105 metadata/metadata.c:131 metadata/metadata.c:158
+#: metadata/metadata.c:228 metadata/metadata.c:252 metadata/metadata.c:346
+#: metadata/metadata.c:352 metadata/metadata.c:358 metadata/metadata.c:369
+#: metadata/metadata.c:375 metadata/metadata.c:387 metadata/metadata.c:393
+#: metadata/metadata.c:405 metadata/metadata.c:413 metadata/metadata.c:420
+#: metadata/metadata.c:427 metadata/metadata.c:434 metadata/metadata.c:447
+#: metadata/metadata.c:455 metadata/metadata.c:464 metadata/metadata.c:495
+#: metadata/metadata.c:510 metadata/metadata.c:692 metadata/metadata.c:748
+#: metadata/metadata.c:754 metadata/metadata.c:761 metadata/metadata.c:772
+#: metadata/metadata.c:777 metadata/metadata.c:799 metadata/metadata.c:821
+#: metadata/metadata.c:838 metadata/metadata.c:904 metadata/metadata.c:909
+#: metadata/metadata.c:954 metadata/metadata.c:994 metadata/metadata.c:1157
+#: metadata/metadata.c:1191 metadata/metadata.c:1243 metadata/metadata.c:1276
+#: metadata/mirror.c:34 metadata/mirror.c:53 metadata/mirror.c:58
+#: metadata/mirror.c:72 metadata/mirror.c:184 metadata/mirror.c:223
+#: metadata/mirror.c:232 metadata/mirror.c:361 metadata/mirror.c:380
+#: metadata/mirror.c:455 metadata/pv_manip.c:55 metadata/pv_manip.c:74
+#: metadata/pv_manip.c:95 metadata/pv_manip.c:127 metadata/pv_manip.c:152
+#: metadata/pv_manip.c:182 metadata/pv_map.c:42 metadata/pv_map.c:90
+#: metadata/pv_map.c:110 metadata/pv_map.c:120 metadata/pv_map.c:138
+#: metadata/pv_map.c:148 metadata/snapshot_manip.c:56
+#: metadata/snapshot_manip.c:63 mirror/mirrored.c:137 mirror/mirrored.c:142
+#: mirror/mirrored.c:144 mirror/mirrored.c:225 mirror/mirrored.c:305
+#: misc/lvm-string.c:152 pvchange.c:185 pvmove.c:98 pvmove.c:103 pvmove.c:180
+#: pvmove.c:208 pvmove.c:215 pvmove.c:279 pvmove.c:286 pvmove.c:295
+#: pvmove.c:324 pvmove.c:337 pvmove.c:344 pvmove.c:351 pvmove.c:359
+#: pvmove.c:371 pvmove.c:512 pvscan.c:54 regex/matcher.c:182
 #: regex/matcher.c:203 regex/matcher.c:208 regex/matcher.c:282
 #: regex/matcher.c:287 regex/matcher.c:300 regex/matcher.c:322
 #: regex/parse_rx.c:229 regex/parse_rx.c:280 regex/parse_rx.c:305
 #: regex/parse_rx.c:328 regex/parse_rx.c:340 regex/ttree.c:91
-#: regex/ttree.c:111 report/report.c:522 report/report.c:550
-#: report/report.c:682 snapshot/snapshot.c:75 snapshot/snapshot.c:84
+#: regex/ttree.c:111 report/report.c:576 report/report.c:604
+#: report/report.c:736 snapshot/snapshot.c:75 snapshot/snapshot.c:84
 #: snapshot/snapshot.c:85 snapshot/snapshot.c:86 snapshot/snapshot.c:155
-#: striped/striped.c:90 striped/striped.c:160 striped/striped.c:209
-#: toollib.c:734 toollib.c:784 toollib.c:831 uuid/uuid.c:91 uuid/uuid.c:95
-#: vgcfgbackup.c:65 vgcfgbackup.c:74 vgcfgbackup.c:81 vgreduce.c:28
-#: vgreduce.c:84 vgreduce.c:92 vgreduce.c:98 vgreduce.c:106 vgreduce.c:142
-#: vgreduce.c:158 zero/zero.c:90
+#: striped/striped.c:91 striped/striped.c:170 striped/striped.c:219
+#: toollib.c:760 toollib.c:810 toollib.c:857 uuid/uuid.c:91 uuid/uuid.c:95
+#: vgcfgbackup.c:65 vgcfgbackup.c:74 vgcfgbackup.c:81 vgchange.c:302
+#: vgmerge.c:160 vgreduce.c:28 vgreduce.c:90 vgreduce.c:96 vgreduce.c:104
+#: vgreduce.c:140 vgreduce.c:156 zero/zero.c:90
 msgid "<backtrace>"
 msgstr ""
 
@@ -316,32 +347,32 @@
 msgid "Failed to get %s target version"
 msgstr ""
 
-#: activate/activate.c:567
+#: activate/activate.c:563
 #, c-format
 msgid "Skipping: Suspending '%s'."
 msgstr ""
 
-#: activate/activate.c:613
+#: activate/activate.c:609
 #, c-format
 msgid "Skipping: Resuming '%s'."
 msgstr ""
 
-#: activate/activate.c:658
+#: activate/activate.c:654
 #, c-format
 msgid "Skipping: Deactivating '%s'."
 msgstr ""
 
-#: activate/activate.c:671
+#: activate/activate.c:667
 #, c-format
 msgid "LV %s/%s in use: not removing"
 msgstr ""
 
-#: activate/activate.c:697 activate/activate.c:721
+#: activate/activate.c:693 activate/activate.c:717
 #, c-format
 msgid "Not activating %s/%s due to config file settings"
 msgstr ""
 
-#: activate/activate.c:727
+#: activate/activate.c:723
 #, c-format
 msgid "Skipping: Activating '%s'."
 msgstr ""
@@ -368,8 +399,8 @@
 msgid "Couldn't split up dm layer name %s"
 msgstr ""
 
-#: activate/dev_manager.c:464 format_text/format-text.c:640
-#: format_text/format-text.c:665 format_text/format-text.c:699
+#: activate/dev_manager.c:464 format_text/format-text.c:681
+#: format_text/format-text.c:706 format_text/format-text.c:740
 #, c-format
 msgid "Renaming %s to %s"
 msgstr ""
@@ -460,152 +491,152 @@
 msgid "Adding target: %llu %llu %s %s"
 msgstr ""
 
-#: activate/dev_manager.c:759
+#: activate/dev_manager.c:750 activate/dev_manager.c:809
 #, c-format
 msgid "device layer %s missing from hash"
 msgstr ""
 
-#: activate/dev_manager.c:766
+#: activate/dev_manager.c:757 activate/dev_manager.c:816
 #, c-format
 msgid "Failed to format device number as dm target (%u,%u)"
 msgstr ""
 
-#: activate/dev_manager.c:795
+#: activate/dev_manager.c:845
 msgid "Insufficient space for target parameters."
 msgstr ""
 
-#: activate/dev_manager.c:808
+#: activate/dev_manager.c:858
 #, c-format
-msgid "Insufficient space in params[%Zu] for target parameters."
+msgid "Insufficient space in params[%zu] for target parameters."
 msgstr ""
 
-#: activate/dev_manager.c:814
+#: activate/dev_manager.c:864
 msgid "Target parameter size too big. Aborting."
 msgstr ""
 
-#: activate/dev_manager.c:830
+#: activate/dev_manager.c:878
 #, c-format
 msgid "Unable to build table for '%s'"
 msgstr ""
 
-#: activate/dev_manager.c:851
+#: activate/dev_manager.c:899
 #, c-format
 msgid "Couldn't find real device layer %s in hash"
 msgstr ""
 
-#: activate/dev_manager.c:857 activate/dev_manager.c:911
+#: activate/dev_manager.c:905 activate/dev_manager.c:960
 #, c-format
 msgid "Couldn't create origin device parameters for '%s'."
 msgstr ""
 
-#: activate/dev_manager.c:862
+#: activate/dev_manager.c:910
 #, c-format
 msgid "Adding target: 0 %llu snapshot-origin %s"
 msgstr ""
 
-#: activate/dev_manager.c:884
+#: activate/dev_manager.c:932
 #, c-format
 msgid "Couldn't find snapshot for '%s'."
 msgstr ""
 
-#: activate/dev_manager.c:899
+#: activate/dev_manager.c:948
 #, c-format
 msgid "Couldn't find origin device layer %s in hash"
 msgstr ""
 
-#: activate/dev_manager.c:905
+#: activate/dev_manager.c:954
 #, c-format
 msgid "Couldn't find cow device layer %s in hash"
 msgstr ""
 
-#: activate/dev_manager.c:918
+#: activate/dev_manager.c:967
 #, c-format
 msgid "Couldn't create cow device parameters for '%s'."
 msgstr ""
 
-#: activate/dev_manager.c:931
+#: activate/dev_manager.c:980
 #, c-format
 msgid "Adding target: 0 %llu snapshot %s"
 msgstr ""
 
-#: activate/dev_manager.c:1015 activate/dev_manager.c:1095
+#: activate/dev_manager.c:1064 activate/dev_manager.c:1144
 #, c-format
 msgid "Getting device info for %s"
 msgstr ""
 
-#: activate/dev_manager.c:1041
+#: activate/dev_manager.c:1090
 #, c-format
 msgid "Getting device status percentage for %s"
 msgstr ""
 
-#: activate/dev_manager.c:1072
+#: activate/dev_manager.c:1121
 #, c-format
 msgid "Getting device mirror status percentage for %s"
 msgstr ""
 
-#: activate/dev_manager.c:1395 activate/dev_manager.c:1555
+#: activate/dev_manager.c:1453 activate/dev_manager.c:1613
 #, c-format
 msgid "Couldn't find device layer '%s'."
 msgstr ""
 
-#: activate/dev_manager.c:1475
+#: activate/dev_manager.c:1533
 #, c-format
 msgid "_suspend_parents couldn't find device layer '%s' - skipping."
 msgstr ""
 
-#: activate/dev_manager.c:1481
+#: activate/dev_manager.c:1539
 #, c-format
 msgid "BUG: pre-suspend loop detected (%s)"
 msgstr ""
 
-#: activate/dev_manager.c:1509
+#: activate/dev_manager.c:1567
 #, c-format
 msgid "_resume_with_deps couldn't find device layer '%s' - skipping."
 msgstr ""
 
-#: activate/dev_manager.c:1515 activate/dev_manager.c:1560
+#: activate/dev_manager.c:1573 activate/dev_manager.c:1618
 #, c-format
 msgid "BUG: pre-create loop detected (%s)"
 msgstr ""
 
-#: activate/dev_manager.c:1667 activate/dev_manager.c:1683
+#: activate/dev_manager.c:1725 activate/dev_manager.c:1741
 #, c-format
 msgid ""
 "_populate_pre_suspend_lists: Couldn't find device layer '%s' - skipping."
 msgstr ""
 
-#: activate/dev_manager.c:1729
+#: activate/dev_manager.c:1787
 #, c-format
 msgid "Couldn't deactivate device %s"
 msgstr ""
 
-#: activate/dev_manager.c:1846
+#: activate/dev_manager.c:1903
 #, c-format
 msgid "Found existing layer '%s'"
 msgstr ""
 
-#: activate/dev_manager.c:2025
+#: activate/dev_manager.c:2083
 #, c-format
 msgid "Can't expand LV: %s target support missing from kernel?"
 msgstr ""
 
-#: activate/dev_manager.c:2037
+#: activate/dev_manager.c:2095
 msgid "Can't expand LV: Mirror support missing from tools?"
 msgstr ""
 
-#: activate/dev_manager.c:2044
+#: activate/dev_manager.c:2102
 msgid "Can't expand LV: Mirror support missing from kernel?"
 msgstr ""
 
-#: activate/dev_manager.c:2052
+#: activate/dev_manager.c:2110
 msgid "Can't expand LV: Snapshot support missing from tools?"
 msgstr ""
 
-#: activate/dev_manager.c:2059
+#: activate/dev_manager.c:2117
 msgid "Can't expand LV: Snapshot support missing from kernel?"
 msgstr ""
 
-#: activate/dev_manager.c:2087
+#: activate/dev_manager.c:2145
 #, c-format
 msgid "Found active lv %s%s"
 msgstr ""
@@ -621,30 +652,31 @@
 
 #: activate/fs.c:50 activate/fs.c:85 activate/fs.c:105 activate/fs.c:158
 #: activate/fs.c:171 activate/fs.c:178 activate/fs.c:213
-#: commands/toolcontext.c:340 commands/toolcontext.c:781 config/config.c:155
+#: commands/toolcontext.c:342 commands/toolcontext.c:799 config/config.c:155
 #: config/config.c:204 config/config.c:220 config/config.c:285
-#: config/config.c:382 device/dev-cache.c:150 device/dev-cache.c:154
-#: device/dev-cache.c:322 device/dev-cache.c:329 device/dev-cache.c:490
-#: device/dev-cache.c:492 device/dev-io.c:131 device/dev-io.c:235
-#: device/dev-io.c:240 device/dev-io.c:242 device/dev-io.c:248
-#: device/dev-io.c:344 device/dev-io.c:400 filters/filter-persistent.c:184
+#: config/config.c:382 device/dev-cache.c:172 device/dev-cache.c:176
+#: device/dev-cache.c:356 device/dev-cache.c:379 device/dev-cache.c:386
+#: device/dev-cache.c:579 device/dev-cache.c:581 device/dev-io.c:131
+#: device/dev-io.c:231 device/dev-io.c:249 device/dev-io.c:254
+#: device/dev-io.c:256 device/dev-io.c:262 device/dev-io.c:386
+#: device/dev-io.c:388 device/dev-io.c:451 filters/filter-persistent.c:186
 #: filters/filter-sysfs.c:43 filters/filter-sysfs.c:155
-#: filters/filter-sysfs.c:179 filters/filter-sysfs.c:222 filters/filter.c:152
-#: format_text/archive.c:221 format_text/archive.c:230
-#: format_text/format-text.c:615 format_text/format-text.c:629
-#: format_text/format-text.c:635 format_text/format-text.c:660
-#: format_text/format-text.c:722 format_text/format-text.c:727
-#: format_text/format-text.c:753 format_text/format-text.c:778
+#: filters/filter-sysfs.c:179 filters/filter-sysfs.c:222 filters/filter.c:153
+#: format_text/archive.c:216 format_text/archive.c:225
+#: format_text/format-text.c:656 format_text/format-text.c:670
+#: format_text/format-text.c:676 format_text/format-text.c:701
+#: format_text/format-text.c:763 format_text/format-text.c:768
+#: format_text/format-text.c:793 format_text/format-text.c:818
 #: locking/file_locking.c:61 locking/file_locking.c:69
-#: locking/file_locking.c:72 locking/file_locking.c:103
-#: locking/file_locking.c:169 locking/file_locking.c:183
-#: locking/file_locking.c:290 locking/file_locking.c:295 locking/locking.c:44
-#: locking/locking.c:49 locking/locking.c:65 locking/locking.c:200
-#: log/log.c:62 lvmcmdline.c:1411 misc/lvm-file.c:47 misc/lvm-file.c:92
-#: misc/lvm-file.c:102 misc/lvm-file.c:151 misc/lvm-file.c:163
-#: misc/lvm-file.c:192 misc/lvm-file.c:201 misc/lvm-file.c:229
-#: misc/lvm-file.c:234 mm/memlock.c:98 mm/memlock.c:106 mm/memlock.c:117
-#: toollib.c:966 uuid/uuid.c:84 uuid/uuid.c:89
+#: locking/file_locking.c:72 locking/file_locking.c:105
+#: locking/file_locking.c:171 locking/file_locking.c:187
+#: locking/file_locking.c:294 locking/file_locking.c:299 locking/locking.c:44
+#: locking/locking.c:49 locking/locking.c:65 locking/locking.c:203
+#: log/log.c:64 lvmcmdline.c:1347 misc/lvm-file.c:47 misc/lvm-file.c:96
+#: misc/lvm-file.c:106 misc/lvm-file.c:156 misc/lvm-file.c:169
+#: misc/lvm-file.c:198 misc/lvm-file.c:207 misc/lvm-file.c:235
+#: misc/lvm-file.c:240 mm/memlock.c:98 mm/memlock.c:106 mm/memlock.c:117
+#: toollib.c:992 uuid/uuid.c:84 uuid/uuid.c:89
 #, c-format
 msgid "%s: %s failed: %s"
 msgstr ""
@@ -712,11 +744,11 @@
 msgid "No space to stack fs operation"
 msgstr ""
 
-#: archiver.c:43
+#: archiver.c:40 format_text/archiver.c:53
 msgid "Couldn't copy archive directory name."
 msgstr ""
 
-#: archiver.c:105
+#: archiver.c:102 format_text/archiver.c:116
 msgid "Test mode: Skipping archiving of volume group."
 msgstr ""
 
@@ -725,45 +757,45 @@
 msgid "Archiving volume group \"%s\" metadata."
 msgstr ""
 
-#: archiver.c:111
+#: archiver.c:111 format_text/archiver.c:131
 #, c-format
 msgid "Volume group \"%s\" metadata archive failed."
 msgstr ""
 
-#: archiver.c:141
+#: archiver.c:138 format_text/archiver.c:164
 msgid "Couldn't copy backup directory name."
 msgstr ""
 
-#: archiver.c:172
+#: archiver.c:169 format_text/archiver.c:195
 msgid "Failed to generate volume group metadata backup filename."
 msgstr ""
 
-#: archiver.c:183
+#: archiver.c:180 format_text/archiver.c:206
 msgid "WARNING: This metadata update is NOT backed up"
 msgstr ""
 
-#: archiver.c:188
+#: archiver.c:185 format_text/archiver.c:211
 msgid "Test mode: Skipping volume group backup."
 msgstr ""
 
-#: archiver.c:193
+#: archiver.c:193 format_text/archiver.c:224
 #, c-format
 msgid "Backup of volume group %s metadata failed."
 msgstr ""
 
-#: archiver.c:207
+#: archiver.c:207 format_text/archiver.c:238
 msgid "Failed to generate backup filename (for removal)."
 msgstr ""
 
-#: archiver.c:230
+#: archiver.c:230 format_text/archiver.c:261
 msgid "Couldn't create text format object."
 msgstr ""
 
-#: archiver.c:259
+#: archiver.c:259 format_text/archiver.c:290
 msgid "Failed to allocate format instance"
 msgstr ""
 
-#: archiver.c:267
+#: archiver.c:267 format_text/archiver.c:298
 #, c-format
 msgid "PV %s missing from cache"
 msgstr ""
@@ -773,12 +805,12 @@
 msgid "PV %s is a different format (%s)"
 msgstr ""
 
-#: archiver.c:279
+#: archiver.c:279 format_text/archiver.c:310
 #, c-format
 msgid "Format-specific setup for %s failed"
 msgstr ""
 
-#: archiver.c:316
+#: archiver.c:316 format_text/archiver.c:347
 msgid "Failed to generate backup filename (for restore)."
 msgstr ""
 
@@ -787,11 +819,11 @@
 msgid "Creating volume group backup \"%s\""
 msgstr ""
 
-#: archiver.c:338
+#: archiver.c:338 format_text/archiver.c:369
 msgid "Couldn't create backup object."
 msgstr ""
 
-#: cache/lvmcache.c:57 cache/lvmcache.c:182 cache/lvmcache.c:444
+#: cache/lvmcache.c:57 cache/lvmcache.c:202 cache/lvmcache.c:464
 msgid "Internal cache initialisation failed"
 msgstr ""
 
@@ -800,247 +832,283 @@
 msgid "Cache locking failure for %s"
 msgstr ""
 
-#: cache/lvmcache.c:192 toollib.c:467
+#: cache/lvmcache.c:212 toollib.c:492
 msgid "dev_iter creation failed"
 msgstr ""
 
-#: cache/lvmcache.c:226
+#: cache/lvmcache.c:245
 msgid "vgnames list allocation failed"
 msgstr ""
 
-#: cache/lvmcache.c:233 toollib.c:147 toollib.c:192 toollib.c:200
-#: toollib.c:212 toollib.c:272 toollib.c:381 toollib.c:401 toollib.c:526
+#: cache/lvmcache.c:252 toollib.c:150 toollib.c:195 toollib.c:203
+#: toollib.c:215 toollib.c:275 toollib.c:406 toollib.c:426 toollib.c:552
 msgid "strlist allocation failed"
 msgstr ""
 
-#: cache/lvmcache.c:327
+#: cache/lvmcache.c:346
 #, c-format
 msgid "_lvmcache_update: pvid insertion failed: %s"
 msgstr ""
 
-#: cache/lvmcache.c:348
+#: cache/lvmcache.c:367
 #, c-format
 msgid "_lvmcache_update: vgid hash insertion failed: %s"
 msgstr ""
 
-#: cache/lvmcache.c:376
+#: cache/lvmcache.c:395
 msgid "lvmcache_update_vgname: list alloc failed"
 msgstr ""
 
-#: cache/lvmcache.c:382
+#: cache/lvmcache.c:401
 #, c-format
 msgid "cache vgname alloc failed for %s"
 msgstr ""
 
-#: cache/lvmcache.c:387
+#: cache/lvmcache.c:406
 #, c-format
 msgid "cache_update: vg hash insertion failed: %s"
 msgstr ""
 
-#: cache/lvmcache.c:458
+#: cache/lvmcache.c:425
+#, c-format
+msgid "lvmcache: %s now %s%s"
+msgstr ""
+
+#: cache/lvmcache.c:478
 msgid "lvmcache_info allocation failed"
 msgstr ""
 
-#: cache/lvmcache.c:473
+#: cache/lvmcache.c:493
 #, c-format
 msgid "Ignoring duplicate PV %s on %s - using md %s"
 msgstr ""
 
-#: cache/lvmcache.c:480
+#: cache/lvmcache.c:500
 #, c-format
 msgid "Duplicate PV %s on %s - using md %s"
 msgstr ""
 
-#: cache/lvmcache.c:485
+#: cache/lvmcache.c:505
 #, c-format
 msgid "Found duplicate PV %s: using %s not %s"
 msgstr ""
 
-#: commands/toolcontext.c:71
+#: cache/lvmcache.c:574
+msgid "Wiping internal VG cache"
+msgstr ""
+
+#: commands/toolcontext.c:73
 msgid "LVM_SYSTEM_DIR environment variable is too long."
 msgstr ""
 
-#: commands/toolcontext.c:144
+#: commands/toolcontext.c:146
 #, c-format
 msgid "Logging initialised at %s"
 msgstr ""
 
-#: commands/toolcontext.c:163
+#: commands/toolcontext.c:165
 #, c-format
 msgid "Set umask to %04o"
 msgstr ""
 
-#: commands/toolcontext.c:169 commands/toolcontext.c:180
+#: commands/toolcontext.c:171 commands/toolcontext.c:182
 msgid "Device directory given in config file too long"
 msgstr ""
 
-#: commands/toolcontext.c:185
+#: commands/toolcontext.c:187
 #, c-format
 msgid "Warning: proc dir %s not found - some checks will be bypassed"
 msgstr ""
 
-#: commands/toolcontext.c:205 lvmcmdline.c:694
+#: commands/toolcontext.c:207 lvmcmdline.c:694
 msgid "Invalid units specification"
 msgstr ""
 
-#: commands/toolcontext.c:214
+#: commands/toolcontext.c:216
 #, c-format
 msgid "Setting host tag: %s"
 msgstr ""
 
-#: commands/toolcontext.c:217
+#: commands/toolcontext.c:219
 #, c-format
 msgid "_set_tag: str_list_add %s failed"
 msgstr ""
 
-#: commands/toolcontext.c:241
+#: commands/toolcontext.c:243
 #, c-format
 msgid "Invalid hostname string for tag %s"
 msgstr ""
 
-#: commands/toolcontext.c:252
+#: commands/toolcontext.c:254
 msgid "host_filter not supported yet"
 msgstr ""
 
-#: commands/toolcontext.c:287
+#: commands/toolcontext.c:289
 #, c-format
 msgid "Invalid tag in config file: %s"
 msgstr ""
 
-#: commands/toolcontext.c:320
+#: commands/toolcontext.c:322
 msgid "LVM_SYSTEM_DIR or tag was too long"
 msgstr ""
 
-#: commands/toolcontext.c:325
+#: commands/toolcontext.c:327
 msgid "config_tree_list allocation failed"
 msgstr ""
 
-#: commands/toolcontext.c:330
+#: commands/toolcontext.c:332
 msgid "config_tree allocation failed"
 msgstr ""
 
-#: commands/toolcontext.c:345
+#: commands/toolcontext.c:347
 #, c-format
 msgid "Loading config file: %s"
 msgstr ""
 
-#: commands/toolcontext.c:347
+#: commands/toolcontext.c:349
 #, c-format
 msgid "Failed to load config file %s"
 msgstr ""
 
-#: commands/toolcontext.c:370 commands/toolcontext.c:408
+#: commands/toolcontext.c:372 commands/toolcontext.c:410
 msgid "Failed to create config tree"
 msgstr ""
 
-#: commands/toolcontext.c:473
+#: commands/toolcontext.c:475
 msgid "Failed to add /dev to internal device cache"
 msgstr ""
 
-#: commands/toolcontext.c:477
+#: commands/toolcontext.c:479
 msgid "device/scan not in config file: Defaulting to /dev"
 msgstr ""
 
-#: commands/toolcontext.c:484
+#: commands/toolcontext.c:486
 msgid "Invalid string in config file: devices/scan"
 msgstr ""
 
-#: commands/toolcontext.c:490 format_text/format-text.c:1681
+#: commands/toolcontext.c:492 format_text/format-text.c:1692
 #, c-format
 msgid "Failed to add %s to internal device cache"
 msgstr ""
 
-#: commands/toolcontext.c:528
+#: commands/toolcontext.c:503
+msgid "Invalid string in config file: devices/loopfiles"
+msgstr ""
+
+#: commands/toolcontext.c:509
+#, c-format
+msgid "Failed to add loopfile %s to internal device cache"
+msgstr ""
+
+#: commands/toolcontext.c:548
 msgid "devices/filter not found in config file: no regex filter installed"
 msgstr ""
 
-#: commands/toolcontext.c:532
+#: commands/toolcontext.c:552
 msgid "Failed to create regex device filter"
 msgstr ""
 
-#: commands/toolcontext.c:539
+#: commands/toolcontext.c:559
 msgid "Failed to create lvm type filter"
 msgstr ""
 
-#: commands/toolcontext.c:570
+#: commands/toolcontext.c:590
 #, c-format
 msgid "Persistent cache filename too long ('%s/.cache')."
 msgstr ""
 
-#: commands/toolcontext.c:578
+#: commands/toolcontext.c:598
 msgid "Failed to create persistent device filter"
 msgstr ""
 
-#: commands/toolcontext.c:592
+#: commands/toolcontext.c:612
 #, c-format
 msgid "Failed to load existing device cache from %s"
 msgstr ""
 
-#: commands/toolcontext.c:637
+#: commands/toolcontext.c:656
 msgid "Invalid string in config file: global/format_libraries"
 msgstr ""
 
-#: commands/toolcontext.c:648
+#: commands/toolcontext.c:667
 #, c-format
 msgid "Shared library %s does not contain format functions"
 msgstr ""
 
-#: commands/toolcontext.c:681
+#: commands/toolcontext.c:699
 #, c-format
 msgid "_init_formats: Default format (%s) not found"
 msgstr ""
 
-#: commands/toolcontext.c:734
+#: commands/toolcontext.c:752
 msgid "Invalid string in config file: global/segment_libraries"
 msgstr ""
 
-#: commands/toolcontext.c:745
+#: commands/toolcontext.c:763
 #, c-format
 msgid "Shared library %s does not contain segment type functions"
 msgstr ""
 
-#: commands/toolcontext.c:759
+#: commands/toolcontext.c:777
 #, c-format
 msgid "Duplicate segment type %s: unloading shared library %s"
 msgstr ""
 
-#: commands/toolcontext.c:786
+#: commands/toolcontext.c:804
 msgid "_init_hostname: pool_strdup failed"
 msgstr ""
 
-#: commands/toolcontext.c:791
+#: commands/toolcontext.c:809
 msgid "_init_hostname: pool_strdup kernel_vsn failed"
 msgstr ""
 
-#: commands/toolcontext.c:808
+#: commands/toolcontext.c:823
+msgid "WARNING: Metadata changes will NOT be backed up"
+msgstr ""
+
+#: commands/toolcontext.c:843
+#, c-format
+msgid "Couldn't create default archive path '%s/%s'."
+msgstr ""
+
+#: commands/toolcontext.c:852 commands/toolcontext.c:872
+msgid "backup_init failed."
+msgstr ""
+
+#: commands/toolcontext.c:864
+#, c-format
+msgid "Couldn't create default backup path '%s/%s'."
+msgstr ""
+
+#: commands/toolcontext.c:889
 msgid "setlocale failed"
 msgstr ""
 
-#: commands/toolcontext.c:817
+#: commands/toolcontext.c:898
 msgid "Failed to allocate command context"
 msgstr ""
 
-#: commands/toolcontext.c:835
+#: commands/toolcontext.c:916
 msgid ""
 "Failed to create LVM2 system dir for metadata backups, config files and "
 "internal cache."
 msgstr ""
 
-#: commands/toolcontext.c:837
+#: commands/toolcontext.c:918
 msgid ""
 "Set environment variable LVM_SYSTEM_DIR to alternative location or empty "
 "string."
 msgstr ""
 
-#: commands/toolcontext.c:843
+#: commands/toolcontext.c:924
 msgid "Library memory pool creation failed"
 msgstr ""
 
-#: commands/toolcontext.c:874
+#: commands/toolcontext.c:955
 msgid "Command memory pool creation failed"
 msgstr ""
 
-#: commands/toolcontext.c:934
+#: commands/toolcontext.c:1018
 msgid "Reloading config files"
 msgstr ""
 
@@ -1145,84 +1213,103 @@
 msgid "%s not found in config: defaulting to %f"
 msgstr ""
 
-#: device/dev-cache.c:60 device/dev-cache.c:97
+#: device/dev-cache.c:65 device/dev-cache.c:82 device/dev-cache.c:119
 msgid "struct device allocation failed"
 msgstr ""
 
-#: device/dev-cache.c:64
+#: device/dev-cache.c:69 device/dev-cache.c:86
 msgid "struct str_list allocation failed"
 msgstr ""
 
-#: device/dev-cache.c:69
+#: device/dev-cache.c:74 device/dev-cache.c:91 device/dev-cache.c:96
 msgid "filename strdup failed"
 msgstr ""
 
-#: device/dev-cache.c:202
+#: device/dev-cache.c:211
+#, c-format
+msgid "%s: Already in device cache"
+msgstr ""
+
+#: device/dev-cache.c:224
 #, c-format
 msgid "%s: Aliased to %s in device cache%s"
 msgstr ""
 
-#: device/dev-cache.c:206
+#: device/dev-cache.c:228
 #, c-format
 msgid "%s: Added to device cache"
 msgstr ""
 
-#: device/dev-cache.c:234
+#: device/dev-cache.c:269
 msgid "Couldn't insert device into binary tree."
 msgstr ""
 
-#: device/dev-cache.c:241
+#: device/dev-cache.c:276
 msgid "Couldn't add alias to dev cache."
 msgstr ""
 
-#: device/dev-cache.c:246
+#: device/dev-cache.c:281
 msgid "Couldn't add name to hash in dev cache."
 msgstr ""
 
-#: device/dev-cache.c:334
+#: device/dev-cache.c:361
+#, c-format
+msgid "%s: Not a regular file"
+msgstr ""
+
+#: device/dev-cache.c:391
 #, c-format
 msgid "%s: Symbolic link to directory"
 msgstr ""
 
-#: device/dev-cache.c:343
+#: device/dev-cache.c:400
 #, c-format
 msgid "%s: Not a block device"
 msgstr ""
 
-#: device/dev-cache.c:405
+#: device/dev-cache.c:463
 msgid "Couldn't create binary tree for dev-cache."
 msgstr ""
 
-#: device/dev-cache.c:421
+#: device/dev-cache.c:480
 #, c-format
 msgid "Device '%s' has been left open."
 msgstr ""
 
-#: device/dev-cache.c:455
+#: device/dev-cache.c:515 device/dev-cache.c:541
 #, c-format
 msgid "Ignoring %s: %s"
 msgstr ""
 
-#: device/dev-cache.c:461
+#: device/dev-cache.c:521
 #, c-format
 msgid "Ignoring %s: Not a directory"
 msgstr ""
 
-#: device/dev-cache.c:466
+#: device/dev-cache.c:526
 msgid "dir_list allocation failed"
 msgstr ""
 
-#: device/dev-cache.c:495 device/dev-cache.c:499
+#: device/dev-cache.c:547
+#, c-format
+msgid "Ignoring %s: Not a regular file"
+msgstr ""
+
+#: device/dev-cache.c:552
+msgid "dir_list allocation failed for file"
+msgstr ""
+
+#: device/dev-cache.c:584 device/dev-cache.c:588
 #, c-format
 msgid "Path %s no longer valid for device(%d,%d)"
 msgstr ""
 
-#: device/dev-cache.c:516
+#: device/dev-cache.c:605
 #, c-format
 msgid "Aborting - please provide new pathname for what used to be %s"
 msgstr ""
 
-#: device/dev-cache.c:548
+#: device/dev-cache.c:641
 msgid "dev_iter allocation failed"
 msgstr ""
 
@@ -1255,54 +1342,59 @@
 msgid "Bounce buffer alloca failed"
 msgstr ""
 
-#: device/dev-io.c:250
+#: device/dev-io.c:238 device/dev-io.c:264
 #, c-format
 msgid "%s: size is %llu sectors"
 msgstr ""
 
-#: device/dev-io.c:307
+#: device/dev-io.c:333
 #, c-format
 msgid "WARNING: %s already opened read-only"
 msgstr ""
 
-#: device/dev-io.c:316
+#: device/dev-io.c:342
 #, c-format
 msgid "WARNING: dev_open(%s) called while suspended"
 msgstr ""
 
-#: device/dev-io.c:328
+#: device/dev-io.c:354
 #, c-format
 msgid "%s: stat failed: Has device name changed?"
 msgstr ""
 
-#: device/dev-io.c:357
+#: device/dev-io.c:380
+#, c-format
+msgid "%s: Not using O_DIRECT"
+msgstr ""
+
+#: device/dev-io.c:407
 #, c-format
 msgid "%s: fstat failed: Has device name changed?"
 msgstr ""
 
-#: device/dev-io.c:373
+#: device/dev-io.c:423
 #, c-format
-msgid "Opened %s %s"
+msgid "Opened %s %s%s"
 msgstr ""
 
-#: device/dev-io.c:405
+#: device/dev-io.c:456
 #, c-format
 msgid "Closed %s"
 msgstr ""
 
-#: device/dev-io.c:418
+#: device/dev-io.c:469
 #, c-format
 msgid "Attempt to close device '%s' which is not open."
 msgstr ""
 
-#: device/dev-io.c:528
+#: device/dev-io.c:579
 #, c-format
-msgid "Wiping %s at %llu length %Zu"
+msgid "Wiping %s at %llu length %zu"
 msgstr ""
 
-#: device/dev-io.c:531
+#: device/dev-io.c:582
 #, c-format
-msgid "Wiping %s at sector %llu length %Zu sectors"
+msgid "Wiping %s at sector %llu length %zu sectors"
 msgstr ""
 
 #: display/display.c:130
@@ -1358,7 +1450,7 @@
 msgid "PE Size (KByte)       %u"
 msgstr ""
 
-#: display/display.c:282 display/display.c:573
+#: display/display.c:282 display/display.c:561
 #, c-format
 msgid "Total PE              %u"
 msgstr ""
@@ -1378,9 +1470,9 @@
 msgid "PV UUID               %s"
 msgstr ""
 
-#: display/display.c:286 display/display.c:312 display/display.c:459
-#: display/display.c:506 display/display.c:592 format_text/archive.c:316
-#: lvmcmdline.c:729 mirror/mirrored.c:54 striped/striped.c:50
+#: display/display.c:286 display/display.c:312 display/display.c:445
+#: display/display.c:494 display/display.c:580 format_text/archive.c:311
+#: lvmcmdline.c:729 mirror/mirrored.c:66 striped/striped.c:51
 msgid " "
 msgstr ""
 
@@ -1404,257 +1496,267 @@
 msgid "%s%s/%s:%s:%d:%d:-1:%d:%llu:%d:-1:%d:%d:%d:%d"
 msgstr ""
 
-#: display/display.c:353
+#: display/display.c:352
 msgid "--- Logical volume ---"
 msgstr ""
 
-#: display/display.c:355
+#: display/display.c:354
 #, c-format
 msgid "LV Name                %s%s/%s"
 msgstr ""
 
-#: display/display.c:357
+#: display/display.c:356
 #, c-format
 msgid "VG Name                %s"
 msgstr ""
 
-#: display/display.c:359
+#: display/display.c:358
 #, c-format
 msgid "LV UUID                %s"
 msgstr ""
 
-#: display/display.c:361
+#: display/display.c:360
 #, c-format
 msgid "LV Write Access        %s"
 msgstr ""
 
-#: display/display.c:365
+#: display/display.c:364
 msgid "LV snapshot status     source of"
 msgstr ""
 
-#: display/display.c:374
+#: display/display.c:373
 #, c-format
 msgid "                       %s%s/%s [%s]"
 msgstr ""
 
-#: display/display.c:384
+#: display/display.c:386
 #, c-format
 msgid "LV snapshot status     %s destination for %s%s/%s"
 msgstr ""
 
-#: display/display.c:391
+#: display/display.c:393
 msgid "LV Status              suspended"
 msgstr ""
 
-#: display/display.c:393
+#: display/display.c:395
 #, c-format
 msgid "LV Status              %savailable"
 msgstr ""
 
-#: display/display.c:401
+#: display/display.c:403
 #, c-format
 msgid "# open                 %u"
 msgstr ""
 
-#: display/display.c:403
+#: display/display.c:405
 #, c-format
 msgid "LV Size                %s"
 msgstr ""
 
-#: display/display.c:408
+#: display/display.c:410
 #, c-format
 msgid "Current LE             %u"
 msgstr ""
 
-#: display/display.c:415
+#: display/display.c:414
 #, c-format
-msgid "Segments               %u"
+msgid "COW-table size         %s"
 msgstr ""
 
-#: display/display.c:425
+#: display/display.c:416
 #, c-format
-msgid "Snapshot chunk size    %s"
+msgid "COW-table LE           %u"
 msgstr ""
 
-#: display/display.c:434
+#: display/display.c:419
 #, c-format
 msgid "Allocated to snapshot  %.2f%% "
 msgstr ""
 
-#: display/display.c:446
+#: display/display.c:421
+#, c-format
+msgid "Snapshot chunk size    %s"
+msgstr ""
+
+#: display/display.c:426
+#, c-format
+msgid "Segments               %u"
+msgstr ""
+
+#: display/display.c:432
 #, c-format
 msgid "Allocation             %s"
 msgstr ""
 
-#: display/display.c:447
+#: display/display.c:433
 #, c-format
 msgid "Read ahead sectors     %u"
 msgstr ""
 
-#: display/display.c:451
+#: display/display.c:437
 #, c-format
 msgid "Persistent major       %d"
 msgstr ""
 
-#: display/display.c:452
+#: display/display.c:438
 #, c-format
 msgid "Persistent minor       %d"
 msgstr ""
 
-#: display/display.c:456
+#: display/display.c:442
 #, c-format
 msgid "Block device           %d:%d"
 msgstr ""
 
-#: display/display.c:468
+#: display/display.c:455
 #, c-format
 msgid "%sPhysical volume\t%s"
 msgstr ""
 
-#: display/display.c:473
+#: display/display.c:461
 #, c-format
 msgid "%sPhysical extents\t%d to %d"
 msgstr ""
 
-#: display/display.c:478
+#: display/display.c:466
 #, c-format
 msgid "%sLogical volume\t%s"
 msgstr ""
 
-#: display/display.c:483
+#: display/display.c:471
 #, c-format
 msgid "%sLogical extents\t%d to %d"
 msgstr ""
 
-#: display/display.c:494
+#: display/display.c:482
 msgid "--- Segments ---"
 msgstr ""
 
-#: display/display.c:497
+#: display/display.c:485
 #, c-format
 msgid "Logical extent %u to %u:"
 msgstr ""
 
-#: display/display.c:500
+#: display/display.c:488
 #, c-format
 msgid "  Type\t\t%s"
 msgstr ""
 
-#: display/display.c:526
+#: display/display.c:514
 msgid "--- Volume group ---"
 msgstr ""
 
-#: display/display.c:527
+#: display/display.c:515
 #, c-format
 msgid "VG Name               %s"
 msgstr ""
 
-#: display/display.c:528
+#: display/display.c:516
 #, c-format
 msgid "System ID             %s"
 msgstr ""
 
-#: display/display.c:529
+#: display/display.c:517
 #, c-format
 msgid "Format                %s"
 msgstr ""
 
-#: display/display.c:531
+#: display/display.c:519
 #, c-format
 msgid "Metadata Areas        %d"
 msgstr ""
 
-#: display/display.c:533
+#: display/display.c:521
 #, c-format
 msgid "Metadata Sequence No  %d"
 msgstr ""
 
-#: display/display.c:536
+#: display/display.c:524
 #, c-format
 msgid "VG Access             %s%s%s%s"
 msgstr ""
 
-#: display/display.c:541
+#: display/display.c:529
 #, c-format
 msgid "VG Status             %s%sresizable"
 msgstr ""
 
-#: display/display.c:548
+#: display/display.c:536
 msgid "Clustered             yes"
 msgstr ""
 
-#: display/display.c:549
+#: display/display.c:537
 #, c-format
 msgid "Shared                %s"
 msgstr ""
 
-#: display/display.c:552
+#: display/display.c:540
 #, c-format
 msgid "MAX LV                %u"
 msgstr ""
 
-#: display/display.c:553
+#: display/display.c:541
 #, c-format
 msgid "Cur LV                %u"
 msgstr ""
 
-#: display/display.c:554
+#: display/display.c:542
 #, c-format
 msgid "Open LV               %u"
 msgstr ""
 
-#: display/display.c:560
+#: display/display.c:548
 #, c-format
 msgid "Max PV                %u"
 msgstr ""
 
-#: display/display.c:561
+#: display/display.c:549
 #, c-format
 msgid "Cur PV                %u"
 msgstr ""
 
-#: display/display.c:562
+#: display/display.c:550
 #, c-format
 msgid "Act PV                %u"
 msgstr ""
 
-#: display/display.c:564
+#: display/display.c:552
 #, c-format
 msgid "VG Size               %s"
 msgstr ""
 
-#: display/display.c:569
+#: display/display.c:557
 #, c-format
 msgid "PE Size               %s"
 msgstr ""
 
-#: display/display.c:575
+#: display/display.c:563
 #, c-format
 msgid "Alloc PE / Size       %u / %s"
 msgstr ""
 
-#: display/display.c:581
+#: display/display.c:569
 #, c-format
 msgid "Free  PE / Size       %u / %s"
 msgstr ""
 
-#: display/display.c:591
+#: display/display.c:579
 #, c-format
 msgid "VG UUID               %s"
 msgstr ""
 
-#: display/display.c:627
+#: display/display.c:615
 #, c-format
 msgid "%s:%s:%d:-1:%u:%u:%u:-1:%u:%u:%u:%llu:%u:%u:%u:%u:%s"
 msgstr ""
 
-#: display/display.c:651
+#: display/display.c:639
 #, c-format
 msgid "\"%s\" %-9s [%-9s used / %s free]"
 msgstr ""
 
-#: display/display.c:671 display/display.c:680 pvscan.c:33
-#: report/report.c:1268 report/report.c:1423
+#: display/display.c:659 display/display.c:668 pvscan.c:33
+#: report/report.c:1325 report/report.c:1477
 #, c-format
 msgid "%s"
 msgstr ""
@@ -1663,8 +1765,8 @@
 msgid "Please specify one file for output"
 msgstr ""
 
-#: error/errseg.c:100 mirror/mirrored.c:261 snapshot/snapshot.c:165
-#: striped/striped.c:220 zero/zero.c:100
+#: error/errseg.c:100 mirror/mirrored.c:315 snapshot/snapshot.c:165
+#: striped/striped.c:230 zero/zero.c:100
 #, c-format
 msgid "Initialised segtype: %s"
 msgstr ""
@@ -1696,36 +1798,40 @@
 msgid "md filter allocation failed"
 msgstr ""
 
-#: filters/filter-persistent.c:70
+#: filters/filter-persistent.c:56
+msgid "Wiping cache of LVM-capable devices"
+msgstr ""
+
+#: filters/filter-persistent.c:72
 #, c-format
 msgid "Couldn't find %s array in '%s'"
 msgstr ""
 
-#: filters/filter-persistent.c:81
+#: filters/filter-persistent.c:83
 msgid "Devices array contains a value which is not a string ... ignoring"
 msgstr ""
 
-#: filters/filter-persistent.c:87
+#: filters/filter-persistent.c:89
 #, c-format
 msgid "Couldn't add '%s' to filter ... ignoring"
 msgstr ""
 
-#: filters/filter-persistent.c:125
+#: filters/filter-persistent.c:127
 #, c-format
 msgid "Loaded persistent filter cache from %s"
 msgstr ""
 
-#: filters/filter-persistent.c:169
+#: filters/filter-persistent.c:171
 #, c-format
 msgid "Internal persistent device cache empty - not writing to %s"
 msgstr ""
 
-#: filters/filter-persistent.c:174
+#: filters/filter-persistent.c:176
 #, c-format
 msgid "Device cache incomplete - not writing to %s"
 msgstr ""
 
-#: filters/filter-persistent.c:179
+#: filters/filter-persistent.c:181
 #, c-format
 msgid "Dumping persistent device cache to %s"
 msgstr ""
@@ -1755,12 +1861,12 @@
 msgid "invalid filter pattern"
 msgstr ""
 
-#: filters/filter-regex.c:174
+#: filters/filter-regex.c:172
 #, c-format
 msgid "%s: New preferred name"
 msgstr ""
 
-#: filters/filter-regex.c:190
+#: filters/filter-regex.c:188
 #, c-format
 msgid "%s: Skipping (regex)"
 msgstr ""
@@ -1800,54 +1906,54 @@
 msgid "sysfs dev_set creation failed"
 msgstr ""
 
-#: filters/filter.c:85
+#: filters/filter.c:86
 #, c-format
 msgid "%s: Skipping: Unrecognised LVM device type %llu"
 msgstr ""
 
-#: filters/filter.c:92
+#: filters/filter.c:93
 #, c-format
 msgid "%s: Skipping: open failed"
 msgstr ""
 
-#: filters/filter.c:98
+#: filters/filter.c:99
 #, c-format
 msgid "%s: Skipping: dev_get_size failed"
 msgstr ""
 
-#: filters/filter.c:103
+#: filters/filter.c:104
 #, c-format
 msgid "%s: Skipping: Too small to hold a PV"
 msgstr ""
 
-#: filters/filter.c:108
+#: filters/filter.c:109
 #, c-format
 msgid "%s: Skipping: Partition table signature found"
 msgstr ""
 
-#: filters/filter.c:135
+#: filters/filter.c:136
 msgid "No proc filesystem found: using all block device types"
 msgstr ""
 
-#: filters/filter.c:147
+#: filters/filter.c:148
 msgid "Failed to create /proc/devices string"
 msgstr ""
 
-#: filters/filter.c:202
+#: filters/filter.c:203
 msgid "Expecting string in devices/types in config file"
 msgstr ""
 
-#: filters/filter.c:210
+#: filters/filter.c:211
 #, c-format
 msgid "Max partition count missing for %s in devices/types in config file"
 msgstr ""
 
-#: filters/filter.c:216
+#: filters/filter.c:217
 #, c-format
 msgid "Zero partition count invalid for %s in devices/types in config file"
 msgstr ""
 
-#: filters/filter.c:244
+#: filters/filter.c:245
 msgid "LVM type filter allocation failed"
 msgstr ""
 
@@ -1901,12 +2007,12 @@
 msgid "Found %s in %sVG %s"
 msgstr ""
 
-#: format1/disk-rep.c:435 format_pool/disk_rep.c:72
+#: format1/disk-rep.c:435 format_pool/disk_rep.c:69
 #, c-format
 msgid "Ignoring duplicate PV %s on %s"
 msgstr ""
 
-#: format1/disk-rep.c:440 format_pool/disk_rep.c:77
+#: format1/disk-rep.c:440 format_pool/disk_rep.c:74
 #, c-format
 msgid "Duplicate PV %s - using md %s"
 msgstr ""
@@ -1915,220 +2021,218 @@
 msgid "read_pvs_in_vg: dev_iter_create failed"
 msgstr ""
 
-#: format1/disk-rep.c:527
+#: format1/disk-rep.c:526
 #, c-format
 msgid "Too many uuids to fit on %s"
 msgstr ""
 
-#: format1/disk-rep.c:561
+#: format1/disk-rep.c:559
 #, c-format
 msgid "Couldn't zero lv area on device '%s'"
 msgstr ""
 
-#: format1/disk-rep.c:571
+#: format1/disk-rep.c:567
 #, c-format
 msgid "lv_number %d too large"
 msgstr ""
 
-#: format1/disk-rep.c:604
+#: format1/disk-rep.c:600
 msgid "Invalid PV structure size."
 msgstr ""
 
-#: format1/disk-rep.c:613
+#: format1/disk-rep.c:609
 msgid "Couldn't allocate temporary PV buffer."
 msgstr ""
 
-#: format1/disk-rep.c:639
+#: format1/disk-rep.c:635
 #, c-format
 msgid "Failed to write PV structure onto %s"
 msgstr ""
 
-#: format1/disk-rep.c:658
+#: format1/disk-rep.c:654
 #, c-format
 msgid "Failed to write VG data to %s"
 msgstr ""
 
-#: format1/disk-rep.c:663
+#: format1/disk-rep.c:659
 #, c-format
 msgid "Failed to write PV uuid list to %s"
 msgstr ""
 
-#: format1/disk-rep.c:668
+#: format1/disk-rep.c:664
 #, c-format
 msgid "Failed to write LV's to %s"
 msgstr ""
 
-#: format1/disk-rep.c:673
+#: format1/disk-rep.c:669
 #, c-format
 msgid "Failed to write extents to %s"
 msgstr ""
 
-#: format1/disk-rep.c:715
+#: format1/disk-rep.c:709
 #, c-format
 msgid "Successfully wrote data to %s"
 msgstr ""
 
-#: format1/format1.c:77
+#: format1/format1.c:75
 #, c-format
 msgid "VG data differs between PVs %s and %s"
 msgstr ""
 
-#: format1/format1.c:79 format1/format1.c:94
+#: format1/format1.c:77 format1/format1.c:92
 #, c-format
 msgid "VG data on %s: %s %s %u %u  %u %u %u %u %u %u %u %u %u %u %u %u %u"
 msgstr ""
 
-#: format1/format1.c:120
+#: format1/format1.c:118
 #, c-format
 msgid "%d PV(s) found for VG %s: expected %d"
 msgstr ""
 
-#: format1/format1.c:307 format_pool/format_pool.c:235
+#: format1/format1.c:301 format_pool/format_pool.c:230
 #, c-format
 msgid "Reading physical volume data %s from disk"
 msgstr ""
 
-#: format1/format1.c:348
+#: format1/format1.c:342
 #, c-format
 msgid "Physical volumes cannot be bigger than %s"
 msgstr ""
 
-#: format1/format1.c:369
+#: format1/format1.c:363
 msgid "Metadata would overwrite physical extents"
 msgstr ""
 
-#: format1/format1.c:384
+#: format1/format1.c:378
 #, c-format
 msgid "logical volumes cannot contain more than %d extents."
 msgstr ""
 
-#: format1/format1.c:389
+#: format1/format1.c:383
 #, c-format
 msgid "logical volumes cannot be larger than %s"
 msgstr ""
 
-#: format1/format1.c:471
+#: format1/format1.c:465
 #, c-format
 msgid "Extent size must be between %s and %s"
 msgstr ""
 
-#: format1/format1.c:481
+#: format1/format1.c:475
 #, c-format
 msgid "Extent size must be multiple of %s"
 msgstr ""
 
-#: format1/format1.c:489 format_text/format-text.c:71
+#: format1/format1.c:483 format_text/format-text.c:71
 msgid "Extent size must be power of 2"
 msgstr ""
 
-#: format1/format1.c:585
+#: format1/format1.c:579
 msgid "Couldn't create lvm1 label handler."
 msgstr ""
 
-#: format1/format1.c:590
+#: format1/format1.c:584
 msgid "Couldn't register lvm1 label handler."
 msgstr ""
 
-#: format1/format1.c:594 format_pool/format_pool.c:360
-#: format_text/format-text.c:1695
+#: format1/format1.c:588 format_pool/format_pool.c:355
+#: format_text/format-text.c:1706
 #, c-format
 msgid "Initialised format: %s"
 msgstr ""
 
-#: format1/import-export.c:71
+#: format1/import-export.c:72
 #, c-format
 msgid "System ID %s on %s differs from %s for volume group"
 msgstr ""
 
-#: format1/import-export.c:101
+#: format1/import-export.c:108
 msgid "Generated system_id too long"
 msgstr ""
 
-#: format1/import-export.c:147
+#: format1/import-export.c:154
 #, c-format
 msgid "Volume group name %s too long to export"
 msgstr ""
 
-#: format1/import-export.c:386
+#: format1/import-export.c:392
 #, c-format
 msgid "Segment type %s in LV %s: unsupported by format1"
 msgstr ""
 
-#: format1/import-export.c:392
+#: format1/import-export.c:398
 #, c-format
 msgid "LV stripe found in LV %s: unsupported by format1"
 msgstr ""
 
-#: format1/import-export.c:562
-#, c-format
-msgid "Couldn't find snapshot origin '%s'."
-msgstr ""
-
-#: format1/import-export.c:568
-#, c-format
-msgid "Couldn't find snapshot cow store '%s'."
-msgstr ""
-
-#: format1/import-export.c:610
+#: format1/import-export.c:590
 msgid "Logical volume number out of bounds."
 msgstr ""
 
-#: format1/import-export.c:617
+#: format1/import-export.c:597
 #, c-format
 msgid "Couldn't find logical volume '%s'."
 msgstr ""
 
-#: format1/import-export.c:639
+#: format1/import-export.c:617
 #, c-format
 msgid "Couldn't find origin logical volume for snapshot '%s'."
 msgstr ""
 
-#: format1/import-export.c:651
+#: format1/import-export.c:630
 msgid "Couldn't add snapshot."
 msgstr ""
 
-#: format1/import-extents.c:56
+#: format1/import-extents.c:55
 msgid "Unable to create hash table for holding extent maps."
 msgstr ""
 
-#: format1/import-extents.c:101
+#: format1/import-extents.c:100
 #, c-format
 msgid "Physical volume (%s) contains an unknown logical volume (%s)."
 msgstr ""
 
-#: format1/import-extents.c:148
+#: format1/import-extents.c:145
 msgid "invalid lv in extent map"
 msgstr ""
 
-#: format1/import-extents.c:155
+#: format1/import-extents.c:152
 msgid "logical extent number out of bounds"
 msgstr ""
 
-#: format1/import-extents.c:161
+#: format1/import-extents.c:158
 #, c-format
 msgid "logical extent (%u) already mapped."
 msgstr ""
 
-#: format1/import-extents.c:181
+#: format1/import-extents.c:178
 #, c-format
 msgid "Logical volume (%s) contains an incomplete mapping table."
 msgstr ""
 
+#: format1/import-extents.c:225
+msgid "Failed to allocate linear segment."
+msgstr ""
+
 #: format1/import-extents.c:273
 #, c-format
 msgid ""
 "Number of stripes (%u) incompatible with logical extent count (%u) for %s"
 msgstr ""
 
-#: format1/import-extents.c:356
+#: format1/import-extents.c:301
+msgid "Failed to allocate striped segment."
+msgstr ""
+
+#: format1/import-extents.c:359
 msgid "Couldn't allocate logical volume maps."
 msgstr ""
 
-#: format1/import-extents.c:361
+#: format1/import-extents.c:364
 msgid "Couldn't fill logical volume maps."
 msgstr ""
 
-#: format1/import-extents.c:371
+#: format1/import-extents.c:374
 msgid "Couldn't build extent segments."
 msgstr ""
 
@@ -2162,112 +2266,112 @@
 msgstr ""
 
 #: format1/lvm1-label.c:111 format_pool/pool_label.c:100
-#: format_text/text_label.c:282
+#: format_text/text_label.c:276
 msgid "Couldn't allocate labeller object."
 msgstr ""
 
-#: format_pool/disk_rep.c:99 format_pool/disk_rep.c:103
+#: format_pool/disk_rep.c:96 format_pool/disk_rep.c:100
 #, c-format
 msgid "Calculated uuid %s for %s"
 msgstr ""
 
-#: format_pool/disk_rep.c:281
+#: format_pool/disk_rep.c:276
 #, c-format
 msgid "Unable to allocate %d 32-bit uints"
 msgstr ""
 
-#: format_pool/disk_rep.c:349
+#: format_pool/disk_rep.c:343
 #, c-format
 msgid "No devices for vg %s found in cache"
 msgstr ""
 
-#: format_pool/disk_rep.c:371
+#: format_pool/disk_rep.c:365
 msgid "Unable to allocate pool list structure"
 msgstr ""
 
-#: format_pool/format_pool.c:51
+#: format_pool/format_pool.c:47
 #, c-format
 msgid "Unable to allocate %d subpool structures"
 msgstr ""
 
-#: format_pool/format_pool.c:71
+#: format_pool/format_pool.c:67
 #, c-format
 msgid "Unable to allocate %d pool_device structures"
 msgstr ""
 
-#: format_pool/format_pool.c:93
+#: format_pool/format_pool.c:89
 #, c-format
 msgid "Missing subpool %d in pool %s"
 msgstr ""
 
-#: format_pool/format_pool.c:98
+#: format_pool/format_pool.c:94
 #, c-format
 msgid "Missing device %d for subpool %d in pool %s"
 msgstr ""
 
-#: format_pool/format_pool.c:119
+#: format_pool/format_pool.c:115
 msgid "Unable to allocate volume group structure"
 msgstr ""
 
-#: format_pool/format_pool.c:285
+#: format_pool/format_pool.c:280
 msgid "Unable to allocate format instance structure for pool format"
 msgstr ""
 
-#: format_pool/format_pool.c:295
+#: format_pool/format_pool.c:290
 msgid "Unable to allocate metadata area structure for pool format"
 msgstr ""
 
-#: format_pool/format_pool.c:338
+#: format_pool/format_pool.c:333
 msgid "Unable to allocate format type structure for pool format"
 msgstr ""
 
-#: format_pool/format_pool.c:351
+#: format_pool/format_pool.c:346
 msgid "Couldn't create pool label handler."
 msgstr ""
 
-#: format_pool/format_pool.c:356
+#: format_pool/format_pool.c:351
 msgid "Couldn't register pool label handler."
 msgstr ""
 
-#: format_pool/import_export.c:68
+#: format_pool/import_export.c:65
 msgid "Unable to allocate lv list structure"
 msgstr ""
 
-#: format_pool/import_export.c:73
+#: format_pool/import_export.c:70
 msgid "Unable to allocate logical volume structure"
 msgstr ""
 
-#: format_pool/import_export.c:102
+#: format_pool/import_export.c:99
 #, c-format
 msgid "Calculated lv uuid for lv %s: %s"
 msgstr ""
 
-#: format_pool/import_export.c:138
+#: format_pool/import_export.c:134
 msgid "Unable to allocate pv list structure"
 msgstr ""
 
-#: format_pool/import_export.c:142
+#: format_pool/import_export.c:138
 msgid "Unable to allocate pv structure"
 msgstr ""
 
-#: format_pool/import_export.c:170
+#: format_pool/import_export.c:166
 msgid "Unable to duplicate vg_name string"
 msgstr ""
 
-#: format_pool/import_export.c:193
+#: format_pool/import_export.c:195
 #, c-format
 msgid "Found sptype %X and converted it to %s"
 msgstr ""
 
-#: format_pool/import_export.c:206
-msgid "Unable to allocate striped lv_segment structure"
-msgstr ""
-
 #: format_pool/import_export.c:210
 msgid "Stripe size must be a power of 2"
 msgstr ""
 
-#: format_pool/import_export.c:250
+#: format_pool/import_export.c:226
+msgid "Unable to allocate striped lv_segment structure"
+msgstr ""
+
+#: format_pool/import_export.c:267
 msgid "Unable to allocate linear lv_segment structure"
 msgstr ""
 
@@ -2276,74 +2380,93 @@
 msgid "The '%s' operation is not supported for the pool labeller."
 msgstr ""
 
-#: format_text/archive.c:150
-msgid "Couldn't scan archive directory."
+#: format_text/archive.c:148
+#, c-format
+msgid "Couldn't scan the archive directory (%s)."
 msgstr ""
 
-#: format_text/archive.c:177
+#: format_text/archive.c:175
 msgid "Couldn't create new archive file."
 msgstr ""
 
-#: format_text/archive.c:228
+#: format_text/archive.c:223
 #, c-format
 msgid "Expiring archive %s"
 msgstr ""
 
-#: format_text/archive.c:253
+#: format_text/archive.c:248
 msgid "Couldn't create temporary archive name."
 msgstr ""
 
-#: format_text/archive.c:258
+#: format_text/archive.c:253
 msgid "Couldn't create FILE object for archive."
 msgstr ""
 
-#: format_text/archive.c:275 format_text/archive.c:351
-#, c-format
-msgid "Couldn't scan the archive directory (%s)."
-msgstr ""
-
-#: format_text/archive.c:289
+#: format_text/archive.c:284
 msgid "Archive file name too long."
 msgstr ""
 
-#: format_text/archive.c:300
+#: format_text/archive.c:295
 #, c-format
 msgid "Archive rename failed for %s"
 msgstr ""
 
-#: format_text/archive.c:317
+#: format_text/archive.c:312
 #, c-format
 msgid "File:\t\t%s"
 msgstr ""
 
-#: format_text/archive.c:322
+#: format_text/archive.c:317
 msgid "Couldn't create text instance object."
 msgstr ""
 
-#: format_text/archive.c:332
+#: format_text/archive.c:327
 msgid "Unable to read archive file."
 msgstr ""
 
-#: format_text/archive.c:337
+#: format_text/archive.c:332
 #, c-format
 msgid "VG name:    \t%s"
 msgstr ""
 
-#: format_text/archive.c:338
+#: format_text/archive.c:333
 #, c-format
 msgid "Description:\t%s"
 msgstr ""
 
-#: format_text/archive.c:339
+#: format_text/archive.c:334
 #, c-format
 msgid "Backup Time:\t%s"
 msgstr ""
 
-#: format_text/archive.c:356
+#: format_text/archive.c:351
 #, c-format
 msgid "No archives found in %s."
 msgstr ""
 
+#: format_text/archiver.c:43 format_text/archiver.c:155
+msgid "archive_params alloc failed"
+msgstr ""
+
+#: format_text/archiver.c:128
+#, c-format
+msgid "Archiving volume group \"%s\" metadata (seqno %u)."
+msgstr ""
+
+#: format_text/archiver.c:303
+#, c-format
+msgid "PV %s is a different format (seqno %s)"
+msgstr ""
+
+#: format_text/archiver.c:364
+#, c-format
+msgid "Creating volume group backup \"%s\" (seqno %u)."
+msgstr ""
+
+#: format_text/archiver.c:402
+msgid "Failed to generate backup filename."
+msgstr ""
+
 #: format_text/export.c:69
 #, c-format
 msgid "uname failed: %s"
@@ -2353,19 +2476,23 @@
 msgid "Internal error tracking indentation"
 msgstr ""
 
-#: format_text/flags.c:73
+#: format_text/export.c:737
+msgid "text_export buffer allocation failed"
+msgstr ""
+
+#: format_text/flags.c:76
 msgid "Unknown flag set requested."
 msgstr ""
 
-#: format_text/flags.c:119
+#: format_text/flags.c:122
 msgid "Metadata inconsistency: Not all flags successfully exported."
 msgstr ""
 
-#: format_text/flags.c:141
+#: format_text/flags.c:144
 msgid "Status value is not a string."
 msgstr ""
 
-#: format_text/flags.c:152
+#: format_text/flags.c:155
 #, c-format
 msgid "Unknown status flag '%s'."
 msgstr ""
@@ -2397,205 +2524,200 @@
 msgid "Incorrect start sector in metadata area header: %llu"
 msgstr ""
 
-#: format_text/format-text.c:275 format_text/format-text.c:376
+#: format_text/format-text.c:285
+#, c-format
+msgid "VG %s not found on %s"
+msgstr ""
+
+#: format_text/format-text.c:293 format_text/format-text.c:390
 #, c-format
 msgid "VG %s metadata too large for circular buffer"
 msgstr ""
 
-#: format_text/format-text.c:290
+#: format_text/format-text.c:308
 #, c-format
-msgid "Read %s metadata (%u) from %s at %llu size %llu"
+msgid "Read %s %smetadata (%u) from %s at %llu size %llu"
 msgstr ""
 
-#: format_text/format-text.c:361
+#: format_text/format-text.c:375
 #, c-format
 msgid "VG %s metadata writing failed"
 msgstr ""
 
-#: format_text/format-text.c:381
+#: format_text/format-text.c:395
 #, c-format
 msgid "Writing %s metadata to %s at %llu len %llu"
 msgstr ""
 
-#: format_text/format-text.c:393
+#: format_text/format-text.c:407
 #, c-format
 msgid "Writing metadata to %s at %llu len %u"
 msgstr ""
 
-#: format_text/format-text.c:460
+#: format_text/format-text.c:481
 #, c-format
-msgid "Committing %s metadata (%u) to %s header at %llu"
+msgid "%sCommitting %s metadata (%u) to %s header at %llu"
 msgstr ""
 
-#: format_text/format-text.c:465 format_text/format-text.c:534
+#: format_text/format-text.c:486 format_text/format-text.c:566
 msgid "Failed to write metadata area header"
 msgstr ""
 
-#: format_text/format-text.c:567
+#: format_text/format-text.c:599
 #, c-format
 msgid "'%s' does not contain volume group '%s'."
 msgstr ""
 
-#: format_text/format-text.c:571
+#: format_text/format-text.c:603
 #, c-format
 msgid "Read volume group %s from %s"
 msgstr ""
 
-#: format_text/format-text.c:605
+#: format_text/format-text.c:646
 msgid "Text format failed to determine directory."
 msgstr ""
 
-#: format_text/format-text.c:610
+#: format_text/format-text.c:651
 msgid "Couldn't create temporary text file name."
 msgstr ""
 
-#: format_text/format-text.c:620
+#: format_text/format-text.c:661
 #, c-format
 msgid "Writing %s metadata to %s"
 msgstr ""
 
-#: format_text/format-text.c:623
+#: format_text/format-text.c:664
 #, c-format
 msgid "Failed to write metadata to %s."
 msgstr ""
 
-#: format_text/format-text.c:641 format_text/format-text.c:667
-#: format_text/format-text.c:704
+#: format_text/format-text.c:682 format_text/format-text.c:708
+#: format_text/format-text.c:745 misc/lvm-file.c:90
 #, c-format
 msgid "%s: rename to %s failed: %s"
 msgstr ""
 
-#: format_text/format-text.c:656
+#: format_text/format-text.c:697
 #, c-format
 msgid "Test mode: Skipping committing %s metadata (%u)"
 msgstr ""
 
-#: format_text/format-text.c:659
+#: format_text/format-text.c:700
 #, c-format
 msgid "Unlinking %s"
 msgstr ""
 
-#: format_text/format-text.c:664
+#: format_text/format-text.c:705
 #, c-format
 msgid "Committing %s metadata (%u)"
 msgstr ""
 
-#: format_text/format-text.c:701
+#: format_text/format-text.c:742
 msgid "Test mode: Skipping rename"
 msgstr ""
 
-#: format_text/format-text.c:765 format_text/format-text.c:1425
+#: format_text/format-text.c:805 format_text/format-text.c:1438
 #, c-format
 msgid "Name too long %s/%s"
 msgstr ""
 
-#: format_text/format-text.c:894
+#: format_text/format-text.c:933
 #, c-format
 msgid "Physical extents end beyond end of device %s!"
 msgstr ""
 
-#: format_text/format-text.c:910
+#: format_text/format-text.c:960
 #, c-format
-msgid "Warning: metadata area fills disk %s"
+msgid "Warning: metadata area fills disk leaving no space for data on %s."
 msgstr ""
 
-#: format_text/format-text.c:940 format_text/format-text.c:986
+#: format_text/format-text.c:990 format_text/format-text.c:1036
 msgid "Failed to wipe new metadata area"
 msgstr ""
 
-#: format_text/format-text.c:1035
+#: format_text/format-text.c:1083
 #, c-format
 msgid "Creating metadata area on %s at sector %llu size %llu sectors"
 msgstr ""
 
-#: format_text/format-text.c:1114
-#, c-format
-msgid "format_text: _vg_read failed to read VG %s"
-msgstr ""
-
-#: format_text/format-text.c:1120
-#, c-format
-msgid "Warning: Volume group %s is not consistent"
-msgstr ""
-
-#: format_text/format-text.c:1147
+#: format_text/format-text.c:1164
 msgid "_add_raw allocation failed"
 msgstr ""
 
-#: format_text/format-text.c:1207
+#: format_text/format-text.c:1223
 #, c-format
 msgid "Must be exactly one data area (found %d) on PV %s"
 msgstr ""
 
-#: format_text/format-text.c:1224 format_text/format-text.c:1228
+#: format_text/format-text.c:1238 format_text/format-text.c:1242
 msgid "metadata_area allocation failed"
 msgstr ""
 
-#: format_text/format-text.c:1402
+#: format_text/format-text.c:1416
 msgid "Couldn't allocate format instance object."
 msgstr ""
 
-#: format_text/format-text.c:1513
+#: format_text/format-text.c:1523
 #, c-format
 msgid "%s: Volume group filename may not end in .tmp"
 msgstr ""
 
-#: format_text/format-text.c:1547
+#: format_text/format-text.c:1557
 msgid "Couldn't allocate text format context object."
 msgstr ""
 
-#: format_text/format-text.c:1569
+#: format_text/format-text.c:1579
 msgid "_add_dir allocation failed"
 msgstr ""
 
-#: format_text/format-text.c:1572
+#: format_text/format-text.c:1582
 #, c-format
 msgid "Adding text format metadata dir: %s"
 msgstr ""
 
-#: format_text/format-text.c:1589
+#: format_text/format-text.c:1599
 msgid "Empty metadata disk_area section of config file"
 msgstr ""
 
-#: format_text/format-text.c:1594
+#: format_text/format-text.c:1604
 msgid "Missing start_sector in metadata disk_area section of config file"
 msgstr ""
 
-#: format_text/format-text.c:1601
+#: format_text/format-text.c:1611
 msgid "Missing size in metadata disk_area section of config file"
 msgstr ""
 
-#: format_text/format-text.c:1608
+#: format_text/format-text.c:1618
 msgid "Missing uuid in metadata disk_area section of config file"
 msgstr ""
 
-#: format_text/format-text.c:1614
+#: format_text/format-text.c:1624
 #, c-format
 msgid "Invalid uuid in metadata disk_area section of config file: %s"
 msgstr ""
 
-#: format_text/format-text.c:1623 format_text/import_vsn1.c:155
+#: format_text/format-text.c:1633 format_text/import_vsn1.c:156
 msgid "Couldn't find device."
 msgstr ""
 
-#: format_text/format-text.c:1625 format_text/import_vsn1.c:157
+#: format_text/format-text.c:1635 format_text/import_vsn1.c:158
 #, c-format
 msgid "Couldn't find device with uuid '%s'."
 msgstr ""
 
-#: format_text/format-text.c:1652
+#: format_text/format-text.c:1663
 msgid "Failed to allocate dir_list"
 msgstr ""
 
-#: format_text/format-text.c:1663
+#: format_text/format-text.c:1674
 msgid "Couldn't create text label handler."
 msgstr ""
 
-#: format_text/format-text.c:1668
+#: format_text/format-text.c:1679
 msgid "Couldn't register text label handler."
 msgstr ""
 
-#: format_text/format-text.c:1675
+#: format_text/format-text.c:1686
 msgid "Invalid string in config file: metadata/dirs"
 msgstr ""
 
@@ -2603,215 +2725,215 @@
 msgid "Couldn't read volume group metadata."
 msgstr ""
 
-#: format_text/import_vsn1.c:47
+#: format_text/import_vsn1.c:48
 #, c-format
 msgid "Can't process text format file - %s."
 msgstr ""
 
-#: format_text/import_vsn1.c:95
+#: format_text/import_vsn1.c:96
 msgid "Couldn't find uuid."
 msgstr ""
 
-#: format_text/import_vsn1.c:101
+#: format_text/import_vsn1.c:102
 msgid "uuid must be a string."
 msgstr ""
 
-#: format_text/import_vsn1.c:106
+#: format_text/import_vsn1.c:107
 msgid "Invalid uuid."
 msgstr ""
 
-#: format_text/import_vsn1.c:139
+#: format_text/import_vsn1.c:140
 msgid "Empty pv section."
 msgstr ""
 
-#: format_text/import_vsn1.c:144
+#: format_text/import_vsn1.c:145
 msgid "Couldn't read uuid for volume group."
 msgstr ""
 
-#: format_text/import_vsn1.c:172
+#: format_text/import_vsn1.c:173
 msgid "Couldn't find status flags for physical volume."
 msgstr ""
 
-#: format_text/import_vsn1.c:177
+#: format_text/import_vsn1.c:178
 msgid "Couldn't read status flags for physical volume."
 msgstr ""
 
-#: format_text/import_vsn1.c:182
+#: format_text/import_vsn1.c:183
 msgid "Couldn't read extent size for volume group."
 msgstr ""
 
-#: format_text/import_vsn1.c:187
+#: format_text/import_vsn1.c:188
 msgid "Couldn't find extent count (pe_count) for physical volume."
 msgstr ""
 
-#: format_text/import_vsn1.c:197
+#: format_text/import_vsn1.c:199
 #, c-format
 msgid "Couldn't read tags for physical volume %s in %s."
 msgstr ""
 
-#: format_text/import_vsn1.c:248
+#: format_text/import_vsn1.c:252
 msgid "Empty segment section."
 msgstr ""
 
-#: format_text/import_vsn1.c:253
+#: format_text/import_vsn1.c:257
 #, c-format
 msgid "Couldn't read 'start_extent' for segment '%s'."
 msgstr ""
 
-#: format_text/import_vsn1.c:259
+#: format_text/import_vsn1.c:263
 #, c-format
 msgid "Couldn't read 'extent_count' for segment '%s'."
 msgstr ""
 
-#: format_text/import_vsn1.c:269
+#: format_text/import_vsn1.c:273
 msgid "Segment type must be a string."
 msgstr ""
 
-#: format_text/import_vsn1.c:287
+#: format_text/import_vsn1.c:293
 msgid "Segment allocation failed"
 msgstr ""
 
-#: format_text/import_vsn1.c:308
+#: format_text/import_vsn1.c:306
 #, c-format
 msgid "Couldn't read tags for a segment of %s/%s."
 msgstr ""
 
-#: format_text/import_vsn1.c:336
+#: format_text/import_vsn1.c:335
 #, c-format
 msgid "Zero areas not allowed for segment '%s'"
 msgstr ""
 
-#: format_text/import_vsn1.c:378
+#: format_text/import_vsn1.c:375
 #, c-format
 msgid "Couldn't find volume '%s' for segment '%s'."
 msgstr ""
 
-#: format_text/import_vsn1.c:391
+#: format_text/import_vsn1.c:388
 #, c-format
 msgid "Incorrect number of areas in area array for segment '%s'."
 msgstr ""
 
-#: format_text/import_vsn1.c:421
+#: format_text/import_vsn1.c:418
 msgid "Only one segment permitted for snapshot"
 msgstr ""
 
-#: format_text/import_vsn1.c:427
+#: format_text/import_vsn1.c:424
 msgid "Couldn't read segment count for logical volume."
 msgstr ""
 
-#: format_text/import_vsn1.c:432
+#: format_text/import_vsn1.c:429
 msgid "segment_count and actual number of segments disagree."
 msgstr ""
 
-#: format_text/import_vsn1.c:478 format_text/import_vsn1.c:544
+#: format_text/import_vsn1.c:475 format_text/import_vsn1.c:543
 msgid "Empty logical volume section."
 msgstr ""
 
-#: format_text/import_vsn1.c:483
+#: format_text/import_vsn1.c:480
 msgid "Couldn't find status flags for logical volume."
 msgstr ""
 
-#: format_text/import_vsn1.c:488
+#: format_text/import_vsn1.c:485
 msgid "Couldn't read status flags for logical volume."
 msgstr ""
 
-#: format_text/import_vsn1.c:496 format_text/import_vsn1.c:710
+#: format_text/import_vsn1.c:493 format_text/import_vsn1.c:714
 msgid "allocation_policy must be a string."
 msgstr ""
 
-#: format_text/import_vsn1.c:517
+#: format_text/import_vsn1.c:516
 #, c-format
 msgid "Couldn't read tags for logical volume %s/%s."
 msgstr ""
 
-#: format_text/import_vsn1.c:537
+#: format_text/import_vsn1.c:536
 #, c-format
 msgid "Lost logical volume reference %s"
 msgstr ""
 
-#: format_text/import_vsn1.c:550
+#: format_text/import_vsn1.c:549
 #, c-format
 msgid "Couldn't read uuid for logical volume %s."
 msgstr ""
 
-#: format_text/import_vsn1.c:569
+#: format_text/import_vsn1.c:576
 #, c-format
 msgid "Couldn't read minor number for logical volume %s."
 msgstr ""
 
-#: format_text/import_vsn1.c:576
+#: format_text/import_vsn1.c:584
 #, c-format
 msgid "Couldn't read major number for logical volume %s."
 msgstr ""
 
-#: format_text/import_vsn1.c:597
+#: format_text/import_vsn1.c:601
 #, c-format
 msgid "Couldn't find section '%s'."
 msgstr ""
 
-#: format_text/import_vsn1.c:626
+#: format_text/import_vsn1.c:630
 msgid "Couldn't find volume group in file."
 msgstr ""
 
-#: format_text/import_vsn1.c:654
+#: format_text/import_vsn1.c:658
 msgid "system_id must be a string"
 msgstr ""
 
-#: format_text/import_vsn1.c:661
+#: format_text/import_vsn1.c:665
 #, c-format
 msgid "Couldn't read uuid for volume group %s."
 msgstr ""
 
-#: format_text/import_vsn1.c:666
+#: format_text/import_vsn1.c:670
 #, c-format
 msgid "Couldn't read 'seqno' for volume group %s."
 msgstr ""
 
-#: format_text/import_vsn1.c:672
+#: format_text/import_vsn1.c:676
 #, c-format
 msgid "Couldn't find status flags for volume group %s."
 msgstr ""
 
-#: format_text/import_vsn1.c:678
+#: format_text/import_vsn1.c:682
 #, c-format
 msgid "Couldn't read status flags for volume group %s."
 msgstr ""
 
-#: format_text/import_vsn1.c:684
+#: format_text/import_vsn1.c:688
 #, c-format
 msgid "Couldn't read extent size for volume group %s."
 msgstr ""
 
-#: format_text/import_vsn1.c:695
+#: format_text/import_vsn1.c:699
 #, c-format
 msgid "Couldn't read 'max_lv' for volume group %s."
 msgstr ""
 
-#: format_text/import_vsn1.c:701
+#: format_text/import_vsn1.c:705
 #, c-format
 msgid "Couldn't read 'max_pv' for volume group %s."
 msgstr ""
 
-#: format_text/import_vsn1.c:726
+#: format_text/import_vsn1.c:730
 msgid "Couldn't create hash table."
 msgstr ""
 
-#: format_text/import_vsn1.c:733
+#: format_text/import_vsn1.c:737
 #, c-format
 msgid "Couldn't find all physical volumes for volume group %s."
 msgstr ""
 
-#: format_text/import_vsn1.c:745
+#: format_text/import_vsn1.c:748
 #, c-format
 msgid "Couldn't read tags for volume group %s."
 msgstr ""
 
-#: format_text/import_vsn1.c:751
+#: format_text/import_vsn1.c:754
 #, c-format
 msgid "Couldn't read all logical volume names for volume group %s."
 msgstr ""
 
-#: format_text/import_vsn1.c:758
+#: format_text/import_vsn1.c:761
 #, c-format
 msgid "Couldn't read all logical volumes for volume group %s."
 msgstr ""
@@ -2820,15 +2942,15 @@
 msgid "Found a tag that is not a string"
 msgstr ""
 
-#: format_text/text_label.c:100 format_text/text_label.c:105
+#: format_text/text_label.c:96 format_text/text_label.c:101
 msgid "struct data_area_list allocation failed"
 msgstr ""
 
-#: format_text/text_label.c:140 format_text/text_label.c:151
+#: format_text/text_label.c:136 format_text/text_label.c:147
 msgid "struct mda_list allocation failed"
 msgstr ""
 
-#: format_text/text_label.c:145 format_text/text_label.c:156
+#: format_text/text_label.c:141 format_text/text_label.c:152
 msgid "struct mda_context allocation failed"
 msgstr ""
 
@@ -2836,22 +2958,22 @@
 msgid "Couldn't allocate memory for labeller list object."
 msgstr ""
 
-#: label/label.c:130 label/label.c:223
+#: label/label.c:131 label/label.c:225
 #, c-format
 msgid "%s: Failed to read label area"
 msgstr ""
 
-#: label/label.c:142 label/label.c:170
+#: label/label.c:143 label/label.c:170
 #, c-format
 msgid "Ignoring additional label on %s at sector %llu"
 msgstr ""
 
-#: label/label.c:147
+#: label/label.c:148
 #, c-format
 msgid "%s: Label for sector %llu found at sector %llu - ignoring"
 msgstr ""
 
-#: label/label.c:156
+#: label/label.c:157
 #, c-format
 msgid "Label checksum incorrect on %s - ignoring"
 msgstr ""
@@ -2861,46 +2983,46 @@
 msgid "%s: %s label detected"
 msgstr ""
 
-#: label/label.c:186
+#: label/label.c:189
 #, c-format
 msgid "%s: No label detected"
 msgstr ""
 
-#: label/label.c:209
+#: label/label.c:211
 #, c-format
 msgid "Scanning for labels to wipe from %s"
 msgstr ""
 
-#: label/label.c:250
+#: label/label.c:251
 #, c-format
 msgid "%s: Wiping label at sector %llu"
 msgstr ""
 
-#: label/label.c:254
+#: label/label.c:255
 #, c-format
 msgid "Failed to remove label from %s at sector %llu"
 msgstr ""
 
-#: label/label.c:296
+#: label/label.c:297
 msgid "Label handler does not support label writes"
 msgstr ""
 
-#: label/label.c:301
+#: label/label.c:302
 #, c-format
 msgid "Label sector %llu beyond range (%ld)"
 msgstr ""
 
-#: label/label.c:325
+#: label/label.c:326
 #, c-format
 msgid "%s: Writing label to sector %llu"
 msgstr ""
 
-#: label/label.c:328
+#: label/label.c:329
 #, c-format
 msgid "Failed to write label to %s"
 msgstr ""
 
-#: label/label.c:363
+#: label/label.c:364
 msgid "label allocaction failed"
 msgstr ""
 
@@ -2943,8 +3065,8 @@
 msgid "Error locking on node %s: %s"
 msgstr ""
 
-#: locking/cluster_locking.c:406 locking/file_locking.c:260
-#: locking/locking.c:244 locking/no_locking.c:71
+#: locking/cluster_locking.c:406 locking/file_locking.c:264
+#: locking/locking.c:247 locking/no_locking.c:71
 #, c-format
 msgid "Unrecognised lock scope: %d"
 msgstr ""
@@ -2977,87 +3099,87 @@
 msgid "CTRL-c detected: giving up waiting for lock"
 msgstr ""
 
-#: locking/file_locking.c:147
+#: locking/file_locking.c:149
 #, c-format
 msgid "Unrecognised lock type: %d"
 msgstr ""
 
-#: locking/file_locking.c:161
+#: locking/file_locking.c:163
 #, c-format
 msgid "Locking %s %c%c"
 msgstr ""
 
-#: locking/file_locking.c:231
+#: locking/file_locking.c:235
 #, c-format
 msgid "Unlocking LV %s"
 msgstr ""
 
-#: locking/file_locking.c:236
+#: locking/file_locking.c:240
 #, c-format
 msgid "Locking LV %s (NL)"
 msgstr ""
 
-#: locking/file_locking.c:241
+#: locking/file_locking.c:245
 #, c-format
 msgid "Locking LV %s (R)"
 msgstr ""
 
-#: locking/file_locking.c:246
+#: locking/file_locking.c:250
 #, c-format
 msgid "Locking LV %s (W)"
 msgstr ""
 
-#: locking/file_locking.c:251
+#: locking/file_locking.c:255
 #, c-format
 msgid "Locking LV %s (EX)"
 msgstr ""
 
-#: locking/locking.c:130
+#: locking/locking.c:132
 msgid ""
 "WARNING: Locking disabled. Be careful! This could corrupt your metadata."
 msgstr ""
 
-#: locking/locking.c:137
+#: locking/locking.c:139
 msgid "File-based locking enabled."
 msgstr ""
 
-#: locking/locking.c:144
+#: locking/locking.c:146
 msgid "External locking enabled."
 msgstr ""
 
-#: locking/locking.c:152
+#: locking/locking.c:154
 msgid "Cluster locking enabled."
 msgstr ""
 
-#: locking/locking.c:157
+#: locking/locking.c:159
 msgid "Unknown locking type requested."
 msgstr ""
 
-#: locking/locking.c:165
+#: locking/locking.c:167
 msgid "Locking disabled - only read operations permitted."
 msgstr ""
 
-#: locking/locking.c:191
+#: locking/locking.c:194
 #, c-format
 msgid "LVM1 proc VG pathname too long for %s"
 msgstr ""
 
-#: locking/locking.c:196
+#: locking/locking.c:199
 #, c-format
 msgid "%s exists: Is the original LVM driver using this volume group?"
 msgstr ""
 
-#: locking/locking.c:285 lvresize.c:469
+#: locking/locking.c:284 lvresize.c:526
 #, c-format
 msgid "Failed to suspend %s"
 msgstr ""
 
-#: locking/locking.c:307
+#: locking/locking.c:305
 #, c-format
 msgid "Failed to activate %s"
 msgstr ""
 
-#: log/log.c:133
+#: log/log.c:135
 msgid "Test mode: Metadata will NOT be updated."
 msgstr ""
 
@@ -3081,22 +3203,23 @@
 msgid "Setting logical volume \"%s\" read-only"
 msgstr ""
 
-#: lvchange.c:47 lvchange.c:162 lvchange.c:205 lvchange.c:290 lvchange.c:348
+#: lvchange.c:47 lvchange.c:168 lvchange.c:211 lvchange.c:296 lvchange.c:354
+#: lvconvert.c:87
 #, c-format
 msgid "Updating logical volume \"%s\" on disk(s)"
 msgstr ""
 
-#: lvchange.c:56 lvchange.c:214 lvchange.c:299
+#: lvchange.c:56 lvchange.c:220 lvchange.c:305 lvconvert.c:97
 #, c-format
 msgid "Failed to lock %s"
 msgstr ""
 
-#: lvchange.c:66 lvchange.c:224 lvchange.c:309
+#: lvchange.c:66 lvchange.c:230 lvchange.c:315
 #, c-format
 msgid "Updating permissions for \"%s\" in kernel"
 msgstr ""
 
-#: lvchange.c:68 lvchange.c:226 lvchange.c:311 lvresize.c:481
+#: lvchange.c:68 lvchange.c:232 lvchange.c:317 lvconvert.c:110 lvresize.c:538
 #, c-format
 msgid "Problem reactivating %s"
 msgstr ""
@@ -3113,203 +3236,313 @@
 
 #: lvchange.c:98
 #, c-format
+msgid "Locking failed: ignoring clustered logical volume %s"
+msgstr ""
+
+#: lvchange.c:104
+#, c-format
 msgid "Activating logical volume \"%s\" exclusively"
 msgstr ""
 
-#: lvchange.c:105
+#: lvchange.c:111
 #, c-format
 msgid "Activating logical volume \"%s\" locally"
 msgstr ""
 
-#: lvchange.c:112
+#: lvchange.c:118
 #, c-format
 msgid "Activating logical volume \"%s\""
 msgstr ""
 
-#: lvchange.c:122
+#: lvchange.c:128
 #, c-format
 msgid "Spawning background pvmove process for %s"
 msgstr ""
 
-#: lvchange.c:133
+#: lvchange.c:139
 #, c-format
 msgid "Refreshing logical volume \"%s\" (if active)"
 msgstr ""
 
-#: lvchange.c:150
+#: lvchange.c:156
 #, c-format
 msgid "Allocation policy of logical volume \"%s\" is already %s"
 msgstr ""
 
-#: lvchange.c:159
+#: lvchange.c:165
 #, c-format
 msgid "Setting contiguous allocation policy for \"%s\" to %s"
 msgstr ""
 
-#: lvchange.c:195
+#: lvchange.c:201
 #, c-format
 msgid "Read ahead is already %u for \"%s\""
 msgstr ""
 
-#: lvchange.c:202
+#: lvchange.c:208
 #, c-format
 msgid "Setting read ahead to %u for \"%s\""
 msgstr ""
 
-#: lvchange.c:241
+#: lvchange.c:247
 #, c-format
 msgid "Minor number is already not persistent for \"%s\""
 msgstr ""
 
-#: lvchange.c:248
+#: lvchange.c:254
 #, c-format
 msgid "Disabling persistent device number for \"%s\""
 msgstr ""
 
-#: lvchange.c:252
+#: lvchange.c:258
 msgid "Minor number must be specified with -My"
 msgstr ""
 
-#: lvchange.c:256
+#: lvchange.c:262
 msgid "Major number must be specified with -My"
 msgstr ""
 
-#: lvchange.c:264
+#: lvchange.c:270
 #, c-format
 msgid "%s device number not changed."
 msgstr ""
 
-#: lvchange.c:270
+#: lvchange.c:276
 #, c-format
 msgid "Ensuring %s is inactive."
 msgstr ""
 
-#: lvchange.c:272
+#: lvchange.c:278
 #, c-format
 msgid "%s: deactivation failed"
 msgstr ""
 
-#: lvchange.c:278
+#: lvchange.c:284
 #, c-format
 msgid "Setting persistent device number to (%d, %d) for \"%s\""
 msgstr ""
 
-#: lvchange.c:281
+#: lvchange.c:287
 #, c-format
 msgid "Re-activating logical volume \"%s\""
 msgstr ""
 
-#: lvchange.c:284
+#: lvchange.c:290
 #, c-format
 msgid "%s: reactivation failed"
 msgstr ""
 
-#: lvchange.c:324 lvcreate.c:542 pvchange.c:46 vgchange.c:219 vgcreate.c:117
+#: lvchange.c:330 lvcreate.c:724 pvchange.c:49 vgchange.c:322 vgcreate.c:111
 msgid "Failed to get tag"
 msgstr ""
 
-#: lvchange.c:329
+#: lvchange.c:335
 #, c-format
 msgid "Logical volume %s/%s does not support tags"
 msgstr ""
 
-#: lvchange.c:336 lvcreate.c:553
+#: lvchange.c:342 lvcreate.c:735
 #, c-format
 msgid "Failed to add tag %s to %s/%s"
 msgstr ""
 
-#: lvchange.c:342
+#: lvchange.c:348
 #, c-format
 msgid "Failed to remove tag %s from %s/%s"
 msgstr ""
 
-#: lvchange.c:374
+#: lvchange.c:381
 #, c-format
 msgid "Only -a permitted with read-only volume group \"%s\""
 msgstr ""
 
-#: lvchange.c:383
+#: lvchange.c:390
 #, c-format
 msgid "Can't change logical volume \"%s\" under snapshot"
 msgstr ""
 
-#: lvchange.c:389
+#: lvchange.c:396
 #, c-format
 msgid "Can't change snapshot logical volume \"%s\""
 msgstr ""
 
-#: lvchange.c:395
+#: lvchange.c:402
 #, c-format
 msgid "Unable to change pvmove LV %s"
 msgstr ""
 
-#: lvchange.c:397
+#: lvchange.c:404
 msgid "Use 'pvmove --abort' to abandon a pvmove"
 msgstr ""
 
-#: lvchange.c:450
+#: lvchange.c:409
+#, c-format
+msgid "Unable to change mirror log LV %s directly"
+msgstr ""
+
+#: lvchange.c:414
+#, c-format
+msgid "Unable to change mirror image LV %s directly"
+msgstr ""
+
+#: lvchange.c:420
+#, c-format
+msgid "Unable to change internal LV %s directly"
+msgstr ""
+
+#: lvchange.c:474
 #, c-format
 msgid "Logical volume \"%s\" changed"
 msgstr ""
 
-#: lvchange.c:472
+#: lvchange.c:496
 msgid ""
 "One or more of -a, -C, -j, -m, -M, -p, -r, --refresh, --alloc, --addtag or --"
 "deltag required"
 msgstr ""
 
-#: lvchange.c:482
+#: lvchange.c:506
 msgid "Only -a permitted with --ignorelockingfailure"
 msgstr ""
 
-#: lvchange.c:487
+#: lvchange.c:511 lvconvert.c:172
 msgid "Please give logical volume path(s)"
 msgstr ""
 
-#: lvchange.c:493
+#: lvchange.c:517
 msgid "--major and --minor require -My"
 msgstr ""
 
-#: lvchange.c:498
+#: lvchange.c:522
 msgid "Only give one logical volume when specifying minor"
 msgstr ""
 
-#: lvchange.c:503
+#: lvchange.c:527
 msgid "Only one of --alloc and --contiguous permitted"
 msgstr ""
 
-#: lvcreate.c:63
+#: lvconvert.c:37
+#, c-format
+msgid "Logical volume %s is already not mirrored."
+msgstr ""
+
+#: lvconvert.c:49
+#, c-format
+msgid "Logical volume %s has multiple mirror segments."
+msgstr ""
+
+#: lvconvert.c:57
+#, c-format
+msgid "Logical volume %s already has %u mirror(s)."
+msgstr ""
+
+#: lvconvert.c:68 lvconvert.c:82
+msgid "Adding mirror images is not supported yet."
+msgstr ""
+
+#: lvconvert.c:107
+#, c-format
+msgid "Updating \"%s\" in kernel"
+msgstr ""
+
+#: lvconvert.c:114
+#, c-format
+msgid "Logical volume %s converted."
+msgstr ""
+
+#: lvconvert.c:125
+#, c-format
+msgid "Cannot convert locked LV %s"
+msgstr ""
+
+#: lvconvert.c:130
+#, c-format
+msgid "Can't convert logical volume \"%s\" under snapshot"
+msgstr ""
+
+#: lvconvert.c:136
+#, c-format
+msgid "Can't convert snapshot logical volume \"%s\""
+msgstr ""
+
+#: lvconvert.c:142
+#, c-format
+msgid "Unable to convert pvmove LV %s"
+msgstr ""
+
+#: lvconvert.c:167
+msgid "--mirrors argument required"
+msgstr ""
+
+#: lvconvert.c:182 lvrename.c:54
+msgid "Please provide a valid volume group name"
+msgstr ""
+
+#: lvconvert.c:189 lvrename.c:102 vgrename.c:65
+#, c-format
+msgid "Checking for existing volume group \"%s\""
+msgstr ""
+
+#: lvconvert.c:192 lvcreate.c:851 lvrename.c:105 lvresize.c:566 pvchange.c:59
+#: pvmove.c:61 vgcreate.c:144 vgextend.c:47 vgmerge.c:33 vgmerge.c:57
+#: vgreduce.c:265 vgrename.c:68 vgrename.c:102 vgsplit.c:189 vgsplit.c:213
+#, c-format
+msgid "Can't get lock for %s"
+msgstr ""
+
+#: lvconvert.c:197 lvcreate.c:480 lvrename.c:110 pvmove.c:66 vgdisplay.c:24
+#: vgmerge.c:38 vgmerge.c:64 vgreduce.c:271 vgrename.c:73 vgsplit.c:194
+#, c-format
+msgid "Volume group \"%s\" doesn't exist"
+msgstr ""
+
+#: lvconvert.c:202 lvcreate.c:485 lvrename.c:115 metadata/metadata.c:1135
+#: polldaemon.c:200 pvchange.c:72 pvmove.c:72 toollib.c:42 vgchange.c:415
+#: vgck.c:32 vgconvert.c:54 vgextend.c:57 vgmerge.c:44 vgmerge.c:69
+#: vgreduce.c:321 vgremove.c:35 vgrename.c:80 vgsplit.c:200
+#, c-format
+msgid "Volume group \"%s\" is exported"
+msgstr ""
+
+#: lvconvert.c:207 lvcreate.c:490 lvremove.c:27 lvrename.c:120 pvchange.c:78
+#: pvmove.c:78 vgchange.c:410 vgconvert.c:49 vgexport.c:38 vgextend.c:62
+#: vgmerge.c:50 vgmerge.c:74 vgreduce.c:327 vgrename.c:86 vgsplit.c:206
+#, c-format
+msgid "Volume group \"%s\" is read-only"
+msgstr ""
+
+#: lvconvert.c:212
+#, c-format
+msgid "Logical volume \"%s\" not found in volume group \"%s\""
+msgstr ""
+
+#: lvcreate.c:65
 msgid "Please specify a logical volume to act as the snapshot origin."
 msgstr ""
 
-#: lvcreate.c:71
+#: lvcreate.c:73
 msgid "The origin name should include the volume group."
 msgstr ""
 
-#: lvcreate.c:87 lvresize.c:101
+#: lvcreate.c:89 lvresize.c:102
 msgid "Please provide a volume group name"
 msgstr ""
 
-#: lvcreate.c:106
+#: lvcreate.c:108
 msgid "Volume group name expected (no slash)"
 msgstr ""
 
-#: lvcreate.c:121
+#: lvcreate.c:123
 #, c-format
 msgid "Inconsistent volume group names given: \"%s\" and \"%s\""
 msgstr ""
 
-#: lvcreate.c:140 lvrename.c:88
-msgid ""
-"Names starting \"snapshot\" are reserved. Please choose a different LV name."
-msgstr ""
-
 #: lvcreate.c:146
 #, c-format
 msgid "Logical volume name \"%s\" is invalid"
 msgstr ""
 
-#: lvcreate.c:159 lvresize.c:63
+#: lvcreate.c:159 lvresize.c:64
 msgid "Please specify either size or extents (not both)"
 msgstr ""
 
@@ -3329,7 +3562,7 @@
 msgid "Ignoring stripesize argument with single stripe"
 msgstr ""
 
-#: lvcreate.c:206 lvresize.c:279
+#: lvcreate.c:206 lvresize.c:287
 #, c-format
 msgid "Using default stripesize %dKB"
 msgstr ""
@@ -3349,215 +3582,246 @@
 msgid "Invalid stripe size %d"
 msgstr ""
 
-#: lvcreate.c:247
+#: lvcreate.c:238
+#, c-format
+msgid "Too few physical volumes on command line for %d-way mirroring"
+msgstr ""
+
+#: lvcreate.c:245
+msgid "Negative regionsize is invalid"
+msgstr ""
+
+#: lvcreate.c:255
+#, c-format
+msgid "Region size (%u) must be a power of 2"
+msgstr ""
+
+#: lvcreate.c:279
 msgid "Redundant stripes argument: default is 1"
 msgstr ""
 
-#: lvcreate.c:254
+#: lvcreate.c:293
+msgid "Redundant mirrors argument: default is 0"
+msgstr ""
+
+#: lvcreate.c:298
 msgid "-Z is incompatible with snapshots"
 msgstr ""
 
-#: lvcreate.c:258
+#: lvcreate.c:302
 msgid "Negative chunk size is invalid"
 msgstr ""
 
-#: lvcreate.c:262
+#: lvcreate.c:306
 #, c-format
 msgid "Setting chunksize to %d sectors."
 msgstr ""
 
-#: lvcreate.c:270
+#: lvcreate.c:314
 msgid "-c is only available with snapshots"
 msgstr ""
 
-#: lvcreate.c:277 metadata/mirror.c:54
+#: lvcreate.c:321
+msgid "mirrors and snapshots are currently incompatible"
+msgstr ""
+
+#: lvcreate.c:327
+msgid "mirrors and stripes are currently incompatible"
+msgstr ""
+
+#: lvcreate.c:340 metadata/mirror.c:190
 #, c-format
 msgid "%s: Required device-mapper target(s) not detected in your kernel"
 msgstr ""
 
-#: lvcreate.c:302
+#: lvcreate.c:368
 msgid "Conflicting contiguous and alloc arguments"
 msgstr ""
 
-#: lvcreate.c:327
+#: lvcreate.c:393
 msgid "Please specify minor number with --minor when using -My"
 msgstr ""
 
-#: lvcreate.c:332
+#: lvcreate.c:398
 msgid "Please specify major number with --major when using -My"
 msgstr ""
 
-#: lvcreate.c:338
+#: lvcreate.c:404
 msgid "--major and --minor incompatible with -Mn"
 msgstr ""
 
-#: lvcreate.c:367
+#: lvcreate.c:433
 msgid "Name allocation failed - device not zeroed"
 msgstr ""
 
-#: lvcreate.c:373
+#: lvcreate.c:439
 #, c-format
 msgid "Name too long - device not zeroed (%s)"
 msgstr ""
 
-#: lvcreate.c:377
+#: lvcreate.c:443
 #, c-format
 msgid "Zeroing start of logical volume \"%s\""
 msgstr ""
 
-#: lvcreate.c:380
+#: lvcreate.c:446
 #, c-format
 msgid "%s: not found: device not zeroed"
 msgstr ""
 
-#: lvcreate.c:407 pvmove.c:291 toollib.c:325 vgreduce.c:258
+#: lvcreate.c:477 pvmove.c:292 toollib.c:350 vgreduce.c:263
 #, c-format
 msgid "Finding volume group \"%s\""
 msgstr ""
 
-#: lvcreate.c:410 lvrename.c:112 pvmove.c:66 vgdisplay.c:24 vgmerge.c:38
-#: vgmerge.c:64 vgreduce.c:266 vgrename.c:73 vgsplit.c:178
+#: lvcreate.c:495 lvrename.c:125
 #, c-format
-msgid "Volume group \"%s\" doesn't exist"
-msgstr ""
-
-#: lvcreate.c:415 lvrename.c:117 metadata/metadata.c:812 polldaemon.c:192
-#: pvchange.c:69 pvmove.c:72 toollib.c:42 vgchange.c:312 vgck.c:32
-#: vgconvert.c:54 vgextend.c:57 vgmerge.c:44 vgmerge.c:69 vgreduce.c:316
-#: vgremove.c:35 vgrename.c:80 vgsplit.c:184
-#, c-format
-msgid "Volume group \"%s\" is exported"
-msgstr ""
-
-#: lvcreate.c:420 lvremove.c:27 lvrename.c:122 pvchange.c:75 pvmove.c:78
-#: vgchange.c:307 vgconvert.c:49 vgexport.c:38 vgextend.c:62 vgmerge.c:50
-#: vgmerge.c:74 vgreduce.c:322 vgrename.c:86 vgsplit.c:190
-#, c-format
-msgid "Volume group \"%s\" is read-only"
+msgid "Logical volume \"%s\" already exists in volume group \"%s\""
 msgstr ""
 
-#: lvcreate.c:425 lvrename.c:127
-#, c-format
-msgid "Logical volume \"%s\" already exists in volume group \"%s\""
+#: lvcreate.c:501
+msgid "Metadata does not support mirroring."
 msgstr ""
 
-#: lvcreate.c:443
+#: lvcreate.c:518
 #, c-format
 msgid "Setting stripe size %d KB to physical extent size %u KB"
 msgstr ""
 
-#: lvcreate.c:456 lvresize.c:198
+#: lvcreate.c:531 lvresize.c:206
 #, c-format
 msgid "Rounding up size to full physical extent %s"
 msgstr ""
 
-#: lvcreate.c:464
+#: lvcreate.c:539
 #, c-format
 msgid "Rounding size (%d extents) up to stripe boundary size (%d extents)"
 msgstr ""
 
-#: lvcreate.c:472
+#: lvcreate.c:547
 msgid "Can't create snapshot without using device-mapper kernel driver"
 msgstr ""
 
-#: lvcreate.c:477
+#: lvcreate.c:552
 #, c-format
 msgid "Couldn't find origin volume '%s'."
 msgstr ""
 
-#: lvcreate.c:482
+#: lvcreate.c:557
 msgid "Snapshots of snapshots are not supported yet."
 msgstr ""
 
-#: lvcreate.c:487
+#: lvcreate.c:562
 msgid "Snapshots of locked devices are not supported yet"
 msgstr ""
 
-#: lvcreate.c:496
+#: lvcreate.c:571
 #, c-format
 msgid "Unable to create logical volume %s with no extents"
 msgstr ""
 
-#: lvcreate.c:503
+#: lvcreate.c:578
 #, c-format
 msgid "Insufficient free extents (%u) in volume group %s: %u required"
 msgstr ""
 
-#: lvcreate.c:509
+#: lvcreate.c:584
 #, c-format
 msgid "Number of stripes (%u) must not exceed number of physical volumes (%d)"
 msgstr ""
 
-#: lvcreate.c:528
-msgid "Setting read ahead sectors"
+#: lvcreate.c:591
+msgid "Can't create mirror without using device-mapper kernel driver."
 msgstr ""
 
-#: lvcreate.c:536
-#, c-format
+#: lvcreate.c:610
+msgid "Failed to generate LV name."
+msgstr ""
+
+#: lvcreate.c:622 mirror/mirrored.c:218
+#, c-format
+msgid "Using reduced mirror region size of %u sectors"
+msgstr ""
+
+#: lvcreate.c:630 lvcreate.c:636 lvcreate.c:644
+msgid "log_name allocation failed. Remove new LV and retry."
+msgstr ""
+
+#: lvcreate.c:683
+msgid "Aborting. Failed to activate mirror log. Remove new LVs and retry."
+msgstr ""
+
+#: lvcreate.c:689
+msgid "Aborting. Failed to wipe mirror log. Remove new LV and retry."
+msgstr ""
+
+#: lvcreate.c:695
+msgid "Aborting. Failed to deactivate mirror log. Remove new LV and retry."
+msgstr ""
+
+#: lvcreate.c:710
+msgid "Setting read ahead sectors"
+msgstr ""
+
+#: lvcreate.c:718
+#, c-format
 msgid "Setting device number to (%d, %d)"
 msgstr ""
 
-#: lvcreate.c:547 vgchange.c:224
+#: lvcreate.c:729 vgchange.c:327
 #, c-format
 msgid "Volume group %s does not support tags"
 msgstr ""
 
-#: lvcreate.c:578
+#: lvcreate.c:773
 msgid ""
 "Aborting. Failed to activate snapshot exception store. Remove new LV and "
 "retry."
 msgstr ""
 
-#: lvcreate.c:581
+#: lvcreate.c:776
 msgid "Failed to activate new LV."
 msgstr ""
 
-#: lvcreate.c:588
+#: lvcreate.c:783
 msgid ""
 "Aborting. Failed to wipe snapshot exception store. Remove new LV and retry."
 msgstr ""
 
-#: lvcreate.c:593
+#: lvcreate.c:788
 #, c-format
 msgid "WARNING: \"%s\" not zeroed"
 msgstr ""
 
-#: lvcreate.c:602
+#: lvcreate.c:797
 msgid "Couldn't deactivate new snapshot."
 msgstr ""
 
-#: lvcreate.c:608
+#: lvcreate.c:803
 #, c-format
 msgid "Failed to suspend origin %s"
 msgstr ""
 
-#: lvcreate.c:614
+#: lvcreate.c:809
 msgid "Couldn't create snapshot."
 msgstr ""
 
-#: lvcreate.c:623
+#: lvcreate.c:818
 #, c-format
 msgid "Problem reactivating origin %s"
 msgstr ""
 
-#: lvcreate.c:630
+#: lvcreate.c:825
 #, c-format
 msgid "Logical volume \"%s\" created"
 msgstr ""
 
-#: lvcreate.c:651 lvrename.c:107 lvresize.c:509 pvchange.c:56 pvmove.c:61
-#: vgcreate.c:139 vgextend.c:47 vgmerge.c:33 vgmerge.c:57 vgreduce.c:260
-#: vgrename.c:68 vgrename.c:102 vgsplit.c:173 vgsplit.c:197
-#, c-format
-msgid "Can't get lock for %s"
-msgstr ""
-
-#: lvdisplay.c:36 lvdisplay.c:45 pvdisplay.c:62 pvdisplay.c:71 vgdisplay.c:65
-#: vgdisplay.c:74
+#: lvdisplay.c:39 lvdisplay.c:48 pvdisplay.c:62 pvdisplay.c:72 vgdisplay.c:67
+#: vgdisplay.c:76
 msgid "Incompatible options selected"
 msgstr ""
 
-#: lvdisplay.c:50
+#: lvdisplay.c:53
 msgid "Options -v and -c are incompatible"
 msgstr ""
 
@@ -3644,109 +3908,91 @@
 msgid "%-16.16s%s"
 msgstr ""
 
-#: lvmcmdline.c:798
+#: lvmcmdline.c:799
 msgid "Couldn't copy command line."
 msgstr ""
 
-#: lvmcmdline.c:811
+#: lvmcmdline.c:812
 #, c-format
 msgid "Parsing: %s"
 msgstr ""
 
-#: lvmcmdline.c:817
+#: lvmcmdline.c:818
 msgid "Error during parsing of command line."
 msgstr ""
 
-#: lvmcmdline.c:826
+#: lvmcmdline.c:827
 msgid "Updated config file invalid. Aborting."
 msgstr ""
 
-#: lvmcmdline.c:835
+#: lvmcmdline.c:836
 #, c-format
 msgid "Processing: %s"
 msgstr ""
 
-#: lvmcmdline.c:838
+#: lvmcmdline.c:839
 msgid "O_DIRECT will be used"
 msgstr ""
 
-#: lvmcmdline.c:851
+#: lvmcmdline.c:852
 #, c-format
 msgid "Locking type %d initialisation failed."
 msgstr ""
 
-#: lvmcmdline.c:863
+#: lvmcmdline.c:864
 msgid "Test mode: Wiping internal cache"
 msgstr ""
 
-#: lvmcmdline.c:921
-msgid "WARNING: Metadata changes will NOT be backed up"
-msgstr ""
-
-#: lvmcmdline.c:941
-#, c-format
-msgid "Couldn't create default archive path '%s/%s'."
-msgstr ""
-
-#: lvmcmdline.c:950 lvmcmdline.c:970
-msgid "backup_init failed."
-msgstr ""
-
-#: lvmcmdline.c:962
-#, c-format
-msgid "Couldn't create default backup path '%s/%s'."
-msgstr ""
-
-#: lvmcmdline.c:1058
+#: lvmcmdline.c:994
 #, c-format
 msgid "Line too long (max 255) beginning: %s"
 msgstr ""
 
-#: lvmcmdline.c:1065
+#: lvmcmdline.c:1001
 #, c-format
 msgid "Too many arguments: %s"
 msgstr ""
 
-#: lvmcmdline.c:1197
+#: lvmcmdline.c:1133
 msgid "$HOME/.lvm_history: path too long"
 msgstr ""
 
-#: lvmcmdline.c:1212
+#: lvmcmdline.c:1148
 #, c-format
 msgid "Couldn't read history from %s."
 msgstr ""
 
-#: lvmcmdline.c:1227
+#: lvmcmdline.c:1163
 #, c-format
 msgid "Couldn't write history to %s."
 msgstr ""
 
-#: lvmcmdline.c:1260
+#: lvmcmdline.c:1196
 msgid "Too many arguments, sorry."
 msgstr ""
 
-#: lvmcmdline.c:1274
+#: lvmcmdline.c:1210
 msgid "Exiting."
 msgstr ""
 
-#: lvmcmdline.c:1280
+#: lvmcmdline.c:1216
 #, c-format
 msgid "No such command '%s'.  Try 'help'."
 msgstr ""
 
-#: lvmcmdline.c:1406
+#: lvmcmdline.c:1342
 msgid "Failed to create LVM1 tool pathname"
 msgstr ""
 
-#: lvmcmdline.c:1443
+#: lvmcmdline.c:1390
 msgid "Falling back to LVM1 tools, but no command specified."
 msgstr ""
 
-#: lvmcmdline.c:1459
+#: lvmcmdline.c:1406
 msgid "Please supply an LVM command."
 msgstr ""
 
-#: lvmcmdline.c:1473
+#: lvmcmdline.c:1420
 msgid "No such command.  Try 'help'."
 msgstr ""
 
@@ -3800,45 +4046,55 @@
 
 #: lvremove.c:38
 #, c-format
+msgid "Can't remove logical volume %s used by a mirror"
+msgstr ""
+
+#: lvremove.c:44
+#, c-format
+msgid "Can't remove logical volume %s used as mirror log"
+msgstr ""
+
+#: lvremove.c:50
+#, c-format
 msgid "Can't remove locked LV %s"
 msgstr ""
 
-#: lvremove.c:46
+#: lvremove.c:58
 #, c-format
 msgid "Can't remove open logical volume \"%s\""
 msgstr ""
 
-#: lvremove.c:55
+#: lvremove.c:67
 #, c-format
 msgid "Logical volume \"%s\" not removed"
 msgstr ""
 
-#: lvremove.c:66
+#: lvremove.c:78
 #, c-format
 msgid "Unable to deactivate logical volume \"%s\""
 msgstr ""
 
-#: lvremove.c:72
+#: lvremove.c:84
 #, c-format
 msgid "Removing snapshot %s"
 msgstr ""
 
-#: lvremove.c:79
+#: lvremove.c:91
 #, c-format
 msgid "Releasing logical volume \"%s\""
 msgstr ""
 
-#: lvremove.c:81
+#: lvremove.c:93
 #, c-format
 msgid "Error releasing logical volume \"%s\""
 msgstr ""
 
-#: lvremove.c:94
+#: lvremove.c:106
 #, c-format
 msgid "Logical volume \"%s\" successfully removed"
 msgstr ""
 
-#: lvremove.c:101
+#: lvremove.c:113
 msgid "Please enter one or more logical volume paths"
 msgstr ""
 
@@ -3851,10 +4107,6 @@
 msgid "Old and new logical volume names required"
 msgstr ""
 
-#: lvrename.c:54
-msgid "Please provide a valid volume group name"
-msgstr ""
-
 #: lvrename.c:61
 #, c-format
 msgid "Logical volume names must have the same volume group (\"%s\" or \"%s\")"
@@ -3862,203 +4114,224 @@
 
 #: lvrename.c:76
 #, c-format
-msgid "New logical volume path exceeds maximum length of %Zu!"
+msgid "New logical volume path exceeds maximum length of %zu!"
 msgstr ""
 
 #: lvrename.c:82
 msgid "New logical volume name may not be blank"
 msgstr ""
 
-#: lvrename.c:94
+#: lvrename.c:92
 #, c-format
 msgid "New logical volume name \"%s\" is invalid"
 msgstr ""
 
-#: lvrename.c:100
+#: lvrename.c:98
 msgid "Old and new logical volume names must differ"
 msgstr ""
 
-#: lvrename.c:104 vgrename.c:65
-#, c-format
-msgid "Checking for existing volume group \"%s\""
-msgstr ""
-
-#: lvrename.c:133
+#: lvrename.c:131
 #, c-format
 msgid "Existing logical volume \"%s\" not found in volume group \"%s\""
 msgstr ""
 
-#: lvrename.c:141
+#: lvrename.c:139
 #, c-format
 msgid "Cannot rename locked LV %s"
 msgstr ""
 
-#: lvrename.c:151
+#: lvrename.c:149
 msgid "Failed to allocate space for new name"
 msgstr ""
 
-#: lvrename.c:155 vgmerge.c:163 vgrename.c:134
+#: lvrename.c:153 vgmerge.c:190 vgrename.c:134
 msgid "Writing out updated volume group"
 msgstr ""
 
-#: lvrename.c:178
+#: lvrename.c:176
 #, c-format
 msgid "Renamed \"%s\" to \"%s\" in volume group \"%s\""
 msgstr ""
 
-#: lvresize.c:79
+#: lvresize.c:80
 msgid "Negative argument not permitted - use lvreduce"
 msgstr ""
 
-#: lvresize.c:84
+#: lvresize.c:85
 msgid "Positive sign not permitted - use lvextend"
 msgstr ""
 
-#: lvresize.c:92
+#: lvresize.c:93
 msgid "Please provide the logical volume name"
 msgstr ""
 
-#: lvresize.c:136
+#: lvresize.c:138
 #, c-format
 msgid "Volume group %s doesn't exist"
 msgstr ""
 
-#: lvresize.c:141
+#: lvresize.c:143
 #, c-format
 msgid "Volume group %s is exported"
 msgstr ""
 
-#: lvresize.c:146
+#: lvresize.c:148
 #, c-format
 msgid "Volume group %s is read-only"
 msgstr ""
 
-#: lvresize.c:152
+#: lvresize.c:154
 #, c-format
 msgid "Logical volume %s not found in volume group %s"
 msgstr ""
 
-#: lvresize.c:161
+#: lvresize.c:163
 msgid "Varied striping not supported. Ignoring."
 msgstr ""
 
-#: lvresize.c:166
+#: lvresize.c:170
+msgid "Mirrors not supported. Ignoring."
+msgstr ""
+
+#: lvresize.c:175
 msgid "Stripesize may not be negative."
 msgstr ""
 
-#: lvresize.c:173
+#: lvresize.c:182
 msgid "Varied stripesize not supported. Ignoring."
 msgstr ""
 
-#: lvresize.c:179
-#, c-format
-msgid "Can't resize locked LV %s"
+#: lvresize.c:184
+msgid "Mirrors and striping cannot be combined yet."
 msgstr ""
 
-#: lvresize.c:184
-msgid "Snapshot origin volumes cannot be resized yet."
+#: lvresize.c:192
+#, c-format
+msgid "Can't resize locked LV %s"
 msgstr ""
 
-#: lvresize.c:211
+#: lvresize.c:219
 #, c-format
 msgid "Unable to reduce %s below 1 extent"
 msgstr ""
 
-#: lvresize.c:220
+#: lvresize.c:228
 msgid "New size of 0 not permitted"
 msgstr ""
 
-#: lvresize.c:225 lvresize.c:330
+#: lvresize.c:233 lvresize.c:365
 #, c-format
 msgid "New size (%d extents) matches existing size (%d extents)"
 msgstr ""
 
-#: lvresize.c:240
+#: lvresize.c:248
 #, c-format
 msgid "VolumeType does not match (%s)"
 msgstr ""
 
-#: lvresize.c:257
+#: lvresize.c:265
 msgid "Please specify number of stripes (-i) and stripesize (-I)"
 msgstr ""
 
-#: lvresize.c:271
+#: lvresize.c:279
 #, c-format
 msgid "Using stripesize of last segment %dKB"
 msgstr ""
 
-#: lvresize.c:290
-msgid "Ignoring stripes and stripesize arguments when reducing"
+#: lvresize.c:303
+#, c-format
+msgid "Extending %u mirror images."
 msgstr ""
 
-#: lvresize.c:313
+#: lvresize.c:309
+msgid "Cannot vary number of mirrors in LV yet."
+msgstr ""
+
+#: lvresize.c:319
+msgid "Ignoring stripes, stripesize and mirrors arguments when reducing"
+msgstr ""
+
+#: lvresize.c:348
 msgid "Stripesize for striped segment should not be 0!"
 msgstr ""
 
-#: lvresize.c:322
+#: lvresize.c:357
 #, c-format
 msgid ""
 "Rounding size (%d extents) down to stripe boundary size for segment (%d "
 "extents)"
 msgstr ""
 
-#: lvresize.c:337
+#: lvresize.c:372
 #, c-format
 msgid "New size given (%d extents) not larger than existing size (%d extents)"
 msgstr ""
 
-#: lvresize.c:347
+#: lvresize.c:382
 #, c-format
 msgid "New size given (%d extents) not less than existing size (%d extents)"
 msgstr ""
 
-#: lvresize.c:357
+#: lvresize.c:392
+msgid "Mirrors cannot be resized while active yet."
+msgstr ""
+
+#: lvresize.c:398
+msgid "Snapshot origin volumes cannot be reduced in size yet."
+msgstr ""
+
+#: lvresize.c:406
+msgid ""
+"Snapshot origin volumes can be resized only while inactive: try lvchange -an"
+msgstr ""
+
+#: lvresize.c:414
 msgid "Ignoring PVs on command line when reducing"
 msgstr ""
 
-#: lvresize.c:368
+#: lvresize.c:425
 msgid "lv_info failed: aborting"
 msgstr ""
 
-#: lvresize.c:373
+#: lvresize.c:430
 #, c-format
 msgid "Logical volume %s must be activated before resizing filesystem"
 msgstr ""
 
-#: lvresize.c:379
+#: lvresize.c:436
 #, c-format
 msgid "WARNING: Reducing active%s logical volume to %s"
 msgstr ""
 
-#: lvresize.c:385
+#: lvresize.c:442
 msgid "THIS MAY DESTROY YOUR DATA (filesystem etc.)"
 msgstr ""
 
-#: lvresize.c:392
+#: lvresize.c:449
 #, c-format
 msgid "Logical volume %s NOT reduced"
 msgstr ""
 
-#: lvresize.c:403
+#: lvresize.c:460
 #, c-format
 msgid "Couldn't create LV path for %s"
 msgstr ""
 
-#: lvresize.c:411
+#: lvresize.c:468
 msgid "Couldn't generate new LV size string"
 msgstr ""
 
-#: lvresize.c:435
+#: lvresize.c:492
 #, c-format
 msgid "%sing logical volume %s to %s"
 msgstr ""
 
-#: lvresize.c:485
+#: lvresize.c:542
 #, c-format
 msgid "Logical volume %s successfully resized"
 msgstr ""
 
-#: lvresize.c:507
+#: lvresize.c:564
 #, c-format
 msgid "Finding volume group %s"
 msgstr ""
@@ -4072,514 +4345,718 @@
 msgid "No additional command line arguments allowed"
 msgstr ""
 
-#: metadata/lv_manip.c:102
-msgid "Couldn't allocate new parallel segment."
+#: metadata/lv_manip.c:78
+msgid "alloc_lv_segment: Missing segtype."
 msgstr ""
 
-#: metadata/lv_manip.c:159
-msgid "striped mirrors are not supported yet"
+#: metadata/lv_manip.c:110
+msgid "Failed to find snapshot segtype"
 msgstr ""
 
-#: metadata/lv_manip.c:174
-msgid "Couldn't allocate areas array."
+#: metadata/lv_manip.c:118
+msgid "Couldn't allocate new snapshot segment."
 msgstr ""
 
-#: metadata/lv_manip.c:191
+#: metadata/lv_manip.c:169
 #, c-format
-msgid ""
-"Insufficient allocatable extents suitable for parallel use for logical "
-"volume %s: %u required"
+msgid "Segment extent reduction %unot divisible by #stripes %u"
 msgstr ""
 
-#: metadata/lv_manip.c:231
-msgid "Couldn't allocate new stripe segment."
+#: metadata/lv_manip.c:303
+msgid "Striped mirrors are not supported yet"
 msgstr ""
 
-#: metadata/lv_manip.c:270
-msgid "Couldn't allocate new mirrored segment."
+#: metadata/lv_manip.c:308
+msgid "Can't mix striping or mirroring with creation of a mirrored PV yet"
 msgstr ""
 
-#: metadata/lv_manip.c:332
-#, c-format
-msgid ""
-"Insufficient allocatable extents (%u) for logical volume %s: %u required"
+#: metadata/lv_manip.c:314
+msgid "Can't mix striping or pvmove with a mirror log yet."
 msgstr ""
 
-#: metadata/lv_manip.c:377
-#, c-format
-msgid ""
-"Insufficient contiguous allocatable extents (%u) for logical volume %s: %u "
-"required"
+#: metadata/lv_manip.c:329
+msgid "allocation handle allocation failed"
+msgstr ""
+
+#: metadata/lv_manip.c:337
+msgid "allocation pool creation failed"
+msgstr ""
+
+#: metadata/lv_manip.c:384
+msgid "Couldn't allocate new LV segment."
+msgstr ""
+
+#: metadata/lv_manip.c:466
+msgid "alloced_area allocation failed"
+msgstr ""
+
+#: metadata/lv_manip.c:678
+msgid "_allocate called with no work to do!"
 msgstr ""
 
-#: metadata/lv_manip.c:410
+#: metadata/lv_manip.c:699
+msgid "Not enough PVs with free space available for parallel allocation."
+msgstr ""
+
+#: metadata/lv_manip.c:701
+msgid "Consider --alloc anywhere if desperate."
+msgstr ""
+
+#: metadata/lv_manip.c:709
+msgid "Couldn't allocate areas array."
+msgstr ""
+
+#: metadata/lv_manip.c:746
 #, c-format
 msgid ""
-"Insufficient allocatable logical extents (%u) for logical volume %s: %u "
+"Insufficient suitable %sallocatable extents for logical volume %s: %u more "
 "required"
 msgstr ""
 
-#: metadata/lv_manip.c:425
+#: metadata/lv_manip.c:770
 msgid "Couldn't allocate new zero segment."
 msgstr ""
 
-#: metadata/lv_manip.c:490
-msgid "Unrecognised allocation policy: unable to set up logical volume."
+#: metadata/lv_manip.c:802
+msgid "allocate_extents does not handle virtual segments"
+msgstr ""
+
+#: metadata/lv_manip.c:808
+#, c-format
+msgid "Metadata format (%s) does not support required LV segment type (%s)."
+msgstr ""
+
+#: metadata/lv_manip.c:811
+msgid "Consider changing the metadata format by running vgconvert."
+msgstr ""
+
+#: metadata/lv_manip.c:852
+msgid "Missing segtype in lv_add_segment()."
+msgstr ""
+
+#: metadata/lv_manip.c:857
+msgid "lv_add_segment cannot handle virtual segments"
+msgstr ""
+
+#: metadata/lv_manip.c:871
+msgid "Couldn't merge segments after extending logical volume."
+msgstr ""
+
+#: metadata/lv_manip.c:893
+msgid "Log segments can only be added to an empty LV"
+msgstr ""
+
+#: metadata/lv_manip.c:902
+msgid "Couldn't allocate new mirror log segment."
+msgstr ""
+
+#: metadata/lv_manip.c:942
+#, c-format
+msgid "Log LV %s is empty."
+msgstr ""
+
+#: metadata/lv_manip.c:952
+msgid "Couldn't allocate new mirror segment."
 msgstr ""
 
-#: metadata/lv_manip.c:556
+#: metadata/lv_manip.c:1013
+#, c-format
+msgid "Aborting. Failed to extend %s."
+msgstr ""
+
+#: metadata/lv_manip.c:1066
 #, c-format
 msgid "Maximum number of logical volumes (%u) reached in volume group %s"
 msgstr ""
 
-#: metadata/lv_manip.c:563
+#: metadata/lv_manip.c:1073
 msgid "Failed to generate unique name for the new logical volume"
 msgstr ""
 
-#: metadata/lv_manip.c:568
+#: metadata/lv_manip.c:1079
 #, c-format
 msgid "Creating logical volume %s"
 msgstr ""
 
-#: metadata/lv_manip.c:572
+#: metadata/lv_manip.c:1083
 msgid "lv_list allocation failed"
 msgstr ""
 
-#: metadata/lv_manip.c:582
+#: metadata/lv_manip.c:1093
 msgid "lv name strdup failed"
 msgstr ""
 
-#: metadata/lv_manip.c:628
+#: metadata/merge.c:72
 #, c-format
-msgid "Metadata format (%s) does not support required LV segment type (%s)."
+msgid "LV %s invalid: segment %u should begin at LE %u (found %u)."
 msgstr ""
 
-#: metadata/lv_manip.c:631
-msgid "Consider changing the metadata format by running vgconvert."
+#: metadata/merge.c:82
+#, c-format
+msgid "LV %s: segment %u has inconsistent area_len %u"
 msgstr ""
 
-#: metadata/lv_manip.c:646
-msgid "Couldn't merge segments after extending logical volume."
+#: metadata/merge.c:93
+#, c-format
+msgid "LV %s: segment %u has inconsistent PV area %u"
 msgstr ""
 
-#: metadata/lv_manip.c:683
+#: metadata/merge.c:102
 #, c-format
-msgid "Segment extent reduction %unot divisible by #stripes %u"
+msgid "LV %s: segment %u has inconsistent LV area %u"
 msgstr ""
 
-#: metadata/merge.c:69
+#: metadata/merge.c:108
 #, c-format
-msgid "LV %s invalid: segment %u should begin at LE %u (found %u)."
+msgid "LV %s: segment %u has inconsistent LV area %u size"
 msgstr ""
 
-#: metadata/merge.c:95
+#: metadata/merge.c:121
+#, c-format
+msgid "LV %s: inconsistent LE count %u != %u"
+msgstr ""
+
+#: metadata/merge.c:142
 #, c-format
 msgid "Unable to split the %s segment at LE %u in LV %s"
 msgstr ""
 
-#: metadata/merge.c:102
-msgid "Couldn't allocate new LV segment."
+#: metadata/merge.c:155
+msgid "Couldn't allocate cloned LV segment."
 msgstr ""
 
-#: metadata/merge.c:110
+#: metadata/merge.c:160
 msgid "LV segment tags duplication failed"
 msgstr ""
 
-#: metadata/merge.c:126
+#: metadata/merge.c:187
 #, c-format
 msgid "Split %s:%u[%u] at %u: %s LE %u"
 msgstr ""
 
-#: metadata/merge.c:134
+#: metadata/merge.c:202
 #, c-format
 msgid "Split %s:%u[%u] at %u: %s PE %u"
 msgstr ""
 
-#: metadata/merge.c:141
+#: metadata/merge.c:209 metadata/metadata.c:469
 #, c-format
 msgid "Unrecognised segment type %u"
 msgstr ""
 
-#: metadata/merge.c:169
+#: metadata/merge.c:229
 #, c-format
 msgid "Segment with extent %u in LV %s not found"
 msgstr ""
 
-#: metadata/metadata.c:33
+#: metadata/metadata.c:35
 #, c-format
 msgid "Adding physical volume '%s' to volume group '%s'"
 msgstr ""
 
-#: metadata/metadata.c:37
+#: metadata/metadata.c:39
 #, c-format
 msgid "pv_list allocation for '%s' failed"
 msgstr ""
 
-#: metadata/metadata.c:43
+#: metadata/metadata.c:45
 #, c-format
 msgid "%s not identified as an existing physical volume"
 msgstr ""
 
-#: metadata/metadata.c:49
+#: metadata/metadata.c:51
 #, c-format
 msgid "Physical volume '%s' is already in volume group '%s'"
 msgstr ""
 
-#: metadata/metadata.c:55
+#: metadata/metadata.c:57
 #, c-format
 msgid "Physical volume %s is of different format type (%s)"
 msgstr ""
 
-#: metadata/metadata.c:61 metadata/metadata.c:120
+#: metadata/metadata.c:63 metadata/metadata.c:175
 #, c-format
 msgid "vg->name allocation failed for '%s'"
 msgstr ""
 
-#: metadata/metadata.c:84
+#: metadata/metadata.c:86
 #, c-format
 msgid "Format-specific setup of physical volume '%s' failed."
 msgstr ""
 
-#: metadata/metadata.c:90
+#: metadata/metadata.c:92
 #, c-format
 msgid "Physical volume '%s' listed more than once."
 msgstr ""
 
-#: metadata/metadata.c:96
+#: metadata/metadata.c:98
 #, c-format
 msgid "No space for '%s' - volume group '%s' holds max %d physical volume(s)."
 msgstr ""
 
-#: metadata/metadata.c:127
+#: metadata/metadata.c:125
+msgid "PV tags duplication failed"
+msgstr ""
+
+#: metadata/metadata.c:146
+#, c-format
+msgid "get_pv_from_vg_by_id: vg_read failed to read VG %s"
+msgstr ""
+
+#: metadata/metadata.c:152
+#, c-format
+msgid "Warning: Volume group %s is not consistent"
+msgstr ""
+
+#: metadata/metadata.c:181
 #, c-format
 msgid "pv->vg_name allocation failed for '%s'"
 msgstr ""
 
-#: metadata/metadata.c:144
+#: metadata/metadata.c:198
 #, c-format
 msgid "Unable to add physical volume '%s' to volume group '%s'."
 msgstr ""
 
-#: metadata/metadata.c:182
+#: metadata/metadata.c:236
 #, c-format
 msgid "A volume group called '%s' already exists."
 msgstr ""
 
-#: metadata/metadata.c:188
+#: metadata/metadata.c:242
 #, c-format
 msgid "Couldn't create uuid for volume group '%s'."
 msgstr ""
 
-#: metadata/metadata.c:230 metadata/metadata.c:667
+#: metadata/metadata.c:283 metadata/metadata.c:923 metadata/metadata.c:966
 msgid "Failed to create format instance"
 msgstr ""
 
-#: metadata/metadata.c:236
+#: metadata/metadata.c:289
 #, c-format
 msgid "Format specific setup of volume group '%s' failed."
 msgstr ""
 
-#: metadata/metadata.c:273
+#: metadata/metadata.c:312
+#, c-format
+msgid "New size %llu for %s%s not an exact number of new extents."
+msgstr ""
+
+#: metadata/metadata.c:320
+#, c-format
+msgid "New extent count %llu for %s%s exceeds 32 bits."
+msgstr ""
+
+#: metadata/metadata.c:502
 #, c-format
 msgid "Failed to create random uuid for %s."
 msgstr ""
 
-#: metadata/metadata.c:288
+#: metadata/metadata.c:517 vgreduce.c:196 vgremove.c:62
 #, c-format
 msgid "%s: Couldn't get size."
 msgstr ""
 
-#: metadata/metadata.c:294
+#: metadata/metadata.c:523
 #, c-format
 msgid "WARNING: %s: Overriding real size. You could lose data."
 msgstr ""
 
-#: metadata/metadata.c:296
+#: metadata/metadata.c:525
 #, c-format
 msgid "%s: Pretending size is %llu sectors."
 msgstr ""
 
-#: metadata/metadata.c:302
+#: metadata/metadata.c:531
 #, c-format
 msgid "%s: Size must exceed minimum of %ld sectors."
 msgstr ""
 
-#: metadata/metadata.c:319
+#: metadata/metadata.c:549
 #, c-format
 msgid "%s: Format-specific setup of physical volume failed."
 msgstr ""
 
-#: metadata/metadata.c:433
+#: metadata/metadata.c:647
 #, c-format
 msgid "Physical volume %s not found"
 msgstr ""
 
-#: metadata/metadata.c:438
+#: metadata/metadata.c:652
 #, c-format
 msgid "Physical volume %s not in a volume group"
 msgstr ""
 
-#: metadata/metadata.c:489
+#: metadata/metadata.c:711
+#, c-format
+msgid "Internal error: PV segments corrupted in %s."
+msgstr ""
+
+#: metadata/metadata.c:718
+#, c-format
+msgid "Internal error: LV segments corrupted in %s."
+msgstr ""
+
+#: metadata/metadata.c:725
 #, c-format
 msgid "Cannot change metadata for partial volume group %s"
 msgstr ""
 
-#: metadata/metadata.c:495
+#: metadata/metadata.c:731
 msgid "Aborting vg_write: No metadata areas to write to!"
 msgstr ""
 
-#: metadata/metadata.c:505
+#: metadata/metadata.c:740
 msgid "Format does not support writing volumegroup metadata areas"
 msgstr ""
 
-#: metadata/metadata.c:596
+#: metadata/metadata.c:843
 msgid "vg allocation failed"
 msgstr ""
 
-#: metadata/metadata.c:605
+#: metadata/metadata.c:851
 msgid "vg name allocation failed"
 msgstr ""
 
-#: metadata/metadata.c:615
+#: metadata/metadata.c:860
 msgid "pv_list allocation failed"
 msgstr ""
 
-#: metadata/metadata.c:705
+#: metadata/metadata.c:890
+msgid "Internal error: vg_read requires vgname with pre-commit."
+msgstr ""
+
+#: metadata/metadata.c:916 metadata/metadata.c:959
+#, c-format
+msgid "Internal error: %s doesn't support pre-commit"
+msgstr ""
+
+#: metadata/metadata.c:1003
+#, c-format
+msgid "Inconsistent pre-commit metadata copies for volume group %s"
+msgstr ""
+
+#: metadata/metadata.c:1014
 #, c-format
 msgid "Inconsistent metadata copies found for partial volume group %s"
 msgstr ""
 
-#: metadata/metadata.c:711
+#: metadata/metadata.c:1020
 #, c-format
 msgid "Inconsistent metadata copies found - updating to use version %u"
 msgstr ""
 
-#: metadata/metadata.c:714
+#: metadata/metadata.c:1023
 msgid "Automatic metadata correction failed"
 msgstr ""
 
-#: metadata/metadata.c:718
+#: metadata/metadata.c:1027
 msgid "Automatic metadata correction commit failed"
 msgstr ""
 
-#: metadata/metadata.c:725
+#: metadata/metadata.c:1034
 #, c-format
 msgid "WARNING: Interrupted pvmove detected in volume group %s"
 msgstr ""
 
-#: metadata/metadata.c:727
+#: metadata/metadata.c:1036
 msgid "Please restore the metadata by running vgcfgrestore."
 msgstr ""
 
-#: metadata/metadata.c:754 metadata/metadata.c:784
+#: metadata/metadata.c:1077 metadata/metadata.c:1107
 #, c-format
 msgid "Volume group %s metadata is inconsistent"
 msgstr ""
 
-#: metadata/metadata.c:772
+#: metadata/metadata.c:1095
 msgid "vg_read_by_vgid: get_vgs failed"
 msgstr ""
 
-#: metadata/metadata.c:804
+#: metadata/metadata.c:1127
 #, c-format
 msgid "Finding volume group for uuid %s"
 msgstr ""
 
-#: metadata/metadata.c:806
+#: metadata/metadata.c:1129
 #, c-format
 msgid "Volume group for uuid not found: %s"
 msgstr ""
 
-#: metadata/metadata.c:810
+#: metadata/metadata.c:1133
 #, c-format
 msgid "Found volume group \"%s\""
 msgstr ""
 
-#: metadata/metadata.c:816
+#: metadata/metadata.c:1139
 #, c-format
 msgid "Can't find logical volume id %s"
 msgstr ""
 
-#: metadata/metadata.c:840
+#: metadata/metadata.c:1163
 #, c-format
 msgid "No physical volume label read from %s"
 msgstr ""
 
-#: metadata/metadata.c:850
+#: metadata/metadata.c:1173
 #, c-format
 msgid "pv allocation for '%s' failed"
 msgstr ""
 
-#: metadata/metadata.c:858
+#: metadata/metadata.c:1182
 #, c-format
 msgid "Failed to read existing physical volume '%s'"
 msgstr ""
 
-#: metadata/metadata.c:889
+#: metadata/metadata.c:1219
 msgid "PV list allocation failed"
 msgstr ""
 
-#: metadata/metadata.c:897
+#: metadata/metadata.c:1227
 msgid "get_pvs: get_vgs failed"
 msgstr ""
 
-#: metadata/metadata.c:917
+#: metadata/metadata.c:1247
 #, c-format
 msgid "Warning: Volume Group %s is not consistent"
 msgstr ""
 
-#: metadata/metadata.c:935
+#: metadata/metadata.c:1265
 msgid "Format does not support writing physical volumes"
 msgstr ""
 
-#: metadata/metadata.c:940
+#: metadata/metadata.c:1270
 #, c-format
 msgid "Assertion failed: can't _pv_write non-orphan PV (in VG %s)"
 msgstr ""
 
-#: metadata/mirror.c:122
+#: metadata/mirror.c:111
+msgid "img_lvs allocation failed. Remove new LV and retry."
+msgstr ""
+
+#: metadata/mirror.c:118 metadata/mirror.c:124
+msgid "img_name allocation failed. Remove new LV and retry."
+msgstr ""
+
+#: metadata/mirror.c:132
+msgid "Aborting. Failed to create submirror LV. Remove new LV and retry."
+msgstr ""
+
+#: metadata/mirror.c:142
+#, c-format
+msgid ""
+"Aborting. Failed to add submirror segment to %s. Remove new LV and retry."
+msgstr ""
+
+#: metadata/mirror.c:151
+msgid "Aborting. Failed to add mirror segment. Remove new LV and retry."
+msgstr ""
+
+#: metadata/mirror.c:256
 #, c-format
 msgid "Matched PE range %u-%u against %s %u len %u"
 msgstr ""
 
-#: metadata/mirror.c:130 metadata/mirror.c:364
+#: metadata/mirror.c:265 metadata/mirror.c:491
 msgid "lv_list alloc failed"
 msgstr ""
 
-#: metadata/mirror.c:138
+#: metadata/mirror.c:273
 #, c-format
 msgid "Moving %s:%u-%u of %s/%s"
 msgstr ""
 
-#: metadata/mirror.c:152
+#: metadata/mirror.c:287
 msgid "Unable to allocate temporary LV for pvmove."
 msgstr ""
 
-#: metadata/mirror.c:169
+#: metadata/mirror.c:302
 #, c-format
 msgid "Moving %u extents of logical volume %s/%s"
 msgstr ""
 
-#: metadata/mirror.c:203
+#: metadata/mirror.c:334
 msgid "No segment found with LE"
 msgstr ""
 
-#: metadata/mirror.c:215
+#: metadata/mirror.c:345
 msgid "Incompatible segments"
 msgstr ""
 
-#: metadata/mirror.c:237
+#: metadata/mirror.c:370
 msgid "Missing striped segtype"
 msgstr ""
 
-#: metadata/mirror.c:344
+#: metadata/mirror.c:472
 msgid "lvs list alloc failed"
 msgstr ""
 
-#: metadata/pv_map.c:67
+#: metadata/pv_manip.c:31
+msgid "pv_segment allocation failed"
+msgstr ""
+
+#: metadata/pv_manip.c:117
 #, c-format
-msgid "Physical extent %d of %s referenced by more than one logical volume"
+msgid "Segment with extent %u in PV %s not found"
 msgstr ""
 
-#: metadata/pv_map.c:87
-msgid "Couldn't create hash table for pv maps."
+#: metadata/pv_manip.c:157
+#, c-format
+msgid "Missing PV segment on %s at %u."
 msgstr ""
 
-#: metadata/pv_map.c:176
+#: metadata/pv_manip.c:223
 #, c-format
-msgid "Allowing allocation on %s start PE %u length %u"
+msgid "%s %u: %6u %6u: %s(%u:%u)"
 msgstr ""
 
-#: metadata/pv_map.c:265
+#: metadata/pv_manip.c:229
 #, c-format
-msgid "Couldn't create physical volume maps in %s"
+msgid "Gap in pvsegs: %u, %u"
+msgstr ""
+
+#: metadata/pv_manip.c:235
+msgid "Wrong lvseg area type"
+msgstr ""
+
+#: metadata/pv_manip.c:239
+msgid "Inconsistent pvseg pointers"
 msgstr ""
 
-#: metadata/pv_map.c:271
+#: metadata/pv_manip.c:243
 #, c-format
-msgid "Couldn't fill extent allocation bitmaps in %s"
+msgid "Inconsistent length: %u %u"
 msgstr ""
 
-#: metadata/pv_map.c:277
+#: metadata/pv_manip.c:254
 #, c-format
-msgid "Couldn't create area maps in %s"
+msgid "PV segment pe_count mismatch: %u != %u"
 msgstr ""
 
-#: metadata/segtype.c:30
+#: metadata/pv_manip.c:260
 #, c-format
-msgid "Unrecognised segment type %s"
+msgid "PV segment pe_alloc_count mismatch: %u != %u"
 msgstr ""
 
-#: metadata/snapshot_manip.c:85
-msgid "snapshot name list allocation failed"
+#: metadata/pv_manip.c:270
+#, c-format
+msgid "PV segment VG pv_count mismatch: %u != %u"
 msgstr ""
 
-#: metadata/snapshot_manip.c:96
-msgid "snapshot_list structure allocation failed"
+#: metadata/pv_manip.c:276
+#, c-format
+msgid "PV segment VG free_count mismatch: %u != %u"
 msgstr ""
 
-#: metadata/snapshot_manip.c:119
+#: metadata/pv_manip.c:282
 #, c-format
-msgid "'%s' is already in use as a snapshot."
+msgid "PV segment VG extent_count mismatch: %u != %u"
+msgstr ""
+
+#: metadata/pv_map.c:46
+#, c-format
+msgid "Allowing allocation on %s start PE %u length %u"
+msgstr ""
+
+#: metadata/pv_map.c:165
+msgid "create_pv_maps alloc failed"
 msgstr ""
 
-#: metadata/snapshot_manip.c:137
+#: metadata/pv_map.c:172
 #, c-format
-msgid "Random UUID creation failed for snapshot %s."
+msgid "Couldn't create physical volume maps in %s"
 msgstr ""
 
-#: metadata/snapshot_manip.c:172
-msgid "Asked to remove an unknown snapshot."
+#: metadata/segtype.c:30
+#, c-format
+msgid "Unrecognised segment type %s"
 msgstr ""
 
-#: mirror/mirrored.c:48
+#: metadata/snapshot_manip.c:49
+#, c-format
+msgid "'%s' is already in use as a snapshot."
+msgstr ""
+
+#: metadata/snapshot_manip.c:90
+#, c-format
+msgid "Failed to remove internal snapshot LV %s"
+msgstr ""
+
+#: mirror/mirrored.c:50
 #, c-format
 msgid "  Mirrors\t\t%u"
 msgstr ""
 
-#: mirror/mirrored.c:49
+#: mirror/mirrored.c:51
 #, c-format
 msgid "  Mirror size\t\t%u"
 msgstr ""
 
-#: mirror/mirrored.c:50
+#: mirror/mirrored.c:53
+#, c-format
+msgid "  Mirror log volume\t%s"
+msgstr ""
+
+#: mirror/mirrored.c:59
+#, c-format
+msgid "  Mirror region size\t%s"
+msgstr ""
+
+#: mirror/mirrored.c:62
 msgid "  Mirror original:"
 msgstr ""
 
-#: mirror/mirrored.c:52
+#: mirror/mirrored.c:64
 msgid "  Mirror destination:"
 msgstr ""
 
-#: mirror/mirrored.c:61
+#: mirror/mirrored.c:72
 #, c-format
 msgid "Couldn't read 'mirror_count' for segment '%s'."
 msgstr ""
 
-#: mirror/mirrored.c:79
+#: mirror/mirrored.c:91
 #, c-format
 msgid "Couldn't read 'extents_moved' for segment '%s'."
 msgstr ""
 
-#: mirror/mirrored.c:86
+#: mirror/mirrored.c:100
+#, c-format
+msgid "Couldn't read 'region_size' for segment '%s'."
+msgstr ""
+
+#: mirror/mirrored.c:108
+msgid "Mirror log type must be a string."
+msgstr ""
+
+#: mirror/mirrored.c:113
+#, c-format
+msgid "Unrecognised mirror log in segment %s."
+msgstr ""
+
+#: mirror/mirrored.c:121
+#, c-format
+msgid "Missing region size for mirror log for segment '%s'."
+msgstr ""
+
+#: mirror/mirrored.c:127
 #, c-format
 msgid "Couldn't find mirrors array for segment '%s'."
 msgstr ""
 
-#: mirror/mirrored.c:111
+#: mirror/mirrored.c:156
 msgid "struct mirr_state allocation failed"
 msgstr ""
 
-#: mirror/mirrored.c:165
-#, c-format
-msgid "Using reduced mirror region size of %u sectors"
+#: mirror/mirrored.c:206
+msgid "Missing region size for mirror segment."
 msgstr ""
 
-#: mirror/mirrored.c:193
+#: mirror/mirrored.c:247
 #, c-format
 msgid "Mirror status: %s"
 msgstr ""
 
-#: mirror/mirrored.c:196
+#: mirror/mirrored.c:250
 #, c-format
 msgid "Failure parsing mirror status: %s"
 msgstr ""
@@ -4588,22 +5065,22 @@
 msgid "Not enough space to build temporary file string."
 msgstr ""
 
-#: misc/lvm-file.c:97
+#: misc/lvm-file.c:101
 #, c-format
 msgid "%s: rename to %s failed"
 msgstr ""
 
-#: misc/lvm-file.c:143
+#: misc/lvm-file.c:147
 #, c-format
 msgid "Creating directory \"%s\""
 msgstr ""
 
-#: misc/lvm-file.c:182
+#: misc/lvm-file.c:188
 #, c-format
 msgid "Directory \"%s\" not found"
 msgstr ""
 
-#: misc/lvm-file.c:213
+#: misc/lvm-file.c:219
 msgid "sync_dir failed in strdup"
 msgstr ""
 
@@ -4617,9 +5094,9 @@
 msgid "Unable to open external %s library %s"
 msgstr ""
 
-#: mm/dbg_malloc.c:224
+#: mm/dbg_malloc.c:239
 #, c-format
-msgid "Huge memory allocation (size %Zu) rejected - metadata corruption?"
+msgid "Huge memory allocation (size %zu) rejected - metadata corruption?"
 msgstr ""
 
 #: mm/memlock.c:100
@@ -4647,7 +5124,7 @@
 
 #: mm/pool-fast.c:45
 #, c-format
-msgid "Couldn't create memory pool %s (size %Zu)"
+msgid "Couldn't create memory pool %s (size %zu)"
 msgstr ""
 
 #: mm/pool-fast.c:134
@@ -4656,14 +5133,14 @@
 
 #: mm/pool-fast.c:223
 #, c-format
-msgid "Out of memory.  Requested %Zu bytes."
+msgid "Out of memory.  Requested %zu bytes."
 msgstr ""
 
 #: polldaemon.c:34
 msgid "Forking background process"
 msgstr ""
 
-#: polldaemon.c:39 toollib.c:958
+#: polldaemon.c:39 toollib.c:984
 #, c-format
 msgid "fork failed: %s"
 msgstr ""
@@ -4673,177 +5150,187 @@
 msgid "Background process failed to setsid: %s"
 msgstr ""
 
-#: polldaemon.c:80
+#: polldaemon.c:82
 msgid "Failed to generate list of copied LVs: can't abort."
 msgstr ""
 
-#: polldaemon.c:90
+#: polldaemon.c:92
 msgid "ABORTING: Mirror percentage check failed."
 msgstr ""
 
-#: polldaemon.c:96 polldaemon.c:98
+#: polldaemon.c:98 polldaemon.c:100
 #, c-format
 msgid "%s: Moved: %.1f%%"
 msgstr ""
 
-#: polldaemon.c:107
+#: polldaemon.c:112
 msgid "ABORTING: Failed to generate list of copied LVs"
 msgstr ""
 
-#: polldaemon.c:119
+#: polldaemon.c:124
 msgid "ABORTING: Segment progression failed."
 msgstr ""
 
-#: polldaemon.c:146
+#: polldaemon.c:154
 #, c-format
 msgid "ABORTING: Can't reread VG for %s"
 msgstr ""
 
-#: polldaemon.c:153
+#: polldaemon.c:161
 #, c-format
 msgid "ABORTING: Can't find mirror LV in %s for %s"
 msgstr ""
 
-#: polldaemon.c:181
+#: polldaemon.c:189
 #, c-format
 msgid "Couldn't read volume group %s"
 msgstr ""
 
-#: polldaemon.c:186
+#: polldaemon.c:194
 #, c-format
 msgid "Volume Group %s inconsistent - skipping"
 msgstr ""
 
-#: polldaemon.c:238
+#: polldaemon.c:246
 #, c-format
 msgid "Checking progress every %u seconds"
 msgstr ""
 
-#: pvchange.c:52
+#: pvchange.c:55
 #, c-format
 msgid "Finding volume group of physical volume \"%s\""
 msgstr ""
 
-#: pvchange.c:62
+#: pvchange.c:65
 #, c-format
 msgid "Unable to find volume group of \"%s\""
 msgstr ""
 
-#: pvchange.c:81
+#: pvchange.c:84
 #, c-format
 msgid "Unable to find \"%s\" in volume group \"%s\""
 msgstr ""
 
-#: pvchange.c:88
+#: pvchange.c:91
 #, c-format
 msgid "Volume group containing %s does not support tags"
 msgstr ""
 
-#: pvchange.c:94
+#: pvchange.c:97
 #, c-format
 msgid "Volume group containing %s has active logical volumes"
 msgstr ""
 
-#: pvchange.c:103
+#: pvchange.c:106
 #, c-format
 msgid "Can't change tag on Physical Volume %s not in volume group"
 msgstr ""
 
-#: pvchange.c:108
+#: pvchange.c:111
 msgid "Can't get lock for orphans"
 msgstr ""
 
-#: pvchange.c:114
+#: pvchange.c:117
 #, c-format
 msgid "Unable to read PV \"%s\""
 msgstr ""
 
-#: pvchange.c:123
+#: pvchange.c:126
 #, c-format
 msgid "Allocatability not supported by orphan %s format PV %s"
 msgstr ""
 
-#: pvchange.c:131
+#: pvchange.c:134
 #, c-format
 msgid "Physical volume \"%s\" is already allocatable"
 msgstr ""
 
-#: pvchange.c:141
+#: pvchange.c:144
 #, c-format
 msgid "Physical volume \"%s\" is already unallocatable"
 msgstr ""
 
-#: pvchange.c:151
+#: pvchange.c:154
 #, c-format
 msgid "Setting physical volume \"%s\" allocatable"
 msgstr ""
 
-#: pvchange.c:155
+#: pvchange.c:158
 #, c-format
 msgid "Setting physical volume \"%s\" NOT allocatable"
 msgstr ""
 
-#: pvchange.c:163
+#: pvchange.c:166
 #, c-format
 msgid "Failed to add tag %s to physical volume %s"
 msgstr ""
 
-#: pvchange.c:169
+#: pvchange.c:172
 #, c-format
 msgid "Failed to remove tag %s from physical volume%s"
 msgstr ""
 
-#: pvchange.c:177
+#: pvchange.c:180
 #, c-format
 msgid "Failed to generate new random UUID for %s."
 msgstr ""
 
-#: pvchange.c:183
+#: pvchange.c:188
+#, c-format
+msgid "Changing uuid of %s to %s."
+msgstr ""
+
+#: pvchange.c:195
+#, c-format
+msgid "pv_write with new uuid failed for %s."
+msgstr ""
+
+#: pvchange.c:204
 #, c-format
 msgid "Updating physical volume \"%s\""
 msgstr ""
 
-#: pvchange.c:187
+#: pvchange.c:208
 #, c-format
 msgid "Failed to store physical volume \"%s\" in volume group \"%s\""
 msgstr ""
 
-#: pvchange.c:196
+#: pvchange.c:217
 #, c-format
 msgid "Failed to store physical volume \"%s\""
 msgstr ""
 
-#: pvchange.c:203
+#: pvchange.c:224
 #, c-format
 msgid "Physical volume \"%s\" changed"
 msgstr ""
 
-#: pvchange.c:225
+#: pvchange.c:246
 msgid "Please give exactly one option of -x, -uuid, --addtag or --deltag"
 msgstr ""
 
-#: pvchange.c:231
+#: pvchange.c:252
 msgid "Please give a physical volume path"
 msgstr ""
 
-#: pvchange.c:236
+#: pvchange.c:257
 msgid "Option a and PhysicalVolumePath are exclusive"
 msgstr ""
 
-#: pvchange.c:241 toollib.c:511
+#: pvchange.c:262 toollib.c:537
 msgid "Using physical volume(s) on command line"
 msgstr ""
 
-#: pvchange.c:246
+#: pvchange.c:267
 #, c-format
 msgid "Failed to read physical volume %s"
 msgstr ""
 
-#: pvchange.c:254 toollib.c:581
+#: pvchange.c:275 toollib.c:607
 msgid "Scanning for physical volume names"
 msgstr ""
 
-#: pvchange.c:265
+#: pvchange.c:286
 #, c-format
 msgid "%d physical volume%s changed / %d physical volume%s not changed"
 msgstr ""
@@ -4864,16 +5351,8 @@
 msgid "%s: physical volume not initialized"
 msgstr ""
 
-#: pvcreate.c:66 pvscan.c:126 vgscan.c:51
-msgid "Wiping cache of LVM-capable devices"
-msgstr ""
-
-#: pvcreate.c:68 pvscan.c:129 vgscan.c:54
-msgid "Wiping internal cache"
-msgstr ""
-
-#: pvcreate.c:72 pvcreate.c:162 pvremove.c:76 vgcreate.c:134 vgextend.c:40
-#: vgremove.c:83
+#: pvcreate.c:72 pvcreate.c:162 pvremove.c:76 vgcreate.c:139 vgextend.c:40
+#: vgremove.c:91
 msgid "Can't get lock for orphan PVs"
 msgstr ""
 
@@ -4925,17 +5404,17 @@
 msgid "%s: Couldn't find device.  Check your filters?"
 msgstr ""
 
-#: pvcreate.c:202 vgconvert.c:125
+#: pvcreate.c:202 vgconvert.c:127
 #, c-format
 msgid "Failed to setup physical volume \"%s\""
 msgstr ""
 
-#: pvcreate.c:206 vgconvert.c:136
+#: pvcreate.c:206 vgconvert.c:138
 #, c-format
 msgid "Set up physical volume for \"%s\" with %llu available sectors"
 msgstr ""
 
-#: pvcreate.c:211 vgconvert.c:141
+#: pvcreate.c:211 vgconvert.c:143
 #, c-format
 msgid "Failed to wipe existing label on %s"
 msgstr ""
@@ -4950,17 +5429,17 @@
 msgid "%s not opened: device not zeroed"
 msgstr ""
 
-#: pvcreate.c:226 vgconvert.c:148
+#: pvcreate.c:226 vgconvert.c:150
 #, c-format
 msgid "Writing physical volume data to disk \"%s\""
 msgstr ""
 
-#: pvcreate.c:230 vgconvert.c:153
+#: pvcreate.c:230 vgconvert.c:155
 #, c-format
 msgid "Failed to write physical volume \"%s\""
 msgstr ""
 
-#: pvcreate.c:234 vgconvert.c:159
+#: pvcreate.c:234 vgconvert.c:161
 #, c-format
 msgid "Physical volume \"%s\" successfully created"
 msgstr ""
@@ -4981,16 +5460,16 @@
 msgid "Option y can only be given with option f"
 msgstr ""
 
-#: pvcreate.c:271 vgconvert.c:203
+#: pvcreate.c:271 vgconvert.c:205
 #, c-format
 msgid "labelsector must be less than %lu"
 msgstr ""
 
-#: pvcreate.c:279 vgconvert.c:211
+#: pvcreate.c:279 vgconvert.c:213
 msgid "Metadata parameters only apply to text format"
 msgstr ""
 
-#: pvcreate.c:285 vgconvert.c:217
+#: pvcreate.c:285 vgconvert.c:219
 msgid "Metadatacopies may only be 0, 1 or 2"
 msgstr ""
 
@@ -5009,7 +5488,7 @@
 msgid "\"%s\" is a new physical volume of \"%s\""
 msgstr ""
 
-#: pvdisplay.c:76
+#: pvdisplay.c:77
 msgid "Option -v not allowed with option -c"
 msgstr ""
 
@@ -5029,11 +5508,11 @@
 msgid "No extents available for allocation"
 msgstr ""
 
-#: pvmove.c:147
+#: pvmove.c:146
 msgid "Creation of temporary pvmove LV failed"
 msgstr ""
 
-#: pvmove.c:154
+#: pvmove.c:153
 msgid "lvs_changed list struct allocation failed"
 msgstr ""
 
@@ -5052,88 +5531,88 @@
 msgid "Skipping locked LV %s"
 msgstr ""
 
-#: pvmove.c:186
+#: pvmove.c:187
 #, c-format
 msgid "No data to move for %s"
 msgstr ""
 
-#: pvmove.c:197
+#: pvmove.c:198
 msgid "Updating volume group metadata"
 msgstr ""
 
-#: pvmove.c:199 pvmove.c:223
+#: pvmove.c:200 pvmove.c:224
 msgid "ABORTING: Volume group metadata update failed."
 msgstr ""
 
-#: pvmove.c:235
+#: pvmove.c:236
 msgid "ABORTING: Temporary mirror activation failed.  Run pvmove --abort."
 msgstr ""
 
-#: pvmove.c:243 pvmove.c:425
+#: pvmove.c:244 pvmove.c:426
 #, c-format
 msgid "Unable to reactivate logical volume \"%s\""
 msgstr ""
 
-#: pvmove.c:251
+#: pvmove.c:252
 msgid "Unable to resume logical volumes"
 msgstr ""
 
-#: pvmove.c:299
+#: pvmove.c:300
 #, c-format
 msgid "Detected pvmove in progress for %s"
 msgstr ""
 
-#: pvmove.c:301
+#: pvmove.c:302
 msgid "Ignoring remaining command line arguments"
 msgstr ""
 
-#: pvmove.c:304
+#: pvmove.c:305
 msgid "ABORTING: Failed to generate list of moving LVs"
 msgstr ""
 
-#: pvmove.c:312
+#: pvmove.c:313
 msgid "ABORTING: Temporary mirror activation failed."
 msgstr ""
 
-#: pvmove.c:390
+#: pvmove.c:391
 msgid "ABORTING: Removal of temporary mirror failed"
 msgstr ""
 
-#: pvmove.c:396 pvmove.c:415 pvmove.c:449
+#: pvmove.c:397 pvmove.c:416 pvmove.c:450
 msgid "ABORTING: Failed to write new data locations to disk."
 msgstr ""
 
-#: pvmove.c:403
+#: pvmove.c:404
 msgid "Locking LVs to remove temporary mirror failed"
 msgstr ""
 
-#: pvmove.c:409
+#: pvmove.c:410
 msgid "Suspension of temporary mirror LV failed"
 msgstr ""
 
-#: pvmove.c:435
+#: pvmove.c:436
 #, c-format
 msgid "ABORTING: Unable to deactivate temporary logical volume \"%s\""
 msgstr ""
 
-#: pvmove.c:440
+#: pvmove.c:441
 msgid "Removing temporary pvmove LV"
 msgstr ""
 
-#: pvmove.c:442
+#: pvmove.c:443
 msgid "ABORTING: Removal of temporary pvmove LV failed"
 msgstr ""
 
-#: pvmove.c:447
+#: pvmove.c:448
 msgid "Writing out final volume group after pvmove"
 msgstr ""
 
-#: pvmove.c:467
+#: pvmove.c:468
 #, c-format
 msgid "ABORTING: Can't reread PV %s"
 msgstr ""
 
-#: pvmove.c:503 toollib.c:882
+#: pvmove.c:504 toollib.c:908
 msgid "Failed to clone PV name"
 msgstr ""
 
@@ -5187,15 +5666,15 @@
 msgid "WARNING: only considering physical volumes %s"
 msgstr ""
 
-#: pvscan.c:132
+#: pvscan.c:129
 msgid "Walking through all physical volumes"
 msgstr ""
 
-#: pvscan.c:185
+#: pvscan.c:182
 msgid "No matching physical volumes found"
 msgstr ""
 
-#: pvscan.c:189
+#: pvscan.c:186
 #, c-format
 msgid "Total: %d [%s] / in use: %d [%s] / in no VG: %d [%s]"
 msgstr ""
@@ -5233,136 +5712,141 @@
 msgid "Parse error in regex"
 msgstr ""
 
-#: report/report.c:124 report/report.c:527 report/report.c:555
+#: report/report.c:125 report/report.c:541 report/report.c:581
+#: report/report.c:609
 msgid "pool_strdup failed"
 msgstr ""
 
-#: report/report.c:151 report/report.c:210
+#: report/report.c:152 report/report.c:211
 msgid "pool_begin_object failed"
 msgstr ""
 
-#: report/report.c:171 report/report.c:182 report/report.c:188
-#: report/report.c:194 report/report.c:217 report/report.c:223
-#: report/report.c:1265
+#: report/report.c:172 report/report.c:183 report/report.c:189
+#: report/report.c:195 report/report.c:218 report/report.c:224
+#: report/report.c:1322
 msgid "pool_grow_object failed"
 msgstr ""
 
-#: report/report.c:177
+#: report/report.c:178
 msgid "Extent number lvm_snprintf failed"
 msgstr ""
 
-#: report/report.c:270 report/report.c:275 report/report.c:331
-#: report/report.c:404 report/report.c:431 report/report.c:532
-#: report/report.c:560 report/report.c:677 report/report.c:700
-#: report/report.c:705 report/report.c:729 report/report.c:734
-#: report/report.c:772 report/report.c:792 report/report.c:817
-#: report/report.c:832
+#: report/report.c:271 report/report.c:276 report/report.c:332
+#: report/report.c:409 report/report.c:436 report/report.c:529
+#: report/report.c:586 report/report.c:614 report/report.c:731
+#: report/report.c:754 report/report.c:759 report/report.c:783
+#: report/report.c:788 report/report.c:826 report/report.c:847
+#: report/report.c:872 report/report.c:887
 msgid "pool_alloc failed"
 msgstr ""
 
-#: report/report.c:280
+#: report/report.c:281
 #, c-format
 msgid "int too big: %d"
 msgstr ""
 
-#: report/report.c:710
+#: report/report.c:534
+msgid "lvname snprintf failed"
+msgstr ""
+
+#: report/report.c:764
 #, c-format
 msgid "uint32 too big: %u"
 msgstr ""
 
-#: report/report.c:739
+#: report/report.c:793
 #, c-format
 msgid "int32 too big: %d"
 msgstr ""
 
-#: report/report.c:797
+#: report/report.c:852
 msgid "snapshot percentage too large"
 msgstr ""
 
-#: report/report.c:837
+#: report/report.c:892
 msgid "copy percentage too large"
 msgstr ""
 
-#: report/report.c:894 report/report.c:933
+#: report/report.c:949 report/report.c:985
 msgid "struct field_properties allocation failed"
 msgstr ""
 
-#: report/report.c:946
+#: report/report.c:998
 #, c-format
 msgid "Ignoring duplicate sort field: %s"
 msgstr ""
 
-#: report/report.c:978
+#: report/report.c:1030
 msgid "Missing sort field name"
 msgstr ""
 
-#: report/report.c:1009 report/report.c:1031
+#: report/report.c:1061 report/report.c:1083
 #, c-format
 msgid "Unrecognised field: %.*s"
 msgstr ""
 
-#: report/report.c:1047
+#: report/report.c:1099
 msgid "report_handle pool_zalloc failed"
 msgstr ""
 
-#: report/report.c:1085
+#: report/report.c:1140
 msgid "Allocation of memory pool for report failed"
 msgstr ""
 
-#: report/report.c:1100
+#: report/report.c:1157
 msgid "Can't report LV and PV fields at the same time"
 msgstr ""
 
-#: report/report.c:1140
+#: report/report.c:1198
 msgid "report_object: One of *lv and *pv must be NULL!"
 msgstr ""
 
-#: report/report.c:1145
+#: report/report.c:1203
 msgid "struct row allocation failed"
 msgstr ""
 
-#: report/report.c:1154
+#: report/report.c:1212
 msgid "row sort value structure allocation failed"
 msgstr ""
 
-#: report/report.c:1168
+#: report/report.c:1224
 msgid "struct field allocation failed"
 msgstr ""
 
-#: report/report.c:1195
+#: report/report.c:1254
 #, c-format
 msgid "report function failed for field %s"
 msgstr ""
 
-#: report/report.c:1236
+#: report/report.c:1294
 msgid "pool_begin_object failed for headings"
 msgstr ""
 
-#: report/report.c:1250
+#: report/report.c:1307
 msgid "snprintf heading failed"
 msgstr ""
 
-#: report/report.c:1273
+#: report/report.c:1330
 msgid "Failed to generate report headings for printing"
 msgstr ""
 
-#: report/report.c:1333
+#: report/report.c:1389
 msgid "sort array allocation failed"
 msgstr ""
 
-#: report/report.c:1378
+#: report/report.c:1432
 msgid "pool_begin_object failed for row"
 msgstr ""
 
-#: report/report.c:1396 report/report.c:1405
+#: report/report.c:1450 report/report.c:1459
 msgid "snprintf repstr failed"
 msgstr ""
 
-#: report/report.c:1420
+#: report/report.c:1474
 msgid "pool_grow_object failed for row"
 msgstr ""
 
-#: report/report.c:1433
+#: report/report.c:1487
 msgid "Failed to generate row for printing"
 msgstr ""
 
@@ -5371,17 +5855,17 @@
 msgid "Volume group %s not found"
 msgstr ""
 
-#: reporter.c:65 toollib.c:233 toollib.c:321
+#: reporter.c:64 reporter.c:105 toollib.c:236 toollib.c:346
 #, c-format
 msgid "Can't lock %s: skipping"
 msgstr ""
 
-#: reporter.c:70
+#: reporter.c:69 reporter.c:110
 #, c-format
 msgid "Can't read %s: skipping"
 msgstr ""
 
-#: reporter.c:160
+#: reporter.c:212
 #, c-format
 msgid "Invalid options string: %s"
 msgstr ""
@@ -5406,37 +5890,37 @@
 msgid "Unknown logical volume specified for snapshot origin."
 msgstr ""
 
-#: striped/striped.c:42
+#: striped/striped.c:43
 #, c-format
 msgid "  Stripes\t\t%u"
 msgstr ""
 
-#: striped/striped.c:43
+#: striped/striped.c:44
 #, c-format
 msgid "  Stripe size\t\t%u KB"
 msgstr ""
 
-#: striped/striped.c:46
+#: striped/striped.c:47
 #, c-format
 msgid "  Stripe %d:"
 msgstr ""
 
-#: striped/striped.c:56
+#: striped/striped.c:57
 #, c-format
 msgid "Couldn't read 'stripe_count' for segment '%s'."
 msgstr ""
 
-#: striped/striped.c:71
+#: striped/striped.c:72
 #, c-format
 msgid "Couldn't read stripe_size for segment '%s'."
 msgstr ""
 
-#: striped/striped.c:77
+#: striped/striped.c:78
 #, c-format
 msgid "Couldn't find stripes array for segment '%s'."
 msgstr ""
 
-#: striped/striped.c:164
+#: striped/striped.c:174
 msgid "Internal error: striped target with no stripes"
 msgstr ""
 
@@ -5458,158 +5942,183 @@
 "Metadata in LVM1 format can still be displayed using LVM1's pvdata command."
 msgstr ""
 
-#: toollib.c:91
+#: toollib.c:94
 msgid "One or more specified logical volume(s) not found."
 msgstr ""
 
-#: toollib.c:127
+#: toollib.c:130
 msgid "Using logical volume(s) on command line"
 msgstr ""
 
-#: toollib.c:140 toollib.c:374 toollib.c:517 toollib.c:863
+#: toollib.c:143 toollib.c:399 toollib.c:543 toollib.c:889
 #, c-format
 msgid "Skipping invalid tag %s"
 msgstr ""
 
-#: toollib.c:167 toollib.c:622 toollib.c:633
+#: toollib.c:170 toollib.c:648 toollib.c:659
 #, c-format
 msgid "\"%s\": Invalid path for Logical Volume"
 msgstr ""
 
-#: toollib.c:208
+#: toollib.c:211
 msgid "vg/lv string alloc failed"
 msgstr ""
 
-#: toollib.c:221
+#: toollib.c:224
 msgid "Finding all logical volumes"
 msgstr ""
 
-#: toollib.c:223 toollib.c:412
+#: toollib.c:226 toollib.c:437
 msgid "No volume groups found"
 msgstr ""
 
-#: toollib.c:243 vgcfgbackup.c:55 vgck.c:22 vgreduce.c:282 vgscan.c:22
+#: toollib.c:246 vgcfgbackup.c:55 vgck.c:22 vgreduce.c:287 vgscan.c:22
 #, c-format
 msgid "Volume group \"%s\" not found"
 msgstr ""
 
-#: toollib.c:246 vgchange.c:301 vgck.c:27 vgconvert.c:43 vgscan.c:29
+#: toollib.c:249 vgchange.c:404 vgck.c:27 vgconvert.c:43 vgscan.c:29
 #, c-format
 msgid "Volume group \"%s\" inconsistent"
 msgstr ""
 
-#: toollib.c:368
+#: toollib.c:393
 msgid "Using volume group(s) on command line"
 msgstr ""
 
-#: toollib.c:395
+#: toollib.c:420
 #, c-format
 msgid "Invalid volume group name: %s"
 msgstr ""
 
-#: toollib.c:410
+#: toollib.c:435
 msgid "Finding all volume groups"
 msgstr ""
 
-#: toollib.c:533 toollib.c:888
+#: toollib.c:559 toollib.c:914
 #, c-format
 msgid "Physical Volume \"%s\" not found in Volume Group \"%s\""
 msgstr ""
 
-#: toollib.c:544
+#: toollib.c:570
 #, c-format
 msgid "Failed to read physical volume \"%s\""
 msgstr ""
 
-#: toollib.c:570
+#: toollib.c:596
 msgid "Using all physical volume(s) in volume group"
 msgstr ""
 
-#: toollib.c:640
+#: toollib.c:666
 msgid "Allocation of vg_name failed"
 msgstr ""
 
-#: toollib.c:650
+#: toollib.c:676
 #, c-format
 msgid "Path required for Logical Volume \"%s\""
 msgstr ""
 
-#: toollib.c:681
+#: toollib.c:707
 #, c-format
 msgid "Environment Volume Group in LVM_VG_NAME invalid: \"%s\""
 msgstr ""
 
-#: toollib.c:697
+#: toollib.c:723
 #, c-format
 msgid "Adding PE range: start PE %u length %u"
 msgstr ""
 
-#: toollib.c:705
+#: toollib.c:731
 #, c-format
 msgid "Overlapping PE ranges detected (%u-%u, %u-%u)"
 msgstr ""
 
-#: toollib.c:714 toollib.c:851 toollib.c:908
+#: toollib.c:740 toollib.c:877 toollib.c:934
 msgid "Allocation of list failed"
 msgstr ""
 
-#: toollib.c:778
+#: toollib.c:804
 #, c-format
 msgid "PE range error: start extent %u to end extent %u"
 msgstr ""
 
-#: toollib.c:793
+#: toollib.c:819
 #, c-format
 msgid "Physical extent parsing error at %s"
 msgstr ""
 
-#: toollib.c:806
+#: toollib.c:832
 #, c-format
 msgid "Physical volume %s not allocatable"
 msgstr ""
 
-#: toollib.c:812
+#: toollib.c:838
 #, c-format
 msgid "No free extents on physical volume \"%s\""
 msgstr ""
 
-#: toollib.c:817 toollib.c:915
+#: toollib.c:843 toollib.c:941
 msgid "Unable to allocate physical volume list."
 msgstr ""
 
-#: toollib.c:824
+#: toollib.c:850
 msgid "Allocation of pe_ranges list failed"
 msgstr ""
 
-#: toollib.c:896
+#: toollib.c:922
 msgid "No specified PVs have space available"
 msgstr ""
 
-#: toollib.c:938
+#: toollib.c:964
 #, c-format
 msgid "Can't lock %s for metadata recovery: skipping"
 msgstr ""
 
-#: toollib.c:955
+#: toollib.c:981
 #, c-format
 msgid "Executing: %s %s %s %s"
 msgstr ""
 
-#: toollib.c:972
+#: toollib.c:998
 #, c-format
 msgid "wait4 child process %u failed: %s"
 msgstr ""
 
-#: toollib.c:978
+#: toollib.c:1004
 #, c-format
 msgid "Child %u exited abnormally"
 msgstr ""
 
-#: toollib.c:983
+#: toollib.c:1009
 #, c-format
 msgid "%s failed: %u"
 msgstr ""
 
+#: toollib.c:1019
+msgid ""
+"Names starting \"snapshot\" are reserved. Please choose a different LV name."
+msgstr ""
+
+#: toollib.c:1025
+msgid ""
+"Names starting \"pvmove\" are reserved. Please choose a different LV name."
+msgstr ""
+
+#: toollib.c:1031
+msgid ""
+"Names including \"_mlog\" are reserved. Please choose a different LV name."
+msgstr ""
+
+#: toollib.c:1037
+msgid ""
+"Names including \"_mimage\" are reserved. Please choose a different LV name."
+msgstr ""
+
+#: toollib.c:1054
+#, c-format
+msgid "%s: already exists in filesystem"
+msgstr ""
+
 #: uuid/uuid.c:133
 msgid "UUID contains invalid character"
 msgstr ""
@@ -5690,101 +6199,145 @@
 
 #: vgchange.c:87
 #, c-format
+msgid "Locking inactive: ignoring clustered volume group %s"
+msgstr ""
+
+#: vgchange.c:97
+#, c-format
 msgid "%d logical volume(s) in volume group \"%s\" already active"
 msgstr ""
 
-#: vgchange.c:91
+#: vgchange.c:101
 #, c-format
 msgid "Activated logical volumes in volume group \"%s\""
 msgstr ""
 
-#: vgchange.c:95
+#: vgchange.c:105
 #, c-format
 msgid "Deactivated logical volumes in volume group \"%s\""
 msgstr ""
 
-#: vgchange.c:98
+#: vgchange.c:108
 #, c-format
 msgid "%d logical volume(s) in volume group \"%s\" now active"
 msgstr ""
 
-#: vgchange.c:110 vgcreate.c:47
+#: vgchange.c:120 vgcreate.c:47
 msgid "Volume Group allocation policy cannot inherit from anything"
 msgstr ""
 
-#: vgchange.c:116
+#: vgchange.c:126
 #, c-format
 msgid "Volume group allocation policy is already %s"
 msgstr ""
 
-#: vgchange.c:131 vgchange.c:166 vgchange.c:208 vgchange.c:250 vgchange.c:282
+#: vgchange.c:141 vgchange.c:176 vgchange.c:211 vgchange.c:253 vgchange.c:311
+#: vgchange.c:353 vgchange.c:385
 #, c-format
 msgid "Volume group \"%s\" successfully changed"
 msgstr ""
 
-#: vgchange.c:142
+#: vgchange.c:152
 #, c-format
 msgid "Volume group \"%s\" is already resizeable"
 msgstr ""
 
-#: vgchange.c:148
+#: vgchange.c:158
 #, c-format
 msgid "Volume group \"%s\" is already not resizeable"
 msgstr ""
 
-#: vgchange.c:177
+#: vgchange.c:187
+#, c-format
+msgid "Volume group \"%s\" is already clustered"
+msgstr ""
+
+#: vgchange.c:193
+#, c-format
+msgid "Volume group \"%s\" is already not clustered"
+msgstr ""
+
+#: vgchange.c:222
 #, c-format
 msgid "Volume group \"%s\" must be resizeable to change MaxLogicalVolume"
 msgstr ""
 
-#: vgchange.c:186
+#: vgchange.c:231
 msgid "MaxLogicalVolume limit is 255"
 msgstr ""
 
-#: vgchange.c:192
+#: vgchange.c:237
 #, c-format
 msgid ""
 "MaxLogicalVolume is less than the current number %d of logical volume(s) for "
 "\"%s\""
 msgstr ""
 
-#: vgchange.c:233 vgcreate.c:127
+#: vgchange.c:263
+#, c-format
+msgid "Volume group \"%s\" must be resizeable to change PE size"
+msgstr ""
+
+#: vgchange.c:269 vgcreate.c:64
+msgid "Physical extent size may not be negative"
+msgstr ""
+
+#: vgchange.c:275 vgcreate.c:83
+msgid "Physical extent size may not be zero"
+msgstr ""
+
+#: vgchange.c:280
+#, c-format
+msgid "Physical extent size of VG %s is already %s"
+msgstr ""
+
+#: vgchange.c:286
+msgid "Physical extent size must be a power of 2."
+msgstr ""
+
+#: vgchange.c:293
+msgid "New extent size is not a perfect fit"
+msgstr ""
+
+#: vgchange.c:336 vgcreate.c:121
 #, c-format
 msgid "Failed to add tag %s to volume group %s"
 msgstr ""
 
-#: vgchange.c:239
+#: vgchange.c:342
 #, c-format
 msgid "Failed to remove tag %s from volume group %s"
 msgstr ""
 
-#: vgchange.c:260
+#: vgchange.c:363
 msgid "Volume group has active logical volumes"
 msgstr ""
 
-#: vgchange.c:268
+#: vgchange.c:371
 #, c-format
 msgid "Failed to generate new random UUID for VG %s."
 msgstr ""
 
-#: vgchange.c:294 vgconvert.c:36 vgexport.c:23
+#: vgchange.c:397 vgconvert.c:36 vgexport.c:23
 #, c-format
 msgid "Unable to find volume group \"%s\""
 msgstr ""
 
-#: vgchange.c:347
-msgid "One of -a, -l, -x, --alloc, --addtag, --deltag or --uuid required"
+#: vgchange.c:457
+msgid ""
+"One of -a, -c, -l, -s, -x, --uuid, --alloc, --addtag or --deltag required"
 msgstr ""
 
-#: vgchange.c:357
-msgid "Only one of -a, -l, -x, --alloc, --addtag, --deltag or --uuid allowed"
+#: vgchange.c:468
+msgid ""
+"Only one of -a, -c, -l, -s, -x, --uuid, --alloc, --addtag or --deltag allowed"
 msgstr ""
 
-#: vgchange.c:364
+#: vgchange.c:475
 msgid "--ignorelockingfailure only available with -a"
 msgstr ""
 
-#: vgchange.c:370
+#: vgchange.c:481
 msgid "-A option not necessary with -a option"
 msgstr ""
 
@@ -5798,47 +6351,47 @@
 msgid "Archive of \"%s\" metadata failed."
 msgstr ""
 
-#: vgconvert.c:98
+#: vgconvert.c:100
 #, c-format
 msgid "Logical volume %s must be deactivated before conversion."
 msgstr ""
 
-#: vgconvert.c:128 vgconvert.c:143 vgconvert.c:155 vgconvert.c:168
-#: vgconvert.c:184
+#: vgconvert.c:130 vgconvert.c:145 vgconvert.c:157 vgconvert.c:170
+#: vgconvert.c:186
 msgid "Use pvcreate and vgcfgrestore to repair from archived metadata."
 msgstr ""
 
-#: vgconvert.c:164
+#: vgconvert.c:166
 #, c-format
 msgid "Deleting existing metadata for VG %s"
 msgstr ""
 
-#: vgconvert.c:166
+#: vgconvert.c:168
 #, c-format
 msgid "Removal of existing metadata for %s failed."
 msgstr ""
 
-#: vgconvert.c:175
+#: vgconvert.c:177
 #, c-format
 msgid "Test mode: Skipping metadata writing for VG %s in format %s"
 msgstr ""
 
-#: vgconvert.c:180
+#: vgconvert.c:182
 #, c-format
 msgid "Writing metadata for VG %s using format %s"
 msgstr ""
 
-#: vgconvert.c:183
+#: vgconvert.c:185
 #, c-format
 msgid "Conversion failed for volume group %s."
 msgstr ""
 
-#: vgconvert.c:188
+#: vgconvert.c:190
 #, c-format
 msgid "Volume group %s successfully converted"
 msgstr ""
 
-#: vgconvert.c:198
+#: vgconvert.c:200
 msgid "Please enter volume group(s)"
 msgstr ""
 
@@ -5854,10 +6407,6 @@
 msgid "Number of volumes may not exceed 255"
 msgstr ""
 
-#: vgcreate.c:64
-msgid "Physical extent size may not be negative"
-msgstr ""
-
 #: vgcreate.c:69
 msgid "Max Logical Volumes may not be negative"
 msgstr ""
@@ -5866,35 +6415,26 @@
 msgid "Max Physical Volumes may not be negative"
 msgstr ""
 
-#: vgcreate.c:83
-msgid "Physical extent size may not be zero"
-msgstr ""
-
-#: vgcreate.c:93
-#, c-format
-msgid "%s: already exists in filesystem"
-msgstr ""
-
-#: vgcreate.c:98 vgrename.c:55
+#: vgcreate.c:92 vgrename.c:55 vgsplit.c:226
 #, c-format
 msgid "New volume group name \"%s\" is invalid"
 msgstr ""
 
-#: vgcreate.c:108
+#: vgcreate.c:102
 #, c-format
 msgid "Warning: Setting maxlogicalvolumes to %d (0 means unlimited)"
 msgstr ""
 
-#: vgcreate.c:112
+#: vgcreate.c:106
 #, c-format
 msgid "Warning: Setting maxphysicalvolumes to %d (0 means unlimited)"
 msgstr ""
 
-#: vgcreate.c:122
+#: vgcreate.c:116
 msgid "Volume group format does not support tags"
 msgstr ""
 
-#: vgcreate.c:162
+#: vgcreate.c:167
 #, c-format
 msgid "Volume group \"%s\" successfully created"
 msgstr ""
@@ -5913,11 +6453,11 @@
 msgid "--- Physical volumes ---"
 msgstr ""
 
-#: vgdisplay.c:79
+#: vgdisplay.c:81
 msgid "Option -c is not allowed with option -s"
 msgstr ""
 
-#: vgdisplay.c:84
+#: vgdisplay.c:86
 msgid "Option -A is not allowed with volume group names"
 msgstr ""
 
@@ -5957,7 +6497,7 @@
 msgid "Please enter physical volume(s)"
 msgstr ""
 
-#: vgextend.c:44 vgmerge.c:31 vgmerge.c:55 vgsplit.c:171 vgsplit.c:195
+#: vgextend.c:44 vgmerge.c:31 vgmerge.c:55 vgsplit.c:187 vgsplit.c:211
 #, c-format
 msgid "Checking for volume group \"%s\""
 msgstr ""
@@ -6002,12 +6542,12 @@
 msgid "Volume group \"%s\" successfully imported"
 msgstr ""
 
-#: vgmerge.c:27 vgsplit.c:167
+#: vgmerge.c:27 vgsplit.c:183
 #, c-format
 msgid "Duplicate volume group name \"%s\""
 msgstr ""
 
-#: vgmerge.c:79 vgsplit.c:211
+#: vgmerge.c:79 vgsplit.c:233
 #, c-format
 msgid "Logical volumes in \"%s\" must be inactive"
 msgstr ""
@@ -6032,12 +6572,22 @@
 msgid "Duplicate logical volume name \"%s\" in \"%s\" and \"%s\""
 msgstr ""
 
-#: vgmerge.c:175
+#: vgmerge.c:153
+#, c-format
+msgid "Failed to generate new random LVID for %s"
+msgstr ""
+
+#: vgmerge.c:164
+#, c-format
+msgid "Changed LVID for %s to %s"
+msgstr ""
+
+#: vgmerge.c:202
 #, c-format
 msgid "Volume group \"%s\" successfully merged into \"%s\""
 msgstr ""
 
-#: vgmerge.c:192
+#: vgmerge.c:219
 msgid "Please enter 2 or more volume groups to merge"
 msgstr ""
 
@@ -6075,79 +6625,79 @@
 msgid "Deactivating (if active) logical volume %s (origin of %s)"
 msgstr ""
 
-#: vgreduce.c:95 vgreduce.c:104
+#: vgreduce.c:93 vgreduce.c:102
 #, c-format
 msgid "Removing LV %s from VG %s"
 msgstr ""
 
-#: vgreduce.c:174
+#: vgreduce.c:172
 #, c-format
 msgid "Physical volume \"%s\" still in use"
 msgstr ""
 
-#: vgreduce.c:179
+#: vgreduce.c:177
 #, c-format
 msgid "Can't remove final physical volume \"%s\" from volume group \"%s\""
 msgstr ""
 
-#: vgreduce.c:189
+#: vgreduce.c:187
 #, c-format
 msgid "Removing \"%s\" from volume group \"%s\""
 msgstr ""
 
-#: vgreduce.c:200
+#: vgreduce.c:205
 #, c-format
 msgid "Removal of physical volume \"%s\" from \"%s\" failed"
 msgstr ""
 
-#: vgreduce.c:206
+#: vgreduce.c:211
 #, c-format
 msgid ""
 "Failed to clear metadata from physical volume \"%s\" after removal from \"%s"
 "\""
 msgstr ""
 
-#: vgreduce.c:214
+#: vgreduce.c:219
 #, c-format
 msgid "Removed \"%s\" from volume group \"%s\""
 msgstr ""
 
-#: vgreduce.c:227
+#: vgreduce.c:232
 msgid "Please give volume group name and physical volume paths"
 msgstr ""
 
-#: vgreduce.c:233
+#: vgreduce.c:238
 msgid "Please give volume group name"
 msgstr ""
 
-#: vgreduce.c:239
+#: vgreduce.c:244
 msgid "Please enter physical volume paths or option -a"
 msgstr ""
 
-#: vgreduce.c:244
+#: vgreduce.c:249
 msgid "Option -a and physical volume paths mutually exclusive"
 msgstr ""
 
-#: vgreduce.c:250
+#: vgreduce.c:255
 msgid "Please only specify the volume group"
 msgstr ""
 
-#: vgreduce.c:273
+#: vgreduce.c:278
 #, c-format
 msgid "Volume group \"%s\" is already consistent"
 msgstr ""
 
-#: vgreduce.c:304
+#: vgreduce.c:309
 #, c-format
 msgid "Failed to write out a consistent VG for %s"
 msgstr ""
 
-#: vgreduce.c:312
+#: vgreduce.c:317
 #, c-format
 msgid "Wrote out consistent volume group %s"
 msgstr ""
 
-#: vgreduce.c:328
+#: vgreduce.c:333
 #, c-format
 msgid "Volume group \"%s\" is not reducible"
 msgstr ""
@@ -6176,17 +6726,17 @@
 msgid "Removing physical volume \"%s\" from volume group \"%s\""
 msgstr ""
 
-#: vgremove.c:61
+#: vgremove.c:69
 #, c-format
 msgid "Failed to remove physical volume \"%s\" from volume group \"%s\""
 msgstr ""
 
-#: vgremove.c:71
+#: vgremove.c:79
 #, c-format
 msgid "Volume group \"%s\" successfully removed"
 msgstr ""
 
-#: vgremove.c:73
+#: vgremove.c:81
 #, c-format
 msgid "Volume group \"%s\" not properly removed"
 msgstr ""
@@ -6243,11 +6793,11 @@
 msgid "Found %svolume group \"%s\" using metadata type %s"
 msgstr ""
 
-#: vgscan.c:47
+#: vgscan.c:49
 msgid "Too many parameters on command line"
 msgstr ""
 
-#: vgscan.c:57
+#: vgscan.c:56
 msgid "Reading all physical volumes.  This may take a while..."
 msgstr ""
 
@@ -6256,40 +6806,40 @@
 msgid "Physical volume %s not in volume group %s"
 msgstr ""
 
-#: vgsplit.c:71
+#: vgsplit.c:87
 #, c-format
 msgid "Logical Volume %s split between Volume Groups"
 msgstr ""
 
-#: vgsplit.c:88
+#: vgsplit.c:104
 #, c-format
 msgid "Physical Volume %s not found"
 msgstr ""
 
-#: vgsplit.c:135
+#: vgsplit.c:149
 #, c-format
 msgid "Snapshot %s split"
 msgstr ""
 
-#: vgsplit.c:157
+#: vgsplit.c:173
 msgid "Existing VG, new VG and physical volumes required."
 msgstr ""
 
-#: vgsplit.c:205
+#: vgsplit.c:221
 #, c-format
 msgid "Volume group \"%s\" already exists"
 msgstr ""
 
-#: vgsplit.c:247
+#: vgsplit.c:269
 msgid "Writing out updated volume groups"
 msgstr ""
 
-#: vgsplit.c:269
+#: vgsplit.c:291
 #, c-format
 msgid "Volume group \"%s\" became inconsistent: please fix manually"
 msgstr ""
 
-#: vgsplit.c:284
+#: vgsplit.c:306
 #, c-format
 msgid "Volume group \"%s\" successfully split from \"%s\""
 msgstr ""

Modified: lvm2/trunk/scripts/clvmd_init_rhel4
==============================================================================
--- lvm2/trunk/scripts/clvmd_init_rhel4	(original)
+++ lvm2/trunk/scripts/clvmd_init_rhel4	Tue Jun 14 11:23:47 2005
@@ -13,6 +13,8 @@
 LVDISPLAY="/usr/sbin/lvdisplay"
 VGCHANGE="/usr/sbin/vgchange"
 VGSCAN="/usr/sbin/vgscan"
+VGDISPLAY="/usr/sbin/vgdisplay"
+VGS="/usr/sbin/vgs"
 
 [ -f /etc/sysconfig/cluster ] && . /etc/sysconfig/cluster
 
@@ -24,20 +26,15 @@
 	do
 		if ! pidof clvmd > /dev/null 
 		then 
-			echo -n "Starting clvmd:"
-			clvmd > /dev/null 2>&1
+			echo -n "Starting clvmd: "
+			daemon clvmd
 			rtrn=$?
-			if [ $rtrn -eq 0 ]
+			echo
+			if [ $rtrn -ne 0 ]
 			then
-				success
-				echo
-			else
-				failure
-				echo
 				break
 			fi
-		fi	
-		
+ 		fi	
 		# refresh cache
 		$VGSCAN  > /dev/null 2>&1
 		
@@ -45,28 +42,16 @@
 		then
 			for vg in $LVM_VGS
 			do
-				echo -n "Activating lvm $vg:"
-				if $VGCHANGE -ayl $vg > /dev/null 2>&1
+				if ! action "Activating VG $vg:" $VGCHANGE -ayl $vg
 				then
-					success
-					echo
-				else
 					rtrn=$?
-					failure
-					echo
-				fi
+                                fi
 			done
 		else
-			echo -n "Activating lvms:"
-			if $VGCHANGE -ayl > /dev/null 2>&1
+			if ! action "Activating VGs:" $VGCHANGE -ayl
 			then
-				success
-				echo
-			else
 				rtrn=$?
-				failure
-				echo
-			fi
+                        fi
 		fi
 	done
 
@@ -81,49 +66,28 @@
 		then
 			for vg in $LVM_VGS
 			do
-				echo -n "Deactivating lvm $vg:"
-				if $VGCHANGE -anl $vg > /dev/null 2>&1
+				if ! action "Deactivating VG $vg:" $VGCHANGE -anl $vg
 				then
-					success
-					echo
-				else
 					rtrn=$?
-					failure
-					echo
 				fi
 			done
 		else
-			echo -n "Deactivating lvms:"
-			if $VGCHANGE -anl > /dev/null 2>&1
-			then
-				success
-				echo
-			else
-				rtrn=$?
-				failure
-				echo
-			fi
+			# Hack to only deactivate clustered volumes
+		        clustervgs=`$VGDISPLAY \`$VGS --noheadings -o name\` | awk 'BEGIN {RS="VG Name"} {if (/Clustered/) print $1;}'`
+			for vg in $clustervgs; do
+				if ! action "Deactivating VG $vg:" $VGCHANGE -anl $vg
+				then
+					rtrn=$?
+				fi
+			done
 		fi
 
 		[ $rtrn -ne 0 ] && break
 
 		echo -n "Stopping clvm:"
-		pid=$(pidof clvmd)
-		if [ -n "$pid" ]
-		then
-			while kill $pid > /dev/null 2>&1
-			do
-				sleep 1
-			done
-		fi
-		if [ $rtrn -eq 0 ]
-		then
-			success
-			echo
-		else
-			failure
-			echo
-		fi
+		killproc clvmd -TERM
+		rtrn=$?
+		echo
 	done
 	
 	return $rtrn
@@ -146,8 +110,10 @@
 	;;
 
   restart)
-	$0 stop
-	$0 start 
+	if stop
+	then
+		start
+	fi 
 	rtrn=$?
 	;;
 

Added: lvm2/trunk/scripts/lvmconf.sh
==============================================================================
--- (empty file)
+++ lvm2/trunk/scripts/lvmconf.sh	Tue Jun 14 11:23:47 2005
@@ -0,0 +1,232 @@
+#!/bin/sh
+#
+# Edit an lvm.conf file to adjust various properties
+#
+#
+#
+
+function usage
+{
+    echo "usage: $0 <command>"
+    echo ""
+    echo "Commands:"
+    echo "Enable clvm:  --enable-cluster --lockinglibdir <dir> [--lockinglib <lib>]"
+    echo "Disable clvm: --disable-cluster"
+    echo ""
+    echo "Global options:"
+    echo "Config file location: --file <configfile>"
+    echo ""
+}
+
+
+function parse_args
+{
+    while [ -n "$1" ]; do
+        case $1 in
+            --enable-cluster)
+                LOCKING_TYPE=2
+                shift
+                ;;
+            --disable-cluster)
+                LOCKING_TYPE=1
+                shift
+                ;;
+            --lockinglibdir)
+                if [ -n "$2" ]; then
+                    LOCKINGLIBDIR=$2
+                    shift 2
+                else
+                    usage
+                    exit 1
+                fi
+                ;;
+            --lockinglib)
+                if [ -n "$2" ]; then
+                    LOCKINGLIB=$2
+                    shift 2
+                else
+                    usage
+                    exit 1
+                fi
+                ;;
+            --file)
+                if [ -n "$2" ]; then
+                    CONFIGFILE=$2
+                    shift 2
+                else
+                    usage
+                    exit 1
+                fi
+                ;;
+            *)
+                usage
+                exit 1
+        esac
+    done
+}
+
+function validate_args
+{
+    [ -z "$CONFIGFILE" ] && CONFIGFILE="/etc/lvm/lvm.conf"
+
+    if [ ! -f "$CONFIGFILE" ]
+            then
+            echo "$CONFIGFILE does not exist"
+            exit 10
+    fi
+
+    if [ -z "$LOCKING_TYPE" ]; then
+        usage
+        exit 1
+    fi
+
+    if [ "$LOCKING_TYPE" == "2" ]; then
+
+        [ -z "$LOCKINGLIBDIR" ] && usage && exit 1    
+        [ -z "$LOCKINGLIB" ] && LOCKINGLIB="liblvm2clusterlock.so"
+            
+        if [ "${LOCKINGLIBDIR:0:1}" != "/" ]
+            then
+            echo "Prefix must be an absolute path name (starting with a /)"
+            exit 12
+        fi
+    
+        if [ ! -f "$LOCKINGLIBDIR/$LOCKINGLIB" ]
+            then
+            echo "$LOCKINGLIBDIR/$LOCKINGLIB does not exist, did you do a \"make install\" ?"
+            exit 11
+        fi
+        
+    fi
+}
+
+umask 0077
+
+parse_args "$@"
+
+validate_args
+
+
+SCRIPTFILE=/etc/lvm/.lvmconf-script.tmp
+TMPFILE=/etc/lvm/.lvmconf-tmp.tmp
+
+
+# Flags so we know which parts of the file we can replace and which need
+# adding. These are return codes from grep, so zero means it IS present!
+have_type=1
+have_dir=1
+have_library=1
+have_global=1
+
+grep -q '^[[:blank:]]*locking_type[[:blank:]]*=' $CONFIGFILE
+have_type=$?
+
+grep -q '^[[:blank:]]*library_dir[[:blank:]]*=' $CONFIGFILE
+have_dir=$?
+
+grep -q '^[[:blank:]]*locking_library[[:blank:]]*=' $CONFIGFILE
+have_library=$?
+
+# Those options are in section "global {" so we must have one if any are present.
+if [ "$have_type" = "0" -o "$have_dir" = "0" -o "$have_library" = "0" ]
+then
+
+    # See if we can find it...
+    grep -q '^[[:blank:]]*global[[:blank:]]*{' $CONFIGFILE
+    have_global=$?
+    
+    if [ "$have_global" = "1" ] 
+	then
+	echo "global keys but no 'global {' found, can't edit file"
+	exit 12
+    fi
+fi
+
+# So if we don't have "global {" we need to create one and 
+# populate it
+
+if [ "$have_global" = "1" ]
+then
+    if [ "$LOCKING_TYPE" = "2" ]; then
+        cat $CONFIGFILE - <<EOF > $TMPFILE
+global {
+    # Enable locking for cluster LVM
+    locking_type = $LOCKING_TYPE
+    library_dir = "$LOCKINGLIBDIR"
+    locking_library = "$LOCKINGLIB"
+}
+EOF
+    fi # if we aren't setting cluster locking, we don't need to create a global section
+
+    if [ $? != 0 ]
+    then
+	echo "failed to create temporary config file, $CONFIGFILE not updated"
+	exit 1
+    fi
+else
+    #
+    # We have a "global {" section, so add or replace the
+    # 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"
+    fi
+    
+    if [ "$LOCKING_TYPE" = "2" ]; then
+        if [ "$have_dir" = "0" ] 
+            then
+            SEDCMD="${SEDCMD}\ns'^[[:blank:]]*library_dir[[:blank:]]*=.*'\ \ \ \ library_dir = \"$LOCKINGLIBDIR\"'g"
+        else
+            SEDCMD="${SEDCMD}\n/global[[:blank:]]*{/a\ \ \ \ library_dir = \"$LOCKINGLIBDIR\""
+        fi
+
+        if [ "$have_library" = "0" ] 
+            then
+            SEDCMD="${SEDCMD}\ns/^[[:blank:]]*locking_library[[:blank:]]*=.*/\ \ \ \ locking_library = \"$LOCKINGLIB\"/g"
+        else
+            SEDCMD="${SEDCMD}\n/global[[:blank:]]*{/a\ \ \ \ locking_library = \"$LOCKINGLIB\""
+        fi
+    else
+        # if we're not using cluster locking, remove the library dir and locking library name
+        if [ "$have_dir" = "0" ] 
+            then
+            SEDCMD="${SEDCMD}\n/^[[:blank:]]*library_dir[[:blank:]]*=.*/d"
+        fi
+
+        if [ "$have_library" = "0" ] 
+            then
+            SEDCMD="${SEDCMD}\n/^[[:blank:]]*locking_library[[:blank:]]*=.*/d"
+        fi
+    fi
+
+    echo -e $SEDCMD > $SCRIPTFILE
+    sed  <$CONFIGFILE >$TMPFILE -f $SCRIPTFILE
+    if [ $? != 0 ]
+    then
+	echo "sed failed, $CONFIGFILE not updated"
+	exit 1
+    fi
+fi
+
+# Now we have a suitably editted config file in a temp place,
+# backup the original and copy our new one into place.
+
+cp $CONFIGFILE $CONFIGFILE.lvmconfold
+if [ $? != 0 ]
+    then
+    echo "failed to backup old config file, $CONFIGFILE not updated"
+    exit 2
+fi
+
+cp $TMPFILE $CONFIGFILE
+if [ $? != 0 ]
+    then
+    echo "failed to copy new config file into place, check $CONFIGFILE is still OK"
+    exit 3
+fi
+
+rm -f $SCRIPTFILE $TMPFILE

Modified: lvm2/trunk/tools/Makefile.in
==============================================================================
--- lvm2/trunk/tools/Makefile.in	(original)
+++ lvm2/trunk/tools/Makefile.in	Tue Jun 14 11:23:47 2005
@@ -21,10 +21,10 @@
 endif
 
 lib_SOURCES =\
-	archiver.c \
 	dumpconfig.c \
 	formats.c \
 	lvchange.c \
+	lvconvert.c \
 	lvcreate.c \
 	lvdisplay.c \
 	lvextend.c \
@@ -96,6 +96,8 @@
 	LVMLIBS += -ldevmapper
 endif
 
+CFLAGS += -DLVM_SHARED_PATH=\"$(exec_prefix)/sbin/lvm\"
+
 include $(top_srcdir)/make.tmpl
 
 lvm: $(OBJECTS) $(top_srcdir)/lib/liblvm.a

Modified: lvm2/trunk/tools/args.h
==============================================================================
--- lvm2/trunk/tools/args.h	(original)
+++ lvm2/trunk/tools/args.h	Tue Jun 14 11:23:47 2005
@@ -59,6 +59,7 @@
 arg(background_ARG, 'b', "background", NULL)
 arg(blockdevice_ARG, 'b', "blockdevice", NULL)
 arg(chunksize_ARG, 'c', "chunksize", size_kb_arg)
+arg(clustered_ARG, 'c', "clustered", yes_no_arg)
 arg(colon_ARG, 'c', "colon", NULL)
 arg(columns_ARG, 'C', "columns", NULL)
 arg(contiguous_ARG, 'C', "contiguous", yes_no_arg)
@@ -84,6 +85,7 @@
 arg(logicalextent_ARG, 'L', "logicalextent", int_arg_with_sign)
 arg(persistent_ARG, 'M', "persistent", yes_no_arg)
 arg(major_ARG, 'j', "major", major_arg)
+arg(mirrors_ARG, 'm', "mirrors", int_arg)
 arg(metadatatype_ARG, 'M', "metadatatype", metadatatype_arg)
 arg(maps_ARG, 'm', "maps", NULL)
 arg(name_ARG, 'n', "name", string_arg)
@@ -99,6 +101,7 @@
 arg(readahead_ARG, 'r', "readahead", int_arg)
 arg(resizefs_ARG, 'r', "resizefs", NULL)
 arg(reset_ARG, 'R', "reset", NULL)
+arg(regionsize_ARG, 'R', "regionsize", size_mb_arg)
 arg(physicalextentsize_ARG, 's', "physicalextentsize", size_mb_arg)
 arg(stdin_ARG, 's', "stdin", NULL)
 arg(snapshot_ARG, 's', "snapshot", NULL)

Modified: lvm2/trunk/tools/commands.h
==============================================================================
--- lvm2/trunk/tools/commands.h	(original)
+++ lvm2/trunk/tools/commands.h	Tue Jun 14 11:23:47 2005
@@ -78,6 +78,19 @@
    persistent_ARG, readahead_ARG, refresh_ARG, addtag_ARG, deltag_ARG,
    test_ARG)
 
+xx(lvconvert,
+   "Change logical volume layout",
+   "lvconvert " "\n"
+   "\t[--alloc AllocationPolicy]\n"
+   "\t[-d|--debug]\n"
+   "\t[-h|-?|--help]\n"
+   "\t[-m|--mirrors Mirrors]\n"
+   "\t[-v|--verbose]\n"
+   "\t[--version]" "\n"
+   "\tLogicalVolume[Path] [LogicalVolume[Path]...]\n",
+
+   alloc_ARG, mirrors_ARG, test_ARG)
+
 xx(lvcreate,
    "Create a logical volume",
    "lvcreate " "\n"
@@ -91,9 +104,11 @@
    "\t{-l|--extents LogicalExtentsNumber |\n"
    "\t -L|--size LogicalVolumeSize[kKmMgGtT]}\n"
    "\t[-M|--persistent {y|n}] [--major major] [--minor minor]\n"
+   "\t[-m|--mirrors Mirrors]\n"
    "\t[-n|--name LogicalVolumeName]\n"
    "\t[-p|--permission {r|rw}]\n"
    "\t[-r|--readahead ReadAheadSectors]\n"
+   "\t[-R|--regionsize MirrorLogRegionSize]\n"
    "\t[-t|--test]\n"
    "\t[--type VolumeType]\n"
    "\t[-v|--verbose]\n"
@@ -122,13 +137,14 @@
    "\tOriginalLogicalVolume[Path] [PhysicalVolumePath...]\n\n",
 
    addtag_ARG, alloc_ARG, autobackup_ARG, chunksize_ARG, contiguous_ARG,
-   extents_ARG, major_ARG, minor_ARG, name_ARG, permission_ARG,
-   persistent_ARG, readahead_ARG, size_ARG, snapshot_ARG, stripes_ARG,
-   stripesize_ARG, test_ARG, type_ARG, zero_ARG)
+   extents_ARG, major_ARG, minor_ARG, mirrors_ARG, name_ARG, permission_ARG,
+   persistent_ARG, readahead_ARG, regionsize_ARG, size_ARG, snapshot_ARG,
+   stripes_ARG, stripesize_ARG, test_ARG, type_ARG, zero_ARG)
 
 xx(lvdisplay,
    "Display information about a logical volume",
    "lvdisplay\n"
+   "\t[-a|--all]\n"
    "\t[-c|--colon]\n"
    "\t[-d|--debug]\n"
    "\t[-h|--help]\n"
@@ -143,6 +159,7 @@
    "\n"
    "lvdisplay --columns|-C\n"
    "\t[--aligned]\n"
+   "\t[-a|--all]\n"
    "\t[-d|--debug]\n"
    "\t[-h|--help]\n"
    "\t[--ignorelockingfailure]\n"
@@ -159,9 +176,10 @@
    "\t[--version]" "\n"
    "\t[LogicalVolume[Path] [LogicalVolume[Path]...]]\n",
 
-    aligned_ARG, colon_ARG, columns_ARG, disk_ARG, ignorelockingfailure_ARG,
-    maps_ARG, noheadings_ARG, nosuffix_ARG, options_ARG, sort_ARG,
-    partial_ARG, segments_ARG, separator_ARG, unbuffered_ARG, units_ARG)
+    aligned_ARG, all_ARG, colon_ARG, columns_ARG, disk_ARG,
+    ignorelockingfailure_ARG, maps_ARG, noheadings_ARG, nosuffix_ARG,
+    options_ARG, sort_ARG, partial_ARG, segments_ARG, separator_ARG,
+    unbuffered_ARG, units_ARG)
 
 xx(lvextend,
    "Add space to a logical volume",
@@ -173,6 +191,7 @@
    "\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n"
    "\t{-l|--extents [+]LogicalExtentsNumber |\n"
    "\t -L|--size [+]LogicalVolumeSize[kKmMgGtT]}\n"
+   "\t[-m|--mirrors Mirrors]\n"
    "\t[-n|--nofsck]\n"
    "\t[-r|--resizefs]\n"
    "\t[-t|--test]\n"
@@ -181,8 +200,9 @@
    "\t[--version]" "\n"
    "\tLogicalVolume[Path] [ PhysicalVolumePath... ]\n",
 
-   alloc_ARG, autobackup_ARG, extents_ARG, nofsck_ARG, resizefs_ARG,
-   size_ARG, stripes_ARG, stripesize_ARG, test_ARG, type_ARG)
+   alloc_ARG, autobackup_ARG, extents_ARG, mirrors_ARG, nofsck_ARG,
+   resizefs_ARG, size_ARG, stripes_ARG, stripesize_ARG, test_ARG,
+   type_ARG)
 
 xx(lvmchange,
    "With the device mapper, this is obsolete and does nothing.",
@@ -298,6 +318,7 @@
 xx(lvs,
    "Display information about logical volumes",
    "lvs" "\n"
+   "\t[-a|--all]\n"
    "\t[--aligned]\n"
    "\t[-d|--debug]\n"
    "\t[-h|--help]\n"
@@ -315,9 +336,9 @@
    "\t[--version]" "\n"
    "\t[LogicalVolume[Path] [LogicalVolume[Path]...]]\n",
    
-   aligned_ARG, ignorelockingfailure_ARG, noheadings_ARG, nolocking_ARG,
-   nosuffix_ARG, options_ARG, partial_ARG, segments_ARG, separator_ARG,
-   sort_ARG, unbuffered_ARG, units_ARG)
+   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)
 
 xx(lvscan,
    "List all logical volumes in all volume groups",
@@ -410,6 +431,7 @@
    "\n"
    "pvdisplay --columns|-C\n"
    "\t[--aligned]\n"
+   "\t[-a|--all]\n"
    "\t[-d|--debug]\n"
    "\t[-h|--help]\n"
    "\t[--ignorelockingfailure]\n"
@@ -424,9 +446,9 @@
    "\t[--version]" "\n"
    "\t[PhysicalVolumePath [PhysicalVolumePath...]]\n",
 
-   aligned_ARG, colon_ARG, columns_ARG, ignorelockingfailure_ARG, maps_ARG,
-   noheadings_ARG, nosuffix_ARG, options_ARG, separator_ARG, short_ARG,
-   sort_ARG, unbuffered_ARG, units_ARG)
+   aligned_ARG, all_ARG, colon_ARG, columns_ARG, ignorelockingfailure_ARG,
+   maps_ARG, noheadings_ARG, nosuffix_ARG, options_ARG, separator_ARG,
+   short_ARG, sort_ARG, unbuffered_ARG, units_ARG)
 
 xx(pvmove,
    "Move extents from one physical volume to another",
@@ -475,6 +497,7 @@
    "\t[--nosuffix]\n"
    "\t[-o|--options [+]Field[,Field]]\n"
    "\t[-O|--sort [+|-]key1[,[+|-]key2[,...]]]\n"
+   "\t[--segments]\n"
    "\t[--separator Separator]\n"
    "\t[--unbuffered]\n"
    "\t[--units hsbkmgtHKMGT]\n"
@@ -483,8 +506,8 @@
    "\t[PhysicalVolume [PhysicalVolume...]]\n",
    
    aligned_ARG, all_ARG, ignorelockingfailure_ARG, noheadings_ARG,
-   nolocking_ARG, nosuffix_ARG, options_ARG, separator_ARG, sort_ARG,
-   unbuffered_ARG, units_ARG)
+   nolocking_ARG, nosuffix_ARG, options_ARG, segments_ARG, separator_ARG,
+   sort_ARG, unbuffered_ARG, units_ARG)
 
 xx(pvscan,
    "List all physical volumes",
@@ -550,15 +573,18 @@
    "\t[-v|--verbose] " "\n"
    "\t[--version]" "\n"
    "\t{-a|--available [e|l]{y|n}  |" "\n"
+   "\t -c|--clustered {y|n} |" "\n"
    "\t -x|--resizeable {y|n} |" "\n"
    "\t -l|--logicalvolume MaxLogicalVolumes |" "\n"
+   "\t -s|--physicalextentsize PhysicalExtentSize[kKmMgGtT] |" "\n"
    "\t --addtag Tag |\n"
    "\t --deltag Tag}\n"
    "\t[VolumeGroupName...]\n",
 
    addtag_ARG, alloc_ARG, allocation_ARG, autobackup_ARG, available_ARG,
-   deltag_ARG, ignorelockingfailure_ARG, logicalvolume_ARG, partial_ARG,
-   resizeable_ARG, resizable_ARG, test_ARG, uuid_ARG)
+   clustered_ARG, deltag_ARG, ignorelockingfailure_ARG, logicalvolume_ARG,
+   partial_ARG, physicalextentsize_ARG, resizeable_ARG, resizable_ARG,
+   test_ARG, uuid_ARG)
 
 xx(vgck,
    "Check the consistency of volume group(s)",
@@ -592,6 +618,7 @@
    "\t[-A|--autobackup {y|n}] " "\n"
    "\t[--addtag Tag] " "\n"
    "\t[--alloc AllocationPolicy] " "\n"
+   "\t[-c|--clustered] " "\n"
    "\t[-d|--debug]" "\n"
    "\t[-h|--help]" "\n"
    "\t[-l|--maxlogicalvolumes MaxLogicalVolumes]" "\n"
@@ -603,7 +630,7 @@
    "\t[--version] " "\n"
    "\tVolumeGroupName PhysicalVolume [PhysicalVolume...]\n",
 
-   addtag_ARG, alloc_ARG, autobackup_ARG, maxlogicalvolumes_ARG,
+   addtag_ARG, alloc_ARG, autobackup_ARG, clustered_ARG, maxlogicalvolumes_ARG,
    maxphysicalvolumes_ARG, metadatatype_ARG, physicalextentsize_ARG, test_ARG)
 
 xx(vgdisplay,
@@ -699,9 +726,12 @@
    "vgmknodes\n"
    "\t[-d|--debug]\n"
    "\t[-h|--help]\n"
+   "\t[--ignorelockingfailure]\n"
    "\t[-v|--verbose]\n"
    "\t[--version]" "\n"
-   "\t[VolumeGroupName...]\n" )
+   "\t[VolumeGroupName...]\n",
+
+   ignorelockingfailure_ARG)
 
 xx(vgreduce,
    "Remove physical volume(s) from a volume group",
@@ -749,6 +779,7 @@
    "Display information about volume groups",
    "vgs" "\n"
    "\t[--aligned]\n"
+   "\t[-a|--all]\n"
    "\t[-d|--debug]\n"
    "\t[-h|--help]\n"
    "\t[--ignorelockingfailure]\n"
@@ -764,9 +795,9 @@
    "\t[--version]\n"
    "\t[VolumeGroupName [VolumeGroupName...]]\n",
    
-   aligned_ARG, ignorelockingfailure_ARG, noheadings_ARG, nolocking_ARG,
-   nosuffix_ARG, options_ARG, partial_ARG, separator_ARG, sort_ARG,
-   unbuffered_ARG, units_ARG)
+   aligned_ARG, all_ARG, ignorelockingfailure_ARG, noheadings_ARG,
+   nolocking_ARG, nosuffix_ARG, options_ARG, partial_ARG, separator_ARG,
+   sort_ARG, unbuffered_ARG, units_ARG)
 
 xx(vgscan,
    "Search for all volume groups",

Modified: lvm2/trunk/tools/lvchange.c
==============================================================================
--- lvm2/trunk/tools/lvchange.c	(original)
+++ lvm2/trunk/tools/lvchange.c	Tue Jun 14 11:23:47 2005
@@ -94,6 +94,12 @@
 			return 0;
 		}
 	} else {
+		if (lockingfailed() && (lv->vg->status & CLUSTERED)) {
+                	log_verbose("Locking failed: ignoring clustered "
+				    "logical volume %s", lv->name);
+                	return 0;
+        	}
+
 		if (lv_is_origin(lv) || (activate == CHANGE_AE)) {
 			log_verbose("Activating logical volume \"%s\" "
 				    "exclusively", lv->name);
@@ -361,6 +367,7 @@
 
 	return 1;
 }
+
 static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
 			   void *handle)
 {
@@ -398,6 +405,23 @@
 		return ECMD_FAILED;
 	}
 
+	if (lv->status & MIRROR_LOG) {
+		log_error("Unable to change mirror log LV %s directly", lv->name);
+		return ECMD_FAILED;
+	}
+
+	if (lv->status & MIRROR_IMAGE) {
+		log_error("Unable to change mirror image LV %s directly",
+			  lv->name);
+		return ECMD_FAILED;
+	}
+
+	if (!(lv->status & VISIBLE_LV)) {
+		log_error("Unable to change internal LV %s directly",
+			  lv->name);
+		return ECMD_FAILED;
+	}
+
 	/* access permission change */
 	if (arg_count(cmd, permission_ARG)) {
 		if (!archive(lv->vg))

Added: lvm2/trunk/tools/lvconvert.c
==============================================================================
--- (empty file)
+++ lvm2/trunk/tools/lvconvert.c	Tue Jun 14 11:23:47 2005
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 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
+ */
+
+#include "tools.h"
+
+struct lvconvert_params {
+	struct list *pvh;
+};
+
+static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * lv,
+			     struct list *allocatable_pvs)
+{
+	struct lv_segment *first_seg;
+	uint32_t mirrors, existing_mirrors;
+	alloc_policy_t alloc = ALLOC_INHERIT;
+	// struct alloc_handle *ah = NULL;
+	// struct logical_volume *log_lv;
+
+	if (arg_count(cmd, alloc_ARG))
+		alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, alloc);
+
+	mirrors = arg_uint_value(cmd, mirrors_ARG, 0) + 1;
+
+	if ((mirrors == 1)) {
+		if (!(lv->status & MIRRORED)) {
+			log_error("Logical volume %s is already not mirrored.",
+				  lv->name);
+			return 1;
+		}
+		/* FIXME If allocatable_pvs supplied only remove those */
+		if (!remove_all_mirror_images(lv)) {
+			stack;
+			return 0;
+		}
+	} else {		/* mirrors > 1 */
+		if ((lv->status & MIRRORED)) {
+			if (list_size(&lv->segments) != 1) {
+				log_error("Logical volume %s has multiple "
+					  "mirror segments.", lv->name);
+				return 0;
+			}
+			list_iterate_items(first_seg, &lv->segments)
+				break;
+			existing_mirrors = first_seg->area_count;
+			if (mirrors == existing_mirrors) {
+				log_error("Logical volume %s already has %"
+					  PRIu32 " mirror(s).", lv->name,
+					  mirrors - 1);
+				return 1;
+			}
+			if (mirrors > existing_mirrors) {
+				/* FIXME Unless anywhere, remove PV of log_lv 
+				 * from allocatable_pvs & allocate 
+				 * (mirrors - existing_mirrors) new areas
+				 */
+				/* FIXME Create mirror hierarchy to sync */
+				log_error("Adding mirror images is not "
+					  "supported yet.");
+				return 0;
+			} else {
+				if (!remove_mirror_images(first_seg, mirrors)) {
+					stack;
+					return 0;
+				}
+			}
+		} else {
+			/* FIXME Share code with lvcreate */
+			/* region size, log_name, create log_lv, zero it */
+			// Allocate (mirrors) new areas & log - replace mirrored_pv with mirrored_lv
+			// Restructure as mirror - add existing param to create_mirror_layers
+			log_error("Adding mirror images is not supported yet.");
+			return 0;
+		}
+	}
+
+	log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
+
+	if (!vg_write(lv->vg)) {
+		stack;
+		return 0;
+	}
+
+	backup(lv->vg);
+
+	if (!suspend_lv(cmd, lv->lvid.s)) {
+		log_error("Failed to lock %s", lv->name);
+		vg_revert(lv->vg);
+		return 0;
+	}
+
+	if (!vg_commit(lv->vg)) {
+		resume_lv(cmd, lv->lvid.s);
+		return 0;
+	}
+
+	log_very_verbose("Updating \"%s\" in kernel", lv->name);
+
+	if (!resume_lv(cmd, lv->lvid.s)) {
+		log_error("Problem reactivating %s", lv->name);
+		return 0;
+	}
+
+	log_print("Logical volume %s converted.", lv->name);
+
+	return 1;
+}
+
+static int lvconvert_single(struct cmd_context * cmd, struct logical_volume * lv,
+			     int argc, char **argv, void *handle)
+{
+	struct lvconvert_params *lp = handle;
+
+	if (lv->status & LOCKED) {
+		log_error("Cannot convert locked LV %s", lv->name);
+		return ECMD_FAILED;
+	}
+
+	if (lv_is_origin(lv)) {
+		log_error("Can't convert logical volume \"%s\" under snapshot",
+			  lv->name);
+		return ECMD_FAILED;
+	}
+
+	if (lv_is_cow(lv)) {
+		log_error("Can't convert snapshot logical volume \"%s\"",
+			  lv->name);
+		return ECMD_FAILED;
+	}
+
+	if (lv->status & PVMOVE) {
+		log_error("Unable to convert pvmove LV %s", lv->name);
+		return ECMD_FAILED;
+	}
+
+	if (arg_count(cmd, mirrors_ARG)) {
+		if (!archive(lv->vg))
+			return ECMD_FAILED;
+		if (!lvconvert_mirrors(cmd, lv, lp->pvh))
+			return ECMD_FAILED;
+	}
+
+	return ECMD_PROCESSED;
+}
+
+int lvconvert(struct cmd_context * cmd, int argc, char **argv)
+{
+	const char *vg_name, *lv_name;
+	char *st;
+	int consistent = 1;
+	struct volume_group *vg;
+	struct lv_list *lvl;
+	struct lvconvert_params lp;
+	int ret = ECMD_FAILED;
+
+	if (!arg_count(cmd, mirrors_ARG)) {
+		log_error("--mirrors argument required");
+		return EINVALID_CMD_LINE;
+	}
+
+	if (!argc) {
+		log_error("Please give logical volume path(s)");
+		return EINVALID_CMD_LINE;
+	}
+
+	lv_name = argv[0];
+	argv++, argc--;
+
+	vg_name = extract_vgname(cmd, lv_name);
+
+	if (!validate_name(vg_name)) {
+		log_error("Please provide a valid volume group name");
+		return EINVALID_CMD_LINE;
+	}
+
+	if ((st = strrchr(lv_name, '/')))
+		lv_name = st + 1;
+
+	log_verbose("Checking for existing volume group \"%s\"", vg_name);
+
+	if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) {
+		log_error("Can't get lock for %s", vg_name);
+		return ECMD_FAILED;
+	}
+
+	if (!(vg = vg_read(cmd, vg_name, &consistent))) {
+		log_error("Volume group \"%s\" doesn't exist", vg_name);
+		goto error;
+	}
+
+	if (vg->status & EXPORTED_VG) {
+		log_error("Volume group \"%s\" is exported", vg_name);
+		goto error;
+	}
+
+	if (!(vg->status & LVM_WRITE)) {
+		log_error("Volume group \"%s\" is read-only", vg_name);
+		goto error;
+	}
+
+	if (!(lvl = find_lv_in_vg(vg, lv_name))) {
+		log_error("Logical volume \"%s\" not found in "
+			  "volume group \"%s\"", lv_name, vg_name);
+		goto error;
+	}
+
+	if (argc) {
+		if (!(lp.pvh = create_pv_list(cmd->mem, vg, argc, argv, 1))) {
+			stack;
+			goto error;
+		}
+	} else
+		lp.pvh = &vg->pvs;
+
+	ret = lvconvert_single(cmd, lvl->lv, argc, argv, &lp);
+
+error:
+	unlock_vg(cmd, vg_name);
+	return ret;
+}

Modified: lvm2/trunk/tools/lvcreate.c
==============================================================================
--- lvm2/trunk/tools/lvcreate.c	(original)
+++ lvm2/trunk/tools/lvcreate.c	Tue Jun 14 11:23:47 2005
@@ -14,6 +14,7 @@
  */
 
 #include "tools.h"
+#include "lv_alloc.h"
 
 #include <fcntl.h>
 
@@ -31,6 +32,7 @@
 	uint32_t stripes;
 	uint32_t stripe_size;
 	uint32_t chunk_size;
+	uint32_t region_size;
 
 	uint32_t mirrors;
 
@@ -135,10 +137,8 @@
 		if ((ptr = strrchr(lp->lv_name, '/')))
 			lp->lv_name = ptr + 1;
 
-		/* FIXME Remove this restriction eventually */
-		if (!strncmp(lp->lv_name, "snapshot", 8)) {
-			log_error("Names starting \"snapshot\" are reserved. "
-				  "Please choose a different LV name.");
+		if (!apply_lvname_restrictions(lp->lv_name)) {
+			stack;
 			return 0;
 		}
 
@@ -228,6 +228,38 @@
 	return 1;
 }
 
+static int _read_mirror_params(struct lvcreate_params *lp,
+			       struct cmd_context *cmd,
+			       int *pargc, char ***pargv)
+{
+	int argc = *pargc;
+
+	if (argc && (unsigned) argc < lp->mirrors) {
+		log_error("Too few physical volumes on "
+			  "command line for %d-way mirroring", lp->mirrors);
+		return 0;
+	}
+
+	if (arg_count(cmd, regionsize_ARG)) {
+		if (arg_sign_value(cmd, regionsize_ARG, 0) == SIGN_MINUS) {
+			log_error("Negative regionsize is invalid");
+			return 0;
+		}
+		lp->region_size = 2 * arg_uint_value(cmd, regionsize_ARG, 0);
+	} else
+		lp->region_size = 2 * find_config_int(cmd->cft->root,
+					"activation/mirror_region_size",
+					DEFAULT_MIRROR_REGION_SIZE);
+
+	if (lp->region_size & (lp->region_size - 1)) {
+		log_error("Region size (%" PRIu32 ") must be a power of 2",
+			  lp->region_size);
+		return 0;
+	}
+
+	return 1;
+}
+
 static int _read_params(struct lvcreate_params *lp, struct cmd_context *cmd,
 			int argc, char **argv)
 {
@@ -246,9 +278,21 @@
 	if (arg_count(cmd, stripes_ARG) && lp->stripes == 1)
 		log_print("Redundant stripes argument: default is 1");
 
-	if (arg_count(cmd, snapshot_ARG) || (lp->segtype->flags & SEG_SNAPSHOT))
+	if (arg_count(cmd, snapshot_ARG) || seg_is_snapshot(lp))
 		lp->snapshot = 1;
 
+	lp->mirrors = 1;
+
+	/* Default to 2 mirrored areas if --type mirror */
+	if (seg_is_mirrored(lp))
+		lp->mirrors = 2;
+
+	if (arg_count(cmd, mirrors_ARG)) {
+		lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0) + 1;
+		if (lp->mirrors == 1)
+			log_print("Redundant mirrors argument: default is 0");
+	}
+
 	if (lp->snapshot) {
 		if (arg_count(cmd, zero_ARG)) {
 			log_error("-Z is incompatible with snapshots");
@@ -272,6 +316,25 @@
 		}
 	}
 
+	if (lp->mirrors > 1) {
+		if (lp->snapshot) {
+			log_error("mirrors and snapshots are currently "
+				  "incompatible");
+			return 0;
+		}
+
+		if (lp->stripes > 1) {
+			log_error("mirrors and stripes are currently "
+				  "incompatible");
+			return 0;
+		}
+
+		if (!(lp->segtype = get_segtype_from_string(cmd, "mirror"))) {
+			stack;
+			return 0;
+		}
+	}
+
 	if (activation() && lp->segtype->ops->target_present &&
 	    !lp->segtype->ops->target_present()) {
 		log_error("%s: Required device-mapper target(s) not "
@@ -281,8 +344,11 @@
 
 	if (!_read_name_params(lp, cmd, &argc, &argv) ||
 	    !_read_size_params(lp, cmd, &argc, &argv) ||
-	    !_read_stripe_params(lp, cmd, &argc, &argv))
+	    !_read_stripe_params(lp, cmd, &argc, &argv) ||
+	    !_read_mirror_params(lp, cmd, &argc, &argv)) {
+		stack;
 		return 0;
+	}
 
 	/*
 	 * Should we zero the lv.
@@ -392,14 +458,18 @@
 
 static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
 {
-	uint32_t size_rest;
+	uint32_t size_rest, region_max;
 	uint32_t status = 0;
 	uint64_t tmp_size;
 	struct volume_group *vg;
-	struct logical_volume *lv, *org = NULL;
+	struct logical_volume *lv, *org = NULL, *log_lv = NULL;
 	struct list *pvh;
 	const char *tag;
 	int consistent = 1;
+	struct alloc_handle *ah = NULL;
+	char *log_name, lv_name_buf[128];
+	const char *lv_name;
+	size_t len;
 
 	status |= lp->permission | VISIBLE_LV;
 
@@ -427,6 +497,11 @@
 		return 0;
 	}
 
+	if (lp->mirrors && !(vg->fid->fmt->features & FMT_SEGMENTS)) {
+		log_error("Metadata does not support mirroring.");
+		return 0;
+	}
+
 	/*
 	 * Create the pv list.
 	 */
@@ -498,32 +573,139 @@
 		return 0;
 	}
 
-	if (!(lp->segtype->flags & SEG_VIRTUAL) &&
+	if (!seg_is_virtual(lp) &&
 	    vg->free_count < lp->extents) {
 		log_error("Insufficient free extents (%u) in volume group %s: "
 			  "%u required", vg->free_count, vg->name, lp->extents);
 		return 0;
 	}
 
-	if (lp->stripes > list_size(pvh)) {
+	if (lp->stripes > list_size(pvh) && lp->alloc != ALLOC_ANYWHERE) {
 		log_error("Number of stripes (%u) must not exceed "
 			  "number of physical volumes (%d)", lp->stripes,
 			  list_size(pvh));
 		return 0;
 	}
 
-	if (!(lv = lv_create_empty(vg->fid, lp->lv_name, "lvol%d",
-				   status, lp->alloc, vg))) {
-		stack;
+	if (lp->mirrors > 1 && !activation()) {
+		log_error("Can't create mirror without using "
+			  "device-mapper kernel driver.");
 		return 0;
 	}
 
-	if (!lv_extend(vg->fid, lv, lp->segtype, lp->stripes, lp->stripe_size,
-		       lp->mirrors, lp->extents, NULL, 0u, 0u, pvh, lp->alloc)) {
+	/* The snapshot segment gets created later */
+	if (lp->snapshot &&
+	    !(lp->segtype = get_segtype_from_string(cmd, "striped"))) {
 		stack;
 		return 0;
 	}
 
+	if (!archive(vg))
+		return 0;
+
+	if (lp->lv_name)
+		lv_name = lp->lv_name;
+	else {
+		if (!generate_lv_name(vg, "lvol%d", lv_name_buf, sizeof(lv_name_buf))) {
+			log_error("Failed to generate LV name.");
+			return 0;
+		}
+		lv_name = &lv_name_buf[0];
+	}
+
+	if (lp->mirrors > 1) {
+		/* FIXME Adjust lp->region_size if necessary */
+		region_max = (1 << (ffs(lp->extents) - 1)) * vg->extent_size;
+
+		if (region_max < lp->region_size) {
+			lp->region_size = region_max;
+			log_print("Using reduced mirror region size of %" PRIu32
+				  " sectors", lp->region_size);
+		}
+
+		/* FIXME Calculate how many extents needed for the log */
+
+		len = strlen(lv_name) + 32;
+        	if (!(log_name = alloca(len))) {
+                	log_error("log_name allocation failed. "
+	                          "Remove new LV and retry.");
+                	return 0;
+        	}
+
+        	if (lvm_snprintf(log_name, len, "%s_mlog", lv_name) < 0) {
+                	log_error("log_name allocation failed. "
+	                          "Remove new LV and retry.");
+                	return 0;
+        	}
+
+		if (find_lv_in_vg(vg, log_name)) {
+        		if (lvm_snprintf(log_name, len, "%s_mlog_%%d",
+					 lv_name) < 0) {
+                		log_error("log_name allocation failed. "
+					  "Remove new LV and retry.");
+                		return 0;
+        		}
+		}
+ 
+		if (!(log_lv = lv_create_empty(vg->fid, log_name, NULL,
+				VISIBLE_LV | LVM_READ | LVM_WRITE,
+				lp->alloc, 0, vg))) {
+			stack;
+			return 0;
+		}
+
+		if (!(ah = allocate_extents(vg, NULL, lp->segtype, lp->stripes,
+					    lp->mirrors, 1, lp->extents,
+					    NULL, 0, 0, pvh, lp->alloc))) {
+			stack;
+			return 0;
+		}
+
+		if (!lv_add_log_segment(ah, log_lv)) {
+			stack;
+			goto error;
+		}
+
+		/* store mirror log on disk(s) */
+		if (!vg_write(vg)) {
+			stack;
+			goto error;
+		}
+
+		backup(vg);
+
+		if (!vg_commit(vg)) {
+			stack;
+			goto error;
+		}
+
+		if (!activate_lv(cmd, log_lv->lvid.s)) {
+			log_error("Aborting. Failed to activate mirror log. "
+				  "Remove new LVs and retry.");
+			goto error;
+		}
+
+		if (activation() && !_zero_lv(cmd, log_lv)) {
+			log_error("Aborting. Failed to wipe mirror log. "
+				  "Remove new LV and retry.");
+			goto error;
+		}
+
+		if (!deactivate_lv(cmd, log_lv->lvid.s)) {
+			log_error("Aborting. Failed to deactivate mirror log. "
+				  "Remove new LV and retry.");
+			goto error;
+		}
+
+		log_lv->status &= ~VISIBLE_LV;
+	}
+
+	if (!(lv = lv_create_empty(vg->fid, lv_name ? lv_name : "lvol%d", NULL,
+				   status, lp->alloc, 0, vg))) {
+		stack;
+		goto error;
+	}
+
 	if (lp->read_ahead) {
 		log_verbose("Setting read ahead sectors");
 		lv->read_ahead = lp->read_ahead;
@@ -540,24 +722,37 @@
 	if (arg_count(cmd, addtag_ARG)) {
 		if (!(tag = arg_str_value(cmd, addtag_ARG, NULL))) {
 			log_error("Failed to get tag");
-			return 0;
+			goto error;
 		}
 
 		if (!(lv->vg->fid->fmt->features & FMT_TAGS)) {
 			log_error("Volume group %s does not support tags",
 				  lv->vg->name);
-			return 0;
+			goto error;
 		}
 
 		if (!str_list_add(cmd->mem, &lv->tags, tag)) {
 			log_error("Failed to add tag %s to %s/%s",
 				  tag, lv->vg->name, lv->name);
-			return 0;
+			goto error;
 		}
 	}
 
-	if (!archive(vg))
+	if (lp->mirrors > 1) {
+		if (!create_mirror_layers(ah, 0, lp->mirrors, lv,
+					  lp->segtype, 0,
+					  lp->region_size, log_lv)) {
+			stack;
+			goto error;
+		}
+
+		alloc_destroy(ah);
+		ah = NULL;
+	} else if (!lv_extend(lv, lp->segtype, lp->stripes, lp->stripe_size,
+		       lp->mirrors, lp->extents, NULL, 0u, 0u, pvh, lp->alloc)) {
+		stack;
 		return 0;
+	}
 
 	/* store vg on disk(s) */
 	if (!vg_write(vg)) {
@@ -609,8 +804,8 @@
 			return 0;
 		}
 
-		if (!vg_add_snapshot(org, lv, 1, NULL, org->le_count,
-				     lp->chunk_size)) {
+		if (!vg_add_snapshot(vg->fid, NULL, org, lv, NULL,
+				     org->le_count, lp->chunk_size)) {
 			log_err("Couldn't create snapshot.");
 			return 0;
 		}
@@ -635,6 +830,11 @@
 	 */
 
 	return 1;
+
+error:
+	if (ah)
+		alloc_destroy(ah);
+	return 0;
 }
 
 int lvcreate(struct cmd_context *cmd, int argc, char **argv)

Modified: lvm2/trunk/tools/lvdisplay.c
==============================================================================
--- lvm2/trunk/tools/lvdisplay.c	(original)
+++ lvm2/trunk/tools/lvdisplay.c	Tue Jun 14 11:23:47 2005
@@ -18,6 +18,9 @@
 static int _lvdisplay_single(struct cmd_context *cmd, struct logical_volume *lv,
 			     void *handle)
 {
+	if (!arg_count(cmd, all_ARG) && !(lv->status & VISIBLE_LV))
+		return ECMD_PROCESSED;
+
 	if (arg_count(cmd, colon_ARG))
 		lvdisplay_colons(lv);
 	else {

Added: lvm2/trunk/tools/lvm-static.c
==============================================================================
--- (empty file)
+++ lvm2/trunk/tools/lvm-static.c	Tue Jun 14 11:23:47 2005
@@ -0,0 +1,21 @@
+/*
+ * 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 "lvm2cmdline.h"
+
+int main(int argc, char **argv)
+{
+	return lvm2_main(argc, argv, 1);
+}

Modified: lvm2/trunk/tools/lvm.c
==============================================================================
--- lvm2/trunk/tools/lvm.c	(original)
+++ lvm2/trunk/tools/lvm.c	Tue Jun 14 11:23:47 2005
@@ -17,5 +17,5 @@
 
 int main(int argc, char **argv)
 {
-	return lvm2_main(argc, argv);
+	return lvm2_main(argc, argv, 0);
 }

Modified: lvm2/trunk/tools/lvm2cmdline.h
==============================================================================
--- lvm2/trunk/tools/lvm2cmdline.h	(original)
+++ lvm2/trunk/tools/lvm2cmdline.h	Tue Jun 14 11:23:47 2005
@@ -16,6 +16,6 @@
 #ifndef _LVM_CMDLINE_H
 #define _LVM_CMDLINE_H
 
-int lvm2_main(int argc, char **argv);
+int lvm2_main(int argc, char **argv, int is_static);
 
 #endif

Modified: lvm2/trunk/tools/lvmcmdline.c
==============================================================================
--- lvm2/trunk/tools/lvmcmdline.c	(original)
+++ lvm2/trunk/tools/lvmcmdline.c	Tue Jun 14 11:23:47 2005
@@ -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), 0, NULL},
 #include "args.h"
 #undef arg
 
@@ -753,12 +753,13 @@
 	init_debug(cmd->current_settings.debug);
 	init_verbose(cmd->current_settings.verbose + VERBOSE_BASE_LEVEL);
 	init_test(cmd->current_settings.test);
+	init_full_scan_done(0);
 
 	init_msg_prefix(cmd->default_settings.msg_prefix);
 	init_cmd_name(cmd->default_settings.cmd_name);
 
-	archive_enable(cmd->current_settings.archive);
-	backup_enable(cmd->current_settings.backup);
+	archive_enable(cmd, cmd->current_settings.archive);
+	backup_enable(cmd, cmd->current_settings.backup);
 
 	set_activation(cmd->current_settings.activation);
 
@@ -911,73 +912,11 @@
 	srand((unsigned int) time(NULL) + (unsigned int) getpid());
 }
 
-static int _init_backup(struct cmd_context *cmd, struct config_tree *cft)
-{
-	uint32_t days, min;
-	char default_dir[PATH_MAX];
-	const char *dir;
-
-	if (!cmd->sys_dir) {
-		log_warn("WARNING: Metadata changes will NOT be backed up");
-		backup_init("");
-		archive_init("", 0, 0);
-		return 1;
-	}
-
-	/* set up archiving */
-	cmd->default_settings.archive =
-	    find_config_bool(cmd->cft->root, "backup/archive",
-			     DEFAULT_ARCHIVE_ENABLED);
-
-	days = (uint32_t) find_config_int(cmd->cft->root, "backup/retain_days",
-					  DEFAULT_ARCHIVE_DAYS);
-
-	min = (uint32_t) find_config_int(cmd->cft->root, "backup/retain_min",
-					 DEFAULT_ARCHIVE_NUMBER);
-
-	if (lvm_snprintf
-	    (default_dir, sizeof(default_dir), "%s/%s", cmd->sys_dir,
-	     DEFAULT_ARCHIVE_SUBDIR) == -1) {
-		log_err("Couldn't create default archive path '%s/%s'.",
-			cmd->sys_dir, DEFAULT_ARCHIVE_SUBDIR);
-		return 0;
-	}
-
-	dir = find_config_str(cmd->cft->root, "backup/archive_dir",
-			      default_dir);
-
-	if (!archive_init(dir, days, min)) {
-		log_debug("backup_init failed.");
-		return 0;
-	}
-
-	/* set up the backup */
-	cmd->default_settings.backup =
-	    find_config_bool(cmd->cft->root, "backup/backup",
-			     DEFAULT_BACKUP_ENABLED);
-
-	if (lvm_snprintf
-	    (default_dir, sizeof(default_dir), "%s/%s", cmd->sys_dir,
-	     DEFAULT_BACKUP_SUBDIR) == -1) {
-		log_err("Couldn't create default backup path '%s/%s'.",
-			cmd->sys_dir, DEFAULT_BACKUP_SUBDIR);
-		return 0;
-	}
-
-	dir = find_config_str(cmd->cft->root, "backup/backup_dir", default_dir);
-
-	if (!backup_init(dir)) {
-		log_debug("backup_init failed.");
-		return 0;
-	}
-
-	return 1;
-}
-
 static void _close_stray_fds(void)
 {
 	struct rlimit rlim;
 	int fd;
+	int suppress_warnings = 0;
 
 	if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
 		fprintf(stderr, "getrlimit(RLIMIT_NOFILE) failed: %s\n",
@@ -985,8 +924,13 @@
 		return;
 	}
 
+	if (getenv("LVM_SUPPRESS_FD_WARNINGS"))
+		suppress_warnings = 1;
+
 	for (fd = 3; fd < rlim.rlim_cur; fd++) {
-		if (!close(fd))
+		if (suppress_warnings)
+			close(fd);
+		else if (!close(fd))
 			fprintf(stderr, "File descriptor %d left open\n", fd);
 		else if (errno != EBADF)
 			fprintf(stderr, "Close failed on stray file "
@@ -1005,9 +949,6 @@
 
 	_init_rand();
 
-	if (!_init_backup(cmd, cmd->cft))
-		return NULL;
-
 	_apply_settings(cmd);
 
 	return cmd;
@@ -1025,10 +966,7 @@
 
 static void _fin(struct cmd_context *cmd)
 {
-	archive_exit();
-	backup_exit();
 	_fin_commands(cmd);
-
 	destroy_toolcontext(cmd);
 }
 
@@ -1409,7 +1347,7 @@
 	log_sys_error("execvp", path);
 }
 
-int lvm2_main(int argc, char **argv)
+int lvm2_main(int argc, char **argv, int is_static)
 {
 	char *namebase, *base;
 	int ret, alias = 0;
@@ -1417,10 +1355,6 @@
 
 	_close_stray_fds();
 
-	if (!(cmd = _init_lvm()))
-		return -1;
-
-	cmd->argv = argv;
 	namebase = strdup(argv[0]);
 	base = basename(namebase);
 	while (*base == '/')
@@ -1428,8 +1362,21 @@
 	if (strcmp(base, "lvm") && strcmp(base, "lvm.static") &&
 	    strcmp(base, "initrd-lvm"))
 		alias = 1;
+
+	if (is_static && strcmp(base, "lvm.static") && 
+	    path_exists(LVM_SHARED_PATH) &&
+	    !getenv("LVM_DID_EXEC")) {
+		setenv("LVM_DID_EXEC", base, 1);
+		execvp(LVM_SHARED_PATH, argv);
+		unsetenv("LVM_DID_EXEC");
+	}
+
 	free(namebase);
 
+	if (!(cmd = _init_lvm()))
+		return -1;
+
+	cmd->argv = argv;
 	_register_commands();
 
 	if (_lvm1_fallback(cmd)) {

Modified: lvm2/trunk/tools/lvmdiskscan.c
==============================================================================
--- lvm2/trunk/tools/lvmdiskscan.c	(original)
+++ lvm2/trunk/tools/lvmdiskscan.c	Tue Jun 14 11:23:47 2005
@@ -34,7 +34,7 @@
 	struct dev_iter *iter;
 	struct device *dev;
 
-	if (!(iter = dev_iter_create(filter))) {
+	if (!(iter = dev_iter_create(filter, 1))) {
 		log_error("dev_iter_create failed");
 		return 0;
 	}
@@ -103,7 +103,7 @@
 
 	max_len = _get_max_dev_name_len(cmd->filter);
 
-	if (!(iter = dev_iter_create(cmd->filter))) {
+	if (!(iter = dev_iter_create(cmd->filter, 0))) {
 		log_error("dev_iter_create failed");
 		return ECMD_FAILED;
 	}

Modified: lvm2/trunk/tools/lvremove.c
==============================================================================
--- lvm2/trunk/tools/lvremove.c	(original)
+++ lvm2/trunk/tools/lvremove.c	Tue Jun 14 11:23:47 2005
@@ -34,6 +34,18 @@
 		return ECMD_FAILED;
 	}
 
+	if (lv->status & MIRROR_IMAGE) {
+		log_error("Can't remove logical volume %s used by a mirror",
+			  lv->name);
+		return ECMD_FAILED;
+	}
+
+	if (lv->status & MIRROR_LOG) {
+		log_error("Can't remove logical volume %s used as mirror log",
+			  lv->name);
+		return ECMD_FAILED;
+	}
+
 	if (lv->status & LOCKED) {
 		log_error("Can't remove locked LV %s", lv->name);
 		return ECMD_FAILED;
@@ -70,14 +82,14 @@
 
 	if (lv_is_cow(lv)) {
 		log_verbose("Removing snapshot %s", lv->name);
-		if (!vg_remove_snapshot(lv->vg, lv)) {
+		if (!vg_remove_snapshot(lv)) {
 			stack;
 			return ECMD_FAILED;
 		}
 	}
 
 	log_verbose("Releasing logical volume \"%s\"", lv->name);
-	if (!lv_remove(vg, lv)) {
+	if (!lv_remove(lv)) {
 		log_error("Error releasing logical volume \"%s\"", lv->name);
 		return ECMD_FAILED;
 	}

Modified: lvm2/trunk/tools/lvrename.c
==============================================================================
--- lvm2/trunk/tools/lvrename.c	(original)
+++ lvm2/trunk/tools/lvrename.c	Tue Jun 14 11:23:47 2005
@@ -83,10 +83,8 @@
 		return ECMD_FAILED;
 	}
 
-	/* FIXME Remove this restriction eventually */
-	if (!strncmp(lv_name_new, "snapshot", 8)) {
-		log_error("Names starting \"snapshot\" are reserved. "
-			  "Please choose a different LV name.");
+	if (!apply_lvname_restrictions(lv_name_new)) {
+		stack;
 		return ECMD_FAILED;
 	}
 

Modified: lvm2/trunk/tools/lvresize.c
==============================================================================
--- lvm2/trunk/tools/lvresize.c	(original)
+++ lvm2/trunk/tools/lvresize.c	Tue Jun 14 11:23:47 2005
@@ -23,6 +23,7 @@
 
 	uint32_t stripes;
 	uint32_t stripe_size;
+	uint32_t mirrors;
 
 	struct segment_type *segtype;
 
@@ -115,10 +116,11 @@
 {
 	struct volume_group *vg;
 	struct logical_volume *lv;
-	struct snapshot *snap;
+	struct lv_segment *snap_seg;
 	struct lvinfo info;
 	uint32_t stripesize_extents = 0;
 	uint32_t seg_stripes = 0, seg_stripesize = 0, seg_size = 0;
+	uint32_t seg_mirrors = 0;
 	uint32_t extents_used = 0;
 	uint32_t size_rest;
 	alloc_policy_t alloc;
@@ -161,6 +163,13 @@
 			log_print("Varied striping not supported. Ignoring.");
 	}
 
+	if (arg_count(cmd, mirrors_ARG)) {
+		if (vg->fid->fmt->features & FMT_SEGMENTS)
+			lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 1) + 1;
+		else
+			log_print("Mirrors not supported. Ignoring.");
+	}
+
 	if (arg_count(cmd, stripesize_ARG)) {
 		if (arg_sign_value(cmd, stripesize_ARG, 0) == SIGN_MINUS) {
 			log_error("Stripesize may not be negative.");
@@ -171,6 +180,10 @@
 							     stripesize_ARG, 0);
 		else
 			log_print("Varied stripesize not supported. Ignoring.");
+		if (lp->mirrors) {
+			log_error("Mirrors and striping cannot be combined yet.");
+			return ECMD_FAILED;
+		}
 	}
 
 	lv = lvl->lv;
@@ -180,11 +193,6 @@
 		return ECMD_FAILED;
 	}
 
-	if (lv_is_origin(lv)) {
-		log_error("Snapshot origin volumes cannot be resized yet.");
-		return ECMD_FAILED;
-	}
-
 	alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, lv->alloc);
 
 	if (lp->size) {
@@ -245,7 +253,7 @@
 	if ((lp->extents > lv->le_count) &&
 	    !(lp->stripes == 1 || (lp->stripes > 1 && lp->stripe_size))) {
 		list_iterate_items(seg, &lv->segments) {
-			if (!(seg->segtype->flags & SEG_AREAS_STRIPED))
+			if (!seg_is_striped(seg))
 				continue;
 
 			sz = seg->stripe_size;
@@ -282,22 +290,48 @@
 		}
 	}
 
+	/* If extending, find mirrors of last segment */
+	if ((lp->extents > lv->le_count)) {
+		list_iterate_back_items(seg, &lv->segments) {
+			if (seg_is_mirrored(seg))
+				seg_mirrors = seg->area_count;
+			else
+				seg_mirrors = 0;
+			break;
+		}
+		if (!arg_count(cmd, mirrors_ARG) && seg_mirrors) {
+			log_print("Extending %" PRIu32 " mirror images.",
+				  seg_mirrors);
+			lp->mirrors = seg_mirrors;
+		}
+		if ((arg_count(cmd, mirrors_ARG) || seg_mirrors) &&
+		    (lp->mirrors != seg_mirrors)) {
+			log_error("Cannot vary number of mirrors in LV yet.");
+			return EINVALID_CMD_LINE;
+		}
+	}
+
 	/* If reducing, find stripes, stripesize & size of last segment */
 	if (lp->extents < lv->le_count) {
 		extents_used = 0;
 
-		if (lp->stripes || lp->stripe_size)
-			log_error("Ignoring stripes and stripesize arguments "
-				  "when reducing");
+		if (lp->stripes || lp->stripe_size || lp->mirrors)
+			log_error("Ignoring stripes, stripesize and mirrors "
+				  "arguments when reducing");
 
 		list_iterate_items(seg, &lv->segments) {
 			seg_extents = seg->len;
 
-			if (seg->segtype->flags & SEG_AREAS_STRIPED) {
+			if (seg_is_striped(seg)) {
 				seg_stripesize = seg->stripe_size;
 				seg_stripes = seg->area_count;
 			}
 
+			if (seg_is_mirrored(seg))
+				seg_mirrors = seg->area_count;
+			else
+				seg_mirrors = 0;
+
 			if (lp->extents <= extents_used + seg_extents)
 				break;
 
@@ -307,6 +341,7 @@
 		seg_size = lp->extents - extents_used;
 		lp->stripe_size = seg_stripesize;
 		lp->stripes = seg_stripes;
+		lp->mirrors = seg_mirrors;
 	}
 
 	if (lp->stripes > 1 && !lp->stripe_size) {
@@ -352,6 +387,28 @@
 			lp->resize = LV_EXTEND;
 	}
 
+	if (lp->mirrors && activation() &&
+	    lv_info(lv, &info, 0) && info.exists) {
+		log_error("Mirrors cannot be resized while active yet.");
+		return ECMD_FAILED;
+	}
+
+	if (lv_is_origin(lv)) {
+		if (lp->resize == LV_REDUCE) {
+			log_error("Snapshot origin volumes cannot be reduced "
+				  "in size yet.");
+			return ECMD_FAILED;
+		}
+
+		memset(&info, 0, sizeof(info));
+
+		if (lv_info(lv, &info, 0) && info.exists) {
+			log_error("Snapshot origin volumes can be resized "
+				  "only while inactive: try lvchange -an");
+			return ECMD_FAILED;
+		}
+	}
+
 	if (lp->resize == LV_REDUCE) {
 		if (lp->argc)
 			log_print("Ignoring PVs on command line when reducing");
@@ -439,14 +496,14 @@
 			       SIZE_SHORT));
 
 	if (lp->resize == LV_REDUCE) {
-		if (!lv_reduce(vg->fid, lv, lv->le_count - lp->extents)) {
+		if (!lv_reduce(lv, lv->le_count - lp->extents)) {
 			stack;
 			return ECMD_FAILED;
 		}
-	} else if (!lv_extend(vg->fid, lv, lp->segtype, lp->stripes,
-			       lp->stripe_size, 0u,
-			       lp->extents - lv->le_count,
-			       NULL, 0u, 0u, pvh, alloc)) {
+	} else if (!lv_extend(lv, lp->segtype, lp->stripes,
+			      lp->stripe_size, lp->mirrors,
+			      lp->extents - lv->le_count,
+			      NULL, 0u, 0u, pvh, alloc)) {
 		stack;
 		return ECMD_FAILED;
 	}
@@ -460,8 +517,8 @@
 	backup(vg);
 
 	/* If snapshot, must suspend all associated devices */
-	if ((snap = find_cow(lv)))
-		lock_lvid = snap->origin->lvid.s;
+	if ((snap_seg = find_cow(lv)))
+		lock_lvid = snap_seg->origin->lvid.s;
 	else
 		lock_lvid = lv->lvid.s;
 

Modified: lvm2/trunk/tools/polldaemon.c
==============================================================================
--- lvm2/trunk/tools/polldaemon.c	(original)
+++ lvm2/trunk/tools/polldaemon.c	Tue Jun 14 11:23:47 2005
@@ -72,6 +72,8 @@
 	float segment_percent = 0.0, overall_percent = 0.0;
 	uint32_t event_nr = 0;
 
+void *x;
+
 	/* By default, caller should not retry */
 	*finished = 1;
 
@@ -97,6 +99,9 @@
 	else
 		log_verbose("%s: Moved: %.1f%%", name, overall_percent);
 
+x = pool_alloc(cmd->mem, 1);
+pool_free(cmd->mem, x);
+
 	if (segment_percent < 100.0) {
 		/* The only case the caller *should* try again later */
 		*finished = 0;
@@ -138,8 +143,11 @@
 	while (!finished) {
 		/* FIXME Also needed in vg/lvchange -ay? */
 		/* FIXME Use alarm for regular intervals instead */
-		if (parms->interval && !parms->aborting)
+		if (parms->interval && !parms->aborting) {
 			sleep(parms->interval);
+			/* Devices might have changed while we slept */
+			init_full_scan_done(0);
+		}
 
 		/* Locks the (possibly renamed) VG again */
 		if (!(vg = parms->poll_fns->get_copy_vg(cmd, name))) {

Modified: lvm2/trunk/tools/pvchange.c
==============================================================================
--- lvm2/trunk/tools/pvchange.c	(original)
+++ lvm2/trunk/tools/pvchange.c	Tue Jun 14 11:23:47 2005
@@ -24,9 +24,12 @@
 	struct pv_list *pvl;
 	struct list mdas;
 	uint64_t sector;
+	uint32_t orig_pe_alloc_count;
 
 	const char *pv_name = dev_name(pv->dev);
 	const char *tag = NULL;
+	const char *orig_vg_name;
+	char uuid[64];
 
 	int consistent = 1;
 	int allocatable = 0;
@@ -178,6 +181,24 @@
 				  pv_name);
 			return 0;
 		}
+		if (!id_write_format(&pv->id, uuid, sizeof(uuid))) {
+			stack;
+			return 0;
+		}
+		log_verbose("Changing uuid of %s to %s.", pv_name, uuid);
+		if (*pv->vg_name) {
+			orig_vg_name = pv->vg_name;
+			orig_pe_alloc_count = pv->pe_alloc_count;
+			pv->vg_name = ORPHAN;
+			pv->pe_alloc_count = 0;
+			if (!(pv_write(cmd, pv, NULL, INT64_C(-1)))) {
+				log_error("pv_write with new uuid failed "
+					  "for %s.", pv_name);
+				return 0;
+			}
+			pv->vg_name = orig_vg_name;
+			pv->pe_alloc_count = orig_pe_alloc_count;
+		}
 	}
 
 	log_verbose("Updating physical volume \"%s\"", pv_name);

Modified: lvm2/trunk/tools/pvcreate.c
==============================================================================
--- lvm2/trunk/tools/pvcreate.c	(original)
+++ lvm2/trunk/tools/pvcreate.c	Tue Jun 14 11:23:47 2005
@@ -63,10 +63,10 @@
 	/* Is there an md superblock here? */
 	if (!dev && md_filtering()) {
 		unlock_vg(cmd, "");
-		log_verbose("Wiping cache of LVM-capable devices");
+
 		persistent_filter_wipe(cmd->filter);
-		log_verbose("Wiping internal cache");
 		lvmcache_destroy();
+
 		init_md_filtering(0);
 		if (!lock_vol(cmd, "", LCK_VG_WRITE)) {
 			log_error("Can't get lock for orphan PVs");

Modified: lvm2/trunk/tools/pvdisplay.c
==============================================================================
--- lvm2/trunk/tools/pvdisplay.c	(original)
+++ lvm2/trunk/tools/pvdisplay.c	Tue Jun 14 11:23:47 2005
@@ -64,6 +64,7 @@
 		}
 		return pvs(cmd, argc, argv);
 	} else if (arg_count(cmd, aligned_ARG) ||
+		   arg_count(cmd, all_ARG) ||
 		   arg_count(cmd, noheadings_ARG) ||
 		   arg_count(cmd, options_ARG) ||
 		   arg_count(cmd, separator_ARG) ||

Modified: lvm2/trunk/tools/pvmove.c
==============================================================================
--- lvm2/trunk/tools/pvmove.c	(original)
+++ lvm2/trunk/tools/pvmove.c	Tue Jun 14 11:23:47 2005
@@ -140,10 +140,9 @@
 	struct lv_list *lvl;
 
 	/* FIXME Cope with non-contiguous => splitting existing segments */
-	/* FIXME Pass 'alloc' down to lv_extend */
-	if (!(lv_mirr = lv_create_empty(vg->fid, NULL, "pvmove%d",
+	if (!(lv_mirr = lv_create_empty(vg->fid, "pvmove%d", NULL,
 					LVM_READ | LVM_WRITE,
-					ALLOC_CONTIGUOUS, vg))) {
+					ALLOC_CONTIGUOUS, 0, vg))) {
 		log_error("Creation of temporary pvmove LV failed");
 		return NULL;
 	}
@@ -160,7 +159,8 @@
 	/* Find segments to be moved and set up mirrors */
 	list_iterate_items(lvl, &vg->lvs) {
 		lv = lvl->lv;
-		if ((lv == lv_mirr) || (lv_name && strcmp(lv->name, lv_name)))
+		if ((lv == lv_mirr) ||
+		    (lv_name && strcmp(lv->name, lv_name)))
 			continue;
 		if (lv_is_origin(lv) || lv_is_cow(lv)) {
 			log_print("Skipping snapshot-related LV %s", lv->name);
@@ -175,7 +175,8 @@
 			continue;
 		}
 		if (!insert_pvmove_mirrors(cmd, lv_mirr, source_pvl, lv,
-					   allocatable_pvs, *lvs_changed)) {
+					   allocatable_pvs, alloc,
+					   *lvs_changed)) {
 			stack;
 			return NULL;
 		}
@@ -438,7 +439,7 @@
 	}
 
 	log_verbose("Removing temporary pvmove LV");
-	if (!lv_remove(vg, lv_mirr)) {
+	if (!lv_remove(lv_mirr)) {
 		log_error("ABORTING: Removal of temporary pvmove LV failed");
 		return 0;
 	}

Modified: lvm2/trunk/tools/pvscan.c
==============================================================================
--- lvm2/trunk/tools/pvscan.c	(original)
+++ lvm2/trunk/tools/pvscan.c	Tue Jun 14 11:23:47 2005
@@ -123,10 +123,7 @@
 			  arg_count(cmd, exported_ARG) ?
 			  "of exported volume group(s)" : "in no volume group");
 
-	log_verbose("Wiping cache of LVM-capable devices");
 	persistent_filter_wipe(cmd->filter);
-
-	log_verbose("Wiping internal cache");
 	lvmcache_destroy();
 
 	log_verbose("Walking through all physical volumes");

Modified: lvm2/trunk/tools/reporter.c
==============================================================================
--- lvm2/trunk/tools/reporter.c	(original)
+++ lvm2/trunk/tools/reporter.c	Tue Jun 14 11:23:47 2005
@@ -24,16 +24,21 @@
 		return ECMD_FAILED;
 	}
 
-	if (!report_object(handle, vg, NULL, NULL, NULL))
+	if (!report_object(handle, vg, NULL, NULL, NULL, NULL))
 		return ECMD_FAILED;
 
+	check_current_backup(vg);
+
 	return ECMD_PROCESSED;
 }
 
 static int _lvs_single(struct cmd_context *cmd, struct logical_volume *lv,
 		       void *handle)
 {
-	if (!report_object(handle, lv->vg, lv, NULL, NULL))
+	if (!arg_count(cmd, all_ARG) && !(lv->status & VISIBLE_LV))
+		return ECMD_PROCESSED;
+
+	if (!report_object(handle, lv->vg, lv, NULL, NULL, NULL))
 		return ECMD_FAILED;
 
 	return ECMD_PROCESSED;
@@ -42,18 +47,53 @@
 static int _segs_single(struct cmd_context *cmd, struct lv_segment *seg,
 			void *handle)
 {
-	if (!report_object(handle, seg->lv->vg, seg->lv, NULL, seg))
+	if (!report_object(handle, seg->lv->vg, seg->lv, NULL, seg, NULL))
 		return ECMD_FAILED;
 
 	return ECMD_PROCESSED;
 }
 
+static int _pvsegs_sub_single(struct cmd_context *cmd, struct volume_group *vg,
+			      struct pv_segment *pvseg, void *handle)
+{
+	int consistent = 0;
+	struct physical_volume *pv = pvseg->pv;
+	int ret = ECMD_PROCESSED;
+
+	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, &consistent))) {
+		log_error("Can't read %s: skipping", pv->vg_name);
+		unlock_vg(cmd, pv->vg_name);
+		return ECMD_FAILED;
+	}
+
+	if (!report_object(handle, vg, NULL, pv, NULL, pvseg))
+		ret = ECMD_FAILED;
+
+	unlock_vg(cmd, pv->vg_name);
+	return ret;
+}
+
 static int _lvsegs_single(struct cmd_context *cmd, struct logical_volume *lv,
 			  void *handle)
 {
+	if (!arg_count(cmd, all_ARG) && !(lv->status & VISIBLE_LV))
+		return ECMD_PROCESSED;
+
 	return process_each_segment_in_lv(cmd, lv, handle, _segs_single);
 }
 
+static int _pvsegs_single(struct cmd_context *cmd, struct volume_group *vg,
+			  struct physical_volume *pv, void *handle)
+{
+	return process_each_segment_in_pv(cmd, vg, pv, handle,
+					  _pvsegs_sub_single);
+}
+
 static int _pvs_single(struct cmd_context *cmd, struct volume_group *vg,
 		       struct physical_volume *pv, void *handle)
 {
@@ -73,7 +113,7 @@
 		}
 	}
 
-	if (!report_object(handle, vg, NULL, pv, NULL))
+	if (!report_object(handle, vg, NULL, pv, NULL, NULL))
 		ret = ECMD_FAILED;
 
 	if (pv->vg_name)
@@ -151,6 +191,18 @@
 						  "report/segs_cols_verbose",
 						  DEFAULT_SEGS_COLS_VERB);
 		break;
+	case PVSEGS:
+		keys = find_config_str(cmd->cft->root, "report/pvsegs_sort",
+				       DEFAULT_PVSEGS_SORT);
+		if (!arg_count(cmd, verbose_ARG))
+			options = find_config_str(cmd->cft->root,
+						  "report/pvsegs_cols",
+						  DEFAULT_PVSEGS_COLS);
+		else
+			options = find_config_str(cmd->cft->root,
+						  "report/pvsegs_cols_verbose",
+						  DEFAULT_PVSEGS_COLS_VERB);
+		break;
 	}
 
 	/* If -o supplied use it, else use default for report_type */
@@ -208,6 +260,10 @@
 		r = process_each_lv(cmd, argc, argv, LCK_VG_READ, report_handle,
 				    &_lvsegs_single);
 		break;
+	case PVSEGS:
+		r = process_each_pv(cmd, argc, argv, NULL, report_handle,
+				    &_pvsegs_single);
+		break;
 	}
 
 	report_output(report_handle);
@@ -235,5 +291,12 @@
 
 int pvs(struct cmd_context *cmd, int argc, char **argv)
 {
-	return _report(cmd, argc, argv, PVS);
+	report_type_t type;
+
+	if (arg_count(cmd, segments_ARG))
+		type = PVSEGS;
+	else
+		type = PVS;
+
+	return _report(cmd, argc, argv, type);
 }

Modified: lvm2/trunk/tools/toollib.c
==============================================================================
--- lvm2/trunk/tools/toollib.c	(original)
+++ lvm2/trunk/tools/toollib.c	Tue Jun 14 11:23:47 2005
@@ -60,6 +60,9 @@
 	}
 
 	list_iterate_items(lvl, &vg->lvs) {
+		if (lvl->lv->status & SNAPSHOT)
+			continue;
+
 		/* Should we process this LV? */
 		if (process_all)
 			process_lv = 1;
@@ -107,9 +110,9 @@
 	int ret = 0;
 	int consistent;
 
-	struct list *slh, *tags_arg;
+	struct list *tags_arg;
 	struct list *vgnames;	/* VGs to process */
-	struct str_list *sll;
+	struct str_list *sll, *strl;
 	struct volume_group *vg;
 	struct list tags, lvnames;
 	struct list arg_lvnames;	/* Cmdline vgname or vgname/lvname */
@@ -225,8 +228,8 @@
 		}
 	}
 
-	list_iterate(slh, vgnames) {
-		vgname = list_item(slh, struct str_list)->str;
+	list_iterate_items(strl, vgnames) {
+		vgname = strl->str;
 		if (!vgname || !*vgname)
 			continue;	/* FIXME Unnecessary? */
 		if (!lock_vol(cmd, vgname, lock_type)) {
@@ -285,6 +288,28 @@
 	return ret_max;
 }
 
+int process_each_segment_in_pv(struct cmd_context *cmd,
+			       struct volume_group *vg,
+			       struct physical_volume *pv,
+			       void *handle,
+			       int (*process_single) (struct cmd_context * cmd,
+						      struct volume_group * vg,
+						      struct pv_segment * pvseg,
+						      void *handle))
+{
+	struct pv_segment *pvseg;
+	int ret_max = 0;
+	int ret;
+
+	list_iterate_items(pvseg, &pv->segments) {
+		ret = process_single(cmd, vg, pvseg, handle);
+		if (ret > ret_max)
+			ret_max = ret;
+	}
+
+	return ret_max;
+}
+
 int process_each_segment_in_lv(struct cmd_context *cmd,
 			       struct logical_volume *lv,
 			       void *handle,
@@ -463,7 +488,7 @@
 	int ret_max = 0;
 	int ret = 0;
 
-	if (!(iter = dev_iter_create(cmd->filter))) {
+	if (!(iter = dev_iter_create(cmd->filter, 1))) {
 		log_error("dev_iter creation failed");
 		return ECMD_FAILED;
 	}
@@ -472,6 +497,7 @@
 		if (!(pv = pv_read(cmd, dev_name(dev), NULL, NULL, 0))) {
 			memset(&pv_dummy, 0, sizeof(pv_dummy));
 			list_init(&pv_dummy.tags);
+			list_init(&pv_dummy.segments);
 			pv_dummy.dev = dev;
 			pv_dummy.fmt = NULL;
 			pv = &pv_dummy;
@@ -986,3 +1012,48 @@
 
 	return 1;
 }
+
+int apply_lvname_restrictions(const char *name)
+{
+	if (!strncmp(name, "snapshot", 8)) {
+		log_error("Names starting \"snapshot\" are reserved. "
+			  "Please choose a different LV name.");
+		return 0;
+	}
+
+	if (!strncmp(name, "pvmove", 6)) {
+		log_error("Names starting \"pvmove\" are reserved. "
+			  "Please choose a different LV name.");
+		return 0;
+	}
+
+	if (strstr(name, "_mlog")) {
+		log_error("Names including \"_mlog\" are reserved. "
+			  "Please choose a different LV name.");
+		return 0;
+	}
+
+	if (strstr(name, "_mimage")) {
+		log_error("Names including \"_mimage\" are reserved. "
+			  "Please choose a different LV name.");
+		return 0;
+	}
+
+	return 1;
+}
+
+int validate_vg_name(struct cmd_context *cmd, const char *vg_name)
+{
+	char vg_path[PATH_MAX];
+
+	if (!validate_name(vg_name))
+		return 0;
+
+	snprintf(vg_path, PATH_MAX, "%s%s", cmd->dev_dir, vg_name);
+	if (path_exists(vg_path)) {
+		log_error("%s: already exists in filesystem", vg_path);
+		return 0;
+	}
+
+	return 1;
+}

Modified: lvm2/trunk/tools/toollib.h
==============================================================================
--- lvm2/trunk/tools/toollib.h	(original)
+++ lvm2/trunk/tools/toollib.h	Tue Jun 14 11:23:47 2005
@@ -40,6 +40,14 @@
 					   struct volume_group * vg,
 					   struct physical_volume * pv,
 					   void *handle));
+int process_each_segment_in_pv(struct cmd_context *cmd,
+			       struct volume_group *vg,
+			       struct physical_volume *pv,
+			       void *handle,
+			       int (*process_single) (struct cmd_context * cmd,
+						      struct volume_group * vg,
+						      struct pv_segment * pvseg,
+						      void *handle));
 
 int process_each_lv(struct cmd_context *cmd, int argc, char **argv,
 		    int lock_type, void *handle,
@@ -82,4 +90,8 @@
 int exec_cmd(const char *command, const char *fscmd, const char *lv_path,
 	     const char *size);
 
+int apply_lvname_restrictions(const char *name);
+
+int validate_vg_name(struct cmd_context *cmd, const char *vg_name);
+
 #endif

Modified: lvm2/trunk/tools/tools.h
==============================================================================
--- lvm2/trunk/tools/tools.h	(original)
+++ lvm2/trunk/tools/tools.h	Tue Jun 14 11:23:47 2005
@@ -89,7 +89,9 @@
 /* a global table of possible arguments */
 struct arg {
 	const char short_arg;
+	char _padding[7];
 	const char *long_arg;
+
 	int (*fn) (struct cmd_context * cmd, struct arg * a);
 
 	unsigned int count;
@@ -135,7 +137,7 @@
 char yes_no_prompt(const char *prompt, ...);
 
 /* we use the enums to access the switches */
-static inline const unsigned int arg_count(struct cmd_context *cmd, int a)
+static inline unsigned int arg_count(struct cmd_context *cmd, int a)
 {
 	return cmd->args[a].count;
 }
@@ -151,25 +153,25 @@
 	return arg_count(cmd, a) ? cmd->args[a].value : def;
 }
 
-static inline const int32_t arg_int_value(struct cmd_context *cmd, int a,
+static inline int32_t arg_int_value(struct cmd_context *cmd, int a,
 					  const int32_t def)
 {
 	return arg_count(cmd, a) ? cmd->args[a].i_value : def;
 }
 
-static inline const uint32_t arg_uint_value(struct cmd_context *cmd, int a,
+static inline uint32_t arg_uint_value(struct cmd_context *cmd, int a,
 					    const uint32_t def)
 {
 	return arg_count(cmd, a) ? cmd->args[a].ui_value : def;
 }
 
-static inline const int64_t arg_int64_value(struct cmd_context *cmd, int a,
+static inline int64_t arg_int64_value(struct cmd_context *cmd, int a,
 					    const uint64_t def)
 {
 	return arg_count(cmd, a) ? cmd->args[a].i64_value : def;
 }
 
-static inline const uint64_t arg_uint64_value(struct cmd_context *cmd, int a,
+static inline uint64_t arg_uint64_value(struct cmd_context *cmd, int a,
 					      const uint64_t def)
 {
 	return arg_count(cmd, a) ? cmd->args[a].ui64_value : def;
@@ -181,13 +183,13 @@
 	return arg_count(cmd, a) ? cmd->args[a].ptr : def;
 }
 
-static inline const sign_t arg_sign_value(struct cmd_context *cmd, int a,
+static inline sign_t arg_sign_value(struct cmd_context *cmd, int a,
 					  const sign_t def)
 {
 	return arg_count(cmd, a) ? cmd->args[a].sign : def;
 }
 
-static inline const int arg_count_increment(struct cmd_context *cmd, int a)
+static inline int arg_count_increment(struct cmd_context *cmd, int a)
 {
 	return cmd->args[a].count++;
 }

Modified: lvm2/trunk/tools/vgcfgbackup.c
==============================================================================
--- lvm2/trunk/tools/vgcfgbackup.c	(original)
+++ lvm2/trunk/tools/vgcfgbackup.c	Tue Jun 14 11:23:47 2005
@@ -76,7 +76,7 @@
 		}
 
 		/* just use the normal backup code */
-		backup_enable(1);	/* force a backup */
+		backup_enable(cmd, 1);	/* force a backup */
 		if (!backup(vg)) {
 			stack;
 			return ECMD_FAILED;

Modified: lvm2/trunk/tools/vgchange.c
==============================================================================
--- lvm2/trunk/tools/vgchange.c	(original)
+++ lvm2/trunk/tools/vgchange.c	Tue Jun 14 11:23:47 2005
@@ -27,13 +27,13 @@
 		lv = lvl->lv;
 
 		/* Only request activation of snapshot origin devices */
-		if (lv_is_cow(lv))
+		if ((lv->status & SNAPSHOT) || lv_is_cow(lv))
 			continue;
 
-		/* Can't deactive a pvmove LV */
+		/* Can't deactive a pvmove or log LV */
 		/* FIXME There needs to be a controlled way of doing this */
 		if (((activate == CHANGE_AN) || (activate == CHANGE_ALN)) &&
-		    (lv->status & PVMOVE))
+		    ((lv->status & PVMOVE) || (lv->status & MIRROR_LOG)))
 			continue;
 
 		if (activate == CHANGE_AN) {
@@ -83,6 +83,16 @@
 		return ECMD_FAILED;
 	}
 
+	if (activate && lockingfailed() && (vg->status & CLUSTERED)) {
+		log_error("Locking inactive: ignoring clustered "
+			  "volume group %s", vg->name);
+		return ECMD_FAILED;
+	}
+
+	/* FIXME Move into library where clvmd can use it */
+	if (activate && !lockingfailed())
+		check_current_backup(vg);
+
 	if (activate && (active = lvs_in_vg_activated(vg)))
 		log_verbose("%d logical volume(s) in volume group \"%s\" "
 			    "already active", active, vg->name);
@@ -168,6 +178,41 @@
 	return ECMD_PROCESSED;
 }
 
+static int _vgchange_clustered(struct cmd_context *cmd,
+			       struct volume_group *vg)
+{
+	int clustered = !strcmp(arg_str_value(cmd, clustered_ARG, "n"), "y");
+
+	if (clustered && (vg->status & CLUSTERED)) {
+		log_error("Volume group \"%s\" is already clustered",
+			  vg->name);
+		return ECMD_FAILED;
+	}
+
+	if (!clustered && !(vg->status & CLUSTERED)) {
+		log_error("Volume group \"%s\" is already not clustered",
+			  vg->name);
+		return ECMD_FAILED;
+	}
+
+	if (!archive(vg))
+		return ECMD_FAILED;
+
+	if (clustered)
+		vg->status |= CLUSTERED;
+	else
+		vg->status &= ~CLUSTERED;
+
+	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_logicalvolume(struct cmd_context *cmd,
 				   struct volume_group *vg)
 {
@@ -210,6 +255,64 @@
 	return ECMD_PROCESSED;
 }
 
+static int _vgchange_pesize(struct cmd_context *cmd, struct volume_group *vg)
+{
+	uint32_t extent_size;
+
+	if (!(vg->status & RESIZEABLE_VG)) {
+		log_error("Volume group \"%s\" must be resizeable "
+			  "to change PE size", vg->name);
+		return ECMD_FAILED;
+	}
+
+	if (arg_sign_value(cmd, physicalextentsize_ARG, 0) == SIGN_MINUS) {
+		log_error("Physical extent size may not be negative");
+		return EINVALID_CMD_LINE;
+	}
+
+	extent_size = arg_uint_value(cmd, physicalextentsize_ARG, 0) * 2;
+	if (!extent_size) {
+		log_error("Physical extent size may not be zero");
+		return EINVALID_CMD_LINE;
+	}
+
+	if (extent_size == vg->extent_size) {
+		log_error("Physical extent size of VG %s is already %s",
+			  vg->name, display_size(cmd, extent_size, SIZE_SHORT));
+		return ECMD_PROCESSED;
+	}
+
+	if (extent_size & (extent_size - 1)) {
+		log_error("Physical extent size must be a power of 2.");
+		return EINVALID_CMD_LINE;
+	}
+
+	if (extent_size > vg->extent_size) {
+		if ((uint64_t) vg->extent_size * vg->extent_count % extent_size) {
+			/* FIXME Adjust used PV sizes instead */
+			log_error("New extent size is not a perfect fit");
+			return EINVALID_CMD_LINE;
+		}
+	}
+
+	if (!archive(vg))
+		return ECMD_FAILED;
+
+	if (!vg_change_pesize(cmd, vg, extent_size)) {
+		stack;
+		return ECMD_FAILED;
+	}
+
+	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_tag(struct cmd_context *cmd, struct volume_group *vg,
 			 int arg)
 {
@@ -328,12 +431,18 @@
 	else if (arg_count(cmd, deltag_ARG))
 		r = _vgchange_tag(cmd, vg, deltag_ARG);
 
+	else if (arg_count(cmd, physicalextentsize_ARG))
+		r = _vgchange_pesize(cmd, vg);
+
 	else if (arg_count(cmd, uuid_ARG))
 		r = _vgchange_uuid(cmd, vg);
 
 	else if (arg_count(cmd, alloc_ARG))
 		r = _vgchange_alloc(cmd, vg);
 
+	else if (arg_count(cmd, clustered_ARG))
+		r = _vgchange_clustered(cmd, vg);
+
 	return r;
 }
 
@@ -343,9 +452,10 @@
 	    (arg_count(cmd, available_ARG) + arg_count(cmd, logicalvolume_ARG) +
 	     arg_count(cmd, resizeable_ARG) + arg_count(cmd, deltag_ARG) +
 	     arg_count(cmd, addtag_ARG) + arg_count(cmd, uuid_ARG) +
-	     arg_count(cmd, alloc_ARG))) {
-		log_error("One of -a, -l, -x, --alloc, --addtag, --deltag "
-			  "or --uuid required");
+	     arg_count(cmd, physicalextentsize_ARG) +
+	     arg_count(cmd, clustered_ARG) + arg_count(cmd, alloc_ARG))) {
+		log_error("One of -a, -c, -l, -s, -x, --uuid, --alloc, --addtag or "
+			  "--deltag required");
 		return EINVALID_CMD_LINE;
 	}
 
@@ -353,9 +463,10 @@
 	if (arg_count(cmd, available_ARG) + arg_count(cmd, logicalvolume_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) > 1) {
-		log_error("Only one of -a, -l, -x, --alloc, --addtag, --deltag "
-		          "or --uuid allowed");
+	    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");
 		return EINVALID_CMD_LINE;
 	}
 

Modified: lvm2/trunk/tools/vgconvert.c
==============================================================================
--- lvm2/trunk/tools/vgconvert.c	(original)
+++ lvm2/trunk/tools/vgconvert.c	Tue Jun 14 11:23:47 2005
@@ -92,6 +92,8 @@
 	if (cmd->fmt->features & FMT_RESTRICTED_LVIDS) {
 		list_iterate_items(lvl, &vg->lvs) {
 			lv = lvl->lv;
+			if (lv->status & SNAPSHOT)
+				continue;
 			if (lvnum_from_lvid(&lv->lvid) < MAX_RESTRICTED_LVS)
 				continue;
 			if (lv_info(lv, &info, 0) && info.exists) {

Modified: lvm2/trunk/tools/vgcreate.c
==============================================================================
--- lvm2/trunk/tools/vgcreate.c	(original)
+++ lvm2/trunk/tools/vgcreate.c	Tue Jun 14 11:23:47 2005
@@ -22,10 +22,10 @@
 	size_t max_lv, max_pv;
 	uint32_t extent_size;
 	char *vg_name;
-	char vg_path[PATH_MAX];
 	struct volume_group *vg;
 	const char *tag;
 	alloc_policy_t alloc;
+	int clustered;
 
 	if (!argc) {
 		log_error("Please provide volume group name and "
@@ -88,13 +88,7 @@
 	if (!strncmp(vg_name, cmd->dev_dir, strlen(cmd->dev_dir)))
 		vg_name += strlen(cmd->dev_dir);
 
-	snprintf(vg_path, PATH_MAX, "%s%s", cmd->dev_dir, vg_name);
-	if (path_exists(vg_path)) {
-		log_error("%s: already exists in filesystem", vg_path);
-		return ECMD_FAILED;
-	}
-
-	if (!validate_name(vg_name)) {
+	if (!validate_vg_name(cmd, vg_name)) {
 		log_error("New volume group name \"%s\" is invalid", vg_name);
 		return ECMD_FAILED;
 	}
@@ -130,6 +124,17 @@
 		}
 	}
 
+	if (arg_count(cmd, clustered_ARG))
+        	clustered = !strcmp(arg_str_value(cmd, clustered_ARG, "n"), "y");
+	else
+		/* Default depends on current locking type */
+		clustered = locking_is_clustered();
+
+	if (clustered)
+		vg->status |= CLUSTERED;
+	else
+		vg->status &= ~CLUSTERED;
+
 	if (!lock_vol(cmd, "", LCK_VG_WRITE)) {
 		log_error("Can't get lock for orphan PVs");
 		return ECMD_FAILED;

Modified: lvm2/trunk/tools/vgdisplay.c
==============================================================================
--- lvm2/trunk/tools/vgdisplay.c	(original)
+++ lvm2/trunk/tools/vgdisplay.c	Tue Jun 14 11:23:47 2005
@@ -53,6 +53,8 @@
 		process_each_pv_in_vg(cmd, vg, NULL, NULL, &pvdisplay_short);
 	}
 
+	check_current_backup(vg);
+
 	return ECMD_PROCESSED;
 }
 

Modified: lvm2/trunk/tools/vgmerge.c
==============================================================================
--- lvm2/trunk/tools/vgmerge.c	(original)
+++ lvm2/trunk/tools/vgmerge.c	Tue Jun 14 11:23:47 2005
@@ -140,6 +140,33 @@
 	}
 	vg_to->pv_count += vg_from->pv_count;
 
+	/* Fix up LVIDs */
+	list_iterate_items(lvl1, &vg_to->lvs) {
+		union lvid *lvid1 = &lvl1->lv->lvid;
+		char uuid[64];
+
+		list_iterate_items(lvl2, &vg_from->lvs) {
+			union lvid *lvid2 = &lvl2->lv->lvid;
+
+                	if (id_equal(&lvid1->id[1], &lvid2->id[1])) {
+				if (!id_create(&lvid2->id[1])) {
+					log_error("Failed to generate new "
+						  "random LVID for %s",
+						  lvl2->lv->name);
+					goto error;
+				}
+                		if (!id_write_format(&lvid2->id[1], uuid,
+						     sizeof(uuid))) {
+                        		stack;
+                        		goto error;
+		                }
+
+				log_verbose("Changed LVID for %s to %s",
+					    lvl2->lv->name, uuid);
+			}
+		}
+	}
+ 
 	while (!list_empty(&vg_from->lvs)) {
 		struct list *lvh = vg_from->lvs.n;
 

Modified: lvm2/trunk/tools/vgreduce.c
==============================================================================
--- lvm2/trunk/tools/vgreduce.c	(original)
+++ lvm2/trunk/tools/vgreduce.c	Tue Jun 14 11:23:47 2005
@@ -49,9 +49,9 @@
 static int _remove_lv(struct cmd_context *cmd, struct logical_volume *lv,
 		      int *list_unsafe)
 {
-	struct snapshot *snap;
-	struct snapshot_list *snl;
-	struct list *snaplist;
+	struct lv_segment *snap_seg;
+	struct list *snh, *snht;
+	struct logical_volume *cow;
 
 	log_verbose("%s/%s has missing extents: removing (including "
 		    "dependencies)", lv->vg->name, lv->name);
@@ -65,36 +65,34 @@
 			log_error("Failed to deactivate LV %s", lv->name);
 			return 0;
 		}
-	} else if ((snap = find_cow(lv))) {
+	} else if ((snap_seg = find_cow(lv))) {
 		log_verbose("Deactivating (if active) logical volume %s "
-			    "(origin of %s)", snap->origin->name, lv->name);
+			    "(origin of %s)", snap_seg->origin->name, lv->name);
 
-		if (!deactivate_lv(cmd, snap->origin->lvid.s)) {
+		if (!deactivate_lv(cmd, snap_seg->origin->lvid.s)) {
 			log_error("Failed to deactivate LV %s",
-				  snap->origin->name);
+				  snap_seg->origin->name);
 			return 0;
 		}
 
 		/* Use the origin LV */
-		lv = snap->origin;
+		lv = snap_seg->origin;
 	}
 
 	/* Remove snapshot dependencies */
-	if (!(snaplist = find_snapshots(lv))) {
-		stack;
-		return 0;
-	}
-	/* List may be empty */
-	list_iterate_items(snl, snaplist) {
+	list_iterate_safe(snh, snht, &lv->snapshot_segs) {
+		snap_seg = list_struct_base(snh, struct lv_segment,
+					    origin_list);
+		cow = snap_seg->cow;
+
 		*list_unsafe = 1;	/* May remove caller's lvht! */
-		snap = snl->snapshot;
-		if (!vg_remove_snapshot(lv->vg, snap->cow)) {
+		if (!vg_remove_snapshot(cow)) {
 			stack;
 			return 0;
 		}
-		log_verbose("Removing LV %s from VG %s", snap->cow->name,
+		log_verbose("Removing LV %s from VG %s", cow->name,
 			    lv->vg->name);
-		if (!lv_remove(lv->vg, snap->cow)) {
+		if (!lv_remove(cow)) {
 			stack;
 			return 0;
 		}
@@ -102,7 +100,7 @@
 
 	/* Remove the LV itself */
 	log_verbose("Removing LV %s from VG %s", lv->name, lv->vg->name);
-	if (!lv_remove(lv->vg, lv)) {
+	if (!lv_remove(lv)) {
 		stack;
 		return 0;
 	}
@@ -131,12 +129,12 @@
 		/* Are any segments of this LV on missing PVs? */
 		list_iterate_items(seg, &lv->segments) {
 			for (s = 0; s < seg->area_count; s++) {
-				if (seg->area[s].type != AREA_PV)
+				if (seg_type(seg, s) != AREA_PV)
 					continue;
 
 				/* FIXME Also check for segs on deleted LVs */
 
-				pv = seg->area[s].u.pv.pv;
+				pv = seg_pv(seg, s);
 				if (!pv || !pv->dev) {
 					if (!_remove_lv(cmd, lv, &list_unsafe)) {
 						stack;
@@ -192,6 +190,13 @@
 		list_del(&pvl->list);
 
 	pv->vg_name = ORPHAN;
+        pv->status = ALLOCATABLE_PV;
+
+	if (!dev_get_size(pv->dev, &pv->size)) {
+		log_error("%s: Couldn't get size.", dev_name(pv->dev));
+		return ECMD_FAILED;
+	}
+
 	vg->pv_count--;
 	vg->free_count -= pv->pe_count - pv->pe_alloc_count;
 	vg->extent_count -= pv->pe_count;

Modified: lvm2/trunk/tools/vgremove.c
==============================================================================
--- lvm2/trunk/tools/vgremove.c	(original)
+++ lvm2/trunk/tools/vgremove.c	Tue Jun 14 11:23:47 2005
@@ -56,6 +56,14 @@
 		log_verbose("Removing physical volume \"%s\" from "
 			    "volume group \"%s\"", dev_name(pv->dev), vg_name);
 		pv->vg_name = ORPHAN;
+		pv->status = ALLOCATABLE_PV;
+
+		if (!dev_get_size(pv->dev, &pv->size)) {
+			log_error("%s: Couldn't get size.", dev_name(pv->dev));
+			ret = ECMD_FAILED;
+			continue;
+		}
+
 		/* FIXME Write to same sector label was read from */
 		if (!pv_write(cmd, pv, NULL, INT64_C(-1))) {
 			log_error("Failed to remove physical volume \"%s\""
@@ -65,7 +73,7 @@
 		}
 	}
 
-	backup_remove(vg_name);
+	backup_remove(cmd, vg_name);
 
 	if (ret == ECMD_PROCESSED)
 		log_print("Volume group \"%s\" successfully removed", vg_name);

Modified: lvm2/trunk/tools/vgrename.c
==============================================================================
--- lvm2/trunk/tools/vgrename.c	(original)
+++ lvm2/trunk/tools/vgrename.c	Tue Jun 14 11:23:47 2005
@@ -51,7 +51,7 @@
 		return ECMD_FAILED;
 	}
 
-	if (!validate_name(vg_name_new)) {
+	if (!validate_vg_name(cmd, vg_name_new)) {
 		log_error("New volume group name \"%s\" is invalid",
 			  vg_name_new);
 		return ECMD_FAILED;

Modified: lvm2/trunk/tools/vgscan.c
==============================================================================
--- lvm2/trunk/tools/vgscan.c	(original)
+++ lvm2/trunk/tools/vgscan.c	Tue Jun 14 11:23:47 2005
@@ -36,6 +36,8 @@
 		  (vg->status & EXPORTED_VG) ? "exported " : "", vg_name,
 		  vg->fid->fmt->name);
 
+	check_current_backup(vg);
+
 	return ECMD_PROCESSED;
 }
 
@@ -48,10 +50,7 @@
 		return EINVALID_CMD_LINE;
 	}
 
-	log_verbose("Wiping cache of LVM-capable devices");
 	persistent_filter_wipe(cmd->filter);
-
-	log_verbose("Wiping internal cache");
 	lvmcache_destroy();
 
 	log_print("Reading all physical volumes.  This may take a while...");

Modified: lvm2/trunk/tools/vgsplit.c
==============================================================================
--- lvm2/trunk/tools/vgsplit.c	(original)
+++ lvm2/trunk/tools/vgsplit.c	Tue Jun 14 11:23:47 2005
@@ -44,6 +44,19 @@
 	return 1;
 }
 
+/* FIXME Why not (lv->vg == vg) ? */
+static int _lv_is_in_vg(struct volume_group *vg, struct logical_volume *lv)
+{
+	struct lv_list *lvl;
+
+	list_iterate_items(lvl, &vg->lvs)
+		if (lv == lvl->lv)
+			 return 1;
+
+	return 0;
+}
+
+
 static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to)
 {
 	struct list *lvh, *lvht;
@@ -56,16 +69,19 @@
 	list_iterate_safe(lvh, lvht, &vg_from->lvs) {
 		lv = list_item(lvh, struct lv_list)->lv;
 
+		if ((lv->status & SNAPSHOT))
+			continue;
+
 		/* Ensure all the PVs used by this LV remain in the same */
 		/* VG as each other */
 		vg_with = NULL;
 		list_iterate_items(seg, &lv->segments) {
 			for (s = 0; s < seg->area_count; s++) {
 				/* FIXME Check AREA_LV too */
-				if (seg->area[s].type != AREA_PV)
+				if (seg_type(seg, s) != AREA_PV)
 					continue;
 
-				pv = seg->area[s].u.pv.pv;
+				pv = seg_pv(seg, s);
 				if (vg_with) {
 					if (!pv_is_in_vg(vg_with, pv)) {
 						log_error("Logical Volume %s "
@@ -89,8 +105,9 @@
 					  dev_name(pv->dev));
 				return 0;
 			}
-		}
 
+		}
+			
 		if (vg_with == vg_from)
 			continue;
 
@@ -107,39 +124,38 @@
 	return 1;
 }
 
-static int _lv_is_in_vg(struct volume_group *vg, struct logical_volume *lv)
+static int _move_snapshots(struct volume_group *vg_from,
+			   struct volume_group *vg_to)
 {
-	struct lv_list *lvl;
+	struct list *lvh, *lvht;
+	struct logical_volume *lv;
+	struct lv_segment *seg;
+	int cow_from = 0;
+	int origin_from = 0;
 
-	list_iterate_items(lvl, &vg->lvs)
-		if (lv == lvl->lv)
-			 return 1;
+	list_iterate_safe(lvh, lvht, &vg_from->lvs) {
+		lv = list_item(lvh, struct lv_list)->lv;
 
-	return 0;
-}
+		if (!(lv->status & SNAPSHOT))
+			continue;
 
-static int _move_snapshots(struct volume_group *vg_from,
-			   struct volume_group *vg_to)
-{
-	struct list *slh, *slth;
-	struct snapshot *snap;
-	int cow_from, origin_from;
-
-	list_iterate_safe(slh, slth, &vg_from->snapshots) {
-		snap = list_item(slh, struct snapshot_list)->snapshot;
-		cow_from = _lv_is_in_vg(vg_from, snap->cow);
-		origin_from = _lv_is_in_vg(vg_from, snap->origin);
+		list_iterate_items(seg, &lv->segments) {
+			cow_from = _lv_is_in_vg(vg_from, seg->cow);
+			origin_from = _lv_is_in_vg(vg_from, seg->origin);
+		}
 		if (cow_from && origin_from)
-			return 1;
+			continue;
 		if ((!cow_from && origin_from) || (cow_from && !origin_from)) {
-			log_error("Snapshot %s split", snap->cow->name);
+			log_error("Snapshot %s split", seg->cow->name);
 			return 0;
-		}
+		}	
+
+		/* Move this snapshot */
+		list_del(lvh);
+		list_add(&vg_to->lvs, lvh);
+
 		vg_from->snapshot_count--;
 		vg_to->snapshot_count++;
-
-		list_del(slh);
-		list_add(&vg_to->snapshots, slh);
 	}
 
 	return 1;
@@ -206,6 +222,12 @@
 		goto error;
 	}
 
+	if (!validate_vg_name(cmd, vg_name_to)) {
+		log_error("New volume group name \"%s\" is invalid",
+			   vg_name_to);
+		goto error;
+	}
+
 	if ((active = lvs_in_vg_activated(vg_from))) {
 		/* FIXME Remove this restriction */
 		log_error("Logical volumes in \"%s\" must be inactive",



More information about the pkg-lvm-commits mailing list