mirror of
git://sourceware.org/git/lvm2.git
synced 2025-01-04 09:18:36 +03:00
dmsetup: Add --count and --interval to reports.
For example, to monitor active devices every second you can now run dmsetup info -c --count 0.
This commit is contained in:
parent
72f754e2bc
commit
a161e29c59
@ -1,5 +1,7 @@
|
|||||||
Version 1.02.104 -
|
Version 1.02.104 -
|
||||||
=================================
|
=================================
|
||||||
|
Add dmsetup --interval and --count to repeat reports at specified intervals.
|
||||||
|
Add report interval and waiting functions to libdevmapper.
|
||||||
Add dm_timestamp functions to libdevmapper.
|
Add dm_timestamp functions to libdevmapper.
|
||||||
|
|
||||||
Version 1.02.103 - 24th July 2015
|
Version 1.02.103 - 24th July 2015
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
dm_report_set_interval_ms
|
||||||
|
dm_report_set_interval_ns
|
||||||
|
dm_report_get_interval_ms
|
||||||
|
dm_report_get_interval_ns
|
||||||
|
dm_report_wait
|
||||||
dm_size_to_string
|
dm_size_to_string
|
||||||
dm_timestamp_alloc
|
dm_timestamp_alloc
|
||||||
dm_timestamp_compare
|
dm_timestamp_compare
|
||||||
|
@ -1928,6 +1928,50 @@ int dm_report_field_percent(struct dm_report *rh, struct dm_report_field *field,
|
|||||||
void dm_report_field_set_value(struct dm_report_field *field, const void *value,
|
void dm_report_field_set_value(struct dm_report_field *field, const void *value,
|
||||||
const void *sortvalue);
|
const void *sortvalue);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set an interval (in nanoseconds) for this dm_report object that will
|
||||||
|
* be used by any subsequent call to dm_report_wait_interval. This is
|
||||||
|
* only useful for repeating reports (e.g. statistics).
|
||||||
|
*
|
||||||
|
* The default value is zero: no interval.
|
||||||
|
*/
|
||||||
|
void dm_report_set_interval_ns(struct dm_report *rh, uint64_t interval_ns);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set an interval in milliseconds for this dm_report object that will
|
||||||
|
* be used by any subsequent call to dm_report_wait. This is only
|
||||||
|
* useful for repeating reports (e.g. statistics).
|
||||||
|
*
|
||||||
|
* The default value is zero: no interval.
|
||||||
|
*/
|
||||||
|
void dm_report_set_interval_ms(struct dm_report *rh, uint64_t interval_ms);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Retrieve the configured interval of the dm_report handle rh in
|
||||||
|
* nanoseconds.
|
||||||
|
*/
|
||||||
|
uint64_t dm_report_get_interval_ns(struct dm_report *rh);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Retrieve the configured interval of the dm_report handle rh in
|
||||||
|
* milliseconds.
|
||||||
|
*/
|
||||||
|
uint64_t dm_report_get_interval_ms(struct dm_report *rh);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Suspend the calling thread until the current reporting interval
|
||||||
|
* expires. When this function returns the caller should obtain updated
|
||||||
|
* report data and call dm_report_object() and dm_report_output() as
|
||||||
|
* necessary in order to produce the new interval's reporting output.
|
||||||
|
*
|
||||||
|
* Delivery of a non-blocked signal to the thread carrying out the
|
||||||
|
* wait will cause the function to return prematurely with an error.
|
||||||
|
*
|
||||||
|
* Attempting to wait on a report that has no interval set is also
|
||||||
|
* treated as an error.
|
||||||
|
*/
|
||||||
|
int dm_report_wait(struct dm_report *rh);
|
||||||
|
|
||||||
/*************************
|
/*************************
|
||||||
* config file parse/print
|
* config file parse/print
|
||||||
*************************/
|
*************************/
|
||||||
|
@ -43,6 +43,8 @@ struct dm_report {
|
|||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
const char *separator;
|
const char *separator;
|
||||||
|
|
||||||
|
uint64_t interval_ns; /* Reporting interval in nanoseconds */
|
||||||
|
|
||||||
uint32_t keys_count;
|
uint32_t keys_count;
|
||||||
|
|
||||||
/* Ordered list of fields needed for this report */
|
/* Ordered list of fields needed for this report */
|
||||||
@ -4210,3 +4212,45 @@ int dm_report_output(struct dm_report *rh)
|
|||||||
else
|
else
|
||||||
return _output_as_columns(rh);
|
return _output_as_columns(rh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define NSEC_PER_USEC UINT64_C(1000)
|
||||||
|
#define NSEC_PER_MSEC UINT64_C(1000000)
|
||||||
|
#define NSEC_PER_SEC UINT64_C(1000000000)
|
||||||
|
|
||||||
|
void dm_report_set_interval_ns(struct dm_report *rh, uint64_t interval_ns)
|
||||||
|
{
|
||||||
|
rh->interval_ns = interval_ns;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dm_report_set_interval_ms(struct dm_report *rh, uint64_t interval_ms)
|
||||||
|
{
|
||||||
|
rh->interval_ns = interval_ms * NSEC_PER_MSEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t dm_report_get_interval_ns(struct dm_report *rh)
|
||||||
|
{
|
||||||
|
return rh->interval_ns;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t dm_report_get_interval_ms(struct dm_report *rh)
|
||||||
|
{
|
||||||
|
return (rh->interval_ns / NSEC_PER_MSEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dm_report_wait(struct dm_report *rh)
|
||||||
|
{
|
||||||
|
int r = 1;
|
||||||
|
|
||||||
|
if (!rh->interval_ns)
|
||||||
|
return_0;
|
||||||
|
|
||||||
|
if (usleep(rh->interval_ns / NSEC_PER_USEC)) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
log_error("Report interval interrupted by signal.");
|
||||||
|
if (errno == EINVAL)
|
||||||
|
log_error("Report interval too short.");
|
||||||
|
r = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
@ -42,6 +42,10 @@ dmsetup \(em low level logical volume management
|
|||||||
.IR sort_fields ]
|
.IR sort_fields ]
|
||||||
.RB [ \-S | \-\-select
|
.RB [ \-S | \-\-select
|
||||||
.IR Selection ]
|
.IR Selection ]
|
||||||
|
.RB [ \-\-interval
|
||||||
|
.IR seconds ]
|
||||||
|
.RB [ \-\-count
|
||||||
|
.IR count ]
|
||||||
.RI [ device_name ]
|
.RI [ device_name ]
|
||||||
.RE
|
.RE
|
||||||
.br
|
.br
|
||||||
@ -187,6 +191,10 @@ In some cases these checks may slow down operations noticeably.
|
|||||||
.BR \-c | \-C | \-\-columns
|
.BR \-c | \-C | \-\-columns
|
||||||
Display output in columns rather than as Field: Value lines.
|
Display output in columns rather than as Field: Value lines.
|
||||||
.TP
|
.TP
|
||||||
|
.B \-\-count \fIcount
|
||||||
|
Specify the number of times to repeat a report. Set this to zero
|
||||||
|
continue until interrupted. The default interval is one second.
|
||||||
|
.TP
|
||||||
.BR \-h | \-\-help
|
.BR \-h | \-\-help
|
||||||
Outputs a summary of the commands available, optionally including
|
Outputs a summary of the commands available, optionally including
|
||||||
the list of report fields (synonym with \fBhelp\fP command).
|
the list of report fields (synonym with \fBhelp\fP command).
|
||||||
@ -196,6 +204,12 @@ When returning any table information from the kernel report on the
|
|||||||
inactive table instead of the live table.
|
inactive table instead of the live table.
|
||||||
Requires kernel driver version 4.16.0 or above.
|
Requires kernel driver version 4.16.0 or above.
|
||||||
.TP
|
.TP
|
||||||
|
.B \-\-interval \fIseconds
|
||||||
|
Specify the interval in seconds between successive iterations for
|
||||||
|
repeating reports. If \-\-interval is specified but \-\-count is not,
|
||||||
|
reports will continue to repeat until interrupted.
|
||||||
|
The default interval is one second.
|
||||||
|
.TP
|
||||||
.IR \fB\-\-manglename \ { none | hex | auto }
|
.IR \fB\-\-manglename \ { none | hex | auto }
|
||||||
Mangle any character not on a whitelist using mangling_mode when
|
Mangle any character not on a whitelist using mangling_mode when
|
||||||
processing device-mapper device names and UUIDs. The names and UUIDs
|
processing device-mapper device names and UUIDs. The names and UUIDs
|
||||||
@ -355,6 +369,10 @@ Outputs some brief information about the device in the form:
|
|||||||
.IR fields ]
|
.IR fields ]
|
||||||
.RB [ \-O | \-\-sort
|
.RB [ \-O | \-\-sort
|
||||||
.IR sort_fields ]
|
.IR sort_fields ]
|
||||||
|
.RB [ \-\-interval
|
||||||
|
.IR seconds ]
|
||||||
|
.RB [ \-\-count
|
||||||
|
.IR count ]
|
||||||
.RI [ device_name ]
|
.RI [ device_name ]
|
||||||
.br
|
.br
|
||||||
Output you can customise.
|
Output you can customise.
|
||||||
|
@ -111,6 +111,7 @@ enum {
|
|||||||
ADD_NODE_ON_RESUME_ARG,
|
ADD_NODE_ON_RESUME_ARG,
|
||||||
CHECKS_ARG,
|
CHECKS_ARG,
|
||||||
COLS_ARG,
|
COLS_ARG,
|
||||||
|
COUNT_ARG,
|
||||||
DEFERRED_ARG,
|
DEFERRED_ARG,
|
||||||
SELECT_ARG,
|
SELECT_ARG,
|
||||||
EXEC_ARG,
|
EXEC_ARG,
|
||||||
@ -118,6 +119,7 @@ enum {
|
|||||||
GID_ARG,
|
GID_ARG,
|
||||||
HELP_ARG,
|
HELP_ARG,
|
||||||
INACTIVE_ARG,
|
INACTIVE_ARG,
|
||||||
|
INTERVAL_ARG,
|
||||||
MANGLENAME_ARG,
|
MANGLENAME_ARG,
|
||||||
MAJOR_ARG,
|
MAJOR_ARG,
|
||||||
MINOR_ARG,
|
MINOR_ARG,
|
||||||
@ -182,6 +184,11 @@ static struct dm_tree *_dtree;
|
|||||||
static struct dm_report *_report;
|
static struct dm_report *_report;
|
||||||
static report_type_t _report_type;
|
static report_type_t _report_type;
|
||||||
static dev_name_t _dev_name_type;
|
static dev_name_t _dev_name_type;
|
||||||
|
static uint32_t _count = 1; /* count of repeating reports */
|
||||||
|
|
||||||
|
#define NSEC_PER_USEC UINT64_C(1000)
|
||||||
|
#define NSEC_PER_MSEC UINT64_C(1000000)
|
||||||
|
#define NSEC_PER_SEC UINT64_C(1000000000)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Commands
|
* Commands
|
||||||
@ -2845,6 +2852,7 @@ static int _report_init(const struct command *cmd)
|
|||||||
int aligned = 1, headings = 1, buffered = 1, field_prefixes = 0;
|
int aligned = 1, headings = 1, buffered = 1, field_prefixes = 0;
|
||||||
int quoted = 1, columns_as_rows = 0;
|
int quoted = 1, columns_as_rows = 0;
|
||||||
uint32_t flags = 0;
|
uint32_t flags = 0;
|
||||||
|
uint32_t interval;
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
int r = 0;
|
int r = 0;
|
||||||
|
|
||||||
@ -2936,6 +2944,11 @@ static int _report_init(const struct command *cmd)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Default interval is 1 second. */
|
||||||
|
interval = _switches[INTERVAL_ARG] ? _int_args[INTERVAL_ARG] : 1;
|
||||||
|
|
||||||
|
dm_report_set_interval_ns(_report, NSEC_PER_SEC * interval);
|
||||||
|
|
||||||
if (field_prefixes)
|
if (field_prefixes)
|
||||||
dm_report_set_output_field_name_prefix(_report, "dm_");
|
dm_report_set_output_field_name_prefix(_report, "dm_");
|
||||||
|
|
||||||
@ -3110,6 +3123,7 @@ static void _dmsetup_usage(FILE *out)
|
|||||||
" [-y|--yes] [--readahead [+]<sectors>|auto|none] [--retry]\n"
|
" [-y|--yes] [--readahead [+]<sectors>|auto|none] [--retry]\n"
|
||||||
" [-c|-C|--columns] [-o <fields>] [-O|--sort <sort_fields>]\n"
|
" [-c|-C|--columns] [-o <fields>] [-O|--sort <sort_fields>]\n"
|
||||||
" [-S|--select <selection>] [--nameprefixes] [--noheadings]\n"
|
" [-S|--select <selection>] [--nameprefixes] [--noheadings]\n"
|
||||||
|
" [--count <count>] [--interval <seconds>]\n"
|
||||||
" [--separator <separator>]\n\n");
|
" [--separator <separator>]\n\n");
|
||||||
for (i = 0; _dmsetup_commands[i].name; i++)
|
for (i = 0; _dmsetup_commands[i].name; i++)
|
||||||
fprintf(out, "\t%s %s\n", _dmsetup_commands[i].name, _dmsetup_commands[i].help);
|
fprintf(out, "\t%s %s\n", _dmsetup_commands[i].name, _dmsetup_commands[i].help);
|
||||||
@ -3523,6 +3537,7 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir)
|
|||||||
{"readonly", 0, &ind, READ_ONLY},
|
{"readonly", 0, &ind, READ_ONLY},
|
||||||
{"checks", 0, &ind, CHECKS_ARG},
|
{"checks", 0, &ind, CHECKS_ARG},
|
||||||
{"columns", 0, &ind, COLS_ARG},
|
{"columns", 0, &ind, COLS_ARG},
|
||||||
|
{"count", 1, &ind, COUNT_ARG},
|
||||||
{"deferred", 0, &ind, DEFERRED_ARG},
|
{"deferred", 0, &ind, DEFERRED_ARG},
|
||||||
{"select", 1, &ind, SELECT_ARG},
|
{"select", 1, &ind, SELECT_ARG},
|
||||||
{"exec", 1, &ind, EXEC_ARG},
|
{"exec", 1, &ind, EXEC_ARG},
|
||||||
@ -3530,6 +3545,7 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir)
|
|||||||
{"gid", 1, &ind, GID_ARG},
|
{"gid", 1, &ind, GID_ARG},
|
||||||
{"help", 0, &ind, HELP_ARG},
|
{"help", 0, &ind, HELP_ARG},
|
||||||
{"inactive", 0, &ind, INACTIVE_ARG},
|
{"inactive", 0, &ind, INACTIVE_ARG},
|
||||||
|
{"interval", 1, &ind, INTERVAL_ARG},
|
||||||
{"manglename", 1, &ind, MANGLENAME_ARG},
|
{"manglename", 1, &ind, MANGLENAME_ARG},
|
||||||
{"major", 1, &ind, MAJOR_ARG},
|
{"major", 1, &ind, MAJOR_ARG},
|
||||||
{"minor", 1, &ind, MINOR_ARG},
|
{"minor", 1, &ind, MINOR_ARG},
|
||||||
@ -3674,6 +3690,14 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir)
|
|||||||
_switches[ADD_NODE_ON_CREATE_ARG]++;
|
_switches[ADD_NODE_ON_CREATE_ARG]++;
|
||||||
if (ind == CHECKS_ARG)
|
if (ind == CHECKS_ARG)
|
||||||
_switches[CHECKS_ARG]++;
|
_switches[CHECKS_ARG]++;
|
||||||
|
if (ind == COUNT_ARG) {
|
||||||
|
_switches[COUNT_ARG]++;
|
||||||
|
_int_args[COUNT_ARG] = atoi(optarg);
|
||||||
|
if (_int_args[COUNT_ARG] < 0) {
|
||||||
|
log_error("Count must be zero or greater.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (ind == UDEVCOOKIE_ARG) {
|
if (ind == UDEVCOOKIE_ARG) {
|
||||||
_switches[UDEVCOOKIE_ARG]++;
|
_switches[UDEVCOOKIE_ARG]++;
|
||||||
_udev_cookie = _get_cookie_value(optarg);
|
_udev_cookie = _get_cookie_value(optarg);
|
||||||
@ -3709,6 +3733,14 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir)
|
|||||||
}
|
}
|
||||||
if (ind == INACTIVE_ARG)
|
if (ind == INACTIVE_ARG)
|
||||||
_switches[INACTIVE_ARG]++;
|
_switches[INACTIVE_ARG]++;
|
||||||
|
if (ind == INTERVAL_ARG) {
|
||||||
|
_switches[INTERVAL_ARG]++;
|
||||||
|
_int_args[INTERVAL_ARG] = atoi(optarg);
|
||||||
|
if (_int_args[INTERVAL_ARG] <= 0) {
|
||||||
|
log_error("Interval must be a positive integer.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (ind == MANGLENAME_ARG) {
|
if (ind == MANGLENAME_ARG) {
|
||||||
_switches[MANGLENAME_ARG]++;
|
_switches[MANGLENAME_ARG]++;
|
||||||
if (!strcasecmp(optarg, "none"))
|
if (!strcasecmp(optarg, "none"))
|
||||||
@ -3880,13 +3912,18 @@ unknown:
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef UDEV_SYNC_SUPPORT
|
||||||
|
if (!_set_up_udev_support(dev_dir))
|
||||||
|
goto out;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (_switches[COLS_ARG] && !_report_init(cmd))
|
if (_switches[COLS_ARG] && !_report_init(cmd))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
#ifdef UDEV_SYNC_SUPPORT
|
if (_switches[COUNT_ARG])
|
||||||
if (!_set_up_udev_support(dev_dir))
|
_count = _int_args[COUNT_ARG] ? : UINT32_MAX;
|
||||||
goto out;
|
else if (_switches[INTERVAL_ARG])
|
||||||
#endif
|
_count = UINT32_MAX;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Extract subcommand?
|
* Extract subcommand?
|
||||||
@ -3897,17 +3934,26 @@ unknown:
|
|||||||
argc--, argv++;
|
argc--, argv++;
|
||||||
}
|
}
|
||||||
|
|
||||||
doit:
|
doit:
|
||||||
multiple_devices = (cmd->repeatable_cmd && argc != 2 &&
|
multiple_devices = (cmd->repeatable_cmd && argc != 2 &&
|
||||||
(argc != 1 || (!_switches[UUID_ARG] && !_switches[MAJOR_ARG])));
|
(argc != 1 || (!_switches[UUID_ARG] && !_switches[MAJOR_ARG])));
|
||||||
|
|
||||||
|
do {
|
||||||
r = _perform_command_for_all_repeatable_args(cmd, subcommand, argc, argv, NULL, multiple_devices);
|
r = _perform_command_for_all_repeatable_args(cmd, subcommand, argc, argv, NULL, multiple_devices);
|
||||||
|
|
||||||
out:
|
|
||||||
if (_report) {
|
if (_report) {
|
||||||
dm_report_output(_report);
|
dm_report_output(_report);
|
||||||
dm_report_free(_report);
|
|
||||||
|
if (_count > 1) {
|
||||||
|
printf("\n");
|
||||||
|
dm_report_wait(_report);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
} while (--_count);
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (_report)
|
||||||
|
dm_report_free(_report);
|
||||||
|
|
||||||
if (_dtree)
|
if (_dtree)
|
||||||
dm_tree_free(_dtree);
|
dm_tree_free(_dtree);
|
||||||
|
Loading…
Reference in New Issue
Block a user