mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
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 } }
This commit is contained in:
parent
790b2e8748
commit
3a0ef77305
@ -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;
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user