mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
Use the MD device's stripe-width, instead of chunk_size, to align the
data blocks of a Physical Volume that is placed directly upon an MD device.
This commit is contained in:
parent
4b2cae463e
commit
bb6a3a9608
@ -1,5 +1,6 @@
|
|||||||
Version 2.02.49 -
|
Version 2.02.49 -
|
||||||
================================
|
================================
|
||||||
|
Update 'md_chunk_alignment' to use stripe-width to align PV data area.
|
||||||
Update test/t-inconsistent-metadata.sh to match new vg_read interface.
|
Update test/t-inconsistent-metadata.sh to match new vg_read interface.
|
||||||
Add lvmcache_init() to polldaemon initialization.
|
Add lvmcache_init() to polldaemon initialization.
|
||||||
Convert tools to use new vg_read / vg_read_for_update.
|
Convert tools to use new vg_read / vg_read_for_update.
|
||||||
|
@ -94,7 +94,7 @@ devices {
|
|||||||
md_component_detection = 1
|
md_component_detection = 1
|
||||||
|
|
||||||
# By default, if a PV is placed directly upon an md device, LVM2
|
# By default, if a PV is placed directly upon an md device, LVM2
|
||||||
# will align its data blocks with the the chunk_size exposed in sysfs.
|
# will align its data blocks with the md device's stripe-width.
|
||||||
# 1 enables; 0 disables.
|
# 1 enables; 0 disables.
|
||||||
md_chunk_alignment = 1
|
md_chunk_alignment = 1
|
||||||
|
|
||||||
|
@ -125,39 +125,57 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static int _md_sysfs_attribute_snprintf(char *path, size_t size,
|
||||||
* Retrieve chunk size from md device using sysfs.
|
const char *sysfs_dir,
|
||||||
*/
|
struct device *dev,
|
||||||
unsigned long dev_md_chunk_size(const char *sysfs_dir, struct device *dev)
|
const char *attribute)
|
||||||
|
{
|
||||||
|
struct stat info;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
if (MAJOR(dev->dev) != md_major())
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (!sysfs_dir || !*sysfs_dir)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = dm_snprintf(path, size, "%s/dev/block/%d:%d/md/%s",
|
||||||
|
sysfs_dir, MAJOR(dev->dev), MINOR(dev->dev), attribute);
|
||||||
|
if (ret < 0) {
|
||||||
|
log_error("dm_snprintf md %s failed", attribute);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stat(path, &info) < 0) {
|
||||||
|
/* old sysfs structure */
|
||||||
|
ret = dm_snprintf(path, size, "%s/block/md%d/md/%s",
|
||||||
|
sysfs_dir, MINOR(dev->dev), attribute);
|
||||||
|
if (ret < 0) {
|
||||||
|
log_error("dm_snprintf old md %s failed", attribute);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _md_sysfs_attribute_scanf(const char *sysfs_dir,
|
||||||
|
struct device *dev,
|
||||||
|
const char *attribute_name,
|
||||||
|
const char *attribute_fmt,
|
||||||
|
void *attribute_value)
|
||||||
{
|
{
|
||||||
char path[PATH_MAX+1], buffer[64];
|
char path[PATH_MAX+1], buffer[64];
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
struct stat info;
|
int ret = 0;
|
||||||
unsigned long chunk_size_bytes = 0UL;
|
|
||||||
|
|
||||||
if (MAJOR(dev->dev) != md_major())
|
if (_md_sysfs_attribute_snprintf(path, PATH_MAX, sysfs_dir,
|
||||||
return 0;
|
dev, attribute_name) < 0)
|
||||||
|
return ret;
|
||||||
if (!sysfs_dir || !*sysfs_dir)
|
|
||||||
return_0;
|
|
||||||
|
|
||||||
if (dm_snprintf(path, PATH_MAX, "%s/dev/block/%d:%d/md/chunk_size",
|
|
||||||
sysfs_dir, MAJOR(dev->dev), MINOR(dev->dev)) < 0) {
|
|
||||||
log_error("dm_snprintf md chunk_size failed");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* old sysfs structure */
|
|
||||||
if (stat(path, &info) &&
|
|
||||||
dm_snprintf(path, PATH_MAX, "%s/block/md%d/md/chunk_size",
|
|
||||||
sysfs_dir, MINOR(dev->dev)) < 0) {
|
|
||||||
log_error("dm_snprintf old md chunk size failed");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(fp = fopen(path, "r"))) {
|
if (!(fp = fopen(path, "r"))) {
|
||||||
log_sys_error("fopen", path);
|
log_sys_error("fopen", path);
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fgets(buffer, sizeof(buffer), fp)) {
|
if (!fgets(buffer, sizeof(buffer), fp)) {
|
||||||
@ -165,22 +183,130 @@ unsigned long dev_md_chunk_size(const char *sysfs_dir, struct device *dev)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sscanf(buffer, "%lu", &chunk_size_bytes) != 1) {
|
if ((ret = sscanf(buffer, attribute_fmt, attribute_value)) != 1) {
|
||||||
log_error("sysfs file %s not in expected format: %s", path,
|
log_error("%s sysfs attr %s not in expected format: %s",
|
||||||
buffer);
|
dev_name(dev), attribute_name, buffer);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_very_verbose("Device %s md chunk size is %lu bytes.",
|
|
||||||
dev_name(dev), chunk_size_bytes);
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (fclose(fp))
|
if (fclose(fp))
|
||||||
log_sys_error("fclose", path);
|
log_sys_error("fclose", path);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Retrieve chunk size from md device using sysfs.
|
||||||
|
*/
|
||||||
|
static unsigned long dev_md_chunk_size(const char *sysfs_dir,
|
||||||
|
struct device *dev)
|
||||||
|
{
|
||||||
|
const char *attribute = "chunk_size";
|
||||||
|
unsigned long chunk_size_bytes = 0UL;
|
||||||
|
|
||||||
|
if (_md_sysfs_attribute_scanf(sysfs_dir, dev, attribute,
|
||||||
|
"%lu", &chunk_size_bytes) != 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
log_very_verbose("Device %s %s is %lu bytes.",
|
||||||
|
dev_name(dev), attribute, chunk_size_bytes);
|
||||||
|
|
||||||
return chunk_size_bytes >> SECTOR_SHIFT;
|
return chunk_size_bytes >> SECTOR_SHIFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Retrieve level from md device using sysfs.
|
||||||
|
*/
|
||||||
|
static int dev_md_level(const char *sysfs_dir, struct device *dev)
|
||||||
|
{
|
||||||
|
const char *attribute = "level";
|
||||||
|
int level = -1;
|
||||||
|
|
||||||
|
if (_md_sysfs_attribute_scanf(sysfs_dir, dev, attribute,
|
||||||
|
"raid%d", &level) != 1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
log_very_verbose("Device %s %s is raid%d.",
|
||||||
|
dev_name(dev), attribute, level);
|
||||||
|
|
||||||
|
return level;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Retrieve raid_disks from md device using sysfs.
|
||||||
|
*/
|
||||||
|
static int dev_md_raid_disks(const char *sysfs_dir, struct device *dev)
|
||||||
|
{
|
||||||
|
const char *attribute = "raid_disks";
|
||||||
|
int raid_disks = 0;
|
||||||
|
|
||||||
|
if (_md_sysfs_attribute_scanf(sysfs_dir, dev, attribute,
|
||||||
|
"%d", &raid_disks) != 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
log_very_verbose("Device %s %s is %d.",
|
||||||
|
dev_name(dev), attribute, raid_disks);
|
||||||
|
|
||||||
|
return raid_disks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate stripe width of md device using its sysfs files.
|
||||||
|
*/
|
||||||
|
unsigned long dev_md_stripe_width(const char *sysfs_dir, struct device *dev)
|
||||||
|
{
|
||||||
|
unsigned long chunk_size_sectors = 0UL;
|
||||||
|
unsigned long stripe_width_sectors = 0UL;
|
||||||
|
int level, raid_disks, data_disks;
|
||||||
|
|
||||||
|
chunk_size_sectors = dev_md_chunk_size(sysfs_dir, dev);
|
||||||
|
if (!chunk_size_sectors)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
level = dev_md_level(sysfs_dir, dev);
|
||||||
|
if (level < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
raid_disks = dev_md_raid_disks(sysfs_dir, dev);
|
||||||
|
if (!raid_disks)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* The raid level governs the number of data disks. */
|
||||||
|
switch (level) {
|
||||||
|
case 0:
|
||||||
|
/* striped md does not have any parity disks */
|
||||||
|
data_disks = raid_disks;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
case 10:
|
||||||
|
/* mirrored md effectively has 1 data disk */
|
||||||
|
data_disks = 1;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
/* both raid 4 and 5 have a single parity disk */
|
||||||
|
data_disks = raid_disks - 1;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
/* raid 6 has 2 parity disks */
|
||||||
|
data_disks = raid_disks - 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log_error("Device %s has an unknown md raid level: %d",
|
||||||
|
dev_name(dev), level);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
stripe_width_sectors = chunk_size_sectors * data_disks;
|
||||||
|
|
||||||
|
log_very_verbose("Device %s stripe-width is %lu bytes.",
|
||||||
|
dev_name(dev),
|
||||||
|
stripe_width_sectors << SECTOR_SHIFT);
|
||||||
|
|
||||||
|
return stripe_width_sectors;
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
int dev_is_md(struct device *dev __attribute((unused)),
|
int dev_is_md(struct device *dev __attribute((unused)),
|
||||||
@ -189,8 +315,8 @@ int dev_is_md(struct device *dev __attribute((unused)),
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long dev_md_chunk_size(const char *sysfs_dir __attribute((unused)),
|
unsigned long dev_md_stripe_width(const char *sysfs_dir __attribute((unused)),
|
||||||
struct device *dev __attribute((unused)))
|
struct device *dev __attribute((unused)))
|
||||||
{
|
{
|
||||||
return 0UL;
|
return 0UL;
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ const char *dev_name_confirmed(struct device *dev, int quiet);
|
|||||||
/* Does device contain md superblock? If so, where? */
|
/* Does device contain md superblock? If so, where? */
|
||||||
int dev_is_md(struct device *dev, uint64_t *sb);
|
int dev_is_md(struct device *dev, uint64_t *sb);
|
||||||
int dev_is_swap(struct device *dev, uint64_t *signature);
|
int dev_is_swap(struct device *dev, uint64_t *signature);
|
||||||
unsigned long dev_md_chunk_size(const char *sysfs_dir, struct device *dev);
|
unsigned long dev_md_stripe_width(const char *sysfs_dir, struct device *dev);
|
||||||
|
|
||||||
int is_partitioned_dev(struct device *dev);
|
int is_partitioned_dev(struct device *dev);
|
||||||
|
|
||||||
|
@ -81,13 +81,13 @@ unsigned long set_pe_align(struct physical_volume *pv, unsigned long data_alignm
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Align to chunk size of underlying md device if present
|
* Align to stripe-width of underlying md device if present
|
||||||
*/
|
*/
|
||||||
if (find_config_tree_bool(pv->fmt->cmd, "devices/md_chunk_alignment",
|
if (find_config_tree_bool(pv->fmt->cmd, "devices/md_chunk_alignment",
|
||||||
DEFAULT_MD_CHUNK_ALIGNMENT))
|
DEFAULT_MD_CHUNK_ALIGNMENT))
|
||||||
pv->pe_align = MAX(pv->pe_align,
|
pv->pe_align = MAX(pv->pe_align,
|
||||||
dev_md_chunk_size(pv->fmt->cmd->sysfs_dir,
|
dev_md_stripe_width(pv->fmt->cmd->sysfs_dir,
|
||||||
pv->dev));
|
pv->dev));
|
||||||
|
|
||||||
log_very_verbose("%s: Setting PE alignment to %lu sectors.",
|
log_very_verbose("%s: Setting PE alignment to %lu sectors.",
|
||||||
dev_name(pv->dev), pv->pe_align);
|
dev_name(pv->dev), pv->pe_align);
|
||||||
|
@ -134,8 +134,8 @@ superblocks. This doesn't always work satisfactorily e.g. if a device
|
|||||||
has been reused without wiping the md superblocks first.
|
has been reused without wiping the md superblocks first.
|
||||||
.IP
|
.IP
|
||||||
\fBmd_chunk_alignment\fP \(em If set to 1, and a Physical Volume is placed
|
\fBmd_chunk_alignment\fP \(em If set to 1, and a Physical Volume is placed
|
||||||
directly upon an md device, LVM2 will align its data blocks with the the
|
directly upon an md device, LVM2 will align its data blocks with the
|
||||||
chunk_size exposed in sysfs.
|
md device's stripe-width.
|
||||||
.IP
|
.IP
|
||||||
\fBdata_alignment\fP \(em Default alignment (in KB) of start of data area
|
\fBdata_alignment\fP \(em Default alignment (in KB) of start of data area
|
||||||
when creating a new Physical Volume using the \fBlvm2\fP format.
|
when creating a new Physical Volume using the \fBlvm2\fP format.
|
||||||
|
Loading…
Reference in New Issue
Block a user