From 3a0ef77305b179511aae6d8e5af05bbbebabee6b Mon Sep 17 00:00:00 2001 From: Peter Rajnoha Date: Tue, 1 Mar 2016 15:20:49 +0100 Subject: [PATCH] metadata: format_text: also export historical LVs Also export historical LVs when exporting LVM2 metadata. This is list of all historical LVs listed in "historical_logical_volumes" metadata section with all the properties exported for each historical LV. For example, we have this thin snapshot sequence: lvol1 --> lvol2 --> lvol3 \ --> lvol4 We end up with these metadata: logical_volume { ... (lvol1, lvol3 and lvol4 listed here as usual - no change here) ... } historical_logical_volumes { lvol2 { id = "S0Dw1U-v5sF-LwAb-W9SI-pNOF-Madd-5dxSv5" creation_time = 1456919613 # 2016-03-02 12:53:33 +0100 removal_time = 1456919620 # 2016-03-02 12:53:40 +0100 origin = "lvol1" descendants = ["lvol3", "lvol4"] } } By removing lvol1 further, we end up with: historical_logical_volumes { lvol2 { id = "S0Dw1U-v5sF-LwAb-W9SI-pNOF-Madd-5dxSv5" creation_time = 1456919613 # 2016-03-02 12:53:33 +0100 removal_time = 1456919620 # 2016-03-02 12:53:40 +0100 origin = "-lvol1" descendants = ["lvol3", "lvol4"] } lvol1 { id = "me0mes-aYnK-nRfT-vNlV-UiR1-GP7r-ojbROr" creation_time = 1456919608 # 2016-03-02 12:53:28 +0100 removal_time = 1456919767 # 2016-03-02 12:56:07 +0100 } } --- lib/format_text/export.c | 144 +++++++++++++++++++++++++++++++ lib/metadata/metadata-exported.h | 2 + lib/thin/thin.c | 1 + 3 files changed, 147 insertions(+) diff --git a/lib/format_text/export.c b/lib/format_text/export.c index 99ed20090..f17ccf574 100644 --- a/lib/format_text/export.c +++ b/lib/format_text/export.c @@ -651,6 +651,25 @@ int out_areas(struct formatter *f, const struct lv_segment *seg, return 1; } +static int _print_timestamp(struct formatter *f, + const char *name, time_t ts, + char *buf, size_t buf_size) +{ + struct tm *local_tm; + + if (ts) { + strncpy(buf, "# ", buf_size); + if (!(local_tm = localtime(&ts)) || + !strftime(buf + 2, buf_size - 2, + "%Y-%m-%d %T %z", local_tm)) + buf[0] = 0; + + outfc(f, buf, "%s = %" PRIu64, name, ts); + } + + return 1; +} + static int _print_lv(struct formatter *f, struct logical_volume *lv) { struct lv_segment *seg; @@ -774,6 +793,127 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg) return 1; } +static int _alloc_printed_indirect_descendants(struct dm_list *indirect_glvs, char **buffer) +{ + struct glv_list *user_glvl; + size_t buf_size = 0; + int first = 1; + char *buf; + + *buffer = NULL; + + dm_list_iterate_items(user_glvl, indirect_glvs) { + if (user_glvl->glv->is_historical) + continue; + /* '"' + name + '"' + ',' + ' ' */ + buf_size += strlen(user_glvl->glv->live->name) + 4; + } + + if (!buf_size) + return 1; + + /* '[' + ']' + '\0' */ + buf_size += 3; + + if (!(*buffer = dm_malloc(buf_size))) { + log_error("Could not allocate memory for ancestor list buffer."); + return 0; + } + buf = *buffer; + + if (!emit_to_buffer(&buf, &buf_size, "[")) + goto_bad; + + dm_list_iterate_items(user_glvl, indirect_glvs) { + if (user_glvl->glv->is_historical) + continue; + if (!first) { + if (!emit_to_buffer(&buf, &buf_size, ", ")) + goto_bad; + } else + first = 0; + + if (!emit_to_buffer(&buf, &buf_size, "\"%s\"", user_glvl->glv->live->name)) + goto_bad; + } + + if (!emit_to_buffer(&buf, &buf_size, "]")) + goto_bad; + + return 1; +bad: + if (*buffer) { + dm_free(*buffer); + *buffer = NULL; + } + return 0; +} + +static int _print_historical_lv(struct formatter *f, struct historical_logical_volume *hlv) +{ + char buffer[40]; + char *descendants_buffer = NULL; + int r = 0; + + if (!id_write_format(&hlv->lvid.id[1], buffer, sizeof(buffer))) + goto_out; + + if (!_alloc_printed_indirect_descendants(&hlv->indirect_glvs, &descendants_buffer)) + goto_out; + + outnl(f); + outf(f, "%s {", hlv->name); + _inc_indent(f); + + outf(f, "id = \"%s\"", buffer); + + if (!_print_timestamp(f, "creation_time", hlv->timestamp, buffer, sizeof(buffer))) + goto_out; + + if (!_print_timestamp(f, "removal_time", hlv->timestamp_removed, buffer, sizeof(buffer))) + goto_out; + + if (hlv->indirect_origin) { + if (hlv->indirect_origin->is_historical) + outf(f, "origin = \"%s%s\"", HISTORICAL_LV_PREFIX, hlv->indirect_origin->historical->name); + else + outf(f, "origin = \"%s\"", hlv->indirect_origin->live->name); + } + + if (descendants_buffer) + outf(f, "descendants = %s", descendants_buffer); + + _dec_indent(f); + outf(f, "}"); + + r = 1; +out: + if (descendants_buffer) + dm_free(descendants_buffer); + return r; +} + +static int _print_historical_lvs(struct formatter *f, struct volume_group *vg) +{ + struct glv_list *glvl; + + if (dm_list_empty(&vg->historical_lvs)) + return 1; + + outf(f, "historical_logical_volumes {"); + _inc_indent(f); + + dm_list_iterate_items(glvl, &vg->historical_lvs) { + if (!_print_historical_lv(f, glvl->glv->historical)) + return_0; + } + + _dec_indent(f); + outf(f, "}"); + + return 1; +} + /* * In the text format we refer to pv's as 'pv1', * 'pv2' etc. This function builds a hash table @@ -840,6 +980,10 @@ static int _text_vg_export(struct formatter *f, if (!_print_lvs(f, vg)) goto_out; + outnl(f); + if (!_print_historical_lvs(f, vg)) + goto_out; + _dec_indent(f); if (!out_text(f, "}")) goto_out; diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h index 76597ba6f..7f1d43c92 100644 --- a/lib/metadata/metadata-exported.h +++ b/lib/metadata/metadata-exported.h @@ -37,6 +37,8 @@ #define MAX_EXTENT_SIZE ((uint32_t) -1) #define MIN_NON_POWER2_EXTENT_SIZE (128U * 2U) /* 128KB in sectors */ +#define HISTORICAL_LV_PREFIX "-" + /* Layer suffix */ #define MIRROR_SYNC_LAYER "_mimagetmp" diff --git a/lib/thin/thin.c b/lib/thin/thin.c index 221ac48ce..6a1905592 100644 --- a/lib/thin/thin.c +++ b/lib/thin/thin.c @@ -532,6 +532,7 @@ static int _thin_text_export(const struct lv_segment *seg, struct formatter *f) outf(f, "external_origin = \"%s\"", seg->external_lv->name); if (seg->origin) outf(f, "origin = \"%s\"", seg->origin->name); + if (seg->merge_lv) outf(f, "merge = \"%s\"", seg->merge_lv->name);