diff options
author | Peter Rajnoha <prajnoha@redhat.com> | 2015-08-10 12:23:01 +0200 |
---|---|---|
committer | Peter Rajnoha <prajnoha@redhat.com> | 2016-02-19 14:40:22 +0100 |
commit | ecf58f9e864f2b9b071578afec991f3aca147d3e (patch) | |
tree | 1f3fd141dbf1f322f8f4eac0ba4f1b737adeb904 | |
parent | 9ddbe44d26293b01777971a0ffde07f902bbff72 (diff) | |
download | lvm2-ecf58f9e864f2b9b071578afec991f3aca147d3e.tar.gz |
metadata: create former 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 former_logical_volume" wrapped up in "struct generic_logical_volume".
All instances of "struct former_logical_volume" are then recorded in "former_lvs"
list which is part of "struct volume_group".
The "former 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) --(indirects_glvs)--> g(formerLV2) --(indirects_glvs)--> g(liveLV3)
g(liveLV1) <--(indirect_origin)-- g(formerLV2) <--(indirect_origin)-- seg(liveLV3)
* Example with more former LVs:
g(liveLV1) --(indirects_glvs)--> g(formerLV2) --(indirects_glvs)--> g(formerLV3)--(indirects_glvs)--> g(liveLV4)
g(liveLV1) <--(indirect_origin)-- g(formerLV2) <--(indirect_origin)-- g(formerLV3) <--(indirect_origin)-- seg(liveLV4)
* Or with branches:
g(liveLV1) --(indirects_glvs)--> g(formerLV2A) --(indirects_glvs)--> g(formerLV3A) --(indirects_glvs)--> g(liveLV4A)
\
-> g(formerLV2B) --(indirects_glvs)--> g(formerLV3BA) --(indirects_glvs)--> g(liveLV4BA)
\
-> g(formerLV3BB) --(indirects_glvs)--> g(liveLV4BB)
g(liveLV1) <--(indirect_origin)-- g(formerLV2A) <--(indirect_origin)-- g(formerLV3A) <--(indirect_origin)-- seg(liveLV4A)
\
-(indirect_origin)-- g(formerLV2B) <--(indirect_origin)-- g(formerLV3BA) <--(indirect_origin)-- seg(liveLV4BA)
\
-(indirect_origin)-- g(formerLV3BB) <--(indirect_origin)-- seg(liveLV4BB)
* Or simple example when former LV is not remembered in records (compare with first "Simple example"):
g(liveLV1) --(indirects_glvs)--> g(liveLV3)
g(liveLV1) <--(indirect_origin)-- seg(liveLV3)
-rw-r--r-- | lib/metadata/metadata.c | 11 | ||||
-rw-r--r-- | lib/metadata/pool_manip.c | 101 |
2 files changed, 112 insertions, 0 deletions
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c index 8478abb08..89ac523bc 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> @@ -3149,7 +3150,9 @@ int vg_write(struct volume_group *vg) struct pv_to_write *pv_to_write, *pv_to_write_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")) { @@ -3161,6 +3164,14 @@ int vg_write(struct volume_group *vg) } } + dm_list_iterate_items(glvl, &vg->former_lvs) { + if (!glvl->glv->former->timestamp_removed) { + if (!current_timestamp) + current_timestamp = time(NULL); + glvl->glv->former->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..d2d1f8932 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,81 @@ int attach_pool_lv(struct lv_segment *seg, return 1; } +static struct glv_list *_init_former_glvl(struct dm_pool *mem, struct lv_segment *seg) +{ + struct glv_list *glvl; + struct former_logical_volume *flv; + + 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 (!(flv = dm_pool_zalloc(mem, sizeof(struct former_logical_volume)))) + goto_bad; + + flv->lvid = seg->lv->lvid; + flv->name = seg->lv->name; + flv->vg = seg->lv->vg; + flv->timestamp = seg->lv->timestamp; + dm_list_init(&flv->indirect_glvs); + + glvl->glv->is_former = 1; + glvl->glv->former = flv; + + return glvl; +bad: + log_error("Initialization of former 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_former_glv(struct lv_segment *seg_to_remove) +{ + struct dm_pool *mem = seg_to_remove->lv->vg->vgmem; + struct generic_logical_volume *former_glv, *origin_glv = NULL; + struct glv_list *former_glvl; + int origin_glv_created = 0; + + if (!(former_glvl = _init_former_glvl(mem, seg_to_remove))) + goto_bad; + former_glv = former_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_glvs(mem, origin_glv, former_glv)) + goto_bad; + } else if (seg_to_remove->indirect_origin) { + origin_glv = seg_to_remove->indirect_origin; + + if (!remove_glv_from_indirect_glvs(origin_glv, seg_to_remove->lv->this_glv)) + goto_bad; + + if (!add_glv_to_indirect_glvs(mem, origin_glv, former_glv)) + goto_bad; + } + + dm_list_add(&seg_to_remove->lv->vg->former_lvs, &former_glvl->list); + return former_glvl->glv; +bad: + log_error("Failed to create former 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 (former_glvl) + dm_pool_free(mem, former_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 +251,9 @@ int detach_pool_lv(struct lv_segment *seg) } } + if (!(previous_glv = _create_former_glv(seg))) + return_0; + if (!detach_thin_external_origin(seg)) return_0; @@ -202,15 +279,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_glvs(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_glvs) { + 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_glvs(glv, user_glv)) + return_0; + + if (previous_glv) { + if (!add_glv_to_indirect_glvs(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; } |