summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBryn M. Reeves <bmr@redhat.com>2016-06-30 21:48:10 +0100
committerBryn M. Reeves <bmr@redhat.com>2016-07-08 14:34:41 +0100
commit7ebe630b696e3bdbd66760ba140e05d11a999df5 (patch)
treeee96ac66e256ee4342f5c5cc45d502c7fb45786b
parente1048259165b09a35c45170cefbbccb4d43a9834 (diff)
downloadlvm2-7ebe630b696e3bdbd66760ba140e05d11a999df5.tar.gz
dmstats: add create --filemap
Add a new option to the create command to create regions that map the extents of a file: # dmstats create --filemap /path/to/file /path/to/file: Created new group with 10 region(s) as group ID 0. When performing a --filemap no device argument is required (and supplying one results in error) since the device to bind to is implied by the file path and is obtained directly from an fstat(). Grouping may be optionally disabled by the --nogroup switch: in this case the command will report each region individually: # dmstats create --nogroup --filemap /path/to/file /path/to/file: Created new region with 1 area as region ID 0. /path/to/file: Created new region with 1 area as region ID 1. /path/to/file: Created new region with 1 area as region ID 2. When grouping regions the group alias is automatically set to the basename (as returned by dm_basename()) of the provided file. This can be overridden to a user-defined value at the command line by use of the --alias option. If grouping is disabled no alias can be set. Use of offset and subdivision options (--start, --length, --segments, --areas, --areasize). Setting aux_data and histograms for groups is possible but is not currently implemented.
-rw-r--r--tools/dmsetup.c221
1 files changed, 203 insertions, 18 deletions
diff --git a/tools/dmsetup.c b/tools/dmsetup.c
index 83d45da65..637a82ab8 100644
--- a/tools/dmsetup.c
+++ b/tools/dmsetup.c
@@ -171,6 +171,7 @@ enum {
DEFERRED_ARG,
SELECT_ARG,
EXEC_ARG,
+ FILEMAP_ARG,
FORCE_ARG,
GID_ARG,
GROUP_ARG,
@@ -187,6 +188,7 @@ enum {
MODE_ARG,
NAMEPREFIXES_ARG,
NOFLUSH_ARG,
+ NOGROUP_ARG,
NOHEADINGS_ARG,
NOLOCKFS_ARG,
NOOPENCOUNT_ARG,
@@ -4611,6 +4613,24 @@ static int _bind_stats_device(struct dm_stats *dms, const char *name)
return 1;
}
+static int _bind_stats_from_fd(struct dm_stats *dms, int fd)
+{
+ int major, minor;
+ struct stat buf;
+
+ if (fstat(fd, &buf)) {
+ log_error("fstat failed for fd %d.", fd);
+ return 0;
+ }
+
+ major = (int) MAJOR(buf.st_dev);
+ minor = (int) MINOR(buf.st_dev);
+
+ if (!dm_stats_bind_devno(dms, major, minor))
+ return_0;
+ return 1;
+}
+
static int _stats_clear_one_region(struct dm_stats *dms, uint64_t region_id)
{
@@ -4841,6 +4861,176 @@ out:
return r;
}
+/*
+ * Returns the full absolute path, or NULL if the path could
+ * not be resolved.
+ */
+static char *_get_abspath(const char *path)
+{
+ char *_path;
+
+#ifdef HAVE_CANONICALIZE_FILE_NAME
+ _path = canonicalize_file_name(path);
+#else
+ /* FIXME Provide alternative */
+ log_error(INTERNAL_ERROR "Unimplemented _get_abspath.");
+ _path = NULL;
+#endif
+ return _path;
+}
+
+static int _stats_create_file(CMD_ARGS)
+{
+ const char *alias, *program_id = DM_STATS_PROGRAM_ID;
+ uint64_t *regions, *region, count = 0;
+ char *path, *abspath = NULL;
+ int group, fd, precise;
+ struct dm_stats *dms;
+
+ if (_switches[AREAS_ARG] || _switches[AREA_SIZE_ARG]) {
+ log_error("--filemap is incompatible with --areas and --area-size.");
+ return 0;
+ }
+
+ if (_switches[START_ARG] || _switches[LENGTH_ARG]) {
+ log_error("--filemap is incompatible with --start and --length.");
+ return 0;
+ }
+
+ if (_switches[SEGMENTS_ARG]) {
+ log_error("--filemap and --segments are incompatible.");
+ return 0;
+ }
+
+ if (_switches[USER_DATA_ARG]) {
+ log_error("--userdata is not yet supported with --filemap.");
+ return 0;
+ }
+
+ if (_switches[BOUNDS_ARG]) {
+ log_error("--bounds is not yet supported with --filemap.");
+ return 0;
+ }
+
+ /* _stats_create_file does not use _process_all() */
+ if (names) {
+ log_error("Device argument not compatible with --filemap.");
+ return 0;
+ } else {
+ if (argc || _switches[UUID_ARG] || _switches[MAJOR_ARG]) {
+ log_error("--uuid, --major, and device argument are "
+ "incompatible with --filemap.");
+ return 0;
+ }
+ if (_switches[ALL_DEVICES_ARG]) {
+ log_error("--alldevices is incompatible with "
+ "--filemap.");
+ return 0;
+ }
+ }
+
+ if (_switches[PRECISE_ARG]) {
+ if (!dm_stats_driver_supports_precise()) {
+ log_error("Using --precise requires driver version "
+ "4.32.0 or later.");
+ return 0;
+ }
+ }
+
+ if (_switches[BOUNDS_ARG]) {
+ if (!dm_stats_driver_supports_histogram()) {
+ log_error("Using --bounds requires driver version "
+ "4.32.0 or later.");
+ return 0;
+ }
+ }
+
+ if (_switches[PROGRAM_ID_ARG])
+ program_id = _string_args[PROGRAM_ID_ARG];
+ if (!strlen(program_id) && !_switches[FORCE_ARG])
+ program_id = DM_STATS_PROGRAM_ID;
+
+ path = _string_args[FILEMAP_ARG];
+ precise = _int_args[PRECISE_ARG];
+ group = !_switches[NOGROUP_ARG];
+
+ if (!(abspath = _get_abspath(path))) {
+ log_error("Could not canonicalize file name: %s", path);
+ return 0;
+ }
+
+ if (!(dms = dm_stats_create(DM_STATS_PROGRAM_ID)))
+ return_0;
+
+ fd = open(abspath, O_RDONLY);
+
+ if (fd < 0) {
+ log_error("Could not open %s for reading", path);
+ goto bad;
+ }
+
+ if (!_bind_stats_from_fd(dms, fd))
+ goto_bad;
+
+ if (!strlen(program_id))
+ /* force creation of a region with no id */
+ dm_stats_set_program_id(dms, 1, NULL);
+
+ if (group && !_switches[ALIAS_ARG])
+ alias = dm_basename(abspath);
+ else if (group)
+ alias = _string_args[ALIAS_ARG];
+ else if (!_switches[ALIAS_ARG])
+ alias = NULL;
+ else {
+ log_error("Cannot set alias with --nogroup.");
+ goto bad;
+ }
+
+ regions = dm_stats_create_regions_from_fd(dms, fd, group, precise,
+ NULL, alias);
+
+ if (close(fd))
+ log_error("Error closing %s", path);
+
+ fd = -1;
+
+ if (!regions) {
+ log_error("Could not create regions from file %s", path);
+ goto bad;
+ }
+
+ for (region = regions; *region != DM_STATS_REGIONS_ALL; region++) {
+ count++;
+ }
+
+ if (group) {
+ printf("%s: Created new group with "FMTu64" region(s) as "
+ "group ID "FMTu64".\n", path, count, regions[0]);
+ } else {
+ region = regions;
+ do
+ printf("%s: Created new region with 1 area as "
+ "region ID "FMTu64".\n", path, *region);
+ while (*(++region) != DM_STATS_REGIONS_ALL);
+ }
+
+ dm_free(regions);
+ dm_free(abspath);
+ dm_stats_destroy(dms);
+ return 1;
+
+bad:
+ if (abspath)
+ dm_free(abspath);
+
+ if ((fd > -1) && close(fd))
+ log_error("Error closing %s", path);
+
+ dm_stats_destroy(dms);
+ return 0;
+}
+
static int _stats_create(CMD_ARGS)
{
struct dm_stats *dms;
@@ -4876,6 +5066,10 @@ static int _stats_create(CMD_ARGS)
return 0;
}
+ if (_switches[FILEMAP_ARG])
+ return _stats_create_file(cmd, subcommand, argc, argv,
+ names, multiple_devices);
+
if (names)
name = names->name;
else {
@@ -5030,6 +5224,7 @@ static int _stats_delete(CMD_ARGS)
log_error("Could not delete statistics group.");
goto out;
}
+ printf("Deleted statistics group " FMTu64 ".\n", group_id);
} else if (_switches[ALL_REGIONS_ARG]) {
dm_stats_foreach_region(dms) {
region_id = dm_stats_get_current_region(dms);
@@ -5682,24 +5877,6 @@ static int _process_tree_options(const char *options)
return 1;
}
-/*
- * Returns the full absolute path, or NULL if the path could
- * not be resolved.
- */
-static char *_get_abspath(const char *path)
-{
- char *_path;
-
-#ifdef HAVE_CANONICALIZE_FILE_NAME
- _path = canonicalize_file_name(path);
-#else
- /* FIXME Provide alternative */
- log_error(INTERNAL_ERROR "Unimplemented _get_abspath.");
- _path = NULL;
-#endif
- return _path;
-}
-
static char *parse_loop_device_name(const char *dev, const char *dev_dir)
{
char *buf;
@@ -5984,6 +6161,7 @@ static int _process_switches(int *argcp, char ***argvp, const char *dev_dir)
{"deferred", 0, &ind, DEFERRED_ARG},
{"select", 1, &ind, SELECT_ARG},
{"exec", 1, &ind, EXEC_ARG},
+ {"filemap", 1, &ind, FILEMAP_ARG},
{"force", 0, &ind, FORCE_ARG},
{"gid", 1, &ind, GID_ARG},
{"group", 0, &ind, GROUP_ARG},
@@ -5998,6 +6176,7 @@ static int _process_switches(int *argcp, char ***argvp, const char *dev_dir)
{"minor", 1, &ind, MINOR_ARG},
{"mode", 1, &ind, MODE_ARG},
{"nameprefixes", 0, &ind, NAMEPREFIXES_ARG},
+ {"nogroup", 0, &ind, NOGROUP_ARG},
{"noflush", 0, &ind, NOFLUSH_ARG},
{"noheadings", 0, &ind, NOHEADINGS_ARG},
{"nolockfs", 0, &ind, NOLOCKFS_ARG},
@@ -6147,6 +6326,10 @@ static int _process_switches(int *argcp, char ***argvp, const char *dev_dir)
_switches[CLEAR_ARG]++;
if (c == 'c' || c == 'C' || ind == COLS_ARG)
_switches[COLS_ARG]++;
+ if (ind == FILEMAP_ARG) {
+ _switches[FILEMAP_ARG]++;
+ _string_args[FILEMAP_ARG] = optarg;
+ }
if (c == 'f' || ind == FORCE_ARG)
_switches[FORCE_ARG]++;
if (c == 'r' || ind == READ_ONLY)
@@ -6306,6 +6489,8 @@ static int _process_switches(int *argcp, char ***argvp, const char *dev_dir)
_switches[NAMEPREFIXES_ARG]++;
if (ind == NOFLUSH_ARG)
_switches[NOFLUSH_ARG]++;
+ if (ind == NOGROUP_ARG)
+ _switches[NOGROUP_ARG]++;
if (ind == NOHEADINGS_ARG)
_switches[NOHEADINGS_ARG]++;
if (ind == NOLOCKFS_ARG)