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

report: add new LVSSTATUS and SEGSSTATUS report type

Similar to LVSINFO type which gathers LV + its DM_DEVICE_INFO, the
new LVSSTATUS/SEGSSTATUS report type will gather LV/segment + its
DM_DEVICE_STATUS.

Since we can report status only for certain segment, in case
of LVSSTATUS we need to choose which segment related to the LV
should be processed that represents the "LV status". In case of
SEGSSTATUS type it's clear - the status is reported for the
segment just processed.
This commit is contained in:
Peter Rajnoha 2014-10-21 12:01:57 +02:00
parent d7e5f03888
commit 7f90ad84c1
3 changed files with 121 additions and 17 deletions

View File

@ -1749,9 +1749,11 @@ static const struct dm_report_object_type _report_types[] = {
{ VGS, "Volume Group", "vg_", _obj_get_vg },
{ LVS, "Logical Volume", "lv_", _obj_get_lv },
{ LVSINFO, "Logical Volume Device Info", "lv_", _obj_get_lv_with_info_and_seg_status },
{ LVSSTATUS, "Logical Volume Device Status", "lv_", _obj_get_lv_with_info_and_seg_status },
{ PVS, "Physical Volume", "pv_", _obj_get_pv },
{ LABEL, "Physical Volume Label", "pv_", _obj_get_label },
{ SEGS, "Logical Volume Segment", "seg_", _obj_get_seg },
{ SEGSSTATUS, "Logical Volume Device Segment Status", "seg_", _obj_get_lv_with_info_and_seg_status },
{ PVSEGS, "Physical Volume Segment", "pvseg_", _obj_get_pvseg },
{ 0, "", "", NULL },
};

View File

@ -23,12 +23,14 @@
typedef enum {
LVS = 1,
LVSINFO = 2,
PVS = 4,
VGS = 8,
SEGS = 16,
PVSEGS = 32,
LABEL = 64,
DEVTYPES = 128
LVSSTATUS = 4,
PVS = 8,
VGS = 16,
SEGS = 32,
SEGSSTATUS = 64,
PVSEGS = 128,
LABEL = 256,
DEVTYPES = 512
} report_type_t;
struct field;

View File

@ -56,6 +56,11 @@ static void _get_lv_info_for_report(struct cmd_context *cmd,
lvinfo->exists = 0;
}
static void _get_lv_info_with_segment_status_for_report(struct cmd_context *cmd,
struct lv_with_info_and_seg_status *lvdm)
{
}
static int _lvs_with_info_single(struct cmd_context *cmd, struct logical_volume *lv,
void *handle)
{
@ -68,6 +73,58 @@ static int _lvs_with_info_single(struct cmd_context *cmd, struct logical_volume
return ECMD_PROCESSED;
}
static void _choose_lv_segment_for_status_report(struct lv_with_info_and_seg_status *lvdm)
{
/*
* By default, take the first LV segment to report status for.
* If there's any other specific segment that needs to be
* reported instead for the LV, choose it here and assign it
* to lvdm->seg_status->seg. This is the segment whose
* status line will be used for report exactly.
*/
lvdm->seg_status->seg = first_seg(lvdm->lv);
}
static int _lvs_with_status_single(struct cmd_context *cmd, struct logical_volume *lv,
void *handle)
{
struct lvinfo lvinfo;
struct lv_seg_status lv_seg_status = { .mem = lv->vg->vgmem,
.type = SEG_STATUS_NONE,
.status = NULL };
struct lv_with_info_and_seg_status lvdm = { .lv = lv,
.seg_status = &lv_seg_status };
int r = ECMD_FAILED;
_choose_lv_segment_for_status_report(&lvdm);
if (lvdm.seg_status->seg->lv != lv) {
/*
* If the info is requested on one LV and segment
* status on another LV, we need to call these separately.
*/
_get_lv_info_for_report(cmd, lv, &lvinfo);
lvdm.info = NULL;
_get_lv_info_with_segment_status_for_report(cmd, &lvdm);
} else {
/*
* If the info is requested on the same LV as status,
* we can get info and status in one go!
*/
lvdm.info = &lvinfo;
_get_lv_info_with_segment_status_for_report(cmd, &lvdm);
}
if (!report_object(handle, lv->vg, lv, NULL, NULL, NULL, &lvinfo, lvdm.seg_status, NULL))
goto out;
r = ECMD_PROCESSED;
out:
if (lvdm.seg_status->status)
dm_pool_free(lvdm.seg_status->mem, lvdm.seg_status->status);
return r;
}
static int _segs_single(struct cmd_context *cmd __attribute__((unused)),
struct lv_segment *seg, void *handle)
{
@ -89,6 +146,30 @@ static int _segs_with_lv_info_single(struct cmd_context *cmd __attribute__((unus
return ECMD_PROCESSED;
}
static int _segs_with_lv_status_single(struct cmd_context *cmd __attribute__((unused)),
struct lv_segment *seg, void *handle)
{
struct lvinfo lvinfo;
struct lv_seg_status lv_seg_status = { .seg = seg,
.mem = seg->lv->vg->vgmem,
.type = SEG_STATUS_NONE,
.status = NULL };
struct lv_with_info_and_seg_status lvdm = { .lv = seg->lv,
.info = &lvinfo,
.seg_status = &lv_seg_status };
int r = ECMD_FAILED;
_get_lv_info_with_segment_status_for_report(cmd, &lvdm);
if (!report_object(handle, seg->lv->vg, seg->lv, NULL, seg, NULL, lvdm.info, lvdm.seg_status, NULL))
goto_out;
r = ECMD_PROCESSED;
out:
if (lvdm.seg_status->status)
dm_pool_free(lvdm.seg_status->mem, lvdm.seg_status->status);
return r;
}
static int _do_pvsegs_sub_single(struct cmd_context *cmd,
struct volume_group *vg,
struct pv_segment *pvseg,
@ -182,6 +263,16 @@ static int _lvsegs_with_lv_info_single(struct cmd_context *cmd,
return process_each_segment_in_lv(cmd, lv, handle, _segs_with_lv_info_single);
}
static int _lvsegs_with_lv_status_single(struct cmd_context *cmd,
struct logical_volume *lv,
void *handle)
{
if (!arg_count(cmd, all_ARG) && !lv_is_visible(lv))
return ECMD_PROCESSED;
return process_each_segment_in_lv(cmd, lv, handle, _segs_with_lv_status_single);
}
static int _pvsegs_single(struct cmd_context *cmd, struct volume_group *vg,
struct physical_volume *pv, void *handle)
{
@ -254,7 +345,7 @@ static int _report(struct cmd_context *cmd, int argc, char **argv,
int r = ECMD_PROCESSED;
int aligned, buffered, headings, field_prefixes, quoted;
int columns_as_rows;
unsigned args_are_pvs, lv_info_needed;
unsigned args_are_pvs, lv_info_needed, lv_segment_status_needed;
int lock_global = 0;
aligned = find_config_tree_bool(cmd, report_aligned_CFG, NULL);
@ -373,15 +464,18 @@ static int _report(struct cmd_context *cmd, int argc, char **argv,
columns_as_rows, selection)))
return_ECMD_FAILED;
/* Do we need lv_info to be called for LV device status? */
/* Do we need to acquire LV device info in addition? */
lv_info_needed = (report_type & LVSINFO) ? 1 : 0;
/* Do we need to acquire LV device status in addition? */
lv_segment_status_needed = (report_type & (SEGSSTATUS | LVSSTATUS)) ? 1 : 0;
/* Ensure options selected are compatible */
if (report_type & SEGS)
if (report_type & (SEGS | SEGSSTATUS))
report_type |= LVS;
if (report_type & PVSEGS)
report_type |= PVS;
if ((report_type & (LVS | LVSINFO)) && (report_type & (PVS | LABEL)) && !args_are_pvs) {
if ((report_type & (LVS | LVSINFO | LVSSTATUS)) && (report_type & (PVS | LABEL)) && !args_are_pvs) {
log_error("Can't report LV and PV fields at the same time");
dm_report_free(report_handle);
return ECMD_FAILED;
@ -389,15 +483,15 @@ static int _report(struct cmd_context *cmd, int argc, char **argv,
/* Change report type if fields specified makes this necessary */
if ((report_type & PVSEGS) ||
((report_type & (PVS | LABEL)) && (report_type & (LVS | LVSINFO))))
((report_type & (PVS | LABEL)) && (report_type & (LVS | LVSINFO | LVSSTATUS))))
report_type = PVSEGS;
else if ((report_type & LABEL) && (report_type & VGS))
report_type = PVS;
else if (report_type & PVS)
report_type = PVS;
else if (report_type & SEGS)
else if (report_type & (SEGS | SEGSSTATUS))
report_type = SEGS;
else if (report_type & (LVS | LVSINFO))
else if (report_type & (LVS | LVSINFO | LVSSTATUS))
report_type = LVS;
/*
@ -419,10 +513,13 @@ static int _report(struct cmd_context *cmd, int argc, char **argv,
break;
case LVSINFO:
/* fall through */
case LVSSTATUS:
/* fall through */
case LVS:
r = process_each_lv(cmd, argc, argv, 0, report_handle,
lv_info_needed ? &_lvs_with_info_single
: &_lvs_single);
lv_segment_status_needed ? &_lvs_with_status_single
: lv_info_needed ? &_lvs_with_info_single
: &_lvs_single);
break;
case VGS:
r = process_each_vg(cmd, argc, argv, 0,
@ -440,10 +537,13 @@ static int _report(struct cmd_context *cmd, int argc, char **argv,
r = process_each_vg(cmd, argc, argv, 0,
report_handle, &_pvs_in_vg);
break;
case SEGSSTATUS:
/* fall through */
case SEGS:
r = process_each_lv(cmd, argc, argv, 0, report_handle,
lv_info_needed ? &_lvsegs_with_lv_info_single
: &_lvsegs_single);
lv_segment_status_needed ? &_lvsegs_with_lv_status_single
:lv_info_needed ? &_lvsegs_with_lv_info_single
: &_lvsegs_single);
break;
case PVSEGS:
if (args_are_pvs)