1
0
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:
Bryn M. Reeves 2015-07-31 21:59:34 +01:00 committed by Alasdair G Kergon
parent 72f754e2bc
commit a161e29c59
6 changed files with 168 additions and 9 deletions

View File

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

View File

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

View File

@ -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
*************************/ *************************/

View File

@ -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;
}

View File

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

View File

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