1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-01-03 05:18:29 +03:00
lvm2/tools/reporter.c

676 lines
19 KiB
C
Raw Normal View History

/*
2008-01-30 17:00:02 +03:00
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
*
2004-03-30 23:35:44 +04:00
* This file is part of LVM2.
*
2004-03-30 23:35:44 +04:00
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
2004-03-30 23:35:44 +04:00
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "tools.h"
#include "report.h"
static int _process_each_devtype(struct cmd_context *cmd, int argc, void *handle)
{
if (argc)
log_warn("WARNING: devtypes currently ignores command line arguments.");
if (!report_devtypes(handle))
return_ECMD_FAILED;
return ECMD_PROCESSED;
}
static int _vgs_single(struct cmd_context *cmd __attribute__((unused)),
const char *vg_name, struct volume_group *vg,
void *handle)
{
if (!report_object(handle, vg, NULL, NULL, NULL, NULL, NULL, NULL))
return_ECMD_FAILED;
check_current_backup(vg);
2003-10-22 02:06:07 +04:00
return ECMD_PROCESSED;
}
static void _choose_lv_segment_for_status_report(const struct logical_volume *lv, const struct lv_segment **lv_seg)
{
/*
* 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.
*/
*lv_seg = first_seg(lv);
}
static int _do_info_and_status(struct cmd_context *cmd,
const struct logical_volume *lv,
const struct lv_segment *lv_seg,
struct lv_with_info_and_seg_status *status,
int do_info, int do_status)
{
unsigned use_layer = lv_is_thin_pool(lv) ? 1 : 0;
status->lv = lv;
if (do_status) {
if (!(status->seg_status.mem = dm_pool_create("reporter_pool", 1024)))
return_0;
if (!lv_seg)
_choose_lv_segment_for_status_report(lv, &lv_seg);
if (do_info) {
/* both info and status */
status->info_ok = lv_info_with_seg_status(cmd, lv, lv_seg, use_layer, status, 1, 1);
/* for inactive thin-pools reset lv info struct */
if (use_layer && status->info_ok &&
!lv_info(cmd, lv, 0, NULL, 0, 0))
memset(&status->info, 0, sizeof(status->info));
} else
/* status only */
status->info_ok = lv_status(cmd, lv_seg, use_layer, &status->seg_status);
} else if (do_info)
/* info only */
status->info_ok = lv_info(cmd, lv, use_layer, &status->info, 1, 1);
return 1;
}
static int _do_lvs_with_info_and_status_single(struct cmd_context *cmd,
const struct logical_volume *lv,
int do_info, int do_status,
void *handle)
{
struct lv_with_info_and_seg_status status = {
.seg_status.type = SEG_STATUS_NONE
};
int r = ECMD_FAILED;
if (!_do_info_and_status(cmd, lv, NULL, &status, do_info, do_status)) {
stack;
return r;
}
if (!report_object(handle, lv->vg, lv, NULL, NULL, NULL,
&status, NULL))
goto_out;
r = ECMD_PROCESSED;
out:
if (status.seg_status.mem)
dm_pool_destroy(status.seg_status.mem);
return r;
}
static int _lvs_single(struct cmd_context *cmd, struct logical_volume *lv,
void *handle)
{
return _do_lvs_with_info_and_status_single(cmd, lv, 0, 0, handle);
}
static int _lvs_with_info_single(struct cmd_context *cmd, struct logical_volume *lv,
void *handle)
{
return _do_lvs_with_info_and_status_single(cmd, lv, 1, 0, handle);
}
static int _lvs_with_status_single(struct cmd_context *cmd, struct logical_volume *lv,
void *handle)
{
return _do_lvs_with_info_and_status_single(cmd, lv, 0, 1, handle);
}
static int _lvs_with_info_and_status_single(struct cmd_context *cmd, struct logical_volume *lv,
void *handle)
{
return _do_lvs_with_info_and_status_single(cmd, lv, 1, 1, handle);
}
static int _do_segs_with_info_and_status_single(struct cmd_context *cmd,
const struct lv_segment *seg,
int do_info, int do_status,
void *handle)
{
struct lv_with_info_and_seg_status status = {
.seg_status.type = SEG_STATUS_NONE
};
int r = ECMD_FAILED;
if (!_do_info_and_status(cmd, seg->lv, seg, &status, do_info, do_status)) {
stack;
return r;
}
if (!report_object(handle, seg->lv->vg, seg->lv, NULL, seg, NULL,
&status, NULL))
goto_out;
r = ECMD_PROCESSED;
out:
if (status.seg_status.mem)
dm_pool_destroy(status.seg_status.mem);
return r;
}
static int _segs_single(struct cmd_context *cmd, struct lv_segment *seg,
void *handle)
{
return _do_segs_with_info_and_status_single(cmd, seg, 0, 0, handle);
}
static int _segs_with_info_single(struct cmd_context *cmd, struct lv_segment *seg,
void *handle)
{
return _do_segs_with_info_and_status_single(cmd, seg, 1, 0, handle);
}
static int _segs_with_status_single(struct cmd_context *cmd, struct lv_segment *seg,
void *handle)
{
return _do_segs_with_info_and_status_single(cmd, seg, 0, 1, handle);
}
static int _segs_with_info_and_status_single(struct cmd_context *cmd, struct lv_segment *seg,
void *handle)
{
return _do_segs_with_info_and_status_single(cmd, seg, 1, 1, handle);
}
static int _lvsegs_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_single);
}
static int _lvsegs_with_info_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_info_single);
}
static int _lvsegs_with_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_status_single);
}
static int _lvsegs_with_info_and_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_info_and_status_single);
}
static int _do_pvsegs_sub_single(struct cmd_context *cmd,
struct volume_group *vg,
struct pv_segment *pvseg,
int do_info,
int do_status,
void *handle)
2005-04-20 00:58:25 +04:00
{
int ret = ECMD_PROCESSED;
struct lv_segment *seg = pvseg->lvseg;
struct segment_type _freeseg_type = {
.name = "free",
.flags = SEG_VIRTUAL | SEG_CANNOT_BE_ZEROED,
};
2005-04-20 00:58:25 +04:00
struct volume_group _free_vg = {
.cmd = cmd,
.name = "",
.pvs = DM_LIST_HEAD_INIT(_free_vg.pvs),
.lvs = DM_LIST_HEAD_INIT(_free_vg.lvs),
.tags = DM_LIST_HEAD_INIT(_free_vg.tags),
};
struct logical_volume _free_logical_volume = {
.vg = vg ?: &_free_vg,
.name = "",
.status = VISIBLE_LV,
.major = -1,
.minor = -1,
.tags = DM_LIST_HEAD_INIT(_free_logical_volume.tags),
.segments = DM_LIST_HEAD_INIT(_free_logical_volume.segments),
.segs_using_this_lv = DM_LIST_HEAD_INIT(_free_logical_volume.segs_using_this_lv),
.snapshot_segs = DM_LIST_HEAD_INIT(_free_logical_volume.snapshot_segs),
};
struct lv_segment _free_lv_segment = {
.lv = &_free_logical_volume,
.segtype = &_freeseg_type,
.len = pvseg->len,
.tags = DM_LIST_HEAD_INIT(_free_lv_segment.tags),
.origin_list = DM_LIST_HEAD_INIT(_free_lv_segment.origin_list),
};
struct lv_with_info_and_seg_status status = {
.seg_status.type = SEG_STATUS_NONE,
.lv = &_free_logical_volume
};
if (seg)
_do_info_and_status(cmd, seg->lv, seg, &status, do_info, do_status);
if (!report_object(handle, vg, seg ? seg->lv : &_free_logical_volume, pvseg->pv,
seg ? : &_free_lv_segment, pvseg, &status,
refactor: rename struct lv_with_info used in reporting code to lv_with_info_and_seg_status The former struct lv_with_info is renamed to lv_with_info_and_seg_status as it can hold more than just "info", there's lv's segment status now in addition: struct lv_with_info_and_seg_status { struct logical_volume *lv; struct lvinfo *info; struct lv_seg_status *seg_status; } Where struct lv_seg_status is: struct lv_seg_status { struct dm_pool *mem; struct lv_segment lv_seg; lv_seg_status_type_t type; void *status; /* struct dm_status_* */ } Where lv_seg points to lv's segment that is being reported or processed in general. New struct lv_seg_status keeps the information about segment status - the status retrieved via DM_DEVICE_STATUS ioctl. This information will be used for reporting dm device target status for the LV segment specified. So this patch introduces third level of LV information that is kept for reuse while reporting fields within one reporting line, causing only one DM_DEVICE_STATUS ioctl call per LV segment line reported (otherwise we'd need to call the DM_DEVICE_STATUS for each segment status field in one LV segment/reporting line which is not efficient). This is following exactly the same principle as already introduced by commit ecb2be5d1642aa0142d216f9e52f64fd3e8c3fc8. So currently we have three levels of information that can be used to report an LV/LV segment: - LV metadata itself (struct logical_volume *lv) - LV's DM_DEVICE_INFO ioctl result (struct lvinfo *info) - LV's segment DM_DEVICE_STATUS ioctl result (this status must be bound to a segment, not the whole LV as the whole LV may be composed of several segments of course) (this is the new struct lv_seg_status *seg_status)
2014-10-20 15:46:50 +04:00
pv_label(pvseg->pv))) {
ret = ECMD_FAILED;
goto_out;
}
out:
if (status.seg_status.mem)
dm_pool_destroy(status.seg_status.mem);
2005-04-20 00:58:25 +04:00
return ret;
}
static int _pvsegs_sub_single(struct cmd_context *cmd,
struct volume_group *vg,
struct pv_segment *pvseg,
void *handle)
{
refactor: rename struct lv_with_info used in reporting code to lv_with_info_and_seg_status The former struct lv_with_info is renamed to lv_with_info_and_seg_status as it can hold more than just "info", there's lv's segment status now in addition: struct lv_with_info_and_seg_status { struct logical_volume *lv; struct lvinfo *info; struct lv_seg_status *seg_status; } Where struct lv_seg_status is: struct lv_seg_status { struct dm_pool *mem; struct lv_segment lv_seg; lv_seg_status_type_t type; void *status; /* struct dm_status_* */ } Where lv_seg points to lv's segment that is being reported or processed in general. New struct lv_seg_status keeps the information about segment status - the status retrieved via DM_DEVICE_STATUS ioctl. This information will be used for reporting dm device target status for the LV segment specified. So this patch introduces third level of LV information that is kept for reuse while reporting fields within one reporting line, causing only one DM_DEVICE_STATUS ioctl call per LV segment line reported (otherwise we'd need to call the DM_DEVICE_STATUS for each segment status field in one LV segment/reporting line which is not efficient). This is following exactly the same principle as already introduced by commit ecb2be5d1642aa0142d216f9e52f64fd3e8c3fc8. So currently we have three levels of information that can be used to report an LV/LV segment: - LV metadata itself (struct logical_volume *lv) - LV's DM_DEVICE_INFO ioctl result (struct lvinfo *info) - LV's segment DM_DEVICE_STATUS ioctl result (this status must be bound to a segment, not the whole LV as the whole LV may be composed of several segments of course) (this is the new struct lv_seg_status *seg_status)
2014-10-20 15:46:50 +04:00
return _do_pvsegs_sub_single(cmd, vg, pvseg, 0, 0, handle);
}
static int _pvsegs_with_lv_info_sub_single(struct cmd_context *cmd,
struct volume_group *vg,
struct pv_segment *pvseg,
void *handle)
{
refactor: rename struct lv_with_info used in reporting code to lv_with_info_and_seg_status The former struct lv_with_info is renamed to lv_with_info_and_seg_status as it can hold more than just "info", there's lv's segment status now in addition: struct lv_with_info_and_seg_status { struct logical_volume *lv; struct lvinfo *info; struct lv_seg_status *seg_status; } Where struct lv_seg_status is: struct lv_seg_status { struct dm_pool *mem; struct lv_segment lv_seg; lv_seg_status_type_t type; void *status; /* struct dm_status_* */ } Where lv_seg points to lv's segment that is being reported or processed in general. New struct lv_seg_status keeps the information about segment status - the status retrieved via DM_DEVICE_STATUS ioctl. This information will be used for reporting dm device target status for the LV segment specified. So this patch introduces third level of LV information that is kept for reuse while reporting fields within one reporting line, causing only one DM_DEVICE_STATUS ioctl call per LV segment line reported (otherwise we'd need to call the DM_DEVICE_STATUS for each segment status field in one LV segment/reporting line which is not efficient). This is following exactly the same principle as already introduced by commit ecb2be5d1642aa0142d216f9e52f64fd3e8c3fc8. So currently we have three levels of information that can be used to report an LV/LV segment: - LV metadata itself (struct logical_volume *lv) - LV's DM_DEVICE_INFO ioctl result (struct lvinfo *info) - LV's segment DM_DEVICE_STATUS ioctl result (this status must be bound to a segment, not the whole LV as the whole LV may be composed of several segments of course) (this is the new struct lv_seg_status *seg_status)
2014-10-20 15:46:50 +04:00
return _do_pvsegs_sub_single(cmd, vg, pvseg, 1, 0, handle);
}
static int _pvsegs_with_lv_status_sub_single(struct cmd_context *cmd,
struct volume_group *vg,
struct pv_segment *pvseg,
void *handle)
{
return _do_pvsegs_sub_single(cmd, vg, pvseg, 0, 1, handle);
}
static int _pvsegs_with_lv_info_and_status_sub_single(struct cmd_context *cmd,
struct volume_group *vg,
struct pv_segment *pvseg,
void *handle)
{
return _do_pvsegs_sub_single(cmd, vg, pvseg, 1, 1, handle);
}
static int _pvsegs_single(struct cmd_context *cmd,
struct volume_group *vg,
struct physical_volume *pv,
void *handle)
2005-04-20 00:58:25 +04:00
{
return process_each_segment_in_pv(cmd, vg, pv, handle, _pvsegs_sub_single);
2005-04-20 00:58:25 +04:00
}
static int _pvsegs_with_lv_info_single(struct cmd_context *cmd,
struct volume_group *vg,
struct physical_volume *pv,
void *handle)
{
return process_each_segment_in_pv(cmd, vg, pv, handle, _pvsegs_with_lv_info_sub_single);
}
static int _pvsegs_with_lv_status_single(struct cmd_context *cmd,
struct volume_group *vg,
struct physical_volume *pv,
void *handle)
{
return process_each_segment_in_pv(cmd, vg, pv, handle, _pvsegs_with_lv_status_sub_single);
}
static int _pvsegs_with_lv_info_and_status_single(struct cmd_context *cmd,
struct volume_group *vg,
struct physical_volume *pv,
void *handle)
{
return process_each_segment_in_pv(cmd, vg, pv, handle, _pvsegs_with_lv_info_and_status_sub_single);
}
static int _pvs_single(struct cmd_context *cmd, struct volume_group *vg,
struct physical_volume *pv, void *handle)
{
if (!report_object(handle, vg, NULL, pv, NULL, NULL, NULL, NULL))
return_ECMD_FAILED;
return ECMD_PROCESSED;
}
static int _label_single(struct cmd_context *cmd, struct label *label,
void *handle)
{
if (!report_object(handle, NULL, NULL, NULL, NULL, NULL, NULL, label))
return_ECMD_FAILED;
return ECMD_PROCESSED;
}
static int _pvs_in_vg(struct cmd_context *cmd, const char *vg_name,
struct volume_group *vg,
void *handle)
{
int skip;
if (ignore_vg(vg, vg_name, 0, &skip))
return_ECMD_FAILED;
if (skip)
return ECMD_PROCESSED;
return process_each_pv_in_vg(cmd, vg, handle, &_pvs_single);
}
2007-01-27 05:32:31 +03:00
static int _pvsegs_in_vg(struct cmd_context *cmd, const char *vg_name,
struct volume_group *vg,
2007-01-27 05:32:31 +03:00
void *handle)
{
int skip;
if (ignore_vg(vg, vg_name, 0, &skip))
return_ECMD_FAILED;
if (skip)
return ECMD_PROCESSED;
return process_each_pv_in_vg(cmd, vg, handle, &_pvsegs_single);
2007-01-27 05:32:31 +03:00
}
static int _report(struct cmd_context *cmd, int argc, char **argv,
report_type_t report_type)
{
void *report_handle;
const char *opts;
char *str;
const char *keys = NULL, *options = NULL, *selection = NULL, *separator;
2003-10-22 02:06:07 +04:00
int r = ECMD_PROCESSED;
2008-06-25 01:21:04 +04:00
int aligned, buffered, headings, field_prefixes, quoted;
2008-06-25 02:48:53 +04:00
int columns_as_rows;
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);
buffered = find_config_tree_bool(cmd, report_buffered_CFG, NULL);
headings = find_config_tree_bool(cmd, report_headings_CFG, NULL);
separator = find_config_tree_str(cmd, report_separator_CFG, NULL);
field_prefixes = find_config_tree_bool(cmd, report_prefixes_CFG, NULL);
quoted = find_config_tree_bool(cmd, report_quoted_CFG, NULL);
columns_as_rows = find_config_tree_bool(cmd, report_colums_as_rows_CFG, NULL);
args_are_pvs = (report_type == PVS ||
report_type == LABEL ||
report_type == PVSEGS) ? 1 : 0;
/*
* FIXME Trigger scans based on unrecognised listed devices instead.
*/
if (args_are_pvs && argc)
cmd->filter->wipe(cmd->filter);
switch (report_type) {
case DEVTYPES:
keys = find_config_tree_str(cmd, report_devtypes_sort_CFG, NULL);
if (!arg_count(cmd, verbose_ARG))
options = find_config_tree_str(cmd, report_devtypes_cols_CFG, NULL);
else
options = find_config_tree_str(cmd, report_devtypes_cols_verbose_CFG, NULL);
break;
case LVS:
keys = find_config_tree_str(cmd, report_lvs_sort_CFG, NULL);
if (!arg_count(cmd, verbose_ARG))
options = find_config_tree_str(cmd, report_lvs_cols_CFG, NULL);
else
options = find_config_tree_str(cmd, report_lvs_cols_verbose_CFG, NULL);
break;
case VGS:
keys = find_config_tree_str(cmd, report_vgs_sort_CFG, NULL);
if (!arg_count(cmd, verbose_ARG))
options = find_config_tree_str(cmd, report_vgs_cols_CFG, NULL);
else
options = find_config_tree_str(cmd, report_vgs_cols_verbose_CFG, NULL);
break;
case LABEL:
case PVS:
keys = find_config_tree_str(cmd, report_pvs_sort_CFG, NULL);
if (!arg_count(cmd, verbose_ARG))
options = find_config_tree_str(cmd, report_pvs_cols_CFG, NULL);
else
options = find_config_tree_str(cmd, report_pvs_cols_verbose_CFG, NULL);
break;
case SEGS:
keys = find_config_tree_str(cmd, report_segs_sort_CFG, NULL);
if (!arg_count(cmd, verbose_ARG))
options = find_config_tree_str(cmd, report_segs_cols_CFG, NULL);
else
options = find_config_tree_str(cmd, report_segs_cols_verbose_CFG, NULL);
break;
2005-04-20 00:58:25 +04:00
case PVSEGS:
keys = find_config_tree_str(cmd, report_pvsegs_sort_CFG, NULL);
2005-04-20 00:58:25 +04:00
if (!arg_count(cmd, verbose_ARG))
options = find_config_tree_str(cmd, report_pvsegs_cols_CFG, NULL);
2005-04-20 00:58:25 +04:00
else
options = find_config_tree_str(cmd, report_pvsegs_cols_verbose_CFG, NULL);
2005-04-20 00:58:25 +04:00
break;
default:
log_error(INTERNAL_ERROR "Unknown report type.");
return ECMD_FAILED;
}
/* If -o supplied use it, else use default for report_type */
if (arg_count(cmd, options_ARG)) {
opts = arg_str_value(cmd, options_ARG, "");
if (!opts || !*opts) {
log_error("Invalid options string: %s", opts);
return EINVALID_CMD_LINE;
}
if (*opts == '+') {
2006-05-10 21:49:25 +04:00
if (!(str = dm_pool_alloc(cmd->mem,
strlen(options) + strlen(opts) + 1))) {
log_error("options string allocation failed");
return ECMD_FAILED;
2006-05-10 21:49:25 +04:00
}
(void) sprintf(str, "%s,%s", options, opts + 1);
options = str;
} else
options = opts;
}
/* -O overrides default sort settings */
keys = arg_str_value(cmd, sort_ARG, keys);
separator = arg_str_value(cmd, separator_ARG, separator);
if (arg_count(cmd, separator_ARG))
aligned = 0;
if (arg_count(cmd, aligned_ARG))
aligned = 1;
if (arg_count(cmd, unbuffered_ARG) && !arg_count(cmd, sort_ARG))
buffered = 0;
if (arg_count(cmd, noheadings_ARG))
headings = 0;
2008-06-06 23:28:35 +04:00
if (arg_count(cmd, nameprefixes_ARG)) {
aligned = 0;
field_prefixes = 1;
}
2008-06-25 01:21:04 +04:00
if (arg_count(cmd, unquoted_ARG))
quoted = 0;
2008-06-25 02:48:53 +04:00
if (arg_count(cmd, rows_ARG))
columns_as_rows = 1;
if (arg_count(cmd, select_ARG))
selection = arg_str_value(cmd, select_ARG, NULL);
if (!(report_handle = report_init(cmd, options, keys, &report_type,
separator, aligned, buffered,
2008-06-25 02:48:53 +04:00
headings, field_prefixes, quoted,
columns_as_rows, selection)))
return_ECMD_FAILED;
/* Do we need to acquire LV device info in addition? */
lv_info_needed = (report_type & (LVSINFO | LVSINFOSTATUS)) ? 1 : 0;
/* Do we need to acquire LV device status in addition? */
lv_segment_status_needed = (report_type & (SEGSSTATUS | LVSSTATUS | LVSINFOSTATUS)) ? 1 : 0;
/* Ensure options selected are compatible */
if (report_type & (SEGS | SEGSSTATUS))
report_type |= LVS;
if (report_type & PVSEGS)
report_type |= PVS;
if ((report_type & (LVS | LVSINFO | LVSSTATUS | LVSINFOSTATUS)) && (report_type & (PVS | LABEL)) && !args_are_pvs) {
log_error("Can't report LV and PV fields at the same time");
2007-02-14 18:18:31 +03:00
dm_report_free(report_handle);
return ECMD_FAILED;
}
/* Change report type if fields specified makes this necessary */
if ((report_type & PVSEGS) ||
((report_type & (PVS | LABEL)) && (report_type & (LVS | LVSINFO | LVSSTATUS | LVSINFOSTATUS))))
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 | SEGSSTATUS))
report_type = SEGS;
else if (report_type & (LVS | LVSINFO | LVSSTATUS | LVSINFOSTATUS))
report_type = LVS;
/*
* We lock VG_GLOBAL to enable use of metadata cache.
* This can pause alongide pvscan or vgscan process for a while.
*/
if (args_are_pvs && (report_type == PVS || report_type == PVSEGS) &&
!lvmetad_active()) {
lock_global = 1;
if (!lock_vol(cmd, VG_GLOBAL, LCK_VG_READ, NULL)) {
log_error("Unable to obtain global lock.");
dm_report_free(report_handle);
return ECMD_FAILED;
}
}
switch (report_type) {
case DEVTYPES:
r = _process_each_devtype(cmd, argc, report_handle);
break;
case LVSINFO:
/* fall through */
case LVSSTATUS:
/* fall through */
case LVSINFOSTATUS:
/* fall through */
case LVS:
r = process_each_lv(cmd, argc, argv, 0, report_handle,
lv_info_needed && !lv_segment_status_needed ? &_lvs_with_info_single :
!lv_info_needed && lv_segment_status_needed ? &_lvs_with_status_single :
lv_info_needed && lv_segment_status_needed ? &_lvs_with_info_and_status_single :
&_lvs_single);
break;
case VGS:
r = process_each_vg(cmd, argc, argv, 0,
2003-10-22 02:06:07 +04:00
report_handle, &_vgs_single);
break;
case LABEL:
r = process_each_label(cmd, argc, argv,
report_handle, &_label_single);
break;
case PVS:
if (args_are_pvs)
2009-07-15 09:50:22 +04:00
r = process_each_pv(cmd, argc, argv, NULL, 0,
report_handle, &_pvs_single);
else
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 && !lv_segment_status_needed ? &_lvsegs_with_info_single :
!lv_info_needed && lv_segment_status_needed ? &_lvsegs_with_status_single :
lv_info_needed && lv_segment_status_needed ? &_lvsegs_with_info_and_status_single :
&_lvsegs_single);
break;
2005-04-20 00:58:25 +04:00
case PVSEGS:
if (args_are_pvs)
2009-07-15 09:50:22 +04:00
r = process_each_pv(cmd, argc, argv, NULL, 0,
report_handle,
lv_info_needed && !lv_segment_status_needed ? &_pvsegs_with_lv_info_single :
!lv_info_needed && lv_segment_status_needed ? &_pvsegs_with_lv_status_single :
lv_info_needed && lv_segment_status_needed ? &_pvsegs_with_lv_info_and_status_single :
&_pvsegs_single);
else
r = process_each_vg(cmd, argc, argv, 0,
2007-01-27 05:32:31 +03:00
report_handle, &_pvsegs_in_vg);
2005-04-20 00:58:25 +04:00
break;
}
if (find_config_tree_bool(cmd, report_compact_output_CFG, NULL) &&
!dm_report_compact_fields(report_handle))
log_error("Failed to compact report output.");
dm_report_output(report_handle);
dm_report_free(report_handle);
if (lock_global)
unlock_vg(cmd, VG_GLOBAL);
2003-10-22 02:06:07 +04:00
return r;
}
int lvs(struct cmd_context *cmd, int argc, char **argv)
{
report_type_t type;
if (arg_count(cmd, segments_ARG))
type = SEGS;
else
type = LVS;
return _report(cmd, argc, argv, type);
}
int vgs(struct cmd_context *cmd, int argc, char **argv)
{
return _report(cmd, argc, argv, VGS);
}
int pvs(struct cmd_context *cmd, int argc, char **argv)
{
2005-04-20 00:58:25 +04:00
report_type_t type;
if (arg_count(cmd, segments_ARG))
type = PVSEGS;
else
type = LABEL;
2005-04-20 00:58:25 +04:00
return _report(cmd, argc, argv, type);
}
int devtypes(struct cmd_context *cmd, int argc, char **argv)
{
return _report(cmd, argc, argv, DEVTYPES);
}