diff options
author | David Teigland <teigland@redhat.com> | 2014-11-06 14:01:12 -0600 |
---|---|---|
committer | David Teigland <teigland@redhat.com> | 2014-11-10 15:03:29 -0600 |
commit | 1b528165ec31d7e7348b03c7f7a2e2a807c5e3ec (patch) | |
tree | e72ba5e8878905c6d23ea8ef0cd28668597e4937 | |
parent | d5ad2a15f43e7246490baa208faf32682b3044cd (diff) | |
download | lvm2-dev-dct-lvmetad-4.tar.gz |
lvmcache: reread vg if the lvmetad copy is staledev-dct-lvmetad-4
-rw-r--r-- | daemons/lvmetad/lvmetad-core.c | 57 | ||||
-rw-r--r-- | lib/cache/lvmetad.c | 95 | ||||
-rw-r--r-- | libdaemon/client/config-util.c | 57 | ||||
-rw-r--r-- | libdaemon/client/config-util.h | 2 |
4 files changed, 154 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..248875e8a 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) @@ -442,6 +444,15 @@ 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); + vg = lvmetad_pvscan_vg(cmd, vg); + } + lvmcache_update_vg(vg, 0); vg_mark_partial_lvs(vg, 1); } @@ -902,6 +913,90 @@ 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 _lvmetad_pvscan_baton baton; + /* Create a dummy instance. */ + struct format_instance_ctx fic = { .type = 0 }; + + 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) { + vg_ret = import_vg_from_config_tree(vgmeta_ret, baton.fid); + 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, |