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, "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, STR_LIST, "Descendants", lvid, 12, lvdescendants, lv_descendants, "LV descendants ignoring any stored history of the ancestry chain.", 0)
+FIELD(LVS, lv, STR_LIST, "FDescendants", lvid, 12, lvfulldescendants, lv_full_descendants, "LV descendants including stored history of the ancestry chain.", 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)
FIELD(LVS, lv, PCT, "Meta%", lvid, 6, metadatapercent, metadata_percent, "For thin pools, the percentage of metadata full if LV is active.", 0)
}
static int _find_descendants(struct _str_list_append_baton *descendants,
- struct logical_volume *lv)
+ struct generic_logical_volume glv,
+ int full, int include_historical_lvs)
{
- struct logical_volume *descendant_lv = NULL;
+ struct generic_logical_volume glv_next = {0};
const struct seg_list *sl;
struct lv_segment *seg;
+ struct glv_list *glvl;
+ struct dm_list *list;
+ const char *descendant_str;
+ char buf[64];
- if (lv_is_origin(lv)) {
- dm_list_iterate_items_gen(seg, &lv->snapshot_segs, origin_list) {
- if ((descendant_lv = seg->cow)) {
- if (!_str_list_append(descendant_lv->name, descendants))
+ if (glv.is_historical) {
+ if (full) {
+ list = &glv.historical->indirect_glvs;
+ dm_list_iterate_items(glvl, list) {
+ if (!glvl->glv->is_historical || include_historical_lvs) {
+ if (!(descendant_str = _get_glv_str(buf, sizeof(buf), glvl->glv)))
+ return_0;
+ if (!_str_list_append(descendant_str, descendants))
+ return_0;
+ }
+ if (!_find_descendants(descendants, *glvl->glv, full, include_historical_lvs))
+ return_0;
+ }
+ }
+ } else if (lv_is_origin(glv.live)) {
+ list = &glv.live->snapshot_segs;
+ dm_list_iterate_items_gen(seg, list, origin_list) {
+ if ((glv.live = seg->cow)) {
+ if (!(descendant_str = _get_glv_str(buf, sizeof(buf), &glv)))
return_0;
- if (!_find_descendants(descendants, descendant_lv))
+ if (!_str_list_append(descendant_str, descendants))
+ return_0;
+ if (!_find_descendants(descendants, glv, full, include_historical_lvs))
return_0;
}
}
} else {
- dm_list_iterate_items(sl, &lv->segs_using_this_lv) {
+ list = &glv.live->segs_using_this_lv;
+ dm_list_iterate_items(sl, list) {
if (lv_is_thin_volume(sl->seg->lv)) {
seg = first_seg(sl->seg->lv);
- if ((seg->origin == lv) || (seg->external_lv == lv))
- descendant_lv = sl->seg->lv;
+ if ((seg->origin == glv.live) || (seg->external_lv == glv.live)) {
+ glv_next.live = sl->seg->lv;
+ if (!(descendant_str = _get_glv_str(buf, sizeof(buf), &glv_next)))
+ return_0;
+ if (!_str_list_append(descendant_str, descendants))
+ return_0;
+ if (!_find_descendants(descendants, glv_next, full, include_historical_lvs))
+ return_0;
+ }
}
+ }
- if (descendant_lv) {
- if (!_str_list_append(descendant_lv->name, descendants))
- return_0;
- if (!_find_descendants(descendants, descendant_lv))
+ if (full) {
+ list = &glv.live->indirect_glvs;
+ dm_list_iterate_items(glvl, list) {
+ if (!glvl->glv->is_historical || include_historical_lvs) {
+ if (!(descendant_str = _get_glv_str(buf, sizeof(buf), glvl->glv)))
+ return_0;
+ if (!_str_list_append(descendant_str, descendants))
+ return_0;
+ }
+ if (!_find_descendants(descendants, *glvl->glv, full, include_historical_lvs))
return_0;
}
}
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 descendants;
+ struct generic_logical_volume glv;
descendants.mem = mem;
if (!(descendants.result = str_list_create(mem)))
return_0;
- if (!_find_descendants(&descendants, lv)) {
+ if ((glv.is_historical = lv_is_historical(lv)))
+ glv.historical = lv->this_glv->historical;
+ else
+ glv.live = lv;
+
+ if (!_find_descendants(&descendants, glv, 0, cmd->include_historical_lvs)) {
+ dm_pool_free(descendants.mem, descendants.result);
+ return_0;
+ }
+
+ return _field_set_string_list(rh, field, descendants.result, private, 0, NULL);
+}
+
+static int _lvfulldescendants_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 descendants;
+ struct generic_logical_volume glv;
+
+ descendants.mem = mem;
+ if (!(descendants.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_descendants(&descendants, glv, 1, cmd->include_historical_lvs)) {
dm_pool_free(descendants.mem, descendants.result);
return_0;
}