mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +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 -
|
||||
=====================================
|
||||
Make sure VG extent size is always greater or equal to PV phys. block size.
|
||||
Optimize double call of stat() for cached devices.
|
||||
Enable support for thin provisioning for default configuration.
|
||||
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' */
|
||||
static void _dev_init(struct device *dev, int max_error_count)
|
||||
{
|
||||
dev->phys_block_size = -1;
|
||||
dev->block_size = -1;
|
||||
dev->fd = -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);
|
||||
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 (ioctl(dev_fd(dev), BLKBSZGET, &dev->block_size) < 0) {
|
||||
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);
|
||||
}
|
||||
|
||||
*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)
|
||||
{
|
||||
char *bounce, *bounce_buf;
|
||||
unsigned int physical_block_size = 0;
|
||||
unsigned int block_size = 0;
|
||||
uintptr_t mask;
|
||||
struct device_area widened;
|
||||
int r = 0;
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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))
|
||||
log_sys_error("close", dev_name(dev));
|
||||
dev->fd = -1;
|
||||
dev->phys_block_size = -1;
|
||||
dev->block_size = -1;
|
||||
dm_list_del(&dev->open_list);
|
||||
|
||||
|
@ -42,6 +42,7 @@ struct device {
|
||||
int open_count;
|
||||
int error_count;
|
||||
int max_error_count;
|
||||
int phys_block_size;
|
||||
int block_size;
|
||||
int read_ahead;
|
||||
uint32_t flags;
|
||||
@ -66,8 +67,8 @@ struct device_area {
|
||||
/*
|
||||
* 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_sectsize(struct device *dev, uint32_t *size);
|
||||
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);
|
||||
|
||||
|
@ -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_pv_dev_block_sizes(const struct volume_group *vg);
|
||||
|
||||
/*
|
||||
* Check if the VG reached maximal LVs count (if set)
|
||||
|
@ -619,6 +619,40 @@ int vg_remove(struct volume_group *vg)
|
||||
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
|
||||
*
|
||||
@ -626,10 +660,12 @@ int vg_remove(struct volume_group *vg)
|
||||
* - vg: handle of volume group to extend by 'pv_name'
|
||||
* - pv_name: device path of PV to add to VG
|
||||
* - 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,
|
||||
struct pvcreate_params *pp)
|
||||
struct pvcreate_params *pp,
|
||||
unsigned int *max_phys_block_size)
|
||||
{
|
||||
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)))
|
||||
return_0;
|
||||
}
|
||||
if (!add_pv_to_vg(vg, pv_name, pv, pp)) {
|
||||
free_pv_fid(pv);
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (!(check_dev_block_size_for_vg(pv->dev, (const struct volume_group *) vg,
|
||||
max_phys_block_size)))
|
||||
goto_bad;
|
||||
|
||||
if (!add_pv_to_vg(vg, pv_name, pv, pp))
|
||||
goto_bad;
|
||||
|
||||
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;
|
||||
char *pv_name;
|
||||
unsigned int max_phys_block_size = 0;
|
||||
|
||||
if (_vg_bad_status_bits(vg, RESIZEABLE_VG))
|
||||
return_0;
|
||||
@ -676,7 +720,7 @@ int vg_extend(struct volume_group *vg, int pv_count, const char *const *pv_names
|
||||
return 0;
|
||||
}
|
||||
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 "
|
||||
"volume group '%s'.", pv_name, vg->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 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 */
|
||||
int pv_add(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 ]
|
||||
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
|
||||
is the default if no suffix is present.
|
||||
The default is 4 MiB and it must be at least 1 KiB and a power of 2.
|
||||
is the default if no suffix is present. The value must be at least 1 sector
|
||||
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,
|
||||
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 ]
|
||||
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
|
||||
is the default if no suffix is present.
|
||||
The default is 4 MiB and it must be at least 1 KiB and a power of 2.
|
||||
is the default if no suffix is present. The value must be at least 1 sector
|
||||
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
|
||||
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))
|
||||
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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user