summaryrefslogtreecommitdiff
path: root/tools/reporter.c
diff options
context:
space:
mode:
authorPeter Rajnoha <prajnoha@redhat.com>2016-05-03 11:18:16 +0200
committerPeter Rajnoha <prajnoha@redhat.com>2016-06-20 11:33:42 +0200
commit26c43c6ce525f5b338a2fbdae72bf308d42708d7 (patch)
treeef73b026591158494483cf4c3a9a4882ffc2004e /tools/reporter.c
parentf1e7f35bb5982f6767bcaa8ab775bde580316c5d (diff)
downloadlvm2-26c43c6ce525f5b338a2fbdae72bf308d42708d7.tar.gz
commands: report: add lvm fullreport command
lvm fullreport executes 5 subreports (vg, pv, lv, pvseg, seg) per each VG (and so taking one VG lock each time) within one command which makes it easier to produce full report about LVM entities. Since all 5 subreports for a VG are done under a VG lock, the output is more consistent mainly in cases where LVM entities may be changed in parallel.
Diffstat (limited to 'tools/reporter.c')
-rw-r--r--tools/reporter.c219
1 files changed, 172 insertions, 47 deletions
diff --git a/tools/reporter.c b/tools/reporter.c
index 9f4f95a83..2037f6e11 100644
--- a/tools/reporter.c
+++ b/tools/reporter.c
@@ -21,6 +21,11 @@ typedef enum {
REPORT_IDX_NULL = -1,
REPORT_IDX_SINGLE,
REPORT_IDX_LOG,
+ REPORT_IDX_FULL_VGS,
+ REPORT_IDX_FULL_LVS,
+ REPORT_IDX_FULL_PVS,
+ REPORT_IDX_FULL_PVSEGS,
+ REPORT_IDX_FULL_SEGS,
REPORT_IDX_COUNT
} report_idx_t;
@@ -48,6 +53,7 @@ struct report_args {
int quoted;
int columns_as_rows;
const char *separator;
+ struct volume_group *full_report_vg;
struct single_report_args single_args[REPORT_IDX_COUNT];
};
@@ -457,8 +463,10 @@ static int _get_final_report_type(int args_are_pvs,
}
/* Change report type if fields specified makes this necessary */
- if ((report_type & PVSEGS) ||
- ((report_type & (PVS | LABEL)) && (report_type & (LVS | LVSINFO | LVSSTATUS | LVSINFOSTATUS))))
+ if (report_type & FULL)
+ report_type = FULL;
+ else if ((report_type & PVSEGS) ||
+ ((report_type & (PVS | LABEL)) && (report_type & (LVS | LVSINFO | LVSSTATUS | LVSINFOSTATUS))))
report_type = PVSEGS;
else if ((report_type & PVS) ||
((report_type & LABEL) && (report_type & VGS)))
@@ -829,6 +837,12 @@ static int _set_report_prefix_and_name(struct single_report_args *single_args)
const char *report_prefix;
size_t len;
+ if (single_args->report_type == FULL) {
+ single_args->report_prefix[0] = '\0';
+ single_args->report_name = single_args->report_prefix;
+ return 1;
+ }
+
report_prefix = report_get_field_prefix(single_args->report_type);
len = strlen(report_prefix);
if (report_prefix[len - 1] == '_')
@@ -850,27 +864,24 @@ static int _set_report_prefix_and_name(struct single_report_args *single_args)
return 1;
}
-static int _do_report(struct cmd_context *cmd, struct report_args *args, struct single_report_args *single_args)
+static int _do_report(struct cmd_context *cmd, struct processing_handle *handle,
+ struct report_args *args, struct single_report_args *single_args)
{
- struct processing_handle *handle = NULL;
+ void *orig_custom_handle = handle->custom_handle;
report_type_t report_type = single_args->report_type;
void *report_handle = NULL;
int lock_global = 0;
int lv_info_needed;
int lv_segment_status_needed;
+ int report_in_group = 0;
int r = ECMD_FAILED;
- if (!(handle = init_processing_handle(cmd, NULL)))
- goto_out;
-
if (!(report_handle = report_init(cmd, single_args->options, single_args->keys, &report_type,
args->separator, args->aligned, args->buffered,
args->headings, args->field_prefixes, args->quoted,
args->columns_as_rows, single_args->selection)))
goto_out;
- handle->internal_report_for_select = 0;
- handle->include_historical_lvs = cmd->include_historical_lvs;
handle->custom_handle = report_handle;
if (!_get_final_report_type(single_args->args_are_pvs,
@@ -879,8 +890,11 @@ static int _do_report(struct cmd_context *cmd, struct report_args *args, struct
&report_type))
goto_out;
- if (!dm_report_group_push(handle->report_group, report_handle, (void *) single_args->report_name))
- goto_out;
+ if (handle->report_group) {
+ if (!dm_report_group_push(handle->report_group, report_handle, (void *) single_args->report_name))
+ goto_out;
+ report_in_group = 1;
+ }
/*
* We lock VG_GLOBAL to enable use of metadata cache.
@@ -906,48 +920,72 @@ static int _do_report(struct cmd_context *cmd, struct report_args *args, struct
case LVSINFOSTATUS:
/* fall through */
case LVS:
- r = process_each_lv(cmd, args->argc, args->argv, NULL, NULL, 0, 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);
+ if (args->full_report_vg)
+ r = _report_all_in_vg(cmd, handle, args->full_report_vg, LVS, lv_info_needed, lv_segment_status_needed);
+ else
+ r = process_each_lv(cmd, args->argc, args->argv, NULL, NULL, 0, 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, args->argc, args->argv, NULL, NULL, 0,
- handle, &_vgs_single);
+ if (args->full_report_vg)
+ r = _report_all_in_vg(cmd, handle, args->full_report_vg, VGS, lv_info_needed, lv_segment_status_needed);
+ else
+ r = process_each_vg(cmd, args->argc, args->argv, NULL, NULL, 0,
+ handle, &_vgs_single);
break;
case LABEL:
r = process_each_label(cmd, args->argc, args->argv,
handle, &_label_single);
break;
case PVS:
- if (single_args->args_are_pvs)
- r = process_each_pv(cmd, args->argc, args->argv, NULL,
- arg_is_set(cmd, all_ARG), 0,
- handle, &_pvs_single);
- else
- r = process_each_vg(cmd, args->argc, args->argv, NULL, NULL,
- 0, handle, &_pvs_in_vg);
+ if (args->full_report_vg)
+ r = _report_all_in_vg(cmd, handle, args->full_report_vg, PVS, lv_info_needed, lv_segment_status_needed);
+ else {
+ if (single_args->args_are_pvs)
+ r = process_each_pv(cmd, args->argc, args->argv, NULL,
+ arg_is_set(cmd, all_ARG), 0,
+ handle, &_pvs_single);
+ else
+ r = process_each_vg(cmd, args->argc, args->argv, NULL, NULL,
+ 0, handle, &_pvs_in_vg);
+ }
break;
case SEGS:
- r = process_each_lv(cmd, args->argc, args->argv, NULL, NULL, 0, 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);
+ if (args->full_report_vg)
+ r = _report_all_in_vg(cmd, handle, args->full_report_vg, SEGS, lv_info_needed, lv_segment_status_needed);
+ else
+ r = process_each_lv(cmd, args->argc, args->argv, NULL, NULL, 0, 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;
case PVSEGS:
- if (single_args->args_are_pvs)
- r = process_each_pv(cmd, args->argc, args->argv, NULL,
- arg_is_set(cmd, all_ARG), 0,
- 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 :
+ if (args->full_report_vg)
+ r = _report_all_in_vg(cmd, handle, args->full_report_vg, PVSEGS, lv_info_needed, lv_segment_status_needed);
+ else {
+ if (single_args->args_are_pvs)
+ r = process_each_pv(cmd, args->argc, args->argv, NULL,
+ arg_is_set(cmd, all_ARG), 0,
+ 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, args->argc, args->argv, NULL, NULL,
- 0, handle, &_pvsegs_in_vg);
+ else
+ r = process_each_vg(cmd, args->argc, args->argv, NULL, NULL,
+ 0, handle, &_pvsegs_in_vg);
+ }
+ break;
+ case FULL:
+ /*
+ * Full report's subreports already covered by combinations above with args->full_report_vg.
+ * We shouldn't see report_type == FULL in this function.
+ */
+ log_error(INTERNAL_ERROR "_do_report: full report requested at incorrect level");
break;
case CMDLOG:
/* Log is reported throughout the code via report_cmdlog calls. */
@@ -970,13 +1008,62 @@ static int _do_report(struct cmd_context *cmd, struct report_args *args, struct
if (lock_global)
unlock_vg(cmd, VG_GLOBAL);
out:
- if (handle)
- destroy_processing_handle(cmd, handle);
- if (report_handle)
+ if (report_handle) {
+ if (report_in_group && !dm_report_group_pop(handle->report_group))
+ stack;
dm_report_free(report_handle);
+ }
+
+ handle->custom_handle = orig_custom_handle;
+ return r;
+}
+
+static int _full_report_single(struct cmd_context *cmd,
+ const char *vg_name,
+ struct volume_group *vg,
+ struct processing_handle *handle)
+{
+ struct report_args *args = (struct report_args *) handle->custom_handle;
+ int orphan = is_orphan_vg(vg->name);
+ int r = ECMD_FAILED;
+
+ if (orphan && !dm_list_size(&vg->pvs))
+ return ECMD_PROCESSED;
+
+ args->full_report_vg = vg;
+
+ if (!dm_report_group_push(handle->report_group, NULL, NULL))
+ goto out;
+
+ if (orphan) {
+ if (((r = _do_report(cmd, handle, args, &args->single_args[REPORT_IDX_FULL_PVS])) != ECMD_PROCESSED) ||
+ ((r = _do_report(cmd, handle, args, &args->single_args[REPORT_IDX_FULL_PVSEGS])) != ECMD_PROCESSED))
+ stack;
+ } else {
+ if (((r = _do_report(cmd, handle, args, &args->single_args[REPORT_IDX_FULL_VGS])) != ECMD_PROCESSED) ||
+ ((r = _do_report(cmd, handle, args, &args->single_args[REPORT_IDX_FULL_PVS])) != ECMD_PROCESSED) ||
+ ((r = _do_report(cmd, handle, args, &args->single_args[REPORT_IDX_FULL_LVS])) != ECMD_PROCESSED) ||
+ ((r = _do_report(cmd, handle, args, &args->single_args[REPORT_IDX_FULL_PVSEGS])) != ECMD_PROCESSED) ||
+ ((r = _do_report(cmd, handle, args, &args->single_args[REPORT_IDX_FULL_SEGS])) != ECMD_PROCESSED))
+ stack;
+ }
+
+ if (!dm_report_group_pop(handle->report_group))
+ goto_out;
+out:
+ args->full_report_vg = NULL;
return r;
}
+#define _set_full_report_single(args,type,name) \
+ do { \
+ args->single_args[REPORT_IDX_FULL_ ## type].report_type = type; \
+ args->single_args[REPORT_IDX_FULL_ ## type].keys = DEFAULT_ ## type ## _SORT_FULL; \
+ args->single_args[REPORT_IDX_FULL_ ## type].options = DEFAULT_ ## type ## _COLS_FULL; \
+ if (!_set_report_prefix_and_name(&args->single_args[REPORT_IDX_FULL_ ## type])) \
+ return_0; \
+ } while (0)
+
static int _config_report(struct cmd_context *cmd, struct report_args *args, struct single_report_args *single_args)
{
args->aligned = find_config_tree_bool(cmd, report_aligned_CFG, NULL);
@@ -1037,6 +1124,13 @@ static int _config_report(struct cmd_context *cmd, struct report_args *args, str
else
single_args->options = find_config_tree_str(cmd, report_pvsegs_cols_verbose_CFG, NULL);
break;
+ case FULL:
+ _set_full_report_single(args, VGS, vgs);
+ _set_full_report_single(args, LVS, lvs);
+ _set_full_report_single(args, PVS, pvs);
+ _set_full_report_single(args, PVSEGS, pvsegs);
+ _set_full_report_single(args, SEGS, segs);
+ break;
case CMDLOG:
single_args->keys = find_config_tree_str(cmd, log_command_log_sort_CFG, NULL);
single_args->options = find_config_tree_str(cmd, log_command_log_cols_CFG, NULL);
@@ -1046,7 +1140,8 @@ static int _config_report(struct cmd_context *cmd, struct report_args *args, str
return 0;
}
- single_args->fields_to_compact = find_config_tree_str_allow_empty(cmd, report_compact_output_cols_CFG, NULL);
+ if (single_args->report_type != FULL)
+ single_args->fields_to_compact = find_config_tree_str_allow_empty(cmd, report_compact_output_cols_CFG, NULL);
/* If -o supplied use it, else use default for report_type */
if ((_get_report_options(cmd, args, single_args) != ECMD_PROCESSED))
@@ -1084,6 +1179,9 @@ static int _report(struct cmd_context *cmd, int argc, char **argv, report_type_t
{
struct report_args args = {0};
struct single_report_args *single_args = &args.single_args[REPORT_IDX_SINGLE];
+ static char report_name[] = "report";
+ struct processing_handle *handle;
+ int r = ECMD_FAILED;
/*
* Include foreign VGs that contain active LVs.
@@ -1097,10 +1195,33 @@ static int _report(struct cmd_context *cmd, int argc, char **argv, report_type_t
args.argv = argv;
single_args->report_type = report_type;
- if (!_config_report(cmd, &args, single_args))
+ if (!(handle = init_processing_handle(cmd, NULL)))
return_ECMD_FAILED;
- return _do_report(cmd, &args, single_args);
+ handle->internal_report_for_select = 0;
+ handle->include_historical_lvs = cmd->include_historical_lvs;
+
+ args.report_group_type = handle->report_group_type;
+
+ if (!_config_report(cmd, &args, single_args)) {
+ destroy_processing_handle(cmd, handle);
+ return_ECMD_FAILED;
+ }
+
+ if (!dm_report_group_push(handle->report_group, NULL, report_name)) {
+ log_error("Failed to add main report section to report group.");
+ destroy_processing_handle(cmd, handle);
+ return ECMD_FAILED;
+ }
+
+ if (single_args->report_type == FULL) {
+ handle->custom_handle = &args;
+ r = process_each_vg(cmd, argc, argv, NULL, NULL, 0, handle, &_full_report_single);
+ } else
+ r = _do_report(cmd, handle, &args, single_args);
+
+ destroy_processing_handle(cmd, handle);
+ return r;
}
int lvs(struct cmd_context *cmd, int argc, char **argv)
@@ -1132,6 +1253,11 @@ int pvs(struct cmd_context *cmd, int argc, char **argv)
return _report(cmd, argc, argv, type);
}
+int fullreport(struct cmd_context *cmd, int argc, char **argv)
+{
+ return _report(cmd, argc, argv, FULL);
+}
+
int devtypes(struct cmd_context *cmd, int argc, char **argv)
{
return _report(cmd, argc, argv, DEVTYPES);
@@ -1143,7 +1269,6 @@ int devtypes(struct cmd_context *cmd, int argc, char **argv)
int report_format_init(struct cmd_context *cmd, dm_report_group_type_t *report_group_type,
struct dm_report_group **report_group, struct dm_report **log_rh)
{
- static char log_report_name[] = "log";
int config_set = find_config_tree_node(cmd, report_output_format_CFG, NULL) != NULL;
const char *config_format_str = find_config_tree_str(cmd, report_output_format_CFG, NULL);
const char *format_str = arg_str_value(cmd, reportformat_ARG, config_set ? config_format_str : NULL);