mirror of
git://sourceware.org/git/lvm2.git
synced 2025-01-03 05:18:29 +03:00
device: add physical block size info and make sure VG extent size >= PV's phys. block size
This commit is contained in:
parent
3eed0aa7dc
commit
32080c4ff7
@ -1,5 +1,6 @@
|
|||||||
Version 2.02.105 -
|
Version 2.02.105 -
|
||||||
=====================================
|
=====================================
|
||||||
|
Make sure VG extent size is always greater or equal to PV phys. block size.
|
||||||
Optimize double call of stat() for cached devices.
|
Optimize double call of stat() for cached devices.
|
||||||
Enable support for thin provisioning for default configuration.
|
Enable support for thin provisioning for default configuration.
|
||||||
Improve process_each_lv_in_vg() tag processing.
|
Improve process_each_lv_in_vg() tag processing.
|
||||||
|
@ -56,6 +56,7 @@ static int _insert(const char *path, const struct stat *info,
|
|||||||
/* Setup non-zero members of passed zeroed 'struct device' */
|
/* Setup non-zero members of passed zeroed 'struct device' */
|
||||||
static void _dev_init(struct device *dev, int max_error_count)
|
static void _dev_init(struct device *dev, int max_error_count)
|
||||||
{
|
{
|
||||||
|
dev->phys_block_size = -1;
|
||||||
dev->block_size = -1;
|
dev->block_size = -1;
|
||||||
dev->fd = -1;
|
dev->fd = -1;
|
||||||
dev->read_ahead = -1;
|
dev->read_ahead = -1;
|
||||||
|
@ -123,23 +123,44 @@ static int _io(struct device_area *where, char *buffer, int should_write)
|
|||||||
*---------------------------------------------------------------*/
|
*---------------------------------------------------------------*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the sector size from an _open_ device.
|
* Get the physical and logical block size for a device.
|
||||||
*/
|
*/
|
||||||
static int _get_block_size(struct device *dev, unsigned int *size)
|
int dev_get_block_size(struct device *dev, unsigned int *physical_block_size, unsigned int *block_size)
|
||||||
{
|
{
|
||||||
const char *name = dev_name(dev);
|
const char *name = dev_name(dev);
|
||||||
|
int needs_open;
|
||||||
|
int r = 1;
|
||||||
|
|
||||||
|
needs_open = (!dev->open_count && (dev->phys_block_size == -1 || dev->block_size == -1));
|
||||||
|
|
||||||
|
if (needs_open && !dev_open_readonly(dev))
|
||||||
|
return_0;
|
||||||
|
|
||||||
|
if (dev->phys_block_size == -1) {
|
||||||
|
if (ioctl(dev_fd(dev), BLKPBSZGET, &dev->phys_block_size) < 0) {
|
||||||
|
log_sys_error("ioctl BLKPBSZGET", name);
|
||||||
|
r = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
log_debug_devs("%s: physical block size is %u bytes", name, dev->phys_block_size);
|
||||||
|
}
|
||||||
|
|
||||||
if (dev->block_size == -1) {
|
if (dev->block_size == -1) {
|
||||||
if (ioctl(dev_fd(dev), BLKBSZGET, &dev->block_size) < 0) {
|
if (ioctl(dev_fd(dev), BLKBSZGET, &dev->block_size) < 0) {
|
||||||
log_sys_error("ioctl BLKBSZGET", name);
|
log_sys_error("ioctl BLKBSZGET", name);
|
||||||
return 0;
|
r = 0;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
log_debug_devs("%s: block size is %u bytes", name, dev->block_size);
|
log_debug_devs("%s: block size is %u bytes", name, dev->block_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
*size = (unsigned int) dev->block_size;
|
*physical_block_size = (unsigned int) dev->phys_block_size;
|
||||||
|
*block_size = (unsigned int) dev->block_size;
|
||||||
|
out:
|
||||||
|
if (needs_open)
|
||||||
|
dev_close(dev);
|
||||||
|
|
||||||
return 1;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -168,13 +189,14 @@ static int _aligned_io(struct device_area *where, char *buffer,
|
|||||||
int should_write)
|
int should_write)
|
||||||
{
|
{
|
||||||
char *bounce, *bounce_buf;
|
char *bounce, *bounce_buf;
|
||||||
|
unsigned int physical_block_size = 0;
|
||||||
unsigned int block_size = 0;
|
unsigned int block_size = 0;
|
||||||
uintptr_t mask;
|
uintptr_t mask;
|
||||||
struct device_area widened;
|
struct device_area widened;
|
||||||
int r = 0;
|
int r = 0;
|
||||||
|
|
||||||
if (!(where->dev->flags & DEV_REGULAR) &&
|
if (!(where->dev->flags & DEV_REGULAR) &&
|
||||||
!_get_block_size(where->dev, &block_size))
|
!dev_get_block_size(where->dev, &physical_block_size, &block_size))
|
||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
if (!block_size)
|
if (!block_size)
|
||||||
@ -370,36 +392,6 @@ int dev_discard_blocks(struct device *dev, uint64_t offset_bytes, uint64_t size_
|
|||||||
return _dev_discard_blocks(dev, offset_bytes, size_bytes);
|
return _dev_discard_blocks(dev, offset_bytes, size_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME Unused
|
|
||||||
int dev_get_sectsize(struct device *dev, uint32_t *size)
|
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
int s;
|
|
||||||
const char *name = dev_name(dev);
|
|
||||||
|
|
||||||
if ((fd = open(name, O_RDONLY)) < 0) {
|
|
||||||
log_sys_error("open", name);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ioctl(fd, BLKSSZGET, &s) < 0) {
|
|
||||||
log_sys_error("ioctl BLKSSZGET", name);
|
|
||||||
if (close(fd))
|
|
||||||
log_sys_error("close", name);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (close(fd))
|
|
||||||
log_sys_error("close", name);
|
|
||||||
|
|
||||||
*size = (uint32_t) s;
|
|
||||||
|
|
||||||
log_very_verbose("%s: sector size is %" PRIu32 " bytes", name, *size);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
void dev_flush(struct device *dev)
|
void dev_flush(struct device *dev)
|
||||||
{
|
{
|
||||||
if (!(dev->flags & DEV_REGULAR) && ioctl(dev->fd, BLKFLSBUF, 0) >= 0)
|
if (!(dev->flags & DEV_REGULAR) && ioctl(dev->fd, BLKFLSBUF, 0) >= 0)
|
||||||
@ -571,6 +563,7 @@ static void _close(struct device *dev)
|
|||||||
if (close(dev->fd))
|
if (close(dev->fd))
|
||||||
log_sys_error("close", dev_name(dev));
|
log_sys_error("close", dev_name(dev));
|
||||||
dev->fd = -1;
|
dev->fd = -1;
|
||||||
|
dev->phys_block_size = -1;
|
||||||
dev->block_size = -1;
|
dev->block_size = -1;
|
||||||
dm_list_del(&dev->open_list);
|
dm_list_del(&dev->open_list);
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@ struct device {
|
|||||||
int open_count;
|
int open_count;
|
||||||
int error_count;
|
int error_count;
|
||||||
int max_error_count;
|
int max_error_count;
|
||||||
|
int phys_block_size;
|
||||||
int block_size;
|
int block_size;
|
||||||
int read_ahead;
|
int read_ahead;
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
@ -66,8 +67,8 @@ struct device_area {
|
|||||||
/*
|
/*
|
||||||
* All io should use these routines.
|
* All io should use these routines.
|
||||||
*/
|
*/
|
||||||
|
int dev_get_block_size(struct device *dev, unsigned int *phys_block_size, unsigned int *block_size);
|
||||||
int dev_get_size(const struct device *dev, uint64_t *size);
|
int dev_get_size(const struct device *dev, uint64_t *size);
|
||||||
int dev_get_sectsize(struct device *dev, uint32_t *size);
|
|
||||||
int dev_get_read_ahead(struct device *dev, uint32_t *read_ahead);
|
int dev_get_read_ahead(struct device *dev, uint32_t *read_ahead);
|
||||||
int dev_discard_blocks(struct device *dev, uint64_t offset_bytes, uint64_t size_bytes);
|
int dev_discard_blocks(struct device *dev, uint64_t offset_bytes, uint64_t size_bytes);
|
||||||
|
|
||||||
|
@ -903,6 +903,7 @@ int vg_remove_snapshot(struct logical_volume *cow);
|
|||||||
|
|
||||||
int vg_check_status(const struct volume_group *vg, uint64_t status);
|
int vg_check_status(const struct volume_group *vg, uint64_t status);
|
||||||
|
|
||||||
|
int vg_check_pv_dev_block_sizes(const struct volume_group *vg);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if the VG reached maximal LVs count (if set)
|
* Check if the VG reached maximal LVs count (if set)
|
||||||
|
@ -619,6 +619,40 @@ int vg_remove(struct volume_group *vg)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int check_dev_block_size_for_vg(struct device *dev, const struct volume_group *vg,
|
||||||
|
unsigned int *max_phys_block_size_found)
|
||||||
|
{
|
||||||
|
unsigned int phys_block_size, block_size;
|
||||||
|
|
||||||
|
if (!(dev_get_block_size(dev, &phys_block_size, &block_size)))
|
||||||
|
return_0;
|
||||||
|
|
||||||
|
if (phys_block_size > *max_phys_block_size_found)
|
||||||
|
*max_phys_block_size_found = phys_block_size;
|
||||||
|
|
||||||
|
if (phys_block_size >> SECTOR_SHIFT > vg->extent_size) {
|
||||||
|
log_error("Physical extent size used for volume group %s "
|
||||||
|
"is less than physical block size that %s uses.",
|
||||||
|
vg->name, dev_name(dev));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vg_check_pv_dev_block_sizes(const struct volume_group *vg)
|
||||||
|
{
|
||||||
|
struct pv_list *pvl;
|
||||||
|
unsigned int max_phys_block_size_found = 0;
|
||||||
|
|
||||||
|
dm_list_iterate_items(pvl, &vg->pvs) {
|
||||||
|
if (!check_dev_block_size_for_vg(pvl->pv->dev, vg, &max_phys_block_size_found))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Extend a VG by a single PV / device path
|
* Extend a VG by a single PV / device path
|
||||||
*
|
*
|
||||||
@ -626,10 +660,12 @@ int vg_remove(struct volume_group *vg)
|
|||||||
* - vg: handle of volume group to extend by 'pv_name'
|
* - vg: handle of volume group to extend by 'pv_name'
|
||||||
* - pv_name: device path of PV to add to VG
|
* - pv_name: device path of PV to add to VG
|
||||||
* - pp: parameters to pass to implicit pvcreate; if NULL, do not pvcreate
|
* - pp: parameters to pass to implicit pvcreate; if NULL, do not pvcreate
|
||||||
|
* - max_phys_block_size: largest physical block size found amongst PVs in a VG
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static int vg_extend_single_pv(struct volume_group *vg, char *pv_name,
|
static int vg_extend_single_pv(struct volume_group *vg, char *pv_name,
|
||||||
struct pvcreate_params *pp)
|
struct pvcreate_params *pp,
|
||||||
|
unsigned int *max_phys_block_size)
|
||||||
{
|
{
|
||||||
struct physical_volume *pv;
|
struct physical_volume *pv;
|
||||||
|
|
||||||
@ -643,11 +679,18 @@ static int vg_extend_single_pv(struct volume_group *vg, char *pv_name,
|
|||||||
if (!(pv = pvcreate_vol(vg->cmd, pv_name, pp, 0)))
|
if (!(pv = pvcreate_vol(vg->cmd, pv_name, pp, 0)))
|
||||||
return_0;
|
return_0;
|
||||||
}
|
}
|
||||||
if (!add_pv_to_vg(vg, pv_name, pv, pp)) {
|
|
||||||
free_pv_fid(pv);
|
if (!(check_dev_block_size_for_vg(pv->dev, (const struct volume_group *) vg,
|
||||||
return_0;
|
max_phys_block_size)))
|
||||||
}
|
goto_bad;
|
||||||
|
|
||||||
|
if (!add_pv_to_vg(vg, pv_name, pv, pp))
|
||||||
|
goto_bad;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
bad:
|
||||||
|
free_pv_fid(pv);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -665,6 +708,7 @@ int vg_extend(struct volume_group *vg, int pv_count, const char *const *pv_names
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
char *pv_name;
|
char *pv_name;
|
||||||
|
unsigned int max_phys_block_size = 0;
|
||||||
|
|
||||||
if (_vg_bad_status_bits(vg, RESIZEABLE_VG))
|
if (_vg_bad_status_bits(vg, RESIZEABLE_VG))
|
||||||
return_0;
|
return_0;
|
||||||
@ -676,7 +720,7 @@ int vg_extend(struct volume_group *vg, int pv_count, const char *const *pv_names
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
dm_unescape_colons_and_at_signs(pv_name, NULL, NULL);
|
dm_unescape_colons_and_at_signs(pv_name, NULL, NULL);
|
||||||
if (!vg_extend_single_pv(vg, pv_name, pp)) {
|
if (!vg_extend_single_pv(vg, pv_name, pp, &max_phys_block_size)) {
|
||||||
log_error("Unable to add physical volume '%s' to "
|
log_error("Unable to add physical volume '%s' to "
|
||||||
"volume group '%s'.", pv_name, vg->name);
|
"volume group '%s'.", pv_name, vg->name);
|
||||||
dm_free(pv_name);
|
dm_free(pv_name);
|
||||||
|
@ -347,6 +347,9 @@ int pvremove_single(struct cmd_context *cmd, const char *pv_name,
|
|||||||
struct physical_volume *pvcreate_vol(struct cmd_context *cmd, const char *pv_name,
|
struct physical_volume *pvcreate_vol(struct cmd_context *cmd, const char *pv_name,
|
||||||
struct pvcreate_params *pp, int write_now);
|
struct pvcreate_params *pp, int write_now);
|
||||||
|
|
||||||
|
int check_dev_block_size_for_vg(struct device *dev, const struct volume_group *vg,
|
||||||
|
unsigned int *max_phys_block_size_found);
|
||||||
|
|
||||||
/* Manipulate PV structures */
|
/* Manipulate PV structures */
|
||||||
int pv_add(struct volume_group *vg, struct physical_volume *pv);
|
int pv_add(struct volume_group *vg, struct physical_volume *pv);
|
||||||
int pv_remove(struct volume_group *vg, struct physical_volume *pv);
|
int pv_remove(struct volume_group *vg, struct physical_volume *pv);
|
||||||
|
@ -183,8 +183,10 @@ minimize metadata read and write overhead.
|
|||||||
.BR \-s ", " \-\-physicalextentsize " " \fIPhysicalExtentSize [ \fIBbBsSkKmMgGtTpPeE ]
|
.BR \-s ", " \-\-physicalextentsize " " \fIPhysicalExtentSize [ \fIBbBsSkKmMgGtTpPeE ]
|
||||||
Changes the physical extent size on physical volumes of this volume group.
|
Changes the physical extent size on physical volumes of this volume group.
|
||||||
A size suffix (k for kilobytes up to t for terabytes) is optional, megabytes
|
A size suffix (k for kilobytes up to t for terabytes) is optional, megabytes
|
||||||
is the default if no suffix is present.
|
is the default if no suffix is present. The value must be at least 1 sector
|
||||||
The default is 4 MiB and it must be at least 1 KiB and a power of 2.
|
for LVM2 format (where the sector size is the largest sector size of the
|
||||||
|
PVs currently used in the VG) or 8KiB for LVM1 format and it must be a
|
||||||
|
power of 2. The default is 4 MiB.
|
||||||
|
|
||||||
Before increasing the physical extent size, you might need to use lvresize,
|
Before increasing the physical extent size, you might need to use lvresize,
|
||||||
pvresize and/or pvmove so that everything fits. For example, every
|
pvresize and/or pvmove so that everything fits. For example, every
|
||||||
|
@ -94,8 +94,10 @@ The default value is \fIunmanaged\fP.
|
|||||||
.BR \-s ", " \-\-physicalextentsize " " \fIPhysicalExtentSize [ \fIbBsSkKmMgGtTpPeE ]
|
.BR \-s ", " \-\-physicalextentsize " " \fIPhysicalExtentSize [ \fIbBsSkKmMgGtTpPeE ]
|
||||||
Sets the physical extent size on physical volumes of this volume group.
|
Sets the physical extent size on physical volumes of this volume group.
|
||||||
A size suffix (k for kilobytes up to t for terabytes) is optional, megabytes
|
A size suffix (k for kilobytes up to t for terabytes) is optional, megabytes
|
||||||
is the default if no suffix is present.
|
is the default if no suffix is present. The value must be at least 1 sector
|
||||||
The default is 4 MiB and it must be at least 1 KiB and a power of 2.
|
for LVM2 format (where the sector size is the largest sector size of the
|
||||||
|
PVs currently used in the VG) or 8KiB for LVM1 format and it must be a
|
||||||
|
power of 2. The default is 4 MiB.
|
||||||
|
|
||||||
Once this value has been set, it is difficult to change it without recreating
|
Once this value has been set, it is difficult to change it without recreating
|
||||||
the volume group which would involve backing up and restoring data on any
|
the volume group which would involve backing up and restoring data on any
|
||||||
|
@ -368,6 +368,12 @@ static int _vgchange_pesize(struct cmd_context *cmd, struct volume_group *vg)
|
|||||||
if (!vg_set_extent_size(vg, extent_size))
|
if (!vg_set_extent_size(vg, extent_size))
|
||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
|
if (!vg_check_pv_dev_block_sizes(vg)) {
|
||||||
|
log_error("Failed to change physical extent size for VG %s.",
|
||||||
|
vg->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user