mirror of
				git://sourceware.org/git/lvm2.git
				synced 2025-11-04 12:23:49 +03:00 
			
		
		
		
	Compare commits
	
		
			41 Commits
		
	
	
		
			v2_03_01
			...
			dev-bmr-dm
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					73111bf33b | ||
| 
						 | 
					3b6f7f00f7 | ||
| 
						 | 
					42746c7026 | ||
| 
						 | 
					a9f1278b55 | ||
| 
						 | 
					ced707df28 | ||
| 
						 | 
					6fb39fce21 | ||
| 
						 | 
					d4d9da6207 | ||
| 
						 | 
					6d374475ce | ||
| 
						 | 
					cc6177284a | ||
| 
						 | 
					c2e043f0c1 | ||
| 
						 | 
					59a3705577 | ||
| 
						 | 
					76f7f28dac | ||
| 
						 | 
					c54da5e82a | ||
| 
						 | 
					4b02aa2548 | ||
| 
						 | 
					e69a34c15e | ||
| 
						 | 
					3914229d60 | ||
| 
						 | 
					e25c27e5c2 | ||
| 
						 | 
					4ebc6b75cb | ||
| 
						 | 
					b7cd377915 | ||
| 
						 | 
					8dffd6d217 | ||
| 
						 | 
					d94c956903 | ||
| 
						 | 
					3626cf025d | ||
| 
						 | 
					65606c90d9 | ||
| 
						 | 
					973ad7434e | ||
| 
						 | 
					14868633cc | ||
| 
						 | 
					5160936b15 | ||
| 
						 | 
					d6aea67a17 | ||
| 
						 | 
					a7ff854ec8 | ||
| 
						 | 
					abb499c1c2 | ||
| 
						 | 
					728949c7bb | ||
| 
						 | 
					9420f82485 | ||
| 
						 | 
					f6a999b437 | ||
| 
						 | 
					ea2fb03750 | ||
| 
						 | 
					f883bca41b | ||
| 
						 | 
					7145d666fc | ||
| 
						 | 
					f3afd1bd13 | ||
| 
						 | 
					b1b32c900a | ||
| 
						 | 
					7cec710e37 | ||
| 
						 | 
					6c86d94219 | ||
| 
						 | 
					05196373be | ||
| 
						 | 
					82f4f073bb | 
							
								
								
									
										15
									
								
								WHATS_NEW_DM
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								WHATS_NEW_DM
									
									
									
									
									
								
							@@ -1,5 +1,20 @@
 | 
			
		||||
Version 1.02.129 - 
 | 
			
		||||
=================================
 | 
			
		||||
  Update default dmstats field selections for groups.
 | 
			
		||||
  Add 'obj_type', 'group_id', and 'statsname' fields to dmstats reports.
 | 
			
		||||
  Add --area, --region, and --group to dmstats to control object selection.
 | 
			
		||||
  Add --alias, --groupid, --regions to dmstats for group creation and deletion.
 | 
			
		||||
  Add 'group' and 'ungroup' commands to dmstats.
 | 
			
		||||
  Allow dm_stats_delete_group() to optionally delete all group members.
 | 
			
		||||
  Add dm_stats_get_object_type() to return the type of object present.
 | 
			
		||||
  Add dm_stats_walk_init() allowing control of objects visited by walks.
 | 
			
		||||
  Add dm_stats_get_group_descriptor() to return the member list as a string.
 | 
			
		||||
  Introduce dm_stats_get_nr_groups() and dm_stats_group_present().
 | 
			
		||||
  Add dm_stats_{get,set}_alias() to set and retrieve alias names for groups.
 | 
			
		||||
  Add dm_stats_get_group_id() to return the group ID for a given region.
 | 
			
		||||
  Add dm_stats_{create,delete}_group() to allow grouping of stats regions.
 | 
			
		||||
  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.
 | 
			
		||||
 | 
			
		||||
Version 1.02.128 - 25th June 2016
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										14
									
								
								libdm/.exported_symbols.DM_1_02_129
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								libdm/.exported_symbols.DM_1_02_129
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
dm_bitset_parse_list
 | 
			
		||||
dm_stats_create_group
 | 
			
		||||
dm_stats_current_object_type
 | 
			
		||||
dm_stats_delete_group
 | 
			
		||||
dm_stats_get_alias
 | 
			
		||||
dm_stats_get_counter
 | 
			
		||||
dm_stats_get_group_descriptor
 | 
			
		||||
dm_stats_get_group_id
 | 
			
		||||
dm_stats_get_metric
 | 
			
		||||
dm_stats_get_nr_groups
 | 
			
		||||
dm_stats_group_present
 | 
			
		||||
dm_stats_object_type
 | 
			
		||||
dm_stats_set_alias
 | 
			
		||||
dm_stats_walk_init
 | 
			
		||||
@@ -15,6 +15,8 @@
 | 
			
		||||
 | 
			
		||||
#include "dmlib.h"
 | 
			
		||||
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
 | 
			
		||||
/* FIXME: calculate this. */
 | 
			
		||||
#define INT_SHIFT 5
 | 
			
		||||
 | 
			
		||||
@@ -103,3 +105,99 @@ int dm_bit_get_first(dm_bitset_t bs)
 | 
			
		||||
{
 | 
			
		||||
	return dm_bit_get_next(bs, -1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Based on the Linux kernel __bitmap_parselist from lib/bitmap.c
 | 
			
		||||
 */
 | 
			
		||||
dm_bitset_t dm_bitset_parse_list(const char *str, struct dm_pool *mem)
 | 
			
		||||
{
 | 
			
		||||
	unsigned a, b;
 | 
			
		||||
	int c, old_c, totaldigits, ndigits, nmaskbits;
 | 
			
		||||
	int at_start, in_range;
 | 
			
		||||
	dm_bitset_t mask = NULL;
 | 
			
		||||
	const char *start = str;
 | 
			
		||||
	size_t len;
 | 
			
		||||
 | 
			
		||||
scan:
 | 
			
		||||
	len = strlen(str);
 | 
			
		||||
	totaldigits = c = 0;
 | 
			
		||||
	nmaskbits = 0;
 | 
			
		||||
	do {
 | 
			
		||||
		at_start = 1;
 | 
			
		||||
		in_range = 0;
 | 
			
		||||
		a = b = 0;
 | 
			
		||||
		ndigits = totaldigits;
 | 
			
		||||
 | 
			
		||||
		/* Get the next value or range of values */
 | 
			
		||||
		while (len) {
 | 
			
		||||
			old_c = c;
 | 
			
		||||
			c = *str++;
 | 
			
		||||
			len--;
 | 
			
		||||
			if (isspace(c))
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			/* A '\0' or a ',' signal the end of a value or range */
 | 
			
		||||
			if (c == '\0' || c == ',')
 | 
			
		||||
				break;
 | 
			
		||||
			/*
 | 
			
		||||
			* whitespaces between digits are not allowed,
 | 
			
		||||
			* but it's ok if whitespaces are on head or tail.
 | 
			
		||||
			* when old_c is whilespace,
 | 
			
		||||
			* if totaldigits == ndigits, whitespace is on head.
 | 
			
		||||
			* if whitespace is on tail, it should not run here.
 | 
			
		||||
			* as c was ',' or '\0',
 | 
			
		||||
			* the last code line has broken the current loop.
 | 
			
		||||
			*/
 | 
			
		||||
			if ((totaldigits != ndigits) && isspace(old_c))
 | 
			
		||||
				goto_bad;
 | 
			
		||||
 | 
			
		||||
			if (c == '-') {
 | 
			
		||||
				if (at_start || in_range)
 | 
			
		||||
					return_0;
 | 
			
		||||
				b = 0;
 | 
			
		||||
				in_range = 1;
 | 
			
		||||
				at_start = 1;
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (!isdigit(c))
 | 
			
		||||
				goto_bad;
 | 
			
		||||
 | 
			
		||||
			b = b * 10 + (c - '0');
 | 
			
		||||
			if (!in_range)
 | 
			
		||||
				a = b;
 | 
			
		||||
			at_start = 0;
 | 
			
		||||
			totaldigits++;
 | 
			
		||||
		}
 | 
			
		||||
		if (ndigits == totaldigits)
 | 
			
		||||
			continue;
 | 
			
		||||
		/* if no digit is after '-', it's wrong */
 | 
			
		||||
		if (at_start && in_range)
 | 
			
		||||
			goto_bad;
 | 
			
		||||
		if (!(a <= b))
 | 
			
		||||
			goto_bad;
 | 
			
		||||
		if (b >= nmaskbits)
 | 
			
		||||
			nmaskbits = b + 1;
 | 
			
		||||
		while ((a <= b) && mask) {
 | 
			
		||||
			dm_bit_set(mask, a);
 | 
			
		||||
			a++;
 | 
			
		||||
		}
 | 
			
		||||
	} while (len && c == ',');
 | 
			
		||||
 | 
			
		||||
	if (!mask) {
 | 
			
		||||
		if (!(mask = dm_bitset_create(mem, nmaskbits)))
 | 
			
		||||
			goto_bad;
 | 
			
		||||
		str = start;
 | 
			
		||||
		goto scan;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return mask;
 | 
			
		||||
bad:
 | 
			
		||||
	if (mask) {
 | 
			
		||||
		if (mem)
 | 
			
		||||
			dm_pool_free(mem, mask);
 | 
			
		||||
		else
 | 
			
		||||
			dm_bitset_destroy(mask);
 | 
			
		||||
	}
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
@@ -714,6 +729,19 @@ void dm_stats_buffer_destroy(struct dm_stats *dms, char *buffer);
 | 
			
		||||
 */
 | 
			
		||||
uint64_t dm_stats_get_nr_regions(const struct dm_stats *dms);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Determine the number of groups contained in a dm_stats handle
 | 
			
		||||
 * following a dm_stats_list() or dm_stats_populate() call.
 | 
			
		||||
 *
 | 
			
		||||
 * The value returned is the number of registered groups visible with the
 | 
			
		||||
 * progam_id value used for the list or populate operation and may not be
 | 
			
		||||
 * equal to the highest present group_id (either due to program_id
 | 
			
		||||
 * filtering or gaps in the sequence of group_id values).
 | 
			
		||||
 *
 | 
			
		||||
 * Always returns zero on an empty handle.
 | 
			
		||||
 */
 | 
			
		||||
uint64_t dm_stats_get_nr_groups(const struct dm_stats *dms);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Test whether region_id is present in this dm_stats handle.
 | 
			
		||||
 */
 | 
			
		||||
@@ -732,6 +760,11 @@ uint64_t dm_stats_get_region_nr_areas(const struct dm_stats *dms,
 | 
			
		||||
 */
 | 
			
		||||
uint64_t dm_stats_get_nr_areas(const struct dm_stats *dms);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Test whether group_id is present in this dm_stats handle.
 | 
			
		||||
 */
 | 
			
		||||
int dm_stats_group_present(const struct dm_stats *dms, uint64_t group_id);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Return the number of bins in the histogram configuration for the
 | 
			
		||||
 * specified region or zero if no histogram specification is configured.
 | 
			
		||||
@@ -904,51 +937,129 @@ 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);
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
	DM_STATS_OBJECT_TYPE_NONE,
 | 
			
		||||
	DM_STATS_OBJECT_TYPE_AREA,
 | 
			
		||||
	DM_STATS_OBJECT_TYPE_REGION,
 | 
			
		||||
	DM_STATS_OBJECT_TYPE_GROUP
 | 
			
		||||
} dm_stats_obj_type_t;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Statistics cursor
 | 
			
		||||
 *
 | 
			
		||||
 * A dm_stats handle maintains an optional cursor into the statistics
 | 
			
		||||
 * regions and areas that it stores. Iterators are provided to visit
 | 
			
		||||
 * each region, or each area in a handle and accessor methods are
 | 
			
		||||
 * provided to obtain properties and values for the region or area
 | 
			
		||||
 * at the current cursor position.
 | 
			
		||||
 * tables that it stores. Iterators are provided to visit each region,
 | 
			
		||||
 * area, or group in a handle and accessor methods are provided to
 | 
			
		||||
 * obtain properties and values for the object at the current cursor
 | 
			
		||||
 * position.
 | 
			
		||||
 *
 | 
			
		||||
 * Using the cursor simplifies walking all regions or areas when the
 | 
			
		||||
 * region table is sparse (i.e. contains some present and some
 | 
			
		||||
 * non-present region_id values either due to program_id filtering
 | 
			
		||||
 * or the ordering of region creation and deletion).
 | 
			
		||||
 * Using the cursor simplifies walking all regions or groups when
 | 
			
		||||
 * the tables are sparse (i.e. contains some present and some
 | 
			
		||||
 * non-present region_id or group_id values either due to program_id
 | 
			
		||||
 * filtering or the ordering of region and group creation and deletion).
 | 
			
		||||
 *
 | 
			
		||||
 * Simple macros are provided to visit each area, region, or group,
 | 
			
		||||
 * contained in a handle and applications are encouraged to use these
 | 
			
		||||
 * where possible.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Initialise the cursor of a dm_stats handle to address the first
 | 
			
		||||
 * present region. It is valid to attempt to walk a NULL stats handle
 | 
			
		||||
 * or a handle containing no present regions; in this case any call to
 | 
			
		||||
 * dm_stats_walk_next() becomes a no-op and all calls to
 | 
			
		||||
 * dm_stats_walk_end() return true.
 | 
			
		||||
 * Walk flags are used to initialise a dm_stats handle's cursor control
 | 
			
		||||
 * and to select region or group aggregation when calling a metric or
 | 
			
		||||
 * counter property method with immediate group, region, and area ID
 | 
			
		||||
 * values.
 | 
			
		||||
 *
 | 
			
		||||
 * Walk flags are stored in the uppermost word of a uint64_t so that
 | 
			
		||||
 * a region_id or group_id may be encoded in the lower bits. This
 | 
			
		||||
 * allows an aggregate region_id or group_id to be specified when
 | 
			
		||||
 * retrieving counter or metric values.
 | 
			
		||||
 *
 | 
			
		||||
 * Flags may be ORred together when used to initialise a dm_stats_walk:
 | 
			
		||||
 * the resulting walk will visit instance of each type specified by
 | 
			
		||||
 * the flag combination.
 | 
			
		||||
 */
 | 
			
		||||
#define DM_STATS_WALK_AREA   0x1000000000000
 | 
			
		||||
#define DM_STATS_WALK_REGION 0x2000000000000
 | 
			
		||||
#define DM_STATS_WALK_GROUP  0x4000000000000
 | 
			
		||||
 | 
			
		||||
#define DM_STATS_WALK_ALL    0x7000000000000
 | 
			
		||||
#define DM_STATS_WALK_DEFAULT (DM_STATS_WALK_AREA | DM_STATS_WALK_REGION)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Skip regions from a DM_STATS_WALK_REGION that contain only a single
 | 
			
		||||
 * area: in this case the region's aggregate values are identical to
 | 
			
		||||
 * the values of the single contained area. Setting this flag will
 | 
			
		||||
 * suppress these duplicate entries during a dm_stats_walk_* with the
 | 
			
		||||
 * DM_STATS_WALK_REGION flag set.
 | 
			
		||||
 */
 | 
			
		||||
#define DM_STATS_WALK_SKIP_SINGLE_AREA   0x8000000000000
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Initialise the cursor control of a dm_stats handle for the specified
 | 
			
		||||
 * walk type(s). Including a walk flag in the flags argument will cause
 | 
			
		||||
 * any subsequent walk to visit that type of object (until the next
 | 
			
		||||
 * call to dm_stats_walk_init()).
 | 
			
		||||
 */
 | 
			
		||||
int dm_stats_walk_init(struct dm_stats *dms, uint64_t flags);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Set the cursor of a dm_stats handle to address the first present
 | 
			
		||||
 * group, region, or area of the currently configured walk. It is
 | 
			
		||||
 * valid to attempt to walk a NULL stats handle or a handle containing
 | 
			
		||||
 * no present regions; in this case any call to dm_stats_walk_next()
 | 
			
		||||
 * becomes a no-op and all calls to dm_stats_walk_end() return true.
 | 
			
		||||
 */
 | 
			
		||||
void dm_stats_walk_start(struct dm_stats *dms);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Advance the statistics cursor to the next area, or to the next
 | 
			
		||||
 * present region if at the end of the current region.
 | 
			
		||||
 * present region if at the end of the current region. If the end of
 | 
			
		||||
 * the region, area, or group tables is reached a subsequent call to
 | 
			
		||||
 * dm_stats_walk_end() will return 1 and dm_stats_object_type() called
 | 
			
		||||
 * on the location will return DM_STATS_OBJECT_TYPE_NONE,
 | 
			
		||||
 */
 | 
			
		||||
void dm_stats_walk_next(struct dm_stats *dms);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Advance the statistics cursor to the next region.
 | 
			
		||||
 * Force the statistics cursor to advance to the next region. This will
 | 
			
		||||
 * stop any in-progress area walk (by clearing DM_STATS_WALK_AREA) and
 | 
			
		||||
 * advance the cursor to the next present region, the first present
 | 
			
		||||
 * group (if DM_STATS_GROUP_WALK is set), or to the end. In this case a
 | 
			
		||||
 * subsequent call to dm_stats_walk_end() will return 1 and a call to
 | 
			
		||||
 * dm_stats_object_type() for the location will return
 | 
			
		||||
 * DM_STATS_OBJECT_TYPE_NONE.
 | 
			
		||||
 */
 | 
			
		||||
void dm_stats_walk_next_region(struct dm_stats *dms);
 | 
			
		||||
 | 
			
		||||
@@ -957,6 +1068,24 @@ void dm_stats_walk_next_region(struct dm_stats *dms);
 | 
			
		||||
 */
 | 
			
		||||
int dm_stats_walk_end(struct dm_stats *dms);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Return the type of object at the location specified by region_id
 | 
			
		||||
 * and area_id. If either region_id or area_id uses one of the special
 | 
			
		||||
 * values DM_STATS_REGION_CURRENT or DM_STATS_AREA_CURRENT the
 | 
			
		||||
 * corresponding region or area identifier will be taken from the
 | 
			
		||||
 * current cursor location. If the cursor location or the value encoded
 | 
			
		||||
 * by region_id and area_id indicates an aggregate region or group,
 | 
			
		||||
 * this will be reflected in the value returned.
 | 
			
		||||
 */
 | 
			
		||||
dm_stats_obj_type_t dm_stats_object_type(const struct dm_stats *dms,
 | 
			
		||||
					 uint64_t region_id,
 | 
			
		||||
					 uint64_t area_id);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Return the type of object at the current stats cursor location.
 | 
			
		||||
 */
 | 
			
		||||
dm_stats_obj_type_t dm_stats_current_object_type(const struct dm_stats *dms);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Stats iterators
 | 
			
		||||
 *
 | 
			
		||||
@@ -978,7 +1107,8 @@ int dm_stats_walk_end(struct dm_stats *dms);
 | 
			
		||||
 * executed.
 | 
			
		||||
 */
 | 
			
		||||
#define dm_stats_foreach_region(dms)				\
 | 
			
		||||
for (dm_stats_walk_start((dms));				\
 | 
			
		||||
for (dm_stats_walk_init((dms), DM_STATS_WALK_REGION),		\
 | 
			
		||||
     dm_stats_walk_start((dms));				\
 | 
			
		||||
     !dm_stats_walk_end((dms)); dm_stats_walk_next_region((dms)))
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@@ -988,9 +1118,23 @@ for (dm_stats_walk_start((dms));				\
 | 
			
		||||
 * be executed.
 | 
			
		||||
 */
 | 
			
		||||
#define dm_stats_foreach_area(dms)				\
 | 
			
		||||
for (dm_stats_walk_start((dms));				\
 | 
			
		||||
for (dm_stats_walk_init((dms), DM_STATS_WALK_AREA),		\
 | 
			
		||||
     dm_stats_walk_start((dms));				\
 | 
			
		||||
     !dm_stats_walk_end((dms)); dm_stats_walk_next((dms)))
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Iterate over the regions table visiting each group. Metric and
 | 
			
		||||
 * counter methods will return values for the group.
 | 
			
		||||
 *
 | 
			
		||||
 * If the group table is empty or unpopulated the loop body will not
 | 
			
		||||
 * be executed.
 | 
			
		||||
 */
 | 
			
		||||
#define dm_stats_foreach_group(dms)				\
 | 
			
		||||
for (dm_stats_walk_init((dms), DM_STATS_WALK_GROUP),		\
 | 
			
		||||
     dm_stats_group_walk_start(dms);				\
 | 
			
		||||
     !dm_stats_group_walk_end(dms);				\
 | 
			
		||||
     dm_stats_group_walk_next(dms))
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Start a walk iterating over the regions contained in dm_stats handle
 | 
			
		||||
 * 'dms'.
 | 
			
		||||
@@ -1074,11 +1218,71 @@ 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);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Statistics groups and data aggregation.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Create a new group in stats handle dms from the group descriptor
 | 
			
		||||
 * passed in group. The group descriptor is a string containing a list
 | 
			
		||||
 * of region_id values that will be included in the group. The first
 | 
			
		||||
 * region_id found will be the group leader. Ranges of identifiers may
 | 
			
		||||
 * be expressed as "M-N", where M and N are the start and end region_id
 | 
			
		||||
 * values for the range.
 | 
			
		||||
 */
 | 
			
		||||
int dm_stats_create_group(struct dm_stats *dms, const char *group,
 | 
			
		||||
			  const char *alias, uint64_t *group_id);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Remove the specified group_id. If the remove argument is zero the
 | 
			
		||||
 * group will be removed but the regions that it contained will remain.
 | 
			
		||||
 * If remove is non-zero then all regions that belong to the group will
 | 
			
		||||
 * also be removed.
 | 
			
		||||
 */
 | 
			
		||||
int dm_stats_delete_group(struct dm_stats *dms, uint64_t group_id, int remove);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Set an alias for this group or region. The alias will be returned
 | 
			
		||||
 * instead of the normal dm-stats name for this region or group.
 | 
			
		||||
 */
 | 
			
		||||
int dm_stats_set_alias(struct dm_stats *dms, uint64_t group_id,
 | 
			
		||||
		       const char *alias);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Returns a pointer to the currently configured alias for id, or the
 | 
			
		||||
 * name of the dm device the handle is bound to if no alias has been
 | 
			
		||||
 * set. The pointer will be freed automatically when a new alias is set
 | 
			
		||||
 * or when the stats handle is cleared.
 | 
			
		||||
 */
 | 
			
		||||
const char *dm_stats_get_alias(const struct dm_stats *dms, uint64_t id);
 | 
			
		||||
 | 
			
		||||
#define DM_STATS_GROUP_NONE UINT64_MAX
 | 
			
		||||
/*
 | 
			
		||||
 * Return the group_id that the specified region_id belongs to, or the
 | 
			
		||||
 * special value DM_STATS_GROUP_NONE if the region does not belong
 | 
			
		||||
 * to any group.
 | 
			
		||||
 */
 | 
			
		||||
uint64_t dm_stats_get_group_id(const struct dm_stats *dms, uint64_t region_id);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Store a pointer to a string describing the regions that are members
 | 
			
		||||
 * of the group specified by group_id in the memory pointed to by buf.
 | 
			
		||||
 * The string is in the same format as the 'group' argument to
 | 
			
		||||
 * dm_stats_create_group().
 | 
			
		||||
 *
 | 
			
		||||
 * The pointer does not need to be freed explicitly by the caller: it
 | 
			
		||||
 * will become invalid following a subsequent dm_stats_list(),
 | 
			
		||||
 * dm_stats_populate() or dm_stats_destroy() of the corresponding
 | 
			
		||||
 * dm_stats handle.
 | 
			
		||||
 */
 | 
			
		||||
int dm_stats_get_group_descriptor(const struct dm_stats *dms,
 | 
			
		||||
				  uint64_t group_id, char **buf);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Call this to actually run the ioctl.
 | 
			
		||||
 */
 | 
			
		||||
@@ -1843,6 +2047,16 @@ int dm_bit_get_next(dm_bitset_t bs, int last_bit);
 | 
			
		||||
#define dm_bit_copy(bs1, bs2) \
 | 
			
		||||
   memcpy((bs1) + 1, (bs2) + 1, ((*(bs1) / DM_BITS_PER_INT) + 1) * sizeof(int))
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Parse a string representation of a bitset into a dm_bitset_t. The
 | 
			
		||||
 * notation used is identical to the kernel bitmap parser (cpuset etc.)
 | 
			
		||||
 * and supports both lists ("1,2,3") and ranges ("1-2,5-8"). If the mem
 | 
			
		||||
 * parameter is NULL memory for the bitset will be allocated using
 | 
			
		||||
 * dm_malloc(). Otherwise the bitset will be allocated using the supplied
 | 
			
		||||
 * dm_pool.
 | 
			
		||||
 */
 | 
			
		||||
dm_bitset_t dm_bitset_parse_list(const char *str, struct dm_pool *mem);
 | 
			
		||||
 | 
			
		||||
/* Returns number of set bits */
 | 
			
		||||
static inline unsigned hweight32(uint32_t i)
 | 
			
		||||
{
 | 
			
		||||
@@ -2732,6 +2946,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:
 | 
			
		||||
 *
 | 
			
		||||
@@ -2756,6 +2976,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);
 | 
			
		||||
 | 
			
		||||
@@ -2822,6 +3063,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);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2334
									
								
								libdm/libdm-stats.c
									
									
									
									
									
								
							
							
						
						
									
										2334
									
								
								libdm/libdm-stats.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										210
									
								
								man/dmstats.8.in
									
									
									
									
									
								
							
							
						
						
									
										210
									
								
								man/dmstats.8.in
									
									
									
									
									
								
							@@ -1,4 +1,4 @@
 | 
			
		||||
.TH DMSTATS 8 "Jul 25 2015" "Linux" "MAINTENANCE COMMANDS"
 | 
			
		||||
.TH DMSTATS 8 "Jun 23 2016" "Linux" "MAINTENANCE COMMANDS"
 | 
			
		||||
 | 
			
		||||
.de OPT_PROGRAMS
 | 
			
		||||
.  RB \%[ \-\-allprograms | \-\-programid
 | 
			
		||||
@@ -9,6 +9,11 @@
 | 
			
		||||
.  RB \%[ \-\-allregions | \-\-regionid
 | 
			
		||||
.  IR id ]
 | 
			
		||||
..
 | 
			
		||||
.de OPT_OBJECTS
 | 
			
		||||
.  RB [ \-\-area ]
 | 
			
		||||
.  RB [ \-\-region ]
 | 
			
		||||
.  RB [ \-\-group ]
 | 
			
		||||
..
 | 
			
		||||
.
 | 
			
		||||
.\" Print units suffix, use with arg to print human
 | 
			
		||||
.\" man2html can't handle too many changes per command
 | 
			
		||||
@@ -87,8 +92,8 @@ dmstats \(em device-mapper statistics management
 | 
			
		||||
.  IR start_sector
 | 
			
		||||
.  BR \-\-length
 | 
			
		||||
.  IR length | \fB\-\-segments ]
 | 
			
		||||
.  RB \%[ \-\-auxdata
 | 
			
		||||
.  IR data ]
 | 
			
		||||
.  RB \%[ \-\-userdata
 | 
			
		||||
.  IR user_data ]
 | 
			
		||||
.  RB [ \-\-programid
 | 
			
		||||
.  IR id ]
 | 
			
		||||
.  ad b
 | 
			
		||||
@@ -110,6 +115,20 @@ dmstats \(em device-mapper statistics management
 | 
			
		||||
.
 | 
			
		||||
.HP
 | 
			
		||||
.B dmstats
 | 
			
		||||
.de CMD_GROUP
 | 
			
		||||
.  ad l
 | 
			
		||||
.  BR group
 | 
			
		||||
.  RI [ device_name ]
 | 
			
		||||
.  RB [ \-\-alias
 | 
			
		||||
.  IR name ]
 | 
			
		||||
.  RB [ \-\-alldevices ]
 | 
			
		||||
.  RB [ \-\-regions
 | 
			
		||||
.  IR regions ]
 | 
			
		||||
.  ad b
 | 
			
		||||
..
 | 
			
		||||
.CMD_GROUP
 | 
			
		||||
.HP
 | 
			
		||||
.B dmstats
 | 
			
		||||
.de CMD_HELP
 | 
			
		||||
.  ad l
 | 
			
		||||
.  BR help
 | 
			
		||||
@@ -126,8 +145,11 @@ dmstats \(em device-mapper statistics management
 | 
			
		||||
.  RI [ device_name ]
 | 
			
		||||
.  RB [ \-\-histogram ]
 | 
			
		||||
.  OPT_PROGRAMS
 | 
			
		||||
.  RB [ \-\-statstype
 | 
			
		||||
.  IR type_list ]
 | 
			
		||||
.  RB [ \-\-units
 | 
			
		||||
.  IR units ]
 | 
			
		||||
.  OPT_OBJECTS
 | 
			
		||||
.  RB \%[ \-\-nosuffix ]
 | 
			
		||||
.  RB [ \-\-notimesuffix ]
 | 
			
		||||
.  RB \%[ \-v | \-\-verbose [ \-v | \-\-verbose ]]
 | 
			
		||||
@@ -163,10 +185,13 @@ dmstats \(em device-mapper statistics management
 | 
			
		||||
.  RB [ \-\-histogram ]
 | 
			
		||||
.  OPT_PROGRAMS
 | 
			
		||||
.  OPT_REGIONS
 | 
			
		||||
.  OPT_OBJECTS
 | 
			
		||||
.  RB [ \-O | \-\-sort
 | 
			
		||||
.  IR sort_fields ]
 | 
			
		||||
.  RB [ \-S | \-\-select
 | 
			
		||||
.  IR selection ]
 | 
			
		||||
.  RB [ \-\-statstype
 | 
			
		||||
.  IR type_list ]
 | 
			
		||||
.  RB [ \-\-units
 | 
			
		||||
.  IR units ]
 | 
			
		||||
.  RB [ \-\-nosuffix ]
 | 
			
		||||
@@ -174,6 +199,18 @@ dmstats \(em device-mapper statistics management
 | 
			
		||||
.  ad b
 | 
			
		||||
..
 | 
			
		||||
.CMD_REPORT
 | 
			
		||||
.HP
 | 
			
		||||
.B dmstats
 | 
			
		||||
.de CMD_UNGROUP
 | 
			
		||||
.  ad l
 | 
			
		||||
.  BR ungroup
 | 
			
		||||
.  RI [ device_name ]
 | 
			
		||||
.  RB [ \-\-alldevices ]
 | 
			
		||||
.  RB [ \-\-groupid
 | 
			
		||||
.  IR id ]
 | 
			
		||||
.  ad b
 | 
			
		||||
..
 | 
			
		||||
.CMD_UNGROUP
 | 
			
		||||
.
 | 
			
		||||
.PD
 | 
			
		||||
.ad b
 | 
			
		||||
@@ -199,6 +236,12 @@ commands require the use of \fB\-\-alldevices\fP when used in this way.
 | 
			
		||||
.SH OPTIONS
 | 
			
		||||
.
 | 
			
		||||
.HP
 | 
			
		||||
.BR \-\-alias
 | 
			
		||||
.IR name
 | 
			
		||||
.br
 | 
			
		||||
Specify an alias name for a group.
 | 
			
		||||
.
 | 
			
		||||
.HP
 | 
			
		||||
.BR \-\-alldevices
 | 
			
		||||
.br
 | 
			
		||||
If no device arguments are given allow operation on all devices when
 | 
			
		||||
@@ -216,6 +259,12 @@ Include all present regions for commands that normally accept a single
 | 
			
		||||
region identifier.
 | 
			
		||||
.
 | 
			
		||||
.HP
 | 
			
		||||
.BR \-\-area
 | 
			
		||||
.br
 | 
			
		||||
When peforming a list or report, include objects of type area in the
 | 
			
		||||
results.
 | 
			
		||||
.
 | 
			
		||||
.HP
 | 
			
		||||
.BR \-\-areas
 | 
			
		||||
.IR nr_areas
 | 
			
		||||
.br
 | 
			
		||||
@@ -232,12 +281,6 @@ optional suffix selects units of:
 | 
			
		||||
.HELP_UNITS
 | 
			
		||||
.
 | 
			
		||||
.HP
 | 
			
		||||
.BR \-\-auxdata
 | 
			
		||||
.IR aux_data
 | 
			
		||||
.br
 | 
			
		||||
Specify auxilliary data (a string) to be stored with a new region.
 | 
			
		||||
.
 | 
			
		||||
.HP
 | 
			
		||||
.BR \-\-clear
 | 
			
		||||
.br
 | 
			
		||||
When printing statistics counters, also atomically reset them to zero.
 | 
			
		||||
@@ -250,6 +293,18 @@ Specify the iteration count for repeating reports. If the count
 | 
			
		||||
argument is zero reports will continue to repeat until interrupted.
 | 
			
		||||
.
 | 
			
		||||
.HP
 | 
			
		||||
.BR \-\-group
 | 
			
		||||
.br
 | 
			
		||||
When peforming a list or report, include objects of type group in the
 | 
			
		||||
results.
 | 
			
		||||
.
 | 
			
		||||
.HP
 | 
			
		||||
.BR \-\-groupid
 | 
			
		||||
.IR id
 | 
			
		||||
.br
 | 
			
		||||
Specify the group to operate on.
 | 
			
		||||
.
 | 
			
		||||
.HP
 | 
			
		||||
.BR \-\-bounds
 | 
			
		||||
.IR histogram_boundaries \c
 | 
			
		||||
.RB [ ns | us | ms | s ]
 | 
			
		||||
@@ -340,12 +395,26 @@ program ID in order to select only regions with a matching value. The
 | 
			
		||||
default program ID for dmstats-managed regions is "dmstats".
 | 
			
		||||
.
 | 
			
		||||
.HP
 | 
			
		||||
.BR \-\-region
 | 
			
		||||
.br
 | 
			
		||||
When peforming a list or report, include objects of type region in the
 | 
			
		||||
results.
 | 
			
		||||
.
 | 
			
		||||
.HP
 | 
			
		||||
.BR \-\-regionid
 | 
			
		||||
.IR id
 | 
			
		||||
.br
 | 
			
		||||
Specify the region to operate on.
 | 
			
		||||
.
 | 
			
		||||
.HP
 | 
			
		||||
.BR \-\-regions
 | 
			
		||||
.IR region_list
 | 
			
		||||
.br
 | 
			
		||||
Specify a list of regions to group. The group list is a comma-separated
 | 
			
		||||
list of region identifiers. Continuous sequences of identifiers may be
 | 
			
		||||
expressed as a hyphen separated range, for example: '1-10'.
 | 
			
		||||
.
 | 
			
		||||
.HP
 | 
			
		||||
.BR \-\-relative
 | 
			
		||||
.br
 | 
			
		||||
If displaying the histogram report show relative (percentage) values
 | 
			
		||||
@@ -379,6 +448,20 @@ device. This causes a separate region to be allocated for each segment
 | 
			
		||||
of the device.
 | 
			
		||||
.
 | 
			
		||||
.HP
 | 
			
		||||
.BR \-\-statstype
 | 
			
		||||
.IR type_list
 | 
			
		||||
.br
 | 
			
		||||
Filter the types of statistics object included in a report or listing
 | 
			
		||||
according to the provided list. A report may include areas, regions,
 | 
			
		||||
and user-defined groups of regions that report aggregate data for all
 | 
			
		||||
group members.
 | 
			
		||||
 | 
			
		||||
The list may be a single object type, a comma separated list of types,
 | 
			
		||||
or the special value 'all'.
 | 
			
		||||
 | 
			
		||||
The currently available object types are 'area', 'region' and 'group'.
 | 
			
		||||
.
 | 
			
		||||
.HP
 | 
			
		||||
.BR \-\-units
 | 
			
		||||
.RI [ units ] \c
 | 
			
		||||
.RB [ h | H | \c
 | 
			
		||||
@@ -391,6 +474,15 @@ All sizes are output in these units:
 | 
			
		||||
Can also specify custom units e.g. \fB\-\-units\ 3M\fP.
 | 
			
		||||
.
 | 
			
		||||
.HP
 | 
			
		||||
.BR \-\-userdata
 | 
			
		||||
.IR user_data
 | 
			
		||||
.br
 | 
			
		||||
Specify user data (a word) to be stored with a new region. The value
 | 
			
		||||
is added to any internal auxilliary data (for example, group
 | 
			
		||||
information), and stored with the region in the aux_data field provided
 | 
			
		||||
by the kernel. Whitespace is not permitted.
 | 
			
		||||
.
 | 
			
		||||
.HP
 | 
			
		||||
.BR \-u | \-\-uuid
 | 
			
		||||
.br
 | 
			
		||||
Specify the uuid.
 | 
			
		||||
@@ -437,9 +529,9 @@ one milisecond can only be used when precise timestamps are enabled: if
 | 
			
		||||
\fB\-\-precise\fP is not given and values less than one milisecond are
 | 
			
		||||
used it will be enabled automatically.
 | 
			
		||||
 | 
			
		||||
An optional \fBprogram_id\fP or \fBaux_data\fP string may be associated
 | 
			
		||||
An optional \fBprogram_id\fP or \fBuser_data\fP string may be associated
 | 
			
		||||
with the region. A \fBprogram_id\fP may then be used to select regions
 | 
			
		||||
for subsequent list, print, and report operations. The \fBaux_data\fP
 | 
			
		||||
for subsequent list, print, and report operations. The \fBuser_data\fP
 | 
			
		||||
stores an arbitrary string and is not used by dmstats or the
 | 
			
		||||
device-mapper kernel statistics subsystem.
 | 
			
		||||
 | 
			
		||||
@@ -461,6 +553,28 @@ All regions registered on a device may be removed using
 | 
			
		||||
 | 
			
		||||
To remove all regions on all devices both \fB\-\-allregions\fP and
 | 
			
		||||
\fB\-\-alldevices\fP must be used.
 | 
			
		||||
 | 
			
		||||
If a \fB\-\-groupid\fP is given instead of a \fB\-\-regionid\fP the
 | 
			
		||||
command will attempt to delete the group and all regions that it
 | 
			
		||||
contains.
 | 
			
		||||
 | 
			
		||||
If a deleted region is the first member of a group of regions the group
 | 
			
		||||
will also be removed.
 | 
			
		||||
.
 | 
			
		||||
.HP
 | 
			
		||||
.CMD_GROUP
 | 
			
		||||
.br
 | 
			
		||||
Combine one or more statistics regions on the specified device into a
 | 
			
		||||
group.
 | 
			
		||||
 | 
			
		||||
The list of regions to be grouped is specified with \fB\-\-regions\fP
 | 
			
		||||
and an optional alias may be assigned with \fB\-\-alias\fP. The set of
 | 
			
		||||
regions is given as a comma-separated list of region identifiers. A
 | 
			
		||||
continuous range of identifers spanning from \fBR1\fP to \fBR2\fP may
 | 
			
		||||
be expressed as '\fBR1\fP-\fBR2\fP'.
 | 
			
		||||
 | 
			
		||||
On success the group list and newly created \fBgroup_id\fP are
 | 
			
		||||
printed to stdout.
 | 
			
		||||
.
 | 
			
		||||
.HP
 | 
			
		||||
.CMD_HELP
 | 
			
		||||
@@ -471,16 +585,23 @@ the list of report fields.
 | 
			
		||||
.HP
 | 
			
		||||
.CMD_LIST
 | 
			
		||||
.br
 | 
			
		||||
List the statistics regions registered on the device. If the
 | 
			
		||||
\fB\-\-allprograms\fP switch is given all regions will be listed
 | 
			
		||||
List the statistics regions, areas, or groups registered on the device.
 | 
			
		||||
If the \fB\-\-allprograms\fP switch is given all regions will be listed
 | 
			
		||||
regardless of region program ID values.
 | 
			
		||||
 | 
			
		||||
If \fB\-v\fP or \fB\-\-verbose\fP is given the report will include
 | 
			
		||||
a row of information for each area contained in each region displayed.
 | 
			
		||||
By default only regions and groups are included in list output. If
 | 
			
		||||
\fB\-v\fP or \fB\-\-verbose\fP is given the report will also include a
 | 
			
		||||
row of information for each configured group and for each area contained
 | 
			
		||||
in each region displayed (regions that contain a single area are by
 | 
			
		||||
default omitted from the verbose list since their properties are
 | 
			
		||||
identical to the area that they contain - to view all regions regardless
 | 
			
		||||
of the number of areas they contain use \fB\-\-statstype\fP).
 | 
			
		||||
 | 
			
		||||
Specific combinations of objects may be selected using the
 | 
			
		||||
\fB\-\-statstype\fP option.
 | 
			
		||||
 | 
			
		||||
If \fB\-\-histogram\fP is given the report will include the bin count
 | 
			
		||||
and latency boundary values for any configured histograms.
 | 
			
		||||
.
 | 
			
		||||
.HP
 | 
			
		||||
.CMD_PRINT
 | 
			
		||||
.br
 | 
			
		||||
@@ -490,7 +611,7 @@ present regions.
 | 
			
		||||
.HP
 | 
			
		||||
.CMD_REPORT
 | 
			
		||||
.br
 | 
			
		||||
Start a report for the specified region or for all present regions. If
 | 
			
		||||
Start a report for the specified object or for all present objects. If
 | 
			
		||||
the count argument is specified, the report will repeat at a fixed
 | 
			
		||||
interval set by the \fB\-\-interval\fP option. The default interval is
 | 
			
		||||
one second.
 | 
			
		||||
@@ -503,19 +624,41 @@ values and latency boundaries.
 | 
			
		||||
 | 
			
		||||
If the \fB\-\-relative\fP is used the default histogram field displays
 | 
			
		||||
bin values as a percentage of the total number of I/Os.
 | 
			
		||||
 | 
			
		||||
Object types (areas, regions and groups) are selected using the
 | 
			
		||||
\fB\-\-statstype\fP option.
 | 
			
		||||
.
 | 
			
		||||
.SH REGIONS AND AREAS
 | 
			
		||||
.HP
 | 
			
		||||
.CMD_UNGROUP
 | 
			
		||||
.br
 | 
			
		||||
Remove an existing group and return all the group's regions to their
 | 
			
		||||
original state.
 | 
			
		||||
 | 
			
		||||
The group to be removed is specified using \fB\-\-groupid\fP.
 | 
			
		||||
.
 | 
			
		||||
.SH REGIONS, AREAS, AND GROUPS
 | 
			
		||||
.
 | 
			
		||||
The device-mapper statistics facility allows separate performance
 | 
			
		||||
counters to be maintained for arbitrary regions of devices. A region may
 | 
			
		||||
span any range: from a single sector to the whole device. A region may
 | 
			
		||||
be further sub-divided into a number of distinct areas (one or more),
 | 
			
		||||
each with its own counter set.
 | 
			
		||||
each with its own counter set. In this case a summary value for the
 | 
			
		||||
entire region is also available for use in reports.
 | 
			
		||||
 | 
			
		||||
In addition, one or more regions on one device can be combined into
 | 
			
		||||
a statistics group allowing reporting of aggregate values for all
 | 
			
		||||
regions and areas making up the group.
 | 
			
		||||
 | 
			
		||||
By default new regions span the entire device. The \fB\-\-start\fP and
 | 
			
		||||
\fB\-\-length\fP options allows a region of any size to be placed at any
 | 
			
		||||
location on the device.
 | 
			
		||||
 | 
			
		||||
Using offsets it is possible to create regions that map individual
 | 
			
		||||
objects within a block device (for example: partitions, files in a file
 | 
			
		||||
system, or stripes or other structures in a RAID volume). Groups allow
 | 
			
		||||
several non-contiguous regions to be assembled together for reporting
 | 
			
		||||
and data aggregation.
 | 
			
		||||
 | 
			
		||||
A region may be either divided into the specified number of equal-sized
 | 
			
		||||
areas, or into areas of the given size by specifying one of
 | 
			
		||||
\fB\-\-areas\fP or \fB\-\-areasize\fP when creating a region with the
 | 
			
		||||
@@ -531,6 +674,19 @@ values).
 | 
			
		||||
 | 
			
		||||
Depending on the sequence of create and delete operations, gaps may
 | 
			
		||||
exist in the sequence of \fBregion_id\fP values for a particular device.
 | 
			
		||||
 | 
			
		||||
The \fBregion_id\fP should be treated as an opaque identifier used to
 | 
			
		||||
reference the region.
 | 
			
		||||
.
 | 
			
		||||
.P
 | 
			
		||||
.B Group identifiers
 | 
			
		||||
.P
 | 
			
		||||
Groups are also assigned an integer identifier at creation time;
 | 
			
		||||
like region identifiers, group identifiers are unique within the
 | 
			
		||||
containing device.
 | 
			
		||||
 | 
			
		||||
The \fBgroup_id\fP should be treated as an opaque identifier used to
 | 
			
		||||
reference the group.
 | 
			
		||||
.
 | 
			
		||||
.SH REPORT FIELDS
 | 
			
		||||
.
 | 
			
		||||
@@ -591,12 +747,12 @@ Percentage of CPU time during which I/O requests were issued to the
 | 
			
		||||
device (bandwidth utilization for the device). Device saturation occurs
 | 
			
		||||
when this value is close to 100%.
 | 
			
		||||
.
 | 
			
		||||
.SS Region and area meta fields
 | 
			
		||||
.SS Group, region and area meta fields
 | 
			
		||||
.
 | 
			
		||||
Meta fields provide information about the region or area that the
 | 
			
		||||
statistics values relate to. This includes the region and area
 | 
			
		||||
Meta fields provide information about the groups, regions, or areas that
 | 
			
		||||
the statistics values relate to. This includes the region and area
 | 
			
		||||
identifier, start, length, and counts, as well as the program ID and
 | 
			
		||||
auxiliary data values.
 | 
			
		||||
user data values.
 | 
			
		||||
.TP
 | 
			
		||||
.B region_id
 | 
			
		||||
Region identifier. This is a non-negative integer returned by the kernel
 | 
			
		||||
@@ -633,8 +789,12 @@ The number of areas in this region.
 | 
			
		||||
.B program_id
 | 
			
		||||
The program ID value associated with this region.
 | 
			
		||||
.TP
 | 
			
		||||
.B aux_data
 | 
			
		||||
The auxiliary data value associated with this region.
 | 
			
		||||
.B user_data
 | 
			
		||||
The user data value associated with this region.
 | 
			
		||||
.TP
 | 
			
		||||
.B group_id
 | 
			
		||||
Group identifier. This is a non-negative integer returned by the dmstats
 | 
			
		||||
\fBgroup\fP command when a statistics group is created.
 | 
			
		||||
.TP
 | 
			
		||||
.B interval_ns
 | 
			
		||||
The estimated interval over which the current counter values have
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										454
									
								
								tools/dmsetup.c
									
									
									
									
									
								
							
							
						
						
									
										454
									
								
								tools/dmsetup.c
									
									
									
									
									
								
							@@ -156,12 +156,13 @@ 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,
 | 
			
		||||
	AREA_ARG,
 | 
			
		||||
	AREAS_ARG,
 | 
			
		||||
	AREA_SIZE_ARG,
 | 
			
		||||
	AUX_DATA_ARG,
 | 
			
		||||
	BOUNDS_ARG,
 | 
			
		||||
	CHECKS_ARG,
 | 
			
		||||
	CLEAR_ARG,
 | 
			
		||||
@@ -172,6 +173,8 @@ enum {
 | 
			
		||||
	EXEC_ARG,
 | 
			
		||||
	FORCE_ARG,
 | 
			
		||||
	GID_ARG,
 | 
			
		||||
	GROUP_ARG,
 | 
			
		||||
	GROUP_ID_ARG,
 | 
			
		||||
	HELP_ARG,
 | 
			
		||||
	HISTOGRAM_ARG,
 | 
			
		||||
	INACTIVE_ARG,
 | 
			
		||||
@@ -179,6 +182,7 @@ enum {
 | 
			
		||||
	LENGTH_ARG,
 | 
			
		||||
	MANGLENAME_ARG,
 | 
			
		||||
	MAJOR_ARG,
 | 
			
		||||
	REGIONS_ARG,
 | 
			
		||||
	MINOR_ARG,
 | 
			
		||||
	MODE_ARG,
 | 
			
		||||
	NAMEPREFIXES_ARG,
 | 
			
		||||
@@ -197,6 +201,7 @@ enum {
 | 
			
		||||
	PROGRAM_ID_ARG,
 | 
			
		||||
	RAW_ARG,
 | 
			
		||||
	READAHEAD_ARG,
 | 
			
		||||
	REGION_ARG,
 | 
			
		||||
	REGION_ID_ARG,
 | 
			
		||||
	RELATIVE_ARG,
 | 
			
		||||
	RETRY_ARG,
 | 
			
		||||
@@ -214,6 +219,7 @@ enum {
 | 
			
		||||
	UNBUFFERED_ARG,
 | 
			
		||||
	UNITS_ARG,
 | 
			
		||||
	UNQUOTED_ARG,
 | 
			
		||||
	USER_DATA_ARG,
 | 
			
		||||
	UUID_ARG,
 | 
			
		||||
	VERBOSE_ARG,
 | 
			
		||||
	VERIFYUDEV_ARG,
 | 
			
		||||
@@ -261,7 +267,16 @@ static struct dm_timestamp *_initial_timestamp = NULL;
 | 
			
		||||
static uint64_t _disp_factor = 512; /* display sizes in sectors */
 | 
			
		||||
static char _disp_units = 's';
 | 
			
		||||
const char *_program_id = DM_STATS_PROGRAM_ID; /* program_id used for reports. */
 | 
			
		||||
static int _stats_report_by_areas = 1; /* output per-area info for stats reports. */
 | 
			
		||||
static uint64_t _statstype = 0; /* stats objects to report */
 | 
			
		||||
 | 
			
		||||
/* string names for stats object types */
 | 
			
		||||
const char *_stats_types[] = {
 | 
			
		||||
	"all",
 | 
			
		||||
	"area",
 | 
			
		||||
	"region",
 | 
			
		||||
	"group",
 | 
			
		||||
	NULL
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* report timekeeping */
 | 
			
		||||
static struct dm_timestamp *_cycle_timestamp = NULL;
 | 
			
		||||
@@ -801,7 +816,7 @@ out:
 | 
			
		||||
static int _display_info_cols(struct dm_task *dmt, struct dm_info *info)
 | 
			
		||||
{
 | 
			
		||||
	struct dmsetup_report_obj obj;
 | 
			
		||||
 | 
			
		||||
	uint64_t walk_flags = _statstype;
 | 
			
		||||
	int r = 0;
 | 
			
		||||
 | 
			
		||||
	if (!info->exists) {
 | 
			
		||||
@@ -832,6 +847,13 @@ static int _display_info_cols(struct dm_task *dmt, struct dm_info *info)
 | 
			
		||||
						       dm_task_get_name(dmt), '-')))
 | 
			
		||||
			goto_out;
 | 
			
		||||
 | 
			
		||||
	if (!(_report_type & (DR_STATS | DR_STATS_META))) {
 | 
			
		||||
		if (!dm_report_object(_report, &obj))
 | 
			
		||||
			goto_out;
 | 
			
		||||
		r = 1;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Obtain statistics for the current reporting object and set
 | 
			
		||||
	 * the interval estimate used for stats rate conversion.
 | 
			
		||||
@@ -851,10 +873,9 @@ static int _display_info_cols(struct dm_task *dmt, struct dm_info *info)
 | 
			
		||||
		log_debug("Adjusted sample interval duration: %12"PRIu64"ns", _last_interval);
 | 
			
		||||
		/* use measured approximation for calculations */
 | 
			
		||||
		dm_stats_set_sampling_interval_ns(obj.stats, _last_interval);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Only a dm_stats_list is needed for DR_STATS_META reports. */
 | 
			
		||||
	if (!obj.stats && (_report_type & DR_STATS_META)) {
 | 
			
		||||
	} else if (!obj.stats && (_report_type & DR_STATS_META)
 | 
			
		||||
		/* Only a dm_stats_list is needed for DR_STATS_META reports. */
 | 
			
		||||
		    && !(_report_type & DR_STATS)) {
 | 
			
		||||
		if (!(obj.stats = dm_stats_create(DM_STATS_PROGRAM_ID)))
 | 
			
		||||
			goto_out;
 | 
			
		||||
 | 
			
		||||
@@ -863,25 +884,23 @@ 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;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Walk any statistics regions contained in the current
 | 
			
		||||
	 * reporting object: for objects with a NULL stats handle,
 | 
			
		||||
	 * or a handle containing no registered regions, this loop
 | 
			
		||||
	 * always executes exactly once.
 | 
			
		||||
	 */
 | 
			
		||||
	/* group report with no groups? */
 | 
			
		||||
	if ((walk_flags == DM_STATS_WALK_GROUP)
 | 
			
		||||
	    && !dm_stats_get_nr_groups(obj.stats))
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	dm_stats_walk_init(obj.stats, walk_flags);
 | 
			
		||||
	dm_stats_walk_do(obj.stats) {
 | 
			
		||||
		if (!dm_report_object(_report, &obj))
 | 
			
		||||
			goto_out;
 | 
			
		||||
		if (_stats_report_by_areas)
 | 
			
		||||
			dm_stats_walk_next(obj.stats);
 | 
			
		||||
		else
 | 
			
		||||
			dm_stats_walk_next_region(obj.stats);
 | 
			
		||||
		dm_stats_walk_next(obj.stats);
 | 
			
		||||
	} dm_stats_walk_while(obj.stats);
 | 
			
		||||
 | 
			
		||||
	r = 1;
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
@@ -3247,7 +3266,19 @@ static int _dm_stats_region_id_disp(struct dm_report *rh,
 | 
			
		||||
				    void *private __attribute__((unused)))
 | 
			
		||||
{
 | 
			
		||||
	const struct dm_stats *dms = (const struct dm_stats *) data;
 | 
			
		||||
	uint64_t region_id = dm_stats_get_current_region(dms);
 | 
			
		||||
	uint64_t group_id, region_id = dm_stats_get_current_region(dms);
 | 
			
		||||
	char *group_buf = NULL, *repstr;
 | 
			
		||||
 | 
			
		||||
	if (dm_stats_current_object_type(dms) == DM_STATS_OBJECT_TYPE_GROUP) {
 | 
			
		||||
		group_id = dm_stats_get_group_id(dms, dm_stats_get_current_region(dms));
 | 
			
		||||
		if (!dm_stats_get_group_descriptor(dms, group_id, &group_buf))
 | 
			
		||||
			return 0;
 | 
			
		||||
		/* group_buf will disappear with the current handle */
 | 
			
		||||
		repstr = dm_pool_strdup(mem, group_buf);
 | 
			
		||||
		dm_report_field_set_value(field, repstr, &group_id);
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return dm_report_field_uint64(rh, field, ®ion_id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -3314,6 +3345,10 @@ static int _dm_stats_area_id_disp(struct dm_report *rh,
 | 
			
		||||
{
 | 
			
		||||
	const struct dm_stats *dms = (const struct dm_stats *) data;
 | 
			
		||||
	uint64_t area_id = dm_stats_get_current_area(dms);
 | 
			
		||||
 | 
			
		||||
	if (dm_stats_current_object_type(dms) == DM_STATS_OBJECT_TYPE_GROUP)
 | 
			
		||||
		area_id = 0;
 | 
			
		||||
 | 
			
		||||
	return dm_report_field_uint64(rh, field, &area_id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -3416,6 +3451,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 (!dm_stats_group_present(dms, group_id)) {
 | 
			
		||||
		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,
 | 
			
		||||
@@ -3428,16 +3482,40 @@ static int _dm_stats_program_id_disp(struct dm_report *rh,
 | 
			
		||||
	return dm_report_field_string(rh, field, (const char * const *) &program_id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _dm_stats_aux_data_disp(struct dm_report *rh,
 | 
			
		||||
static int _dm_stats_user_data_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;
 | 
			
		||||
	const char *user_data;
 | 
			
		||||
	if (!(user_data = dm_stats_get_current_region_aux_data(dms)))
 | 
			
		||||
		return_0;
 | 
			
		||||
	return dm_report_field_string(rh, field, (const char * const *) &user_data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _dm_stats_name_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;
 | 
			
		||||
	const char *stats_name;
 | 
			
		||||
	if (!(stats_name = dm_stats_get_alias(dms, DM_STATS_REGION_CURRENT)))
 | 
			
		||||
		return_0;
 | 
			
		||||
 | 
			
		||||
	return dm_report_field_string(rh, field, (const char * const *) &stats_name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _dm_stats_object_type_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;
 | 
			
		||||
	const char *aux_data;
 | 
			
		||||
	if (!(aux_data = dm_stats_get_current_region_aux_data(dms)))
 | 
			
		||||
		return_0;
 | 
			
		||||
	return dm_report_field_string(rh, field, (const char * const *) &aux_data);
 | 
			
		||||
	int type = dm_stats_current_object_type(dms);
 | 
			
		||||
 | 
			
		||||
	return dm_report_field_string(rh, field, (const char * const *) &_stats_types[type]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _dm_stats_precise_disp(struct dm_report *rh,
 | 
			
		||||
@@ -4200,12 +4278,15 @@ 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, "UserData", 8, dm_stats_user_data, "user_data", "Auxiliary data.")
 | 
			
		||||
FIELD_F(STATS_META, STR, "Precise", 7, dm_stats_precise, "precise", "Set if nanosecond precision counters are enabled.")
 | 
			
		||||
FIELD_F(STATS_META, STR, "#Bins", 9, dm_stats_hist_bins, "hist_bins", "The number of histogram bins configured.")
 | 
			
		||||
FIELD_F(STATS_META, STR, "Histogram Bounds", 16, dm_stats_hist_bounds, "hist_bounds", "Latency histogram bin boundaries.")
 | 
			
		||||
FIELD_F(STATS_META, STR, "Histogram Ranges", 16, dm_stats_hist_ranges, "hist_ranges", "Latency histogram bin ranges.")
 | 
			
		||||
FIELD_F(STATS_META, STR, "Name", 16, dm_stats_name, "stats_name", "Stats name of current object.")
 | 
			
		||||
FIELD_F(STATS_META, STR, "ObjType", 11, dm_stats_object_type, "obj_type", "Type of stats object being reported.")
 | 
			
		||||
{0, 0, 0, 0, "", "", NULL, NULL},
 | 
			
		||||
/* *INDENT-ON* */
 | 
			
		||||
};
 | 
			
		||||
@@ -4233,7 +4314,7 @@ static const char *splitname_report_options = "vg_name,lv_name,lv_layer";
 | 
			
		||||
		"await,read_await,write_await"
 | 
			
		||||
 | 
			
		||||
/* Device, region and area metadata. */
 | 
			
		||||
#define STATS_DEV_INFO "name,region_id"
 | 
			
		||||
#define STATS_DEV_INFO "statsname,group_id,region_id,obj_type"
 | 
			
		||||
#define STATS_AREA_INFO "area_id,area_start,area_len"
 | 
			
		||||
#define STATS_AREA_INFO_FULL STATS_DEV_INFO ",region_start,region_len,area_count,area_id,area_start,area_len"
 | 
			
		||||
#define STATS_REGION_INFO STATS_DEV_INFO ",region_start,region_len,area_count,area_len"
 | 
			
		||||
@@ -4530,6 +4611,22 @@ static int _bind_stats_device(struct dm_stats *dms, const char *name)
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _stats_clear_one_region(struct dm_stats *dms, uint64_t region_id)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	if (!dm_stats_region_present(dms, region_id)) {
 | 
			
		||||
		log_error("No such region: %"PRIu64".", region_id);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	if (!dm_stats_clear_region(dms, region_id)) {
 | 
			
		||||
		log_error("Clearing statistics region %"PRIu64" failed.",
 | 
			
		||||
			  region_id);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	log_info("Cleared statistics region %"PRIu64".", region_id);
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _stats_clear_regions(struct dm_stats *dms, uint64_t region_id)
 | 
			
		||||
{
 | 
			
		||||
	int allregions = (region_id == DM_STATS_REGIONS_ALL);
 | 
			
		||||
@@ -4540,22 +4637,14 @@ static int _stats_clear_regions(struct dm_stats *dms, uint64_t region_id)
 | 
			
		||||
	if (!dm_stats_get_nr_regions(dms))
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	dm_stats_walk_do(dms) {
 | 
			
		||||
		if (allregions)
 | 
			
		||||
			region_id = dm_stats_get_current_region(dms);
 | 
			
		||||
	if (!allregions)
 | 
			
		||||
		return _stats_clear_one_region(dms, region_id);
 | 
			
		||||
 | 
			
		||||
		if (!dm_stats_region_present(dms, region_id)) {
 | 
			
		||||
			log_error("No such region: %"PRIu64".", region_id);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		if (!dm_stats_clear_region(dms, region_id)) {
 | 
			
		||||
			log_error("Clearing statistics region %"PRIu64" failed.",
 | 
			
		||||
				  region_id);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		log_info("Cleared statistics region %"PRIu64".", region_id);
 | 
			
		||||
		dm_stats_walk_next_region(dms);
 | 
			
		||||
	} dm_stats_walk_while(dms);
 | 
			
		||||
	dm_stats_foreach_region(dms) {
 | 
			
		||||
		region_id = dm_stats_get_current_region(dms);
 | 
			
		||||
		if (!_stats_clear_one_region(dms, region_id))
 | 
			
		||||
			return_0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
@@ -4671,7 +4760,7 @@ static int _do_stats_create_regions(struct dm_stats *dms,
 | 
			
		||||
				    uint64_t len, int64_t step,
 | 
			
		||||
				    int segments,
 | 
			
		||||
				    const char *program_id,
 | 
			
		||||
				    const char *aux_data)
 | 
			
		||||
				    const char *user_data)
 | 
			
		||||
{
 | 
			
		||||
	uint64_t this_start = 0, this_len = len, region_id = UINT64_C(0);
 | 
			
		||||
	const char *devname = NULL, *histogram = _string_args[BOUNDS_ARG];
 | 
			
		||||
@@ -4732,7 +4821,7 @@ static int _do_stats_create_regions(struct dm_stats *dms,
 | 
			
		||||
			if (!dm_stats_create_region(dms, ®ion_id,
 | 
			
		||||
						    this_start, this_len, step,
 | 
			
		||||
						    precise, bounds,
 | 
			
		||||
						    program_id, aux_data)) {
 | 
			
		||||
						    program_id, user_data)) {
 | 
			
		||||
				log_error("%s: Could not create statistics region.",
 | 
			
		||||
					  devname);
 | 
			
		||||
				goto out;
 | 
			
		||||
@@ -4755,7 +4844,7 @@ out:
 | 
			
		||||
static int _stats_create(CMD_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_stats *dms;
 | 
			
		||||
	const char *name, *aux_data = "", *program_id = DM_STATS_PROGRAM_ID;
 | 
			
		||||
	const char *name, *user_data = "", *program_id = DM_STATS_PROGRAM_ID;
 | 
			
		||||
	uint64_t start = 0, len = 0, areas = 0, area_size = 0;
 | 
			
		||||
	int64_t step = 0;
 | 
			
		||||
 | 
			
		||||
@@ -4836,8 +4925,8 @@ static int _stats_create(CMD_ARGS)
 | 
			
		||||
	if (!strlen(program_id) && !_switches[FORCE_ARG])
 | 
			
		||||
		program_id = DM_STATS_PROGRAM_ID;
 | 
			
		||||
 | 
			
		||||
	if (_switches[AUX_DATA_ARG])
 | 
			
		||||
		aux_data = _string_args[AUX_DATA_ARG];
 | 
			
		||||
	if (_switches[USER_DATA_ARG])
 | 
			
		||||
		user_data = _string_args[USER_DATA_ARG];
 | 
			
		||||
 | 
			
		||||
	if (!(dms = dm_stats_create(DM_STATS_PROGRAM_ID)))
 | 
			
		||||
		return_0;
 | 
			
		||||
@@ -4867,7 +4956,7 @@ static int _stats_create(CMD_ARGS)
 | 
			
		||||
 | 
			
		||||
	return _do_stats_create_regions(dms, name, start, len, step,
 | 
			
		||||
					_switches[SEGMENTS_ARG],
 | 
			
		||||
					program_id, aux_data);
 | 
			
		||||
					program_id, user_data);
 | 
			
		||||
 | 
			
		||||
bad:
 | 
			
		||||
	dm_stats_destroy(dms);
 | 
			
		||||
@@ -4877,7 +4966,7 @@ bad:
 | 
			
		||||
static int _stats_delete(CMD_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_stats *dms;
 | 
			
		||||
	uint64_t region_id;
 | 
			
		||||
	uint64_t region_id, group_id;
 | 
			
		||||
	char *name = NULL;
 | 
			
		||||
	const char *program_id = DM_STATS_PROGRAM_ID;
 | 
			
		||||
	int allregions = _switches[ALL_REGIONS_ARG];
 | 
			
		||||
@@ -4889,8 +4978,13 @@ static int _stats_delete(CMD_ARGS)
 | 
			
		||||
		_report = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_switches[REGION_ID_ARG] && !allregions) {
 | 
			
		||||
		err("Please specify a --regionid or use --allregions.");
 | 
			
		||||
	if (_switches[REGION_ID_ARG] && _switches[GROUP_ID_ARG]) {
 | 
			
		||||
		err("Please use one of --regionid and --groupid.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_switches[REGION_ID_ARG] && !allregions && !_switches[GROUP_ID_ARG]) {
 | 
			
		||||
		err("Please specify a --regionid or --groupid, or use --allregions.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -4912,6 +5006,7 @@ static int _stats_delete(CMD_ARGS)
 | 
			
		||||
		program_id = DM_STATS_ALL_PROGRAMS;
 | 
			
		||||
 | 
			
		||||
	region_id = (uint64_t) _int_args[REGION_ID_ARG];
 | 
			
		||||
	group_id = (uint64_t) _int_args[GROUP_ID_ARG];
 | 
			
		||||
 | 
			
		||||
	if (!(dms = dm_stats_create(program_id)))
 | 
			
		||||
		return_0;
 | 
			
		||||
@@ -4919,7 +5014,9 @@ static int _stats_delete(CMD_ARGS)
 | 
			
		||||
	if (!_bind_stats_device(dms, name))
 | 
			
		||||
		goto_out;
 | 
			
		||||
 | 
			
		||||
	if (allregions && !dm_stats_list(dms, program_id))
 | 
			
		||||
	/* allregions and group delete require a listed handle */
 | 
			
		||||
	if ((allregions || _switches[GROUP_ID_ARG])
 | 
			
		||||
	    && !dm_stats_list(dms, program_id))
 | 
			
		||||
		goto_out;
 | 
			
		||||
 | 
			
		||||
	if (allregions && !dm_stats_get_nr_regions(dms)) {
 | 
			
		||||
@@ -4928,16 +5025,24 @@ static int _stats_delete(CMD_ARGS)
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dm_stats_walk_do(dms) {
 | 
			
		||||
		if (_switches[ALL_REGIONS_ARG])
 | 
			
		||||
			region_id = dm_stats_get_current_region(dms);
 | 
			
		||||
		if (!dm_stats_delete_region(dms, region_id)) {
 | 
			
		||||
			log_error("Could not delete statistics region.");
 | 
			
		||||
	if (_switches[GROUP_ID_ARG]) {
 | 
			
		||||
		if (!dm_stats_delete_group(dms, group_id, 1)) {
 | 
			
		||||
			log_error("Could not delete statistics group.");
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
		log_info("Deleted statistics region %" PRIu64, region_id);
 | 
			
		||||
		dm_stats_walk_next_region(dms);
 | 
			
		||||
	} dm_stats_walk_while(dms);
 | 
			
		||||
	} else if (_switches[ALL_REGIONS_ARG]) {
 | 
			
		||||
		dm_stats_foreach_region(dms) {
 | 
			
		||||
			region_id = dm_stats_get_current_region(dms);
 | 
			
		||||
			if (!dm_stats_delete_region(dms, region_id)) {
 | 
			
		||||
				log_error("Could not delete statistics region.");
 | 
			
		||||
				goto out;
 | 
			
		||||
			}
 | 
			
		||||
			log_info("Deleted statistics region %" PRIu64, region_id);
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		dm_stats_delete_region(dms, region_id);
 | 
			
		||||
		log_info("Deleted statistics region " FMTu64 ".\n", region_id);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = 1;
 | 
			
		||||
 | 
			
		||||
@@ -4946,6 +5051,23 @@ out:
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _stats_print_one_region(struct dm_stats *dms, int clear,
 | 
			
		||||
				   uint64_t region_id)
 | 
			
		||||
{
 | 
			
		||||
	char *stbuff = NULL;
 | 
			
		||||
 | 
			
		||||
	/*FIXME: line control for large regions */
 | 
			
		||||
	if (!(stbuff = dm_stats_print_region(dms, region_id, 0, 0, clear))) {
 | 
			
		||||
		log_error("Could not print statistics region.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	printf("%s", stbuff);
 | 
			
		||||
	dm_stats_buffer_destroy(dms, stbuff);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _stats_print(CMD_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_stats *dms;
 | 
			
		||||
@@ -4974,8 +5096,6 @@ static int _stats_print(CMD_ARGS)
 | 
			
		||||
		name = argv[0];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	region_id = (uint64_t) _int_args[REGION_ID_ARG];
 | 
			
		||||
 | 
			
		||||
	if (!(dms = dm_stats_create(DM_STATS_PROGRAM_ID)))
 | 
			
		||||
		return_0;
 | 
			
		||||
 | 
			
		||||
@@ -4990,14 +5110,18 @@ static int _stats_print(CMD_ARGS)
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dm_stats_walk_do(dms) {
 | 
			
		||||
		if (_switches[ALL_REGIONS_ARG])
 | 
			
		||||
			region_id = dm_stats_get_current_region(dms);
 | 
			
		||||
	if (!allregions) {
 | 
			
		||||
		region_id = (uint64_t) _int_args[REGION_ID_ARG];
 | 
			
		||||
		if (!_stats_print_one_region(dms, clear, region_id))
 | 
			
		||||
			goto_out;
 | 
			
		||||
		r = 1;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
		if (!dm_stats_region_present(dms, region_id)) {
 | 
			
		||||
			log_error("No such region: %"PRIu64".", region_id);
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
	dm_stats_foreach_region(dms) {
 | 
			
		||||
		region_id = dm_stats_get_current_region(dms);
 | 
			
		||||
		if (!_stats_print_one_region(dms, clear, region_id))
 | 
			
		||||
			goto_out;
 | 
			
		||||
 | 
			
		||||
		/*FIXME: line control for large regions */
 | 
			
		||||
		if (!(stbuff = dm_stats_print_region(dms, region_id, 0, 0, clear))) {
 | 
			
		||||
@@ -5006,11 +5130,8 @@ static int _stats_print(CMD_ARGS)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		printf("%s", stbuff);
 | 
			
		||||
 | 
			
		||||
		dm_stats_buffer_destroy(dms, stbuff);
 | 
			
		||||
		dm_stats_walk_next_region(dms);
 | 
			
		||||
 | 
			
		||||
	} dm_stats_walk_while(dms);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = 1;
 | 
			
		||||
 | 
			
		||||
@@ -5021,19 +5142,30 @@ out:
 | 
			
		||||
 | 
			
		||||
static int _stats_report(CMD_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	int r = 0;
 | 
			
		||||
	int r = 0, objtype_args;
 | 
			
		||||
 | 
			
		||||
	struct dm_task *dmt;
 | 
			
		||||
	char *name = NULL;
 | 
			
		||||
 | 
			
		||||
	objtype_args = (_switches[AREA_ARG]
 | 
			
		||||
			|| _switches[REGION_ARG]
 | 
			
		||||
			|| _switches[GROUP_ARG]);
 | 
			
		||||
 | 
			
		||||
	if (_switches[PROGRAM_ID_ARG])
 | 
			
		||||
		_program_id = _string_args[PROGRAM_ID_ARG];
 | 
			
		||||
 | 
			
		||||
	if (_switches[ALL_PROGRAMS_ARG])
 | 
			
		||||
		_program_id = "";
 | 
			
		||||
 | 
			
		||||
	if (!_switches[VERBOSE_ARG] && !strcmp(subcommand, "list"))
 | 
			
		||||
		_stats_report_by_areas = 0;
 | 
			
		||||
	if (_switches[VERBOSE_ARG] && !strcmp(subcommand, "list"))
 | 
			
		||||
		_statstype |= (DM_STATS_WALK_ALL
 | 
			
		||||
			       | DM_STATS_WALK_SKIP_SINGLE_AREA);
 | 
			
		||||
 | 
			
		||||
	/* suppress duplicates unless the user has requested all regions */
 | 
			
		||||
	if (!strcmp(subcommand, "report") && !objtype_args)
 | 
			
		||||
		/* suppress duplicate rows of output */
 | 
			
		||||
		_statstype |= (DM_STATS_WALK_ALL
 | 
			
		||||
			       | DM_STATS_WALK_SKIP_SINGLE_AREA);
 | 
			
		||||
 | 
			
		||||
	if (names)
 | 
			
		||||
		name = names->name;
 | 
			
		||||
@@ -5068,6 +5200,121 @@ out:
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _stats_group(CMD_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	char *name, *alias = NULL, *regions = NULL;
 | 
			
		||||
	struct dm_stats *dms;
 | 
			
		||||
	uint64_t group_id;
 | 
			
		||||
	int r = 0;
 | 
			
		||||
 | 
			
		||||
	/* group does not use a report */
 | 
			
		||||
	if (_report) {
 | 
			
		||||
		dm_report_free(_report);
 | 
			
		||||
		_report = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_switches[REGIONS_ARG]) {
 | 
			
		||||
		err("Group requires --regions.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	regions = _string_args[REGIONS_ARG];
 | 
			
		||||
 | 
			
		||||
	if (names)
 | 
			
		||||
		name = names->name;
 | 
			
		||||
	else {
 | 
			
		||||
		if (!argc && !_switches[UUID_ARG] && !_switches[MAJOR_ARG]) {
 | 
			
		||||
			if (!_switches[ALL_DEVICES_ARG]) {
 | 
			
		||||
				log_error("Please specify device(s) or use "
 | 
			
		||||
					  "--alldevices.");
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
			return _process_all(cmd, subcommand, argc, argv, 0, _stats_group);
 | 
			
		||||
		}
 | 
			
		||||
		name = argv[0];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (_switches[ALIAS_ARG])
 | 
			
		||||
		alias = _string_args[ALIAS_ARG];
 | 
			
		||||
 | 
			
		||||
	if (!(dms = dm_stats_create(DM_STATS_PROGRAM_ID)))
 | 
			
		||||
		return_0;
 | 
			
		||||
 | 
			
		||||
	if (!_bind_stats_device(dms, name))
 | 
			
		||||
		goto_out;
 | 
			
		||||
 | 
			
		||||
	if (!dm_stats_list(dms, NULL))
 | 
			
		||||
		goto_out;
 | 
			
		||||
 | 
			
		||||
	if(!dm_stats_create_group(dms, regions, alias, &group_id)) {
 | 
			
		||||
		log_error("Could not create group on %s: %s", name, regions);
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	printf("Grouped regions %s as group ID " FMTu64 " on %s\n",
 | 
			
		||||
	       regions, group_id, name);
 | 
			
		||||
 | 
			
		||||
	r = 1;
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	dm_stats_destroy(dms);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _stats_ungroup(CMD_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_stats *dms;
 | 
			
		||||
	uint64_t group_id;
 | 
			
		||||
	char *name;
 | 
			
		||||
	int r = 0;
 | 
			
		||||
 | 
			
		||||
	/* ungroup does not use a report */
 | 
			
		||||
	if (_report) {
 | 
			
		||||
		dm_report_free(_report);
 | 
			
		||||
		_report = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_switches[GROUP_ID_ARG]) {
 | 
			
		||||
		err("Please specify group id.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	group_id = (uint64_t) _int_args[GROUP_ID_ARG];
 | 
			
		||||
 | 
			
		||||
	if (names)
 | 
			
		||||
		name = names->name;
 | 
			
		||||
	else {
 | 
			
		||||
		if (!argc && !_switches[UUID_ARG] && !_switches[MAJOR_ARG]) {
 | 
			
		||||
			if (!_switches[ALL_DEVICES_ARG]) {
 | 
			
		||||
				log_error("Please specify device(s) or use "
 | 
			
		||||
					  "--alldevices.");
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
			return _process_all(cmd, subcommand, argc, argv, 0, _stats_ungroup);
 | 
			
		||||
		}
 | 
			
		||||
		name = argv[0];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(dms = dm_stats_create(DM_STATS_PROGRAM_ID)))
 | 
			
		||||
		return_0;
 | 
			
		||||
 | 
			
		||||
	if (!_bind_stats_device(dms, name))
 | 
			
		||||
		goto_out;
 | 
			
		||||
 | 
			
		||||
	if (!dm_stats_list(dms, NULL))
 | 
			
		||||
		goto_out;
 | 
			
		||||
 | 
			
		||||
	if (!(r = dm_stats_delete_group(dms, group_id, 0)))
 | 
			
		||||
		log_error("Could not delete group " FMTu64 " on %s.",
 | 
			
		||||
			  group_id, name);
 | 
			
		||||
 | 
			
		||||
	printf("Removed group ID "FMTu64" on %s\n", group_id, name);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	dm_stats_destroy(dms);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Command dispatch tables and usage.
 | 
			
		||||
 */
 | 
			
		||||
@@ -5080,30 +5327,35 @@ static int _stats_help(CMD_ARGS);
 | 
			
		||||
 *    clear [--regionid id] <device_name>
 | 
			
		||||
 *    create [--areas nr_areas] [--areasize size]
 | 
			
		||||
 *           [ [--start start] [--length len] | [--segments]]
 | 
			
		||||
 *           [--auxdata data] [--programid id] [<device_name>]
 | 
			
		||||
 *           [--userdata data] [--programid id] [<device_name>]
 | 
			
		||||
 *    delete [--regionid] <device_name>
 | 
			
		||||
 *    delete_all [--programid id]
 | 
			
		||||
 *    group [--alias name] [--alldevices] [--regions <regions>] [<device_name>]
 | 
			
		||||
 *    list [--programid id] [<device_name>]
 | 
			
		||||
 *    print [--clear] [--programid id] [--regionid id] [<device_name>]
 | 
			
		||||
 *    report [--interval seconds] [--count count] [--units units] [--regionid id]
 | 
			
		||||
 *           [--programid id] [<device>]
 | 
			
		||||
 *    ungroup [--alldevices] [--groupid id] [<device_name>]
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define AREA_OPTS "[--areas <nr_areas>] [--areasize <size>] "
 | 
			
		||||
#define CREATE_OPTS "[--start <start> [--length <len>]]\n\t\t" AREA_OPTS
 | 
			
		||||
#define ID_OPTS "[--programid <id>] [--auxdata <data> ] "
 | 
			
		||||
#define ID_OPTS "[--programid <id>] [--userdata <data> ] "
 | 
			
		||||
#define SELECT_OPTS "[--programid <id>] [--regionid <id>] "
 | 
			
		||||
#define PRINT_OPTS "[--clear] " SELECT_OPTS
 | 
			
		||||
#define REPORT_OPTS "[--interval <seconds>] [--count <cnt>]\n\t\t[--units <u>]" SELECT_OPTS
 | 
			
		||||
#define GROUP_OPTS "[--alias NAME] --regions <regions>"
 | 
			
		||||
 | 
			
		||||
static struct command _stats_subcommands[] = {
 | 
			
		||||
	{"help", "", 0, 0, 0, 0, _stats_help},
 | 
			
		||||
	{"clear", "--regionid <id> [<device>]", 0, -1, 1, 0, _stats_clear},
 | 
			
		||||
	{"create", CREATE_OPTS "\n\t\t" ID_OPTS "[<device>]", 0, -1, 1, 0, _stats_create},
 | 
			
		||||
	{"delete", "--regionid <id> <device>", 1, -1, 1, 0, _stats_delete},
 | 
			
		||||
	{"group", GROUP_OPTS, 1, -1, 1, 0, _stats_group},
 | 
			
		||||
	{"list", "[--programid <id>] [<device>]", 0, -1, 1, 0, _stats_report},
 | 
			
		||||
	{"print", PRINT_OPTS "[<device>]", 0, -1, 1, 0, _stats_print},
 | 
			
		||||
	{"report", REPORT_OPTS "[<device>]", 0, -1, 1, 0, _stats_report},
 | 
			
		||||
	{"ungroup", "--groupid <id> [device]", 1, -1, 1, 0, _stats_ungroup},
 | 
			
		||||
	{"version", "", 0, -1, 1, 0, _version},
 | 
			
		||||
	{NULL, NULL, 0, 0, 0, 0, NULL}
 | 
			
		||||
};
 | 
			
		||||
@@ -5177,7 +5429,7 @@ static void _stats_usage(FILE *out)
 | 
			
		||||
	fprintf(out, "        [-h|--help]\n");
 | 
			
		||||
	fprintf(out, "        [-v|--verbose [-v|--verbose ...]]\n");
 | 
			
		||||
	fprintf(out, "        [--areas <nr_areas>] [--areasize <size>]\n");
 | 
			
		||||
	fprintf(out, "        [--auxdata <data>] [--clear]\n");
 | 
			
		||||
	fprintf(out, "        [--userdata <data>] [--clear]\n");
 | 
			
		||||
	fprintf(out, "        [--count <count>] [--interval <seconds>]\n");
 | 
			
		||||
	fprintf(out, "        [-o <fields>] [-O|--sort <sort_fields>]\n");
 | 
			
		||||
	fprintf(out, "	      [--programid <id>]\n");
 | 
			
		||||
@@ -5319,6 +5571,18 @@ static int _stats(CMD_ARGS)
 | 
			
		||||
{
 | 
			
		||||
	const struct command *stats_cmd;
 | 
			
		||||
 | 
			
		||||
	if (_switches[AREA_ARG] || _switches[REGION_ARG] || _switches[GROUP_ARG])
 | 
			
		||||
		_statstype = 0; /* switches will OR flags in */
 | 
			
		||||
	else
 | 
			
		||||
		_statstype = DM_STATS_WALK_REGION | DM_STATS_WALK_GROUP;
 | 
			
		||||
 | 
			
		||||
	if (_switches[AREA_ARG])
 | 
			
		||||
		_statstype |= DM_STATS_WALK_AREA;
 | 
			
		||||
	if (_switches[REGION_ARG])
 | 
			
		||||
		_statstype |= DM_STATS_WALK_REGION;
 | 
			
		||||
	if (_switches[GROUP_ARG])
 | 
			
		||||
		_statstype |= DM_STATS_WALK_GROUP;
 | 
			
		||||
 | 
			
		||||
	if (!(stats_cmd = _find_stats_subcommand(subcommand))) {
 | 
			
		||||
		log_error("Unknown stats command.");
 | 
			
		||||
		_stats_help(stats_cmd, NULL, argc, argv, NULL, multiple_devices);
 | 
			
		||||
@@ -5702,12 +5966,13 @@ 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},
 | 
			
		||||
		{"area", 0, &ind, AREA_ARG},
 | 
			
		||||
		{"areas", 1, &ind, AREAS_ARG},
 | 
			
		||||
		{"areasize", 1, &ind, AREA_SIZE_ARG},
 | 
			
		||||
		{"auxdata", 1, &ind, AUX_DATA_ARG},
 | 
			
		||||
		{"bounds", 1, &ind, BOUNDS_ARG},
 | 
			
		||||
		{"checks", 0, &ind, CHECKS_ARG},
 | 
			
		||||
		{"clear", 0, &ind, CLEAR_ARG},
 | 
			
		||||
@@ -5718,6 +5983,8 @@ static int _process_switches(int *argcp, char ***argvp, const char *dev_dir)
 | 
			
		||||
		{"exec", 1, &ind, EXEC_ARG},
 | 
			
		||||
		{"force", 0, &ind, FORCE_ARG},
 | 
			
		||||
		{"gid", 1, &ind, GID_ARG},
 | 
			
		||||
		{"group", 0, &ind, GROUP_ARG},
 | 
			
		||||
		{"groupid", 1, &ind, GROUP_ID_ARG},
 | 
			
		||||
		{"help", 0, &ind, HELP_ARG},
 | 
			
		||||
		{"histogram", 0, &ind, HISTOGRAM_ARG},
 | 
			
		||||
		{"inactive", 0, &ind, INACTIVE_ARG},
 | 
			
		||||
@@ -5743,6 +6010,8 @@ static int _process_switches(int *argcp, char ***argvp, const char *dev_dir)
 | 
			
		||||
		{"programid", 1, &ind, PROGRAM_ID_ARG},
 | 
			
		||||
		{"raw", 0, &ind, RAW_ARG},
 | 
			
		||||
		{"readahead", 1, &ind, READAHEAD_ARG},
 | 
			
		||||
		{"region", 0, &ind, REGION_ARG},
 | 
			
		||||
		{"regions", 1, &ind, REGIONS_ARG},
 | 
			
		||||
		{"regionid", 1, &ind, REGION_ID_ARG},
 | 
			
		||||
		{"relative", 0, &ind, RELATIVE_ARG},
 | 
			
		||||
		{"retry", 0, &ind, RETRY_ARG},
 | 
			
		||||
@@ -5761,6 +6030,7 @@ static int _process_switches(int *argcp, char ***argvp, const char *dev_dir)
 | 
			
		||||
		{"uuid", 1, &ind, UUID_ARG},
 | 
			
		||||
		{"unbuffered", 0, &ind, UNBUFFERED_ARG},
 | 
			
		||||
		{"unquoted", 0, &ind, UNQUOTED_ARG},
 | 
			
		||||
		{"userdata", 1, &ind, USER_DATA_ARG},
 | 
			
		||||
		{"verbose", 1, &ind, VERBOSE_ARG},
 | 
			
		||||
		{"verifyudev", 0, &ind, VERIFYUDEV_ARG},
 | 
			
		||||
		{"version", 0, &ind, VERSION_ARG},
 | 
			
		||||
@@ -5838,12 +6108,18 @@ 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)
 | 
			
		||||
			_switches[ALL_PROGRAMS_ARG]++;
 | 
			
		||||
		if (ind == ALL_REGIONS_ARG)
 | 
			
		||||
			_switches[ALL_REGIONS_ARG]++;
 | 
			
		||||
		if (ind == AREA_ARG)
 | 
			
		||||
			_switches[AREA_ARG]++;
 | 
			
		||||
		if (ind == AREAS_ARG) {
 | 
			
		||||
			_switches[AREAS_ARG]++;
 | 
			
		||||
			_int_args[AREAS_ARG] = atoi(optarg);
 | 
			
		||||
@@ -5852,9 +6128,9 @@ static int _process_switches(int *argcp, char ***argvp, const char *dev_dir)
 | 
			
		||||
			_switches[AREA_SIZE_ARG]++;
 | 
			
		||||
			_string_args[AREA_SIZE_ARG] = optarg;
 | 
			
		||||
		}
 | 
			
		||||
		if (ind == AUX_DATA_ARG) {
 | 
			
		||||
			_switches[AUX_DATA_ARG]++;
 | 
			
		||||
			_string_args[AUX_DATA_ARG] = optarg;
 | 
			
		||||
		if (ind == USER_DATA_ARG) {
 | 
			
		||||
			_switches[USER_DATA_ARG]++;
 | 
			
		||||
			_string_args[USER_DATA_ARG] = optarg;
 | 
			
		||||
		}
 | 
			
		||||
		if (c == ':' || c == '?')
 | 
			
		||||
			return_0;
 | 
			
		||||
@@ -5882,6 +6158,10 @@ static int _process_switches(int *argcp, char ***argvp, const char *dev_dir)
 | 
			
		||||
			_switches[MAJOR_ARG]++;
 | 
			
		||||
			_int_args[MAJOR_ARG] = atoi(optarg);
 | 
			
		||||
		}
 | 
			
		||||
		if (ind == REGIONS_ARG) {
 | 
			
		||||
			_switches[REGIONS_ARG]++;
 | 
			
		||||
			_string_args[REGIONS_ARG] = optarg;
 | 
			
		||||
		}
 | 
			
		||||
		if (c == 'm' || ind == MINOR_ARG) {
 | 
			
		||||
			_switches[MINOR_ARG]++;
 | 
			
		||||
			_int_args[MINOR_ARG] = atoi(optarg);
 | 
			
		||||
@@ -5904,6 +6184,8 @@ static int _process_switches(int *argcp, char ***argvp, const char *dev_dir)
 | 
			
		||||
			_switches[PRECISE_ARG]++;
 | 
			
		||||
		if (ind == RAW_ARG)
 | 
			
		||||
			_switches[RAW_ARG]++;
 | 
			
		||||
		if (ind == REGION_ARG)
 | 
			
		||||
			_switches[REGION_ARG]++;
 | 
			
		||||
		if (ind == REGION_ID_ARG) {
 | 
			
		||||
			_switches[REGION_ID_ARG]++;
 | 
			
		||||
			_int_args[REGION_ID_ARG] = atoi(optarg);
 | 
			
		||||
@@ -5966,6 +6248,12 @@ static int _process_switches(int *argcp, char ***argvp, const char *dev_dir)
 | 
			
		||||
			_switches[GID_ARG]++;
 | 
			
		||||
			_int_args[GID_ARG] = atoi(optarg);
 | 
			
		||||
		}
 | 
			
		||||
		if (ind == GROUP_ARG)
 | 
			
		||||
			_switches[GROUP_ARG]++;
 | 
			
		||||
		if (ind == GROUP_ID_ARG) {
 | 
			
		||||
			_switches[GROUP_ID_ARG]++;
 | 
			
		||||
			_int_args[GROUP_ID_ARG] = atoi(optarg);
 | 
			
		||||
		}
 | 
			
		||||
		if (c == 'U' || ind == UID_ARG) {
 | 
			
		||||
			_switches[UID_ARG]++;
 | 
			
		||||
			_int_args[UID_ARG] = atoi(optarg);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										132
									
								
								tools/vgsplit.c
									
									
									
									
									
								
							
							
						
						
									
										132
									
								
								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;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user