summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Rajnoha <prajnoha@redhat.com>2015-08-10 12:23:01 +0200
committerPeter Rajnoha <prajnoha@redhat.com>2016-02-03 17:40:31 +0100
commitf2757e402760b26a601746a877f2407adb9dedb5 (patch)
tree03fdaf3945593015a02406bd81fccd0e3076d0ef
parentc5e1fb9fcc7f0ab84bd77aac22118558cc614e40 (diff)
downloadlvm2-f2757e402760b26a601746a877f2407adb9dedb5.tar.gz
metadata: create dead LVs when LVs are removed and interconnect with live LVs to track history
When an LV is being removed, we create an instance of "struct dead_logical_volume" wrapped up in "struct generic_logical_volume". All instances of "struct dead_logical_volume" are then recorded in "dead_lvs" list which is part of "struct volume_group". The "dead lv" is then interconnected with "live LVs" (the ones which are not removed yet) like this: "g" stands for "this logical_volume is wrapped with struct generic_logical_volume" "seg" stands for "representative segment is chosen for this logical_volume" * Simple example: g(liveLV1) --(indirect_users)--> g(deadLV2) --(indirect_users)--> g(liveLV3) g(liveLV1) <--(indirect_origin)-- g(deadLV2) <--(indirect_origin)-- seg(liveLV3) * Example with more dead LVs: g(liveLV1) --(indirect_users)--> g(deadLV2) --(indirect_users)--> g(deadLV3)--(indirect_users)--> g(liveLV4) g(liveLV1) <--(indirect_origin)-- g(deadLV2) <--(indirect_origin)-- g(deadLV3) <--(indirect_origin)-- seg(liveLV4) * Or with branches: g(liveLV1) --(indirect_users)--> g(deadLV2A) --(indirect_users)--> g(deadLV3A) --(indirect_users)--> g(liveLV4A) \ -> g(deadLV2B) --(indirect_users)--> g(deadLV3BA) --(indirect_users)--> g(liveLV4BA) \ -> g(deadLV3BB) --(indirect_users)--> g(liveLV4BB) g(liveLV1) <--(indirect_origin)-- g(deadLV2A) <--(indirect_origin)-- g(deadLV3A) <--(indirect_origin)-- seg(liveLV4A) \ -(indirect_origin)-- g(deadLV2B) <--(indirect_origin)-- g(deadLV3BA) <--(indirect_origin)-- seg(liveLV4BA) \ -(indirect_origin)-- g(deadLV3BB) <--(indirect_origin)-- seg(liveLV4BB) * Or simple example when dead LV is not remembered in records (compare with first "Simple example"): g(liveLV1) --(indirect_users)--> g(liveLV3) g(liveLV1) <--(indirect_origin)-- seg(liveLV3)
-rw-r--r--lib/metadata/metadata.c11
-rw-r--r--lib/metadata/pool_manip.c109
2 files changed, 120 insertions, 0 deletions
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index d8a7128d1..d8bad0c3e 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -32,6 +32,7 @@
#include "archiver.h"
#include "defaults.h"
#include "lvmlockd.h"
+#include "time.h"
#include <math.h>
#include <sys/param.h>
@@ -3050,7 +3051,9 @@ int vg_write(struct volume_group *vg)
struct pv_to_create *pv_to_create, *pv_to_create_safe;
struct metadata_area *mda;
struct lv_list *lvl;
+ struct glv_list *glvl;
int revert = 0, wrote = 0;
+ time_t current_timestamp = 0;
dm_list_iterate_items(lvl, &vg->lvs) {
if (lvl->lv->lock_args && !strcmp(lvl->lv->lock_args, "pending")) {
@@ -3062,6 +3065,14 @@ int vg_write(struct volume_group *vg)
}
}
+ dm_list_iterate_items(glvl, &vg->dead_lvs) {
+ if (!glvl->glv->dead->timestamp_removed) {
+ if (!current_timestamp)
+ current_timestamp = time(NULL);
+ glvl->glv->dead->timestamp_removed = (uint64_t) current_timestamp;
+ }
+ }
+
if (!vg_validate(vg))
return_0;
diff --git a/lib/metadata/pool_manip.c b/lib/metadata/pool_manip.c
index cb12aaacd..1aef595c0 100644
--- a/lib/metadata/pool_manip.c
+++ b/lib/metadata/pool_manip.c
@@ -26,6 +26,7 @@
#include "dev-type.h"
#include "display.h"
#include "toolcontext.h"
+#include <stddef.h>
int attach_pool_metadata_lv(struct lv_segment *pool_seg,
struct logical_volume *metadata_lv)
@@ -123,8 +124,89 @@ int attach_pool_lv(struct lv_segment *seg,
return 1;
}
+static struct glv_list *_init_dead_glvl(struct dm_pool *mem, struct lv_segment *seg)
+{
+ struct glv_list *glvl;
+ struct dead_logical_volume *dlv;
+ char buf[NAME_LEN];
+ char *dname;
+
+ if (!(glvl = dm_pool_zalloc(mem, sizeof(struct glv_list))))
+ goto_bad;
+
+ if (!(glvl->glv = dm_pool_zalloc(mem, sizeof(struct generic_logical_volume))))
+ goto_bad;
+
+ if (!(dlv = dm_pool_zalloc(mem, sizeof(struct dead_logical_volume))))
+ goto_bad;
+
+ if (!(dname = generate_dead_lv_name(seg->lv->vg, "rlvol%d", buf, sizeof(buf))))
+ goto_bad;
+
+ if (!(dlv->dname = dm_pool_strdup(seg->lv->vg->vgmem, dname)))
+ goto_bad;
+
+ dlv->lvid = seg->lv->lvid;
+ dlv->name = seg->lv->name;
+ dlv->vg = seg->lv->vg;
+ dlv->timestamp = seg->lv->timestamp;
+ dm_list_init(&dlv->indirect_users);
+
+ glvl->glv->is_dead = 1;
+ glvl->glv->dead = dlv;
+
+ return glvl;
+bad:
+ log_error("Initialization of dead LV representation for removed logical "
+ "volume %s/%s failed.", seg->lv->vg->name, seg->lv->name);
+ if (glvl)
+ dm_pool_free(mem, glvl);
+ return NULL;
+}
+
+static struct generic_logical_volume *_create_dead_glv(struct lv_segment *seg_to_remove)
+{
+ struct dm_pool *mem = seg_to_remove->lv->vg->vgmem;
+ struct generic_logical_volume *dead_glv, *origin_glv = NULL;
+ struct glv_list *dead_glvl;
+ int origin_glv_created = 0;
+
+ if (!(dead_glvl = _init_dead_glvl(mem, seg_to_remove)))
+ goto_bad;
+ dead_glv = dead_glvl->glv;
+
+ if (seg_to_remove->origin) {
+ if (!(origin_glv = get_or_create_glv(mem, seg_to_remove->origin, &origin_glv_created)))
+ goto_bad;
+
+ if (!add_glv_to_indirect_user_list(mem, origin_glv, dead_glv))
+ goto_bad;
+ } else if (seg_to_remove->indirect_origin) {
+ origin_glv = seg_to_remove->indirect_origin;
+
+ if (!remove_glv_from_indirect_user_list(origin_glv, seg_to_remove->lv->this_glv))
+ goto_bad;
+
+ if (!add_glv_to_indirect_user_list(mem, origin_glv, dead_glv))
+ goto_bad;
+ }
+
+ dm_list_add(&seg_to_remove->lv->vg->dead_lvs, &dead_glvl->list);
+ return dead_glvl->glv;
+bad:
+ log_error("Failed to create dead LV representation for removed logical "
+ "volume %s/%s.", seg_to_remove->lv->vg->name, seg_to_remove->lv->name);
+ if (origin_glv_created)
+ seg_to_remove->origin->this_glv = NULL;
+ if (dead_glvl)
+ dm_pool_free(mem, dead_glvl);
+ return NULL;
+}
+
int detach_pool_lv(struct lv_segment *seg)
{
+ struct generic_logical_volume *previous_glv = NULL, *glv, *user_glv;
+ struct glv_list *user_glvl, *tglvl;
struct lv_thin_message *tmsg, *tmp;
struct seg_list *sl, *tsl;
int no_update = 0;
@@ -177,6 +259,9 @@ int detach_pool_lv(struct lv_segment *seg)
}
}
+ if (!(previous_glv = _create_dead_glv(seg)))
+ return_0;
+
if (!detach_thin_external_origin(seg))
return_0;
@@ -202,15 +287,39 @@ int detach_pool_lv(struct lv_segment *seg)
(seg->lv != sl->seg->origin))
continue;
+ if (previous_glv) {
+ if (!(user_glv = get_or_create_glv(seg->lv->vg->vgmem, sl->seg->lv, NULL)))
+ return_0;
+
+ if (!add_glv_to_indirect_user_list(seg->lv->vg->vgmem, previous_glv, user_glv))
+ return_0;
+ }
+
if (!remove_seg_from_segs_using_this_lv(seg->lv, sl->seg))
return_0;
/* Thin snapshot is now regular thin volume */
sl->seg->origin = NULL;
}
+ dm_list_iterate_items_safe(user_glvl, tglvl, &seg->lv->indirect_users) {
+ user_glv = user_glvl->glv;
+
+ if (!(glv = get_or_create_glv(seg->lv->vg->vgmem, seg->lv, NULL)))
+ return_0;
+
+ if (!remove_glv_from_indirect_user_list(glv, user_glv))
+ return_0;
+
+ if (previous_glv) {
+ if (!add_glv_to_indirect_user_list(seg->lv->vg->vgmem, previous_glv, user_glv))
+ return_0;
+ }
+ }
+
seg->lv->status &= ~THIN_VOLUME;
seg->pool_lv = NULL;
seg->origin = NULL;
+ seg->indirect_origin = NULL;
return 1;
}