summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Teigland <teigland@redhat.com>2014-11-06 14:01:12 -0600
committerDavid Teigland <teigland@redhat.com>2014-11-10 17:35:58 -0600
commitca434c7fa935b4b55da2f1d339b6a29b46debd8e (patch)
tree79376361cab1f59918955b07443d9d81f8e1f8ee
parentd5ad2a15f43e7246490baa208faf32682b3044cd (diff)
downloadlvm2-dev-dct-lvmetad-5.tar.gz
lvmcache: reread vg if the lvmetad copy is staledev-dct-lvmetad-5
-rw-r--r--daemons/lvmetad/lvmetad-core.c57
-rw-r--r--lib/cache/lvmetad.c100
-rw-r--r--libdaemon/client/config-util.c57
-rw-r--r--libdaemon/client/config-util.h2
4 files changed, 159 insertions, 57 deletions
diff --git a/daemons/lvmetad/lvmetad-core.c b/daemons/lvmetad/lvmetad-core.c
index ffa1c2867..e7b80c113 100644
--- a/daemons/lvmetad/lvmetad-core.c
+++ b/daemons/lvmetad/lvmetad-core.c
@@ -26,9 +26,6 @@
#include <stdint.h>
#include <unistd.h>
-#include <math.h> /* fabs() */
-#include <float.h> /* DBL_EPSILON */
-
#define LVMETAD_SOCKET DEFAULT_RUN_DIR "/lvmetad.socket"
struct vg_info {
@@ -552,60 +549,6 @@ bad:
return reply_fail("out of memory");
}
-/* Test if the doubles are close enough to be considered equal */
-static int close_enough(double d1, double d2)
-{
- return fabs(d1 - d2) < DBL_EPSILON;
-}
-
-static int compare_value(struct dm_config_value *a, struct dm_config_value *b)
-{
- int r = 0;
-
- if (a->type > b->type)
- return 1;
- if (a->type < b->type)
- return -1;
-
- switch (a->type) {
- case DM_CFG_STRING: r = strcmp(a->v.str, b->v.str); break;
- case DM_CFG_FLOAT: r = close_enough(a->v.f, b->v.f) ? 0 : (a->v.f > b->v.f) ? 1 : -1; break;
- case DM_CFG_INT: r = (a->v.i == b->v.i) ? 0 : (a->v.i > b->v.i) ? 1 : -1; break;
- case DM_CFG_EMPTY_ARRAY: return 0;
- }
-
- if (r == 0 && a->next && b->next)
- r = compare_value(a->next, b->next);
- return r;
-}
-
-static int compare_config(struct dm_config_node *a, struct dm_config_node *b)
-{
- int result = 0;
- if (a->v && b->v)
- result = compare_value(a->v, b->v);
- if (a->v && !b->v)
- result = 1;
- if (!a->v && b->v)
- result = -1;
- if (a->child && b->child)
- result = compare_config(a->child, b->child);
-
- if (result) {
- // DEBUGLOG("config inequality at %s / %s", a->key, b->key);
- return result;
- }
-
- if (a->sib && b->sib)
- result = compare_config(a->sib, b->sib);
- if (a->sib && !b->sib)
- result = 1;
- if (!a->sib && b->sib)
- result = -1;
-
- return result;
-}
-
static int vg_remove_if_missing(lvmetad_state *s, const char *vgid, int update_pvids);
/* You need to be holding the pvid_to_vgid lock already to call this. */
diff --git a/lib/cache/lvmetad.c b/lib/cache/lvmetad.c
index ccdf63a35..6526d285a 100644
--- a/lib/cache/lvmetad.c
+++ b/lib/cache/lvmetad.c
@@ -34,6 +34,8 @@ static char *_lvmetad_token = NULL;
static const char *_lvmetad_socket = NULL;
static struct cmd_context *_lvmetad_cmd = NULL;
+static struct volume_group *lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg);
+
void lvmetad_disconnect(void)
{
if (_lvmetad_connected)
@@ -362,6 +364,7 @@ static struct lvmcache_info *_pv_populate_lvmcache(struct cmd_context *cmd,
struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgname, const char *vgid)
{
struct volume_group *vg = NULL;
+ struct volume_group *vg2 = NULL;
daemon_reply reply;
int found;
char uuid[64];
@@ -442,6 +445,17 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgna
pvl->pv->status |= MISSING_PV; /* probably missing */
}
+ /*
+ * locking may have detected a newer vg version and
+ * invalidated the cached vg.
+ */
+ if (dm_config_find_node(reply.cft->root, "vg_invalid")) {
+ log_debug_lvmetad("Update invalid lvmetad cache for VG %s", vgname);
+ vg2 = lvmetad_pvscan_vg(cmd, vg);
+ release_vg(vg);
+ vg = vg2;
+ }
+
lvmcache_update_vg(vg, 0);
vg_mark_partial_lvs(vg, 1);
}
@@ -902,6 +916,92 @@ static int _lvmetad_pvscan_single(struct metadata_area *mda, void *baton)
return 1;
}
+/*
+ * The lock manager may detect that the vg cached in lvmetad is out of date,
+ * due to something like an lvcreate from another host.
+ * This is limited to changes that only affect the vg (not global state like
+ * orphan PVs), so we only need to reread mdas on the vg's existing pvs.
+ */
+
+static struct volume_group *lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg)
+{
+ struct volume_group *vg_ret = NULL;
+ struct dm_config_tree *vgmeta_ret = NULL;
+ struct dm_config_tree *vgmeta;
+ struct pv_list *pvl;
+ struct device *dev;
+ struct label *label;
+ struct lvmcache_info *info;
+ struct format_instance *fid;
+ struct format_instance_ctx fic = { .type = 0 };
+ struct _lvmetad_pvscan_baton baton;
+
+ dm_list_iterate_items(pvl, &vg->pvs) {
+ /* missing pv */
+ if (!pvl->pv->dev)
+ continue;
+
+ dev = pvl->pv->dev;
+
+ if (!label_read(dev, &label, 0)) {
+ log_print_unless_silent("No PV label found on %s.", dev_name(dev));
+ continue;
+ }
+
+ info = (struct lvmcache_info *) label->info;
+
+ baton.vg = NULL;
+ baton.fid = lvmcache_fmt(info)->ops->create_instance(lvmcache_fmt(info), &fic);
+
+ if (!baton.fid)
+ return NULL;
+
+ if (baton.fid->fmt->features & FMT_OBSOLETE) {
+ log_error("WARNING: Ignoring obsolete format of metadata (%s) on device %s when using lvmetad",
+ baton.fid->fmt->name, dev_name(dev));
+ lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
+ return NULL;
+ }
+
+ lvmcache_foreach_mda(info, _lvmetad_pvscan_single, &baton);
+
+ if (!baton.vg) {
+ lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
+ return NULL;
+ }
+
+ if (!(vgmeta = export_vg_to_config_tree(baton.vg))) {
+ log_error("VG export to config tree failed");
+ release_vg(baton.vg);
+ return NULL;
+ }
+
+ if (!vgmeta_ret) {
+ vgmeta_ret = vgmeta;
+ } else {
+ if (!compare_config(vgmeta_ret->root, vgmeta->root)) {
+ log_error("VG metadata comparison failed");
+ dm_config_destroy(vgmeta);
+ dm_config_destroy(vgmeta_ret);
+ release_vg(baton.vg);
+ return NULL;
+ }
+ dm_config_destroy(vgmeta);
+ }
+
+ release_vg(baton.vg);
+ }
+
+ if (vgmeta_ret) {
+ fid = lvmcache_fmt(info)->ops->create_instance(lvmcache_fmt(info), &fic);
+ if (!(vg_ret = import_vg_from_config_tree(vgmeta_ret, fid)))
+ log_error("VG import from config tree failed");
+ dm_config_destroy(vgmeta_ret);
+ }
+
+ return vg_ret;
+}
+
int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
activation_handler handler)
{
diff --git a/libdaemon/client/config-util.c b/libdaemon/client/config-util.c
index e5f4e2205..d6e23d08d 100644
--- a/libdaemon/client/config-util.c
+++ b/libdaemon/client/config-util.c
@@ -20,6 +20,9 @@
#include <string.h>
#include <unistd.h>
+#include <math.h> /* fabs() */
+#include <float.h> /* DBL_EPSILON */
+
int buffer_append_vf(struct buffer *buf, va_list ap)
{
char *append;
@@ -277,6 +280,60 @@ struct dm_config_node *config_make_nodes(struct dm_config_tree *cft,
return res;
}
+/* Test if the doubles are close enough to be considered equal */
+static int close_enough(double d1, double d2)
+{
+ return fabs(d1 - d2) < DBL_EPSILON;
+}
+
+static int compare_value(struct dm_config_value *a, struct dm_config_value *b)
+{
+ int r = 0;
+
+ if (a->type > b->type)
+ return 1;
+ if (a->type < b->type)
+ return -1;
+
+ switch (a->type) {
+ case DM_CFG_STRING: r = strcmp(a->v.str, b->v.str); break;
+ case DM_CFG_FLOAT: r = close_enough(a->v.f, b->v.f) ? 0 : (a->v.f > b->v.f) ? 1 : -1; break;
+ case DM_CFG_INT: r = (a->v.i == b->v.i) ? 0 : (a->v.i > b->v.i) ? 1 : -1; break;
+ case DM_CFG_EMPTY_ARRAY: return 0;
+ }
+
+ if (r == 0 && a->next && b->next)
+ r = compare_value(a->next, b->next);
+ return r;
+}
+
+int compare_config(struct dm_config_node *a, struct dm_config_node *b)
+{
+ int result = 0;
+ if (a->v && b->v)
+ result = compare_value(a->v, b->v);
+ if (a->v && !b->v)
+ result = 1;
+ if (!a->v && b->v)
+ result = -1;
+ if (a->child && b->child)
+ result = compare_config(a->child, b->child);
+
+ if (result) {
+ // DEBUGLOG("config inequality at %s / %s", a->key, b->key);
+ return result;
+ }
+
+ if (a->sib && b->sib)
+ result = compare_config(a->sib, b->sib);
+ if (a->sib && !b->sib)
+ result = 1;
+ if (!a->sib && b->sib)
+ result = -1;
+
+ return result;
+}
+
int buffer_realloc(struct buffer *buf, int needed)
{
char *new;
diff --git a/libdaemon/client/config-util.h b/libdaemon/client/config-util.h
index 47fab6bcb..d1ee3b345 100644
--- a/libdaemon/client/config-util.h
+++ b/libdaemon/client/config-util.h
@@ -42,6 +42,8 @@ struct dm_config_node *make_config_node(struct dm_config_tree *cft,
struct dm_config_node *parent,
struct dm_config_node *pre_sib);
+int compare_config(struct dm_config_node *a, struct dm_config_node *b);
+
struct dm_config_node *make_text_node(struct dm_config_tree *cft,
const char *key,
const char *value,