1
0
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:
Mike Snitzer 2009-07-06 19:04:24 +00:00
parent 4b2cae463e
commit bb6a3a9608
6 changed files with 168 additions and 41 deletions

View File

@ -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.

View File

@ -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

View File

@ -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;
} }

View File

@ -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);

View File

@ -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);

View File

@ -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.