master - dmstats: add group alias support
by Bryn Reeves
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=b55daa28e89ebc...
Commit: b55daa28e89ebc19da1292baaeeed437501aaeec
Parent: 0761863e28ec3184c0884b8f11f42f10a1374b9e
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Mon Mar 7 18:16:22 2016 +0000
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Tue Jul 5 19:53:16 2016 +0100
dmstats: add group alias support
---
tools/dmsetup.c | 13 +++++++++++--
1 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/tools/dmsetup.c b/tools/dmsetup.c
index 36058c8..9f63608 100644
--- a/tools/dmsetup.c
+++ b/tools/dmsetup.c
@@ -156,6 +156,7 @@ enum {
READ_ONLY = 0,
ADD_NODE_ON_CREATE_ARG,
ADD_NODE_ON_RESUME_ARG,
+ ALIAS_ARG,
ALL_DEVICES_ARG,
ALL_PROGRAMS_ARG,
ALL_REGIONS_ARG,
@@ -5092,7 +5093,7 @@ out:
static int _stats_group(CMD_ARGS)
{
- char *name, *regions = NULL;
+ char *name, *alias = NULL, *regions = NULL;
struct dm_stats *dms;
uint64_t group_id;
int r = 0;
@@ -5124,6 +5125,9 @@ static int _stats_group(CMD_ARGS)
name = argv[0];
}
+ if (_switches[ALIAS_ARG])
+ alias = _string_args[ALIAS_ARG];
+
if (!(dms = dm_stats_create(DM_STATS_PROGRAM_ID)))
return_0;
@@ -5133,7 +5137,7 @@ static int _stats_group(CMD_ARGS)
if (!dm_stats_list(dms, NULL))
goto_out;
- if(!dm_stats_create_group(dms, regions, NULL, &group_id)) {
+ if(!dm_stats_create_group(dms, regions, alias, &group_id)) {
log_error("Could not create group on %s: %s", name, regions);
goto out;
}
@@ -5841,6 +5845,7 @@ static int _process_switches(int *argcp, char ***argvp, const char *dev_dir)
#ifdef HAVE_GETOPTLONG
static struct option long_options[] = {
{"readonly", 0, &ind, READ_ONLY},
+ {"alias", 1, &ind, ALIAS_ARG},
{"alldevices", 0, &ind, ALL_DEVICES_ARG},
{"allprograms", 0, &ind, ALL_PROGRAMS_ARG},
{"allregions", 0, &ind, ALL_REGIONS_ARG},
@@ -5979,6 +5984,10 @@ static int _process_switches(int *argcp, char ***argvp, const char *dev_dir)
optind = OPTIND_INIT;
while ((ind = -1, c = GETOPTLONG_FN(*argcp, *argvp, "cCfG:hj:m:M:no:O:rS:u:U:vy",
long_options, NULL)) != -1) {
+ if (ind == ALIAS_ARG) {
+ _switches[ALIAS_ARG]++;
+ _string_args[ALIAS_ARG] = optarg;
+ }
if (ind == ALL_DEVICES_ARG)
_switches[ALL_DEVICES_ARG]++;
if (ind == ALL_PROGRAMS_ARG)
7 years, 9 months
master - dmstats: add group_id report field type
by Bryn Reeves
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=b4cbc8f2838ce5...
Commit: b4cbc8f2838ce52233151700a59e09b17a3d9a0d
Parent: cda1622fef6c2160f92c88f4eab0200e4864d781
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Mon Mar 7 18:01:45 2016 +0000
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Tue Jul 5 19:53:16 2016 +0100
dmstats: add group_id report field type
---
tools/dmsetup.c | 20 ++++++++++++++++++++
1 files changed, 20 insertions(+), 0 deletions(-)
diff --git a/tools/dmsetup.c b/tools/dmsetup.c
index 8ba12dd..5cd0ef4 100644
--- a/tools/dmsetup.c
+++ b/tools/dmsetup.c
@@ -3416,6 +3416,25 @@ static int _dm_stats_area_count_disp(struct dm_report *rh,
return dm_report_field_uint64(rh, field, &area_count);
}
+static int _dm_stats_group_id_disp(struct dm_report *rh,
+ struct dm_pool *mem __attribute__((unused)),
+ struct dm_report_field *field, const void *data,
+ void *private __attribute__((unused)))
+{
+ const struct dm_stats *dms = (const struct dm_stats *) data;
+ uint64_t group_id;
+
+ group_id = dm_stats_get_group_id(dms,
+ dm_stats_get_current_region(dms));
+
+ if (group_id == UINT64_MAX) {
+ dm_report_field_set_value(field, "-", &group_id);
+ return 1;
+ }
+
+ return dm_report_field_uint64(rh, field, &group_id);
+}
+
static int _dm_stats_program_id_disp(struct dm_report *rh,
struct dm_pool *mem __attribute__((unused)),
struct dm_report_field *field, const void *data,
@@ -4200,6 +4219,7 @@ FIELD_F(STATS_META, SIZ, "ArStart", 7, dm_stats_area_start, "area_start", "Area
FIELD_F(STATS_META, SIZ, "ArSize", 6, dm_stats_area_len, "area_len", "Area length.")
FIELD_F(STATS_META, SIZ, "ArOff", 5, dm_stats_area_offset, "area_offset", "Area offset from start of region.")
FIELD_F(STATS_META, NUM, "#Areas", 6, dm_stats_area_count, "area_count", "Area count.")
+FIELD_F(STATS_META, NUM, "GrpID", 5, dm_stats_group_id, "group_id", "Group ID.")
FIELD_F(STATS_META, STR, "ProgID", 6, dm_stats_program_id, "program_id", "Program ID.")
FIELD_F(STATS_META, STR, "AuxDat", 6, dm_stats_aux_data, "aux_data", "Auxiliary data.")
FIELD_F(STATS_META, STR, "Precise", 7, dm_stats_precise, "precise", "Set if nanosecond precision counters are enabled.")
7 years, 9 months
master - libdm: rename 'region' to 'skip_region' in _stats_walk_next
by Bryn Reeves
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=4cd3dcbbc20d0c...
Commit: 4cd3dcbbc20d0cd97a87d0e584dd91baea1ff34d
Parent: 82e57660623c6b131632a5ec37deef3428de5399
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Mon Jun 20 17:12:38 2016 +0100
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Tue Jul 5 19:53:16 2016 +0100
libdm: rename 'region' to 'skip_region' in _stats_walk_next
In libdm-stats.c 'region' usually refers to a 'struct region*'.
Rename the argument to _stats_walk_start to avoid confusion.
---
libdm/libdm-stats.c | 7 +++----
1 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/libdm/libdm-stats.c b/libdm/libdm-stats.c
index e89f3d6..dc97346 100644
--- a/libdm/libdm-stats.c
+++ b/libdm/libdm-stats.c
@@ -1003,7 +1003,7 @@ bad:
return 0;
}
-static void _stats_walk_next(const struct dm_stats *dms, int region,
+static void _stats_walk_next(const struct dm_stats *dms, int skip_region,
uint64_t *cur_r, uint64_t *cur_a)
{
struct dm_stats_region *cur;
@@ -1015,17 +1015,16 @@ static void _stats_walk_next(const struct dm_stats *dms, int region,
cur = dms->regions + *cur_r;
present = _stats_region_present(cur);
- if (region && present)
+ if (skip_region && present)
*cur_a = _nr_areas_region(cur);
- if (region || !present || ++(*cur_a) == _nr_areas_region(cur)) {
+ if (skip_region || !present || ++(*cur_a) == _nr_areas_region(cur)) {
*cur_a = 0;
while(!dm_stats_region_present(dms, ++(*cur_r))
&& *cur_r < dms->max_region)
; /* keep walking until a present region is found
* or the end of the table is reached. */
}
-
}
static void _stats_walk_start(const struct dm_stats *dms,
7 years, 9 months
master - libdm: add enum based counter and metric calls
by Bryn Reeves
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=82e57660623c6b...
Commit: 82e57660623c6b131632a5ec37deef3428de5399
Parent: 69f808ac8d25e3c7ef39bd2de66fed1efd290bbe
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Mon Feb 29 17:33:16 2016 +0000
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Tue Jul 5 19:53:16 2016 +0100
libdm: add enum based counter and metric calls
Add a new enum based interface for accessing counter and metric
values that uses a single function for each:
uint64_t dm_stats_get_counter(const struct dm_stats *dms,
dm_stats_counter_t counter
uint64_t region_id, uint64_t area_id);
int dm_stats_get_metric(const struct dm_stats *dms, int metric,
uint64_t region_id, uint64_t area_id,
double *value);
This simplifies the implementation of value aggregation for
groups of regions. The named function interface now calls the
enum interface internally so that all new functionality is
available regardless of the method used to retrieve values.
---
WHATS_NEW_DM | 1 +
libdm/.exported_symbols.DM_1_02_129 | 2 +
libdm/libdevmapper.h | 48 +++
libdm/libdm-stats.c | 567 +++++++++++++++++++++--------------
4 files changed, 396 insertions(+), 222 deletions(-)
diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
index 28999f1..59d0cdf 100644
--- a/WHATS_NEW_DM
+++ b/WHATS_NEW_DM
@@ -1,5 +1,6 @@
Version 1.02.129 -
=================================
+ Add enum-driven dm_stats_get_{metric,counter}() interfaces.
Add dm_bitset_parse_list() to parse a string representation of a bitset.
Thin dmeventd plugin umounts lvm2 volume only when pool is 95% or more.
diff --git a/libdm/.exported_symbols.DM_1_02_129 b/libdm/.exported_symbols.DM_1_02_129
index fbd2a57..8385362 100644
--- a/libdm/.exported_symbols.DM_1_02_129
+++ b/libdm/.exported_symbols.DM_1_02_129
@@ -1 +1,3 @@
dm_bitset_parse_list
+dm_stats_get_counter
+dm_stats_get_metric
diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h
index 3668188..68f1192 100644
--- a/libdm/libdevmapper.h
+++ b/libdm/libdevmapper.h
@@ -2742,6 +2742,12 @@ int dm_report_group_destroy(struct dm_report_group *group);
* or area is selected according to the current state of the dm_stats
* handle's embedded cursor.
*
+ * Two methods are provided to access counter values: a named function
+ * for each available counter field and a single function that accepts
+ * an enum value specifying the required field. New code is encouraged
+ * to use the enum based interface as calls to the named functions are
+ * implemented using the enum method internally.
+ *
* See the kernel documentation for complete descriptions of each
* counter field:
*
@@ -2766,6 +2772,27 @@ int dm_report_group_destroy(struct dm_report_group *group);
#define DM_STATS_REGION_CURRENT UINT64_MAX
#define DM_STATS_AREA_CURRENT UINT64_MAX
+typedef enum {
+ DM_STATS_READS_COUNT,
+ DM_STATS_READS_MERGED_COUNT,
+ DM_STATS_READ_SECTORS_COUNT,
+ DM_STATS_READ_NSECS,
+ DM_STATS_WRITES_COUNT,
+ DM_STATS_WRITES_MERGED_COUNT,
+ DM_STATS_WRITE_SECTORS_COUNT,
+ DM_STATS_WRITE_NSECS,
+ DM_STATS_IO_IN_PROGRESS_COUNT,
+ DM_STATS_IO_NSECS,
+ DM_STATS_WEIGHTED_IO_NSECS,
+ DM_STATS_TOTAL_READ_NSECS,
+ DM_STATS_TOTAL_WRITE_NSECS,
+ DM_STATS_NR_COUNTERS
+} dm_stats_counter_t;
+
+uint64_t dm_stats_get_counter(const struct dm_stats *dms,
+ dm_stats_counter_t counter,
+ uint64_t region_id, uint64_t area_id);
+
uint64_t dm_stats_get_reads(const struct dm_stats *dms,
uint64_t region_id, uint64_t area_id);
@@ -2832,6 +2859,27 @@ uint64_t dm_stats_get_total_write_nsecs(const struct dm_stats *dms,
* average_wr_wait_time: the average write wait time
*/
+typedef enum {
+ DM_STATS_RD_MERGES_PER_SEC,
+ DM_STATS_WR_MERGES_PER_SEC,
+ DM_STATS_READS_PER_SEC,
+ DM_STATS_WRITES_PER_SEC,
+ DM_STATS_READ_SECTORS_PER_SEC,
+ DM_STATS_WRITE_SECTORS_PER_SEC,
+ DM_STATS_AVERAGE_REQUEST_SIZE,
+ DM_STATS_AVERAGE_QUEUE_SIZE,
+ DM_STATS_AVERAGE_WAIT_TIME,
+ DM_STATS_AVERAGE_RD_WAIT_TIME,
+ DM_STATS_AVERAGE_WR_WAIT_TIME,
+ DM_STATS_SERVICE_TIME,
+ DM_STATS_THROUGHPUT,
+ DM_STATS_UTILIZATION,
+ DM_STATS_NR_METRICS
+} dm_stats_metric_t;
+
+int dm_stats_get_metric(const struct dm_stats *dms, int metric,
+ uint64_t region_id, uint64_t area_id, double *value);
+
int dm_stats_get_rd_merges_per_sec(const struct dm_stats *dms, double *rrqm,
uint64_t region_id, uint64_t area_id);
diff --git a/libdm/libdm-stats.c b/libdm/libdm-stats.c
index 99e4d72..e89f3d6 100644
--- a/libdm/libdm-stats.c
+++ b/libdm/libdm-stats.c
@@ -1438,342 +1438,465 @@ void dm_stats_destroy(struct dm_stats *dms)
dm_free(dms);
}
+static uint64_t _stats_get_counter(const struct dm_stats *dms,
+ const struct dm_stats_counters *area,
+ dm_stats_counter_t counter)
+{
+ switch(counter) {
+ case DM_STATS_READS_COUNT:
+ return area->reads;
+ case DM_STATS_READS_MERGED_COUNT:
+ return area->reads_merged;
+ case DM_STATS_READ_SECTORS_COUNT:
+ return area->read_sectors;
+ case DM_STATS_READ_NSECS:
+ return area->read_nsecs;
+ case DM_STATS_WRITES_COUNT:
+ return area->writes;
+ case DM_STATS_WRITES_MERGED_COUNT:
+ return area->writes_merged;
+ case DM_STATS_WRITE_SECTORS_COUNT:
+ return area->write_sectors;
+ case DM_STATS_WRITE_NSECS:
+ return area->write_nsecs;
+ case DM_STATS_IO_IN_PROGRESS_COUNT:
+ return area->io_in_progress;
+ case DM_STATS_IO_NSECS:
+ return area->io_nsecs;
+ case DM_STATS_WEIGHTED_IO_NSECS:
+ return area->weighted_io_nsecs;
+ case DM_STATS_TOTAL_READ_NSECS:
+ return area->total_read_nsecs;
+ case DM_STATS_TOTAL_WRITE_NSECS:
+ return area->total_write_nsecs;
+ case DM_STATS_NR_COUNTERS:
+ default:
+ log_error("Attempt to read invalid counter: %d", counter);
+ }
+ return 0;
+}
+
+uint64_t dm_stats_get_counter(const struct dm_stats *dms,
+ dm_stats_counter_t counter,
+ uint64_t region_id, uint64_t area_id)
+{
+ struct dm_stats_region *region;
+ struct dm_stats_counters *area;
+
+ region_id = (region_id == DM_STATS_REGION_CURRENT)
+ ? dms->cur_region : region_id ;
+ area_id = (area_id == DM_STATS_REGION_CURRENT)
+ ? dms->cur_area : area_id ;
+
+ region = &dms->regions[region_id];
+
+ area = ®ion->counters[area_id];
+
+ return _stats_get_counter(dms, area, counter);
+}
+
/**
- * Methods for accessing counter fields. All methods share the
+ * Methods for accessing named counter fields. All methods share the
* following naming scheme and prototype:
*
- * uint64_t dm_stats_get_COUNTER(struct dm_stats *, uint64_t, uint64_t)
+ * uint64_t dm_stats_get_COUNTER(const struct dm_stats *, uint64_t, uint64_t)
*
* Where the two integer arguments are the region_id and area_id
* respectively.
+ *
+ * name is the name of the counter (lower case)
+ * counter is the part of the enum name following DM_STATS_ (upper case)
*/
-#define MK_STATS_GET_COUNTER_FN(counter) \
-uint64_t dm_stats_get_ ## counter(const struct dm_stats *dms, \
- uint64_t region_id, uint64_t area_id) \
+#define MK_STATS_GET_COUNTER_FN(name, counter) \
+uint64_t dm_stats_get_ ## name(const struct dm_stats *dms, \
+ uint64_t region_id, uint64_t area_id) \
{ \
- region_id = (region_id == DM_STATS_REGION_CURRENT) \
- ? dms->cur_region : region_id ; \
- area_id = (area_id == DM_STATS_REGION_CURRENT) \
- ? dms->cur_area : area_id ; \
- return dms->regions[region_id].counters[area_id].counter; \
-}
-
-MK_STATS_GET_COUNTER_FN(reads)
-MK_STATS_GET_COUNTER_FN(reads_merged)
-MK_STATS_GET_COUNTER_FN(read_sectors)
-MK_STATS_GET_COUNTER_FN(read_nsecs)
-MK_STATS_GET_COUNTER_FN(writes)
-MK_STATS_GET_COUNTER_FN(writes_merged)
-MK_STATS_GET_COUNTER_FN(write_sectors)
-MK_STATS_GET_COUNTER_FN(write_nsecs)
-MK_STATS_GET_COUNTER_FN(io_in_progress)
-MK_STATS_GET_COUNTER_FN(io_nsecs)
-MK_STATS_GET_COUNTER_FN(weighted_io_nsecs)
-MK_STATS_GET_COUNTER_FN(total_read_nsecs)
-MK_STATS_GET_COUNTER_FN(total_write_nsecs)
+ return dm_stats_get_counter(dms, DM_STATS_ ## counter, \
+ region_id, area_id); \
+}
+
+MK_STATS_GET_COUNTER_FN(reads, READS_COUNT)
+MK_STATS_GET_COUNTER_FN(reads_merged, READS_MERGED_COUNT)
+MK_STATS_GET_COUNTER_FN(read_sectors, READ_SECTORS_COUNT)
+MK_STATS_GET_COUNTER_FN(read_nsecs, READ_NSECS)
+MK_STATS_GET_COUNTER_FN(writes, WRITES_COUNT)
+MK_STATS_GET_COUNTER_FN(writes_merged, WRITES_MERGED_COUNT)
+MK_STATS_GET_COUNTER_FN(write_sectors, WRITE_SECTORS_COUNT)
+MK_STATS_GET_COUNTER_FN(write_nsecs, WRITE_NSECS)
+MK_STATS_GET_COUNTER_FN(io_in_progress, IO_IN_PROGRESS_COUNT)
+MK_STATS_GET_COUNTER_FN(io_nsecs, IO_NSECS)
+MK_STATS_GET_COUNTER_FN(weighted_io_nsecs, WEIGHTED_IO_NSECS)
+MK_STATS_GET_COUNTER_FN(total_read_nsecs, TOTAL_READ_NSECS)
+MK_STATS_GET_COUNTER_FN(total_write_nsecs, TOTAL_WRITE_NSECS)
#undef MK_STATS_GET_COUNTER_FN
-int dm_stats_get_rd_merges_per_sec(const struct dm_stats *dms, double *rrqm,
- uint64_t region_id, uint64_t area_id)
-{
- struct dm_stats_counters *c;
+/*
+ * Floating point stats metric functions
+ *
+ * Called from dm_stats_get_metric() to calculate the value of
+ * the requested metric.
+ *
+ * int _metric_name(const struct dm_stats *dms,
+ * struct dm_stats_counters *c,
+ * double *value);
+ *
+ * Calculate a metric value from the counter data for the given
+ * identifiers and store it in the memory pointed to by value,
+ * applying group or region aggregation if enabled.
+ *
+ * Return one on success or zero on failure.
+ *
+ * To add a new metric:
+ *
+ * o Add a new name to the dm_stats_metric_t enum.
+ * o Create a _metric_fn() to calculate the new metric.
+ * o Add _metric_fn to the _metrics function table
+ * (entries in enum order).
+ * o Do not add a new named public function for the metric -
+ * users of new metrics are encouraged to convert to the enum
+ * based metric interface.
+ *
+ */
- if (!dms->interval_ns)
- return_0;
+static int _rd_merges_per_sec(const struct dm_stats *dms, double *rrqm,
+ uint64_t region_id, uint64_t area_id)
+{
+ double mrgs;
+ mrgs = (double) dm_stats_get_counter(dms, DM_STATS_READS_MERGED_COUNT,
+ region_id, area_id);
- region_id = (region_id == DM_STATS_REGION_CURRENT)
- ? dms->cur_region : region_id ;
- area_id = (area_id == DM_STATS_REGION_CURRENT)
- ? dms->cur_area : area_id ;
+ *rrqm = mrgs / (double) dms->interval_ns;
- c = &(dms->regions[region_id].counters[area_id]);
- *rrqm = ((double) c->reads_merged) / (double) dms->interval_ns;
return 1;
}
-int dm_stats_get_wr_merges_per_sec(const struct dm_stats *dms, double *wrqm,
- uint64_t region_id, uint64_t area_id)
+static int _wr_merges_per_sec(const struct dm_stats *dms, double *wrqm,
+ uint64_t region_id, uint64_t area_id)
{
- struct dm_stats_counters *c;
+ double mrgs;
+ mrgs = (double) dm_stats_get_counter(dms, DM_STATS_WRITES_MERGED_COUNT,
+ region_id, area_id);
- if (!dms->interval_ns)
- return_0;
+ *wrqm = mrgs / (double) dms->interval_ns;
- region_id = (region_id == DM_STATS_REGION_CURRENT)
- ? dms->cur_region : region_id ;
- area_id = (area_id == DM_STATS_REGION_CURRENT)
- ? dms->cur_area : area_id ;
-
- c = &(dms->regions[region_id].counters[area_id]);
- *wrqm = ((double) c->writes_merged) / (double) dms->interval_ns;
return 1;
}
-int dm_stats_get_reads_per_sec(const struct dm_stats *dms, double *rd_s,
- uint64_t region_id, uint64_t area_id)
+static int _reads_per_sec(const struct dm_stats *dms, double *rd_s,
+ uint64_t region_id, uint64_t area_id)
{
- struct dm_stats_counters *c;
-
- if (!dms->interval_ns)
- return_0;
+ double reads;
+ reads = (double) dm_stats_get_counter(dms, DM_STATS_READS_COUNT,
+ region_id, area_id);
- region_id = (region_id == DM_STATS_REGION_CURRENT)
- ? dms->cur_region : region_id ;
- area_id = (area_id == DM_STATS_REGION_CURRENT)
- ? dms->cur_area : area_id ;
+ *rd_s = (reads * NSEC_PER_SEC) / (double) dms->interval_ns;
- c = &(dms->regions[region_id].counters[area_id]);
- *rd_s = ((double) c->reads * NSEC_PER_SEC) / (double) dms->interval_ns;
return 1;
}
-int dm_stats_get_writes_per_sec(const struct dm_stats *dms, double *wr_s,
- uint64_t region_id, uint64_t area_id)
+static int _writes_per_sec(const struct dm_stats *dms, double *wr_s,
+ uint64_t region_id, uint64_t area_id)
{
- struct dm_stats_counters *c;
+ double writes;
+ writes = (double) dm_stats_get_counter(dms, DM_STATS_WRITES_COUNT,
+ region_id, area_id);
- if (!dms->interval_ns)
- return_0;
+ *wr_s = (writes * NSEC_PER_SEC) / (double) dms->interval_ns;
- region_id = (region_id == DM_STATS_REGION_CURRENT)
- ? dms->cur_region : region_id ;
- area_id = (area_id == DM_STATS_REGION_CURRENT)
- ? dms->cur_area : area_id ;
+ return 1;
+}
+
+static int _read_sectors_per_sec(const struct dm_stats *dms, double *rsec_s,
+ uint64_t region_id, uint64_t area_id)
+{
+ double sect;
+ sect = (double) dm_stats_get_counter(dms, DM_STATS_READ_SECTORS_COUNT,
+ region_id, area_id);
- c = &(dms->regions[region_id].counters[area_id]);
- *wr_s = ((double) c->writes * (double) NSEC_PER_SEC)
- / (double) dms->interval_ns;
+ *rsec_s = (sect * (double) NSEC_PER_SEC) / (double) dms->interval_ns;
return 1;
}
-int dm_stats_get_read_sectors_per_sec(const struct dm_stats *dms, double *rsec_s,
- uint64_t region_id, uint64_t area_id)
+static int _write_sectors_per_sec(const struct dm_stats *dms, double *wsec_s,
+ uint64_t region_id, uint64_t area_id)
{
- struct dm_stats_counters *c;
+ double sect;
+ sect = (double) dm_stats_get_counter(dms, DM_STATS_WRITE_SECTORS_COUNT,
+ region_id, area_id);
- if (!dms->interval_ns)
- return_0;
+ *wsec_s = (sect * (double) NSEC_PER_SEC) / (double) dms->interval_ns;
- region_id = (region_id == DM_STATS_REGION_CURRENT)
- ? dms->cur_region : region_id ;
- area_id = (area_id == DM_STATS_REGION_CURRENT)
- ? dms->cur_area : area_id ;
+ return 1;
+}
- c = &(dms->regions[region_id].counters[area_id]);
- *rsec_s = ((double) c->read_sectors * (double) NSEC_PER_SEC)
- / (double) dms->interval_ns;
+static int _average_request_size(const struct dm_stats *dms, double *arqsz,
+ uint64_t region_id, uint64_t area_id)
+{
+ double ios, sectors;
+
+ ios = (double) (dm_stats_get_counter(dms, DM_STATS_READS_COUNT,
+ region_id, area_id)
+ + dm_stats_get_counter(dms, DM_STATS_WRITES_COUNT,
+ region_id, area_id));
+ sectors = (double) (dm_stats_get_counter(dms, DM_STATS_READ_SECTORS_COUNT,
+ region_id, area_id)
+ + dm_stats_get_counter(dms, DM_STATS_WRITE_SECTORS_COUNT,
+ region_id, area_id));
+
+ if (ios > 0.0)
+ *arqsz = sectors / ios;
+ else
+ *arqsz = 0.0;
return 1;
}
-int dm_stats_get_write_sectors_per_sec(const struct dm_stats *dms, double *wsec_s,
- uint64_t region_id, uint64_t area_id)
+static int _average_queue_size(const struct dm_stats *dms, double *qusz,
+ uint64_t region_id, uint64_t area_id)
{
- struct dm_stats_counters *c;
-
- if (!dms->interval_ns)
- return_0;
+ double io_ticks;
+ io_ticks = (double) dm_stats_get_counter(dms, DM_STATS_WEIGHTED_IO_NSECS,
+ region_id, area_id);
- region_id = (region_id == DM_STATS_REGION_CURRENT)
- ? dms->cur_region : region_id ;
- area_id = (area_id == DM_STATS_REGION_CURRENT)
- ? dms->cur_area : area_id ;
+ if (io_ticks > 0.0)
+ *qusz = io_ticks / (double) dms->interval_ns;
+ else
+ *qusz = 0.0;
- c = &(dms->regions[region_id].counters[area_id]);
- *wsec_s = ((double) c->write_sectors * (double) NSEC_PER_SEC)
- / (double) dms->interval_ns;
return 1;
}
-int dm_stats_get_average_request_size(const struct dm_stats *dms, double *arqsz,
- uint64_t region_id, uint64_t area_id)
+static int _average_wait_time(const struct dm_stats *dms, double *await,
+ uint64_t region_id, uint64_t area_id)
{
- struct dm_stats_counters *c;
- uint64_t nr_ios, nr_sectors;
+ uint64_t io_ticks, nr_ios;
- if (!dms->interval_ns)
- return_0;
+ io_ticks = dm_stats_get_counter(dms, DM_STATS_READ_NSECS,
+ region_id, area_id);
+ io_ticks += dm_stats_get_counter(dms, DM_STATS_WRITE_NSECS,
+ region_id, area_id);
- *arqsz = 0.0;
+ nr_ios = dm_stats_get_counter(dms, DM_STATS_READS_COUNT,
+ region_id, area_id);
+ nr_ios += dm_stats_get_counter(dms, DM_STATS_WRITES_COUNT,
+ region_id, area_id);
- region_id = (region_id == DM_STATS_REGION_CURRENT)
- ? dms->cur_region : region_id ;
- area_id = (area_id == DM_STATS_REGION_CURRENT)
- ? dms->cur_area : area_id ;
+ if (nr_ios > 0)
+ *await = (double) io_ticks / (double) nr_ios;
+ else
+ *await = 0.0;
- c = &(dms->regions[region_id].counters[area_id]);
- nr_ios = c->reads + c->writes;
- nr_sectors = c->read_sectors + c->write_sectors;
- if (nr_ios)
- *arqsz = (double) nr_sectors / (double) nr_ios;
return 1;
}
-int dm_stats_get_average_queue_size(const struct dm_stats *dms, double *qusz,
- uint64_t region_id, uint64_t area_id)
+static int _average_rd_wait_time(const struct dm_stats *dms, double *await,
+ uint64_t region_id, uint64_t area_id)
{
- struct dm_stats_counters *c;
- uint64_t io_ticks;
+ uint64_t rd_io_ticks, nr_rd_ios;
- if (!dms->interval_ns)
- return_0;
+ rd_io_ticks = dm_stats_get_counter(dms, DM_STATS_READ_NSECS,
+ region_id, area_id);
- *qusz = 0.0;
+ nr_rd_ios = dm_stats_get_counter(dms, DM_STATS_READS_COUNT,
+ region_id, area_id);
- region_id = (region_id == DM_STATS_REGION_CURRENT)
- ? dms->cur_region : region_id ;
- area_id = (area_id == DM_STATS_REGION_CURRENT)
- ? dms->cur_area : area_id ;
+ if (rd_io_ticks > 0)
+ *await = (double) rd_io_ticks / (double) nr_rd_ios;
+ else
+ *await = 0.0;
- c = &(dms->regions[region_id].counters[area_id]);
- io_ticks = c->weighted_io_nsecs;
- if (io_ticks)
- *qusz = (double) io_ticks / (double) dms->interval_ns;
return 1;
}
-int dm_stats_get_average_wait_time(const struct dm_stats *dms, double *await,
- uint64_t region_id, uint64_t area_id)
+static int _average_wr_wait_time(const struct dm_stats *dms, double *await,
+ uint64_t region_id, uint64_t area_id)
{
- struct dm_stats_counters *c;
- uint64_t io_ticks, nr_ios;
-
- if (!dms->interval_ns)
- return_0;
+ uint64_t wr_io_ticks, nr_wr_ios;
- *await = 0.0;
+ wr_io_ticks = dm_stats_get_counter(dms, DM_STATS_WRITE_NSECS,
+ region_id, area_id);
+ nr_wr_ios = dm_stats_get_counter(dms, DM_STATS_WRITES_COUNT,
+ region_id, area_id);
- region_id = (region_id == DM_STATS_REGION_CURRENT)
- ? dms->cur_region : region_id ;
- area_id = (area_id == DM_STATS_REGION_CURRENT)
- ? dms->cur_area : area_id ;
+ if (wr_io_ticks > 0)
+ *await = (double) wr_io_ticks / (double) nr_wr_ios;
+ else
+ *await = 0.0;
- c = &(dms->regions[region_id].counters[area_id]);
- io_ticks = c->read_nsecs + c->write_nsecs;
- nr_ios = c->reads + c->writes;
- if (nr_ios)
- *await = (double) io_ticks / (double) nr_ios;
return 1;
}
-int dm_stats_get_average_rd_wait_time(const struct dm_stats *dms,
- double *await, uint64_t region_id,
- uint64_t area_id)
+static int _throughput(const struct dm_stats *dms, double *tput,
+ uint64_t region_id, uint64_t area_id)
{
- struct dm_stats_counters *c;
- uint64_t rd_io_ticks, nr_rd_ios;
+ uint64_t nr_ios;
- if (!dms->interval_ns)
- return_0;
+ nr_ios = dm_stats_get_counter(dms, DM_STATS_READS_COUNT,
+ region_id, area_id);
+ nr_ios += dm_stats_get_counter(dms, DM_STATS_WRITES_COUNT,
+ region_id, area_id);
- *await = 0.0;
+ *tput = ((double) NSEC_PER_SEC * (double) nr_ios)
+ / (double) (dms->interval_ns);
- region_id = (region_id == DM_STATS_REGION_CURRENT)
- ? dms->cur_region : region_id ;
- area_id = (area_id == DM_STATS_REGION_CURRENT)
- ? dms->cur_area : area_id ;
-
- c = &(dms->regions[region_id].counters[area_id]);
- rd_io_ticks = c->read_nsecs;
- nr_rd_ios = c->reads;
- if (rd_io_ticks)
- *await = (double) rd_io_ticks / (double) nr_rd_ios;
return 1;
}
-int dm_stats_get_average_wr_wait_time(const struct dm_stats *dms,
- double *await, uint64_t region_id,
- uint64_t area_id)
+static int _utilization(const struct dm_stats *dms, double *util,
+ uint64_t region_id, uint64_t area_id)
{
- struct dm_stats_counters *c;
- uint64_t wr_io_ticks, nr_wr_ios;
+ uint64_t io_nsecs, interval_ns = dms->interval_ns;
- if (!dms->interval_ns)
- return_0;
+ /**
+ * If io_nsec > interval_ns there is something wrong with the clock
+ * for the last interval; do not allow a value > 100% utilization
+ * to be passed to a dm_make_percent() call. We expect to see these
+ * at startup if counters have not been cleared before the first read.
+ */
+ io_nsecs = dm_stats_get_counter(dms, DM_STATS_IO_NSECS,
+ region_id, area_id);
- *await = 0.0;
+ io_nsecs = ((io_nsecs < interval_ns) ? io_nsecs : interval_ns);
- region_id = (region_id == DM_STATS_REGION_CURRENT)
- ? dms->cur_region : region_id ;
- area_id = (area_id == DM_STATS_REGION_CURRENT)
- ? dms->cur_area : area_id ;
+ *util = (double) io_nsecs / (double) interval_ns;
- c = &(dms->regions[region_id].counters[area_id]);
- wr_io_ticks = c->write_nsecs;
- nr_wr_ios = c->writes;
- if (wr_io_ticks && nr_wr_ios)
- *await = (double) wr_io_ticks / (double) nr_wr_ios;
return 1;
}
-int dm_stats_get_service_time(const struct dm_stats *dms, double *svctm,
- uint64_t region_id, uint64_t area_id)
+static int _service_time(const struct dm_stats *dms, double *svctm,
+ uint64_t region_id, uint64_t area_id)
{
- dm_percent_t util;
- double tput;
+ double tput, util;
- if (!dm_stats_get_throughput(dms, &tput, region_id, area_id))
- return_0;
+ if (!_throughput(dms, &tput, region_id, area_id))
+ return 0;
- if (!dm_stats_get_utilization(dms, &util, region_id, area_id))
- return_0;
+ if (!_utilization(dms, &util, region_id, area_id))
+ return 0;
+
+ util *= 100;
/* avoid NAN with zero counter values */
if ( (uint64_t) tput == 0 || (uint64_t) util == 0) {
*svctm = 0.0;
return 1;
}
+
*svctm = ((double) NSEC_PER_SEC * dm_percent_to_float(util))
/ (100.0 * tput);
+
return 1;
}
-int dm_stats_get_throughput(const struct dm_stats *dms, double *tput,
- uint64_t region_id, uint64_t area_id)
-{
- struct dm_stats_counters *c;
+/*
+ * Table in enum order:
+ * DM_STATS_RD_MERGES_PER_SEC,
+ * DM_STATS_WR_MERGES_PER_SEC,
+ * DM_STATS_READS_PER_SEC,
+ * DM_STATS_WRITES_PER_SEC,
+ * DM_STATS_READ_SECTORS_PER_SEC,
+ * DM_STATS_WRITE_SECTORS_PER_SEC,
+ * DM_STATS_AVERAGE_REQUEST_SIZE,
+ * DM_STATS_AVERAGE_QUEUE_SIZE,
+ * DM_STATS_AVERAGE_WAIT_TIME,
+ * DM_STATS_AVERAGE_RD_WAIT_TIME,
+ * DM_STATS_AVERAGE_WR_WAIT_TIME
+ * DM_STATS_SERVICE_TIME,
+ * DM_STATS_THROUGHPUT,
+ * DM_STATS_UTILIZATION
+ *
+*/
+
+typedef int (*_metric_fn_t)(const struct dm_stats *, double *,
+ uint64_t, uint64_t);
+
+_metric_fn_t _metrics[DM_STATS_NR_METRICS] = {
+ _rd_merges_per_sec,
+ _wr_merges_per_sec,
+ _reads_per_sec,
+ _writes_per_sec,
+ _read_sectors_per_sec,
+ _write_sectors_per_sec,
+ _average_request_size,
+ _average_queue_size,
+ _average_wait_time,
+ _average_rd_wait_time,
+ _average_wr_wait_time,
+ _service_time,
+ _throughput,
+ _utilization
+};
+int dm_stats_get_metric(const struct dm_stats *dms, int metric,
+ uint64_t region_id, uint64_t area_id, double *value)
+{
if (!dms->interval_ns)
return_0;
- region_id = (region_id == DM_STATS_REGION_CURRENT)
- ? dms->cur_region : region_id ;
- area_id = (area_id == DM_STATS_REGION_CURRENT)
- ? dms->cur_area : area_id ;
-
- c = &(dms->regions[region_id].counters[area_id]);
+ if (metric < 0 || metric >= DM_STATS_NR_METRICS) {
+ log_error("Attempt to read invalid metric: %d", metric);
+ return 0;
+ }
- *tput = (( NSEC_PER_SEC * ((double) c->reads + (double) c->writes))
- / (double) (dms->interval_ns));
- return 1;
+ return _metrics[metric](dms, value, region_id, area_id);
}
+/**
+ * Methods for accessing stats metrics. All methods share the
+ * following naming scheme and prototype:
+ *
+ * uint64_t dm_stats_get_metric(struct dm_stats *,
+ * int, int,
+ * uint64_t, uint64_t,
+ * double *v)
+ *
+ * Where the two integer arguments are the region_id and area_id
+ * respectively.
+ *
+ * name is the name of the metric (lower case)
+ * metric is the part of the enum name following DM_STATS_ (upper case)
+ */
+#define MK_STATS_GET_METRIC_FN(name, metric, meta) \
+int dm_stats_get_ ## name(const struct dm_stats *dms, double *meta, \
+ uint64_t region_id, uint64_t area_id) \
+{ \
+ return dm_stats_get_metric(dms, DM_STATS_ ## metric, \
+ region_id, area_id, meta); \
+}
+
+MK_STATS_GET_METRIC_FN(rd_merges_per_sec, RD_MERGES_PER_SEC, rrqm)
+MK_STATS_GET_METRIC_FN(wr_merges_per_sec, WR_MERGES_PER_SEC, wrqm)
+MK_STATS_GET_METRIC_FN(reads_per_sec, READS_PER_SEC, rd_s)
+MK_STATS_GET_METRIC_FN(writes_per_sec, WRITES_PER_SEC, wr_s)
+MK_STATS_GET_METRIC_FN(read_sectors_per_sec, READ_SECTORS_PER_SEC, rsec_s)
+MK_STATS_GET_METRIC_FN(write_sectors_per_sec, WRITE_SECTORS_PER_SEC, wsec_s)
+MK_STATS_GET_METRIC_FN(average_request_size, AVERAGE_REQUEST_SIZE, arqsz)
+MK_STATS_GET_METRIC_FN(average_queue_size, AVERAGE_QUEUE_SIZE, qusz)
+MK_STATS_GET_METRIC_FN(average_wait_time, AVERAGE_WAIT_TIME, await)
+MK_STATS_GET_METRIC_FN(average_rd_wait_time, AVERAGE_RD_WAIT_TIME, await)
+MK_STATS_GET_METRIC_FN(average_wr_wait_time, AVERAGE_WR_WAIT_TIME, await)
+MK_STATS_GET_METRIC_FN(service_time, SERVICE_TIME, svctm)
+MK_STATS_GET_METRIC_FN(throughput, THROUGHPUT, tput)
+
+/*
+ * Utilization is an exception since it used the dm_percent_t type in the
+ * original named function based interface: preserve this behaviour for
+ * backwards compatibility with existing users.
+ *
+ * The same metric may be accessed as a double via the enum based metric
+ * interface.
+ */
int dm_stats_get_utilization(const struct dm_stats *dms, dm_percent_t *util,
uint64_t region_id, uint64_t area_id)
{
- struct dm_stats_counters *c;
- uint64_t io_nsecs;
+ double _util;
- if (!dms->interval_ns)
+ if (!dm_stats_get_metric(dms, DM_STATS_UTILIZATION,
+ region_id, area_id, &_util))
return_0;
-
- region_id = (region_id == DM_STATS_REGION_CURRENT)
- ? dms->cur_region : region_id ;
- area_id = (area_id == DM_STATS_REGION_CURRENT)
- ? dms->cur_area : area_id ;
-
- c = &(dms->regions[region_id].counters[area_id]);
-
- /**
- * If io_nsec > interval_ns there is something wrong with the clock
- * for the last interval; do not allow a value > 100% utilization
- * to be passed to a dm_make_percent() call. We expect to see these
- * at startup if counters have not been cleared before the first read.
- */
- io_nsecs = (c->io_nsecs <= dms->interval_ns) ? c->io_nsecs : dms->interval_ns;
- *util = dm_make_percent(io_nsecs, dms->interval_ns);
-
+ /* scale up utilization value in the range [0.00..1.00] */
+ *util = dm_make_percent(DM_PERCENT_1 * _util, DM_PERCENT_1);
return 1;
}
7 years, 9 months
master - libdm: cache dm name in stats handle
by Bryn Reeves
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=69f808ac8d25e3...
Commit: 69f808ac8d25e3c7ef39bd2de66fed1efd290bbe
Parent: 4a66f02f8876edf6bbbc127d2888a0f50f8be611
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Fri Jun 17 12:17:33 2016 +0100
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Tue Jul 5 19:53:16 2016 +0100
libdm: cache dm name in stats handle
Cache the device-mapper name of a bound device in the dm_stats
handle.
This will be used by stats groups to report a device name or
user defined alias for groups.
---
libdm/libdm-stats.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 44 insertions(+), 0 deletions(-)
diff --git a/libdm/libdm-stats.c b/libdm/libdm-stats.c
index 58f8951..99e4d72 100644
--- a/libdm/libdm-stats.c
+++ b/libdm/libdm-stats.c
@@ -81,6 +81,7 @@ struct dm_stats {
char *bind_name; /* device-mapper device name */
char *bind_uuid; /* device-mapper UUID */
char *program_id; /* default program_id for this handle */
+ const char *name; /* cached device_name used for reporting */
struct dm_pool *mem; /* memory pool for region and counter tables */
struct dm_pool *hist_mem; /* separate pool for histogram tables */
uint64_t nr_regions; /* total number of present regions */
@@ -167,6 +168,8 @@ struct dm_stats *dm_stats_create(const char *program_id)
dms->bind_name = NULL;
dms->bind_uuid = NULL;
+ dms->name = NULL;
+
/* by default all regions use msec precision */
dms->timescale = NSEC_PER_MSEC;
dms->precise = 0;
@@ -267,9 +270,12 @@ static void _stats_clear_binding(struct dm_stats *dms)
dm_pool_free(dms->mem, dms->bind_name);
if (dms->bind_uuid)
dm_pool_free(dms->mem, dms->bind_uuid);
+ if (dms->name)
+ dm_free((char *) dms->name);
dms->bind_name = dms->bind_uuid = NULL;
dms->bind_major = dms->bind_minor = -1;
+ dms->name = NULL;
}
int dm_stats_bind_devno(struct dm_stats *dms, int major, int minor)
@@ -446,6 +452,38 @@ bad:
}
/*
+ * Cache the dm device_name for the device bound to dms.
+ */
+static int _stats_set_name_cache(struct dm_stats *dms)
+{
+ struct dm_task *dmt;
+
+ if (dms->name)
+ return 1;
+
+ if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
+ return_0;
+
+ if (!_set_stats_device(dms, dmt))
+ goto_bad;
+
+ if (!dm_task_run(dmt))
+ goto_bad;
+
+ if (!(dms->name = dm_strdup(dm_task_get_name(dmt))))
+ goto_bad;
+
+ dm_task_destroy(dmt);
+
+ return 1;
+
+bad:
+ log_error("Could not retrieve device-mapper name for device.");
+ dm_task_destroy(dmt);
+ return 0;
+}
+
+/*
* Parse a histogram specification returned by the kernel in a
* @stats_list response.
*/
@@ -714,6 +752,9 @@ int dm_stats_list(struct dm_stats *dms, const char *program_id)
if (!program_id)
program_id = dms->program_id;
+ if (!_stats_set_name_cache(dms))
+ return_0;
+
r = dm_snprintf(msg, sizeof(msg), "@stats_list %s", program_id);
if (r < 0) {
@@ -1347,6 +1388,8 @@ int dm_stats_populate(struct dm_stats *dms, const char *program_id,
if (all_regions && !dm_stats_list(dms, program_id)) {
log_error("Could not parse @stats_list response.");
goto bad;
+ } else if (!_stats_set_name_cache(dms)) {
+ goto_bad;
}
/* successful list but no regions registered */
@@ -1391,6 +1434,7 @@ void dm_stats_destroy(struct dm_stats *dms)
dm_pool_destroy(dms->mem);
dm_pool_destroy(dms->hist_mem);
dm_free(dms->program_id);
+ dm_free((char *) dms->name);
dm_free(dms);
}
7 years, 9 months
master - libdm: fix histogram pool user-after-free (CWE-825)
by Bryn Reeves
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=d382e660356f10...
Commit: d382e660356f1095040b8a84b54a0c1db0ab78b1
Parent: 4420d41fea8f772dcaef07660e7cff0cbb32d6b3
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Mon Jul 4 18:20:09 2016 +0100
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Tue Jul 5 19:53:15 2016 +0100
libdm: fix histogram pool user-after-free (CWE-825)
---
libdm/libdm-stats.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/libdm/libdm-stats.c b/libdm/libdm-stats.c
index f1c0560..3d53755 100644
--- a/libdm/libdm-stats.c
+++ b/libdm/libdm-stats.c
@@ -158,8 +158,8 @@ struct dm_stats *dm_stats_create(const char *program_id)
dms->program_id = dm_strdup(program_id);
if (!dms->program_id) {
- dm_pool_destroy(dms->hist_mem);
- goto_bad;
+ log_error("Could not allocate memory for program_id");
+ goto bad;
}
dms->major = -1;
7 years, 9 months
master - vgsplit: fix moving RAID LVs to split off VG and check for LVs not to skip moving with other LV types
by Alasdair Kergon
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=4420d41fea8f77...
Commit: 4420d41fea8f772dcaef07660e7cff0cbb32d6b3
Parent: e5d1f3d6c5433e8b118e572a507f121c45729715
Author: Heinz Mauelshagen <heinzm(a)redhat.com>
AuthorDate: Tue Jul 5 15:39:57 2016 +0200
Committer: Alasdair G Kergon <agk(a)redhat.com>
CommitterDate: Tue Jul 5 19:49:44 2016 +0100
vgsplit: fix moving RAID LVs to split off VG and check for LVs not to skip moving with other LV types
---
tools/vgsplit.c | 132 +++++++++++++++++++++++++++++++++++++++++--------------
1 files changed, 99 insertions(+), 33 deletions(-)
diff --git a/tools/vgsplit.c b/tools/vgsplit.c
index 6114a72..afe87af 100644
--- a/tools/vgsplit.c
+++ b/tools/vgsplit.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2009,2016 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -23,9 +23,46 @@ static int _lv_is_in_vg(struct volume_group *vg, struct logical_volume *lv)
return 1;
}
+static struct dm_list *_lvh_in_vg(struct logical_volume *lv, struct volume_group *vg)
+{
+ struct dm_list *lvh;
+
+ dm_list_iterate(lvh, &vg->lvs)
+ if (lv == dm_list_item(lvh, struct lv_list)->lv)
+ return lvh;
+
+ return NULL;
+}
+
+static int _lv_tree_move(struct dm_list *lvh,
+ struct volume_group *vg_from,
+ struct volume_group *vg_to)
+{
+ uint32_t s;
+ struct logical_volume *lv = dm_list_item(lvh, struct lv_list)->lv;
+ struct lv_segment *seg = first_seg(lv);
+ struct dm_list *lvh1;
+
+ dm_list_move(&vg_to->lvs, lvh);
+ lv->vg = vg_to;
+ lv->lvid.id[0] = lv->vg->id;
+
+ if (seg)
+ for (s = 0; s < seg->area_count; s++)
+ if (seg_type(seg, s) == AREA_LV && seg_lv(seg, s)) {
+ if ((lvh1 = _lvh_in_vg(seg_lv(seg, s), vg_from))) {
+ if (!_lv_tree_move(lvh1, vg_from, vg_to))
+ return 0;
+ } else if (!_lvh_in_vg(seg_lv(seg, s), vg_to))
+ return 0;
+ }
+
+ return 1;
+}
+
static int _move_one_lv(struct volume_group *vg_from,
- struct volume_group *vg_to,
- struct dm_list *lvh)
+ struct volume_group *vg_to,
+ struct dm_list *lvh)
{
struct logical_volume *lv = dm_list_item(lvh, struct lv_list)->lv;
struct logical_volume *parent_lv;
@@ -38,10 +75,15 @@ static int _move_one_lv(struct volume_group *vg_from,
return 0;
}
- dm_list_move(&vg_to->lvs, lvh);
- lv->vg = vg_to;
+ /* Bail out, if any allocations of @lv are still on PVs of @vg_from */
+ if (lv_is_on_pvs(lv, &vg_from->pvs)) {
+ log_error("Can't split LV %s between "
+ "two Volume Groups", lv->name);
+ return 0;
+ }
- lv->lvid.id[0] = lv->vg->id;
+ if (!_lv_tree_move(lvh, vg_from, vg_to))
+ return 0;
/* Moved pool metadata spare LV */
if (vg_from->pool_metadata_spare_lv == lv) {
@@ -148,6 +190,10 @@ static int _move_snapshots(struct volume_group *vg_from,
if (!(lv->status & SNAPSHOT))
continue;
+ /* Ignore, if no allocations on PVs of @vg_to */
+ if (!lv_is_on_pvs(lv, &vg_to->pvs))
+ continue;
+
dm_list_iterate_items(seg, &lv->segments) {
cow_from = _lv_is_in_vg(vg_from, seg->cow);
origin_from = _lv_is_in_vg(vg_from, seg->origin);
@@ -194,6 +240,10 @@ static int _move_mirrors(struct volume_group *vg_from,
if (!lv_is_mirrored(lv))
continue;
+ /* Ignore, if no allocations on PVs of @vg_to */
+ if (!lv_is_on_pvs(lv, &vg_to->pvs))
+ continue;
+
seg = first_seg(lv);
seg_in = 0;
@@ -233,13 +283,18 @@ static int _move_mirrors(struct volume_group *vg_from,
return 1;
}
-static int _move_raid(struct volume_group *vg_from,
- struct volume_group *vg_to)
+/*
+ * Check for any RAID LVs with allocations on PVs of @vg_to.
+ *
+ * If these don't have any allocations on PVs of @vg_from,
+ * move their whole lv stack across to @vg_to including the
+ * top-level RAID LV.
+ */
+static int _move_raids(struct volume_group *vg_from,
+ struct volume_group *vg_to)
{
struct dm_list *lvh, *lvht;
struct logical_volume *lv;
- struct lv_segment *seg;
- unsigned s, seg_in;
dm_list_iterate_safe(lvh, lvht, &vg_from->lvs) {
lv = dm_list_item(lvh, struct lv_list)->lv;
@@ -247,22 +302,11 @@ static int _move_raid(struct volume_group *vg_from,
if (!lv_is_raid(lv))
continue;
- seg = first_seg(lv);
-
- seg_in = 0;
- for (s = 0; s < seg->area_count; s++) {
- if (_lv_is_in_vg(vg_to, seg_lv(seg, s)))
- seg_in++;
- if (seg->meta_areas && seg_metalv(seg, s) && _lv_is_in_vg(vg_to, seg_metalv(seg, s)))
- seg_in++; /* FIXME Inadequate - must count separately */
- }
-
- if (seg_in && seg_in != (seg->area_count * (seg->meta_areas ? 2 : 1))) {
- log_error("Can't split RAID %s between "
- "two Volume Groups", lv->name);
- return 0;
- }
-
+ /* Ignore, if no allocations on PVs of @vg_to */
+ if (!lv_is_on_pvs(lv, &vg_to->pvs))
+ continue;
+
+ /* If allocations are on PVs of @vg_to -> move RAID LV stack across */
if (!_move_one_lv(vg_from, vg_to, lvh))
return_0;
}
@@ -283,6 +327,11 @@ static int _move_thins(struct volume_group *vg_from,
if (lv_is_thin_volume(lv)) {
seg = first_seg(lv);
data_lv = seg_lv(first_seg(seg->pool_lv), 0);
+
+ /* Ignore, if no allocations on PVs of @vg_to */
+ if (!lv_is_on_pvs(data_lv, &vg_to->pvs))
+ continue;
+
if ((_lv_is_in_vg(vg_to, data_lv) ||
_lv_is_in_vg(vg_to, seg->external_lv))) {
if (_lv_is_in_vg(vg_from, seg->external_lv) ||
@@ -299,6 +348,11 @@ static int _move_thins(struct volume_group *vg_from,
} else if (lv_is_thin_pool(lv)) {
seg = first_seg(lv);
data_lv = seg_lv(seg, 0);
+
+ /* Ignore, if no allocations on PVs of @vg_to */
+ if (!lv_is_on_pvs(data_lv, &vg_to->pvs))
+ continue;
+
if (_lv_is_in_vg(vg_to, data_lv) ||
_lv_is_in_vg(vg_to, seg->metadata_lv)) {
if (_lv_is_in_vg(vg_from, seg->metadata_lv) ||
@@ -364,6 +418,12 @@ static int _move_cache(struct volume_group *vg_from,
is_moving = 1;
}
+ if (!lv_is_on_pvs(data, &vg_to->pvs))
+ continue;
+
+ if (!lv_is_on_pvs(meta, &vg_to->pvs))
+ continue;
+
if (orig && (_lv_is_in_vg(vg_to, orig) != is_moving)) {
log_error("Can't split %s and its origin (%s)"
" into separate VGs", lv->name, orig->name);
@@ -601,13 +661,19 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
if (lv_name && !move_pvs_used_by_lv(vg_from, vg_to, lv_name))
goto_bad;
- /* Move required LVs across, checking consistency */
- if (!(_move_lvs(vg_from, vg_to)))
+ /*
+ * First move any required RAID LVs across recursively.
+ * Reject if they get split between VGs.
+ *
+ * This moves the whole LV stack across, thus _move_lvs() below
+ * ain't hit any of their MetaLVs/DataLVs any more but'll still
+ * work for all other type specific moves following it.
+ */
+ if (!(_move_raids(vg_from, vg_to)))
goto_bad;
- /* FIXME Separate the 'move' from the 'validation' to fix dev stacks */
- /* Move required RAID across */
- if (!(_move_raid(vg_from, vg_to)))
+ /* Move required sub LVs across, checking consistency */
+ if (!(_move_lvs(vg_from, vg_to)))
goto_bad;
/* Move required mirrors across */
@@ -641,8 +707,8 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
/*
* First, write out the new VG as EXPORTED. We do this first in case
* there is a crash - we will still have the new VG information, in an
- * exported state. Recovery after this point would be removal of the
- * new VG and redoing the vgsplit.
+ * exported state. Recovery after this point would importing and removal
+ * of the new VG and redoing the vgsplit.
* FIXME: recover automatically or instruct the user?
*/
vg_to->status |= EXPORTED_VG;
7 years, 9 months
master - dmstats: fix <backtrace> in _display_info_cols()
by Bryn Reeves
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=3b6f7f00f725bc...
Commit: 3b6f7f00f725bc01d27796217cc53d77d5f42d31
Parent: 42746c70262d8999d7780410553c64b769fca2ce
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Tue Jul 5 18:42:29 2016 +0100
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Tue Jul 5 19:29:51 2016 +0100
dmstats: fix <backtrace> in _display_info_cols()
Remove a false <backtrace> in _display_info_cols(): it is not an
error if there are no regions to display.
Fixes commit e6724f03.
---
tools/dmsetup.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/tools/dmsetup.c b/tools/dmsetup.c
index 3ee9ed8..ed03c2b 100644
--- a/tools/dmsetup.c
+++ b/tools/dmsetup.c
@@ -884,9 +884,9 @@ static int _display_info_cols(struct dm_task *dmt, struct dm_info *info)
if (!dm_stats_list(obj.stats, _program_id))
goto_out;
- /* No regions to report */
+ /* No regions to report is not an error */
if (!dm_stats_get_nr_regions(obj.stats))
- goto_out;
+ goto out;
}
/* group report with no groups? */
7 years, 9 months
master - libdm: fix <backtrace> in dm_stats_get_nr_regions
by Bryn Reeves
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=a9f1278b55b406...
Commit: a9f1278b55b406de66cde0f26b77cbcf1f3796d1
Parent: ced707df28a5950c26af9d5529a3c05e10bf217e
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Tue Jul 5 18:33:02 2016 +0100
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Tue Jul 5 19:29:51 2016 +0100
libdm: fix <backtrace> in dm_stats_get_nr_regions
---
libdm/libdm-stats.c | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/libdm/libdm-stats.c b/libdm/libdm-stats.c
index 93b8e0b..ab15589 100644
--- a/libdm/libdm-stats.c
+++ b/libdm/libdm-stats.c
@@ -2132,8 +2132,12 @@ void dm_stats_buffer_destroy(struct dm_stats *dms, char *buffer)
uint64_t dm_stats_get_nr_regions(const struct dm_stats *dms)
{
- if (!dms || !dms->regions)
+ if (!dms)
return_0;
+
+ if (!dms->regions)
+ return 0;
+
return dms->nr_regions;
}
7 years, 9 months
master - libdm: clarify library's use of aux_data
by Bryn Reeves
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=d4d9da6207a144...
Commit: d4d9da6207a144a43ae8d441da5f8caed2285f5a
Parent: 6d374475ce6b9b8485b33c7ca7d4ae18e97a8c11
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Tue Jul 5 15:17:44 2016 +0100
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Tue Jul 5 19:29:51 2016 +0100
libdm: clarify library's use of aux_data
Make it clear in libdevmapper.h, and in function argument names, that
libdm-stats uses the aux_data field internally and that any values set
for user_data are appended to the library values before being stored
with a region, and similarly, that internal data fields will be stripped
prior to returning any previously stored user_data.
---
libdm/libdevmapper.h | 58 +++++++++++++++++++++++++++++++++++++++----------
libdm/libdm-stats.c | 4 +-
2 files changed, 48 insertions(+), 14 deletions(-)
diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h
index 2fd8061..e769be2 100644
--- a/libdm/libdevmapper.h
+++ b/libdm/libdevmapper.h
@@ -638,9 +638,24 @@ int dm_stats_populate(struct dm_stats *dms, const char *program_id,
* program creating the region. If program_id is NULL or the empty
* string the default program_id stored in the handle will be used.
*
- * aux_data is an optional string argument passed to the kernel that is
- * stored with the statistics region. It is not currently accessed by
- * the library or kernel and may be used to store arbitrary user data.
+ * user_data is an optional string argument that is added to the
+ * content of the aux_data field stored with the statistics region by
+ * the kernel.
+ *
+ * The library may also use this space internally, for example, to
+ * store a group descriptor or other metadata: in this case the
+ * library will strip any internal data fields from the value before
+ * it is returned via a call to dm_stats_get_region_aux_data().
+ *
+ * The user data stored is not accessed by the library or kernel and
+ * may be used to store an arbitrary data word (embedded whitespace is
+ * not permitted).
+ *
+ * An application using both the library and direct access to the
+ * @stats_list device-mapper message may see the internal values stored
+ * in this field by the library. In such cases any string up to and
+ * including the first '#' in the field must be treated as an opaque
+ * value and preserved across any external modification of aux_data.
*
* The region_id of the newly-created region is returned in *region_id
* if it is non-NULL.
@@ -648,7 +663,7 @@ int dm_stats_populate(struct dm_stats *dms, const char *program_id,
int dm_stats_create_region(struct dm_stats *dms, uint64_t *region_id,
uint64_t start, uint64_t len, int64_t step,
int precise, struct dm_histogram *bounds,
- const char *program_id, const char *aux_data);
+ const char *program_id, const char *user_data);
/*
* Delete the specified statistics region. This will also mark the
@@ -922,16 +937,35 @@ int dm_stats_get_area_offset(const struct dm_stats *dms, uint64_t *offset,
uint64_t region_id, uint64_t area_id);
/*
- * Retrieve program_id and aux_data for a specific region. Only valid
- * following a call to dm_stats_list(). The returned pointer does not
- * need to be freed separately from the dm_stats handle but will become
- * invalid after a dm_stats_destroy(), dm_stats_list(),
- * dm_stats_populate(), or dm_stats_bind*() of the handle from which it
- * was obtained.
+ * Retrieve program_id and user aux_data for a specific region.
+ *
+ * Only valid following a call to dm_stats_list().
+ */
+
+/*
+ * Retrieve program_id for the specified region.
+ *
+ * The returned pointer does not need to be freed separately from the
+ * dm_stats handle but will become invalid after a dm_stats_destroy(),
+ * dm_stats_list(), dm_stats_populate(), or dm_stats_bind*() of the
+ * handle from which it was obtained.
*/
const char *dm_stats_get_region_program_id(const struct dm_stats *dms,
uint64_t region_id);
+/*
+ * Retrieve user aux_data set for the specified region. This function
+ * will return any stored user aux_data as a string in the memory
+ * pointed to by the aux_data argument.
+ *
+ * Any library internal aux_data fields, such as DMS_GROUP descriptors,
+ * are stripped before the value is returned.
+ *
+ * The returned pointer does not need to be freed separately from the
+ * dm_stats handle but will become invalid after a dm_stats_destroy(),
+ * dm_stats_list(), dm_stats_populate(), or dm_stats_bind*() of the
+ * handle from which it was obtained.
+ */
const char *dm_stats_get_region_aux_data(const struct dm_stats *dms,
uint64_t region_id);
@@ -1184,8 +1218,8 @@ int dm_stats_get_current_area_len(const struct dm_stats *dms,
const char *dm_stats_get_current_region_program_id(const struct dm_stats *dms);
/*
- * Return a pointer to the aux_data string for the region at the current
- * cursor location.
+ * Return a pointer to the user aux_data string for the region at the
+ * current cursor location.
*/
const char *dm_stats_get_current_region_aux_data(const struct dm_stats *dms);
diff --git a/libdm/libdm-stats.c b/libdm/libdm-stats.c
index e1f05c7..93b8e0b 100644
--- a/libdm/libdm-stats.c
+++ b/libdm/libdm-stats.c
@@ -1930,7 +1930,7 @@ out:
int dm_stats_create_region(struct dm_stats *dms, uint64_t *region_id,
uint64_t start, uint64_t len, int64_t step,
int precise, struct dm_histogram *bounds,
- const char *program_id, const char *aux_data)
+ const char *program_id, const char *user_data)
{
char *hist_arg = NULL;
int r = 0;
@@ -1946,7 +1946,7 @@ int dm_stats_create_region(struct dm_stats *dms, uint64_t *region_id,
}
r = _stats_create_region(dms, region_id, start, len, step,
- precise, hist_arg, program_id, aux_data);
+ precise, hist_arg, program_id, user_data);
dm_free(hist_arg);
out:
7 years, 9 months