[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[lvm-devel] [PATCH] lvmetad client side



Hi,

the attached patch is a semi-final version of the lvmetad
integration. In lvmetad mode it gets through all the tests fine, without
lvmetad I get a new failure in lvcreate-repair, somehow related to
vgremove -ff. I'll investigate that tomorrow. There are some other
issues that need to be sorted out, but I'll do these bits when this main
blob is merged. At least a cursory review is still needed.

Petr

Index: daemons/dmeventd/plugins/lvm2/Makefile.in
===================================================================
RCS file: /cvs/lvm2/LVM2/daemons/dmeventd/plugins/lvm2/Makefile.in,v
retrieving revision 1.7
diff -u -p -r1.7 Makefile.in
--- daemons/dmeventd/plugins/lvm2/Makefile.in	24 Sep 2011 21:00:52 -0000	1.7
+++ daemons/dmeventd/plugins/lvm2/Makefile.in	21 Feb 2012 23:46:52 -0000
@@ -24,7 +24,7 @@ LIB_VERSION = $(LIB_VERSION_LVM)
 
 include $(top_builddir)/make.tmpl
 
-LIBS += @LVM2CMD_LIB@ -ldevmapper $(PTHREAD_LIBS)
+LIBS += @LVM2CMD_LIB@ -ldevmapper $(PTHREAD_LIBS) -L$(top_builddir)/daemons/common -ldaemon
 
 install_lvm2: install_lib_shared
 
Index: daemons/dmeventd/plugins/mirror/Makefile.in
===================================================================
RCS file: /cvs/lvm2/LVM2/daemons/dmeventd/plugins/mirror/Makefile.in,v
retrieving revision 1.23
diff -u -p -r1.23 Makefile.in
--- daemons/dmeventd/plugins/mirror/Makefile.in	24 Sep 2011 21:00:52 -0000	1.23
+++ daemons/dmeventd/plugins/mirror/Makefile.in	21 Feb 2012 23:46:53 -0000
@@ -30,7 +30,7 @@ CFLOW_LIST_TARGET = $(LIB_NAME).cflow
 
 include $(top_builddir)/make.tmpl
 
-LIBS += -ldevmapper-event-lvm2 -ldevmapper
+LIBS += -ldevmapper-event-lvm2 -ldevmapper -L$(top_builddir)/daemons/common -ldaemon
 
 install_lvm2: install_dm_plugin
 
Index: daemons/dmeventd/plugins/snapshot/Makefile.in
===================================================================
RCS file: /cvs/lvm2/LVM2/daemons/dmeventd/plugins/snapshot/Makefile.in,v
retrieving revision 1.18
diff -u -p -r1.18 Makefile.in
--- daemons/dmeventd/plugins/snapshot/Makefile.in	24 Sep 2011 21:00:53 -0000	1.18
+++ daemons/dmeventd/plugins/snapshot/Makefile.in	21 Feb 2012 23:46:53 -0000
@@ -26,7 +26,7 @@ LIB_VERSION = $(LIB_VERSION_LVM)
 
 include $(top_builddir)/make.tmpl
 
-LIBS += -ldevmapper-event-lvm2 -ldevmapper
+LIBS += -ldevmapper-event-lvm2 -ldevmapper -L$(top_builddir)/daemons/common -ldaemon
 
 install_lvm2: install_dm_plugin
 
Index: doc/example.conf.in
===================================================================
RCS file: /cvs/lvm2/LVM2/doc/example.conf.in,v
retrieving revision 1.43
diff -u -p -r1.43 example.conf.in
--- doc/example.conf.in	26 Jan 2012 14:02:44 -0000	1.43
+++ doc/example.conf.in	21 Feb 2012 23:46:54 -0000
@@ -453,6 +453,16 @@ global {
     # Set to 1 to reinstate the previous format.
     #
     # lvdisplay_shows_full_device_path = 0
+
+    # Whether to use (trust) a running instance of lvmetad. If this is set to
+    # 0, all commands fall back to the usual scanning mechanisms. When set to 1
+    # *and* when lvmetad is running (it is not auto-started), the volume group
+    # metadata and PV state flags are obtained from the lvmetad instance and no
+    # scanning is done by the individual commands. In a setup with lvmetad,
+    # lvmetad udev rules *must* be set up for LVM to work correctly. Without
+    # proper udev rules, all changes in block device configuration will be
+    # *ignored* until a manual 'vgscan' is performed.
+    use_lvmetad = 0
 }
 
 activation {
Index: lib/Makefile.in
===================================================================
RCS file: /cvs/lvm2/LVM2/lib/Makefile.in,v
retrieving revision 1.114
diff -u -p -r1.114 Makefile.in
--- lib/Makefile.in	11 Nov 2011 15:11:10 -0000	1.114
+++ lib/Makefile.in	21 Feb 2012 23:46:55 -0000
@@ -16,6 +16,8 @@ srcdir = @srcdir@
 top_srcdir = @top_srcdir@
 top_builddir = @top_builddir@
 
+INCLUDES += -I$(top_srcdir)/daemons/common -I$(top_srcdir)/daemons/lvmetad
+
 ifeq ("@LVM1@", "shared")
   SUBDIRS = format1
 endif
@@ -46,6 +48,7 @@ endif
 
 SOURCES =\
 	activate/activate.c \
+	cache/lvmetad.c \
 	cache/lvmcache.c \
 	commands/toolcontext.c \
 	config/config.c \
Index: lib/activate/activate.c
===================================================================
RCS file: /cvs/lvm2/LVM2/lib/activate/activate.c,v
retrieving revision 1.241
diff -u -p -r1.241 activate.c
--- lib/activate/activate.c	25 Jan 2012 22:16:04 -0000	1.241
+++ lib/activate/activate.c	21 Feb 2012 23:46:57 -0000
@@ -1883,7 +1883,7 @@ int lv_mknodes(struct cmd_context *cmd, 
 int pv_uses_vg(struct physical_volume *pv,
 	       struct volume_group *vg)
 {
-	if (!activation())
+	if (!activation() || !pv->dev)
 		return 0;
 
 	if (!dm_is_dm_major(MAJOR(pv->dev->dev)))
Index: lib/cache/lvmcache.c
===================================================================
RCS file: /cvs/lvm2/LVM2/lib/cache/lvmcache.c,v
retrieving revision 1.126
diff -u -p -r1.126 lvmcache.c
--- lib/cache/lvmcache.c	13 Feb 2012 14:26:15 -0000	1.126
+++ lib/cache/lvmcache.c	21 Feb 2012 23:46:59 -0000
@@ -28,6 +28,8 @@
 #include "format1.h"
 #include "config.h"
 
+#include "lvmetad.h"
+
 #define CACHE_INVALID	0x00000001
 #define CACHE_LOCKED	0x00000002
 
@@ -107,9 +109,20 @@ int lvmcache_init(void)
 		_vg_global_lock_held = 0;
 	}
 
+	lvmetad_init();
+
 	return 1;
 }
 
+void lvmcache_seed_infos_from_lvmetad(struct cmd_context *cmd)
+{
+	if (lvmetad_active() && !_has_scanned) {
+		lvmetad_pv_list_to_lvmcache(cmd);
+		_has_scanned = 1;
+	}
+};
+
+
 /* Volume Group metadata cache functions */
 static void _free_cached_vgmetadata(struct lvmcache_vginfo *vginfo)
 {
@@ -429,7 +442,9 @@ struct lvmcache_vginfo *lvmcache_vginfo_
 	return vginfo;
 }
 
-const struct format_type *lvmcache_fmt_from_vgname(const char *vgname, const char *vgid, unsigned revalidate_labels)
+const struct format_type *lvmcache_fmt_from_vgname(struct cmd_context *cmd,
+						   const char *vgname, const char *vgid,
+						   unsigned revalidate_labels)
 {
 	struct lvmcache_vginfo *vginfo;
 	struct lvmcache_info *info;
@@ -439,8 +454,19 @@ const struct format_type *lvmcache_fmt_f
 	struct device_list *devl;
 	char vgid_found[ID_LEN + 1] __attribute__((aligned(8)));
 
-	if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, vgid)))
+	if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, vgid))) {
+		if (!lvmetad_active())
+			return NULL; /* too bad */
+		/* If we don't have the info but we have lvmetad, we can ask
+		 * there before failing. */
+		struct volume_group *vg = lvmetad_vg_lookup(cmd, vgname, vgid);
+		if (vg) {
+			const struct format_type *fmt = vg->fid->fmt;
+			release_vg(vg);
+			return fmt;
+		}
 		return NULL;
+	}
 
 	/*
 	 * If this function is called repeatedly, only the first one needs to revalidate.
@@ -581,6 +607,13 @@ struct lvmcache_info *lvmcache_info_from
 	return info;
 }
 
+const char *lvmcache_vgname_from_info(struct lvmcache_info *info)
+{
+	if (info->vginfo)
+		return info->vginfo->vgname;
+	return NULL;
+}
+
 char *lvmcache_vgname_from_pvid(struct cmd_context *cmd, const char *pvid)
 {
 	struct lvmcache_info *info;
@@ -626,6 +659,9 @@ int lvmcache_label_scan(struct cmd_conte
 
 	int r = 0;
 
+	if (lvmetad_active())
+		return 1;
+
 	/* Avoid recursion when a PVID can't be found! */
 	if (_scanning_in_progress)
 		return 0;
@@ -678,13 +714,28 @@ int lvmcache_label_scan(struct cmd_conte
 	return r;
 }
 
-struct volume_group *lvmcache_get_vg(const char *vgid, unsigned precommitted)
+struct volume_group *lvmcache_get_vg(struct cmd_context *cmd, const char *vgname,
+				     const char *vgid, unsigned precommitted)
 {
 	struct lvmcache_vginfo *vginfo;
 	struct volume_group *vg = NULL;
 	struct format_instance *fid;
 	struct format_instance_ctx fic;
 
+	/*
+	 * We currently do not store precommitted metadata in lvmetad at
+	 * all. This means that any request for precommitted metadata is served
+	 * using the classic scanning mechanics, and read from disk or from
+	 * lvmcache.
+	 */
+	if (lvmetad_active() && !precommitted) {
+		/* Still serve the locally cached VG if available */
+		if (vgid && (vginfo = lvmcache_vginfo_from_vgid(vgid)) &&
+		    vginfo->vgmetadata && (vg = vginfo->cached_vg))
+			goto out;
+		return lvmetad_vg_lookup(cmd, vgname, vgid);
+	}
+
 	if (!vgid || !(vginfo = lvmcache_vginfo_from_vgid(vgid)) || !vginfo->vgmetadata)
 		return NULL;
 
@@ -781,6 +832,7 @@ struct dm_list *lvmcache_get_vgids(struc
 	struct dm_list *vgids;
 	struct lvmcache_vginfo *vginfo;
 
+	// TODO plug into lvmetad here automagically?
 	lvmcache_label_scan(cmd, 0);
 
 	if (!(vgids = str_list_create(cmd->mem))) {
@@ -862,6 +914,12 @@ static struct device *_device_from_pvid(
 	struct label *label;
 
 	if ((info = lvmcache_info_from_pvid((const char *) pvid, 0))) {
+		if (lvmetad_active()) {
+			if (info->label && label_sector)
+				*label_sector = info->label->sector;
+			return info->dev;
+		}
+
 		if (label_read(info->dev, &label, UINT64_C(0))) {
 			info = (struct lvmcache_info *) label->info;
 			if (id_equal(pvid, (struct id *) &info->dev->pvid)) {
@@ -1333,6 +1391,10 @@ int lvmcache_update_vgname_and_id(struct
 		vgid = vgname;
 	}
 
+	/* When using lvmetad, the PV could not have become orphaned. */
+	if (lvmetad_active() && is_orphan_vg(vgname) && info->vginfo)
+		return 1;
+
 	/* If PV without mdas is already in a real VG, don't make it orphan */
 	if (is_orphan_vg(vgname) && info->vginfo &&
 	    mdas_empty_or_ignored(&info->mdas) &&
@@ -1408,6 +1470,9 @@ struct lvmcache_info *lvmcache_add(struc
 		info->label = label;
 		dm_list_init(&info->list);
 		info->dev = dev;
+
+		lvmcache_del_mdas(info);
+		lvmcache_del_das(info);
 	} else {
 		if (existing->dev != dev) {
 			/* Is the existing entry a duplicate pvid e.g. md ? */
@@ -1711,7 +1776,7 @@ int lvmcache_update_das(struct lvmcache_
 	} else
 		dm_list_init(&info->das);
 
-	if (!add_da(NULL, &info->das, pv->pe_start << SECTOR_SHIFT, UINT64_C(0)))
+	if (!add_da(NULL, &info->das, pv->pe_start << SECTOR_SHIFT, pv->size << SECTOR_SHIFT))
 		return_0;
 
 	return 1;
@@ -1749,12 +1814,12 @@ int lvmcache_mda_count(struct lvmcache_i
 }
 
 int lvmcache_foreach_da(struct lvmcache_info *info,
-			int (*fun)(struct data_area_list *, void *),
+			int (*fun)(struct disk_locn *, void *),
 			void *baton)
 {
 	struct data_area_list *da;
 	dm_list_iterate_items(da, &info->das) {
-		if (!fun(da, baton))
+		if (!fun(&da->disk_locn, baton))
 			return_0;
 	}
 
@@ -1793,6 +1858,10 @@ int lvmcache_is_orphan(struct lvmcache_i
 
 int lvmcache_vgid_is_cached(const char *vgid) {
 	struct lvmcache_vginfo *vginfo;
+
+	if (lvmetad_active())
+		return 1;
+
 	vginfo = lvmcache_vginfo_from_vgid(vgid);
 
 	if (!vginfo || !vginfo->vgname)
Index: lib/cache/lvmcache.h
===================================================================
RCS file: /cvs/lvm2/LVM2/lib/cache/lvmcache.h,v
retrieving revision 1.42
diff -u -p -r1.42 lvmcache.h
--- lib/cache/lvmcache.h	10 Feb 2012 01:28:27 -0000	1.42
+++ lib/cache/lvmcache.h	21 Feb 2012 23:46:59 -0000
@@ -34,11 +34,13 @@ struct physical_volume;
 struct dm_config_tree;
 struct format_instance;
 struct metadata_area;
-struct data_area_list;
+struct disk_locn;
 
 struct lvmcache_vginfo;
 
 int lvmcache_init(void);
+void lvmcache_allow_reads_with_lvmetad();
+
 void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans);
 
 /* Set full_scan to 1 to reread every filtered device label or
@@ -64,7 +66,7 @@ void lvmcache_unlock_vgname(const char *
 int lvmcache_verify_lock_order(const char *vgname);
 
 /* Queries */
-const struct format_type *lvmcache_fmt_from_vgname(const char *vgname, const char *vgid, unsigned revalidate_labels);
+const struct format_type *lvmcache_fmt_from_vgname(struct cmd_context *cmd, const char *vgname, const char *vgid, unsigned revalidate_labels);
 
 /* Decrement and test if there are still vg holders in vginfo. */
 int lvmcache_vginfo_holders_dec_and_test_for_zero(struct lvmcache_vginfo *vginfo);
@@ -79,9 +81,12 @@ struct device *lvmcache_device_from_pvid
 const char *lvmcache_pvid_from_devname(struct cmd_context *cmd,
 			      const char *dev_name);
 char *lvmcache_vgname_from_pvid(struct cmd_context *cmd, const char *pvid);
+const char *lvmcache_vgname_from_info(struct lvmcache_info *info);
 int lvmcache_vgs_locked(void);
 int lvmcache_vgname_is_locked(const char *vgname);
 
+void lvmcache_seed_infos_from_lvmetad(struct cmd_context *cmd);
+
 /* Returns list of struct str_lists containing pool-allocated copy of vgnames */
 /* If include_internal is not set, return only proper vg names. */
 struct dm_list *lvmcache_get_vgnames(struct cmd_context *cmd,
@@ -97,7 +102,8 @@ struct dm_list *lvmcache_get_pvids(struc
 				const char *vgid);
 
 /* Returns cached volume group metadata. */
-struct volume_group *lvmcache_get_vg(const char *vgid, unsigned precommitted);
+struct volume_group *lvmcache_get_vg(struct cmd_context *cmd, const char *vgname,
+				     const char *vgid, unsigned precommitted);
 void lvmcache_drop_metadata(const char *vgname, int drop_precommitted);
 void lvmcache_commit_metadata(const char *vgname);
 
@@ -127,7 +133,7 @@ int lvmcache_foreach_mda(struct lvmcache
 			 void *baton);
 
 int lvmcache_foreach_da(struct lvmcache_info *info,
-			int (*fun)(struct data_area_list *, void *),
+			int (*fun)(struct disk_locn *, void *),
 			void *baton);
 
 int lvmcache_foreach_pv(struct lvmcache_vginfo *vg,
Index: lib/cache/lvmetad.c
===================================================================
RCS file: lib/cache/lvmetad.c
diff -N lib/cache/lvmetad.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/cache/lvmetad.c	21 Feb 2012 23:46:59 -0000
@@ -0,0 +1,635 @@
+#include "lib.h"
+#include "toolcontext.h"
+#include "metadata.h"
+#include "device.h"
+#include "lvmetad.h"
+#include "lvmcache.h"
+#include "lvmetad-client.h"
+#include "format-text.h" // TODO for disk_locn, used as a DA representation
+#include "filter.h"
+
+static int _using_lvmetad = 0;
+static daemon_handle _lvmetad;
+
+void lvmetad_init(void)
+{
+	const char *socket = getenv("LVM_LVMETAD_SOCKET");
+	if (_using_lvmetad) { /* configured by the toolcontext */
+		_lvmetad = lvmetad_open(socket ?: DEFAULT_RUN_DIR "/lvmetad.socket");
+		if (_lvmetad.socket_fd < 0) {
+			log_warn("Failed to connect to lvmetad. Falling back to scanning.");
+			_using_lvmetad = 0;
+		}
+	}
+}
+
+/*
+ * Helper; evaluate the reply from lvmetad, check for errors, print diagnostics
+ * and return a summary success/failure exit code. Frees up the reply resources
+ * as well.
+ */
+static int _lvmetad_handle_reply(daemon_reply reply, const char *action, const char *object) {
+	if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
+		log_error("Request to %s %s in lvmetad has failed. Reason: %s",
+			  action, object, reply.error ? strerror(reply.error) :
+			  daemon_reply_str(reply, "reason", "Unknown."));
+		daemon_reply_destroy(reply);
+		return 0;
+	}
+
+	daemon_reply_destroy(reply);
+	return 1;
+}
+
+static int _read_mda(struct lvmcache_info *info,
+		     struct format_type *fmt,
+		     const struct dm_config_node *cn)
+{
+	struct metadata_area_ops *ops;
+	struct metadata_area *mda = NULL;
+	dm_list_iterate_items(ops, &fmt->mda_ops) {
+		if (ops->mda_import_text && ops->mda_import_text(info, cn))
+			return 1;
+	}
+	return 0;
+}
+
+static struct lvmcache_info *_pv_populate_lvmcache(
+	struct cmd_context *cmd, struct dm_config_node *cn, dev_t fallback)
+{
+	const char *pvid_txt = dm_config_find_str(cn->child, "id", NULL),
+		   *vgid_txt = dm_config_find_str(cn->child, "vgid", NULL),
+		   *vgname = dm_config_find_str(cn->child, "vgname", NULL),
+		   *fmt_name = dm_config_find_str(cn->child, "format", NULL);
+	dev_t devt = dm_config_find_int(cn->child, "device", 0);
+	uint64_t devsize = dm_config_find_int(cn->child, "dev_size", 0),
+		 label_sector = dm_config_find_int(cn->child, "label_sector", 0);
+
+	struct format_type *fmt = fmt_name ? get_format_by_name(cmd, fmt_name) : NULL;
+
+	if (!fmt) {
+		log_warn("No format for PV %s. It is probably missing.", pvid_txt);
+		return_NULL;
+	}
+
+	struct device *device = dev_cache_get_by_devt(devt, cmd->filter);
+	struct id pvid, vgid;
+
+	if (!device && fallback)
+		device = dev_cache_get_by_devt(fallback, cmd->filter);
+
+	if (!device) {
+		log_warn("No device for PV %s.", pvid_txt);
+		return_NULL;
+	}
+
+	if (!pvid_txt || !id_read_format(&pvid, pvid_txt)) {
+		log_warn("Missing or ill-formatted PVID for PV: %s.", pvid_txt);
+		return_NULL;
+	}
+
+	if (vgid_txt)
+		id_read_format(&vgid, vgid_txt);
+	else
+		strcpy((char*)&vgid, fmt->orphan_vg_name);
+
+	if (!vgname)
+		vgname = fmt->orphan_vg_name;
+
+	struct lvmcache_info *info =
+		lvmcache_add(fmt->labeller, (const char *)&pvid, device,
+			     vgname, (const char *)&vgid, 0);
+
+	lvmcache_get_label(info)->sector = label_sector;
+	lvmcache_set_device_size(info, devsize);
+	lvmcache_del_das(info);
+	lvmcache_del_mdas(info);
+
+	int i = 0;
+	struct dm_config_node *mda = NULL;
+	do {
+		char mda_id[32];
+		sprintf(mda_id, "mda%d", i);
+		mda = dm_config_find_node(cn->child, mda_id);
+		if (mda)
+			_read_mda(info, fmt, mda);
+		++i;
+	} while (mda);
+
+	i = 0;
+	struct dm_config_node *da = NULL;
+	do {
+		char da_id[32];
+		sprintf(da_id, "da%d", i);
+		da = dm_config_find_node(cn->child, da_id);
+		if (da) {
+			uint64_t offset, size;
+			if (!dm_config_get_uint64(da->child, "offset", &offset)) return_0;
+			if (!dm_config_get_uint64(da->child, "size", &size)) return_0;
+			lvmcache_add_da(info, offset, size);
+		}
+		++i;
+	} while (da);
+
+	return info;
+}
+
+struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgname, const char *vgid)
+{
+	if (!_using_lvmetad)
+		return NULL;
+
+	struct volume_group *vg = NULL;
+	daemon_reply reply;
+	if (vgid) {
+		char uuid[64];
+		id_write_format((struct id*)vgid, uuid, 64);
+		reply = daemon_send_simple(_lvmetad, "vg_lookup", "uuid = %s", uuid, NULL);
+	} else {
+		if (!vgname)
+			log_error(INTERNAL_ERROR "VG name required (VGID not available)");
+		reply = daemon_send_simple(_lvmetad, "vg_lookup", "name = %s", vgname, NULL);
+	}
+
+	if (!strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
+
+		struct dm_config_node *top = dm_config_find_node(reply.cft->root, "metadata");
+		const char *name = daemon_reply_str(reply, "name", NULL);
+
+		struct format_instance *fid;
+		struct format_instance_ctx fic;
+
+		/* fall back to lvm2 if we don't know better */
+		const char *fmt_name = dm_config_find_str(top, "metadata/format", "lvm2");
+		struct format_type *fmt = get_format_by_name(cmd, fmt_name);
+		if (!fmt) {
+			log_error(INTERNAL_ERROR
+				  "We do not know the format (%s) reported by lvmetad.",
+				  fmt_name);
+			return NULL;
+		}
+
+		fic.type = FMT_INSTANCE_MDAS | FMT_INSTANCE_AUX_MDAS;
+		fic.context.vg_ref.vg_name = name;
+		fic.context.vg_ref.vg_id = vgid;
+
+		if (!(fid = fmt->ops->create_instance(fmt, &fic)))
+			return_NULL;
+
+		struct dm_config_node *pvcn =
+			dm_config_find_node(top, "metadata/physical_volumes")->child;
+		while (pvcn) {
+			_pv_populate_lvmcache(cmd, pvcn, 0);
+			pvcn = pvcn->sib;
+		}
+
+		top->key = name;
+		vg = import_vg_from_config_tree(reply.cft, fid);
+
+		struct pv_list *pvl;
+		dm_list_iterate_items(pvl, &vg->pvs) {
+			struct lvmcache_info *info =
+				lvmcache_info_from_pvid((const char *)&pvl->pv->id, 0);
+			if (info) {
+				pvl->pv->label_sector = lvmcache_get_label(info)->sector;
+				pvl->pv->dev = lvmcache_device(info);
+				lvmcache_fid_add_mdas_pv(info, fid);
+			} /* else probably missing */
+		}
+
+		lvmcache_update_vg(vg, 0);
+	}
+
+	daemon_reply_destroy(reply);
+	return vg;
+}
+
+struct _fixup_baton {
+	int i;
+	int find;
+	int ignore;
+};
+
+static int _fixup_ignored(struct metadata_area *mda, void *baton) {
+	struct _fixup_baton *b = baton;
+	if (b->i == b->find)
+		mda_set_ignored(mda, b->ignore);
+	b->i ++;
+	return 1;
+}
+
+int lvmetad_vg_update(struct volume_group *vg)
+{
+	char *buf = NULL;
+	if (!vg)
+		return 0;
+	if (!_using_lvmetad)
+		return 1; /* fake it */
+
+	/* TODO. This is not entirely correct, since export_vg_to_buffer
+	 * adds trailing nodes to the buffer. We may need to use
+	 * export_vg_to_config_tree and format the buffer ourselves. It
+	 * does, however, work for now, since the garbage is well
+	 * formatted and has no conflicting keys with the rest of the
+	 * request.  */
+	if (!export_vg_to_buffer(vg, &buf)) {
+		log_error("Could not format VG metadata.");
+		return_0;
+	}
+
+	daemon_reply reply;
+
+	reply = daemon_send_simple(_lvmetad, "vg_update", "vgname = %s", vg->name,
+				             "metadata = %b", strchr(buf, '{'),
+				   NULL);
+
+	if (!_lvmetad_handle_reply(reply, "update VG", vg->name))
+		return 0;
+
+	struct dm_hash_node *n = (vg->fid && vg->fid->metadata_areas_index) ?
+		dm_hash_get_first(vg->fid->metadata_areas_index) : NULL;
+	while (n) {
+		struct metadata_area *mda = dm_hash_get_data(vg->fid->metadata_areas_index, n);
+		char mda_id[128], *num;
+		strcpy(mda_id, dm_hash_get_key(vg->fid->metadata_areas_index, n));
+		if ((num = strchr(mda_id, '_'))) {
+			*num = 0;
+			++num;
+			struct lvmcache_info *info =
+				lvmcache_info_from_pvid(mda_id, 0);
+			struct _fixup_baton baton = { .i = 0, .find = atoi(num),
+						      .ignore = mda_is_ignored(mda) };
+			if (info)
+				lvmcache_foreach_mda(info, _fixup_ignored, &baton);
+		}
+		n = dm_hash_get_next(vg->fid->metadata_areas_index, n);
+	}
+
+	struct pv_list *pvl;
+	dm_list_iterate_items(pvl, &vg->pvs) {
+		/* NB. the PV fmt pointer is sometimes wrong during vgconvert */
+		if (pvl->pv->dev && !lvmetad_pv_found(pvl->pv->id, pvl->pv->dev,
+						      vg->fid ? vg->fid->fmt : pvl->pv->fmt,
+						      pvl->pv->label_sector, NULL))
+			return 0;
+	}
+
+	return 1;
+}
+
+int lvmetad_vg_remove(struct volume_group *vg)
+{
+	if (!_using_lvmetad)
+		return 1; /* just fake it */
+	char uuid[64];
+	id_write_format(&vg->id, uuid, 64);
+	daemon_reply reply =
+		daemon_send_simple(_lvmetad, "vg_remove", "uuid = %s", uuid, NULL);
+
+	return _lvmetad_handle_reply(reply, "remove VG", vg->name);
+}
+
+int lvmetad_pv_lookup(struct cmd_context *cmd, struct id pvid)
+{
+	if (!_using_lvmetad)
+		return_0;
+
+	int result = 1;
+	char uuid[64];
+	id_write_format(&pvid, uuid, 64);
+
+	daemon_reply reply =
+		daemon_send_simple(_lvmetad, "pv_lookup", "uuid = %s", uuid, NULL);
+
+	if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
+		_lvmetad_handle_reply(reply, "lookup PVs", "");
+		return_0;
+	}
+
+	struct dm_config_node *cn = dm_config_find_node(reply.cft->root, "physical_volume");
+	if (!_pv_populate_lvmcache(cmd, cn, 0))
+		result = 0;
+
+	daemon_reply_destroy(reply);
+	return result;
+}
+
+int lvmetad_pv_lookup_by_devt(struct cmd_context *cmd, dev_t device)
+{
+	if (!_using_lvmetad)
+		return_0;
+
+	int result = 1;
+
+	daemon_reply reply =
+		daemon_send_simple(_lvmetad, "pv_lookup", "device = %d", device, NULL);
+
+	if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
+		_lvmetad_handle_reply(reply, "lookup PVs", "");
+		return_0;
+	}
+
+	struct dm_config_node *cn = dm_config_find_node(reply.cft->root, "physical_volume");
+	if (!_pv_populate_lvmcache(cmd, cn, device))
+		result = 0;
+
+	daemon_reply_destroy(reply);
+	return result;
+}
+
+int lvmetad_pv_list_to_lvmcache(struct cmd_context *cmd)
+{
+	if (!_using_lvmetad)
+		return_0;
+
+	daemon_reply reply =
+		daemon_send_simple(_lvmetad, "pv_list", NULL);
+
+	if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
+		_lvmetad_handle_reply(reply, "list PVs", "");
+		return_0;
+	}
+
+	struct dm_config_node *cn = dm_config_find_node(reply.cft->root, "physical_volumes")->child;
+	while (cn) {
+		_pv_populate_lvmcache(cmd, cn, 0);
+		cn = cn->sib;
+	}
+
+	daemon_reply_destroy(reply);
+	return 1;
+}
+
+int lvmetad_vg_list_to_lvmcache(struct cmd_context *cmd)
+{
+	if (!_using_lvmetad)
+		return_0;
+
+	daemon_reply reply =
+		daemon_send_simple(_lvmetad, "vg_list", NULL);
+
+	if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
+		_lvmetad_handle_reply(reply, "list VGs", "");
+		return_0;
+	}
+
+	struct dm_config_node *cn = dm_config_find_node(reply.cft->root, "volume_groups")->child;
+	while (cn) {
+		struct id vgid;
+		const char *vgid_txt = cn->key,
+			   *name = dm_config_find_str(cn->child, "name", NULL);
+		id_read_format(&vgid, vgid_txt);
+
+		cn = cn->sib;
+
+		/* the call to lvmetad_vg_lookup will poke the VG into lvmcache */
+		struct volume_group *tmp = lvmetad_vg_lookup(cmd, NULL, (const char*)&vgid);
+		release_vg(tmp);
+	}
+
+	daemon_reply_destroy(reply);
+	return 1;
+}
+
+struct _print_mda_baton {
+	int i;
+	char *buffer;
+};
+
+static int _print_mda(struct metadata_area *mda, void *baton)
+{
+	int result = 0;
+	struct _print_mda_baton *b = baton;
+
+	if (!mda->ops->mda_export_text) /* do nothing */
+		return 1;
+
+	char *buf = b->buffer;
+	char *mda_txt = mda->ops->mda_export_text(mda);
+	if (!dm_asprintf(&b->buffer, "%s mda%i { %s }", b->buffer ?: "", b->i, mda_txt))
+		goto_out;
+	b->i ++;
+	result = 1;
+out:
+	dm_free(mda_txt);
+	dm_free(buf);
+	return result;
+}
+
+static int _print_da(struct disk_locn *da, void *baton)
+{
+	if (!da)
+		return 1;
+
+	struct _print_mda_baton *b = baton;
+
+	char *buf = b->buffer;
+	if (!dm_asprintf(&b->buffer, "%s da%i { offset = %lld size = %lld }",
+			 b->buffer ?: "", b->i, da->offset, da->size))
+	{
+		dm_free(buf);
+		return_0;
+	}
+	b->i ++;
+	dm_free(buf);
+	return 1;
+}
+
+static const char *_print_mdas(struct lvmcache_info *info)
+{
+	struct _print_mda_baton baton = { .i = 0, .buffer = NULL };
+	if (!lvmcache_foreach_mda(info, &_print_mda, &baton))
+		return NULL;
+	baton.i = 0;
+	if (!lvmcache_foreach_da(info, &_print_da, &baton))
+		return NULL;
+	return baton.buffer;
+}
+
+int lvmetad_pv_found(struct id pvid, struct device *device, const struct format_type *fmt,
+		     uint64_t label_sector, struct volume_group *vg)
+{
+	if (!_using_lvmetad)
+		return 1;
+
+	char uuid[64];
+
+	id_write_format(&pvid, uuid, 64);
+
+	/* FIXME A more direct route would be much preferable. */
+	struct lvmcache_info *info = lvmcache_info_from_pvid((const char *)&pvid, 0);
+	const char *mdas = NULL;
+	if (info)
+		mdas = _print_mdas(info);
+
+	char *pvmeta;
+	if (!dm_asprintf(&pvmeta,
+			 "{ device = %lld\n"
+			 "  dev_size = %lld\n"
+			 "  format = \"%s\"\n"
+			 "  label_sector = %lld\n"
+			 "  id = \"%s\"\n"
+			 "  %s"
+			 "}", device->dev, info ? lvmcache_device_size(info) : 0,
+			 fmt->name, label_sector, uuid, mdas ?: ""))
+		return_0;
+
+	daemon_reply reply;
+
+	if (vg) {
+		char *buf = NULL;
+		/*
+		 * TODO. This is not entirely correct, since export_vg_to_buffer
+		 * adds trailing garbage to the buffer. We may need to use
+		 * export_vg_to_config_tree and format the buffer ourselves. It
+		 * does, however, work for now, since the garbage is well
+		 * formatted and has no conflicting keys with the rest of the
+		 * request.
+		 */
+		export_vg_to_buffer(vg, &buf);
+		reply = daemon_send_simple(_lvmetad,
+					   "pv_found",
+					   "pvmeta = %b", pvmeta,
+					   "vgname = %s", vg->name,
+					   "metadata = %b", strchr(buf, '{'),
+					   NULL);
+	} else {
+		/* There are no MDAs on this PV. */
+		reply = daemon_send_simple(_lvmetad,
+					   "pv_found",
+					   "pvmeta = %b", pvmeta,
+					   NULL);
+	}
+
+	dm_free(pvmeta);
+	return _lvmetad_handle_reply(reply, "update PV", uuid);
+}
+
+int lvmetad_pv_gone(dev_t device)
+{
+	daemon_reply reply =
+		daemon_send_simple(_lvmetad, "pv_gone", "device = %d", device, NULL);
+
+	return _lvmetad_handle_reply(reply, "drop PV", "");
+}
+
+int lvmetad_active()
+{
+	return _using_lvmetad;
+}
+
+void lvmetad_set_active(int active)
+{
+	_using_lvmetad = active;
+}
+
+/*
+ * The following code implements pvscan --lvmetad.
+ */
+
+struct _pvscan_lvmetad_baton {
+	struct volume_group *vg;
+	struct format_instance *fid;
+};
+
+static int _pvscan_lvmetad_single(struct metadata_area *mda, void *baton)
+{
+	struct _pvscan_lvmetad_baton *b = baton;
+	struct volume_group *this = mda->ops->vg_read(b->fid, "", mda);
+	if ((this && !b->vg) || this->seqno > b->vg->seqno)
+		b->vg = this;
+	else release_vg(this);
+	return 1;
+}
+
+static dev_t _parse_devt(const char *str) { /* Oh. */
+	char *where = (char *) str;
+	int major = strtol(str, &where, 10);
+	if (where == str)
+		return -1;
+	if (*where != ':')
+		return -1;
+	++where;
+	str = where;
+	int minor = strtol(str, &where, 10);
+	if (where == str)
+		return -1;
+	if (*where)
+		return -1;
+
+	return MKDEV(major, minor);
+}
+
+int pvscan_lvmetad(struct cmd_context *cmd, int argc, char **argv)
+{
+	if (argc != 1) {
+		log_error("Exactly one device parameter required.");
+		return 0;
+	}
+
+	if (!lvmetad_active()) {
+		log_error("Cannot proceed since lvmetad is not active.");
+		return 0;
+	}
+
+	struct device *dev = dev_cache_get(argv[0], NULL);
+	if (!dev && _parse_devt(argv[0]) != -1)
+		dev = dev_cache_get_by_devt(_parse_devt(argv[0]), NULL);
+
+	if (!dev) {
+		if (_parse_devt(argv[0]) == -1) {
+			log_error("For devices that do not exist, we need a MAJOR:MINOR pair.");
+			return 0;
+		}
+
+		if (!lvmetad_pv_gone(_parse_devt(argv[0])))
+			goto fatal;
+
+		log_info("Device %s not found and was wiped from lvmetad.", argv[0]);
+		return 1;
+	}
+
+	allow_reads_with_lvmetad();
+
+	struct label *label;
+	if (!label_read(dev, &label, 0)) {
+		log_warn("No PV label found on %s.", dev_name(dev));
+		if (!lvmetad_pv_gone(dev->dev))
+			goto fatal;
+		return 1;
+	}
+
+	struct lvmcache_info *info = (struct lvmcache_info *) label->info;
+	struct physical_volume pv;
+	memset(&pv, 0, sizeof(pv));
+
+	struct _pvscan_lvmetad_baton baton;
+	baton.vg = NULL;
+
+	/* Create a dummy instance. */
+	struct format_instance_ctx fic = { .type = 0 };
+	baton.fid =
+		lvmcache_fmt(info)->ops->create_instance(lvmcache_fmt(info), &fic);
+	struct metadata_area *mda;
+
+	lvmcache_foreach_mda(info, _pvscan_lvmetad_single, &baton);
+
+	/*
+	 * NB. If this command failed and we are relying on lvmetad to have an
+	 * *exact* image of the system, the lvmetad instance that went out of
+	 * sync needs to be killed.
+	 */
+	if (!lvmetad_pv_found(*(struct id *)dev->pvid, dev, lvmcache_fmt(info),
+			      label->sector, baton.vg))
+		goto fatal;
+
+	release_vg(baton.vg);
+	return 1;
+fatal:
+	release_vg(baton.vg);
+	/* FIXME kill lvmetad automatically if we can */
+	log_error("Update of lvmetad failed. This is a serious problem.\n  "
+		  "It is strongly recommended that you restart lvmetad immediately.");
+	return 0;
+}
+
Index: lib/cache/lvmetad.h
===================================================================
RCS file: lib/cache/lvmetad.h
diff -N lib/cache/lvmetad.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/cache/lvmetad.h	21 Feb 2012 23:46:59 -0000
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _LVM_METAD_H
+#define _LVM_METAD_H
+
+struct volume_group;
+struct cmd_context;
+struct dm_config_tree;
+
+/*
+ * Initialise the communication with lvmetad. Normally called by
+ * lvmcache_init. Sets up a global handle for our process.
+ */
+void lvmetad_init(void);
+
+/*
+ * Override the use of lvmetad for retrieving scan results and metadata.
+ */
+void lvmetad_set_active(int);
+
+/*
+ * Check whether lvmetad is active (where active means both that it is running
+ * and that we have a working connection with it).
+ */
+int lvmetad_active(void);
+
+/*
+ * Send a new version of VG metadata to lvmetad. This is normally called after
+ * vg_write but before vg_commit. After vg_commit, lvmetad_vg_commit is called
+ * to seal the transaction. The result of lvmetad_vg_update is that the new
+ * metadata is stored tentatively in lvmetad, but it is not used until
+ * lvmetad_vg_commit. The request is validated immediately and lvmetad_vg_commit
+ * only constitutes a pointer update.
+ */
+int lvmetad_vg_update(struct volume_group *vg);
+
+/*
+ * Inform lvmetad that a VG has been removed. This is not entirely safe, but is
+ * only needed during vgremove, which does not wipe PV labels and therefore
+ * cannot mark the PVs as gone.
+ */
+int lvmetad_vg_remove(struct volume_group *vg);
+
+/*
+ * Notify lvmetad that a PV has been found. It is not an error if the PV is
+ * already marked as present in lvmetad. If a non-NULL vg pointer is supplied,
+ * it is taken to represent the metadata read from the MDA(s) present on that
+ * PV. It *is* an error if: the VG is already known to lvmetad, the sequence
+ * number on the cached and on the discovered PV match but the metadata content
+ * does not.
+ */
+int lvmetad_pv_found(struct id pvid, struct device *device,
+		     const struct format_type *fmt, uint64_t label_sector,
+		     struct volume_group *vg);
+
+/*
+ * Inform the daemon that the device no longer exists. We do not support
+ * multiple device names, so this needs a unique and stable name, the same as
+ * provided to lvmetad_pv_found.
+ */
+int lvmetad_pv_gone(dev_t device);
+
+/*
+ * Request a list of all PVs available to lvmetad. If requested, this will also
+ * read labels off all the PVs to populate lvmcache.
+ */
+int lvmetad_pv_list_to_lvmcache(struct cmd_context *cmd);
+
+int lvmetad_pv_lookup(struct cmd_context *cmd, struct id pvid);
+int lvmetad_pv_lookup_by_devt(struct cmd_context *cmd, dev_t dev);
+
+/*
+ * Request a list of all VGs available to lvmetad and use it to fill in
+ * lvmcache..
+ */
+int lvmetad_vg_list_to_lvmcache(struct cmd_context *cmd);
+
+struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgname, const char *vgid);
+
+/*
+ * Scan a single device and update lvmetad with the result(s). If the device
+ * node does not exist, it must be supplied in a major:minor format.
+ */
+int pvscan_lvmetad(struct cmd_context *cmd, int argc, char **argv);
+
+#endif
+
Index: lib/commands/toolcontext.c
===================================================================
RCS file: /cvs/lvm2/LVM2/lib/commands/toolcontext.c,v
retrieving revision 1.150
diff -u -p -r1.150 toolcontext.c
--- lib/commands/toolcontext.c	8 Feb 2012 13:44:49 -0000	1.150
+++ lib/commands/toolcontext.c	21 Feb 2012 23:47:01 -0000
@@ -34,6 +34,7 @@
 #include "str_list.h"
 #include "segtype.h"
 #include "lvmcache.h"
+#include "lvmetad.h"
 #include "dev-cache.h"
 #include "archiver.h"
 
@@ -389,6 +390,8 @@ static int _process_config(struct cmd_co
 		(find_config_tree_int(cmd, "global/detect_internal_vg_cache_corruption()",
 				      DEFAULT_DETECT_INTERNAL_VG_CACHE_CORRUPTION));
 
+	lvmetad_set_active(find_config_tree_int(cmd, "global/use_lvmetad", 0));
+
 	return 1;
 }
 
Index: lib/device/dev-cache.c
===================================================================
RCS file: /cvs/lvm2/LVM2/lib/device/dev-cache.c,v
retrieving revision 1.71
diff -u -p -r1.71 dev-cache.c
--- lib/device/dev-cache.c	8 Feb 2012 11:05:04 -0000	1.71
+++ lib/device/dev-cache.c	21 Feb 2012 23:47:01 -0000
@@ -906,6 +906,39 @@ struct device *dev_cache_get(const char 
 		      f->passes_filter(f, d))) ? d : NULL;
 }
 
+static struct device *_dev_cache_seek_devt(dev_t dev)
+{
+	struct device *d = NULL;
+	struct dm_hash_node *n = dm_hash_get_first(_cache.names);
+	while (n) {
+		d = dm_hash_get_data(_cache.names, n);
+		if (d->dev == dev)
+			return d;
+		n = dm_hash_get_next(_cache.names, n);
+	}
+	return NULL;
+}
+
+/*
+ * TODO This is very inefficient. We probably want a hash table indexed by
+ * major:minor for keys to speed up these lookups.
+ */
+struct device *dev_cache_get_by_devt(dev_t dev, struct dev_filter *f)
+{
+	struct device *d = _dev_cache_seek_devt(dev);
+
+	if (d && (d->flags & DEV_REGULAR))
+		return d;
+
+	if (!d) {
+		_full_scan(0);
+		d = _dev_cache_seek_devt(dev);
+	}
+
+	return (d && (!f || (d->flags & DEV_REGULAR) ||
+		      f->passes_filter(f, d))) ? d : NULL;
+}
+
 struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan)
 {
 	struct dev_iter *di = dm_malloc(sizeof(*di));
Index: lib/device/dev-cache.h
===================================================================
RCS file: /cvs/lvm2/LVM2/lib/device/dev-cache.h,v
retrieving revision 1.14
diff -u -p -r1.14 dev-cache.h
--- lib/device/dev-cache.h	22 Apr 2011 12:05:33 -0000	1.14
+++ lib/device/dev-cache.h	21 Feb 2012 23:47:01 -0000
@@ -44,6 +44,9 @@ int dev_cache_add_dir(const char *path);
 int dev_cache_add_loopfile(const char *path);
 struct device *dev_cache_get(const char *name, struct dev_filter *f);
 
+// TODO
+struct device *dev_cache_get_by_devt(dev_t device, struct dev_filter *f);
+
 void dev_set_preferred_name(struct str_list *sl, struct device *dev);
 
 /*
Index: lib/device/dev-io.c
===================================================================
RCS file: /cvs/lvm2/LVM2/lib/device/dev-io.c,v
retrieving revision 1.81
diff -u -p -r1.81 dev-io.c
--- lib/device/dev-io.c	10 Feb 2012 01:28:27 -0000	1.81
+++ lib/device/dev-io.c	21 Feb 2012 23:47:02 -0000
@@ -664,6 +664,8 @@ int dev_read(struct device *dev, uint64_
 	where.start = offset;
 	where.size = len;
 
+	// fprintf(stderr, "READ: %s, %lld, %d\n", dev_name(dev), offset, len);
+
 	ret = _aligned_io(&where, buffer, 0);
 	if (!ret)
 		_dev_inc_error_count(dev);
Index: lib/format1/format1.c
===================================================================
RCS file: /cvs/lvm2/LVM2/lib/format1/format1.c,v
retrieving revision 1.147
diff -u -p -r1.147 format1.c
--- lib/format1/format1.c	15 Feb 2012 01:44:58 -0000	1.147
+++ lib/format1/format1.c	21 Feb 2012 23:47:02 -0000
@@ -415,6 +415,7 @@ static int _format1_pv_write(const struc
 
 	lvmcache_update_pv(info, pv, fmt);
 	lvmcache_del_mdas(info);
+	lvmcache_del_das(info);
 
 	dm_list_init(&pvs);
 
@@ -590,6 +591,8 @@ struct format_type *init_format(struct c
 			FMT_RESTRICTED_READAHEAD;
 	fmt->private = NULL;
 
+	dm_list_init(&fmt->mda_ops);
+
 	if (!(fmt->labeller = lvm1_labeller_create(fmt))) {
 		log_error("Couldn't create lvm1 label handler.");
 		dm_free(fmt);
Index: lib/format_pool/format_pool.c
===================================================================
RCS file: /cvs/lvm2/LVM2/lib/format_pool/format_pool.c,v
retrieving revision 1.52
diff -u -p -r1.52 format_pool.c
--- lib/format_pool/format_pool.c	15 Feb 2012 13:46:54 -0000	1.52
+++ lib/format_pool/format_pool.c	21 Feb 2012 23:47:03 -0000
@@ -301,6 +301,8 @@ struct format_type *init_format(struct c
 	fmt->features = 0;
 	fmt->private = NULL;
 
+	dm_list_init(&fmt->mda_ops);
+
 	if (!(fmt->labeller = pool_labeller_create(fmt))) {
 		log_error("Couldn't create pool label handler.");
 		dm_free(fmt);
Index: lib/format_text/export.c
===================================================================
RCS file: /cvs/lvm2/LVM2/lib/format_text/export.c,v
retrieving revision 1.86
diff -u -p -r1.86 export.c
--- lib/format_text/export.c	25 Jan 2012 22:35:36 -0000	1.86
+++ lib/format_text/export.c	21 Feb 2012 23:47:03 -0000
@@ -395,6 +395,9 @@ static int _print_vg(struct formatter *f
 
 	outf(f, "seqno = %u", vg->seqno);
 
+	if (vg->fid && vg->fid->fmt)
+		outf(f, "format = \"%s\" # informational", vg->fid->fmt->name);
+
 	if (!_print_flag_config(f, vg->status, VG_FLAGS))
 		return_0;
 
Index: lib/format_text/format-text.c
===================================================================
RCS file: /cvs/lvm2/LVM2/lib/format_text/format-text.c,v
retrieving revision 1.193
diff -u -p -r1.193 format-text.c
--- lib/format_text/format-text.c	13 Feb 2012 11:09:25 -0000	1.193
+++ lib/format_text/format-text.c	21 Feb 2012 23:47:05 -0000
@@ -29,6 +29,7 @@
 #include "label.h"
 #include "memlock.h"
 #include "lvmcache.h"
+#include "lvmetad.h"
 
 #include <unistd.h>
 #include <sys/file.h>
@@ -738,6 +739,7 @@ static int _vg_commit_raw_rlocn(struct f
 			  dev_name(mdac->area.dev), mdac->area.start);
 
 	rlocn_set_ignored(mdah->raw_locns, mda_is_ignored(mda));
+
 	if (!_raw_write_mda_header(fid->fmt, mdac->area.dev, mdac->area.start,
 				   mdah)) {
 		dm_pool_free(fid->fmt->cmd->mem, mdah);
@@ -1430,16 +1432,25 @@ static uint64_t _metadata_locn_offset_ra
 static int _text_pv_read(const struct format_type *fmt, const char *pv_name,
 		    struct physical_volume *pv, int scan_label_only)
 {
-	struct label *label;
+	struct lvmcache_info *info;
 	struct device *dev;
 
 	if (!(dev = dev_cache_get(pv_name, fmt->cmd->filter)))
 		return_0;
 
-	if (!(label_read(dev, &label, UINT64_C(0))))
-		return_0;
+	if (lvmetad_active()) {
+		info = lvmcache_info_from_pvid(dev->pvid, 0);
+		if (!info && !lvmetad_pv_lookup_by_devt(fmt->cmd, dev->dev))
+			return 0;
+		info = lvmcache_info_from_pvid(dev->pvid, 0);
+	} else {
+		struct label *label;
+		if (!(label_read(dev, &label, UINT64_C(0))))
+			return_0;
+		info = label->info;
+	}
 
-	if (!lvmcache_populate_pv_fields(label->info, pv, scan_label_only))
+	if (!lvmcache_populate_pv_fields(info, pv, scan_label_only))
 		return 0;
 
 	return 1;
@@ -1568,6 +1579,9 @@ static struct metadata_area_ops _metadat
 	.vg_commit = _vg_commit_file_backup
 };
 
+static char *_mda_export_text_raw(struct metadata_area *mda);
+static int _mda_import_text_raw(struct lvmcache_info *info, const struct dm_config_node *cn);
+
 static struct metadata_area_ops _metadata_text_raw_ops = {
 	.vg_read = _vg_read_raw,
 	.vg_read_precommit = _vg_read_precommit_raw,
@@ -1584,9 +1598,42 @@ static struct metadata_area_ops _metadat
 	.mda_in_vg = _mda_in_vg_raw,
 	.pv_analyze_mda = _pv_analyze_mda_raw,
 	.mda_locns_match = _mda_locns_match_raw,
-	.mda_get_device = _mda_get_device_raw
+	.mda_get_device = _mda_get_device_raw,
+	.mda_export_text = _mda_export_text_raw,
+	.mda_import_text = _mda_import_text_raw
 };
 
+static char *_mda_export_text_raw(struct metadata_area *mda)
+{
+	struct mda_context *mdc = (struct mda_context *) mda->metadata_locn;
+	char *result;
+	dm_asprintf(&result,
+		    "ignore = %d "
+		    "start = %" PRIu64" "
+		    "size = %" PRIu64 " "
+		    "free_sectors = %" PRIu64,
+		    mda_is_ignored(mda), mdc->area.start, mdc->area.size, mdc->free_sectors);
+	return result;
+}
+
+static int _mda_import_text_raw(struct lvmcache_info *info, const struct dm_config_node *cn)
+{
+	if (!cn->child)
+		return 0;
+	cn = cn->child;
+
+	struct device *device = lvmcache_device(info);
+	uint64_t offset = dm_config_find_int(cn, "start", 0);
+	uint64_t size = dm_config_find_int(cn, "size", 0);
+	int ignore = dm_config_find_int(cn, "ignore", 0);
+
+	if (!device || !size)
+		return 0;
+
+	lvmcache_add_mda(info, device, offset, size, ignore);
+	return 1;
+}
+
 static int _text_pv_setup(const struct format_type *fmt,
 			  struct physical_volume *pv,
 			  struct volume_group *vg)
@@ -1619,7 +1666,9 @@ static int _text_pv_setup(const struct f
 	 * reread PV mda information from the cache and add it to vg->fid.
 	 */
 	else {
-		if (!(info = lvmcache_info_from_pvid(pv->dev->pvid, 0))) {
+		if (!pv->dev ||
+		    !pv->dev->pvid ||
+		    !(info = lvmcache_info_from_pvid(pv->dev->pvid, 0))) {
 			log_error("PV %s missing from cache", pv_dev_name(pv));
 			return 0;
 		}
@@ -2292,6 +2341,9 @@ struct format_type *create_text_format(s
 	mda_lists->raw_ops = &_metadata_text_raw_ops;
 	fmt->private = (void *) mda_lists;
 
+	dm_list_init(&fmt->mda_ops);
+	dm_list_add(&fmt->mda_ops, &_metadata_text_raw_ops.list);
+
 	if (!(fmt->labeller = text_labeller_create(fmt))) {
 		log_error("Couldn't create text label handler.");
 		goto bad;
Index: lib/format_text/import_vsn1.c
===================================================================
RCS file: /cvs/lvm2/LVM2/lib/format_text/import_vsn1.c,v
retrieving revision 1.100
diff -u -p -r1.100 import_vsn1.c
--- lib/format_text/import_vsn1.c	10 Feb 2012 01:28:28 -0000	1.100
+++ lib/format_text/import_vsn1.c	21 Feb 2012 23:47:06 -0000
@@ -19,6 +19,7 @@
 #include "display.h"
 #include "toolcontext.h"
 #include "lvmcache.h"
+#include "lvmetad.h"
 #include "lv_alloc.h"
 #include "pv_alloc.h"
 #include "segtype.h"
@@ -59,6 +60,10 @@ static int _vsn1_check_version(const str
 	const struct dm_config_node *cn;
 	const struct dm_config_value *cv;
 
+	// TODO if this is pvscan --lvmetad, we want this check back.
+	if (lvmetad_active())
+		return 1;
+
 	/*
 	 * Check the contents field.
 	 */
@@ -212,7 +217,8 @@ static int _read_pv(struct format_instan
 		return 0;
 	}
 
-	if (!pv->dev)
+	/* TODO is the !lvmetad_active() too coarse here? */
+	if (!pv->dev && !lvmetad_active())
 		pv->status |= MISSING_PV;
 
 	/* Late addition */
Index: lib/format_text/text_label.c
===================================================================
RCS file: /cvs/lvm2/LVM2/lib/format_text/text_label.c,v
retrieving revision 1.41
diff -u -p -r1.41 text_label.c
--- lib/format_text/text_label.c	10 Feb 2012 01:28:28 -0000	1.41
+++ lib/format_text/text_label.c	21 Feb 2012 23:47:06 -0000
@@ -19,6 +19,7 @@
 #include "label.h"
 #include "xlate.h"
 #include "lvmcache.h"
+#include "lvmetad.h"
 
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -40,11 +41,11 @@ struct _da_setup_baton {
 	struct device *dev;
 };
 
-static int _da_setup(struct data_area_list *da, void *baton)
+static int _da_setup(struct disk_locn *da, void *baton)
 {
 	struct _da_setup_baton *p = baton;
-	p->pvh_dlocn_xl->offset = xlate64(da->disk_locn.offset);
-	p->pvh_dlocn_xl->size = xlate64(da->disk_locn.size);
+	p->pvh_dlocn_xl->offset = xlate64(da->offset);
+	p->pvh_dlocn_xl->size = xlate64(da->size);
 	p->pvh_dlocn_xl++;
 	return 1;
 }
@@ -275,7 +276,7 @@ static int _update_mda(struct metadata_a
 	const struct format_type *fmt = p->label->labeller->private; // Oh dear.
 	struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
 	struct mda_header *mdah;
-	const char *vgname;
+	const char *vgname = NULL;
 	struct id vgid;
 	uint64_t vgstatus;
 	char *creation_host;
@@ -337,7 +338,6 @@ static int _text_read(struct labeller *l
 				  FMT_TEXT_ORPHAN_VG_NAME, 0)))
 		return_0;
 
-	/* this one is leaked forever */
 	*label = lvmcache_get_label(info);
 
 	lvmcache_set_device_size(info, xlate64(pvhdr->device_size_xl));
Index: lib/label/label.c
===================================================================
RCS file: /cvs/lvm2/LVM2/lib/label/label.c,v
retrieving revision 1.56
diff -u -p -r1.56 label.c
--- lib/label/label.c	10 Feb 2012 01:28:28 -0000	1.56
+++ lib/label/label.c	21 Feb 2012 23:47:06 -0000
@@ -18,12 +18,18 @@
 #include "crc.h"
 #include "xlate.h"
 #include "lvmcache.h"
+#include "lvmetad.h"
 #include "metadata.h"
 
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <unistd.h>
 
+static int _allow_reads = 0;
+void allow_reads_with_lvmetad() {
+	_allow_reads = 1;
+};
+
 /* FIXME Allow for larger labels?  Restricted to single sector currently */
 
 /*
@@ -261,9 +267,12 @@ int label_read(struct device *dev, struc
 	struct lvmcache_info *info;
 	int r = 0;
 
+	/* if (lvmetad_active() && !_allow_reads)
+	 *(char*)NULL = 0; */
+
 	if ((info = lvmcache_info_from_pvid(dev->pvid, 1))) {
 		log_debug("Using cached label for %s", dev_name(dev));
-		*result = lvmcache_get_label(info); /* leaked */
+		*result = lvmcache_get_label(info);
 		return 1;
 	}
 
Index: lib/label/label.h
===================================================================
RCS file: /cvs/lvm2/LVM2/lib/label/label.h,v
retrieving revision 1.20
diff -u -p -r1.20 label.h
--- lib/label/label.h	20 Aug 2007 20:55:26 -0000	1.20
+++ lib/label/label.h	21 Feb 2012 23:47:08 -0000
@@ -26,6 +26,8 @@
 
 struct labeller;
 
+void allow_reads_with_lvmetad(void);
+
 /* On disk - 32 bytes */
 struct label_header {
 	int8_t id[8];		/* LABELONE */
Index: lib/metadata/metadata-exported.h
===================================================================
RCS file: /cvs/lvm2/LVM2/lib/metadata/metadata-exported.h,v
retrieving revision 1.230
diff -u -p -r1.230 metadata-exported.h
--- lib/metadata/metadata-exported.h	12 Feb 2012 23:01:19 -0000	1.230
+++ lib/metadata/metadata-exported.h	21 Feb 2012 23:47:18 -0000
@@ -174,6 +174,7 @@ struct format_type {
 	struct dm_list list;
 	struct cmd_context *cmd;
 	struct format_handler *ops;
+	struct dm_list mda_ops; /* List of permissible mda ops. */
 	struct labeller *labeller;
 	const char *name;
 	const char *alias;
Index: lib/metadata/metadata.c
===================================================================
RCS file: /cvs/lvm2/LVM2/lib/metadata/metadata.c,v
retrieving revision 1.484
diff -u -p -r1.484 metadata.c
--- lib/metadata/metadata.c	13 Feb 2012 11:04:00 -0000	1.484
+++ lib/metadata/metadata.c	21 Feb 2012 23:47:34 -0000
@@ -20,6 +20,7 @@
 #include "lvm-string.h"
 #include "lvm-file.h"
 #include "lvmcache.h"
+#include "lvmetad.h"
 #include "memlock.h"
 #include "str_list.h"
 #include "pv_alloc.h"
@@ -257,7 +258,7 @@ int add_pv_to_vg(struct volume_group *vg
 			stack;
 			uuid[0] = '\0';
 		}
-		log_error("Physical volume '%s (%s)' listed more than once.",
+		log_error("Physical volume '%s (%s)' already in the VG.",
 			  pv_name, uuid);
 		return 0;
 	}
@@ -615,6 +616,10 @@ int vg_remove(struct volume_group *vg)
 		}
 	}
 
+	/* FIXME Handle partial failures from above. */
+	if (!lvmetad_vg_remove(vg))
+		stack;
+
 	if (!backup_remove(vg->cmd, vg->name))
 		stack;
 
@@ -2651,6 +2656,7 @@ static int _vg_commit_mdas(struct volume
 		/* Update cache first time we succeed */
 		if (!failed && !cache_updated) {
 			lvmcache_update_vg(vg, 0);
+			// lvmetad_vg_commit(vg);
 			cache_updated = 1;
 		}
 	}
@@ -2668,6 +2674,9 @@ int vg_commit(struct volume_group *vg)
 		return cache_updated;
 	}
 
+	if (!lvmetad_vg_update(vg))
+		return 0;
+
 	cache_updated = _vg_commit_mdas(vg);
 
 	if (cache_updated) {
@@ -2723,6 +2732,7 @@ static int _vg_read_orphan_pv(struct lvm
 			    b->vg->fid, b->warnings, 0))) {
 		return 1;
 	}
+
 	if (!(pvl = dm_pool_zalloc(b->vg->vgmem, sizeof(*pvl)))) {
 		log_error("pv_list allocation failed");
 		free_pv_fid(pv);
@@ -2744,11 +2754,12 @@ static struct volume_group *_vg_read_orp
 	struct _vg_read_orphan_baton baton;
 
 	lvmcache_label_scan(cmd, 0);
+	lvmcache_seed_infos_from_lvmetad(cmd);
 
 	if (!(vginfo = lvmcache_vginfo_from_vgname(orphan_vgname, NULL)))
 		return_NULL;
 
-	if (!(fmt = lvmcache_fmt_from_vgname(orphan_vgname, NULL, 0)))
+	if (!(fmt = lvmcache_fmt_from_vgname(cmd, orphan_vgname, NULL, 0)))
 		return_NULL;
 
 	vg = fmt->orphan_vg;
@@ -2888,6 +2899,7 @@ static struct volume_group *_vg_read(str
 	struct pv_list *pvl, *pvl2;
 	struct dm_list all_pvs;
 	char uuid[64] __attribute__((aligned(8)));
+	int seqno = 0;
 
 	if (is_orphan_vg(vgname)) {
 		if (use_precommitted) {
@@ -2899,31 +2911,39 @@ static struct volume_group *_vg_read(str
 		return _vg_read_orphans(cmd, warnings, vgname);
 	}
 
+	if (lvmetad_active() && !use_precommitted) {
+		*consistent = 1;
+		return lvmcache_get_vg(cmd, vgname, vgid, precommitted);
+	}
+
 	/*
 	 * If cached metadata was inconsistent and *consistent is set
 	 * then repair it now.  Otherwise just return it.
 	 * Also return if use_precommitted is set due to the FIXME in
 	 * the missing PV logic below.
 	 */
-	if ((correct_vg = lvmcache_get_vg(vgid, precommitted)) &&
+	if ((correct_vg = lvmcache_get_vg(cmd, vgname, vgid, precommitted)) &&
 	    (use_precommitted || !*consistent)) {
 		*consistent = 1;
 		return correct_vg;
 	} else {
+		if (correct_vg && correct_vg->seqno > seqno)
+			seqno = correct_vg->seqno;
 		release_vg(correct_vg);
 		correct_vg = NULL;
 	}
 
+
 	/* Find the vgname in the cache */
 	/* If it's not there we must do full scan to be completely sure */
-	if (!(fmt = lvmcache_fmt_from_vgname(vgname, vgid, 1))) {
+	if (!(fmt = lvmcache_fmt_from_vgname(cmd, vgname, vgid, 1))) {
 		lvmcache_label_scan(cmd, 0);
-		if (!(fmt = lvmcache_fmt_from_vgname(vgname, vgid, 1))) {
+		if (!(fmt = lvmcache_fmt_from_vgname(cmd, vgname, vgid, 1))) {
 			/* Independent MDAs aren't supported under low memory */
 			if (!cmd->independent_metadata_areas && critical_section())
 				return_NULL;
 			lvmcache_label_scan(cmd, 2);
-			if (!(fmt = lvmcache_fmt_from_vgname(vgname, vgid, 0)))
+			if (!(fmt = lvmcache_fmt_from_vgname(cmd, vgname, vgid, 0)))
 				return_NULL;
 		}
 	}
@@ -2999,6 +3019,12 @@ static struct volume_group *_vg_read(str
 	/* Ensure every PV in the VG was in the cache */
 	if (correct_vg) {
 		/*
+		 * Update the seqno from the cache, for the benefit of
+		 * retro-style metadata formats like LVM1.
+		 */
+		correct_vg->seqno = seqno > correct_vg->seqno ? seqno : correct_vg->seqno;
+
+		/*
 		 * If the VG has PVs without mdas, or ignored mdas, they may
 		 * still be orphans in the cache: update the cache state here,
 		 * and update the metadata lists in the vg.
@@ -3109,7 +3135,7 @@ static struct volume_group *_vg_read(str
 		if (!cmd->independent_metadata_areas && critical_section())
 			return_NULL;
 		lvmcache_label_scan(cmd, 2);
-		if (!(fmt = lvmcache_fmt_from_vgname(vgname, vgid, 0)))
+		if (!(fmt = lvmcache_fmt_from_vgname(cmd, vgname, vgid, 0)))
 			return_NULL;
 
 		if (precommitted && !(fmt->features & FMT_PRECOMMIT))
@@ -3555,14 +3581,22 @@ static struct physical_volume *_pv_read(
 	if (!(dev = dev_cache_get(pv_name, cmd->filter)))
 		return_NULL;
 
-	if (!(label_read(dev, &label, UINT64_C(0)))) {
-		if (warnings)
-			log_error("No physical volume label read from %s",
-				  pv_name);
-		return NULL;
+	if (lvmetad_active()) {
+		info = lvmcache_info_from_pvid(dev->pvid, 0);
+		if (!info && !lvmetad_pv_lookup_by_devt(cmd, dev->dev))
+			return NULL;
+		info = lvmcache_info_from_pvid(dev->pvid, 0);
+		label = lvmcache_get_label(info);
+	} else {
+		if (!(label_read(dev, &label, UINT64_C(0)))) {
+			if (warnings)
+				log_error("No physical volume label read from %s",
+					  pv_name);
+			return NULL;
+		}
+		info = (struct lvmcache_info *) label->info;
 	}
 
-	info = (struct lvmcache_info *) label->info;
 	fmt = lvmcache_fmt(info);
 
 	pv = _alloc_pv(pvmem, dev);
@@ -3721,6 +3755,9 @@ int pv_write(struct cmd_context *cmd __a
 	if (!pv->fmt->ops->pv_write(pv->fmt, pv))
 		return_0;
 
+	if (!lvmetad_pv_found(pv->id, pv->dev, pv->fmt, pv->label_sector, NULL))
+		return_0;
+
 	return 1;
 }
 
@@ -4093,9 +4130,9 @@ uint32_t vg_lock_newname(struct cmd_cont
 
 	/* Find the vgname in the cache */
 	/* If it's not there we must do full scan to be completely sure */
-	if (!lvmcache_fmt_from_vgname(vgname, NULL, 1)) {
+	if (!lvmcache_fmt_from_vgname(cmd, vgname, NULL, 1)) {
 		lvmcache_label_scan(cmd, 0);
-		if (!lvmcache_fmt_from_vgname(vgname, NULL, 1)) {
+		if (!lvmcache_fmt_from_vgname(cmd, vgname, NULL, 1)) {
 			/* Independent MDAs aren't supported under low memory */
 			if (!cmd->independent_metadata_areas && critical_section()) {
 				/*
@@ -4106,7 +4143,7 @@ uint32_t vg_lock_newname(struct cmd_cont
 				return FAILED_LOCKING;
 			}
 			lvmcache_label_scan(cmd, 2);
-			if (!lvmcache_fmt_from_vgname(vgname, NULL, 0)) {
+			if (!lvmcache_fmt_from_vgname(cmd, vgname, NULL, 0)) {
 				/* vgname not found after scanning */
 				return SUCCESS;
 			}
@@ -4201,8 +4238,9 @@ int fid_add_mda(struct format_instance *
 		 const char *key, size_t key_len, const unsigned sub_key)
 {
 	static char full_key[PATH_MAX];
+
 	dm_list_add(mda_is_ignored(mda) ? &fid->metadata_areas_ignored :
-					  &fid->metadata_areas_in_use, &mda->list);
+		                          &fid->metadata_areas_in_use, &mda->list);
 
 	/* Return if the mda is not supposed to be indexed. */
 	if (!key)
@@ -4211,7 +4249,7 @@ int fid_add_mda(struct format_instance *
 	/* Add metadata area to index. */
 	if (!_convert_key_to_string(key, key_len, sub_key,
 				    full_key, sizeof(full_key)))
-	return_0;
+		return_0;
 
 	dm_hash_insert(fid->metadata_areas_index,
 		       full_key, mda);
Index: lib/metadata/metadata.h
===================================================================
RCS file: /cvs/lvm2/LVM2/lib/metadata/metadata.h,v
retrieving revision 1.266
diff -u -p -r1.266 metadata.h
--- lib/metadata/metadata.h	8 Feb 2012 13:05:39 -0000	1.266
+++ lib/metadata/metadata.h	21 Feb 2012 23:47:36 -0000
@@ -70,9 +70,11 @@
 struct dm_config_tree;
 struct metadata_area;
 struct alloc_handle;
+struct lvmcache_info;
 
 /* Per-format per-metadata area operations */
 struct metadata_area_ops {
+	struct dm_list list;
 	struct volume_group *(*vg_read) (struct format_instance * fi,
 					 const char *vg_name,
 					 struct metadata_area * mda);
@@ -145,6 +147,8 @@ struct metadata_area_ops {
 				    struct metadata_area *mda2);
 
 	struct device *(*mda_get_device)(struct metadata_area *mda);
+	char *(*mda_export_text)(struct metadata_area *mda);
+	int (*mda_import_text)(struct lvmcache_info *info, const struct dm_config_node *cn);
 };
 
 #define MDA_IGNORED      0x00000001
Index: scripts/vgimportclone.sh
===================================================================
RCS file: /cvs/lvm2/LVM2/scripts/vgimportclone.sh,v
retrieving revision 1.4
diff -u -p -r1.4 vgimportclone.sh
--- scripts/vgimportclone.sh	7 Sep 2011 08:31:17 -0000	1.4
+++ scripts/vgimportclone.sh	21 Feb 2012 23:47:36 -0000
@@ -249,6 +249,7 @@ LVMCONF=${TMP_LVM_SYSTEM_DIR}/lvm.conf
     '/^[ \t]*filter[ \t]*=/{print ENVIRON["FILTER"];next} \
      /^[ \t]*scan[ \t]*=/{print "scan = [ \"" DEV "\" ]";next} \
      /^[ \t]*cache[ \t]*=/{print "cache = \"" CACHE "\"";next} \
+     /^[ \t]*use_lvmetad[ \t]*=/{print "use_lvmetad = 0";next} \
      /^[ \t]*cache_dir[ \t]*=/{print "cache_dir = \"" CACHE_DIR "\"";next} \
      {print $0}' > ${LVMCONF}
 
Index: test/lib/aux.sh
===================================================================
RCS file: /cvs/lvm2/LVM2/test/lib/aux.sh,v
retrieving revision 1.37
diff -u -p -r1.37 aux.sh
--- test/lib/aux.sh	15 Feb 2012 14:24:32 -0000	1.37
+++ test/lib/aux.sh	21 Feb 2012 23:47:37 -0000
@@ -70,6 +70,7 @@ prepare_lvmetad() {
 	}
 
 	lvmconf "global/use_lvmetad = 1"
+	lvmconf "devices/md_component_detection = 0"
 
 	lvmetad -f "$@" -s $TESTDIR/lvmetad.socket &
 	echo "$!" > LOCAL_LVMETAD
@@ -323,8 +324,11 @@ disable_dev() {
 
 	init_udev_transaction
 	for dev in "$@"; do
-        	dmsetup remove -f $dev || true
-		pvscan --lvmetad $dev || true
+	    maj=$(($(stat --printf=0x%t $dev)))
+	    min=$(($(stat --printf=0x%T $dev)))
+	    echo "disabling device $dev ($maj:$min)"
+            dmsetup remove -f $dev || true
+	    pvscan --lvmetad $maj:$min || true
 	done
 	finish_udev_transaction
 
Index: test/shell/inconsistent-metadata.sh
===================================================================
RCS file: /cvs/lvm2/LVM2/test/shell/inconsistent-metadata.sh,v
retrieving revision 1.1
diff -u -p -r1.1 inconsistent-metadata.sh
--- test/shell/inconsistent-metadata.sh	21 Nov 2011 00:15:46 -0000	1.1
+++ test/shell/inconsistent-metadata.sh	21 Feb 2012 23:47:37 -0000
@@ -40,29 +40,32 @@ vgscan 2>&1 | tee cmd.out
 not grep "Inconsistent metadata found for VG $vg" cmd.out
 check
 
-# vgdisplay fixes
-init
-vgdisplay 2>&1 | tee cmd.out
-grep "Inconsistent metadata found for VG $vg" cmd.out
-vgdisplay 2>&1 | tee cmd.out
-not grep "Inconsistent metadata found for VG $vg" cmd.out
-check
+# only vgscan would have noticed metadata inconsistencies when lvmetad is active
+if !test -e LOCAL_LVMETAD; then
+	# vgdisplay fixes
+	init
+	vgdisplay 2>&1 | tee cmd.out
+	grep "Inconsistent metadata found for VG $vg" cmd.out
+	vgdisplay 2>&1 | tee cmd.out
+	not grep "Inconsistent metadata found for VG $vg" cmd.out
+	check
 
-# lvs fixes up
-init
-lvs 2>&1 | tee cmd.out
-grep "Inconsistent metadata found for VG $vg" cmd.out
-vgdisplay 2>&1 | tee cmd.out
-not grep "Inconsistent metadata found for VG $vg" cmd.out
-check
+	# lvs fixes up
+	init
+	lvs 2>&1 | tee cmd.out
+	grep "Inconsistent metadata found for VG $vg" cmd.out
+	vgdisplay 2>&1 | tee cmd.out
+	not grep "Inconsistent metadata found for VG $vg" cmd.out
+	check
 
-# vgs fixes up as well
-init
-vgs 2>&1 | tee cmd.out
-grep "Inconsistent metadata found for VG $vg" cmd.out
-vgs 2>&1 | tee cmd.out
-not grep "Inconsistent metadata found for VG $vg" cmd.out
-check
+	# vgs fixes up as well
+	init
+	vgs 2>&1 | tee cmd.out
+	grep "Inconsistent metadata found for VG $vg" cmd.out
+	vgs 2>&1 | tee cmd.out
+	not grep "Inconsistent metadata found for VG $vg" cmd.out
+	check
+fi
 
 echo Check auto-repair of failed vgextend - metadata written to original pv but not new pv
 vgremove -f $vg
Index: test/shell/lvconvert-mirror.sh
===================================================================
RCS file: /cvs/lvm2/LVM2/test/shell/lvconvert-mirror.sh,v
retrieving revision 1.1
diff -u -p -r1.1 lvconvert-mirror.sh
--- test/shell/lvconvert-mirror.sh	21 Nov 2011 00:15:46 -0000	1.1
+++ test/shell/lvconvert-mirror.sh	21 Feb 2012 23:47:37 -0000
@@ -79,6 +79,7 @@ should not lvconvert -m-1 $vg/$lv1 $dev1
 lvconvert $vg/$lv1 # wait
 lvconvert -m2 $vg/$lv1 $dev1 $dev2 $dev4 $dev3:0 # If the above "should" failed...
 
+sleep 1
 lvconvert -m-1 $vg/$lv1 $dev1
 check mirror_images_on $lv1 $dev2 $dev4
 lvconvert -m-1 $vg/$lv1 $dev2
Index: test/shell/lvcreate-repair.sh
===================================================================
RCS file: /cvs/lvm2/LVM2/test/shell/lvcreate-repair.sh,v
retrieving revision 1.1
diff -u -p -r1.1 lvcreate-repair.sh
--- test/shell/lvcreate-repair.sh	21 Nov 2011 00:15:46 -0000	1.1
+++ test/shell/lvcreate-repair.sh	21 Feb 2012 23:47:37 -0000
@@ -14,8 +14,8 @@
 aux prepare_vg 3
 
 # fail multiple devices
-for i in pv1 pv2 pv3 ; do
-	for j in pv2 pv3 ; do
+for i in $dev1 $dev2 $dev3 ; do
+	for j in $dev2 $dev3 ; do
 
 		if test $i = $j ; then continue ; fi
 
@@ -24,21 +24,21 @@ for i in pv1 pv2 pv3 ; do
 
 		lvcreate -l1 -n $lv1 $vg $dev1
 
-		aux lvmconf "devices/filter = [ \"r/.*$i$/\", \"r/.*$j$/\", \"a/dev\/mapper\/.*pv[0-9_]*$/\", \"r/.*/\" ]"
+		aux disable_dev $i $j
 
 		vgreduce --removemissing --force $vg
 
 		# check if reduced device was removed
-		test $i = pv1 && dmsetup table | not egrep "$vg-$lv1: *[^ ]+" >/dev/null
+		test $i = $dev1 && dmsetup table | not egrep "$vg-$lv1: *[^ ]+" >/dev/null
 
 		lvcreate -l1 -n $lv2 $vg
 
-		test $i != pv1 && check lv_exists $vg $lv1
+		test $i != $dev1 && check lv_exists $vg $lv1
 		check lv_exists $vg $lv2
 
-		aux lvmconf 'devices/filter = [ "a/dev\/mapper\/.*pv[0-9_]*$/", "r/.*/" ]'
+		aux enable_dev $i $j
 
-		test $i != pv1 && check lv_exists $vg $lv1
+		test $i != $dev1 && check lv_exists $vg $lv1
 		check lv_exists $vg $lv2
 	done
 done
@@ -84,6 +84,7 @@ dd if=backup_i of="$dev1" bs=256K count=
 
 # dirty game
 dd if=/dev/zero of="$dev3" bs=256K count=1
+pvscan --lvmetad $dev3 || true # udev be watching you
 
 vgreduce --removemissing --force $vg
 
Index: test/shell/pool-labels.sh
===================================================================
RCS file: /cvs/lvm2/LVM2/test/shell/pool-labels.sh,v
retrieving revision 1.1
diff -u -p -r1.1 pool-labels.sh
--- test/shell/pool-labels.sh	21 Nov 2011 00:15:46 -0000	1.1
+++ test/shell/pool-labels.sh	21 Feb 2012 23:47:37 -0000
@@ -18,6 +18,7 @@ create_pool_label_()
   # printf comes from coreutils, and is probably not posix either
   env printf "\x01\x16\x70\x06\x5f\xcf\xff\xb9\xf8\x24\x8apool1" | dd of=$2 bs=5 seek=1 conv=notrunc
   env printf "\x04\x01\x03\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x0$1\x68\x01\x16\x70\x00\x00\x00\x00\x00\x06\x5f\xd0" | dd of=$2 bs=273 seek=1 conv=notrunc
+  pvscan --lvmetad "$2" || true
 }
 
 env printf "" || exit 200 # skip if printf is not available
Index: test/shell/vgimportclone.sh
===================================================================
RCS file: /cvs/lvm2/LVM2/test/shell/vgimportclone.sh,v
retrieving revision 1.1
diff -u -p -r1.1 vgimportclone.sh
--- test/shell/vgimportclone.sh	21 Nov 2011 00:15:46 -0000	1.1
+++ test/shell/vgimportclone.sh	21 Feb 2012 23:47:37 -0000
@@ -17,6 +17,7 @@ lvcreate -l100%FREE -n $lv1 $vg1
 
 # Clone the LUN
 dd if=$dev1 of=$dev2 bs=256K count=1
+pvscan --lvmetad $dev2 || true
 
 # Verify pvs works on each device to give us vgname
 check pv_field $dev1 vg_name $vg1
@@ -25,6 +26,13 @@ check pv_field $dev2 vg_name $vg1
 # Import the cloned PV to a new VG
 vgimportclone --basevgname $vg2 $dev2
 
+# We need to re-scan *both* $dev1 and $dev2 since a PV, as far as lvmetad is
+# concerned, can only live on a single device. With the last pvscan, we told it
+# that PV from $dev1 now lives on $dev2, but in fact this is not true anymore,
+# since we wrote a different PV over $dev2.
+pvscan --lvmetad $dev2 || true
+pvscan --lvmetad $dev1 || true
+
 # Verify we can activate / deactivate the LV from both VGs
 lvchange -ay $vg1/$lv1 $vg2/$lv1
 vgchange -an $vg1 $vg2
Index: test/unit/Makefile.in
===================================================================
RCS file: /cvs/lvm2/LVM2/test/unit/Makefile.in,v
retrieving revision 1.7
diff -u -p -r1.7 Makefile.in
--- test/unit/Makefile.in	27 Jan 2012 10:55:02 -0000	1.7
+++ test/unit/Makefile.in	21 Feb 2012 23:47:37 -0000
@@ -25,7 +25,7 @@ ifeq ("$(TESTING)", "yes")
 LDLIBS += -ldevmapper @CUNIT_LIBS@
 CFLAGS += @CUNIT_CFLAGS@
 
-all: unit
+check: unit
 
 unit: $(TARGETS)
 	@echo Running unit tests
Index: tools/Makefile.in
===================================================================
RCS file: /cvs/lvm2/LVM2/tools/Makefile.in,v
retrieving revision 1.124
diff -u -p -r1.124 Makefile.in
--- tools/Makefile.in	14 Nov 2011 21:30:36 -0000	1.124
+++ tools/Makefile.in	21 Feb 2012 23:47:41 -0000
@@ -16,6 +16,8 @@ srcdir = @srcdir@
 top_srcdir = @top_srcdir@
 top_builddir = @top_builddir@
 
+INCLUDES += -I$(top_srcdir)/daemons/common -I$(top_srcdir)/daemons/lvmetad
+
 SOURCES =\
 	dumpconfig.c \
 	formats.c \
Index: tools/args.h
===================================================================
RCS file: /cvs/lvm2/LVM2/tools/args.h,v
retrieving revision 1.86
diff -u -p -r1.86 args.h
--- tools/args.h	30 Nov 2011 02:02:12 -0000	1.86
+++ tools/args.h	21 Feb 2012 23:47:41 -0000
@@ -61,6 +61,7 @@ arg(use_policies_ARG, '\0', "use-policie
 arg(monitor_ARG, '\0', "monitor", yes_no_arg, 0)
 arg(config_ARG, '\0', "config", string_arg, 0)
 arg(trustcache_ARG, '\0', "trustcache", NULL, 0)
+arg(lvmetad_ARG, '\0', "lvmetad", NULL, 0)
 arg(ignoremonitoring_ARG, '\0', "ignoremonitoring", NULL, 0)
 arg(nameprefixes_ARG, '\0', "nameprefixes", NULL, 0)
 arg(unquoted_ARG, '\0', "unquoted", NULL, 0)
Index: tools/commands.h
===================================================================
RCS file: /cvs/lvm2/LVM2/tools/commands.h,v
retrieving revision 1.167
diff -u -p -r1.167 commands.h
--- tools/commands.h	30 Nov 2011 02:02:12 -0000	1.167
+++ tools/commands.h	21 Feb 2012 23:47:44 -0000
@@ -670,11 +670,12 @@ xx(pvscan,
    "\t[-P|--partial] " "\n"
    "\t[-s|--short] " "\n"
    "\t[-u|--uuid] " "\n"
+   "\t[--lvmetad DEVICE] " "\n"
    "\t[-v|--verbose] " "\n"
    "\t[--version]\n",
 
    exported_ARG, ignorelockingfailure_ARG, novolumegroup_ARG, partial_ARG,
-   short_ARG, uuid_ARG)
+   short_ARG, uuid_ARG, lvmetad_ARG)
 
 xx(segtypes,
    "List available segment types",
Index: tools/pvcreate.c
===================================================================
RCS file: /cvs/lvm2/LVM2/tools/pvcreate.c,v
retrieving revision 1.98
diff -u -p -r1.98 pvcreate.c
--- tools/pvcreate.c	13 Feb 2012 11:04:00 -0000	1.98
+++ tools/pvcreate.c	21 Feb 2012 23:47:44 -0000
@@ -56,6 +56,7 @@ static int pvcreate_restore_params_valid
 		if (!id_read_format(&pp->id, uuid))
 			return 0;
 		pp->idp = &pp->id;
+		lvmcache_seed_infos_from_lvmetad(cmd); /* need to check for UUID dups */
 	}
 
 	if (arg_count(cmd, restorefile_ARG)) {
@@ -95,6 +96,7 @@ int pvcreate(struct cmd_context *cmd, in
 	struct pvcreate_params pp;
 	struct physical_volume *pv;
 
+	allow_reads_with_lvmetad();
 	pvcreate_params_set_defaults(&pp);
 
 	if (!pvcreate_restore_params_validate(cmd, argc, argv, &pp)) {
Index: tools/pvremove.c
===================================================================
RCS file: /cvs/lvm2/LVM2/tools/pvremove.c,v
retrieving revision 1.36
diff -u -p -r1.36 pvremove.c
--- tools/pvremove.c	30 Aug 2011 14:55:19 -0000	1.36
+++ tools/pvremove.c	21 Feb 2012 23:47:44 -0000
@@ -128,6 +128,8 @@ static int pvremove_single(struct cmd_co
 		goto error;
 	}
 
+	lvmetad_pv_gone(dev->dev);
+
 	log_print("Labels on physical volume \"%s\" successfully wiped",
 		  pv_name);
 
Index: tools/pvscan.c
===================================================================
RCS file: /cvs/lvm2/LVM2/tools/pvscan.c,v
retrieving revision 1.53
diff -u -p -r1.53 pvscan.c
--- tools/pvscan.c	11 Mar 2011 14:56:56 -0000	1.53
+++ tools/pvscan.c	21 Feb 2012 23:47:44 -0000
@@ -15,6 +15,9 @@
 
 #include "tools.h"
 
+#include "lvmetad.h"
+#include "lvmcache.h"
+
 int pv_max_name_len = 0;
 int vg_max_name_len = 0;
 
@@ -96,8 +99,7 @@ static void _pvscan_display_single(struc
 					   pv_pe_size(pv)));
 }
 
-int pvscan(struct cmd_context *cmd, int argc __attribute__((unused)),
-	   char **argv __attribute__((unused)))
+int pvscan(struct cmd_context *cmd, int argc, char **argv)
 {
 	int new_pvs_found = 0;
 	int pvs_found = 0;
@@ -113,6 +115,12 @@ int pvscan(struct cmd_context *cmd, int 
 	pv_max_name_len = 0;
 	vg_max_name_len = 0;
 
+	if (arg_count(cmd, lvmetad_ARG)) {
+		if (!pvscan_lvmetad(cmd, argc, argv))
+			return ECMD_FAILED;
+		return ECMD_PROCESSED;
+	}
+
 	if (arg_count(cmd, novolumegroup_ARG) && arg_count(cmd, exported_ARG)) {
 		log_error("Options -e and -n are incompatible");
 		return EINVALID_CMD_LINE;
@@ -184,8 +192,9 @@ int pvscan(struct cmd_context *cmd, int 
 	vg_max_name_len += 2;
 
 	dm_list_iterate_items(pvl, pvslist) {
-	    _pvscan_display_single(cmd, pvl->pv, NULL);
-	    free_pv_fid(pvl->pv);
+		// lvmetad_pv_found(pvl->pv->id, pvl->pv->dev, NULL);
+		_pvscan_display_single(cmd, pvl->pv, NULL);
+		free_pv_fid(pvl->pv);
 	}
 
 	if (!pvs_found) {
Index: tools/toollib.c
===================================================================
RCS file: /cvs/lvm2/LVM2/tools/toollib.c,v
retrieving revision 1.240
diff -u -p -r1.240 toollib.c
--- tools/toollib.c	10 Feb 2012 01:28:28 -0000	1.240
+++ tools/toollib.c	21 Feb 2012 23:48:03 -0000
@@ -305,6 +305,7 @@ int process_each_lv(struct cmd_context *
 
 	if (!argc || !dm_list_empty(&tags)) {
 		log_verbose("Finding all logical volumes");
+		lvmetad_vg_list_to_lvmcache(cmd);
 		if (!(vgnames = get_vgnames(cmd, 0)) || dm_list_empty(vgnames)) {
 			log_error("No volume groups found");
 			return ret_max;
@@ -581,6 +582,7 @@ int process_each_vg(struct cmd_context *
 
 	if (!argc || !dm_list_empty(&tags)) {
 		log_verbose("Finding all volume groups");
+		lvmetad_vg_list_to_lvmcache(cmd);
 		if (!(vgids = get_vgids(cmd, 0)) || dm_list_empty(vgids)) {
 			log_error("No volume groups found");
 			return ret_max;
@@ -837,6 +839,7 @@ int process_each_pv(struct cmd_context *
 		} else {
 			log_verbose("Scanning for physical volume names");
 
+			lvmcache_seed_infos_from_lvmetad(cmd);
 			if (!(pvslist = get_pvs(cmd)))
 				goto bad;
 
Index: tools/tools.h
===================================================================
RCS file: /cvs/lvm2/LVM2/tools/tools.h,v
retrieving revision 1.78
diff -u -p -r1.78 tools.h
--- tools/tools.h	5 Jan 2012 15:38:19 -0000	1.78
+++ tools/tools.h	21 Feb 2012 23:48:03 -0000
@@ -28,6 +28,7 @@
 #include "activate.h"
 #include "archiver.h"
 #include "lvmcache.h"
+#include "lvmetad.h"
 #include "config.h"
 #include "defaults.h"
 #include "dev-cache.h"
Index: tools/vgcfgrestore.c
===================================================================
RCS file: /cvs/lvm2/LVM2/tools/vgcfgrestore.c,v
retrieving revision 1.25
diff -u -p -r1.25 vgcfgrestore.c
--- tools/vgcfgrestore.c	18 Feb 2011 14:47:31 -0000	1.25
+++ tools/vgcfgrestore.c	21 Feb 2012 23:48:03 -0000
@@ -45,6 +45,8 @@ int vgcfgrestore(struct cmd_context *cmd
 		return ECMD_PROCESSED;
 	}
 
+	lvmcache_seed_infos_from_lvmetad(cmd);
+
 	if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) {
 		log_error("Unable to lock volume group %s", vg_name);
 		return ECMD_FAILED;
Index: tools/vgcreate.c
===================================================================
RCS file: /cvs/lvm2/LVM2/tools/vgcreate.c,v
retrieving revision 1.84
diff -u -p -r1.84 vgcreate.c
--- tools/vgcreate.c	10 Aug 2011 20:25:31 -0000	1.84
+++ tools/vgcreate.c	21 Feb 2012 23:48:03 -0000
@@ -49,6 +49,8 @@ int vgcreate(struct cmd_context *cmd, in
 	if (vgcreate_params_validate(cmd, &vp_new))
 	    return EINVALID_CMD_LINE;
 
+	lvmcache_seed_infos_from_lvmetad(cmd);
+
 	/* Create the new VG */
 	vg = vg_create(cmd, vp_new.vg_name);
 	if (vg_read_error(vg)) {
Index: tools/vgrename.c
===================================================================
RCS file: /cvs/lvm2/LVM2/tools/vgrename.c,v
retrieving revision 1.77
diff -u -p -r1.77 vgrename.c
--- tools/vgrename.c	10 Feb 2012 01:28:29 -0000	1.77
+++ tools/vgrename.c	21 Feb 2012 23:48:06 -0000
@@ -79,6 +79,8 @@ static int vg_rename_path(struct cmd_con
 
 	log_verbose("Checking for existing volume group \"%s\"", vg_name_old);
 
+	lvmetad_vg_list_to_lvmcache(cmd); /* populate lvmcache */
+
 	/* Avoid duplicates */
 	if (!(vgids = get_vgids(cmd, 0)) || dm_list_empty(vgids)) {
 		log_error("No complete volume groups found");
Index: tools/vgscan.c
===================================================================
RCS file: /cvs/lvm2/LVM2/tools/vgscan.c,v
retrieving revision 1.38
diff -u -p -r1.38 vgscan.c
--- tools/vgscan.c	9 Jul 2010 15:34:48 -0000	1.38
+++ tools/vgscan.c	21 Feb 2012 23:48:06 -0000
@@ -24,13 +24,14 @@ static int vgscan_single(struct cmd_cont
 		  vg->fid->fmt->name);
 
 	check_current_backup(vg);
+	lvmetad_vg_update(vg); /* keep lvmetad up to date */
 
 	return ECMD_PROCESSED;
 }
 
 int vgscan(struct cmd_context *cmd, int argc, char **argv)
 {
-	int maxret, ret;
+	int maxret, ret, lvmetad;
 
 	if (argc) {
 		log_error("Too many parameters on command line");
@@ -44,6 +45,8 @@ int vgscan(struct cmd_context *cmd, int 
 
 	persistent_filter_wipe(cmd->filter);
 	lvmcache_destroy(cmd, 1);
+	lvmetad = lvmetad_active();
+	lvmetad_set_active(0); /* do not rely on lvmetad info */
 
 	log_print("Reading all physical volumes.  This may take a while...");
 
@@ -56,6 +59,7 @@ int vgscan(struct cmd_context *cmd, int 
 			maxret = ret;
 	}
 
+	lvmetad_set_active(lvmetad); /* restore */
 	unlock_vg(cmd, VG_GLOBAL);
 	return maxret;
 }
-- 
id' Ash = Ash; id' Dust = Dust; id' _ = undefined

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]