From 715f1fb4c4cbdb49a86ee95e17070d0ecc548ee0 Mon Sep 17 00:00:00 2001 From: Peter Rajnoha Date: Tue, 1 Mar 2016 15:24:40 +0100 Subject: [PATCH] report: add full_ancestors field to display ancestors with history The lv_full_ancestors reporting field is just like the existing lv_ancestors field but it also takes into account any history and indirect relations recorded. --- lib/report/columns.h | 3 +- lib/report/properties.c | 2 + lib/report/report.c | 91 +++++++++++++++++++++++++++++++++-------- 3 files changed, 79 insertions(+), 17 deletions(-) diff --git a/lib/report/columns.h b/lib/report/columns.h index 11d563996..07ebc4456 100644 --- a/lib/report/columns.h +++ b/lib/report/columns.h @@ -65,7 +65,8 @@ FIELD(LVS, lv, NUM, "#Seg", lvid, 4, lvsegcount, seg_count, "Number of segments FIELD(LVS, lv, STR, "Origin", lvid, 6, origin, origin, "For snapshots, the origin device of this LV.", 0) FIELD(LVS, lv, STR, "Origin UUID", lvid, 38, originuuid, origin_uuid, "For snapshots, the UUID of origin device of this LV.", 0) FIELD(LVS, lv, SIZ, "OSize", lvid, 5, originsize, origin_size, "For snapshots, the size of the origin device of this LV.", 0) -FIELD(LVS, lv, STR_LIST, "Ancestors", lvid, 12, lvancestors, lv_ancestors, "Ancestors of this LV.", 0) +FIELD(LVS, lv, STR_LIST, "Ancestors", lvid, 12, lvancestors, lv_ancestors, "LV ancestors ignoring any stored history of the ancestry chain.", 0) +FIELD(LVS, lv, STR_LIST, "FAncestors", lvid, 12, lvfullancestors, lv_full_ancestors, "LV ancestors including stored history of the ancestry chain.", 0) FIELD(LVS, lv, STR_LIST, "Descendants", lvid, 12, lvdescendants, lv_descendants, "Descendants of this LV.", 0) FIELD(LVS, lv, PCT, "Data%", lvid, 6, datapercent, data_percent, "For snapshot and thin pools and volumes, the percentage full if LV is active.", 0) FIELD(LVS, lv, PCT, "Snap%", lvid, 6, snpercent, snap_percent, "For snapshots, the percentage full if LV is active.", 0) diff --git a/lib/report/properties.c b/lib/report/properties.c index 9c1b23a2b..c879bc871 100644 --- a/lib/report/properties.c +++ b/lib/report/properties.c @@ -312,6 +312,8 @@ GET_LV_NUM_PROPERTY_FN(origin_size, (SECTOR_SIZE * lv_origin_size(lv))) #define _origin_size_set prop_not_implemented_set #define _lv_ancestors_set prop_not_implemented_set #define _lv_ancestors_get prop_not_implemented_get +#define _lv_full_ancestors_set prop_not_implemented_set +#define _lv_full_ancestors_get prop_not_implemented_get #define _lv_descendants_set prop_not_implemented_set #define _lv_descendants_get prop_not_implemented_get GET_LV_NUM_PROPERTY_FN(snap_percent, _snap_percent(lv)) diff --git a/lib/report/report.c b/lib/report/report.c index dfc76bc64..b1ba9fd0e 100644 --- a/lib/report/report.c +++ b/lib/report/report.c @@ -1929,26 +1929,52 @@ static int _originuuid_disp(struct dm_report *rh, struct dm_pool *mem, return _do_origin_disp(rh, mem, field, data, private, 1); } -static int _find_ancestors(struct _str_list_append_baton *ancestors, - struct logical_volume *lv) +static const char *_get_glv_str(char *buf, size_t buf_len, + struct generic_logical_volume *glv) { - struct logical_volume *ancestor_lv = NULL; - struct lv_segment *seg; + if (!glv->is_historical) + return glv->live->name; - if (lv_is_cow(lv)) { - ancestor_lv = origin_from_cow(lv); - } else if (lv_is_thin_volume(lv)) { - seg = first_seg(lv); - if (seg->origin) - ancestor_lv = seg->origin; - else if (seg->external_lv) - ancestor_lv = seg->external_lv; + if (dm_snprintf(buf, buf_len, "%s%s", HISTORICAL_LV_PREFIX, glv->historical->name) < 0) { + log_error("_get_glv_str: dm_snprintf failed"); + return NULL; } - if (ancestor_lv) { - if (!_str_list_append(ancestor_lv->name, ancestors)) + return buf; +} + +static int _find_ancestors(struct _str_list_append_baton *ancestors, + struct generic_logical_volume glv, + int full, int include_historical_lvs) +{ + struct lv_segment *seg; + void *orig_p = glv.live; + const char *ancestor_str; + char buf[NAME_LEN + strlen(HISTORICAL_LV_PREFIX) + 1]; + + if (glv.is_historical) { + if (full && glv.historical->indirect_origin) + glv = *glv.historical->indirect_origin; + } else if (lv_is_cow(glv.live)) { + glv.live = origin_from_cow(glv.live); + } else if (lv_is_thin_volume(glv.live)) { + seg = first_seg(glv.live); + if (seg->origin) + glv.live = seg->origin; + else if (seg->external_lv) + glv.live = seg->external_lv; + else if (full && seg->indirect_origin) + glv = *seg->indirect_origin; + } + + if (orig_p != glv.live) { + if (!(ancestor_str = _get_glv_str(buf, sizeof(buf), &glv))) return_0; - if (!_find_ancestors(ancestors, ancestor_lv)) + if (!glv.is_historical || include_historical_lvs) { + if (!_str_list_append(ancestor_str, ancestors)) + return_0; + } + if (!_find_ancestors(ancestors, glv, full, include_historical_lvs)) return_0; } @@ -1959,14 +1985,21 @@ static int _lvancestors_disp(struct dm_report *rh, struct dm_pool *mem, struct dm_report_field *field, const void *data, void *private) { + struct cmd_context *cmd = (struct cmd_context *) private; struct logical_volume *lv = (struct logical_volume *) data; struct _str_list_append_baton ancestors; + struct generic_logical_volume glv; ancestors.mem = mem; if (!(ancestors.result = str_list_create(mem))) return_0; - if (!_find_ancestors(&ancestors, lv)) { + if ((glv.is_historical = lv_is_historical(lv))) + glv.historical = lv->this_glv->historical; + else + glv.live = lv; + + if (!_find_ancestors(&ancestors, glv, 0, cmd->include_historical_lvs)) { dm_pool_free(ancestors.mem, ancestors.result); return_0; } @@ -1974,6 +2007,32 @@ static int _lvancestors_disp(struct dm_report *rh, struct dm_pool *mem, return _field_set_string_list(rh, field, ancestors.result, private, 0, NULL); } +static int _lvfullancestors_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + struct cmd_context *cmd = (struct cmd_context *) private; + struct logical_volume *lv = (struct logical_volume *) data; + struct _str_list_append_baton full_ancestors; + struct generic_logical_volume glv; + + full_ancestors.mem = mem; + if (!(full_ancestors.result = str_list_create(mem))) + return_0; + + if ((glv.is_historical = lv_is_historical(lv))) + glv.historical = lv->this_glv->historical; + else + glv.live = lv; + + if (!_find_ancestors(&full_ancestors, glv, 1, cmd->include_historical_lvs)) { + dm_pool_free(full_ancestors.mem, full_ancestors.result); + return_0; + } + + return _field_set_string_list(rh, field, full_ancestors.result, private, 0, NULL); +} + static int _find_descendants(struct _str_list_append_baton *descendants, struct logical_volume *lv) {