mirror of
git://sourceware.org/git/lvm2.git
synced 2025-09-06 05:44:18 +03:00
Compare commits
17 Commits
v2_02_160
...
dev-bmr-dm
Author | SHA1 | Date | |
---|---|---|---|
|
d901468a27 | ||
|
7ebe630b69 | ||
|
e104825916 | ||
|
12ecd95965 | ||
|
ebc7fc67c8 | ||
|
005adb0a0a | ||
|
cc4f036d36 | ||
|
059a383cf8 | ||
|
5e06b33c51 | ||
|
6233bcf52d | ||
|
589b752eeb | ||
|
0de56eeaad | ||
|
13cd3ff5a0 | ||
|
37d1b7b745 | ||
|
4d1c4e1f73 | ||
|
351bcf5f82 | ||
|
f6b98ec7ca |
@@ -1 +1 @@
|
||||
1.02.130-git (2016-07-06)
|
||||
1.02.131-git (2016-07-06)
|
||||
|
@@ -1,3 +1,6 @@
|
||||
Version 2.02.161 -
|
||||
================================
|
||||
|
||||
Version 2.02.160 - 6th July 2016
|
||||
================================
|
||||
Minor fixes from coverity.
|
||||
|
@@ -1,3 +1,6 @@
|
||||
Version 1.02.131 -
|
||||
================================
|
||||
|
||||
Version 1.02.130 - 6th July 2016
|
||||
================================
|
||||
Minor fixes from coverity.
|
||||
|
1
libdm/.exported_symbols.DM_1_02_131
Normal file
1
libdm/.exported_symbols.DM_1_02_131
Normal file
@@ -0,0 +1 @@
|
||||
dm_stats_create_regions_from_fd
|
@@ -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.
|
||||
*/
|
||||
|
@@ -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.
|
||||
*
|
||||
|
@@ -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
|
||||
#
|
||||
|
1308
man/lvconvert.8.in
1308
man/lvconvert.8.in
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
226
tools/dmsetup.c
226
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);
|
||||
@@ -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)
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user