1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-09-06 05:44:18 +03:00

Compare commits

...

17 Commits

Author SHA1 Message Date
Bryn M. Reeves
d901468a27 doc: update dmstats.8.in for --filemap and --nogroup 2016-07-08 14:34:41 +01:00
Bryn M. Reeves
7ebe630b69 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.
2016-07-08 14:34:41 +01:00
Bryn M. Reeves
e104825916 libdm: add dm_stats_create_regions_from_fd()
Add a call to create dmstats regions that correspond to the extents
present in a file descriptor open on a file in a local file system.
The file must reside on a file system type that correctly supports
physical extent location data in the FIEMAP ioctl.

Regions are optionally placed into a group with a user-defined alias.

File systems that do not support physical offsets in FIEMAP (btrfs
currently) are detected via fstatfs() - although attempting to map
a --filemap group on btrfs will fail anyway with the generic error
"Not on a device-mapper device" this is confusing; the file system
mount is on a device-mapper device, but btrfs' volume layer masks
this in the returned st_dev field since the returned logical file
extents may span multiple physical devices.
2016-07-08 14:34:41 +01:00
Heinz Mauelshagen
12ecd95965 man: enhance lvconvert 2016-07-08 15:18:18 +02:00
Bryn M. Reeves
ebc7fc67c8 libdm: fix group resource leak in dm_stats_delete_region()
The function _stats_remove_region_id_from_group() incorecctly set
the group_id to DM_STATS_GROUP_NOT_PRESENT _before_ the call to
_stats_group_destroy(). This will cause the destroy function to
return immediately without doing anything:

 339 static void _stats_group_destroy(struct dm_stats_group *group)
 340 {
 341         if (!_stats_group_present(group))
 342                 return;

Invalidating the ID in _stats_region_region_id_from_group() is
redundant anyway; it is rightly done as the last operation in
_stats_group_destroy (and it is not possible for anything to see
the old value between the two calls).

Remove the change to group_id to ensure that the alias and bitset
resources are correctly freed.
2016-07-08 12:30:09 +01:00
Bryn M. Reeves
005adb0a0a dmstats: ensure dm_stats_delete_region() return is checked 2016-07-08 12:26:34 +01:00
Bryn M. Reeves
cc4f036d36 libdm: improve comments in stats grouping functions
Add more detailed comments to dm_stats_create_group() and
_stats_group_check_overlap().
2016-07-08 11:16:12 +01:00
Bryn M. Reeves
059a383cf8 libdm: fix resource leak in dm_stats_set_alias()
When we fail to update aux_data the newly allocated group->alias must
be freed before reinstating old_alias.
2016-07-08 11:14:29 +01:00
Bryn M. Reeves
5e06b33c51 libdm: enclose dm_stats_walk_do/while() body in do..while
The call to dm_stats_walk_start() before the do statement makes
dm_stats_walk_do() behave inconsistently depending on context;
wrap them in an additional do { } while (0) so that the macro
always expands to a valid statement.
2016-07-08 11:14:22 +01:00
David Teigland
6233bcf52d man: more lvcreate size rewording 2016-07-07 17:21:05 -05:00
David Teigland
589b752eeb man: rewrite lvconvert
Based on the new enumeration of all possible commands.
2016-07-07 17:12:37 -05:00
David Teigland
0de56eeaad man: more rewording for lvcreate size 2016-07-07 13:11:43 -05:00
David Teigland
13cd3ff5a0 lvconvert: allow converting type raid1 to type linear
The code could perform this conversion but ironically
did not recognize the standard command form, only the
the unpreferred "implication-based" command form.

"lvconvert --type linear VG/RaidLV" would fail, but
"lvconvert --mirrors 0 VG/RaidLV" would succeed.
2016-07-06 16:44:18 -05:00
David Teigland
37d1b7b745 lvconvert: allow converting type mirror to type linear
The code could perform this conversion but ironically
did not recognize the standard command form, only the
the unpreferred "implication-based" command form.

"lvconvert --type linear VG/MirrorLV" would fail, but
"lvconvert --mirrors 0 VG/MirrorLV" would succeed.
2016-07-06 16:33:25 -05:00
David Teigland
4d1c4e1f73 vgcreate: allow pvcreate force option
Commit a9940bd3c9 began disallowing the -f (force) option
to apply to the implicit pvcreate.  Make it allowed again.
2016-07-06 14:10:53 -05:00
David Teigland
351bcf5f82 man: clarify lvcreate size in extents 2016-07-06 11:35:50 -05:00
Alasdair G Kergon
f6b98ec7ca post-release 2016-07-06 17:04:25 +01:00
13 changed files with 1410 additions and 604 deletions

View File

@@ -1 +1 @@
2.02.160(2)-git (2016-07-06)
2.02.161(2)-git (2016-07-06)

View File

@@ -1 +1 @@
1.02.130-git (2016-07-06)
1.02.131-git (2016-07-06)

View File

@@ -1,3 +1,6 @@
Version 2.02.161 -
================================
Version 2.02.160 - 6th July 2016
================================
Minor fixes from coverity.

View File

@@ -1,3 +1,6 @@
Version 1.02.131 -
================================
Version 1.02.130 - 6th July 2016
================================
Minor fixes from coverity.

View File

@@ -0,0 +1 @@
dm_stats_create_regions_from_fd

View File

@@ -1146,15 +1146,17 @@ for (dm_stats_walk_init((dms), DM_STATS_WALK_GROUP), \
* empty.
*/
#define dm_stats_walk_do(dms) \
dm_stats_walk_start((dms)); \
do
do { \
dm_stats_walk_start((dms)); \
do
/*
* Start a 'while' style loop or end a 'do..while' loop iterating over the
* regions contained in dm_stats handle 'dms'.
*/
#define dm_stats_walk_while(dms) \
while(!dm_stats_walk_end((dms)))
while(!dm_stats_walk_end((dms))); \
} while (0)
/*
* Cursor relative property methods
@@ -1283,6 +1285,35 @@ uint64_t dm_stats_get_group_id(const struct dm_stats *dms, uint64_t region_id);
int dm_stats_get_group_descriptor(const struct dm_stats *dms,
uint64_t group_id, char **buf);
/*
* Create regions that correspond to the extents of a file in the
* filesystem and optionally place them into a group.
*
* File descriptor fd must reference a regular file, open for reading,
* in a local file system that supports the FIEMAP ioctl and that
* returns data describing the physical location of extents.
*
* The file descriptor can be closed by the caller following the call
* to dm_stats_create_regions_from_fd().
*
* The function returns a pointer to an array of uint64_t containing
* the IDs of the newly created regions. The array is terminated by the
* value DM_STATS_REGIONS_ALL and should be freed using dm_free() when
* no longer required.
*
* Unless nogroup is non-zero the regions will be placed into a group
* and the group alias is set to the value supplied.
*
* The group_id for the new group is equal to the region_id value in
* the first array element.
*
* File mapped histograms will be supported in a future version.
*/
uint64_t *dm_stats_create_regions_from_fd(struct dm_stats *dms, int fd,
int group, int precise,
struct dm_histogram *bounds,
const char *alias);
/*
* Call this to actually run the ioctl.
*/

View File

@@ -1,5 +1,8 @@
/*
* Copyright (C) 2015 Red Hat, Inc. All rights reserved.
* Copyright (C) 2016 Red Hat, Inc. All rights reserved.
*
* _stats_get_extents_for_file() based in part on filefrag_fiemap() from
* e2fsprogs/misc/filefrag.c. Copyright 2003 by Theodore Ts'o.
*
* This file is part of the device-mapper userspace tools.
*
@@ -16,6 +19,12 @@
#include "math.h" /* log10() */
#include <sys/ioctl.h>
#include <sys/vfs.h> /* fstatfs */
#include <linux/fs.h> /* FS_IOC_FIEMAP */
#include <linux/fiemap.h> /* fiemap */
#include <linux/magic.h> /* BTRFS_SUPER_MAGIC */
#define DM_STATS_REGION_NOT_PRESENT UINT64_MAX
#define DM_STATS_GROUP_NOT_PRESENT DM_STATS_GROUP_NONE
@@ -1980,7 +1989,6 @@ static int _stats_remove_region_id_from_group(struct dm_stats *dms,
/* removing group leader? */
if (region_id == group_id) {
dms->groups[group_id].group_id = DM_STATS_GROUP_NOT_PRESENT;
_stats_clear_group_regions(dms, group_id);
_stats_group_destroy(&dms->groups[group_id]);
}
@@ -3106,6 +3114,7 @@ int dm_stats_set_alias(struct dm_stats *dms, uint64_t group_id, const char *alia
return 1;
bad:
dm_free((char *) group->alias);
group->alias = old_alias;
return 0;
}
@@ -3685,6 +3694,7 @@ static int _stats_group_check_overlap(const struct dm_stats *dms,
return 0;
}
/* build a table of extents in order of region_id */
for (id = dm_bit_get_first(regions); id >= 0;
id = dm_bit_get_next(regions, id)) {
dm_list_init(&map[i].list);
@@ -3694,6 +3704,7 @@ static int _stats_group_check_overlap(const struct dm_stats *dms,
i++;
}
/* sort by extent.start */
qsort(map, count, sizeof(*map), _extent_start_compare);
for (i = 0; i < count; i++)
@@ -3723,6 +3734,7 @@ merge:
overlap = merged = 1;
}
}
/* continue until no merge candidates remain */
if (merged)
goto merge;
@@ -3756,6 +3768,11 @@ int dm_stats_create_group(struct dm_stats *dms, const char *members,
goto bad;
}
/*
* Check that each region_id in the bitmap meets the group
* constraints: present, not already grouped, and if any
* histogram is present that they all have the same bounds.
*/
for (i = dm_bit_get_first(regions); i >= 0;
i = dm_bit_get_next(regions, i)) {
if (!dm_stats_region_present(dms, i)) {
@@ -3827,9 +3844,11 @@ int dm_stats_delete_group(struct dm_stats *dms, uint64_t group_id,
}
}
/* clear group and mark as not present */
_stats_clear_group_regions(dms, group_id);
_stats_group_destroy(&dms->groups[group_id]);
/* delete leader or clear aux_data */
if (remove_regions)
return dm_stats_delete_region(dms, group_id);
else if (!_stats_set_aux(dms, group_id, leader->aux_data))
@@ -3876,6 +3895,297 @@ int dm_stats_get_group_descriptor(const struct dm_stats *dms,
return 1;
}
/*
* Group a table of region_ids corresponding to the extents of a file.
*/
static int _stats_group_file_regions(struct dm_stats *dms, uint64_t *region_ids,
uint64_t count, const char *alias)
{
dm_bitset_t regions = dm_bitset_create(NULL, dms->nr_regions);
uint64_t i, group_id = DM_STATS_GROUP_NOT_PRESENT;
char *members = NULL;
int buflen;
if (!regions) {
log_error("Cannot map file: failed to allocate group bitmap.");
return 0;
}
for (i = 0; i < count; i++)
dm_bit_set(regions, region_ids[i]);
buflen = _stats_group_tag_len(dms, regions);
members = dm_malloc(buflen);
if (!members) {
log_error("Cannot map file: failed to allocate group "
"descriptor.");
dm_bitset_destroy(regions);
return 0;
}
if (!_stats_group_tag_fill(dms, regions, members, buflen))
goto bad;
/*
* overlaps should not be possible: overlapping file extents
* returned by FIEMAP imply a kernel bug or a corrupt fs.
*/
if (!_stats_group_check_overlap(dms, regions, count))
log_info("Creating group with overlapping regions.");
if (!_stats_create_group(dms, regions, alias, &group_id))
goto bad;
dm_free(members);
return 1;
bad:
dm_bitset_destroy(regions);
dm_free(members);
return 0;
}
static int _stats_add_extent(struct dm_pool *mem, struct fiemap_extent *fm_ext,
uint64_t id)
{
struct _extent extent;
/* final address of list is unknown */
memset(&extent.list, 0, sizeof(extent.list));
/* convert bytes to dm (512b) sectors */
extent.start = fm_ext->fe_physical >> 9;
extent.len = fm_ext->fe_length >> 9;
extent.id = id;
if (!dm_pool_grow_object(mem, &extent,
sizeof(extent))) {
log_error("Cannot map file: failed to grow extent map.");
return 0;
}
return 1;
}
/*
* Read the extents of an open file descriptor into a table of struct _extent.
*
* Based on e2fsprogs/misc/filefrag.c::filefrag_fiemap().
*
* Copyright 2003 by Theodore Ts'o.
*
*/
static struct _extent *_stats_get_extents_for_file(struct dm_pool *mem, int fd,
uint64_t *count)
{
uint64_t buf[2048];
struct fiemap *fiemap = (struct fiemap *)buf;
struct fiemap_extent *fm_ext = &fiemap->fm_extents[0];
struct fiemap_extent fm_last = {0};
struct _extent *extents;
unsigned long long expected = 0;
unsigned long long expected_dense = 0;
unsigned long flags = 0;
unsigned int i, num = 0;
int tot_extents = 0, n = 0;
int last = 0;
int rc;
memset(buf, 0, sizeof(buf));
/* space available per ioctl */
*count = (sizeof(buf) - sizeof(*fiemap))
/ sizeof(struct fiemap_extent);
/* grow temporary extent table in the pool */
if (!dm_pool_begin_object(mem, sizeof(*extents)))
return NULL;
flags |= FIEMAP_FLAG_SYNC;
do {
/* start of ioctl loop - zero size and set count to bufsize */
fiemap->fm_length = ~0ULL;
fiemap->fm_flags = flags;
fiemap->fm_extent_count = *count;
/* get count-sized chunk of extents */
rc = ioctl(fd, FS_IOC_FIEMAP, (unsigned long) fiemap);
if (rc < 0) {
rc = -errno;
if (rc == -EBADR)
log_err_once("FIEMAP failed with unknown "
"flags %x.", fiemap->fm_flags);
goto bad;
}
/* If 0 extents are returned, then more ioctls are not needed */
if (fiemap->fm_mapped_extents == 0)
break;
for (i = 0; i < fiemap->fm_mapped_extents; i++) {
expected_dense = fm_last.fe_physical +
fm_last.fe_length;
expected = fm_last.fe_physical +
fm_ext[i].fe_logical - fm_last.fe_logical;
if ((fm_ext[i].fe_logical != 0)
&& (fm_ext[i].fe_physical != expected)
&& (fm_ext[i].fe_physical != expected_dense)) {
tot_extents++;
if (!_stats_add_extent(mem, fm_ext + i,
tot_extents - 1))
goto bad;
} else {
expected = 0;
if (!tot_extents)
tot_extents = 1;
if (fm_ext[i].fe_logical == 0)
if (!_stats_add_extent(mem, fm_ext + i,
tot_extents - 1))
goto bad;
}
num += tot_extents;
if (fm_ext[i].fe_flags & FIEMAP_EXTENT_LAST)
last = 1;
fm_last = fm_ext[i];
n++;
}
fiemap->fm_start = (fm_ext[i - 1].fe_logical +
fm_ext[i - 1].fe_length);
} while (last == 0);
if (!tot_extents) {
log_error("Cannot map file: no allocated extents.");
goto bad;
}
/* return total number of extents */
*count = tot_extents;
return dm_pool_end_object(mem);
bad:
dm_pool_abandon_object(mem);
return NULL;
}
/*
* Create a set of regions representing the extents of a file and
* return a table of uint64_t region_id values. The number of regions
* created is returned in the memory pointed to by count (which must be
* non-NULL).
*/
static uint64_t *_stats_create_file_regions(struct dm_stats *dms, int fd,
struct dm_histogram *bounds,
int precise, uint64_t *count)
{
struct _extent *extents = NULL;
uint64_t *regions = NULL, i;
struct statfs fsbuf;
struct stat buf;
if (fstatfs(fd, &fsbuf)) {
log_error("fstatfs failed for fd %d", fd);
return 0;
}
if (fsbuf.f_type == BTRFS_SUPER_MAGIC) {
log_error("Cannot map file: btrfs does not provide "
"physical FIEMAP extent data.");
return 0;
}
if (fstat(fd, &buf)) {
log_error("fstat failed for fd %d", fd);
return 0;
}
if (!(buf.st_mode & S_IFREG)) {
log_error("Not a regular file");
return 0;
}
if (!dm_is_dm_major(major(buf.st_dev))) {
log_error("Cannot map file: not a device-mapper device.");
return 0;
}
if (!(extents = _stats_get_extents_for_file(dms->mem, fd, count)))
return_0;
/* make space for end-of-table marker */
if (!(regions = dm_malloc((1 + *count) * sizeof(*regions)))) {
log_error("Could not allocate memory for region IDs.");
goto out;
}
for (i = 0; i < *count; i++) {
if (!_stats_create_region(dms, regions + i,
extents[i].start, extents[i].len, -1,
precise, NULL, dms->program_id, "")) {
log_error("Failed to create region " FMTu64 " of "
FMTu64 " at " FMTu64 ".", i, *count,
extents[i].start);
goto out_remove;
}
}
regions[*count] = DM_STATS_REGION_NOT_PRESENT;
dm_pool_free(dms->mem, extents);
return regions;
out_remove:
/* clean up regions after create failure */
for (--i; i != DM_STATS_REGION_NOT_PRESENT; i--) {
if (!dm_stats_delete_region(dms, i))
log_error("Could not delete region " FMTu64 ".", i);
}
out:
dm_pool_free(dms->mem, extents);
dm_free(regions);
return NULL;
}
uint64_t *dm_stats_create_regions_from_fd(struct dm_stats *dms, int fd,
int group, int precise,
struct dm_histogram *bounds,
const char *alias)
{
uint64_t *regions, count = 0;
if (bounds) {
log_error("File mapped groups with histograms are not "
"yet supported.");
return NULL;
}
if (alias && !group) {
log_error("Cannot set alias without grouping regions.");
return NULL;
}
regions = _stats_create_file_regions(dms, fd, bounds, precise, &count);
if (!regions)
return_0;
if (!group)
return regions;
/* refresh handle */
if (!dm_stats_list(dms, NULL))
goto_out;
if (!_stats_group_file_regions(dms, regions, count, alias))
goto_out;
return regions;
out:
dm_free(regions);
return NULL;
}
/*
* Backward compatible dm_stats_create_region() implementations.
*

View File

@@ -87,6 +87,9 @@ dmstats \(em device-mapper statistics management
. IR area_size ]
. RB [ \-\-bounds
. IR \%histogram_boundaries ]
. RB [ \-\-filemap
. IR path ]
. RB [ \-\-nogroup ]
. RB [ \-\-precise ]
. RB [ \-\-start
. IR start_sector
@@ -299,6 +302,14 @@ When peforming a list or report, include objects of type group in the
results.
.
.HP
.BR \-\-filemap
.IR path
.br
Instead of creating regions specified by command line options, open
the file found at \fBpath\fP, and create regions corresponding to the
locations of the on-disk extents allocated to the file.
.
.HP
.BR \-\-groupid
.IR id
.br
@@ -356,6 +367,12 @@ Specify the major number.
Specify the minor number.
.
.HP
.BR \-\-nogroup
.br
When creating regions mapping the extents of a file in the file
system, do not create a group or set an alias.
.
.HP
.BR \-\-nosuffix
.br
Suppress the suffix on output sizes. Use with \fB\-\-units\fP
@@ -538,8 +555,27 @@ device-mapper kernel statistics subsystem.
By default dmstats creates regions with a \fBprogram_id\fP of
"dmstats".
On success the \fBregion_id\fP of the newly created region is printed to
stdout.
On success the \fBregion_id\fP of the newly created region is printed
to stdout.
If the \fB\-\-filemap\fP option is given with a regular file as the
\fBpath\fP argument, instead of creating regions with parameters
specified on the command line, \fBdmstats\fP will open the file located
at \fBpath\fP and create regions corresponding to the physical extents
allocated to the file. This can be used to monitor statistics for
individual files in the file system, for example, virtual machine
images, swap areas, or large database files.
To work with the \fB\-\-filemap\fP option, files must be located on a
local file system, backed by a device-mapper device, that supports
physical extent data using the FIEMAP ioctl (Ext4 and XFS for e.g.).
By default regions that map a file are placed into a group and the
group alias is set to the basename of the file. This behaviour can be
overridden with the \fB\-\-alias\fP and \fB\-\-nogroup\fP options.
To display only group information when listing and reporting, use the
\fB\-\-statstype\fP option with the 'group' type.
.
.HP
.CMD_DELETE
@@ -1019,6 +1055,14 @@ vg00-lvol1: Created new region with 1 area(s) as region ID 1
.br
vg00-lvol1: Created new region with 1 area(s) as region ID 2
.P
Create regions mapping the file vm.img and place them into a group with
the alias set to the same name as the file.
.br
#
.B dmstats create --filemap vm.img
.br
vm.img: Created new group with 112 region(s) as group ID 3.
.P
Print raw counters for region 4 on device d0
.br
#

File diff suppressed because it is too large Load Diff

View File

@@ -329,19 +329,20 @@ is specified.
.IR LogicalExtentsNumber \c
.RB [ % { VG | PVS | FREE | ORIGIN }]
.br
Gives the number of logical extents to allocate for the new
logical volume. The total number of physical extents allocated will be
greater than this, for example, if the volume is mirrored.
The number can also be expressed as a percentage of the total space
in the Volume Group with the suffix \fB%VG\fP, as a percentage of the
remaining free space in the Volume Group with the suffix \fB%FREE\fP, as a
percentage of the remaining free space for the specified
PhysicalVolume(s) with the suffix \fB%PVS\fP, or (for a snapshot) as a
percentage of the total space in the Origin Logical Volume with the
suffix \fB%ORIGIN\fP (i.e. \fB100%ORIGIN\fP provides space for the whole origin).
When expressed as a percentage, the number is treated
as an approximate upper limit for the number of physical extents
to be allocated (including extents used by any mirrors, for example).
Specifies the size of the new LV in logical extents. The number of
physical extents allocated may be different, and depends on the LV type.
Certain LV types require more physical extents for data redundancy or
metadata. An alternate syntax allows the size to be determined indirectly
as a percentage of the size of a related VG, LV, or set of PVs. The
suffix \fB%VG\fP denotes the total size of the VG, the suffix \fB%FREE\fP
the remaining free space in the VG, and the suffix \fB%PVS\fP the free
space in the specified Physical Volumes. For a snapshot, the size
can be expressed as a percentage of the total size of the Origin Logical
Volume with the suffix \fB%ORIGIN\fP (\fB100%ORIGIN\fP provides space for
the whole origin).
When expressed as a percentage, the size defines an upper limit for the
number of logical extents in the new LV. The precise number of logical
extents in the new LV is not determined until the command has completed.
.
.HP
.BR \-j | \-\-major

View File

@@ -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);
@@ -5040,7 +5235,10 @@ static int _stats_delete(CMD_ARGS)
log_info("Deleted statistics region %" PRIu64, region_id);
}
} else {
dm_stats_delete_region(dms, region_id);
if (!dm_stats_delete_region(dms, region_id)) {
log_error("Could not delete statistics region");
goto out;
}
log_info("Deleted statistics region " FMTu64 ".\n", region_id);
}
@@ -5679,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;
@@ -5981,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},
@@ -5995,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},
@@ -6144,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)
@@ -6303,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)

View File

@@ -1705,6 +1705,7 @@ static int _lvconvert_mirrors(struct cmd_context *cmd,
struct logical_volume *lv,
struct lvconvert_params *lp)
{
const char *new_type;
uint32_t old_mimage_count;
uint32_t old_log_count;
uint32_t new_mimage_count;
@@ -1733,6 +1734,16 @@ static int _lvconvert_mirrors(struct cmd_context *cmd,
return 0;
}
if ((new_type = arg_str_value(cmd, type_ARG, NULL)) &&
!strcmp(new_type, SEG_TYPE_NAME_LINEAR)) {
if (arg_is_set(cmd, mirrors_ARG) && (arg_uint_value(cmd, mirrors_ARG, 0) != 0)) {
log_error("Cannot specify mirrors with linear type.");
return 0;
}
lp->mirrors_supplied = 1;
lp->mirrors = 0;
}
/* Adjust mimage and/or log count */
if (!_lvconvert_mirrors_parse_params(cmd, lv, lp,
&old_mimage_count, &old_log_count,
@@ -1812,6 +1823,7 @@ static void _lvconvert_raid_repair_ask(struct cmd_context *cmd,
static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *lp)
{
const char *new_type;
int replace = 0, image_count = 0;
struct dm_list *failed_pvs;
struct cmd_context *cmd = lv->vg->cmd;
@@ -1821,6 +1833,16 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
if (!lp->segtype)
lp->segtype = seg->segtype;
if ((new_type = arg_str_value(cmd, type_ARG, NULL)) &&
!strcmp(new_type, SEG_TYPE_NAME_LINEAR)) {
if (arg_is_set(cmd, mirrors_ARG) && (arg_uint_value(cmd, mirrors_ARG, 0) != 0)) {
log_error("Cannot specify mirrors with linear type.");
return 0;
}
lp->mirrors_supplied = 1;
lp->mirrors = 0;
}
/* Can only change image count for raid1 and linear */
if (lp->mirrors_supplied && !seg_is_mirrored(seg) && !seg_is_linear(seg)) {
log_error("'--mirrors/-m' is not compatible with %s",
@@ -3614,6 +3636,20 @@ static int _convert_mirror_repair(struct cmd_context *cmd, struct logical_volume
return ret;
}
/*
* Convert mirror LV to linear LV.
* lvconvert --type linear LV
*
* Alternate syntax:
* lvconvert --mirrors 0 LV
*/
static int _convert_mirror_linear(struct cmd_context *cmd, struct logical_volume *lv,
struct lvconvert_params *lp)
{
return _lvconvert_mirrors(cmd, lv, lp);
}
/*
* Convert mirror LV to raid1 LV.
* lvconvert --type raid1 LV
@@ -4126,6 +4162,9 @@ static int _convert_mirror(struct cmd_context *cmd, struct logical_volume *lv,
if (arg_is_set(cmd, repair_ARG))
return _convert_mirror_repair(cmd, lv, lp);
if (new_type && !strcmp(new_type, SEG_TYPE_NAME_LINEAR))
return _convert_mirror_linear(cmd, lv, lp);
if (new_type && new_segtype && segtype_is_raid(new_segtype))
return _convert_mirror_raid(cmd, lv, lp);
@@ -4152,6 +4191,7 @@ static int _convert_mirror(struct cmd_context *cmd, struct logical_volume *lv,
" --splitmirrors\n"
" --mirrorlog\n"
" --repair\n"
" --type linear\n"
" --type raid*\n");
return 0;
}

View File

@@ -49,9 +49,6 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
/* Don't create a new PV on top of an existing PV like pvcreate does. */
pp.preserve_existing = 1;
/* pvcreate within vgcreate cannot be forced. */
pp.force = 0;
if (!vgcreate_params_set_defaults(cmd, &vp_def, NULL))
return EINVALID_CMD_LINE;
vp_def.vg_name = vg_name;