summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPetr Rockai <prockai@redhat.com>2015-04-15 13:00:35 +0200
committerPetr Rockai <prockai@redhat.com>2015-05-20 19:46:13 +0200
commit925268794f4c97091674d99d98e3d73349a75502 (patch)
tree7fc59ec447a671ec8ba6ead03d6d9c3de40e9960
parentf3c7bd4004a64b6ce2c9e0f0069eedb050420c62 (diff)
downloadlvm2-925268794f4c97091674d99d98e3d73349a75502.tar.gz
lvmetad: Maintain info about outdated PVs.
-rw-r--r--daemons/lvmetad/lvmetad-core.c82
1 files changed, 76 insertions, 6 deletions
diff --git a/daemons/lvmetad/lvmetad-core.c b/daemons/lvmetad/lvmetad-core.c
index 398ef38be..7e30add2a 100644
--- a/daemons/lvmetad/lvmetad-core.c
+++ b/daemons/lvmetad/lvmetad-core.c
@@ -40,6 +40,7 @@ typedef struct {
struct dm_hash_table *vgid_to_metadata;
struct dm_hash_table *vgid_to_vgname;
+ struct dm_hash_table *vgid_to_outdated_pvs;
struct dm_hash_table *vgname_to_vgid;
struct dm_hash_table *pvid_to_vgid;
struct {
@@ -66,6 +67,7 @@ static void destroy_metadata_hashes(lvmetad_state *s)
dm_hash_destroy(s->pvid_to_pvmeta);
dm_hash_destroy(s->vgid_to_metadata);
dm_hash_destroy(s->vgid_to_vgname);
+ dm_hash_destroy(s->vgid_to_outdated_pvs);
dm_hash_destroy(s->vgname_to_vgid);
dm_hash_destroy(s->device_to_pvid);
@@ -78,6 +80,7 @@ static void create_metadata_hashes(lvmetad_state *s)
s->device_to_pvid = dm_hash_create(32);
s->vgid_to_metadata = dm_hash_create(32);
s->vgid_to_vgname = dm_hash_create(32);
+ s->vgid_to_outdated_pvs = dm_hash_create(32);
s->pvid_to_vgid = dm_hash_create(32);
s->vgname_to_vgid = dm_hash_create(32);
}
@@ -420,6 +423,54 @@ bad:
return res;
}
+static void mark_outdated_pv(lvmetad_state *s, const char *vgid, const char *pvid)
+{
+ struct dm_config_tree *pvmeta, *outdated_pvs;
+ struct dm_config_node *list, *cft_vgid;
+ struct dm_config_value *v;
+
+ lock_pvid_to_pvmeta(s);
+ pvmeta = dm_hash_lookup(s->pvid_to_pvmeta, pvid);
+ unlock_pvid_to_pvmeta(s);
+
+ /* if the MDA exists and is used, it will have ignore=0 set */
+ if (!pvmeta ||
+ (dm_config_find_int64(pvmeta->root, "pvmeta/mda0/ignore", 1) &&
+ dm_config_find_int64(pvmeta->root, "pvmeta/mda1/ignore", 1)))
+ return;
+
+ WARN(s, "PV %s has outdated metadata", pvid);
+
+ outdated_pvs = dm_hash_lookup(s->vgid_to_outdated_pvs, vgid);
+ if (!outdated_pvs) {
+ if (!(outdated_pvs = dm_config_from_string("outdated_pvs/pv_list = []")) ||
+ !(cft_vgid = make_text_node(outdated_pvs, "vgid", dm_pool_strdup(outdated_pvs->mem, vgid),
+ outdated_pvs->root, NULL)))
+ abort();
+ if(!dm_hash_insert(s->vgid_to_outdated_pvs, cft_vgid->v->v.str, outdated_pvs))
+ abort();
+ DEBUGLOG(s, "created outdated_pvs list for VG %s", vgid);
+ }
+
+ list = dm_config_find_node(outdated_pvs->root, "outdated_pvs/pv_list");
+ v = list->v;
+ while (v) {
+ if (v->type != DM_CFG_EMPTY_ARRAY && !strcmp(v->v.str, pvid))
+ return;
+ v = v->next;
+ }
+ if (!(v = dm_config_create_value(outdated_pvs)))
+ abort();
+ v->type = DM_CFG_STRING;
+ v->v.str = dm_pool_strdup(outdated_pvs->mem, pvid);
+ v->next = list->v;
+ list->v = v;
+}
+
+static void chain_outdated_pvs(lvmetad_state *s, const char *vgid, struct dm_config_tree *metadata)
+{
+}
+
static response vg_lookup(lvmetad_state *s, request r)
{
struct dm_config_tree *cft;
@@ -486,6 +537,7 @@ static response vg_lookup(lvmetad_state *s, request r)
unlock_vg(s, uuid);
update_pv_status(s, res.cft, n, 1); /* FIXME report errors */
+ chain_outdated_pvs(s, uuid, res.cft);
return res;
bad:
@@ -549,9 +601,11 @@ static int compare_config(struct dm_config_node *a, struct dm_config_node *b)
static int vg_remove_if_missing(lvmetad_state *s, const char *vgid, int update_pvids);
+enum update_pvid_mode { UPDATE_ONLY, REMOVE_EMPTY, MARK_OUTDATED };
+
/* You need to be holding the pvid_to_vgid lock already to call this. */
static int update_pvid_to_vgid(lvmetad_state *s, struct dm_config_tree *vg,
- const char *vgid, int nuke_empty)
+ const char *vgid, int mode)
{
struct dm_config_node *pv;
struct dm_hash_table *to_check;
@@ -571,11 +625,14 @@ static int update_pvid_to_vgid(lvmetad_state *s, struct dm_config_tree *vg,
if (!(pvid = dm_config_find_str(pv->child, "id", NULL)))
continue;
- if (nuke_empty &&
+ if (mode == REMOVE_EMPTY &&
(vgid_old = dm_hash_lookup(s->pvid_to_vgid, pvid)) &&
!dm_hash_insert(to_check, vgid_old, (void*) 1))
goto out;
+ if (mode == MARK_OUTDATED)
+ mark_outdated_pv(s, vgid, pvid);
+
if (!dm_hash_insert(s->pvid_to_vgid, pvid, (void*) vgid))
goto out;
@@ -599,10 +656,11 @@ static int update_pvid_to_vgid(lvmetad_state *s, struct dm_config_tree *vg,
/* A pvid map lock needs to be held if update_pvids = 1. */
static int remove_metadata(lvmetad_state *s, const char *vgid, int update_pvids)
{
- struct dm_config_tree *old;
+ struct dm_config_tree *old, *outdated_pvs;
const char *oldname;
lock_vgid_to_metadata(s);
old = dm_hash_lookup(s->vgid_to_metadata, vgid);
+ outdated_pvs = dm_hash_lookup(s->vgid_to_outdated_pvs, vgid);
oldname = dm_hash_lookup(s->vgid_to_vgname, vgid);
if (!old) {
@@ -616,12 +674,15 @@ static int remove_metadata(lvmetad_state *s, const char *vgid, int update_pvids)
dm_hash_remove(s->vgid_to_metadata, vgid);
dm_hash_remove(s->vgid_to_vgname, vgid);
dm_hash_remove(s->vgname_to_vgid, oldname);
+ dm_hash_remove(s->vgid_to_outdated_pvs, vgid);
unlock_vgid_to_metadata(s);
if (update_pvids)
/* FIXME: What should happen when update fails */
update_pvid_to_vgid(s, old, "#orphan", 0);
dm_config_destroy(old);
+ if (outdated_pvs)
+ dm_config_destroy(outdated_pvs);
return 1;
}
@@ -665,7 +726,7 @@ static int vg_remove_if_missing(lvmetad_state *s, const char *vgid, int update_p
* this function, so they can be safely destroyed after update_metadata returns
* (anything that might have been retained is copied). */
static int update_metadata(lvmetad_state *s, const char *name, const char *_vgid,
- struct dm_config_node *metadata, int64_t *oldseq)
+ struct dm_config_node *metadata, int64_t *oldseq, const char *pvid)
{
struct dm_config_tree *cft = NULL;
struct dm_config_tree *old;
@@ -714,6 +775,10 @@ static int update_metadata(lvmetad_state *s, const char *name, const char *_vgid
if (seq < haveseq) {
DEBUGLOG(s, "Refusing to update metadata for %s (at %d) to %d", _vgid, haveseq, seq);
+
+ if (pvid)
+ mark_outdated_pv(s, dm_config_find_str(old->root, "metadata/id", NULL), pvid);
+
/* TODO: notify the client that their metadata is out of date? */
retval = 1;
goto out;
@@ -736,6 +801,8 @@ static int update_metadata(lvmetad_state *s, const char *name, const char *_vgid
if (haveseq >= 0 && haveseq < seq) {
INFO(s, "Updating metadata for %s at %d to %d", _vgid, haveseq, seq);
+ if (oldseq)
+ update_pvid_to_vgid(s, old, vgid, MARK_OUTDATED);
/* temporarily orphan all of our PVs */
update_pvid_to_vgid(s, old, "#orphan", 0);
}
@@ -992,7 +1059,7 @@ out_of_mem:
if (daemon_request_int(r, "metadata/seqno", -1) < 0)
return reply_fail("need VG seqno");
- if (!update_metadata(s, vgname, vgid, metadata, &seqno_old))
+ if (!update_metadata(s, vgname, vgid, metadata, &seqno_old, pvid))
return reply_fail("metadata update failed");
changed |= (seqno_old != dm_config_find_int(metadata, "metadata/seqno", -1));
} else {
@@ -1055,7 +1122,7 @@ static response vg_update(lvmetad_state *s, request r)
/* TODO defer metadata update here; add a separate vg_commit
* call; if client does not commit, die */
- if (!update_metadata(s, vgname, vgid, metadata, NULL))
+ if (!update_metadata(s, vgname, vgid, metadata, NULL, NULL))
return reply_fail("metadata update failed");
}
return daemon_reply_simple("OK", NULL);
@@ -1136,6 +1203,9 @@ static response dump(lvmetad_state *s)
buffer_append(b, "\n# VGID to VGNAME mapping\n\n");
_dump_pairs(b, s->vgid_to_vgname, "vgid_to_vgname", 0);
+ buffer_append(b, "\n# VGID to outdated PVs mapping\n\n");
+ _dump_cft(b, s->vgid_to_outdated_pvs, "outdated_pvs/vgid");
+
buffer_append(b, "\n# VGNAME to VGID mapping\n\n");
_dump_pairs(b, s->vgname_to_vgid, "vgname_to_vgid", 0);