r308 - in lvm2/upstream/current: . daemons/clvmd dmeventd/mirror lib/activate lib/cache lib/commands lib/format1 lib/format_pool lib/format_text lib/label lib/locking lib/log lib/metadata lib/misc lib/report man tools

Bastian Blank waldi at costa.debian.org
Sat Apr 15 09:40:36 UTC 2006


Author: waldi
Date: Sat Apr 15 09:40:33 2006
New Revision: 308

Modified:
   lvm2/upstream/current/VERSION
   lvm2/upstream/current/WHATS_NEW
   lvm2/upstream/current/daemons/clvmd/Makefile.in
   lvm2/upstream/current/daemons/clvmd/clvmd-cman.c
   lvm2/upstream/current/daemons/clvmd/clvmd-comms.h
   lvm2/upstream/current/daemons/clvmd/clvmd.c
   lvm2/upstream/current/daemons/clvmd/lvm-functions.c
   lvm2/upstream/current/dmeventd/mirror/Makefile.in
   lvm2/upstream/current/lib/activate/activate.c
   lvm2/upstream/current/lib/activate/activate.h
   lvm2/upstream/current/lib/activate/dev_manager.c
   lvm2/upstream/current/lib/activate/dev_manager.h
   lvm2/upstream/current/lib/cache/lvmcache.c
   lvm2/upstream/current/lib/cache/lvmcache.h
   lvm2/upstream/current/lib/commands/toolcontext.c
   lvm2/upstream/current/lib/format1/disk-rep.c
   lvm2/upstream/current/lib/format1/disk-rep.h
   lvm2/upstream/current/lib/format1/format1.c
   lvm2/upstream/current/lib/format1/import-export.c
   lvm2/upstream/current/lib/format1/lvm1-label.c
   lvm2/upstream/current/lib/format_pool/disk_rep.c
   lvm2/upstream/current/lib/format_pool/format_pool.c
   lvm2/upstream/current/lib/format_pool/import_export.c
   lvm2/upstream/current/lib/format_text/archive.c
   lvm2/upstream/current/lib/format_text/archiver.c
   lvm2/upstream/current/lib/format_text/format-text.c
   lvm2/upstream/current/lib/format_text/format-text.h
   lvm2/upstream/current/lib/format_text/import-export.h
   lvm2/upstream/current/lib/format_text/import.c
   lvm2/upstream/current/lib/format_text/import_vsn1.c
   lvm2/upstream/current/lib/format_text/text_label.c
   lvm2/upstream/current/lib/label/label.c
   lvm2/upstream/current/lib/locking/cluster_locking.c
   lvm2/upstream/current/lib/locking/external_locking.c
   lvm2/upstream/current/lib/locking/locking.h
   lvm2/upstream/current/lib/log/log.c
   lvm2/upstream/current/lib/log/log.h
   lvm2/upstream/current/lib/metadata/metadata.c
   lvm2/upstream/current/lib/metadata/metadata.h
   lvm2/upstream/current/lib/metadata/snapshot_manip.c
   lvm2/upstream/current/lib/misc/sharedlib.c
   lvm2/upstream/current/lib/misc/sharedlib.h
   lvm2/upstream/current/lib/report/report.c
   lvm2/upstream/current/man/vgchange.8
   lvm2/upstream/current/man/vgcreate.8
   lvm2/upstream/current/tools/commands.h
   lvm2/upstream/current/tools/lvconvert.c
   lvm2/upstream/current/tools/lvcreate.c
   lvm2/upstream/current/tools/lvdisplay.c
   lvm2/upstream/current/tools/lvremove.c
   lvm2/upstream/current/tools/lvrename.c
   lvm2/upstream/current/tools/lvresize.c
   lvm2/upstream/current/tools/lvscan.c
   lvm2/upstream/current/tools/pvchange.c
   lvm2/upstream/current/tools/pvmove.c
   lvm2/upstream/current/tools/pvremove.c
   lvm2/upstream/current/tools/pvresize.c
   lvm2/upstream/current/tools/reporter.c
   lvm2/upstream/current/tools/toollib.c
   lvm2/upstream/current/tools/vgchange.c
   lvm2/upstream/current/tools/vgexport.c
   lvm2/upstream/current/tools/vgextend.c
   lvm2/upstream/current/tools/vgimport.c
   lvm2/upstream/current/tools/vgmerge.c
   lvm2/upstream/current/tools/vgreduce.c
   lvm2/upstream/current/tools/vgrename.c
   lvm2/upstream/current/tools/vgsplit.c
Log:
Load LVM2.2.02.03 into /lvm2/upstream/current.


Modified: lvm2/upstream/current/VERSION
==============================================================================
--- lvm2/upstream/current/VERSION	(original)
+++ lvm2/upstream/current/VERSION	Sat Apr 15 09:40:33 2006
@@ -1 +1 @@
-2.02.02 (2006-02-07)
+2.02.03 (2006-04-14)

Modified: lvm2/upstream/current/WHATS_NEW
==============================================================================
--- lvm2/upstream/current/WHATS_NEW	(original)
+++ lvm2/upstream/current/WHATS_NEW	Sat Apr 15 09:40:33 2006
@@ -1,3 +1,25 @@
+Version 2.02.03 - 14th April 2006
+=================================
+  vgrename accepts vgid and exported VG.
+  Add --partial to pvs.
+  When choosing between identically-named VGs, also consider creation_host.
+  Provide total log suppression with 2.
+  Fix vgexport/vgimport to set/reset PV exported flag so pv_attr is correct.
+  Add vgid to struct physical_volume and pass with vg_name to some functions.
+  If two or more VGs are found with the same name, use one that is not exported.
+  Whenever vgname is captured, also capture vgid and whether exported.
+  Remove an incorrect unlock_vg() from process_each_lv().
+  Update extent size information in vgchange and vgcreate man pages.
+  Introduce origin_from_cow() and lv_is_visible().
+  pvremove without -f now fails if there's no PV label.
+  Support lvconvert -s.
+  Suppress locking library load failure message if --ignorelockingfailure.
+  Propagate partial mode around cluster.
+  Fix archive file expiration.
+  Fix dmeventd build.
+  clvmd now uses libcman rather than cman ioctls.
+  clvmd will allow new cman to shutdown on request.
+
 Version 2.02.02 - 7th February 2006
 ===================================
   Add %.so: %.a make template rule.

Modified: lvm2/upstream/current/daemons/clvmd/Makefile.in
==============================================================================
--- lvm2/upstream/current/daemons/clvmd/Makefile.in	(original)
+++ lvm2/upstream/current/daemons/clvmd/Makefile.in	Sat Apr 15 09:40:33 2006
@@ -46,17 +46,17 @@
 
 ifeq ("$(CMAN)", "yes")
 	SOURCES += clvmd-cman.c
-	LMLIBS += -ldlm
+	LMLIBS += -ldlm -lcman
 	CFLAGS += -DUSE_CMAN
 endif
 
 TARGETS = \
 	clvmd
 
-LVMLIBS = -llvm
+LVMLIBS = -llvm -lpthread
 
 ifeq ("@DMEVENTD@", "yes")
-	LVMLIBS += -ldevmapper-event -lpthread
+	LVMLIBS += -ldevmapper-event
 endif
  
 ifeq ("@DEVMAPPER@", "yes")

Modified: lvm2/upstream/current/daemons/clvmd/clvmd-cman.c
==============================================================================
--- lvm2/upstream/current/daemons/clvmd/clvmd-cman.c	(original)
+++ lvm2/upstream/current/daemons/clvmd/clvmd-cman.c	Sat Apr 15 09:40:33 2006
@@ -46,19 +46,23 @@
 
 #define LOCKSPACE_NAME "clvmd"
 
-static int cluster_sock;
 static int num_nodes;
-static struct cl_cluster_node *nodes = NULL;
+static struct cman_node *nodes = NULL;
+static struct cman_node this_node;
 static int count_nodes; /* size of allocated nodes array */
 static int max_updown_nodes = 50;	/* Current size of the allocated array */
 /* Node up/down status, indexed by nodeid */
 static int *node_updown = NULL;
 static dlm_lshandle_t *lockspace;
+static cman_handle_t c_handle;
 
 static void count_clvmds_running(void);
 static void get_members(void);
 static int nodeid_from_csid(char *csid);
 static int name_from_nodeid(int nodeid, char *name);
+static void event_callback(cman_handle_t handle, void *private, int reason, int arg);
+static void data_callback(cman_handle_t handle, void *private,
+			  char *buf, int len, uint8_t port, int nodeid);
 
 struct lock_wait {
 	pthread_cond_t cond;
@@ -68,30 +72,23 @@
 
 static int _init_cluster(void)
 {
-	struct sockaddr_cl saddr;
-	int port = CLUSTER_PORT_CLVMD;
-
 	/* Open the cluster communication socket */
-	cluster_sock = socket(AF_CLUSTER, SOCK_DGRAM, CLPROTO_CLIENT);
-	if (cluster_sock == -1) {
-		/* Don't print an error here because we could be just probing for CMAN */
+	c_handle = cman_init(NULL);
+	if (!c_handle) {
+		syslog(LOG_ERR, "Can't open cluster manager socket: %m");
 		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 */
-	saddr.scl_family = AF_CLUSTER;
-	saddr.scl_port = port;
-
-	if (bind
-	    (cluster_sock, (struct sockaddr *) &saddr,
-	     sizeof(struct sockaddr_cl))) {
+	if (cman_start_recv_data(c_handle, data_callback, CLUSTER_PORT_CLVMD)) {
 		syslog(LOG_ERR, "Can't bind cluster socket: %m");
 		return -1;
 	}
 
+	if (cman_start_notification(c_handle, event_callback)) {
+		syslog(LOG_ERR, "Can't start cluster event listening");
+		return -1;
+	}
+
 	/* Get the cluster members list */
 	get_members();
 	count_clvmds_running();
@@ -114,63 +111,46 @@
 
 static int _get_main_cluster_fd()
 {
-	return cluster_sock;
+	return cman_get_fd(c_handle);
 }
 
 static int _get_num_nodes()
 {
-	return num_nodes;
+	int i;
+	int nnodes = 0;
+
+	/* return number of ACTIVE nodes */
+	for (i=0; i<num_nodes; i++) {
+		if (nodes[i].cn_member)
+			nnodes++;
+	}
+	return nnodes;
 }
 
 /* send_message with the fd check removed */
 static int _cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
 {
-	struct iovec iov[2];
-	struct msghdr msg;
-	struct sockaddr_cl saddr;
-	int len = 0;
-
-	msg.msg_control = NULL;
-	msg.msg_controllen = 0;
-	msg.msg_iovlen = 1;
-	msg.msg_iov = iov;
-	msg.msg_flags = 0;
-	iov[0].iov_len = msglen;
-	iov[0].iov_base = buf;
-
-	saddr.scl_family = AF_CLUSTER;
-	saddr.scl_port = CLUSTER_PORT_CLVMD;
-	if (csid) {
-		msg.msg_name = &saddr;
-		msg.msg_namelen = sizeof(saddr);
-		memcpy(&saddr.scl_nodeid, csid, CMAN_MAX_CSID_LEN);
-	} else {		/* Cluster broadcast */
+	int nodeid = 0;
 
-		msg.msg_name = NULL;
-		msg.msg_namelen = 0;
-	}
+	if (csid)
+		memcpy(&nodeid, csid, CMAN_MAX_CSID_LEN);
 
-	do {
-		len = sendmsg(cluster_sock, &msg, 0);
-		if (len < 0 && errno != EAGAIN)
+	if (cman_send_data(c_handle, buf, msglen, 0, CLUSTER_PORT_CLVMD, nodeid) <= 0)
+	{
 			log_error(errtext);
-
-	} while (len == -1 && errno == EAGAIN);
-	return len;
+	}
+	return msglen;
 }
 
 static void _get_our_csid(char *csid)
 {
-	int i;
-	memset(csid, 0, CMAN_MAX_CSID_LEN);
-
-	for (i = 0; i < num_nodes; i++) {
-		if (nodes[i].us)
-			memcpy(csid, &nodes[i].node_id, CMAN_MAX_CSID_LEN);
+	if (this_node.cn_nodeid == 0) {
+		cman_get_node(c_handle, 0, &this_node);
 	}
+	memcpy(csid, &this_node.cn_nodeid, CMAN_MAX_CSID_LEN);
 }
 
-/* Call a callback routine for each node that known (down mean not running a clvmd) */
+/* Call a callback routine for each node is that known (down means not running a clvmd) */
 static int _cluster_do_node_callback(struct local_client *client,
 			     void (*callback) (struct local_client *, char *,
 					       int))
@@ -179,8 +159,8 @@
 	int somedown = 0;
 
 	for (i = 0; i < _get_num_nodes(); i++) {
-		callback(client, (char *)&nodes[i].node_id, node_updown[nodes[i].node_id]);
-		if (!node_updown[nodes[i].node_id])
+		callback(client, (char *)&nodes[i].cn_nodeid, node_updown[nodes[i].cn_nodeid]);
+		if (!node_updown[nodes[i].cn_nodeid])
 			somedown = -1;
 	}
 	return somedown;
@@ -188,78 +168,63 @@
 
 /* Process OOB message from the cluster socket,
    this currently just means that a node has stopped listening on our port */
-static void process_oob_msg(char *buf, int len, int nodeid)
+static void event_callback(cman_handle_t handle, void *private, int reason, int arg)
 {
-	char namebuf[256];
-	switch (buf[0]) {
-        case CLUSTER_OOB_MSG_PORTCLOSED:
-		name_from_nodeid(nodeid, namebuf);
+	char namebuf[MAX_CLUSTER_NAME_LEN];
+
+	switch (reason) {
+        case CMAN_REASON_PORTCLOSED:
+		name_from_nodeid(arg, namebuf);
 		log_notice("clvmd on node %s has died\n", namebuf);
-		DEBUGLOG("Got OOB message, removing node %s\n", namebuf);
+		DEBUGLOG("Got port closed message, removing node %s\n", namebuf);
 
-		node_updown[nodeid] = 0;
+		node_updown[arg] = 0;
 		break;
 
-	case CLUSTER_OOB_MSG_STATECHANGE:
-		DEBUGLOG("Got OOB message, Cluster state change\n");
+	case CMAN_REASON_STATECHANGE:
+		DEBUGLOG("Got state change message, re-reading members list\n");
 		get_members();
 		break;
+
+#if defined(LIBCMAN_VERSION) && LIBCMAN_VERSION >= 2
+	case CMAN_REASON_PORTOPENED:
+		/* Ignore this, wait for startup message from clvmd itself */
+		break;
+
+	case CMAN_REASON_TRY_SHUTDOWN:
+		DEBUGLOG("Got try shutdown, sending OK\n");
+		cman_replyto_shutdown(c_handle, 1);
+		break;
+#endif
 	default:
 		/* ERROR */
-		DEBUGLOG("Got unknown OOB message: %d\n", buf[0]);
+		DEBUGLOG("Got unknown event callback message: %d\n", reason);
+		break;
 	}
 }
 
-static int _cluster_fd_callback(struct local_client *client, char *buf, int len, char *csid,
+static struct local_client *cman_client;
+static int _cluster_fd_callback(struct local_client *fd, char *buf, int len, char *csid,
 			struct local_client **new_client)
 {
-	struct iovec iov[2];
-	struct msghdr msg;
-	struct sockaddr_cl saddr;
+
+	/* Save this for data_callback */
+	cman_client = fd;
 
 	/* We never return a new client */
 	*new_client = NULL;
 
-	msg.msg_control = NULL;
-	msg.msg_controllen = 0;
-	msg.msg_iovlen = 1;
-	msg.msg_iov = iov;
-	msg.msg_name = &saddr;
-	msg.msg_flags = 0;
-	msg.msg_namelen = sizeof(saddr);
-	iov[0].iov_len = len;
-	iov[0].iov_base = buf;
-
-	len = recvmsg(cluster_sock, &msg, MSG_OOB | O_NONBLOCK);
-	if (len < 0 && errno == EAGAIN)
-		return len;
-
-	DEBUGLOG("Read on cluster socket, len = %d\n", len);
-
-	/* A real error */
-	if (len < 0) {
-		log_error("read error on cluster socket: %m");
-		return 0;
-	}
+	return cman_dispatch(c_handle, 0);
+}
 
-	/* EOF - we have left the cluster */
-	if (len == 0)
-		return 0;
 
-	/* Is it OOB? probably a node gone down */
-	if (msg.msg_flags & MSG_OOB) {
-		process_oob_msg(iov[0].iov_base, len, saddr.scl_nodeid);
-
-		/* Tell the upper layer to ignore this message */
-		len = -1;
-		errno = EAGAIN;
-	}
-	else {
-		memcpy(csid, &saddr.scl_nodeid, sizeof(saddr.scl_nodeid));
-		/* Send it back to clvmd */
-		process_message(client, buf, len, csid);
-	}
-	return len;
+static void data_callback(cman_handle_t handle, void *private,
+			  char *buf, int len, uint8_t port, int nodeid)
+{
+	/* Ignore looped back messages */
+	if (nodeid == this_node.cn_nodeid)
+		return;
+	process_message(cman_client, buf, len, (char *)&nodeid);
 }
 
 static void _add_up_node(char *csid)
@@ -290,19 +255,15 @@
 {
 	unlock_all();
 	dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1);
-	close(cluster_sock);
+	cman_finish(c_handle);
 }
 
 static int is_listening(int nodeid)
 {
-	struct cl_listen_request rq;
 	int status;
 
-	rq.port = CLUSTER_PORT_CLVMD;
-	rq.nodeid = nodeid;
-
 	do {
-		status = ioctl(cluster_sock, SIOCCLUSTER_ISLISTENING, &rq);
+		status = cman_is_listening(c_handle, nodeid, CLUSTER_PORT_CLVMD);
 		if (status < 0 && errno == EBUSY) {	/* Don't busywait */
 			sleep(1);
 			errno = EBUSY;	/* In case sleep trashes it */
@@ -320,19 +281,22 @@
 	int i;
 
 	for (i = 0; i < num_nodes; i++) {
-		node_updown[nodes[i].node_id] = is_listening(nodes[i].node_id);
+		node_updown[nodes[i].cn_nodeid] = is_listening(nodes[i].cn_nodeid);
 	}
 }
 
 /* Get a list of active cluster members */
 static void get_members()
 {
-	struct cl_cluster_nodelist nodelist;
+	int retnodes;
+	int status;
 
-	num_nodes = ioctl(cluster_sock, SIOCCLUSTER_GETMEMBERS, 0);
+	num_nodes = cman_get_node_count(c_handle);
 	if (num_nodes == -1) {
 		log_error("Unable to get node count");
-	} else {
+		return;
+	}
+
 	        /* Not enough room for new nodes list ? */
 	        if (num_nodes > count_nodes && nodes) {
 			free(nodes);
@@ -341,28 +305,19 @@
 
 		if (nodes == NULL) {
 		        count_nodes = num_nodes + 10; /* Overallocate a little */
-		        nodes = malloc(count_nodes * sizeof(struct cl_cluster_node));
+		nodes = malloc(count_nodes * sizeof(struct cman_node));
 			if (!nodes) {
 			        log_error("Unable to allocate nodes array\n");
 				exit(5);
 			}
 		}
-		nodelist.max_members = count_nodes;
-		nodelist.nodes = nodes;
 
-		num_nodes = ioctl(cluster_sock, SIOCCLUSTER_GETMEMBERS, &nodelist);
-		if (num_nodes <= 0) {
+	status = cman_get_nodes(c_handle, count_nodes, &retnodes, nodes);
+	if (status < 0) {
 		        log_error("Unable to get node details");
 			exit(6);
 		}
 
-		/* Sanity check struct */
-		if (nodes[0].size != sizeof(struct cl_cluster_node)) {
-			log_error
-			    ("sizeof(cl_cluster_node) does not match size returned from the kernel: aborting\n");
-			exit(10);
-		}
-
 		if (node_updown == NULL) {
 			node_updown =
 			    (int *) malloc(sizeof(int) *
@@ -371,7 +326,6 @@
 			       sizeof(int) * max(num_nodes, max_updown_nodes));
 		}
 	}
-}
 
 /* Convert a node name to a CSID */
 static int _csid_from_name(char *csid, char *name)
@@ -379,8 +333,8 @@
 	int i;
 
 	for (i = 0; i < num_nodes; i++) {
-		if (strcmp(name, nodes[i].name) == 0) {
-			memcpy(csid, &nodes[i].node_id, CMAN_MAX_CSID_LEN);
+		if (strcmp(name, nodes[i].cn_name) == 0) {
+			memcpy(csid, &nodes[i].cn_nodeid, CMAN_MAX_CSID_LEN);
 			return 0;
 		}
 	}
@@ -393,8 +347,8 @@
 	int i;
 
 	for (i = 0; i < num_nodes; i++) {
-		if (memcmp(csid, &nodes[i].node_id, CMAN_MAX_CSID_LEN) == 0) {
-			strcpy(name, nodes[i].name);
+		if (memcmp(csid, &nodes[i].cn_nodeid, CMAN_MAX_CSID_LEN) == 0) {
+			strcpy(name, nodes[i].cn_name);
 			return 0;
 		}
 	}
@@ -409,8 +363,8 @@
 	int i;
 
 	for (i = 0; i < num_nodes; i++) {
-		if (nodeid == nodes[i].node_id) {
-			strcpy(name, nodes[i].name);
+		if (nodeid == nodes[i].cn_nodeid) {
+			strcpy(name, nodes[i].cn_name);
 			return 0;
 		}
 	}
@@ -431,7 +385,7 @@
 
 static int _is_quorate()
 {
-	return ioctl(cluster_sock, SIOCCLUSTER_ISQUORATE, 0);
+	return cman_is_quorate(c_handle);
 }
 
 static void sync_ast_routine(void *arg)

Modified: lvm2/upstream/current/daemons/clvmd/clvmd-comms.h
==============================================================================
--- lvm2/upstream/current/daemons/clvmd/clvmd-comms.h	(original)
+++ lvm2/upstream/current/daemons/clvmd/clvmd-comms.h	Sat Apr 15 09:40:33 2006
@@ -56,15 +56,19 @@
 #endif
 
 #ifdef USE_CMAN
-#  include "cnxman-socket.h"
+#  include <netinet/in.h>
+#  include "libcman.h"
 #  define CMAN_MAX_CSID_LEN 4
 #  ifndef MAX_CSID_LEN
 #    define MAX_CSID_LEN CMAN_MAX_CSID_LEN
 #  endif
 #  undef MAX_CLUSTER_MEMBER_NAME_LEN
-#  define MAX_CLUSTER_MEMBER_NAME_LEN	CMAN_MAX_CLUSTER_MEMBER_NAME_LEN
+#  define MAX_CLUSTER_MEMBER_NAME_LEN   CMAN_MAX_NODENAME_LEN
+#  define CMAN_MAX_CLUSTER_MESSAGE 1500
+#  define CLUSTER_PORT_CLVMD 11
 struct cluster_ops *init_cman_cluster(void);
 #endif
 
 
+
 #endif

Modified: lvm2/upstream/current/daemons/clvmd/clvmd.c
==============================================================================
--- lvm2/upstream/current/daemons/clvmd/clvmd.c	(original)
+++ lvm2/upstream/current/daemons/clvmd/clvmd.c	Sat Apr 15 09:40:33 2006
@@ -247,7 +247,7 @@
 	if ((clops = init_cman_cluster())) {
 		max_csid_len = CMAN_MAX_CSID_LEN;
 		max_cluster_message = CMAN_MAX_CLUSTER_MESSAGE;
-		max_cluster_member_name_len = CMAN_MAX_CLUSTER_MEMBER_NAME_LEN;
+		max_cluster_member_name_len = CMAN_MAX_NODENAME_LEN;
 		syslog(LOG_NOTICE, "Cluster LVM daemon started - connected to CMAN");
 	}
 #endif
@@ -509,6 +509,7 @@
 		int quorate = clops->is_quorate();
 
 		/* Wait on the cluster FD and all local sockets/pipes */
+		local_client_head.fd = clops->get_main_cluster_fd();
 		FD_ZERO(&in);
 		for (thisfd = &local_client_head; thisfd != NULL;
 		     thisfd = thisfd->next) {

Modified: lvm2/upstream/current/daemons/clvmd/lvm-functions.c
==============================================================================
--- lvm2/upstream/current/daemons/clvmd/lvm-functions.c	(original)
+++ lvm2/upstream/current/daemons/clvmd/lvm-functions.c	Sat Apr 15 09:40:33 2006
@@ -303,6 +303,9 @@
 		}
 	}
 
+	if (lock_flags & LCK_PARTIAL_MODE)
+		init_partial(1);
+
 	switch (command) {
 	case LCK_LV_EXCLUSIVE:
 		status = do_activate_lv(resource, lock_flags, LKM_EXMODE);
@@ -331,6 +334,9 @@
 		break;
 	}
 
+	if (lock_flags & LCK_PARTIAL_MODE)
+		init_partial(0);
+
 	/* clean the pool for another command */
 	dm_pool_empty(cmd->mem);
 

Modified: lvm2/upstream/current/dmeventd/mirror/Makefile.in
==============================================================================
--- lvm2/upstream/current/dmeventd/mirror/Makefile.in	(original)
+++ lvm2/upstream/current/dmeventd/mirror/Makefile.in	Sat Apr 15 09:40:33 2006
@@ -16,7 +16,7 @@
 top_srcdir = @top_srcdir@
 VPATH = @srcdir@
 
-CFLAGS += -I${top_srcdir}/tools -I${top_srcdir}/include
+INCLUDES += -I${top_srcdir}/tools
 CLDFLAGS += -L${top_srcdir}/tools -ldevmapper -llvm2cmd
 
 SOURCES = dmeventd_mirror.c
@@ -32,5 +32,5 @@
 install: libdevmapper-event-lvm2mirror.$(LIB_SUFFIX)
 	$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
 		$(libdir)/$<.$(LIB_VERSION)
-	$(LN_S) -f $(libdir)/$<.$(LIB_VERSION) $(libdir)/$<
+	$(LN_S) -f $<.$(LIB_VERSION) $(libdir)/$<
 

Modified: lvm2/upstream/current/lib/activate/activate.c
==============================================================================
--- lvm2/upstream/current/lib/activate/activate.c	(original)
+++ lvm2/upstream/current/lib/activate/activate.c	Sat Apr 15 09:40:33 2006
@@ -95,12 +95,12 @@
 {
 	return 0;
 }
-int lv_snapshot_percent(struct logical_volume *lv, float *percent)
+int lv_snapshot_percent(const struct logical_volume *lv, float *percent)
 {
 	return 0;
 }
-int lv_mirror_percent(struct logical_volume *lv, int wait, float *percent,
-		      uint32_t *event_nr)
+int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv,
+		      int wait, float *percent, uint32_t *event_nr)
 {
 	return 0;
 }
@@ -407,7 +407,7 @@
 /*
  * Returns 1 if percent set, else 0 on failure.
  */
-int lv_snapshot_percent(struct logical_volume *lv, float *percent)
+int lv_snapshot_percent(const struct logical_volume *lv, float *percent)
 {
 	int r;
 	struct dev_manager *dm;
@@ -427,8 +427,8 @@
 }
 
 /* FIXME Merge with snapshot_percent */
-int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv, int wait, float *percent,
-		      uint32_t *event_nr)
+int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv,
+		      int wait, float *percent, uint32_t *event_nr)
 {
 	int r;
 	struct dev_manager *dm;

Modified: lvm2/upstream/current/lib/activate/activate.h
==============================================================================
--- lvm2/upstream/current/lib/activate/activate.h	(original)
+++ lvm2/upstream/current/lib/activate/activate.h	Sat Apr 15 09:40:33 2006
@@ -70,9 +70,9 @@
 /*
  * Returns 1 if percent has been set, else 0.
  */
-int lv_snapshot_percent(struct logical_volume *lv, float *percent);
-int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv, int wait, float *percent,
-		      uint32_t *event_nr);
+int lv_snapshot_percent(const struct logical_volume *lv, float *percent);
+int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv,
+		      int wait, float *percent, uint32_t *event_nr);
 
 /*
  * Return number of LVs in the VG that are active.

Modified: lvm2/upstream/current/lib/activate/dev_manager.c
==============================================================================
--- lvm2/upstream/current/lib/activate/dev_manager.c	(original)
+++ lvm2/upstream/current/lib/activate/dev_manager.c	Sat Apr 15 09:40:33 2006
@@ -432,7 +432,8 @@
 }
 
 int dev_manager_snapshot_percent(struct dev_manager *dm,
-				 struct logical_volume *lv, float *percent)
+				 const struct logical_volume *lv,
+				 float *percent)
 {
 	char *name;
 	const char *dlid;

Modified: lvm2/upstream/current/lib/activate/dev_manager.h
==============================================================================
--- lvm2/upstream/current/lib/activate/dev_manager.h	(original)
+++ lvm2/upstream/current/lib/activate/dev_manager.h	Sat Apr 15 09:40:33 2006
@@ -41,7 +41,8 @@
 		     const struct logical_volume *lv,
 		     int mknodes, int with_open_count, struct dm_info *info);
 int dev_manager_snapshot_percent(struct dev_manager *dm,
-				 struct logical_volume *lv, float *percent);
+				 const struct logical_volume *lv,
+				 float *percent);
 int dev_manager_mirror_percent(struct dev_manager *dm,
 			       struct logical_volume *lv, int wait,
 			       float *percent, uint32_t *event_nr);

Modified: lvm2/upstream/current/lib/cache/lvmcache.c
==============================================================================
--- lvm2/upstream/current/lib/cache/lvmcache.c	(original)
+++ lvm2/upstream/current/lib/cache/lvmcache.c	Sat Apr 15 09:40:33 2006
@@ -86,7 +86,8 @@
 	return _vgs_locked;
 }
 
-struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname)
+/* If vgid supplied, require a match. */
+struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname, const char *vgid)
 {
 	struct lvmcache_vginfo *vginfo;
 
@@ -96,10 +97,16 @@
 	if (!(vginfo = dm_hash_lookup(_vgname_hash, vgname)))
 		return NULL;
 
+	if (vgid)
+		do 
+			if (!strncmp(vgid, vginfo->vgid, sizeof(vginfo->vgid)))
+				return vginfo;
+		while ((vginfo = vginfo->next));
+
 	return vginfo;
 }
 
-const struct format_type *fmt_from_vgname(const char *vgname)
+const struct format_type *fmt_from_vgname(const char *vgname, const char *vgid)
 {
 	struct lvmcache_vginfo *vginfo;
 	struct lvmcache_info *info;
@@ -107,8 +114,9 @@
 	struct list *devh, *tmp;
 	struct list devs;
 	struct device_list *devl;
+	char vgid_found[ID_LEN + 1];
 
-	if (!(vginfo = vginfo_from_vgname(vgname)))
+	if (!(vginfo = vginfo_from_vgname(vgname, vgid)))
 		return NULL;
 
 	/* This function is normally called before reading metadata so
@@ -120,6 +128,8 @@
 		list_add(&devs, &devl->list);
 	}
 
+	memcpy(vgid_found, vginfo->vgid, sizeof(vgid_found));
+
 	list_iterate_safe(devh, tmp, &devs) {
 		devl = list_item(devh, struct device_list);
 		label_read(devl->dev, &label);
@@ -127,6 +137,11 @@
 		dm_free(devl);
 	}
 
+	/* If vginfo changed, caller needs to rescan */
+	if (!(vginfo = vginfo_from_vgname(vgname, vgid_found)) ||
+	    strncmp(vginfo->vgid, vgid_found, sizeof(vgid_found)))
+		return NULL;
+
 	return vginfo->fmt;
 }
 
@@ -148,6 +163,19 @@
 	return vginfo;
 }
 
+const char *vgname_from_vgid(struct dm_pool *mem, const char *vgid)
+{
+	struct lvmcache_vginfo *vginfo;
+
+	if ((vginfo = vginfo_from_vgid(vgid))) {
+		if (mem)
+			return dm_pool_strdup(mem, vginfo->vgname);
+		return vginfo->vgname;
+	}
+
+	return NULL;
+}
+
 struct lvmcache_info *info_from_pvid(const char *pvid)
 {
 	struct lvmcache_info *info;
@@ -232,10 +260,33 @@
 	return r;
 }
 
+struct list *lvmcache_get_vgids(struct cmd_context *cmd, int full_scan)
+{
+	struct list *vgids;
+	struct lvmcache_vginfo *vginfo;
+
+	lvmcache_label_scan(cmd, full_scan);
+
+	if (!(vgids = str_list_create(cmd->mem))) {
+		log_error("vgids list allocation failed");
+		return NULL;
+	}
+
+	list_iterate_items(vginfo, &_vginfos) {
+		if (!str_list_add(cmd->mem, vgids, 
+				  dm_pool_strdup(cmd->mem, vginfo->vgid))) {
+			log_error("strlist allocation failed");
+			return NULL;
+		}
+	}
+
+	return vgids;
+}
+
 struct list *lvmcache_get_vgnames(struct cmd_context *cmd, int full_scan)
 {
 	struct list *vgnames;
-	struct lvmcache_vginfo *vgi;
+	struct lvmcache_vginfo *vginfo;
 
 	lvmcache_label_scan(cmd, full_scan);
 
@@ -244,9 +295,9 @@
 		return NULL;
 	}
 
-	list_iterate_items(vgi, &_vginfos) {
+	list_iterate_items(vginfo, &_vginfos) {
 		if (!str_list_add(cmd->mem, vgnames, 
-				  dm_pool_strdup(cmd->mem, vgi->vgname))) {
+				  dm_pool_strdup(cmd->mem, vginfo->vgname))) {
 			log_error("strlist allocation failed");
 			return NULL;
 		}
@@ -297,7 +348,7 @@
 	return NULL;
 }
 
-static void _drop_vginfo(struct lvmcache_info *info)
+static int _drop_vginfo(struct lvmcache_info *info)
 {
 	if (!list_empty(&info->list)) {
 		list_del(&info->list);
@@ -306,8 +357,18 @@
 
 	if (info->vginfo && list_empty(&info->vginfo->infos)) {
 		dm_hash_remove(_vgname_hash, info->vginfo->vgname);
+		if (info->vginfo->next) {
+                	if (!dm_hash_insert(_vgname_hash, info->vginfo->vgname, info->vginfo->next)) {
+                        	log_error("vg hash re-insertion failed: %s",
+					  info->vginfo->vgname);
+                        	return 0;
+			}
+                }
+
 		if (info->vginfo->vgname)
 			dm_free(info->vginfo->vgname);
+		if (info->vginfo->creation_host)
+			dm_free(info->vginfo->creation_host);
 		if (*info->vginfo->vgid)
 			dm_hash_remove(_vgid_hash, info->vginfo->vgid);
 		list_del(&info->vginfo->list);
@@ -315,6 +376,8 @@
 	}
 
 	info->vginfo = NULL;
+
+	return 1;
 }
 
 /* Unused
@@ -356,8 +419,10 @@
 
 	if (info->vginfo && *info->vginfo->vgid)
 		dm_hash_remove(_vgid_hash, info->vginfo->vgid);
-	if (!vgid)
+	if (!vgid) {
+		log_debug("lvmcache: %s: clearing VGID", dev_name(info->dev));
 		return 1;
+	}
 
 	strncpy(info->vginfo->vgid, vgid, sizeof(info->vginfo->vgid));
 	info->vginfo->vgid[sizeof(info->vginfo->vgid) - 1] = '\0';
@@ -367,19 +432,110 @@
 		return 0;
 	}
 
+	log_debug("lvmcache: %s: setting %s VGID to %s", dev_name(info->dev),
+		  info->vginfo->vgname, info->vginfo->vgid);
+
 	return 1;
 }
 
-int lvmcache_update_vgname(struct lvmcache_info *info, const char *vgname)
+static int _insert_vginfo(struct lvmcache_vginfo *new_vginfo, const char *vgid,
+			  uint32_t vgstatus, const char *creation_host,
+			  struct lvmcache_vginfo *primary_vginfo)
+{
+	struct lvmcache_vginfo *last_vginfo = primary_vginfo;
+	char uuid_primary[64], uuid_new[64];
+	int use_new = 0;
+	
+	/* Pre-existing VG takes precedence. Unexported VG takes precedence. */
+	if (primary_vginfo) {
+		if (!id_write_format((struct id *)vgid, uuid_new, sizeof(uuid_new)))
+			return_0;
+
+		if (!id_write_format((struct id *)&primary_vginfo->vgid, uuid_primary,
+				     sizeof(uuid_primary)))
+			return_0;
+
+		/*
+		 * If   Primary not exported, new exported => keep
+		 * Else Primary exported, new not exported => change
+		 * Else Primary has hostname for this machine => keep
+		 * Else Primary has no hostname, new has one => change
+		 * Else New has hostname for this machine => change
+		 * Else Keep primary.
+		 */
+		if (!(primary_vginfo->status & EXPORTED_VG) &&
+		    (vgstatus & EXPORTED_VG))
+			log_error("WARNING: Duplicate VG name %s: "
+				  "Existing %s takes precedence over "
+				  "exported %s", new_vginfo->vgname,
+				  uuid_primary, uuid_new);
+		else if ((primary_vginfo->status & EXPORTED_VG) &&
+			   !(vgstatus & EXPORTED_VG)) {
+			log_error("WARNING: Duplicate VG name %s: "
+				  "%s takes precedence over exported %s",
+				  new_vginfo->vgname, uuid_new,
+				  uuid_primary);
+			use_new = 1;
+		} else if (primary_vginfo->creation_host &&
+			   !strcmp(primary_vginfo->creation_host,
+				   primary_vginfo->fmt->cmd->hostname))
+			log_error("WARNING: Duplicate VG name %s: "
+				  "Existing %s (created here) takes precedence "
+				  "over %s", new_vginfo->vgname, uuid_primary,
+				  uuid_new);
+		else if (!primary_vginfo->creation_host && creation_host) {
+			log_error("WARNING: Duplicate VG name %s: "
+				  "%s (with creation_host) takes precedence over %s",
+				  new_vginfo->vgname, uuid_new,
+				  uuid_primary);
+			use_new = 1;
+		} else if (creation_host &&
+			   !strcmp(creation_host,
+				   primary_vginfo->fmt->cmd->hostname)) {
+			log_error("WARNING: Duplicate VG name %s: "
+				  "%s (created here) takes precedence over %s",
+				  new_vginfo->vgname, uuid_new,
+				  uuid_primary);
+			use_new = 1;
+		}
+
+		if (!use_new) {
+			while (last_vginfo->next)
+				last_vginfo = last_vginfo->next;
+			last_vginfo->next = new_vginfo;
+			return 1;
+		}
+
+		dm_hash_remove(_vgname_hash, primary_vginfo->vgname);
+	}
+
+	if (!dm_hash_insert(_vgname_hash, new_vginfo->vgname, new_vginfo)) {
+		log_error("cache_update: vg hash insertion failed: %s",
+		  	new_vginfo->vgname);
+		return 0;
+	}
+
+	if (primary_vginfo)
+		new_vginfo->next = primary_vginfo;
+
+	return 1;
+}
+
+static int _lvmcache_update_vgname(struct lvmcache_info *info,
+				   const char *vgname, const char *vgid,
+				   uint32_t vgstatus, const char *creation_host)
 {
-	struct lvmcache_vginfo *vginfo;
+	struct lvmcache_vginfo *vginfo, *primary_vginfo;
+	// struct lvmcache_vginfo  *old_vginfo, *next;
 
 	/* If vgname is NULL and we don't already have a vgname, 
 	 * assume ORPHAN - we want every entry to have a vginfo
 	 * attached for scanning reasons.
 	 */
-	if (!vgname && !info->vginfo)
+	if (!vgname && !info->vginfo) {
 		vgname = ORPHAN;
+		vgid = ORPHAN;
+	}
 
 	if (!vgname || (info->vginfo && !strcmp(info->vginfo->vgname, vgname)))
 		return 1;
@@ -388,7 +544,43 @@
 	_drop_vginfo(info);
 
 	/* Get existing vginfo or create new one */
-	if (!(vginfo = vginfo_from_vgname(vgname))) {
+	if (!(vginfo = vginfo_from_vgname(vgname, vgid))) {
+/*** FIXME - vginfo ends up duplicated instead of renamed.
+		// Renaming?  This lookup fails.
+		if ((vginfo = vginfo_from_vgid(vgid))) {
+			next = vginfo->next;
+			old_vginfo = vginfo_from_vgname(vginfo->vgname, NULL);
+			if (old_vginfo == vginfo) {
+				dm_hash_remove(_vgname_hash, old_vginfo->vgname);
+				if (old_vginfo->next) {
+					if (!dm_hash_insert(_vgname_hash, old_vginfo->vgname, old_vginfo->next)) {
+                        			log_error("vg hash re-insertion failed: %s",
+							  old_vginfo->vgname);
+                        			return 0;
+					}
+				}
+			} else do {
+				if (old_vginfo->next == vginfo) {
+					old_vginfo->next = vginfo->next;
+					break;
+				}
+			} while ((old_vginfo = old_vginfo->next));
+			vginfo->next = NULL;
+
+			dm_free(vginfo->vgname);
+			if (!(vginfo->vgname = dm_strdup(vgname))) {
+				log_error("cache vgname alloc failed for %s", vgname);
+				return 0;
+			}
+
+			// Rename so can assume new name does not already exist 
+			if (!dm_hash_insert(_vgname_hash, vginfo->vgname, vginfo->next)) {
+				log_error("vg hash re-insertion failed: %s",
+					  vginfo->vgname);
+                      		return 0;
+			}
+		} else {
+***/
 		if (!(vginfo = dm_malloc(sizeof(*vginfo)))) {
 			log_error("lvmcache_update_vgname: list alloc failed");
 			return 0;
@@ -400,9 +592,9 @@
 			return 0;
 		}
 		list_init(&vginfo->infos);
-		if (!dm_hash_insert(_vgname_hash, vginfo->vgname, vginfo)) {
-			log_error("cache_update: vg hash insertion failed: %s",
-				  vginfo->vgname);
+			primary_vginfo = vginfo_from_vgname(vgname, NULL);
+		if (!_insert_vginfo(vginfo, vgid, vgstatus, creation_host,
+				    primary_vginfo)) {
 			dm_free(vginfo->vgname);
 			dm_free(vginfo);
 			return 0;
@@ -412,6 +604,9 @@
 			list_add(&_vginfos, &vginfo->list);
 		else
 			list_add_h(&_vginfos, &vginfo->list);
+/***
+		}
+***/
 	}
 
 	info->vginfo = vginfo;
@@ -420,8 +615,59 @@
 	/* 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);
+	log_debug("lvmcache: %s: now %s%s%s%s%s", dev_name(info->dev),
+		  *vgname ? "in VG " : "orphaned", vgname,
+		  vginfo->vgid[0] ? " (" : "",
+		  vginfo->vgid[0] ? vginfo->vgid : "",
+		  vginfo->vgid[0] ? ")" : "");
+
+	return 1;
+}
+
+static int _lvmcache_update_vgstatus(struct lvmcache_info *info, uint32_t vgstatus,
+				     const char *creation_host)
+{
+	if (!info || !info->vginfo)
+		return 1;
+
+	if ((info->vginfo->status & EXPORTED_VG) != (vgstatus & EXPORTED_VG))
+		log_debug("lvmcache: %s: VG %s %s exported",
+			  dev_name(info->dev), info->vginfo->vgname,
+			  vgstatus & EXPORTED_VG ? "now" : "no longer");
+
+	info->vginfo->status = vgstatus;
+
+	if (!creation_host)
+		return 1;
+
+	if (info->vginfo->creation_host && !strcmp(creation_host,
+						   info->vginfo->creation_host))
+		return 1;
+
+	if (info->vginfo->creation_host)
+		dm_free(info->vginfo->creation_host);
+
+	if (!(info->vginfo->creation_host = dm_strdup(creation_host))) {
+		log_error("cache creation host alloc failed for %s",
+			  creation_host);
+		return 0;
+	}
+
+	log_debug("lvmcache: %s: VG %s: Set creation host to %s.",
+		  dev_name(info->dev), info->vginfo->vgname, creation_host);
+
+	return 1;
+}
+
+int lvmcache_update_vgname_and_id(struct lvmcache_info *info,
+				  const char *vgname, const char *vgid,
+				  uint32_t vgstatus, const char *creation_host)
+{
+	if (!_lvmcache_update_vgname(info, vgname, vgid, vgstatus,
+				     creation_host) ||
+	    !_lvmcache_update_vgid(info, vgid) ||
+	    !_lvmcache_update_vgstatus(info, vgstatus, creation_host))
+		return_0;
 
 	return 1;
 }
@@ -431,20 +677,17 @@
 	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_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) {
-				_lvmcache_update_vgid(info, (char *) &vg->id);
-				vgid_updated = 1;
-			}
-		}
+		if ((info = info_from_pvid(pvid_s)) &&
+		    !lvmcache_update_vgname_and_id(info, vg->name,
+						   (char *) &vg->id,
+						   vg->status, NULL))
+			return_0;
 	}
 
 	return 1;
@@ -452,7 +695,8 @@
 
 struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
 				   struct device *dev,
-				   const char *vgname, const char *vgid)
+				   const char *vgname, const char *vgid,
+				   uint32_t vgstatus)
 {
 	struct label *label;
 	struct lvmcache_info *existing, *info;
@@ -548,7 +792,7 @@
 		return NULL;
 	}
 
-	if (!lvmcache_update_vgname(info, vgname)) {
+	if (!lvmcache_update_vgname_and_id(info, vgname, vgid, vgstatus, NULL)) {
 		if (!existing) {
 			dm_hash_remove(_pvid_hash, pvid_s);
 			strcpy(info->dev->pvid, "");
@@ -558,10 +802,6 @@
 		return NULL;
 	}
 
-	if (!_lvmcache_update_vgid(info, vgid))
-		/* Non-critical */
-		stack;
-
 	return info;
 }
 
@@ -576,9 +816,16 @@
 
 static void _lvmcache_destroy_vgnamelist(struct lvmcache_vginfo *vginfo)
 {
-	if (vginfo->vgname)
-		dm_free(vginfo->vgname);
-	dm_free(vginfo);
+	struct lvmcache_vginfo *next;
+
+	do {
+		next = vginfo->next;
+		if (vginfo->vgname)
+			dm_free(vginfo->vgname);
+		if (vginfo->creation_host)
+			dm_free(vginfo->creation_host);
+		dm_free(vginfo);
+	} while ((vginfo = next));
 }
 
 static void _lvmcache_destroy_lockname(int present)

Modified: lvm2/upstream/current/lib/cache/lvmcache.h
==============================================================================
--- lvm2/upstream/current/lib/cache/lvmcache.h	(original)
+++ lvm2/upstream/current/lib/cache/lvmcache.h	Sat Apr 15 09:40:33 2006
@@ -33,15 +33,20 @@
 struct format_type;
 struct volume_group;
 
+/* One per VG */
 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 */
+	uint32_t status;
 	char vgid[ID_LEN + 1];
 	char _padding[7];
+	struct lvmcache_vginfo *next; /* Another VG with same name? */
+	char *creation_host;
 };
 
+/* One per device */
 struct lvmcache_info {
 	struct list list;	/* Join VG members together */
 	struct list mdas;	/* list head for metadata areas */
@@ -64,21 +69,26 @@
 /* Add/delete a device */
 struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
 				   struct device *dev,
-				   const char *vgname, const char *vgid);
+				   const char *vgname, const char *vgid,
+				   uint32_t vgstatus);
 void lvmcache_del(struct lvmcache_info *info);
 
 /* Update things */
-int lvmcache_update_vgname(struct lvmcache_info *info, const char *vgname);
+int lvmcache_update_vgname_and_id(struct lvmcache_info *info,
+				  const char *vgname, const char *vgid,
+				  uint32_t vgstatus, const char *hostname);
 int lvmcache_update_vg(struct volume_group *vg);
 
 void lvmcache_lock_vgname(const char *vgname, int read_only);
 void lvmcache_unlock_vgname(const char *vgname);
 
 /* Queries */
-const struct format_type *fmt_from_vgname(const char *vgname);
-struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname);
+const struct format_type *fmt_from_vgname(const char *vgname, const char *vgid);
+struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname,
+					   const char *vgid);
 struct lvmcache_vginfo *vginfo_from_vgid(const char *vgid);
 struct lvmcache_info *info_from_pvid(const char *pvid);
+const char *vgname_from_vgid(struct dm_pool *mem, const char *vgid);
 struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid);
 int vgs_locked(void);
 int vgname_is_locked(const char *vgname);
@@ -87,4 +97,8 @@
 /* Set full_scan to 1 to reread every filtered device label */
 struct list *lvmcache_get_vgnames(struct cmd_context *cmd, int full_scan);
 
+/* Returns list of struct str_lists containing pool-allocated copy of vgids */
+/* Set full_scan to 1 to reread every filtered device label */
+struct list *lvmcache_get_vgids(struct cmd_context *cmd, int full_scan);
+
 #endif

Modified: lvm2/upstream/current/lib/commands/toolcontext.c
==============================================================================
--- lvm2/upstream/current/lib/commands/toolcontext.c	(original)
+++ lvm2/upstream/current/lib/commands/toolcontext.c	Sat Apr 15 09:40:33 2006
@@ -657,7 +657,7 @@
 				return 0;
 			}
 			if (!(lib = load_shared_library(cmd->cft, cv->v.str,
-							"format"))) {
+							"format", 0))) {
 				stack;
 				return 0;
 			}
@@ -753,7 +753,7 @@
 				return 0;
 			}
 			if (!(lib = load_shared_library(cmd->cft, cv->v.str,
-							"segment type"))) {
+							"segment type", 0))) {
 				stack;
 				return 0;
 			}

Modified: lvm2/upstream/current/lib/format1/disk-rep.c
==============================================================================
--- lvm2/upstream/current/lib/format1/disk-rep.c	(original)
+++ lvm2/upstream/current/lib/format1/disk-rep.c	Sat Apr 15 09:40:33 2006
@@ -223,11 +223,11 @@
 	return 1;
 }
 
-static int _read_vgd(struct disk_list *data)
+int read_vgd(struct device *dev, struct vg_disk *vgd, struct pv_disk *pvd)
 {
-	struct vg_disk *vgd = &data->vgd;
-	uint64_t pos = data->pvd.vg_on_disk.base;
-	if (!dev_read(data->dev, pos, sizeof(*vgd), vgd))
+	uint64_t pos = pvd->vg_on_disk.base;
+
+	if (!dev_read(dev, pos, sizeof(*vgd), vgd))
 		fail;
 
 	_xlate_vgd(vgd);
@@ -319,13 +319,31 @@
 	return 1;
 }
 
+static void __update_lvmcache(const struct format_type *fmt,
+			      struct disk_list *dl,
+			      struct device *dev, const char *vgid,
+			      int exported)
+{
+	struct lvmcache_info *info;
+
+	if (!(info = lvmcache_add(fmt->labeller, dl->pvd.pv_uuid, dev,
+				  dl->pvd.vg_name, vgid,
+				  exported ? EXPORTED_VG : 0))) {
+		stack;
+		return;
+	}
+
+	info->device_size = xlate32(dl->pvd.pv_size) << SECTOR_SHIFT;
+	list_init(&info->mdas);
+	info->status &= ~CACHE_INVALID;
+}
+
 static struct disk_list *__read_disk(const struct format_type *fmt,
 				     struct device *dev, struct dm_pool *mem,
 				     const char *vg_name)
 {
-	struct disk_list *dl = dm_pool_alloc(mem, sizeof(*dl));
+	struct disk_list *dl = dm_pool_zalloc(mem, sizeof(*dl));
 	const char *name = dev_name(dev);
-	struct lvmcache_info *info;
 
 	if (!dl) {
 		stack;
@@ -342,41 +360,32 @@
 		goto bad;
 	}
 
-	if (!(info = lvmcache_add(fmt->labeller, dl->pvd.pv_uuid, dev,
-				  dl->pvd.vg_name, NULL)))
-		stack;
-	else {
-		info->device_size = xlate32(dl->pvd.pv_size) << SECTOR_SHIFT;
-		list_init(&info->mdas);
-		info->status &= ~CACHE_INVALID;
-	}
-
 	/*
 	 * is it an orphan ?
 	 */
 	if (!*dl->pvd.vg_name) {
 		log_very_verbose("%s is not a member of any format1 VG", name);
 
-		/* Update VG cache */
-		/* vgcache_add(dl->pvd.vg_name, NULL, dev, fmt); */
-
+		__update_lvmcache(fmt, dl, dev, NULL, 0);
 		return (vg_name) ? NULL : dl;
 	}
 
-	if (!_read_vgd(dl)) {
+	if (!read_vgd(dl->dev, &dl->vgd, &dl->pvd)) {
 		log_error("Failed to read VG data from PV (%s)", name);
+		__update_lvmcache(fmt, dl, dev, NULL, 0);
 		goto bad;
 	}
 
-	/* Update VG cache with what we found */
-	/* vgcache_add(dl->pvd.vg_name, dl->vgd.vg_uuid, dev, fmt); */
-
 	if (vg_name && strcmp(vg_name, dl->pvd.vg_name)) {
 		log_very_verbose("%s is not a member of the VG %s",
 				 name, vg_name);
+		__update_lvmcache(fmt, dl, dev, NULL, 0);
 		goto bad;
 	}
 
+	__update_lvmcache(fmt, dl, dev, dl->vgd.vg_uuid,
+			  dl->vgd.vg_status & VG_EXPORTED);
+
 	if (!_read_uuids(dl)) {
 		log_error("Failed to read PV uuid list from %s", name);
 		goto bad;
@@ -461,7 +470,7 @@
 	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)) &&
+	if (vg_name && (vginfo = vginfo_from_vgname(vg_name, NULL)) &&
 	    vginfo->infos.n) {
 		list_iterate_items(info, &vginfo->infos) {
 			dev = info->dev;

Modified: lvm2/upstream/current/lib/format1/disk-rep.h
==============================================================================
--- lvm2/upstream/current/lib/format1/disk-rep.h	(original)
+++ lvm2/upstream/current/lib/format1/disk-rep.h	Sat Apr 15 09:40:33 2006
@@ -204,7 +204,8 @@
  */
 int import_pv(struct dm_pool *mem, struct device *dev,
 	      struct volume_group *vg,
-	      struct physical_volume *pv, struct pv_disk *pvd);
+	      struct physical_volume *pv, struct pv_disk *pvd,
+	      struct vg_disk *vgd);
 int export_pv(struct cmd_context *cmd, struct dm_pool *mem,
 	      struct volume_group *vg,
 	      struct pv_disk *pvd, struct physical_volume *pv);
@@ -237,6 +238,7 @@
 
 void export_pv_act(struct list *pvds);
 int munge_pvd(struct device *dev, struct pv_disk *pvd);
+int read_vgd(struct device *dev, struct vg_disk *vgd, struct pv_disk *pvd);
 
 /* blech */
 int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,

Modified: lvm2/upstream/current/lib/format1/format1.c
==============================================================================
--- lvm2/upstream/current/lib/format1/format1.c	(original)
+++ lvm2/upstream/current/lib/format1/format1.c	Sat Apr 15 09:40:33 2006
@@ -312,7 +312,7 @@
 		goto out;
 	}
 
-	if (!import_pv(fmt->cmd->mem, dl->dev, NULL, pv, &dl->pvd)) {
+	if (!import_pv(fmt->cmd->mem, dl->dev, NULL, pv, &dl->pvd, &dl->vgd)) {
 		stack;
 		goto out;
 	}
@@ -396,7 +396,7 @@
 	struct lvmcache_info *info;
 
 	if (!(info = lvmcache_add(fmt->labeller, (char *) &pv->id, pv->dev,
-				  pv->vg_name, NULL))) {
+				  pv->vg_name, NULL, 0))) {
 		stack;
 		return 0;
 	}
@@ -502,6 +502,7 @@
 
 static struct format_instance *_create_instance(const struct format_type *fmt,
 						const char *vgname,
+						const char *vgid,
 						void *private)
 {
 	struct format_instance *fid;

Modified: lvm2/upstream/current/lib/format1/import-export.c
==============================================================================
--- lvm2/upstream/current/lib/format1/import-export.c	(original)
+++ lvm2/upstream/current/lib/format1/import-export.c	Sat Apr 15 09:40:33 2006
@@ -49,7 +49,8 @@
 
 int import_pv(struct dm_pool *mem, struct device *dev,
 	      struct volume_group *vg,
-	      struct physical_volume *pv, struct pv_disk *pvd)
+	      struct physical_volume *pv, struct pv_disk *pvd,
+	      struct vg_disk *vgd)
 {
 	memset(pv, 0, sizeof(*pv));
 	memcpy(&pv->id, pvd->pv_uuid, ID_LEN);
@@ -60,6 +61,8 @@
 		return 0;
 	}
 
+	memcpy(&pv->vgid, vgd->vg_uuid, sizeof(vg->id));
+
 	/* Store system_id from first PV if PV belongs to a VG */
 	if (vg && !*vg->system_id)
 		strncpy(vg->system_id, pvd->system_id, NAME_LEN);
@@ -426,7 +429,7 @@
 			return 0;
 		}
 
-		if (!import_pv(mem, dl->dev, vg, pvl->pv, &dl->pvd)) {
+		if (!import_pv(mem, dl->dev, vg, pvl->pv, &dl->pvd, &dl->vgd)) {
 			stack;
 			return 0;
 		}

Modified: lvm2/upstream/current/lib/format1/lvm1-label.c
==============================================================================
--- lvm2/upstream/current/lib/format1/lvm1-label.c	(original)
+++ lvm2/upstream/current/lib/format1/lvm1-label.c	Sat Apr 15 09:40:33 2006
@@ -58,11 +58,20 @@
 		 struct label **label)
 {
 	struct pv_disk *pvd = (struct pv_disk *) buf;
+	struct vg_disk vgd;
 	struct lvmcache_info *info;
+	const char *vgid = NULL;
+	int exported = 0;
 
 	munge_pvd(dev, pvd);
 
-	if (!(info = lvmcache_add(l, pvd->pv_uuid, dev, pvd->vg_name, NULL))) {
+	if (*pvd->vg_name && read_vgd(dev, &vgd, pvd)) {
+		vgid = vgd.vg_uuid;
+		exported = pvd->pv_status & VG_EXPORTED;
+	}
+
+	if (!(info = lvmcache_add(l, pvd->pv_uuid, dev, pvd->vg_name, vgid,
+				  exported))) {
 		stack;
 		return 0;
 	}

Modified: lvm2/upstream/current/lib/format_pool/disk_rep.c
==============================================================================
--- lvm2/upstream/current/lib/format_pool/disk_rep.c	(original)
+++ lvm2/upstream/current/lib/format_pool/disk_rep.c	Sat Apr 15 09:40:33 2006
@@ -98,7 +98,7 @@
 	log_debug("Calculated uuid %s for %s", uuid, pd->pl_pool_name);
 
 	if (!(info = lvmcache_add(l, (char *) &pvid, dev, pd->pl_pool_name,
-				  (char *) &vgid))) {
+				  (char *) &vgid, 0))) {
 		stack;
 		return 0;
 	}
@@ -314,7 +314,7 @@
 		/*
 		 * If the cache scanning doesn't work, this will never work
 		 */
-		if (vg_name && (vginfo = vginfo_from_vgname(vg_name)) &&
+		if (vg_name && (vginfo = vginfo_from_vgname(vg_name, NULL)) &&
 		    vginfo->infos.n) {
 
 			if (_read_vg_pds(fmt, mem, vginfo, pdhead, &totaldevs)) {

Modified: lvm2/upstream/current/lib/format_pool/format_pool.c
==============================================================================
--- lvm2/upstream/current/lib/format_pool/format_pool.c	(original)
+++ lvm2/upstream/current/lib/format_pool/format_pool.c	Sat Apr 15 09:40:33 2006
@@ -268,6 +268,7 @@
 
 static struct format_instance *_create_instance(const struct format_type *fmt,
 						const char *vgname,
+						const char *vgid,
 						void *private)
 {
 	struct format_instance *fid;

Modified: lvm2/upstream/current/lib/format_pool/import_export.c
==============================================================================
--- lvm2/upstream/current/lib/format_pool/import_export.c	(original)
+++ lvm2/upstream/current/lib/format_pool/import_export.c	Sat Apr 15 09:40:33 2006
@@ -165,6 +165,7 @@
 		log_error("Unable to duplicate vg_name string");
 		return 0;
 	}
+	memcpy(&pv->vgid, &vg->id, sizeof(vg->id));
 	pv->status = 0;
 	pv->size = pd->pl_blocks;
 	pv->pe_size = POOL_PE_SIZE;

Modified: lvm2/upstream/current/lib/format_text/archive.c
==============================================================================
--- lvm2/upstream/current/lib/format_text/archive.c	(original)
+++ lvm2/upstream/current/lib/format_text/archive.c	Sat Apr 15 09:40:33 2006
@@ -207,8 +207,8 @@
 	/* Convert retain_days into the time after which we must retain */
 	retain_time = time(NULL) - (time_t) retain_days *SECS_PER_DAY;
 
-	/* Assume list is ordered oldest first (by index) */
-	list_iterate_items(bf, archives) {
+	/* Assume list is ordered newest first (by index) */
+	list_iterate_back_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);
@@ -311,7 +311,7 @@
 
 	if (!(context = create_text_context(cmd, af->path, NULL)) ||
 	    !(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
-							 context))) {
+							 NULL, context))) {
 		log_error("Couldn't create text instance object.");
 		return;
 	}

Modified: lvm2/upstream/current/lib/format_text/archiver.c
==============================================================================
--- lvm2/upstream/current/lib/format_text/archiver.c	(original)
+++ lvm2/upstream/current/lib/format_text/archiver.c	Sat Apr 15 09:40:33 2006
@@ -257,7 +257,7 @@
 	if (!(context = create_text_context(cmd, file,
 					    cmd->cmd_line)) ||
 	    !(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
-							 context))) {
+							 NULL, context))) {
 		log_error("Couldn't create text format object.");
 		return NULL;
 	}
@@ -286,7 +286,7 @@
 
 	/* Attempt to write out using currently active format */
 	if (!(vg->fid = cmd->fmt->ops->create_instance(cmd->fmt, vg->name,
-						       NULL))) {
+						       NULL, NULL))) {
 		log_error("Failed to allocate format instance");
 		return 0;
 	}
@@ -365,7 +365,7 @@
 
 	if (!(context = create_text_context(cmd, file, desc)) ||
 	    !(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
-							 context))) {
+							 NULL, context))) {
 		log_error("Couldn't create backup object.");
 		return 0;
 	}

Modified: lvm2/upstream/current/lib/format_text/format-text.c
==============================================================================
--- lvm2/upstream/current/lib/format_text/format-text.c	(original)
+++ lvm2/upstream/current/lib/format_text/format-text.c	Sat Apr 15 09:40:33 2006
@@ -41,6 +41,7 @@
 
 static struct format_instance *_create_text_instance(const struct format_type
 						     *fmt, const char *vgname,
+						     const char *vgid,
 						     void *context);
 
 struct text_fid_context {
@@ -219,7 +220,7 @@
 
       error:
 	if ((info = info_from_pvid(dev_area->dev->pvid)))
-		lvmcache_update_vgname(info, ORPHAN);
+		lvmcache_update_vgname_and_id(info, ORPHAN, ORPHAN, 0, NULL);
 
 	return NULL;
 }
@@ -858,9 +859,11 @@
 				}
 
 				/* FIXME stat file to see if it's changed */
-				fid = _create_text_instance(fmt, NULL, NULL);
+				fid = _create_text_instance(fmt, NULL, NULL,
+							    NULL);
 				if ((vg = _vg_read_file_name(fid, vgname,
 							     path)))
+					/* FIXME Store creation host in vg */
 					lvmcache_update_vg(vg);
 			}
 
@@ -871,65 +874,92 @@
 	return 1;
 }
 
-int vgname_from_mda(const struct format_type *fmt, struct device_area *dev_area,
-		    char *buf, uint32_t size)
+const char *vgname_from_mda(const struct format_type *fmt,
+			    struct device_area *dev_area, struct id *vgid,
+			    uint32_t *vgstatus, char **creation_host)
 {
 	struct raw_locn *rlocn;
 	struct mda_header *mdah;
-	unsigned int len;
-	int r = 0;
+	uint32_t wrap = 0;
+	const char *vgname = NULL;
+	unsigned int len = 0;
+	char buf[NAME_LEN + 1];
 
 	if (!dev_open(dev_area->dev)) {
 		stack;
-		return 0;
+		return NULL;
 	}
 
-	if (!(mdah = _raw_read_mda_header(fmt, dev_area))) {
-		stack;
-		goto out;
-	}
+	if (!(mdah = _raw_read_mda_header(fmt, dev_area)))
+		goto_out;
 
+	/* FIXME Cope with returning a list */
 	rlocn = mdah->raw_locns;
 
-	while (rlocn->offset) {
-		if (!dev_read(dev_area->dev, dev_area->start + rlocn->offset,
-			      size, buf)) {
-			stack;
-			goto out;
-		}
-		len = 0;
-		while (buf[len] && !isspace(buf[len]) && buf[len] != '{' &&
-		       len < (size - 1))
-			len++;
-		buf[len] = '\0';
+	/* Do quick check for a vgname */
+	if (!dev_read(dev_area->dev, dev_area->start + rlocn->offset,
+		      NAME_LEN, buf))
+		goto_out;
 
-		/* Ignore this entry if the characters aren't permissible */
-		if (!validate_name(buf)) {
-			stack;
-			goto out;
-		}
+	while (buf[len] && !isspace(buf[len]) && buf[len] != '{' &&
+	       len < (NAME_LEN - 1))
+		len++;
 
-		r = 1;
-		break;
+	buf[len] = '\0';
 
-		/* FIXME Cope with returning a list */
-		rlocn++;
+	/* Ignore this entry if the characters aren't permissible */
+	if (!validate_name(buf))
+		goto_out;
+
+	/* We found a VG - now check the metadata */
+	if (rlocn->offset + rlocn->size > mdah->size)
+		wrap = (uint32_t) ((rlocn->offset + rlocn->size) - mdah->size);
+
+	if (wrap > rlocn->offset) {
+		log_error("%s: metadata too large for circular buffer",
+			  dev_name(dev_area->dev));
+		goto out;
+	}
+
+	/* FIXME 64-bit */
+	if (!(vgname = text_vgname_import(fmt, dev_area->dev,
+					  (off_t) (dev_area->start +
+						   rlocn->offset),
+					  (uint32_t) (rlocn->size - wrap),
+					  (off_t) (dev_area->start +
+						   MDA_HEADER_SIZE),
+					  wrap, calc_crc, rlocn->checksum,
+					  vgid, vgstatus, creation_host)))
+		goto_out;
+
+	/* Ignore this entry if the characters aren't permissible */
+	if (!validate_name(vgname)) {
+		stack;
+		vgname = NULL;
+		goto out;
 	}
 
+	log_debug("%s: Found metadata at %" PRIu64 " size %" PRIu64
+		  " for %s (%s)", 
+		  dev_name(dev_area->dev), dev_area->start + rlocn->offset,
+		  rlocn->size, vgname, vgid->uuid);
+
       out:
 	if (!dev_close(dev_area->dev))
 		stack;
 
-	return r;
+	return vgname;
 }
 
 static int _scan_raw(const struct format_type *fmt)
 {
 	struct raw_list *rl;
 	struct list *raw_list;
-	char vgnamebuf[NAME_LEN + 2];
+	const char *vgname;
 	struct volume_group *vg;
 	struct format_instance fid;
+	struct id vgid;
+	uint32_t vgstatus;
 
 	raw_list = &((struct mda_lists *) fmt->private)->raws;
 
@@ -938,9 +968,9 @@
 
 	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,
+		if ((vgname = vgname_from_mda(fmt, &rl->dev_area, &vgid, &vgstatus,
+					      NULL))) {
+			if ((vg = _vg_read_raw_area(&fid, vgname,
 						    &rl->dev_area, 0)))
 				lvmcache_update_vg(vg);
 		}
@@ -1109,7 +1139,7 @@
 	/* FIXME Test mode don't update cache? */
 
 	if (!(info = lvmcache_add(fmt->labeller, (char *) &pv->id, pv->dev,
-				  ORPHAN, NULL))) {
+				  ORPHAN, NULL, 0))) {
 		stack;
 		return 0;
 	}
@@ -1245,7 +1275,7 @@
 	/* Have we already cached vgname? */
 	if (info->vginfo && info->vginfo->vgname && *info->vginfo->vgname &&
 	    get_pv_from_vg_by_id(info->fmt, info->vginfo->vgname,
-				 info->dev->pvid, pv)) {
+				 info->vginfo->vgid, info->dev->pvid, pv)) {
 		return 1;
 	}
 
@@ -1256,6 +1286,7 @@
 		if (info->vginfo && info->vginfo->vgname &&
 		    *info->vginfo->vgname &&
 		    get_pv_from_vg_by_id(info->fmt, info->vginfo->vgname,
+					 info->vginfo->vgid,
 					 info->dev->pvid, pv)) {
 			return 1;
 		}
@@ -1450,6 +1481,7 @@
 /* NULL vgname means use only the supplied context e.g. an archive file */
 static struct format_instance *_create_text_instance(const struct format_type
 						     *fmt, const char *vgname,
+						     const char *vgid,
 						     void *context)
 {
 	struct format_instance *fid;
@@ -1535,7 +1567,7 @@
 
 		/* Scan PVs in VG for any further MDAs */
 		lvmcache_label_scan(fmt->cmd, 0);
-		if (!(vginfo = vginfo_from_vgname(vgname))) {
+		if (!(vginfo = vginfo_from_vgname(vgname, vgid))) {
 			stack;
 			goto out;
 		}
@@ -1569,7 +1601,6 @@
 
       out:
 	return fid;
-
 }
 
 void *create_text_context(struct cmd_context *cmd, const char *path,

Modified: lvm2/upstream/current/lib/format_text/format-text.h
==============================================================================
--- lvm2/upstream/current/lib/format_text/format-text.h	(original)
+++ lvm2/upstream/current/lib/format_text/format-text.h	Sat Apr 15 09:40:33 2006
@@ -54,7 +54,8 @@
 	    struct device *dev, uint64_t start, uint64_t size);
 void del_mdas(struct list *mdas);
 
-int vgname_from_mda(const struct format_type *fmt, struct device_area *dev_area,
-		    char *buf, uint32_t size);
+const char *vgname_from_mda(const struct format_type *fmt,
+			    struct device_area *dev_area, struct id *vgid,
+			    uint32_t *vgstatus, char **creation_host);
 
 #endif

Modified: lvm2/upstream/current/lib/format_text/import-export.h
==============================================================================
--- lvm2/upstream/current/lib/format_text/import-export.h	(original)
+++ lvm2/upstream/current/lib/format_text/import-export.h	Sat Apr 15 09:40:33 2006
@@ -47,6 +47,10 @@
 					 struct config_tree * cf);
 	void (*read_desc) (struct dm_pool * mem, struct config_tree * cf,
 			   time_t *when, char **desc);
+	const char *(*read_vgname) (const struct format_type *fmt,
+				    struct config_tree *cft,
+				    struct id *vgid, uint32_t *vgstatus,
+				    char **creation_host);
 };
 
 struct text_vg_version_ops *text_vg_vsn1_init(void);
@@ -70,5 +74,12 @@
 				       checksum_fn_t checksum_fn,
 				       uint32_t checksum,
 				       time_t *when, char **desc);
+const char *text_vgname_import(const struct format_type *fmt,
+			       struct device *dev,
+                               off_t offset, uint32_t size,
+                               off_t offset2, uint32_t size2,
+                               checksum_fn_t checksum_fn, uint32_t checksum,
+                               struct id *vgid, uint32_t *vgstatus,
+			       char **creation_host);
 
 #endif

Modified: lvm2/upstream/current/lib/format_text/import.c
==============================================================================
--- lvm2/upstream/current/lib/format_text/import.c	(original)
+++ lvm2/upstream/current/lib/format_text/import.c	Sat Apr 15 09:40:33 2006
@@ -23,6 +23,53 @@
 /* FIXME Use tidier inclusion method */
 static struct text_vg_version_ops *(_text_vsn_list[2]);
 
+const char *text_vgname_import(const struct format_type *fmt,
+			       struct device *dev,
+			       off_t offset, uint32_t size,
+			       off_t offset2, uint32_t size2,
+			       checksum_fn_t checksum_fn, uint32_t checksum,
+			       struct id *vgid, uint32_t *vgstatus,
+			       char **creation_host)
+{
+	struct config_tree *cft;
+	struct text_vg_version_ops **vsn;
+	const char *vgname;
+
+	static int _initialised = 0;
+
+	if (!_initialised) {
+		_text_vsn_list[0] = text_vg_vsn1_init();
+		_text_vsn_list[1] = NULL;
+		_initialised = 1;
+	}
+
+	if (!(cft = create_config_tree(NULL)))
+		goto_out;
+
+	if ((!dev && !read_config_file(cft)) ||
+	    (dev && !read_config_fd(cft, dev, offset, size,
+				    offset2, size2, checksum_fn, checksum)))
+		goto_out;
+
+	/* 
+	 * Find a set of version functions that can read this file
+	 */
+	for (vsn = &_text_vsn_list[0]; *vsn; vsn++) {
+		if (!(*vsn)->check_version(cft))
+			continue;
+
+		if (!(vgname = (*vsn)->read_vgname(fmt, cft, vgid, vgstatus,
+						   creation_host)))
+			goto_out;
+
+		break;
+	}
+
+      out:
+	destroy_config_tree(cft);
+	return vgname;
+}
+
 struct volume_group *text_vg_import_fd(struct format_instance *fid,
 				       const char *file,
 				       struct device *dev,

Modified: lvm2/upstream/current/lib/format_text/import_vsn1.c
==============================================================================
--- lvm2/upstream/current/lib/format_text/import_vsn1.c	(original)
+++ lvm2/upstream/current/lib/format_text/import_vsn1.c	Sat Apr 15 09:40:33 2006
@@ -167,6 +167,8 @@
 		return 0;
 	}
 
+	memcpy(&pv->vgid, &vg->id, sizeof(vg->id));
+
 	if (!(cn = find_config_node(pvn, "status"))) {
 		log_error("Couldn't find status flags for physical volume.");
 		return 0;
@@ -798,10 +800,59 @@
 	*when = u;
 }
 
+static const char *_read_vgname(const struct format_type *fmt,
+				struct config_tree *cft, struct id *vgid,
+				uint32_t *vgstatus, char **creation_host)
+{
+	struct config_node *vgn, *cn;
+	struct dm_pool *mem = fmt->cmd->mem;
+	char *vgname;
+	int old_suppress;
+
+	old_suppress = log_suppress(2);
+	*creation_host = dm_pool_strdup(mem,
+					find_config_str(cft->root,
+						        "creation_host", ""));
+	log_suppress(old_suppress);
+
+	/* skip any top-level values */
+	for (vgn = cft->root; (vgn && vgn->v); vgn = vgn->sib) ;
+
+	if (!vgn) {
+		log_error("Couldn't find volume group in file.");
+		return 0;
+	}
+
+	if (!(vgname = dm_pool_strdup(mem, vgn->key)))
+		return_0;
+
+	vgn = vgn->child;
+
+	if (!_read_id(vgid, vgn, "id")) {
+		log_error("Couldn't read uuid for volume group %s.", vgname);
+		return 0;
+	}
+
+	if (!(cn = find_config_node(vgn, "status"))) {
+		log_error("Couldn't find status flags for volume group %s.",
+			  vgname);
+		return 0;
+	}
+
+	if (!(read_flags(vgstatus, VG_FLAGS, cn->v))) {
+		log_error("Couldn't read status flags for volume group %s.",
+			  vgname);
+		return 0;
+	}
+
+	return vgname;
+}
+
 static struct text_vg_version_ops _vsn1_ops = {
 	check_version:_check_version,
 	read_vg:_read_vg,
-	read_desc:_read_desc
+	read_desc:_read_desc,
+	read_vgname:_read_vgname
 };
 
 struct text_vg_version_ops *text_vg_vsn1_init(void)

Modified: lvm2/upstream/current/lib/format_text/text_label.c
==============================================================================
--- lvm2/upstream/current/lib/format_text/text_label.c	(original)
+++ lvm2/upstream/current/lib/format_text/text_label.c	Sat Apr 15 09:40:33 2006
@@ -195,13 +195,16 @@
 	struct disk_locn *dlocn_xl;
 	uint64_t offset;
 	struct metadata_area *mda;
-	char vgnamebuf[NAME_LEN + 2];
+	struct id vgid;
 	struct mda_context *mdac;
+	const char *vgname;
+	uint32_t vgstatus;
+	char *creation_host;
 
 	pvhdr = (struct pv_header *) ((void *) buf + xlate32(lh->offset_xl));
 
-	if (!(info = lvmcache_add(l, pvhdr->pv_uuid, dev, NULL, NULL)))
-		return 0;
+	if (!(info = lvmcache_add(l, pvhdr->pv_uuid, dev, NULL, NULL, 0)))
+		return_0;
 	*label = info->label;
 
 	info->device_size = xlate64(pvhdr->device_size_xl);
@@ -232,10 +235,12 @@
 
 	list_iterate_items(mda, &info->mdas) {
 		mdac = (struct mda_context *) mda->metadata_locn;
-		if (vgname_from_mda(info->fmt, &mdac->area, vgnamebuf,
-				    sizeof(vgnamebuf))) {
-			lvmcache_update_vgname(info, vgnamebuf);
-		}
+		if ((vgname = vgname_from_mda(info->fmt, &mdac->area, 
+					      &vgid, &vgstatus, &creation_host)) &&
+		    !lvmcache_update_vgname_and_id(info, vgname,
+						   (char *) &vgid, vgstatus,
+						   creation_host))
+			return_0;
 	}
 
 	info->status &= ~CACHE_INVALID;

Modified: lvm2/upstream/current/lib/label/label.c
==============================================================================
--- lvm2/upstream/current/lib/label/label.c	(original)
+++ lvm2/upstream/current/lib/label/label.c	Sat Apr 15 09:40:33 2006
@@ -117,15 +117,6 @@
 	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;
-	}
-
 	if (!dev_read(dev, UINT64_C(0), LABEL_SCAN_SIZE, readbuf)) {
 		log_debug("%s: Failed to read label area", dev_name(dev));
 		goto out;
@@ -184,13 +175,11 @@
       out:
 	if (!found) {
 		if ((info = info_from_pvid(dev->pvid)))
-			lvmcache_update_vgname(info, ORPHAN);
+			lvmcache_update_vgname_and_id(info, ORPHAN, ORPHAN,
+						      0, NULL);
 		log_very_verbose("%s: No label detected", dev_name(dev));
 	}
 
-	if (!dev_close(dev))
-		stack;
-
 	return r;
 }
 
@@ -272,16 +261,29 @@
 	char buf[LABEL_SIZE];
 	struct labeller *l;
 	uint64_t sector;
-	int r;
+	struct lvmcache_info *info;
+	int r = 0;
 
-	if (!(l = _find_labeller(dev, buf, &sector))) {
+	if (!dev_open(dev)) {
 		stack;
-		return 0;
+
+		if ((info = info_from_pvid(dev->pvid)))
+			lvmcache_update_vgname_and_id(info, ORPHAN, ORPHAN,
+						      0, NULL);
+
+		goto out;
 	}
 
+	if (!(l = _find_labeller(dev, buf, &sector)))
+		goto_out;
+
 	if ((r = (l->ops->read)(l, dev, buf, result)) && result && *result)
 		(*result)->sector = sector;
 
+      out:
+	if (!dev_close(dev))
+		stack;
+
 	return r;
 }
 
@@ -335,18 +337,35 @@
 	return r;
 }
 
+/* Unused */
 int label_verify(struct device *dev)
 {
 	struct labeller *l;
 	char buf[LABEL_SIZE];
 	uint64_t sector;
+	struct lvmcache_info *info;
+	int r = 0;
 
-	if (!(l = _find_labeller(dev, buf, &sector))) {
+	if (!dev_open(dev)) {
 		stack;
-		return 0;
+
+		if ((info = info_from_pvid(dev->pvid)))
+			lvmcache_update_vgname_and_id(info, ORPHAN, ORPHAN,
+						      0, NULL);
+
+		goto out;
 	}
 
-	return ((l->ops->verify) ? l->ops->verify(l, buf, sector) : 1);
+	if (!(l = _find_labeller(dev, buf, &sector)))
+		goto_out;
+
+	r = l->ops->verify ? l->ops->verify(l, buf, sector) : 1;
+
+      out:
+	if (!dev_close(dev))
+		stack;
+
+	return r;
 }
 
 void label_destroy(struct label *label)

Modified: lvm2/upstream/current/lib/locking/cluster_locking.c
==============================================================================
--- lvm2/upstream/current/lib/locking/cluster_locking.c	(original)
+++ lvm2/upstream/current/lib/locking/cluster_locking.c	Sat Apr 15 09:40:33 2006
@@ -330,6 +330,9 @@
 	args[0] = flags & 0x7F; /* Maskoff lock flags */
 	args[1] = flags & 0xC0; /* Bitmap flags */
 
+	if (partial_mode())
+		args[1] |= LCK_PARTIAL_MODE;
+
 	/*
 	 * VG locks are just that: locks, and have no side effects
 	 * so we only need to do them on the local node because all

Modified: lvm2/upstream/current/lib/locking/external_locking.c
==============================================================================
--- lvm2/upstream/current/lib/locking/external_locking.c	(original)
+++ lvm2/upstream/current/lib/locking/external_locking.c	Sat Apr 15 09:40:33 2006
@@ -72,7 +72,7 @@
 	libname = find_config_str(cft->root, "global/locking_library",
 				  DEFAULT_LOCKING_LIB);
 
-	if (!(_locking_lib = load_shared_library(cft, libname, "locking"))) {
+	if (!(_locking_lib = load_shared_library(cft, libname, "locking", 1))) {
 		stack;
 		return 0;
 	}

Modified: lvm2/upstream/current/lib/locking/locking.h
==============================================================================
--- lvm2/upstream/current/lib/locking/locking.h	(original)
+++ lvm2/upstream/current/lib/locking/locking.h	Sat Apr 15 09:40:33 2006
@@ -68,6 +68,11 @@
 #define LCK_CLUSTER_VG	0x00000080	/* VG is clustered */
 
 /*
+ * Additional lock bits for cluster communication
+ */
+#define LCK_PARTIAL_MODE	0x00000001	/* Running in partial mode */
+
+/*
  * Common combinations
  */
 #define LCK_VG_READ		(LCK_VG | LCK_READ | LCK_HOLD)

Modified: lvm2/upstream/current/lib/log/log.c
==============================================================================
--- lvm2/upstream/current/lib/log/log.c	(original)
+++ lvm2/upstream/current/lib/log/log.c	Sat Apr 15 09:40:33 2006
@@ -90,9 +90,13 @@
 	_syslog = 1;
 }
 
-void log_suppress(int suppress)
+int log_suppress(int suppress)
 {
+	int old_suppress = _log_suppress;
+
 	_log_suppress = suppress;
+
+	return old_suppress;
 }
 
 void release_log_memory(void)
@@ -253,6 +257,9 @@
 	const char *message;
 	const char *trformat;		/* Translated format string */
 
+	if (_log_suppress == 2)
+		return;
+
 	trformat = _(format);
 
 	if (_lvm2_log_fn) {

Modified: lvm2/upstream/current/lib/log/log.h
==============================================================================
--- lvm2/upstream/current/lib/log/log.h	(original)
+++ lvm2/upstream/current/lib/log/log.h	Sat Apr 15 09:40:33 2006
@@ -86,8 +86,9 @@
 int lockingfailed(void);
 int security_level(void);
 
-/* Suppress messages to stdout/stderr */
-void log_suppress(int suppress);
+/* Suppress messages to stdout/stderr (1) or everywhere (2) */
+/* Returns previous setting */
+int log_suppress(int suppress);
 
 /* Suppress messages to syslog */
 void syslog_suppress(int suppress);

Modified: lvm2/upstream/current/lib/metadata/metadata.c
==============================================================================
--- lvm2/upstream/current/lib/metadata/metadata.c	(original)
+++ lvm2/upstream/current/lib/metadata/metadata.c	Sat Apr 15 09:40:33 2006
@@ -71,6 +71,8 @@
 		return 0;
 	}
 
+	memcpy(&pv->vgid, &vg->id, sizeof(vg->id));
+
 	/* Units of 512-byte sectors */
 	pv->pe_size = vg->extent_size;
 
@@ -143,13 +145,14 @@
 }
 
 int get_pv_from_vg_by_id(const struct format_type *fmt, const char *vg_name,
-			 const char *id, struct physical_volume *pv)
+			 const char *vgid, const char *pvid,
+			 struct physical_volume *pv)
 {
 	struct volume_group *vg;
 	struct pv_list *pvl;
 	int consistent = 0;
 
-	if (!(vg = vg_read(fmt->cmd, vg_name, &consistent))) {
+	if (!(vg = vg_read(fmt->cmd, vg_name, vgid, &consistent))) {
 		log_error("get_pv_from_vg_by_id: vg_read failed to read VG %s",
 			  vg_name);
 		return 0;
@@ -160,7 +163,7 @@
 			  vg_name);
 
 	list_iterate_items(pvl, &vg->pvs) {
-		if (id_equal(&pvl->pv->id, (const struct id *) id)) {
+		if (id_equal(&pvl->pv->id, (const struct id *) pvid)) {
 			if (!_copy_pv(pv, pvl->pv)) {
 				stack;
 				return 0;
@@ -239,7 +242,7 @@
 	/* is this vg name already in use ? */
 	old_partial = partial_mode();
 	init_partial(1);
-	if (vg_read(cmd, vg_name, &consistent)) {
+	if (vg_read(cmd, vg_name, NULL, &consistent)) {
 		log_err("A volume group called '%s' already exists.", vg_name);
 		goto bad;
 	}
@@ -286,7 +289,7 @@
 	list_init(&vg->tags);
 
 	if (!(vg->fid = cmd->fmt->ops->create_instance(cmd->fmt, vg_name,
-						       NULL))) {
+						       NULL, NULL))) {
 		log_error("Failed to create format instance");
 		goto bad;
 	}
@@ -496,7 +499,7 @@
 				  uint64_t pvmetadatasize, struct list *mdas)
 {
 	struct dm_pool *mem = fmt->cmd->mem;
-	struct physical_volume *pv = dm_pool_alloc(mem, sizeof(*pv));
+	struct physical_volume *pv = dm_pool_zalloc(mem, sizeof(*pv));
 
 	if (!pv) {
 		stack;
@@ -862,7 +865,7 @@
 	struct volume_group *vg;
 	struct physical_volume *pv;
 
-	if (!(vginfo = vginfo_from_vgname(ORPHAN))) {
+	if (!(vginfo = vginfo_from_vgname(ORPHAN, NULL))) {
 		stack;
 		return NULL;
 	}
@@ -907,6 +910,7 @@
  */
 static struct volume_group *_vg_read(struct cmd_context *cmd,
 				     const char *vgname,
+				     const char *vgid,
 				     int *consistent, int precommitted)
 {
 	struct format_instance *fid;
@@ -928,15 +932,15 @@
 
 	/* Find the vgname in the cache */
 	/* If it's not there we must do full scan to be completely sure */
-	if (!(fmt = fmt_from_vgname(vgname))) {
+	if (!(fmt = fmt_from_vgname(vgname, vgid))) {
 		lvmcache_label_scan(cmd, 0);
-		if (!(fmt = fmt_from_vgname(vgname))) {
+		if (!(fmt = fmt_from_vgname(vgname, vgid))) {
 			if (memlock()) {
 				stack;
 				return NULL;
 			}
 			lvmcache_label_scan(cmd, 2);
-			if (!(fmt = fmt_from_vgname(vgname))) {
+			if (!(fmt = fmt_from_vgname(vgname, vgid))) {
 				stack;
 				return NULL;
 			}
@@ -947,7 +951,7 @@
 		use_precommitted = 0;
 
 	/* create format instance with appropriate metadata area */
-	if (!(fid = fmt->ops->create_instance(fmt, vgname, NULL))) {
+	if (!(fid = fmt->ops->create_instance(fmt, vgname, vgid, NULL))) {
 		log_error("Failed to create format instance");
 		return NULL;
 	}
@@ -978,7 +982,7 @@
 		inconsistent = 0;
 
 		lvmcache_label_scan(cmd, 2);
-		if (!(fmt = fmt_from_vgname(vgname))) {
+		if (!(fmt = fmt_from_vgname(vgname, vgid))) {
 			stack;
 			return NULL;
 		}
@@ -987,7 +991,7 @@
 			use_precommitted = 0;
 
 		/* create format instance with appropriate metadata area */
-		if (!(fid = fmt->ops->create_instance(fmt, vgname, NULL))) {
+		if (!(fid = fmt->ops->create_instance(fmt, vgname, vgid, NULL))) {
 			log_error("Failed to create format instance");
 			return NULL;
 		}
@@ -1069,12 +1073,12 @@
 }
 
 struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
-			     int *consistent)
+			     const char *vgid, int *consistent)
 {
 	struct volume_group *vg;
 	struct lv_list *lvl;
 
-	if (!(vg = _vg_read(cmd, vgname, consistent, 0)))
+	if (!(vg = _vg_read(cmd, vgname, vgid, consistent, 0)))
 		return NULL;
 
 	if (!check_pv_segments(vg)) {
@@ -1112,7 +1116,7 @@
 	/* Is corresponding vgname already cached? */
 	if ((vginfo = vginfo_from_vgid(vgid)) &&
 	    vginfo->vgname && *vginfo->vgname) {
-		if ((vg = _vg_read(cmd, vginfo->vgname,
+		if ((vg = _vg_read(cmd, vginfo->vgname, vgid,
 				   &consistent, precommitted)) &&
 		    !strncmp(vg->id.uuid, vgid, ID_LEN)) {
 			if (!consistent) {
@@ -1143,7 +1147,7 @@
 		if (!vgname || !*vgname)
 			continue;	// FIXME Unnecessary? 
 		consistent = 0;
-		if ((vg = _vg_read(cmd, vgname, &consistent,
+		if ((vg = _vg_read(cmd, vgname, vgid, &consistent,
 				   precommitted)) &&
 		    !strncmp(vg->id.uuid, vgid, ID_LEN)) {
 			if (!consistent) {
@@ -1245,13 +1249,18 @@
 	return lvmcache_get_vgnames(cmd, full_scan);
 }
 
+struct list *get_vgids(struct cmd_context *cmd, int full_scan)
+{
+	return lvmcache_get_vgids(cmd, full_scan);
+}
+
 struct list *get_pvs(struct cmd_context *cmd)
 {
 	struct str_list *strl;
 	struct list *results;
-	const char *vgname;
+	const char *vgname, *vgid;
 	struct list *pvh, *tmp;
-	struct list *vgnames;
+	struct list *vgids;
 	struct volume_group *vg;
 	int consistent = 0;
 	int old_partial;
@@ -1267,7 +1276,7 @@
 	list_init(results);
 
 	/* Get list of VGs */
-	if (!(vgnames = get_vgs(cmd, 0))) {
+	if (!(vgids = get_vgids(cmd, 0))) {
 		log_error("get_pvs: get_vgs failed");
 		return NULL;
 	}
@@ -1278,12 +1287,16 @@
 	old_pvmove = pvmove_mode();
 	init_partial(1);
 	init_pvmove(1);
-	list_iterate_items(strl, vgnames) {
-		vgname = strl->str;
-		if (!vgname)
+	list_iterate_items(strl, vgids) {
+		vgid = strl->str;
+		if (!vgid)
 			continue;	/* FIXME Unnecessary? */
 		consistent = 0;
-		if (!(vg = vg_read(cmd, vgname, &consistent))) {
+		if (!(vgname = vgname_from_vgid(NULL, vgid))) {
+			stack;
+			continue;
+		}
+		if (!(vg = vg_read(cmd, vgname, vgid, &consistent))) {
 			stack;
 			continue;
 		}

Modified: lvm2/upstream/current/lib/metadata/metadata.h
==============================================================================
--- lvm2/upstream/current/lib/metadata/metadata.h	(original)
+++ lvm2/upstream/current/lib/metadata/metadata.h	Sat Apr 15 09:40:33 2006
@@ -122,6 +122,7 @@
 	struct device *dev;
 	const struct format_type *fmt;
 	const char *vg_name;
+	struct id vgid;
 
 	uint32_t status;
 	uint64_t size;
@@ -382,6 +383,7 @@
 	 */
 	struct format_instance *(*create_instance) (const struct format_type *
 						    fmt, const char *vgname,
+						    const char *vgid,
 						    void *context);
 
 	/*
@@ -403,7 +405,7 @@
 int vg_commit(struct volume_group *vg);
 int vg_revert(struct volume_group *vg);
 struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name,
-			     int *consistent);
+			     const char *vgid, int *consistent);
 struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
 				struct list *mdas, uint64_t *label_sector,
 				int warnings);
@@ -411,6 +413,7 @@
 
 /* Set full_scan to 1 to re-read every (filtered) device label */
 struct list *get_vgs(struct cmd_context *cmd, int full_scan);
+struct list *get_vgids(struct cmd_context *cmd, int full_scan);
 
 int pv_write(struct cmd_context *cmd, struct physical_volume *pv,
 	     struct list *mdas, int64_t label_sector);
@@ -478,7 +481,8 @@
 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);
+			 const char *vgid, const char *pvid,
+			 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);
@@ -535,11 +539,16 @@
  */
 int lv_is_origin(const struct logical_volume *lv);
 int lv_is_cow(const struct logical_volume *lv);
+int lv_is_visible(const struct logical_volume *lv);
 
 int pv_is_in_vg(struct volume_group *vg, struct physical_volume *pv);
 
+/* Given a cow LV, return return the snapshot lv_segment that uses it */
 struct lv_segment *find_cow(const struct logical_volume *lv);
 
+/* Given a cow LV, return its origin */
+struct logical_volume *origin_from_cow(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,

Modified: lvm2/upstream/current/lib/metadata/snapshot_manip.c
==============================================================================
--- lvm2/upstream/current/lib/metadata/snapshot_manip.c	(original)
+++ lvm2/upstream/current/lib/metadata/snapshot_manip.c	Sat Apr 15 09:40:33 2006
@@ -28,12 +28,26 @@
 	return lv->snapshot ? 1 : 0;
 }
 
+int lv_is_visible(const struct logical_volume *lv)
+{
+	if (lv_is_cow(lv))
+		return lv_is_visible(find_cow(lv)->lv);
+
+	return lv->status & VISIBLE_LV ? 1 : 0;
+}
+
 /* Given a cow LV, return the snapshot lv_segment that uses it */
 struct lv_segment *find_cow(const struct logical_volume *lv)
 {
 	return lv->snapshot;
 }
 
+/* Given a cow LV, return its origin */
+struct logical_volume *origin_from_cow(const struct logical_volume *lv)
+{
+	return lv->snapshot->origin;
+}
+
 int vg_add_snapshot(struct format_instance *fid, const char *name,
 		    struct logical_volume *origin,
 		    struct logical_volume *cow, union lvid *lvid,

Modified: lvm2/upstream/current/lib/misc/sharedlib.c
==============================================================================
--- lvm2/upstream/current/lib/misc/sharedlib.c	(original)
+++ lvm2/upstream/current/lib/misc/sharedlib.c	Sat Apr 15 09:40:33 2006
@@ -38,7 +38,7 @@
 }
 
 void *load_shared_library(struct config_tree *cft, const char *libname,
-			  const char *desc)
+			  const char *desc, int silent)
 {
 	char path[PATH_MAX];
 	void *library;
@@ -47,8 +47,14 @@
 
 	log_very_verbose("Opening shared %s library %s", desc, path);
 
-	if (!(library = dlopen(path, RTLD_LAZY)))
-		log_error("Unable to open external %s library %s", desc, path);
+	if (!(library = dlopen(path, RTLD_LAZY))) {
+		if (silent && ignorelockingfailure())
+			log_verbose("Unable to open external %s library %s",
+				    desc, path);
+		else
+			log_error("Unable to open external %s library %s",
+				  desc, path);
+	}
 
 	return library;
 }

Modified: lvm2/upstream/current/lib/misc/sharedlib.h
==============================================================================
--- lvm2/upstream/current/lib/misc/sharedlib.h	(original)
+++ lvm2/upstream/current/lib/misc/sharedlib.h	Sat Apr 15 09:40:33 2006
@@ -19,4 +19,4 @@
 void get_shared_library_path(struct config_tree *cft, const char *libname,
 			     char *path, int path_len);
 void *load_shared_library(struct config_tree *cf, const char *libname,
-			  const char *what);
+			  const char *what, int silent);

Modified: lvm2/upstream/current/lib/report/report.c
==============================================================================
--- lvm2/upstream/current/lib/report/report.c	(original)
+++ lvm2/upstream/current/lib/report/report.c	Sat Apr 15 09:40:33 2006
@@ -324,7 +324,6 @@
 	const struct logical_volume *lv = (const struct logical_volume *) data;
 	struct lvinfo info;
 	char *repstr;
-	struct lv_segment *snap_seg;
 	float snap_percent;
 
 	if (!(repstr = dm_pool_zalloc(rh->mem, 7))) {
@@ -344,7 +343,7 @@
 		repstr[0] = 'v';
 	else if (lv_is_origin(lv))
 		repstr[0] = 'o';
-	else if (find_cow(lv))
+	else if (lv_is_cow(lv))
 		repstr[0] = 's';
 	else
 		repstr[0] = '-';
@@ -377,8 +376,8 @@
 			repstr[4] = 'd';	/* Inactive without table */
 
 		/* Snapshot dropped? */
-		if (info.live_table && (snap_seg = find_cow(lv)) &&
-		    (!lv_snapshot_percent(snap_seg->cow, &snap_percent) ||
+		if (info.live_table && lv_is_cow(lv) &&
+		    (!lv_snapshot_percent(lv, &snap_percent) ||
 		     snap_percent < 0 || snap_percent >= 100)) {
 			repstr[0] = toupper(repstr[0]);
 			if (info.suspended)
@@ -491,10 +490,9 @@
 			const void *data)
 {
 	const struct logical_volume *lv = (const struct logical_volume *) data;
-	struct lv_segment *snap_seg;
 
-	if ((snap_seg = find_cow(lv)))
-		return _string_disp(rh, field, &snap_seg->origin->name);
+	if (lv_is_cow(lv))
+		return _string_disp(rh, field, &origin_from_cow(lv)->name);
 
 	field->report_string = "";
 	field->sort_value = (const void *) field->report_string;
@@ -527,8 +525,7 @@
 	char *repstr;
 	size_t len;
 
-	/* FIXME Remove need for snapshot special case */
-	if (lv->status & VISIBLE_LV || lv_is_cow(lv)) {
+	if (lv_is_visible(lv)) {
 		repstr = lv->name;
 		return _string_disp(rh, field, &repstr);
 	}
@@ -667,11 +664,10 @@
 			   const void *data)
 {
 	const struct lv_segment *seg = (const struct lv_segment *) data;
-	struct lv_segment *snap_seg;
 	uint64_t size;
 
-	if ((snap_seg = find_cow(seg->lv)))
-		size = (uint64_t) snap_seg->chunk_size;
+	if (lv_is_cow(seg->lv))
+		size = (uint64_t) find_cow(seg->lv)->chunk_size;
 	else
 		size = 0;
 
@@ -840,7 +836,6 @@
 			   const void *data)
 {
 	const struct logical_volume *lv = (const struct logical_volume *) data;
-	struct lv_segment *snap_seg;
 	struct lvinfo info;
 	float snap_percent;
 	uint64_t *sortval;
@@ -851,16 +846,15 @@
 		return 0;
 	}
 
-	if (!(snap_seg = find_cow(lv)) ||
-	    (lv_info(lv->vg->cmd, snap_seg->cow, &info, 0) && !info.exists)) {
+	if (!lv_is_cow(lv) ||
+	    (lv_info(lv->vg->cmd, lv, &info, 0) && !info.exists)) {
 		field->report_string = "";
 		*sortval = UINT64_C(0);
 		field->sort_value = sortval;
 		return 1;
 	}
 
-	if (!lv_snapshot_percent(snap_seg->cow, &snap_percent)
-	    || snap_percent < 0) {
+	if (!lv_snapshot_percent(lv, &snap_percent) || snap_percent < 0) {
 		field->report_string = "100.00";
 		*sortval = UINT64_C(100);
 		field->sort_value = sortval;

Modified: lvm2/upstream/current/man/vgchange.8
==============================================================================
--- lvm2/upstream/current/man/vgchange.8	(original)
+++ lvm2/upstream/current/man/vgchange.8	Sat Apr 15 09:40:33 2006
@@ -17,6 +17,8 @@
 .RB [ \-l | \-\-logicalvolume
 .IR MaxLogicalVolumes ]
 .RB [ \-P | \-\-partial]
+.RB [ \-s | \-\-physicalextentsize
+.IR PhysicalExtentSize [ \fBkKmMgGtT\fR ]]
 .RB [ -t | \-\-test]
 .RB [ \-v | \-\-verbose]
 .RB [ \-\-version ]
@@ -59,6 +61,27 @@
 Changes the maximum logical volume number of an existing inactive
 volume group.
 .TP
+.BR \-s ", " \-\-physicalextentsize " " \fIPhysicalExtentSize\fR[\fBkKmMgGtT\fR]
+Changes the physical extent size on physical volumes of this volume group.
+A size suffix (k for kilobytes up to t for terabytes) is optional, megabytes
+is the default if no suffix is present.
+The default is 4 MB and it must be at least 1 KB and a power of 2.
+ 
+Before increasing the physical extent size, you might need to use lvresize,
+pvresize and/or pvmove so that everything fits.  For example, every
+contiguous range of extents used in a logical volume must start and 
+end on an extent boundary.
+ 
+If the volume group metadata uses lvm1 format, extents can vary in size from
+8KB to 16GB and there is a limit of 65534 extents in each logical volume.  The
+default of 4 MB leads to a maximum logical volume size of around 256GB.
+ 
+If the volume group metadata uses lvm2 format those restrictions do not apply,
+but having a large number of extents will slow down the tools but have no
+impact on I/O performance to the logical volume.  The smallest PE is 1KB.
+ 
+The 2.4 kernel has a limitation of 2TB per block device.
+.TP
 .BR \-x ", " \-\-resizeable { y | n }
 Enables or disables the extension/reduction of this volume group
 with/by physical volumes.

Modified: lvm2/upstream/current/man/vgcreate.8
==============================================================================
--- lvm2/upstream/current/man/vgcreate.8	(original)
+++ lvm2/upstream/current/man/vgcreate.8	Sat Apr 15 09:40:33 2006
@@ -59,17 +59,22 @@
 .BR \-s ", " \-\-physicalextentsize " " \fIPhysicalExtentSize\fR[\fBkKmMgGtT\fR]
 Sets the physical extent size on physical volumes of this volume group.
 A size suffix (k for kilobytes up to t for terabytes) is optional, megabytes
-is the default if no suffix is present.  Values can be from 8 KB to 16 GB in
-powers of 2.  The default is 4 MB.
+is the default if no suffix is present.  
+The default is 4 MB and it must be at least 1 KB and a power of 2.
+
 Once this value has been set, it is difficult to change it without recreating
 the volume group which would involve backing up and restoring data on any 
-logical volumes.
-If the volume group metadata uses lvm1 format, there is a limit of 65534
-extents in each logical volume, so the default of 4 MB leads to a maximum 
-logical volume size of around 256GB.
-If the volume group metadata uses lvm2 format there is no such restriction,
-although having a large number of extents will slow down
-the tools but have no impact on I/O performance to the logical volume.
+logical volumes.  However, if no extents need moving for the new
+value to apply, it can be altered using vgchange \-s.
+
+If the volume group metadata uses lvm1 format, extents can vary in size from
+8KB to 16GB and there is a limit of 65534 extents in each logical volume.  The
+default of 4 MB leads to a maximum logical volume size of around 256GB.  
+
+If the volume group metadata uses lvm2 format those restrictions do not apply,
+but having a large number of extents will slow down the tools but have no
+impact on I/O performance to the logical volume.  The smallest PE is 1KB.
+
 The 2.4 kernel has a limitation of 2TB per block device.
 .SH EXAMPLES
 To create a volume group named

Modified: lvm2/upstream/current/tools/commands.h
==============================================================================
--- lvm2/upstream/current/tools/commands.h	(original)
+++ lvm2/upstream/current/tools/commands.h	Sat Apr 15 09:40:33 2006
@@ -80,17 +80,26 @@
 
 xx(lvconvert,
    "Change logical volume layout",
-   "lvconvert " "\n"
+   "lvconvert "
+   "[-m|--mirrors Mirrors]\n"
    "\t[--alloc AllocationPolicy]\n"
    "\t[-d|--debug]\n"
    "\t[-h|-?|--help]\n"
-   "\t[-m|--mirrors Mirrors]\n"
-   "\t[-R|--regionsize MirrorLogRegionSize]\n"
    "\t[-v|--verbose]\n"
    "\t[--version]" "\n"
-   "\tLogicalVolume[Path] [PhysicalVolume[Path]...]\n",
+   "\tLogicalVolume[Path] [PhysicalVolume[Path]...]\n\n"
 
-   alloc_ARG, mirrors_ARG, regionsize_ARG, test_ARG)
+   "lvconvert "
+   "[-s|--snapshot]\n"
+   "\t[-c|--chunksize]\n"
+   "\t[-d|--debug]\n"
+   "\t[-h|-?|--help]\n"
+   "\t[-v|--verbose]\n"
+   "\t[-Z|--zero {y|n}]\n"
+   "\t[--version]" "\n"
+   "\tOriginalLogicalVolume[Path] SnapshotLogicalVolume[Path]\n",
+
+   alloc_ARG, chunksize_ARG, mirrors_ARG, snapshot_ARG, test_ARG, zero_ARG)
 
 xx(lvcreate,
    "Create a logical volume",
@@ -527,6 +536,7 @@
    "\t[--nosuffix]\n"
    "\t[-o|--options [+]Field[,Field]]\n"
    "\t[-O|--sort [+|-]key1[,[+|-]key2[,...]]]\n"
+   "\t[-P|--partial] " "\n"
    "\t[--segments]\n"
    "\t[--separator Separator]\n"
    "\t[--unbuffered]\n"
@@ -536,8 +546,8 @@
    "\t[PhysicalVolume [PhysicalVolume...]]\n",
    
    aligned_ARG, all_ARG, ignorelockingfailure_ARG, noheadings_ARG,
-   nolocking_ARG, nosuffix_ARG, options_ARG, segments_ARG, separator_ARG,
-   sort_ARG, unbuffered_ARG, units_ARG)
+   nolocking_ARG, nosuffix_ARG, options_ARG, partial_ARG, segments_ARG,
+   separator_ARG, sort_ARG, unbuffered_ARG, units_ARG)
 
 xx(pvscan,
    "List all physical volumes",

Modified: lvm2/upstream/current/tools/lvconvert.c
==============================================================================
--- lvm2/upstream/current/tools/lvconvert.c	(original)
+++ lvm2/upstream/current/tools/lvconvert.c	Sat Apr 15 09:40:33 2006
@@ -16,10 +16,20 @@
 #include "lv_alloc.h"
 
 struct lvconvert_params {
+	int snapshot;
+	int zero;
+
+	const char *origin;
 	const char *lv_name;
+	const char *vg_name;
+
+	uint32_t chunk_size;
+	uint32_t region_size;
+
 	uint32_t mirrors;
 	sign_t mirrors_sign;
-	uint32_t region_size;
+
+	struct segment_type *segtype;
 
 	alloc_policy_t alloc;
 
@@ -28,52 +38,164 @@
 	struct list *pvh;
 };
 
+static int _read_name_params(struct lvconvert_params *lp,
+			     struct cmd_context *cmd, int *pargc, char ***pargv)
+{
+	char *ptr;
+	const char *vg_name = NULL;
+
+	if (lp->snapshot) {
+		if (!*pargc) {
+			log_error("Please specify a logical volume to act as "
+				  "the snapshot origin.");
+			return 0;
+		}
+
+		lp->origin = *pargv[0];
+		(*pargv)++, (*pargc)--;
+		if (!(lp->vg_name = extract_vgname(cmd, lp->origin))) {
+			log_error("The origin name should include the "
+				  "volume group.");
+			return 0;
+		}
+
+		/* Strip the volume group from the origin */
+		if ((ptr = strrchr(lp->origin, (int) '/')))
+			lp->origin = ptr + 1;
+	}
+
+	if (!*pargc) {
+		log_error("Please provide logical volume path");
+		return 0;
+	}
+
+	lp->lv_name = (*pargv)[0];
+	(*pargv)++, (*pargc)--;
+
+	if (strchr(lp->lv_name, '/') &&
+	    (vg_name = extract_vgname(cmd, lp->lv_name)) &&
+	    lp->vg_name && strcmp(vg_name, lp->vg_name)) {
+		log_error("Please use a single volume group name "
+			  "(\"%s\" or \"%s\")", vg_name, lp->vg_name);
+		return 0;
+	}
+
+	if (!lp->vg_name)
+		lp->vg_name = vg_name;
+
+	if (!validate_name(lp->vg_name)) {
+		log_error("Please provide a valid volume group name");
+		return 0;
+	}
+
+	if ((ptr = strrchr(lp->lv_name, '/')))
+		lp->lv_name = ptr + 1;
+
+	if (!apply_lvname_restrictions(lp->lv_name))
+		return_0;
+
+	return 1;
+}
+
 static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
 			int argc, char **argv)
 {
 	memset(lp, 0, sizeof(*lp));
 
+	if (arg_count(cmd, mirrors_ARG) + arg_count(cmd, snapshot_ARG) != 1) {
+		log_error("Exactly one of --mirrors or --snapshot arguments "
+			  "required.");
+		return 0;
+	}
+
+	if (arg_count(cmd, snapshot_ARG))
+		lp->snapshot = 1;
+
+	if (arg_count(cmd, mirrors_ARG)) {
+		lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0);
+		lp->mirrors_sign = arg_sign_value(cmd, mirrors_ARG, 0);
+	}
+
 	lp->alloc = ALLOC_INHERIT;
 	if (arg_count(cmd, alloc_ARG))
 		lp->alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG,
 							    lp->alloc);
 
-	if (!arg_count(cmd, mirrors_ARG)) {
-		log_error("--mirrors argument required");
-		return 0;
-	}
+	if (lp->snapshot) {
+		if (arg_count(cmd, regionsize_ARG)) {
+			log_error("--regionsize is only available with mirrors");
+			return 0;
+		}
+
+		if (arg_sign_value(cmd, chunksize_ARG, 0) == SIGN_MINUS) {
+			log_error("Negative chunk size is invalid");
+			return 0;
+		}
+		lp->chunk_size = 2 * arg_uint_value(cmd, chunksize_ARG, 8);
+		if (lp->chunk_size < 8 || lp->chunk_size > 1024 ||
+		    (lp->chunk_size & (lp->chunk_size - 1))) {
+			log_error("Chunk size must be a power of 2 in the "
+				  "range 4K to 512K");
+			return 0;
+		}
+		log_verbose("Setting chunksize to %d sectors.", lp->chunk_size);
 
-	lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0);
-	lp->mirrors_sign = arg_sign_value(cmd, mirrors_ARG, 0);
+		if (!(lp->segtype = get_segtype_from_string(cmd, "snapshot")))
+			return_0;
 
-	/*
-	 * --regionsize is only valid when converting an LV into a mirror.
-	 * This is checked when we know the state of the LV being converted.
-	 */
-	if (arg_count(cmd, regionsize_ARG)) {
-		if (arg_sign_value(cmd, regionsize_ARG, 0) == SIGN_MINUS) {
-			log_error("Negative regionsize is invalid");
+		lp->zero = strcmp(arg_str_value(cmd, zero_ARG,
+						(lp->segtype->flags &
+						 SEG_CANNOT_BE_ZEROED) ?
+						"n" : "y"), "n");
+
+	} else {	/* Mirrors */
+		if (arg_count(cmd, chunksize_ARG)) {
+			log_error("--chunksize is only available with "
+				  "snapshots");
 			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;
+		if (arg_count(cmd, zero_ARG)) {
+			log_error("--zero is only available with snapshots");
+			return 0;
+		}
+
+		/*
+	 	 * --regionsize is only valid if converting an LV into a mirror.
+	 	 * Checked when we know the state of the LV being converted.
+	 	 */
+		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;
+		}
+
+		if (!(lp->segtype = get_segtype_from_string(cmd, "striped")))
+			return_0;
 	}
 
-	if (!argc) {
-		log_error("Please give logical volume path");
+	if (activation() && lp->segtype->ops->target_present &&
+	    !lp->segtype->ops->target_present()) {
+		log_error("%s: Required device-mapper target(s) not "
+			  "detected in your kernel", lp->segtype->name);
 		return 0;
 	}
 
-	lp->lv_name = argv[0];
-	argv++, argc--;
+	if (!_read_name_params(lp, cmd, &argc, &argv))
+		return_0;
 
 	lp->pv_count = argc;
 	lp->pvs = argv;
@@ -89,7 +211,6 @@
 	struct alloc_handle *ah = NULL;
 	struct logical_volume *log_lv;
 	struct list *parallel_areas;
-	struct segment_type *segtype;
 
 	seg = first_seg(lv);
 	existing_mirrors = seg->area_count;
@@ -121,10 +242,9 @@
 			return 1;
 		}
 
-		if (!remove_mirror_images(seg, 1, lp->pv_count ? lp->pvh : NULL, 1)) {
-			stack;
-			return 0;
-		}
+		if (!remove_mirror_images(seg, 1,
+					  lp->pv_count ? lp->pvh : NULL, 1))
+			return_0;
 	} else {		/* mirrors > 1 */
 		if ((lv->status & MIRRORED)) {
 			if (list_size(&lv->segments) != 1) {
@@ -149,10 +269,10 @@
 				return 0;
 			} else {
 				/* Reduce number of mirrors */
-				if (!remove_mirror_images(seg, lp->mirrors, lp->pv_count ? lp->pvh : NULL, 0)) {
-					stack;
-					return 0;
-				}
+				if (!remove_mirror_images(seg, lp->mirrors,
+							  lp->pv_count ?
+							  lp->pvh : NULL, 0))
+					return_0;
 			}
 		} else {
 			/* Make existing LV into mirror set */
@@ -166,22 +286,16 @@
 				}
 			}
 
-			if (!(parallel_areas = build_parallel_areas_from_lv(cmd, lv))) {
-				stack;
-				return 0;
-			}
-
-			segtype = get_segtype_from_string(cmd, "striped");
+			if (!(parallel_areas = build_parallel_areas_from_lv(cmd, lv)))
+				return_0;
 
-			if (!(ah = allocate_extents(lv->vg, NULL, segtype, 1,
-						    lp->mirrors - 1, 1,
+			if (!(ah = allocate_extents(lv->vg, NULL, lp->segtype,
+						    1, lp->mirrors - 1, 1,
 						    lv->le_count * (lp->mirrors - 1),
 						    NULL, 0, 0, lp->pvh,
 						    lp->alloc,
-						    parallel_areas))) {
-				stack;
-				return 0;
-			}
+						    parallel_areas)))
+				return_0;
 
 			lp->region_size = adjusted_mirror_region_size(lv->vg->extent_size,
 								      lv->le_count,
@@ -195,20 +309,17 @@
 			}
 
 			if (!create_mirror_layers(ah, 1, lp->mirrors, lv,
-						  segtype, 0, lp->region_size,
-						  log_lv)) {
-				stack;
-				return 0;
-			}
+						  lp->segtype, 0,
+						  lp->region_size,
+						  log_lv))
+				return_0;
 		}
 	}
 
 	log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
 
-	if (!vg_write(lv->vg)) {
-		stack;
-		return 0;
-	}
+	if (!vg_write(lv->vg))
+		return_0;
 
 	backup(lv->vg);
 
@@ -235,6 +346,68 @@
 	return 1;
 }
 
+static int lvconvert_snapshot(struct cmd_context *cmd,
+			      struct logical_volume *lv,
+			      struct lvconvert_params *lp)
+{
+	struct logical_volume *org;
+
+	if (!(org = find_lv(lv->vg, lp->origin))) {
+		log_error("Couldn't find origin volume '%s'.", lp->origin);
+		return 0;
+	}
+
+	if (org->status & (LOCKED|PVMOVE) || lv_is_cow(org)) {
+		log_error("Unable to create a snapshot of a %s LV.",
+			  org->status & LOCKED ? "locked" :
+			  org->status & PVMOVE ? "pvmove" : "snapshot");
+		return 0;
+	}
+
+	if (!lp->zero)
+		log_error("WARNING: \"%s\" not zeroed", lv->name);
+	else if (!zero_lv(cmd, lv)) {
+			log_error("Aborting. Failed to wipe snapshot "
+				  "exception store.");
+			return 0;
+	}
+
+	if (!deactivate_lv(cmd, lv)) {
+		log_error("Couldn't deactivate LV %s.", lv->name);
+		return 0;
+	}
+
+	if (!vg_add_snapshot(lv->vg->fid, NULL, org, lv, NULL, org->le_count,
+			     lp->chunk_size)) {
+		log_error("Couldn't create snapshot.");
+		return 0;
+	}
+
+	/* store vg on disk(s) */
+	if (!vg_write(lv->vg))
+		return_0;
+
+	backup(lv->vg);
+
+	if (!suspend_lv(cmd, org)) {
+		log_error("Failed to suspend origin %s", org->name);
+		vg_revert(lv->vg);
+		return 0;
+	}
+
+	if (!vg_commit(lv->vg))
+		return_0;
+
+	if (!resume_lv(cmd, org)) {
+		log_error("Problem reactivating origin %s", org->name);
+		return 0;
+	}
+
+	log_print("Logical volume %s converted to snapshot.", lv->name);
+
+	return 1;
+}
+
 static int lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv,
 			    void *handle)
 {
@@ -267,6 +440,11 @@
 			return ECMD_FAILED;
 		if (!lvconvert_mirrors(cmd, lv, lp))
 			return ECMD_FAILED;
+	} else if (lp->snapshot) {
+		if (!archive(lv->vg))
+			return ECMD_FAILED;
+		if (!lvconvert_snapshot(cmd, lv, lp))
+			return ECMD_FAILED;
 	}
 
 	return ECMD_PROCESSED;
@@ -274,8 +452,6 @@
 
 int lvconvert(struct cmd_context * cmd, int argc, char **argv)
 {
-	const char *vg_name;
-	char *st;
 	int consistent = 1;
 	struct volume_group *vg;
 	struct lv_list *lvl;
@@ -287,41 +463,31 @@
 		return EINVALID_CMD_LINE;
 	}
 
-	vg_name = extract_vgname(cmd, lp.lv_name);
-
-	if (!validate_name(vg_name)) {
-		log_error("Please provide a valid volume group name");
-		return EINVALID_CMD_LINE;
-	}
-
-	if ((st = strrchr(lp.lv_name, '/')))
-		lp.lv_name = st + 1;
-
-	log_verbose("Checking for existing volume group \"%s\"", vg_name);
+	log_verbose("Checking for existing volume group \"%s\"", lp.vg_name);
 
-	if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) {
-		log_error("Can't get lock for %s", vg_name);
+	if (!lock_vol(cmd, lp.vg_name, LCK_VG_WRITE)) {
+		log_error("Can't get lock for %s", lp.vg_name);
 		return ECMD_FAILED;
 	}
 
-	if (!(vg = vg_read(cmd, vg_name, &consistent))) {
-		log_error("Volume group \"%s\" doesn't exist", vg_name);
+	if (!(vg = vg_read(cmd, lp.vg_name, NULL, &consistent))) {
+		log_error("Volume group \"%s\" doesn't exist", lp.vg_name);
 		goto error;
 	}
 
 	if (vg->status & EXPORTED_VG) {
-		log_error("Volume group \"%s\" is exported", vg_name);
+		log_error("Volume group \"%s\" is exported", lp.vg_name);
 		goto error;
 	}
 
 	if (!(vg->status & LVM_WRITE)) {
-		log_error("Volume group \"%s\" is read-only", vg_name);
+		log_error("Volume group \"%s\" is read-only", lp.vg_name);
 		goto error;
 	}
 
 	if (!(lvl = find_lv_in_vg(vg, lp.lv_name))) {
 		log_error("Logical volume \"%s\" not found in "
-			  "volume group \"%s\"", lp.lv_name, vg_name);
+			  "volume group \"%s\"", lp.lv_name, lp.vg_name);
 		goto error;
 	}
 
@@ -337,6 +503,6 @@
 	ret = lvconvert_single(cmd, lvl->lv, &lp);
 
 error:
-	unlock_vg(cmd, vg_name);
+	unlock_vg(cmd, lp.vg_name);
 	return ret;
 }

Modified: lvm2/upstream/current/tools/lvcreate.c
==============================================================================
--- lvm2/upstream/current/tools/lvcreate.c	(original)
+++ lvm2/upstream/current/tools/lvcreate.c	Sat Apr 15 09:40:33 2006
@@ -444,7 +444,7 @@
 	/* does VG exist? */
 	log_verbose("Finding volume group \"%s\"", lp->vg_name);
 
-	if (!(vg = vg_read(cmd, lp->vg_name, &consistent))) {
+	if (!(vg = vg_read(cmd, lp->vg_name, NULL, &consistent))) {
 		log_error("Volume group \"%s\" doesn't exist", lp->vg_name);
 		return 0;
 	}

Modified: lvm2/upstream/current/tools/lvdisplay.c
==============================================================================
--- lvm2/upstream/current/tools/lvdisplay.c	(original)
+++ lvm2/upstream/current/tools/lvdisplay.c	Sat Apr 15 09:40:33 2006
@@ -18,8 +18,7 @@
 static int _lvdisplay_single(struct cmd_context *cmd, struct logical_volume *lv,
 			     void *handle)
 {
-	if (!arg_count(cmd, all_ARG) && !(lv->status & VISIBLE_LV) &&
-	    !(lv_is_cow(lv)))
+	if (!arg_count(cmd, all_ARG) && !lv_is_visible(lv))
 		return ECMD_PROCESSED;
 
 	if (arg_count(cmd, colon_ARG))

Modified: lvm2/upstream/current/tools/lvremove.c
==============================================================================
--- lvm2/upstream/current/tools/lvremove.c	(original)
+++ lvm2/upstream/current/tools/lvremove.c	Sat Apr 15 09:40:33 2006
@@ -83,7 +83,7 @@
 	}
 
 	if (lv_is_cow(lv)) {
-		origin = find_cow(lv)->origin;
+		origin = origin_from_cow(lv);
 		log_verbose("Removing snapshot %s", lv->name);
 		if (!vg_remove_snapshot(lv)) {
 			stack;

Modified: lvm2/upstream/current/tools/lvrename.c
==============================================================================
--- lvm2/upstream/current/tools/lvrename.c	(original)
+++ lvm2/upstream/current/tools/lvrename.c	Sat Apr 15 09:40:33 2006
@@ -106,7 +106,7 @@
 		return ECMD_FAILED;
 	}
 
-	if (!(vg = vg_read(cmd, vg_name, &consistent))) {
+	if (!(vg = vg_read(cmd, vg_name, NULL, &consistent))) {
 		log_error("Volume group \"%s\" doesn't exist", vg_name);
 		goto error;
 	}

Modified: lvm2/upstream/current/tools/lvresize.c
==============================================================================
--- lvm2/upstream/current/tools/lvresize.c	(original)
+++ lvm2/upstream/current/tools/lvresize.c	Sat Apr 15 09:40:33 2006
@@ -116,7 +116,6 @@
 {
 	struct volume_group *vg;
 	struct logical_volume *lv;
-	struct lv_segment *snap_seg;
 	struct lvinfo info;
 	uint32_t stripesize_extents = 0;
 	uint32_t seg_stripes = 0, seg_stripesize = 0, seg_size = 0;
@@ -134,7 +133,7 @@
 	char size_buf[SIZE_BUF];
 	char lv_path[PATH_MAX];
 
-	if (!(vg = vg_read(cmd, lp->vg_name, &consistent))) {
+	if (!(vg = vg_read(cmd, lp->vg_name, NULL, &consistent))) {
 		log_error("Volume group %s doesn't exist", lp->vg_name);
 		return ECMD_FAILED;
 	}
@@ -521,8 +520,8 @@
 	backup(vg);
 
 	/* If snapshot, must suspend all associated devices */
-	if ((snap_seg = find_cow(lv)))
-		lock_lv = snap_seg->origin;
+	if (lv_is_cow(lv))
+		lock_lv = origin_from_cow(lv);
 	else
 		lock_lv = lv;
 

Modified: lvm2/upstream/current/tools/lvscan.c
==============================================================================
--- lvm2/upstream/current/tools/lvscan.c	(original)
+++ lvm2/upstream/current/tools/lvscan.c	Sat Apr 15 09:40:33 2006
@@ -27,9 +27,7 @@
 
 	const char *active_str, *snapshot_str;
 
-	/* FIXME Avoid snapshot special-case */
-	if (!arg_count(cmd, all_ARG) && !(lv->status & VISIBLE_LV) &&
-	    !(lv_is_cow(lv)))
+	if (!arg_count(cmd, all_ARG) && !lv_is_visible(lv))
 		return ECMD_PROCESSED;
 
 	inkernel = lv_info(cmd, lv, &info, 1) && info.exists;
@@ -43,10 +41,9 @@
 					snap_active = 0;
 		}
 		snap_seg = NULL;
-	} else if ((snap_seg = find_cow(lv))) {
+	} else if (lv_is_cow(lv)) {
 		if (inkernel &&
-		    (snap_active = lv_snapshot_percent(snap_seg->cow,
-						       &snap_percent)))
+		    (snap_active = lv_snapshot_percent(lv, &snap_percent)))
 			if (snap_percent < 0 || snap_percent >= 100)
 				snap_active = 0;
 	}

Modified: lvm2/upstream/current/tools/pvchange.c
==============================================================================
--- lvm2/upstream/current/tools/pvchange.c	(original)
+++ lvm2/upstream/current/tools/pvchange.c	Sat Apr 15 09:40:33 2006
@@ -60,7 +60,7 @@
 			return 0;
 		}
 
-		if (!(vg = vg_read(cmd, pv->vg_name, &consistent))) {
+		if (!(vg = vg_read(cmd, pv->vg_name, NULL, &consistent))) {
 			unlock_vg(cmd, pv->vg_name);
 			log_error("Unable to find volume group of \"%s\"",
 				  pv_name);

Modified: lvm2/upstream/current/tools/pvmove.c
==============================================================================
--- lvm2/upstream/current/tools/pvmove.c	(original)
+++ lvm2/upstream/current/tools/pvmove.c	Sat Apr 15 09:40:33 2006
@@ -62,7 +62,7 @@
 		return NULL;
 	}
 
-	if (!(vg = vg_read(cmd, vgname, &consistent)) || !consistent) {
+	if (!(vg = vg_read(cmd, vgname, NULL, &consistent)) || !consistent) {
 		log_error("Volume group \"%s\" doesn't exist", vgname);
 		unlock_vg(cmd, vgname);
 		return NULL;

Modified: lvm2/upstream/current/tools/pvremove.c
==============================================================================
--- lvm2/upstream/current/tools/pvremove.c	(original)
+++ lvm2/upstream/current/tools/pvremove.c	Sat Apr 15 09:40:33 2006
@@ -33,9 +33,14 @@
 		return 0;
 	}
 
-	/* is there a pv here already */
-	if (!(pv = pv_read(cmd, name, NULL, NULL, 1)))
-		return 1;
+	/* Is there a pv here already? */
+	/* If not, this is an error unless you used -f. */
+	if (!(pv = pv_read(cmd, name, NULL, NULL, 1))) {
+		if (arg_count(cmd, force_ARG))
+			return 1;
+		else
+			return 0;
+	}
 
 	/* orphan ? */
 	if (!pv->vg_name[0])

Modified: lvm2/upstream/current/tools/pvresize.c
==============================================================================
--- lvm2/upstream/current/tools/pvresize.c	(original)
+++ lvm2/upstream/current/tools/pvresize.c	Sat Apr 15 09:40:33 2006
@@ -70,7 +70,7 @@
 			return ECMD_FAILED;
 		}
 
-		if (!(vg = vg_read(cmd, vg_name, &consistent))) {
+		if (!(vg = vg_read(cmd, vg_name, NULL, &consistent))) {
 			unlock_vg(cmd, vg_name);
 			log_error("Unable to find volume group of \"%s\"",
 				  pv_name);

Modified: lvm2/upstream/current/tools/reporter.c
==============================================================================
--- lvm2/upstream/current/tools/reporter.c	(original)
+++ lvm2/upstream/current/tools/reporter.c	Sat Apr 15 09:40:33 2006
@@ -35,9 +35,7 @@
 static int _lvs_single(struct cmd_context *cmd, struct logical_volume *lv,
 		       void *handle)
 {
-	/* FIXME Avoid snapshot special-case */
-	if (!arg_count(cmd, all_ARG) && !(lv->status & VISIBLE_LV) &&
-	    !(lv_is_cow(lv)))
+	if (!arg_count(cmd, all_ARG) && !lv_is_visible(lv))
 		return ECMD_PROCESSED;
 
 	if (!report_object(handle, lv->vg, lv, NULL, NULL, NULL))
@@ -67,7 +65,7 @@
 		return ECMD_FAILED;
 	}
 
-	if (!(vg = vg_read(cmd, pv->vg_name, &consistent))) {
+	if (!(vg = vg_read(cmd, pv->vg_name, NULL, &consistent))) {
 		log_error("Can't read %s: skipping", pv->vg_name);
 		unlock_vg(cmd, pv->vg_name);
 		return ECMD_FAILED;
@@ -83,9 +81,7 @@
 static int _lvsegs_single(struct cmd_context *cmd, struct logical_volume *lv,
 			  void *handle)
 {
-	/* FIXME Avoid snapshot special-case */
-	if (!arg_count(cmd, all_ARG) && !(lv->status & VISIBLE_LV) &&
-	    !(lv_is_cow(lv)))
+	if (!arg_count(cmd, all_ARG) && !lv_is_visible(lv))
 		return ECMD_PROCESSED;
 
 	return process_each_segment_in_lv(cmd, lv, handle, _segs_single);
@@ -110,7 +106,7 @@
 			return ECMD_FAILED;
 		}
 
-		if (!(vg = vg_read(cmd, pv->vg_name, &consistent))) {
+		if (!(vg = vg_read(cmd, pv->vg_name, (char *)&pv->vgid, &consistent))) {
 			log_error("Can't read %s: skipping", pv->vg_name);
 			unlock_vg(cmd, pv->vg_name);
 			return ECMD_FAILED;

Modified: lvm2/upstream/current/tools/toollib.c
==============================================================================
--- lvm2/upstream/current/tools/toollib.c	(original)
+++ lvm2/upstream/current/tools/toollib.c	Sat Apr 15 09:40:33 2006
@@ -241,7 +241,7 @@
 			consistent = 1;
 		else
 			consistent = 0;
-		if (!(vg = vg_read(cmd, vgname, &consistent)) || !consistent) {
+		if (!(vg = vg_read(cmd, vgname, NULL, &consistent)) || !consistent) {
 			unlock_vg(cmd, vgname);
 			if (!vg)
 				log_error("Volume group \"%s\" "
@@ -250,7 +250,6 @@
 				log_error("Volume group \"%s\" "
 					  "inconsistent", vgname);
 			if (!vg || !(vg = recover_vg(cmd, vgname, lock_type))) {
-				unlock_vg(cmd, vgname);
 				if (ret_max < ECMD_FAILED)
 					ret_max = ECMD_FAILED;
 				continue;
@@ -332,6 +331,7 @@
 }
 
 static int _process_one_vg(struct cmd_context *cmd, const char *vg_name,
+			   const char *vgid,
 			   struct list *tags, struct list *arg_vgnames,
 			   int lock_type, int consistent, void *handle,
 			   int ret_max,
@@ -349,7 +349,7 @@
 	}
 
 	log_verbose("Finding volume group \"%s\"", vg_name);
-	vg = vg_read(cmd, vg_name, &consistent);
+	vg = vg_read(cmd, vg_name, vgid, &consistent);
 
 	if (!list_empty(tags)) {
 		/* Only process if a tag matches or it's on arg_vgnames */
@@ -381,10 +381,10 @@
 	int ret_max = 0;
 
 	struct str_list *sl;
-	struct list *vgnames;
+	struct list *vgnames, *vgids;
 	struct list arg_vgnames, tags;
 
-	const char *vg_name;
+	const char *vg_name, *vgid;
 	char *dev_dir = cmd->dev_dir;
 
 	list_init(&tags);
@@ -434,19 +434,30 @@
 
 	if (!argc || !list_empty(&tags)) {
 		log_verbose("Finding all volume groups");
-		if (!(vgnames = get_vgs(cmd, 0)) || list_empty(vgnames)) {
+		if (!(vgids = get_vgids(cmd, 0)) || list_empty(vgids)) {
 			log_error("No volume groups found");
 			return ret_max;
 		}
-	}
-
-	list_iterate_items(sl, vgnames) {
-		vg_name = sl->str;
-		if (!vg_name || !*vg_name)
-			continue;	/* FIXME Unnecessary? */
-		ret_max = _process_one_vg(cmd, vg_name, &tags, &arg_vgnames,
-					  lock_type, consistent, handle,
-					  ret_max, process_single);
+		list_iterate_items(sl, vgids) {
+			vgid = sl->str;
+			if (!vgid || !(vg_name = vgname_from_vgid(cmd->mem, vgid)) ||
+			    !*vg_name)
+				continue;
+			ret_max = _process_one_vg(cmd, vg_name, vgid, &tags,
+						  &arg_vgnames,
+					  	  lock_type, consistent, handle,
+					  	  ret_max, process_single);
+		}
+	} else {
+		list_iterate_items(sl, vgnames) {
+			vg_name = sl->str;
+			if (!vg_name || !*vg_name)
+				continue;	/* FIXME Unnecessary? */
+			ret_max = _process_one_vg(cmd, vg_name, NULL, &tags,
+						  &arg_vgnames,
+					  	  lock_type, consistent, handle,
+					  	  ret_max, process_single);
+		}
 	}
 
 	return ret_max;
@@ -582,7 +593,7 @@
 		if (!list_empty(&tags) && (vgnames = get_vgs(cmd, 0)) &&
 		    !list_empty(vgnames)) {
 			list_iterate_items(sll, vgnames) {
-				vg = vg_read(cmd, sll->str, &consistent);
+				vg = vg_read(cmd, sll->str, NULL, &consistent);
 				if (!consistent)
 					continue;
 				ret = process_each_pv_in_vg(cmd, vg, &tags,
@@ -967,7 +978,7 @@
 		return NULL;
 	}
 
-	return vg_read(cmd, vgname, &consistent);
+	return vg_read(cmd, vgname, NULL, &consistent);
 }
 
 int apply_lvname_restrictions(const char *name)
@@ -1046,7 +1057,7 @@
 	 * <clausen> also, more than 4k
 	 * <clausen> say, reiserfs puts it's superblock 32k in, IIRC
 	 * <ejt_> k, I'll drop a fixme to that effect
-	 *           (I know the device is at least 4k, but not 32k)
+	 *	   (I know the device is at least 4k, but not 32k)
 	 */
 	if (!(name = dm_pool_alloc(cmd->mem, PATH_MAX))) {
 		log_error("Name allocation failed - device not zeroed");

Modified: lvm2/upstream/current/tools/vgchange.c
==============================================================================
--- lvm2/upstream/current/tools/vgchange.c	(original)
+++ lvm2/upstream/current/tools/vgchange.c	Sat Apr 15 09:40:33 2006
@@ -198,7 +198,7 @@
 
 	if (clustered) {
         	list_iterate_items(lvl, &vg->lvs) {
-                	if (lvl->lv->origin_count || lvl->lv->snapshot) {
+                	if (lv_is_origin(lvl->lv) || lv_is_cow(lvl->lv)) {
 				log_error("Volume group %s contains snapshots "
 					  "that are not yet supported.",
 					  vg->name);

Modified: lvm2/upstream/current/tools/vgexport.c
==============================================================================
--- lvm2/upstream/current/tools/vgexport.c	(original)
+++ lvm2/upstream/current/tools/vgexport.c	Sat Apr 15 09:40:33 2006
@@ -19,6 +19,9 @@
 			   struct volume_group *vg, int consistent,
 			   void *handle)
 {
+	struct pv_list *pvl;
+	struct physical_volume *pv;
+
 	if (!vg) {
 		log_error("Unable to find volume group \"%s\"", vg_name);
 		goto error;
@@ -50,6 +53,11 @@
 
 	vg->status |= EXPORTED_VG;
 
+	list_iterate_items(pvl, &vg->pvs) {
+		pv = pvl->pv;
+		pv->status |= EXPORTED_VG;
+	}
+
 	if (!vg_write(vg) || !vg_commit(vg))
 		goto error;
 

Modified: lvm2/upstream/current/tools/vgextend.c
==============================================================================
--- lvm2/upstream/current/tools/vgextend.c	(original)
+++ lvm2/upstream/current/tools/vgextend.c	Sat Apr 15 09:40:33 2006
@@ -48,7 +48,7 @@
 		goto error;
 	}
 
-	if (!(vg = vg_read(cmd, vg_name, &consistent)) || !consistent) {
+	if (!(vg = vg_read(cmd, vg_name, NULL, &consistent)) || !consistent) {
 		log_error("Volume group \"%s\" not found.", vg_name);
 		goto error;
 	}

Modified: lvm2/upstream/current/tools/vgimport.c
==============================================================================
--- lvm2/upstream/current/tools/vgimport.c	(original)
+++ lvm2/upstream/current/tools/vgimport.c	Sat Apr 15 09:40:33 2006
@@ -19,6 +19,9 @@
 			   struct volume_group *vg, int consistent,
 			   void *handle)
 {
+	struct pv_list *pvl;
+	struct physical_volume *pv;
+
 	if (!vg || !consistent) {
 		log_error("Unable to find exported volume group \"%s\"",
 			  vg_name);
@@ -40,6 +43,11 @@
 
 	vg->status &= ~EXPORTED_VG;
 
+	list_iterate_items(pvl, &vg->pvs) {
+		pv = pvl->pv;
+		pv->status &= ~EXPORTED_VG;
+	}
+
 	if (!vg_write(vg) || !vg_commit(vg))
 		goto error;
 

Modified: lvm2/upstream/current/tools/vgmerge.c
==============================================================================
--- lvm2/upstream/current/tools/vgmerge.c	(original)
+++ lvm2/upstream/current/tools/vgmerge.c	Sat Apr 15 09:40:33 2006
@@ -35,7 +35,7 @@
 		return ECMD_FAILED;
 	}
 
-	if (!(vg_to = vg_read(cmd, vg_name_to, &consistent)) || !consistent) {
+	if (!(vg_to = vg_read(cmd, vg_name_to, NULL, &consistent)) || !consistent) {
 		log_error("Volume group \"%s\" doesn't exist", vg_name_to);
 		unlock_vg(cmd, vg_name_to);
 		return ECMD_FAILED;
@@ -61,7 +61,7 @@
 	}
 
 	consistent = 1;
-	if (!(vg_from = vg_read(cmd, vg_name_from, &consistent)) || !consistent) {
+	if (!(vg_from = vg_read(cmd, vg_name_from, NULL, &consistent)) || !consistent) {
 		log_error("Volume group \"%s\" doesn't exist", vg_name_from);
 		goto error;
 	}

Modified: lvm2/upstream/current/tools/vgreduce.c
==============================================================================
--- lvm2/upstream/current/tools/vgreduce.c	(original)
+++ lvm2/upstream/current/tools/vgreduce.c	Sat Apr 15 09:40:33 2006
@@ -432,7 +432,7 @@
 		return ECMD_FAILED;
 	}
 
-	if ((!(vg = vg_read(cmd, vg_name, &consistent)) || !consistent) &&
+	if ((!(vg = vg_read(cmd, vg_name, NULL, &consistent)) || !consistent) &&
 	    !arg_count(cmd, removemissing_ARG)) {
 		log_error("Volume group \"%s\" doesn't exist", vg_name);
 		unlock_vg(cmd, vg_name);
@@ -449,7 +449,7 @@
 
 		init_partial(1);
 		consistent = 0;
-		if (!(vg = vg_read(cmd, vg_name, &consistent))) {
+		if (!(vg = vg_read(cmd, vg_name, NULL, &consistent))) {
 			log_error("Volume group \"%s\" not found", vg_name);
 			unlock_vg(cmd, vg_name);
 			return ECMD_FAILED;

Modified: lvm2/upstream/current/tools/vgrename.c
==============================================================================
--- lvm2/upstream/current/tools/vgrename.c	(original)
+++ lvm2/upstream/current/tools/vgrename.c	Sat Apr 15 09:40:33 2006
@@ -19,12 +19,15 @@
 {
 	char *dev_dir;
 	unsigned int length;
+	struct id id;
 	int consistent = 1;
-
-	char *vg_name_old, *vg_name_new;
-
+	int match = 0;
+	int found_id = 0;
+	struct list *vgids;
+	struct str_list *sl;
+	char *vg_name_new;
+	const char *vgid = NULL, *vg_name, *vg_name_old;
 	char old_path[NAME_LEN], new_path[NAME_LEN];
-
 	struct volume_group *vg_old, *vg_new;
 
 	if (argc != 2) {
@@ -64,23 +67,50 @@
 
 	log_verbose("Checking for existing volume group \"%s\"", vg_name_old);
 
-	if (!lock_vol(cmd, vg_name_old, LCK_VG_WRITE)) {
-		log_error("Can't get lock for %s", vg_name_old);
+	/* Avoid duplicates */
+	if (!(vgids = get_vgids(cmd, 0)) || list_empty(vgids)) {
+		log_error("No complete volume groups found");
 		return ECMD_FAILED;
 	}
 
-	if (!(vg_old = vg_read(cmd, vg_name_old, &consistent)) || !consistent) {
-		log_error("Volume group \"%s\" doesn't exist", vg_name_old);
-		unlock_vg(cmd, vg_name_old);
+	list_iterate_items(sl, vgids) {
+		vgid = sl->str;
+		if (!vgid || !(vg_name = vgname_from_vgid(NULL, vgid)) || !*vg_name)
+			continue;
+		if (!strcmp(vg_name, vg_name_old)) {
+			if (match) {
+				log_error("Found more than one VG called %s. "
+					  "Please supply VG uuid.", vg_name_old);
+				return ECMD_FAILED;
+			}
+			match = 1;
+		}
+	}
+
+	log_suppress(2);
+	found_id = id_read_format(&id, vg_name_old);
+	log_suppress(0);
+	if (found_id && (vg_name = vgname_from_vgid(cmd->mem, id.uuid))) {
+		vg_name_old = vg_name;
+		vgid = id.uuid;
+	} else
+		vgid = NULL;
+
+	if (!lock_vol(cmd, vg_name_old, LCK_VG_WRITE)) {
+		log_error("Can't get lock for %s", vg_name_old);
 		return ECMD_FAILED;
 	}
 
-	if (vg_old->status & EXPORTED_VG) {
+	if (!(vg_old = vg_read(cmd, vg_name_old, vgid, &consistent)) || !consistent) {
+		log_error("Volume group %s %s%s%snot found.", vg_name_old,
+		vgid ? "(" : "", vgid ? vgid : "", vgid ? ") " : "");
 		unlock_vg(cmd, vg_name_old);
-		log_error("Volume group \"%s\" is exported", vg_old->name);
 		return ECMD_FAILED;
 	}
 
+	if (vg_old->status & EXPORTED_VG)
+		log_info("Volume group \"%s\" is exported", vg_old->name);
+
 	if (!(vg_old->status & LVM_WRITE)) {
 		unlock_vg(cmd, vg_name_old);
 		log_error("Volume group \"%s\" is read-only", vg_old->name);
@@ -104,7 +134,7 @@
 	}
 
 	consistent = 0;
-	if ((vg_new = vg_read(cmd, vg_name_new, &consistent))) {
+	if ((vg_new = vg_read(cmd, vg_name_new, NULL, &consistent))) {
 		log_error("New volume group \"%s\" already exists",
 			  vg_name_new);
 		goto error;
@@ -146,6 +176,10 @@
 	log_print("Volume group \"%s\" successfully renamed to \"%s\"",
 		  vg_name_old, vg_name_new);
 
+	/* FIXME lvmcache corruption - vginfo duplicated instead of renamed */
+        persistent_filter_wipe(cmd->filter);
+        lvmcache_destroy();
+
 	return ECMD_PROCESSED;
 
       error:

Modified: lvm2/upstream/current/tools/vgsplit.c
==============================================================================
--- lvm2/upstream/current/tools/vgsplit.c	(original)
+++ lvm2/upstream/current/tools/vgsplit.c	Sat Apr 15 09:40:33 2006
@@ -190,7 +190,7 @@
 		return ECMD_FAILED;
 	}
 
-	if (!(vg_from = vg_read(cmd, vg_name_from, &consistent)) || !consistent) {
+	if (!(vg_from = vg_read(cmd, vg_name_from, NULL, &consistent)) || !consistent) {
 		log_error("Volume group \"%s\" doesn't exist", vg_name_from);
 		unlock_vg(cmd, vg_name_from);
 		return ECMD_FAILED;
@@ -216,7 +216,7 @@
 	}
 
 	consistent = 0;
-	if ((vg_to = vg_read(cmd, vg_name_to, &consistent))) {
+	if ((vg_to = vg_read(cmd, vg_name_to, NULL, &consistent))) {
 		/* FIXME Remove this restriction */
 		log_error("Volume group \"%s\" already exists", vg_name_to);
 		goto error;
@@ -287,7 +287,7 @@
 
 	/* Remove EXPORTED flag from new VG */
 	consistent = 1;
-	if (!(vg_to = vg_read(cmd, vg_name_to, &consistent)) || !consistent) {
+	if (!(vg_to = vg_read(cmd, vg_name_to, NULL, &consistent)) || !consistent) {
 		log_error("Volume group \"%s\" became inconsistent: please "
 			  "fix manually", vg_name_to);
 		goto error;



More information about the pkg-lvm-commits mailing list