[lvm-devel] master - dmsetup: Add --count and --interval to reports.

Alasdair Kergon agk at fedoraproject.org
Fri Jul 31 21:00:26 UTC 2015


Gitweb:        http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=a161e29c59e01605401c9096f5ad5ace2ae03d9a
Commit:        a161e29c59e01605401c9096f5ad5ace2ae03d9a
Parent:        72f754e2bc571ada133057c5a248162dc349cf93
Author:        Bryn M. Reeves <breeves at redhat.com>
AuthorDate:    Fri Jul 31 21:59:34 2015 +0100
Committer:     Alasdair G Kergon <agk at redhat.com>
CommitterDate: Fri Jul 31 21:59:34 2015 +0100

dmsetup: Add --count and --interval to reports.

For example, to monitor active devices every second you can now run
dmsetup info -c --count 0.
---
 WHATS_NEW_DM                        |    2 +
 libdm/.exported_symbols.DM_1_02_104 |    5 +++
 libdm/libdevmapper.h                |   44 ++++++++++++++++++++++++
 libdm/libdm-report.c                |   44 ++++++++++++++++++++++++
 man/dmsetup.8.in                    |   18 ++++++++++
 tools/dmsetup.c                     |   64 ++++++++++++++++++++++++++++++-----
 6 files changed, 168 insertions(+), 9 deletions(-)

diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
index 81acfe9..2a006db 100644
--- a/WHATS_NEW_DM
+++ b/WHATS_NEW_DM
@@ -1,5 +1,7 @@
 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.
 
 Version 1.02.103 - 24th July 2015
diff --git a/libdm/.exported_symbols.DM_1_02_104 b/libdm/.exported_symbols.DM_1_02_104
index 9fafa48..815c689 100644
--- a/libdm/.exported_symbols.DM_1_02_104
+++ b/libdm/.exported_symbols.DM_1_02_104
@@ -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_timestamp_alloc
 dm_timestamp_compare
diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h
index 001d4c0..11ba0a3 100644
--- a/libdm/libdevmapper.h
+++ b/libdm/libdevmapper.h
@@ -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,
 			       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
  *************************/
diff --git a/libdm/libdm-report.c b/libdm/libdm-report.c
index 34374bb..5ae994d 100644
--- a/libdm/libdm-report.c
+++ b/libdm/libdm-report.c
@@ -43,6 +43,8 @@ struct dm_report {
 	uint32_t flags;
 	const char *separator;
 
+	uint64_t interval_ns;	/* Reporting interval in nanoseconds */
+
 	uint32_t keys_count;
 
 	/* Ordered list of fields needed for this report */
@@ -4210,3 +4212,45 @@ int dm_report_output(struct dm_report *rh)
 	else
 		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;
+}
diff --git a/man/dmsetup.8.in b/man/dmsetup.8.in
index 57fbdf9..14e393a 100644
--- a/man/dmsetup.8.in
+++ b/man/dmsetup.8.in
@@ -42,6 +42,10 @@ dmsetup \(em low level logical volume management
 .IR sort_fields ]
 .RB [ \-S | \-\-select
 .IR Selection ]
+.RB [ \-\-interval
+.IR seconds ]
+.RB [ \-\-count
+.IR count ]
 .RI [ device_name ]
 .RE
 .br
@@ -187,6 +191,10 @@ In some cases these checks may slow down operations noticeably.
 .BR \-c | \-C | \-\-columns
 Display output in columns rather than as Field: Value lines.
 .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
 Outputs a summary of the commands available, optionally including
 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.
 Requires kernel driver version 4.16.0 or above.
 .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 }
 Mangle any character not on a whitelist using mangling_mode when
 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 ]
 .RB [ \-O | \-\-sort
 .IR sort_fields ]
+.RB [ \-\-interval
+.IR seconds ]
+.RB [ \-\-count
+.IR count ]
 .RI [ device_name ]
 .br
 Output you can customise.
diff --git a/tools/dmsetup.c b/tools/dmsetup.c
index f36119f..4b23d72 100644
--- a/tools/dmsetup.c
+++ b/tools/dmsetup.c
@@ -111,6 +111,7 @@ enum {
 	ADD_NODE_ON_RESUME_ARG,
 	CHECKS_ARG,
 	COLS_ARG,
+	COUNT_ARG,
 	DEFERRED_ARG,
 	SELECT_ARG,
 	EXEC_ARG,
@@ -118,6 +119,7 @@ enum {
 	GID_ARG,
 	HELP_ARG,
 	INACTIVE_ARG,
+	INTERVAL_ARG,
 	MANGLENAME_ARG,
 	MAJOR_ARG,
 	MINOR_ARG,
@@ -182,6 +184,11 @@ static struct dm_tree *_dtree;
 static struct dm_report *_report;
 static report_type_t _report_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
@@ -2845,6 +2852,7 @@ static int _report_init(const struct command *cmd)
 	int aligned = 1, headings = 1, buffered = 1, field_prefixes = 0;
 	int quoted = 1, columns_as_rows = 0;
 	uint32_t flags = 0;
+	uint32_t interval;
 	size_t len = 0;
 	int r = 0;
 
@@ -2936,6 +2944,11 @@ static int _report_init(const struct command *cmd)
 		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)
 		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"
 		"        [-c|-C|--columns] [-o <fields>] [-O|--sort <sort_fields>]\n"
 		"        [-S|--select <selection>] [--nameprefixes] [--noheadings]\n"
+		"        [--count <count>] [--interval <seconds>]\n"
 		"        [--separator <separator>]\n\n");
 	for (i = 0; _dmsetup_commands[i].name; i++)
 		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},
 		{"checks", 0, &ind, CHECKS_ARG},
 		{"columns", 0, &ind, COLS_ARG},
+		{"count", 1, &ind, COUNT_ARG},
 		{"deferred", 0, &ind, DEFERRED_ARG},
 		{"select", 1, &ind, SELECT_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},
 		{"help", 0, &ind, HELP_ARG},
 		{"inactive", 0, &ind, INACTIVE_ARG},
+		{"interval", 1, &ind, INTERVAL_ARG},
 		{"manglename", 1, &ind, MANGLENAME_ARG},
 		{"major", 1, &ind, MAJOR_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]++;
 		if (ind == 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) {
 			_switches[UDEVCOOKIE_ARG]++;
 			_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)
 		       _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) {
 			_switches[MANGLENAME_ARG]++;
 			if (!strcasecmp(optarg, "none"))
@@ -3880,13 +3912,18 @@ unknown:
 		goto out;
 	}
 
-	if (_switches[COLS_ARG] && !_report_init(cmd))
+#ifdef UDEV_SYNC_SUPPORT
+	if (!_set_up_udev_support(dev_dir))
 		goto out;
+#endif
 
-	#ifdef UDEV_SYNC_SUPPORT
-	if (!_set_up_udev_support(dev_dir))
+	if (_switches[COLS_ARG] && !_report_init(cmd))
 		goto out;
-	#endif
+
+	if (_switches[COUNT_ARG])
+		_count = _int_args[COUNT_ARG] ? : UINT32_MAX;
+	else if (_switches[INTERVAL_ARG])
+		_count = UINT32_MAX;
 
 	/*
 	 * Extract subcommand?
@@ -3897,17 +3934,26 @@ unknown:
 		argc--, argv++;
 	}
 
-      doit:
+doit:
 	multiple_devices = (cmd->repeatable_cmd && argc != 2 &&
 			    (argc != 1 || (!_switches[UUID_ARG] && !_switches[MAJOR_ARG])));
 
-	r = _perform_command_for_all_repeatable_args(cmd, subcommand, argc, argv, NULL, multiple_devices);
+	do {
+		r = _perform_command_for_all_repeatable_args(cmd, subcommand, argc, argv, NULL, multiple_devices);
+
+		if (_report) {
+			dm_report_output(_report);
+
+			if (_count > 1) {
+				printf("\n");
+				dm_report_wait(_report);
+			}
+		}
+	} while (--_count);
 
 out:
-	if (_report) {
-		dm_report_output(_report);
+	if (_report)
 		dm_report_free(_report);
-	}
 
 	if (_dtree)
 		dm_tree_free(_dtree);




More information about the lvm-devel mailing list