diff --git a/WHATS_NEW b/WHATS_NEW index 23c70eb4b..ca5ee0f3e 100644 --- a/WHATS_NEW +++ b/WHATS_NEW @@ -1,5 +1,6 @@ Version 2.02.119 - ================================== + Add lv_ancestors and lv_descendants reporting fields. Add --ignorelocal option to dumpconfig to ignore the local section. Close connection to lvmetad after fork. Make lvchange able to resume background pvmove polling again. diff --git a/lib/report/columns.h b/lib/report/columns.h index 6fde503f5..8da8db198 100644 --- a/lib/report/columns.h +++ b/lib/report/columns.h @@ -64,6 +64,8 @@ FIELD(LVS, lv, SIZ, "MSize", lvid, 6, lvmetadatasize, lv_metadata_size, "For thi FIELD(LVS, lv, NUM, "#Seg", lvid, 4, lvsegcount, seg_count, "Number of segments in LV.", 0) FIELD(LVS, lv, STR, "Origin", lvid, 6, origin, origin, "For snapshots, the 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, ancestors, ancestors, "Ancestors of this LV.", 0) +FIELD(LVS, lv, STR_LIST, "Descendants", lvid, 12, descendants, 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) FIELD(LVS, lv, PCT, "Meta%", lvid, 6, metadatapercent, metadata_percent, "For thin pools, the percentage of metadata full if LV is active.", 0) diff --git a/lib/report/properties.c b/lib/report/properties.c index 4c1f6f5cc..45ca0c759 100644 --- a/lib/report/properties.c +++ b/lib/report/properties.c @@ -300,6 +300,10 @@ GET_LV_STR_PROPERTY_FN(origin, lv_origin_dup(lv->vg->vgmem, lv)) #define _origin_set prop_not_implemented_set GET_LV_NUM_PROPERTY_FN(origin_size, (SECTOR_SIZE * lv_origin_size(lv))) #define _origin_size_set prop_not_implemented_set +#define _ancestors_set prop_not_implemented_set +#define _ancestors_get prop_not_implemented_get +#define _descendants_set prop_not_implemented_set +#define _descendants_get prop_not_implemented_get GET_LV_NUM_PROPERTY_FN(snap_percent, _snap_percent(lv)) #define _snap_percent_set prop_not_implemented_set GET_LV_NUM_PROPERTY_FN(copy_percent, _copy_percent(lv)) diff --git a/lib/report/report.c b/lib/report/report.c index c29acdb82..73beda32f 100644 --- a/lib/report/report.c +++ b/lib/report/report.c @@ -633,6 +633,106 @@ static int _origin_disp(struct dm_report *rh, struct dm_pool *mem, return _field_set_value(field, "", NULL); } +static int _find_ancestors(struct _str_list_append_baton *ancestors, + struct logical_volume *lv) +{ + struct logical_volume *ancestor_lv = NULL; + struct lv_segment *seg; + + 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 (ancestor_lv) { + if (!_str_list_append(ancestor_lv->name, ancestors)) + return_0; + if (!_find_ancestors(ancestors, ancestor_lv)) + return_0; + } + + return 1; +} + +static int _ancestors_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + struct logical_volume *lv = (struct logical_volume *) data; + struct _str_list_append_baton ancestors; + + ancestors.mem = mem; + if (!(ancestors.result = str_list_create(mem))) + return_0; + + if (!_find_ancestors(&ancestors, lv)) { + dm_pool_free(ancestors.mem, ancestors.result); + return_0; + } + + return _field_set_string_list(rh, field, ancestors.result, private, 0); +} + +static int _find_descendants(struct _str_list_append_baton *descendants, + struct logical_volume *lv) +{ + struct logical_volume *descendant_lv = NULL; + const struct seg_list *sl; + struct lv_segment *seg; + + 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)) + return_0; + if (!_find_descendants(descendants, descendant_lv)) + return_0; + } + } + } else { + dm_list_iterate_items(sl, &lv->segs_using_this_lv) { + 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 (descendant_lv) { + if (!_str_list_append(descendant_lv->name, descendants)) + return_0; + if (!_find_descendants(descendants, descendant_lv)) + return_0; + } + } + } + + return 1; +} + +static int _descendants_disp(struct dm_report *rh, struct dm_pool *mem, + struct dm_report_field *field, + const void *data, void *private) +{ + struct logical_volume *lv = (struct logical_volume *) data; + struct _str_list_append_baton descendants; + + descendants.mem = mem; + if (!(descendants.result = str_list_create(mem))) + return_0; + + if (!_find_descendants(&descendants, lv)) { + dm_pool_free(descendants.mem, descendants.result); + return_0; + } + + return _field_set_string_list(rh, field, descendants.result, private, 0); +} + static int _movepv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)), struct dm_report_field *field, const void *data, void *private __attribute__((unused)))