1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

report: add lv_ancestors and lv_descendants reporting fields

Show full chain of ancestors and descendants for snapshots
(both thick and thin - in case of thick, the "ancestor" field
is actually equal to "origin" field as snapshots can't be
chained for thick snapshots).

These fields display current state as it is, they do not
display any history! If the snapshot chain is broken in
the middle, we don't report the historical origin (this
is going to be a part of another patch and a different
set of fields or just a switch for existing fields to
show ancestors and descendants with history included).

For example:

(origin --> snapshot)

lvol1 --> lvol2 --> lvol3 --> lvol4
              \
                --> lvol5 --> lvol6 --> lvol7 --> lvol8

$ lvs -o name,pool_lv,origin,ancestors,descendants vg
  LV    Pool Origin Ancestors                     Descendants
  lvol1 pool                                      lvol2,lvol3,lvol4,lvol5,lvol6,lvol7,lvol8
  lvol2 pool lvol1  lvol1                         lvol3,lvol4,lvol5,lvol6,lvol7,lvol8
  lvol3 pool lvol2  lvol2,lvol1                   lvol4
  lvol4 pool lvol3  lvol3,lvol2,lvol1
  lvol5 pool lvol2  lvol2,lvol1                   lvol6,lvol7,lvol8
  lvol6 pool lvol5  lvol5,lvol2,lvol1             lvol7,lvol8
  lvol7 pool lvol6  lvol6,lvol5,lvol2,lvol1       lvol8
  lvol8 pool lvol7  lvol7,lvol6,lvol5,lvol2,lvol1
This commit is contained in:
Peter Rajnoha 2015-04-24 11:51:52 +02:00
parent 82f6dbfaf7
commit 6e4aee0492
4 changed files with 107 additions and 0 deletions

View File

@ -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.

View File

@ -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)

View File

@ -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))

View File

@ -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)))