1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

refactor: make device type recognition code common for general use

Changes:

- move device type registration out of "type filter" (filter.c)
to a separate and new dev-type.[ch] for common use throughout the code

- the structure for keeping the major numbers detected for available
device types and available partitioning available is stored in
"dev_types" structure now

- move common partitioning detection code to dev-type.[ch] as well
together with other device-related functions bound to dev_types
(see dev-type.h for the interface)

The dev-type interface contains all common functions used to detect
subsystems/device types, signature/superblock recognition code,
type-specific device properties and other common device properties
(bound to dev_types), including partitioning support.

- add dev_types instance to cmd context as cmd->dev_types for common use

- use cmd->dev_types throughout as a central point for providing
information about device types
This commit is contained in:
Peter Rajnoha 2013-06-12 12:08:56 +02:00
parent 1778d34cef
commit c6f48b7c1a
29 changed files with 559 additions and 533 deletions

View File

@ -15,6 +15,7 @@
@top_srcdir@/lib/datastruct/lvm-types.h @top_srcdir@/lib/datastruct/lvm-types.h
@top_srcdir@/lib/datastruct/str_list.h @top_srcdir@/lib/datastruct/str_list.h
@top_srcdir@/lib/device/dev-cache.h @top_srcdir@/lib/device/dev-cache.h
@top_srcdir@/lib/device/dev-type.h
@top_srcdir@/lib/device/device.h @top_srcdir@/lib/device/device.h
@top_srcdir@/lib/display/display.h @top_srcdir@/lib/display/display.h
@top_srcdir@/lib/filters/filter-composite.h @top_srcdir@/lib/filters/filter-composite.h

14
lib/cache/lvmcache.c vendored
View File

@ -1452,6 +1452,8 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
const char *vgname, const char *vgid, const char *vgname, const char *vgid,
uint32_t vgstatus) uint32_t vgstatus)
{ {
const struct format_type *fmt = (const struct format_type *) labeller->private;
struct dev_types *dt = fmt->cmd->dev_types;
struct label *label; struct label *label;
struct lvmcache_info *existing, *info; struct lvmcache_info *existing, *info;
char pvid_s[ID_LEN + 1] __attribute__((aligned(8))); char pvid_s[ID_LEN + 1] __attribute__((aligned(8)));
@ -1485,12 +1487,12 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
} else { } else {
if (existing->dev != dev) { if (existing->dev != dev) {
/* Is the existing entry a duplicate pvid e.g. md ? */ /* Is the existing entry a duplicate pvid e.g. md ? */
if (dev_subsystem_part_major(existing->dev) && if (dev_subsystem_part_major(dt, existing->dev) &&
!dev_subsystem_part_major(dev)) { !dev_subsystem_part_major(dt, dev)) {
log_very_verbose("Ignoring duplicate PV %s on " log_very_verbose("Ignoring duplicate PV %s on "
"%s - using %s %s", "%s - using %s %s",
pvid, dev_name(dev), pvid, dev_name(dev),
dev_subsystem_name(existing->dev), dev_subsystem_name(dt, existing->dev),
dev_name(existing->dev)); dev_name(existing->dev));
return NULL; return NULL;
} else if (dm_is_dm_major(MAJOR(existing->dev->dev)) && } else if (dm_is_dm_major(MAJOR(existing->dev->dev)) &&
@ -1500,12 +1502,12 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
pvid, dev_name(dev), pvid, dev_name(dev),
dev_name(existing->dev)); dev_name(existing->dev));
return NULL; return NULL;
} else if (!dev_subsystem_part_major(existing->dev) && } else if (!dev_subsystem_part_major(dt, existing->dev) &&
dev_subsystem_part_major(dev)) dev_subsystem_part_major(dt, dev))
log_very_verbose("Duplicate PV %s on %s - " log_very_verbose("Duplicate PV %s on %s - "
"using %s %s", pvid, "using %s %s", pvid,
dev_name(existing->dev), dev_name(existing->dev),
dev_subsystem_name(existing->dev), dev_subsystem_name(dt, existing->dev),
dev_name(dev)); dev_name(dev));
else if (!dm_is_dm_major(MAJOR(existing->dev->dev)) && else if (!dm_is_dm_major(MAJOR(existing->dev->dev)) &&
dm_is_dm_major(MAJOR(dev->dev))) dm_is_dm_major(MAJOR(dev->dev)))

View File

@ -17,6 +17,7 @@
#define _LVM_CACHE_H #define _LVM_CACHE_H
#include "dev-cache.h" #include "dev-cache.h"
#include "dev-type.h"
#include "uuid.h" #include "uuid.h"
#include "label.h" #include "label.h"
#include "locking.h" #include "locking.h"

View File

@ -820,8 +820,7 @@ static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
nr_filt++; nr_filt++;
/* device type filter. Required. */ /* device type filter. Required. */
cn = find_config_tree_node(cmd, devices_types_CFG); if (!(filters[nr_filt] = lvm_type_filter_create(cmd->dev_types))) {
if (!(filters[nr_filt] = lvm_type_filter_create(cmd->proc_dir, cn))) {
log_error("Failed to create lvm type filter"); log_error("Failed to create lvm type filter");
goto bad; goto bad;
} }
@ -830,13 +829,13 @@ static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
/* md component filter. Optional, non-critical. */ /* md component filter. Optional, non-critical. */
if (find_config_tree_bool(cmd, devices_md_component_detection_CFG)) { if (find_config_tree_bool(cmd, devices_md_component_detection_CFG)) {
init_md_filtering(1); init_md_filtering(1);
if ((filters[nr_filt] = md_filter_create())) if ((filters[nr_filt] = md_filter_create(cmd->dev_types)))
nr_filt++; nr_filt++;
} }
/* mpath component filter. Optional, non-critical. */ /* mpath component filter. Optional, non-critical. */
if (find_config_tree_bool(cmd, devices_multipath_component_detection_CFG)) { if (find_config_tree_bool(cmd, devices_multipath_component_detection_CFG)) {
if ((filters[nr_filt] = mpath_filter_create())) if ((filters[nr_filt] = mpath_filter_create(cmd->dev_types)))
nr_filt++; nr_filt++;
} }
@ -898,7 +897,7 @@ static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache
if (!dev_cache) if (!dev_cache)
dev_cache = cache_file; dev_cache = cache_file;
if (!(f4 = persistent_filter_create(f3, dev_cache))) { if (!(f4 = persistent_filter_create(cmd->dev_types, f3, dev_cache))) {
log_verbose("Failed to create persistent device filter."); log_verbose("Failed to create persistent device filter.");
f3->destroy(f3); f3->destroy(f3);
return_0; return_0;
@ -1451,6 +1450,10 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
if (!_process_config(cmd)) if (!_process_config(cmd))
goto_out; goto_out;
if (!(cmd->dev_types = create_dev_types(cmd->proc_dir,
find_config_tree_node(cmd, devices_types_CFG))))
goto_out;
if (!_init_dev_cache(cmd)) if (!_init_dev_cache(cmd))
goto_out; goto_out;
@ -1541,6 +1544,15 @@ skip_dlclose:
} }
} }
static void _destroy_dev_types(struct cmd_context *cmd)
{
if (!cmd->dev_types)
return;
dm_free(cmd->dev_types);
cmd->dev_types = NULL;
}
int refresh_filters(struct cmd_context *cmd) int refresh_filters(struct cmd_context *cmd)
{ {
int r, saved_ignore_suspended_devices = ignore_suspended_devices(); int r, saved_ignore_suspended_devices = ignore_suspended_devices();
@ -1584,6 +1596,7 @@ int refresh_toolcontext(struct cmd_context *cmd)
cmd->filter = NULL; cmd->filter = NULL;
} }
dev_cache_exit(); dev_cache_exit();
_destroy_dev_types(cmd);
_destroy_tags(cmd); _destroy_tags(cmd);
cft_cmdline = _destroy_tag_configs(cmd); cft_cmdline = _destroy_tag_configs(cmd);
@ -1623,6 +1636,10 @@ int refresh_toolcontext(struct cmd_context *cmd)
if (!_process_config(cmd)) if (!_process_config(cmd))
return 0; return 0;
if (!(cmd->dev_types = create_dev_types(cmd->proc_dir,
find_config_tree_node(cmd, devices_types_CFG))))
return 0;
if (!_init_dev_cache(cmd)) if (!_init_dev_cache(cmd))
return 0; return 0;
@ -1667,6 +1684,7 @@ void destroy_toolcontext(struct cmd_context *cmd)
if (cmd->mem) if (cmd->mem)
dm_pool_destroy(cmd->mem); dm_pool_destroy(cmd->mem);
dev_cache_exit(); dev_cache_exit();
_destroy_dev_types(cmd);
_destroy_tags(cmd); _destroy_tags(cmd);
if ((cft_cmdline = _destroy_tag_configs(cmd))) if ((cft_cmdline = _destroy_tag_configs(cmd)))

View File

@ -17,6 +17,7 @@
#define _LVM_TOOLCONTEXT_H #define _LVM_TOOLCONTEXT_H
#include "dev-cache.h" #include "dev-cache.h"
#include "dev-type.h"
#include <stdio.h> #include <stdio.h>
#include <limits.h> #include <limits.h>
@ -91,6 +92,7 @@ struct cmd_context {
unsigned independent_metadata_areas:1; /* Active formats have MDAs outside PVs */ unsigned independent_metadata_areas:1; /* Active formats have MDAs outside PVs */
struct dev_types *dev_types;
struct dev_filter *filter; struct dev_filter *filter;
struct dev_filter *lvmetad_filter; struct dev_filter *lvmetad_filter;
int dump_filter; /* Dump filter when exiting? */ int dump_filter; /* Dump filter when exiting? */

View File

@ -18,6 +18,7 @@
#include "lvm-types.h" #include "lvm-types.h"
#include "btree.h" #include "btree.h"
#include "filter.h" #include "filter.h"
#include "config.h"
#include "toolcontext.h" #include "toolcontext.h"
#include <unistd.h> #include <unistd.h>

View File

@ -13,6 +13,7 @@
*/ */
#include "lib.h" #include "lib.h"
#include "dev-type.h"
#include "metadata.h" #include "metadata.h"
#define LUKS_SIGNATURE "LUKS\xba\xbe" #define LUKS_SIGNATURE "LUKS\xba\xbe"

View File

@ -14,9 +14,9 @@
*/ */
#include "lib.h" #include "lib.h"
#include "dev-type.h"
#include "metadata.h" #include "metadata.h"
#include "xlate.h" #include "xlate.h"
#include "filter.h"
#ifdef linux #ifdef linux
@ -127,6 +127,7 @@ out:
} }
static int _md_sysfs_attribute_snprintf(char *path, size_t size, static int _md_sysfs_attribute_snprintf(char *path, size_t size,
struct dev_types *dt,
struct device *blkdev, struct device *blkdev,
const char *attribute) const char *attribute)
{ {
@ -138,13 +139,13 @@ static int _md_sysfs_attribute_snprintf(char *path, size_t size,
if (!sysfs_dir || !*sysfs_dir) if (!sysfs_dir || !*sysfs_dir)
return ret; return ret;
if (MAJOR(dev) == blkext_major()) { if (MAJOR(dev) == dt->blkext_major) {
/* lookup parent MD device from blkext partition */ /* lookup parent MD device from blkext partition */
if (!get_primary_dev(blkdev, &dev)) if (!dev_get_primary_dev(dt, blkdev, &dev))
return ret; return ret;
} }
if (MAJOR(dev) != md_major()) if (MAJOR(dev) != dt->md_major)
return ret; return ret;
ret = dm_snprintf(path, size, "%s/dev/block/%d:%d/md/%s", sysfs_dir, ret = dm_snprintf(path, size, "%s/dev/block/%d:%d/md/%s", sysfs_dir,
@ -171,7 +172,7 @@ static int _md_sysfs_attribute_snprintf(char *path, size_t size,
return ret; return ret;
} }
static int _md_sysfs_attribute_scanf(const char *sysfs_dir, static int _md_sysfs_attribute_scanf(struct dev_types *dt,
struct device *dev, struct device *dev,
const char *attribute_name, const char *attribute_name,
const char *attribute_fmt, const char *attribute_fmt,
@ -181,8 +182,8 @@ static int _md_sysfs_attribute_scanf(const char *sysfs_dir,
FILE *fp; FILE *fp;
int ret = 0; int ret = 0;
if (_md_sysfs_attribute_snprintf(path, PATH_MAX, dev, if (_md_sysfs_attribute_snprintf(path, PATH_MAX, dt,
attribute_name) < 0) dev, attribute_name) < 0)
return ret; return ret;
if (!(fp = fopen(path, "r"))) { if (!(fp = fopen(path, "r"))) {
@ -211,13 +212,13 @@ out:
/* /*
* Retrieve chunk size from md device using sysfs. * Retrieve chunk size from md device using sysfs.
*/ */
static unsigned long dev_md_chunk_size(const char *sysfs_dir, static unsigned long dev_md_chunk_size(struct dev_types *dt,
struct device *dev) struct device *dev)
{ {
const char *attribute = "chunk_size"; const char *attribute = "chunk_size";
unsigned long chunk_size_bytes = 0UL; unsigned long chunk_size_bytes = 0UL;
if (_md_sysfs_attribute_scanf(sysfs_dir, dev, attribute, if (_md_sysfs_attribute_scanf(dt, dev, attribute,
"%lu", &chunk_size_bytes) != 1) "%lu", &chunk_size_bytes) != 1)
return 0; return 0;
@ -230,13 +231,13 @@ static unsigned long dev_md_chunk_size(const char *sysfs_dir,
/* /*
* Retrieve level from md device using sysfs. * Retrieve level from md device using sysfs.
*/ */
static int dev_md_level(const char *sysfs_dir, struct device *dev) static int dev_md_level(struct dev_types *dt, struct device *dev)
{ {
char level_string[MD_MAX_SYSFS_SIZE]; char level_string[MD_MAX_SYSFS_SIZE];
const char *attribute = "level"; const char *attribute = "level";
int level = -1; int level = -1;
if (_md_sysfs_attribute_scanf(sysfs_dir, dev, attribute, if (_md_sysfs_attribute_scanf(dt, dev, attribute,
"%s", &level_string) != 1) "%s", &level_string) != 1)
return -1; return -1;
@ -253,12 +254,12 @@ static int dev_md_level(const char *sysfs_dir, struct device *dev)
/* /*
* Retrieve raid_disks from md device using sysfs. * Retrieve raid_disks from md device using sysfs.
*/ */
static int dev_md_raid_disks(const char *sysfs_dir, struct device *dev) static int dev_md_raid_disks(struct dev_types *dt, struct device *dev)
{ {
const char *attribute = "raid_disks"; const char *attribute = "raid_disks";
int raid_disks = 0; int raid_disks = 0;
if (_md_sysfs_attribute_scanf(sysfs_dir, dev, attribute, if (_md_sysfs_attribute_scanf(dt, dev, attribute,
"%d", &raid_disks) != 1) "%d", &raid_disks) != 1)
return 0; return 0;
@ -271,22 +272,21 @@ static int dev_md_raid_disks(const char *sysfs_dir, struct device *dev)
/* /*
* Calculate stripe width of md device using its sysfs files. * Calculate stripe width of md device using its sysfs files.
*/ */
unsigned long dev_md_stripe_width(struct device *dev) unsigned long dev_md_stripe_width(struct dev_types *dt, struct device *dev)
{ {
const char *sysfs_dir = dm_sysfs_dir();
unsigned long chunk_size_sectors = 0UL; unsigned long chunk_size_sectors = 0UL;
unsigned long stripe_width_sectors = 0UL; unsigned long stripe_width_sectors = 0UL;
int level, raid_disks, data_disks; int level, raid_disks, data_disks;
chunk_size_sectors = dev_md_chunk_size(sysfs_dir, dev); chunk_size_sectors = dev_md_chunk_size(dt, dev);
if (!chunk_size_sectors) if (!chunk_size_sectors)
return 0; return 0;
level = dev_md_level(sysfs_dir, dev); level = dev_md_level(dt, dev);
if (level < 0) if (level < 0)
return 0; return 0;
raid_disks = dev_md_raid_disks(sysfs_dir, dev); raid_disks = dev_md_raid_disks(dt, dev);
if (!raid_disks) if (!raid_disks)
return 0; return 0;
@ -333,7 +333,8 @@ int dev_is_md(struct device *dev __attribute__((unused)),
return 0; return 0;
} }
unsigned long dev_md_stripe_width(struct device *dev __attribute__((unused))) unsigned long dev_md_stripe_width(struct dev_types *dt __attribute__((unused)),
struct device *dev __attribute__((unused)))
{ {
return 0UL; return 0UL;
} }

View File

@ -13,6 +13,7 @@
*/ */
#include "lib.h" #include "lib.h"
#include "dev-type.h"
#include "metadata.h" #include "metadata.h"
#ifdef linux #ifdef linux

View File

@ -1,6 +1,5 @@
/* /*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2013 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
* *
* This file is part of LVM2. * This file is part of LVM2.
* *
@ -14,16 +13,240 @@
*/ */
#include "lib.h" #include "lib.h"
#include "lvm-types.h" #include "dev-type.h"
#include "device.h"
#include "metadata.h"
#include "filter.h"
#include "xlate.h" #include "xlate.h"
#include "config.h"
#include "metadata.h"
#include <libgen.h> /* dirname, basename */ #include <libgen.h>
#include <ctype.h>
#include "device-types.h"
struct dev_types *create_dev_types(const char *proc_dir,
const struct dm_config_node *cn)
{
struct dev_types *dt;
char line[80];
char proc_devices[PATH_MAX];
FILE *pd = NULL;
int i, j = 0;
int line_maj = 0;
int blocksection = 0;
size_t dev_len = 0;
const struct dm_config_value *cv;
const char *name;
char *nl;
if (!(dt = dm_zalloc(sizeof(struct dev_types)))) {
log_error("Failed to allocate device type register.");
return NULL;
}
if (!*proc_dir) {
log_verbose("No proc filesystem found: using all block device types");
for (i = 0; i < NUMBER_OF_MAJORS; i++)
dt->dev_type_array[i].max_partitions = 1;
return dt;
}
if (dm_snprintf(proc_devices, sizeof(proc_devices),
"%s/devices", proc_dir) < 0) {
log_error("Failed to create /proc/devices string");
goto bad;
}
if (!(pd = fopen(proc_devices, "r"))) {
log_sys_error("fopen", proc_devices);
goto bad;
}
while (fgets(line, sizeof(line), pd) != NULL) {
i = 0;
while (line[i] == ' ')
i++;
/* If it's not a number it may be name of section */
line_maj = atoi(((char *) (line + i)));
if (line_maj < 0 || line_maj >= NUMBER_OF_MAJORS) {
/*
* Device numbers shown in /proc/devices are actually direct
* numbers passed to registering function, however the kernel
* uses only 12 bits, so use just 12 bits for major.
*/
if ((nl = strchr(line, '\n'))) *nl = '\0';
log_warn("WARNING: /proc/devices line: %s, replacing major with %d.",
line, line_maj & (NUMBER_OF_MAJORS - 1));
line_maj &= (NUMBER_OF_MAJORS - 1);
}
if (!line_maj) {
blocksection = (line[i] == 'B') ? 1 : 0;
continue;
}
/* We only want block devices ... */
if (!blocksection)
continue;
/* Find the start of the device major name */
while (line[i] != ' ' && line[i] != '\0')
i++;
while (line[i] == ' ')
i++;
/* Look for md device */
if (!strncmp("md", line + i, 2) && isspace(*(line + i + 2)))
dt->md_major = line_maj;
/* Look for blkext device */
if (!strncmp("blkext", line + i, 6) && isspace(*(line + i + 6)))
dt->blkext_major = line_maj;
/* Look for drbd device */
if (!strncmp("drbd", line + i, 4) && isspace(*(line + i + 4)))
dt->drbd_major = line_maj;
/* Look for EMC powerpath */
if (!strncmp("emcpower", line + i, 8) && isspace(*(line + i + 8)))
dt->emcpower_major = line_maj;
if (!strncmp("power2", line + i, 6) && isspace(*(line + i + 6)))
dt->power2_major = line_maj;
/* Look for device-mapper device */
/* FIXME Cope with multiple majors */
if (!strncmp("device-mapper", line + i, 13) && isspace(*(line + i + 13)))
dt->device_mapper_major = line_maj;
/* Major is SCSI device */
if (!strncmp("sd", line + i, 2) && isspace(*(line + i + 2)))
dt->dev_type_array[line_maj].flags |= PARTITION_SCSI_DEVICE;
/* Go through the valid device names and if there is a
match store max number of partitions */
for (j = 0; _dev_known_types[j].name[0]; j++) {
dev_len = strlen(_dev_known_types[j].name);
if (dev_len <= strlen(line + i) &&
!strncmp(_dev_known_types[j].name, line + i, dev_len) &&
(line_maj < NUMBER_OF_MAJORS)) {
dt->dev_type_array[line_maj].max_partitions =
_dev_known_types[j].max_partitions;
break;
}
}
if (!cn)
continue;
/* Check devices/types for local variations */
for (cv = cn->v; cv; cv = cv->next) {
if (cv->type != DM_CFG_STRING) {
log_error("Expecting string in devices/types "
"in config file");
if (fclose(pd))
log_sys_error("fclose", proc_devices);
goto bad;
}
dev_len = strlen(cv->v.str);
name = cv->v.str;
cv = cv->next;
if (!cv || cv->type != DM_CFG_INT) {
log_error("Max partition count missing for %s "
"in devices/types in config file",
name);
if (fclose(pd))
log_sys_error("fclose", proc_devices);
goto bad;
}
if (!cv->v.i) {
log_error("Zero partition count invalid for "
"%s in devices/types in config file",
name);
if (fclose(pd))
log_sys_error("fclose", proc_devices);
goto bad;
}
if (dev_len <= strlen(line + i) &&
!strncmp(name, line + i, dev_len) &&
(line_maj < NUMBER_OF_MAJORS)) {
dt->dev_type_array[line_maj].max_partitions = cv->v.i;
break;
}
}
}
if (fclose(pd))
log_sys_error("fclose", proc_devices);
return dt;
bad:
dm_free(dt);
return NULL;
}
int dev_subsystem_part_major(struct dev_types *dt, struct device *dev)
{
dev_t primary_dev;
if (MAJOR(dev->dev) == dt->device_mapper_major)
return 1;
if (MAJOR(dev->dev) == dt->drbd_major)
return 1;
if (MAJOR(dev->dev) == dt->emcpower_major)
return 1;
if (MAJOR(dev->dev) == dt->power2_major)
return 1;
if ((MAJOR(dev->dev) == dt->blkext_major) &&
(dev_get_primary_dev(dt, dev, &primary_dev)) &&
(MAJOR(primary_dev) == dt->md_major))
return 1;
return 0;
}
const char *dev_subsystem_name(struct dev_types *dt, struct device *dev)
{
if (MAJOR(dev->dev) == dt->md_major)
return "MD";
if (MAJOR(dev->dev) == dt->drbd_major)
return "DRBD";
if (MAJOR(dev->dev) == dt->emcpower_major)
return "EMCPOWER";
if (MAJOR(dev->dev) == dt->power2_major)
return "POWER2";
if (MAJOR(dev->dev) == dt->blkext_major)
return "BLKEXT";
return "";
}
int major_max_partitions(struct dev_types *dt, int major)
{
if (major >= NUMBER_OF_MAJORS)
return 0;
return dt->dev_type_array[major].max_partitions;
}
int major_is_scsi_device(struct dev_types *dt, int major)
{
if (major >= NUMBER_OF_MAJORS)
return 0;
return (dt->dev_type_array[major].flags & PARTITION_SCSI_DEVICE) ? 1 : 0;
}
/* See linux/genhd.h and fs/partitions/msdos */ /* See linux/genhd.h and fs/partitions/msdos */
#define PART_MAGIC 0xAA55 #define PART_MAGIC 0xAA55
#define PART_MAGIC_OFFSET UINT64_C(0x1FE) #define PART_MAGIC_OFFSET UINT64_C(0x1FE)
#define PART_OFFSET UINT64_C(0x1BE) #define PART_OFFSET UINT64_C(0x1BE)
@ -41,12 +264,12 @@ struct partition {
uint32_t nr_sects; uint32_t nr_sects;
} __attribute__((packed)); } __attribute__((packed));
static int _is_partitionable(struct device *dev) static int _is_partitionable(struct dev_types *dt, struct device *dev)
{ {
int parts = max_partitions(MAJOR(dev->dev)); int parts = major_max_partitions(dt, MAJOR(dev->dev));
/* All MD devices are partitionable via blkext (as of 2.6.28) */ /* All MD devices are partitionable via blkext (as of 2.6.28) */
if (MAJOR(dev->dev) == md_major()) if (MAJOR(dev->dev) == dt->md_major)
return 1; return 1;
if ((parts <= 1) || (MINOR(dev->dev) % parts)) if ((parts <= 1) || (MINOR(dev->dev) % parts))
@ -87,14 +310,93 @@ static int _has_partition_table(struct device *dev)
return ret; return ret;
} }
int is_partitioned_dev(struct device *dev) int dev_is_partitioned(struct dev_types *dt, struct device *dev)
{ {
if (!_is_partitionable(dev)) if (!_is_partitionable(dt, dev))
return 0; return 0;
return _has_partition_table(dev); return _has_partition_table(dev);
} }
int dev_get_primary_dev(struct dev_types *dt, struct device *dev, dev_t *result)
{
const char *sysfs_dir = dm_sysfs_dir();
char path[PATH_MAX+1];
char temp_path[PATH_MAX+1];
char buffer[64];
struct stat info;
FILE *fp;
uint32_t pri_maj, pri_min;
int size, ret = 0;
/* check if dev is a partition */
if (dm_snprintf(path, PATH_MAX, "%s/dev/block/%d:%d/partition",
sysfs_dir, (int)MAJOR(dev->dev), (int)MINOR(dev->dev)) < 0) {
log_error("dm_snprintf partition failed");
return ret;
}
if (stat(path, &info) == -1) {
if (errno != ENOENT)
log_sys_error("stat", path);
return ret;
}
/*
* extract parent's path from the partition's symlink, e.g.:
* - readlink /sys/dev/block/259:0 = ../../block/md0/md0p1
* - dirname ../../block/md0/md0p1 = ../../block/md0
* - basename ../../block/md0/md0 = md0
* Parent's 'dev' sysfs attribute = /sys/block/md0/dev
*/
if ((size = readlink(dirname(path), temp_path, PATH_MAX)) < 0) {
log_sys_error("readlink", path);
return ret;
}
temp_path[size] = '\0';
if (dm_snprintf(path, PATH_MAX, "%s/block/%s/dev",
sysfs_dir, basename(dirname(temp_path))) < 0) {
log_error("dm_snprintf dev failed");
return ret;
}
/* finally, parse 'dev' attribute and create corresponding dev_t */
if (stat(path, &info) == -1) {
if (errno == ENOENT)
log_error("sysfs file %s does not exist", path);
else
log_sys_error("stat", path);
return ret;
}
fp = fopen(path, "r");
if (!fp) {
log_sys_error("fopen", path);
return ret;
}
if (!fgets(buffer, sizeof(buffer), fp)) {
log_sys_error("fgets", path);
goto out;
}
if (sscanf(buffer, "%d:%d", &pri_maj, &pri_min) != 2) {
log_error("sysfs file %s not in expected MAJ:MIN format: %s",
path, buffer);
goto out;
}
*result = MKDEV((dev_t)pri_maj, pri_min);
ret = 1;
out:
if (fclose(fp))
log_sys_error("fclose", path);
return ret;
}
#if 0 #if 0
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/mman.h> #include <sys/mman.h>
@ -278,86 +580,9 @@ int _get_partition_type(struct dev_mgr *dm, struct device *d)
#ifdef linux #ifdef linux
int get_primary_dev(const struct device *dev, dev_t *result) static unsigned long _dev_topology_attribute(struct dev_types *dt,
{ const char *attribute,
const char *sysfs_dir = dm_sysfs_dir(); struct device *dev)
char path[PATH_MAX+1];
char temp_path[PATH_MAX+1];
char buffer[64];
struct stat info;
FILE *fp;
uint32_t pri_maj, pri_min;
int size, ret = 0;
/* check if dev is a partition */
if (dm_snprintf(path, PATH_MAX, "%s/dev/block/%d:%d/partition",
sysfs_dir, (int)MAJOR(dev->dev), (int)MINOR(dev->dev)) < 0) {
log_error("dm_snprintf partition failed");
return ret;
}
if (stat(path, &info) == -1) {
if (errno != ENOENT)
log_sys_error("stat", path);
return ret;
}
/*
* extract parent's path from the partition's symlink, e.g.:
* - readlink /sys/dev/block/259:0 = ../../block/md0/md0p1
* - dirname ../../block/md0/md0p1 = ../../block/md0
* - basename ../../block/md0/md0 = md0
* Parent's 'dev' sysfs attribute = /sys/block/md0/dev
*/
if ((size = readlink(dirname(path), temp_path, PATH_MAX)) < 0) {
log_sys_error("readlink", path);
return ret;
}
temp_path[size] = '\0';
if (dm_snprintf(path, PATH_MAX, "%s/block/%s/dev",
sysfs_dir, basename(dirname(temp_path))) < 0) {
log_error("dm_snprintf dev failed");
return ret;
}
/* finally, parse 'dev' attribute and create corresponding dev_t */
if (stat(path, &info) == -1) {
if (errno == ENOENT)
log_error("sysfs file %s does not exist", path);
else
log_sys_error("stat", path);
return ret;
}
fp = fopen(path, "r");
if (!fp) {
log_sys_error("fopen", path);
return ret;
}
if (!fgets(buffer, sizeof(buffer), fp)) {
log_sys_error("fgets", path);
goto out;
}
if (sscanf(buffer, "%d:%d", &pri_maj, &pri_min) != 2) {
log_error("sysfs file %s not in expected MAJ:MIN format: %s",
path, buffer);
goto out;
}
*result = MKDEV((dev_t)pri_maj, pri_min);
ret = 1;
out:
if (fclose(fp))
log_sys_error("fclose", path);
return ret;
}
static unsigned long _dev_topology_attribute(const char *attribute, struct device *dev)
{ {
const char *sysfs_dir = dm_sysfs_dir(); const char *sysfs_dir = dm_sysfs_dir();
static const char sysfs_fmt_str[] = "%s/dev/block/%d:%d/%s"; static const char sysfs_fmt_str[] = "%s/dev/block/%d:%d/%s";
@ -390,7 +615,7 @@ static unsigned long _dev_topology_attribute(const char *attribute, struct devic
log_sys_error("stat", path); log_sys_error("stat", path);
return 0; return 0;
} }
if (!get_primary_dev(dev, &primary)) if (!dev_get_primary_dev(dt, dev, &primary))
return 0; return 0;
/* get attribute from partition's primary device */ /* get attribute from partition's primary device */
@ -433,29 +658,29 @@ out:
return result >> SECTOR_SHIFT; return result >> SECTOR_SHIFT;
} }
unsigned long dev_alignment_offset(struct device *dev) unsigned long dev_alignment_offset(struct dev_types *dt, struct device *dev)
{ {
return _dev_topology_attribute("alignment_offset", dev); return _dev_topology_attribute(dt, "alignment_offset", dev);
} }
unsigned long dev_minimum_io_size(struct device *dev) unsigned long dev_minimum_io_size(struct dev_types *dt, struct device *dev)
{ {
return _dev_topology_attribute("queue/minimum_io_size", dev); return _dev_topology_attribute(dt, "queue/minimum_io_size", dev);
} }
unsigned long dev_optimal_io_size(struct device *dev) unsigned long dev_optimal_io_size(struct dev_types *dt, struct device *dev)
{ {
return _dev_topology_attribute("queue/optimal_io_size", dev); return _dev_topology_attribute(dt, "queue/optimal_io_size", dev);
} }
unsigned long dev_discard_max_bytes(struct device *dev) unsigned long dev_discard_max_bytes(struct dev_types *dt, struct device *dev)
{ {
return _dev_topology_attribute("queue/discard_max_bytes", dev); return _dev_topology_attribute(dt, "queue/discard_max_bytes", dev);
} }
unsigned long dev_discard_granularity(struct device *dev) unsigned long dev_discard_granularity(struct dev_types *dt, struct device *dev)
{ {
return _dev_topology_attribute("queue/discard_granularity", dev); return _dev_topology_attribute(dt, "queue/discard_granularity", dev);
} }
#else #else
@ -465,27 +690,27 @@ int get_primary_dev(struct device *dev, dev_t *result)
return 0; return 0;
} }
unsigned long dev_alignment_offset(struct device *dev) unsigned long dev_alignment_offset(struct dev_types *dt, struct device *dev)
{ {
return 0UL; return 0UL;
} }
unsigned long dev_minimum_io_size(struct device *dev) unsigned long dev_minimum_io_size(struct dev_types *dt, struct device *dev)
{ {
return 0UL; return 0UL;
} }
unsigned long dev_optimal_io_size(struct device *dev) unsigned long dev_optimal_io_size(struct dev_types *dt, struct device *dev)
{ {
return 0UL; return 0UL;
} }
unsigned long dev_discard_max_bytes(struct device *dev) unsigned long dev_discard_max_bytes(struct dev_types *dt, struct device *dev)
{ {
return 0UL; return 0UL;
} }
unsigned long dev_discard_granularity(struct device *dev) unsigned long dev_discard_granularity(struct dev_types *dt, struct device *dev)
{ {
return 0UL; return 0UL;
} }

76
lib/device/dev-type.h Normal file
View File

@ -0,0 +1,76 @@
/*
* Copyright (C) 2013 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LVM_DEV_TYPE_H
#define _LVM_DEV_TYPE_H
#include "device.h"
#define NUMBER_OF_MAJORS 4096
#ifdef linux
# define MAJOR(dev) ((dev & 0xfff00) >> 8)
# define MINOR(dev) ((dev & 0xff) | ((dev >> 12) & 0xfff00))
# define MKDEV(ma,mi) ((mi & 0xff) | (ma << 8) | ((mi & ~0xff) << 12))
#else
# define MAJOR(x) major((x))
# define MINOR(x) minor((x))
# define MKDEV(x,y) makedev((x),(y))
#endif
#define PARTITION_SCSI_DEVICE (1 << 0)
struct dev_type_def {
int max_partitions; /* 0 means LVM won't use this major number. */
int flags;
};
struct dev_types {
int md_major;
int blkext_major;
int drbd_major;
int device_mapper_major;
int emcpower_major;
int power2_major;
struct dev_type_def dev_type_array[NUMBER_OF_MAJORS];
};
struct dev_types *create_dev_types(const char *proc_dir, const struct dm_config_node *cn);
/* Subsystems */
int dev_subsystem_part_major(struct dev_types *dt, struct device *dev);
const char *dev_subsystem_name(struct dev_types *dt, struct device *dev);
int major_is_scsi_device(struct dev_types *dt, int major);
/* Signature/superblock recognition with position returned where found. */
int dev_is_md(struct device *dev, uint64_t *sb);
int dev_is_swap(struct device *dev, uint64_t *signature);
int dev_is_luks(struct device *dev, uint64_t *signature);
/* Type-specific device properties */
unsigned long dev_md_stripe_width(struct dev_types *dt, struct device *dev);
/* Partitioning */
int major_max_partitions(struct dev_types *dt, int major);
int dev_is_partitioned(struct dev_types *dt, struct device *dev);
int dev_get_primary_dev(struct dev_types *dt, struct device *dev, dev_t *result);
/* Various device properties */
unsigned long dev_alignment_offset(struct dev_types *dt, struct device *dev);
unsigned long dev_minimum_io_size(struct dev_types *dt, struct device *dev);
unsigned long dev_optimal_io_size(struct dev_types *dt, struct device *dev);
unsigned long dev_discard_max_bytes(struct dev_types *dt, struct device *dev);
unsigned long dev_discard_granularity(struct dev_types *dt, struct device *dev);
#endif

View File

@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. * Copyright (C) 2004-2013 Red Hat, Inc. All rights reserved.
* *
* This file is part of LVM2. * This file is part of LVM2.
* *
@ -16,7 +16,8 @@
typedef struct { typedef struct {
const char name[15]; const char name[15];
const int8_t max_partitions; const int8_t max_partitions;
} device_info_t; const char *desc;
} dev_known_type_t;
/* /*
* Devices are only checked for partition tables if their minor number * Devices are only checked for partition tables if their minor number
@ -26,38 +27,38 @@ typedef struct {
* *
* The list can be supplemented with devices/types in the config file. * The list can be supplemented with devices/types in the config file.
*/ */
static const device_info_t _device_info[] = { static const dev_known_type_t _dev_known_types[] = {
{"ide", 64}, /* IDE disk */ {"ide", 64, "IDE disk"},
{"sd", 16}, /* SCSI disk */ {"sd", 16, "SCSI disk"},
{"md", 1}, /* Multiple Disk driver (SoftRAID) */ {"md", 1, "Multiple Disk (MD/SoftRAID)"},
{"mdp", 1}, /* Partitionable MD */ {"mdp", 1, "Partitionable MD"},
{"loop", 1}, /* Loop device */ {"loop", 1, "Loop device"},
{"dasd", 4}, /* DASD disk (IBM S/390, zSeries) */ {"dasd", 4, "DASD disk (IBM S/390, zSeries)"},
{"dac960", 8}, /* DAC960 */ {"dac960", 8, "DAC960"},
{"nbd", 16}, /* Network Block Device */ {"nbd", 16, "Network Block Device"},
{"ida", 16}, /* Compaq SMART2 */ {"ida", 16, "Compaq SMART2"},
{"cciss", 16}, /* Compaq CCISS array */ {"cciss", 16, "Compaq CCISS array"},
{"ubd", 16}, /* User-mode virtual block device */ {"ubd", 16, "User-mode virtual block device"},
{"ataraid", 16}, /* ATA Raid */ {"ataraid", 16, "ATA Raid"},
{"drbd", 16}, /* Distributed Replicated Block Device */ {"drbd", 16, "Distributed Replicated Block Device (DRBD)"},
{"emcpower", 16}, /* EMC Powerpath */ {"emcpower", 16, "EMC Powerpath"},
{"power2", 16}, /* EMC Powerpath */ {"power2", 16, "EMC Powerpath"},
{"i2o_block", 16}, /* i2o Block Disk */ {"i2o_block", 16, "i2o Block Disk"},
{"iseries/vd", 8}, /* iSeries disks */ {"iseries/vd", 8, "iSeries disks"},
{"gnbd", 1}, /* Network block device */ {"gnbd", 1, "Network block device"},
{"ramdisk", 1}, /* RAM disk */ {"ramdisk", 1, "RAM disk"},
{"aoe", 16}, /* ATA over Ethernet */ {"aoe", 16, "ATA over Ethernet"},
{"device-mapper", 1}, /* Other mapped devices */ {"device-mapper", 1, "Mapped device"},
{"xvd", 16}, /* Xen virtual block device */ {"xvd", 16, "Xen virtual block device"},
{"vdisk", 8}, /* SUN's LDOM virtual block device */ {"vdisk", 8, "SUN's LDOM virtual block device"},
{"ps3disk", 16}, /* PlayStation 3 internal disk */ {"ps3disk", 16, "PlayStation 3 internal disk"},
{"virtblk", 8}, /* VirtIO disk */ {"virtblk", 8, "VirtIO disk"},
{"mmc", 16}, /* MMC block device */ {"mmc", 16, "MMC block device"},
{"blkext", 1}, /* Extended device partitions */ {"blkext", 1, "Extended device partitions"},
{"fio", 16}, /* Fusion */ {"fio", 16, "Fusion IO"},
{"mtip32xx", 16}, /* Micron PCIe SSDs */ {"mtip32xx", 16, "Micron PCIe SSD"},
{"vtms", 16}, /* Violin Memory */ {"vtms", 16, "Violin Memory"},
{"skd", 16}, /* STEC */ {"skd", 16, "STEC"},
{"scm", 8}, /* Storage Class Memory (IBM S/390) */ {"scm", 8, "Storage Class Memory (IBM S/390)"},
{"", 0} {"", 0, ""}
}; };

View File

@ -99,20 +99,4 @@ struct device *dev_create_file(const char *filename, struct device *dev,
/* Return a valid device name from the alias list; NULL otherwise */ /* Return a valid device name from the alias list; NULL otherwise */
const char *dev_name_confirmed(struct device *dev, int quiet); const char *dev_name_confirmed(struct device *dev, int quiet);
/* Does device contain md superblock? If so, where? */
int dev_is_md(struct device *dev, uint64_t *sb);
int dev_is_swap(struct device *dev, uint64_t *signature);
int dev_is_luks(struct device *dev, uint64_t *signature);
unsigned long dev_md_stripe_width(struct device *dev);
int is_partitioned_dev(struct device *dev);
int get_primary_dev(const struct device *dev, dev_t *result);
unsigned long dev_alignment_offset(struct device *dev);
unsigned long dev_minimum_io_size(struct device *dev);
unsigned long dev_optimal_io_size(struct device *dev);
unsigned long dev_discard_max_bytes(struct device *dev);
unsigned long dev_discard_granularity(struct device *dev);
#endif #endif

View File

@ -16,8 +16,6 @@
#include "lib.h" #include "lib.h"
#include "filter-composite.h" #include "filter-composite.h"
#include <stdarg.h>
static int _and_p(struct dev_filter *f, struct device *dev) static int _and_p(struct dev_filter *f, struct device *dev)
{ {
struct dev_filter **filters; struct dev_filter **filters;

View File

@ -50,7 +50,7 @@ static void _destroy(struct dev_filter *f)
dm_free(f); dm_free(f);
} }
struct dev_filter *md_filter_create(void) struct dev_filter *md_filter_create(struct dev_types *dt)
{ {
struct dev_filter *f; struct dev_filter *f;
@ -62,14 +62,14 @@ struct dev_filter *md_filter_create(void)
f->passes_filter = _ignore_md; f->passes_filter = _ignore_md;
f->destroy = _destroy; f->destroy = _destroy;
f->use_count = 0; f->use_count = 0;
f->private = NULL; f->private = dt;
return f; return f;
} }
#else #else
struct dev_filter *md_filter_create(void) struct dev_filter *md_filter_create(struct dev_types *dt)
{ {
return NULL; return NULL;
} }

View File

@ -16,8 +16,9 @@
#define _LVM_FILTER_MD_H #define _LVM_FILTER_MD_H
#include "dev-cache.h" #include "dev-cache.h"
#include "dev-type.h"
struct dev_filter *md_filter_create(void); struct dev_filter *md_filter_create(struct dev_types *dt);
#endif #endif

View File

@ -13,11 +13,11 @@
*/ */
#include "lib.h" #include "lib.h"
#include "filter.h"
#include "filter-mpath.h" #include "filter-mpath.h"
#include "activate.h" #include "activate.h"
#ifdef linux #ifdef linux
#include <dirent.h> #include <dirent.h>
#define MPATH_PREFIX "mpath-" #define MPATH_PREFIX "mpath-"
@ -115,15 +115,17 @@ static int get_parent_mpath(const char *dir, char *name, int max_size)
static int dev_is_mpath(struct dev_filter *f, struct device *dev) static int dev_is_mpath(struct dev_filter *f, struct device *dev)
{ {
struct dev_types *dt = (struct dev_types *) f->private;
const char *name; const char *name;
char path[PATH_MAX+1]; char path[PATH_MAX+1];
char parent_name[PATH_MAX+1]; char parent_name[PATH_MAX+1];
struct stat info; struct stat info;
const char *sysfs_dir = dm_sysfs_dir(); const char *sysfs_dir = dm_sysfs_dir();
int major, minor; int major = MAJOR(dev->dev);
int minor = MINOR(dev->dev);
/* Limit this filter only to SCSI devices */ /* Limit this filter only to SCSI devices */
if (!major_is_scsi_device(MAJOR(dev->dev))) if (!major_is_scsi_device(dt, MAJOR(dev->dev)))
return 0; return 0;
if (!(name = get_sysfs_name(dev))) if (!(name = get_sysfs_name(dev)))
@ -149,8 +151,9 @@ static int dev_is_mpath(struct dev_filter *f, struct device *dev)
if (!get_sysfs_get_major_minor(sysfs_dir, parent_name, &major, &minor)) if (!get_sysfs_get_major_minor(sysfs_dir, parent_name, &major, &minor))
return_0; return_0;
if (major != dm_major()) { if (major != dt->device_mapper_major) {
log_error("mpath major %d is not dm major %d.", major, dm_major()); log_error("mpath major %d is not dm major %d.", major,
dt->device_mapper_major);
return 0; return 0;
} }
@ -172,11 +175,10 @@ static void _destroy(struct dev_filter *f)
if (f->use_count) if (f->use_count)
log_error(INTERNAL_ERROR "Destroying mpath filter while in use %u times.", f->use_count); log_error(INTERNAL_ERROR "Destroying mpath filter while in use %u times.", f->use_count);
dm_free(f->private);
dm_free(f); dm_free(f);
} }
struct dev_filter *mpath_filter_create(void) struct dev_filter *mpath_filter_create(struct dev_types *dt)
{ {
const char *sysfs_dir = dm_sysfs_dir(); const char *sysfs_dir = dm_sysfs_dir();
struct dev_filter *f; struct dev_filter *f;
@ -194,19 +196,14 @@ struct dev_filter *mpath_filter_create(void)
f->passes_filter = _ignore_mpath; f->passes_filter = _ignore_mpath;
f->destroy = _destroy; f->destroy = _destroy;
f->use_count = 0; f->use_count = 0;
f->private = dt;
if (!(f->private = dm_strdup(sysfs_dir))) {
log_error("Cannot duplicate sysfs dir.");
dm_free(f);
return NULL;
}
return f; return f;
} }
#else #else
struct dev_filter *mpath_filter_create(const char *sysfs_dir __attribute__((unused))) struct dev_filter *mpath_filter_create(struct device_types *dt)
{ {
return NULL; return NULL;
} }

View File

@ -16,8 +16,9 @@
#define _LVM_FILTER_MPATH_H #define _LVM_FILTER_MPATH_H
#include "dev-cache.h" #include "dev-cache.h"
#include "dev-type.h"
struct dev_filter *mpath_filter_create(void); struct dev_filter *mpath_filter_create(struct dev_types *dt);
#endif #endif

View File

@ -14,23 +14,17 @@
*/ */
#include "lib.h" #include "lib.h"
#include "config.h"
#include "dev-cache.h"
#include "filter.h"
#include "filter-persistent.h" #include "filter-persistent.h"
#include "config.h"
#include "lvm-file.h" #include "lvm-file.h"
#include "lvm-string.h"
#include "activate.h" #include "activate.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
struct pfilter { struct pfilter {
char *file; char *file;
struct dm_hash_table *devices; struct dm_hash_table *devices;
struct dev_filter *real; struct dev_filter *real;
time_t ctime; time_t ctime;
struct dev_types *dt;
}; };
/* /*
@ -287,7 +281,7 @@ static int _lookup_p(struct dev_filter *f, struct device *dev)
} }
/* Test dm devices every time, so cache them as GOOD. */ /* Test dm devices every time, so cache them as GOOD. */
if (MAJOR(dev->dev) == dm_major()) { if (MAJOR(dev->dev) == pf->dt->device_mapper_major) {
if (!l) if (!l)
dm_list_iterate_items(sl, &dev->aliases) dm_list_iterate_items(sl, &dev->aliases)
if (!dm_hash_insert(pf->devices, sl->str, PF_GOOD_DEVICE)) { if (!dm_hash_insert(pf->devices, sl->str, PF_GOOD_DEVICE)) {
@ -329,7 +323,8 @@ static void _persistent_destroy(struct dev_filter *f)
dm_free(f); dm_free(f);
} }
struct dev_filter *persistent_filter_create(struct dev_filter *real, struct dev_filter *persistent_filter_create(struct dev_types *dt,
struct dev_filter *real,
const char *file) const char *file)
{ {
struct pfilter *pf; struct pfilter *pf;
@ -341,6 +336,8 @@ struct dev_filter *persistent_filter_create(struct dev_filter *real,
return NULL; return NULL;
} }
pf->dt = dt;
if (!(pf->file = dm_strdup(file))) { if (!(pf->file = dm_strdup(file))) {
log_error("Filename duplication for persistent filter failed."); log_error("Filename duplication for persistent filter failed.");
goto bad; goto bad;

View File

@ -17,8 +17,10 @@
#define _LVM_FILTER_PERSISTENT_H #define _LVM_FILTER_PERSISTENT_H
#include "dev-cache.h" #include "dev-cache.h"
#include "dev-type.h"
struct dev_filter *persistent_filter_create(struct dev_filter *f, struct dev_filter *persistent_filter_create(struct dev_types *dt,
struct dev_filter *f,
const char *file); const char *file);
int persistent_filter_load(struct dev_filter *f, struct dm_config_tree **cft_out); int persistent_filter_load(struct dev_filter *f, struct dm_config_tree **cft_out);

View File

@ -15,7 +15,6 @@
#include "lib.h" #include "lib.h"
#include "filter-regex.h" #include "filter-regex.h"
#include "device.h"
struct rfilter { struct rfilter {
struct dm_pool *mem; struct dm_pool *mem;

View File

@ -16,7 +16,6 @@
#ifndef _LVM_FILTER_REGEX_H #ifndef _LVM_FILTER_REGEX_H
#define _LVM_FILTER_REGEX_H #define _LVM_FILTER_REGEX_H
#include "config.h"
#include "dev-cache.h" #include "dev-cache.h"
/* /*

View File

@ -15,7 +15,6 @@
#ifndef _LVM_FILTER_SYSFS_H #ifndef _LVM_FILTER_SYSFS_H
#define _LVM_FILTER_SYSFS_H #define _LVM_FILTER_SYSFS_H
#include "config.h"
#include "dev-cache.h" #include "dev-cache.h"
struct dev_filter *sysfs_filter_create(void); struct dev_filter *sysfs_filter_create(void);

View File

@ -14,104 +14,21 @@
*/ */
#include "lib.h" #include "lib.h"
#include "dev-cache.h"
#include "filter.h" #include "filter.h"
#include "lvm-string.h" #include "lvm-string.h"
#include "config.h" #include "config.h"
#include "metadata.h" #include "metadata.h"
#include "activate.h" #include "activate.h"
#include <dirent.h> static int _passes_lvm_type_device_filter(struct dev_filter *f, struct device *dev)
#include <unistd.h>
#include <ctype.h>
#include <fcntl.h>
#include <limits.h>
#include "device/device-types.h"
#define NUMBER_OF_MAJORS 4096
#define PARTITION_SCSI_DEVICE (1 << 0)
static struct {
int max_partitions; /* 0 means LVM won't use this major number. */
int flags;
} _partitions[NUMBER_OF_MAJORS];
static int _md_major = -1;
static int _blkext_major = -1;
static int _drbd_major = -1;
static int _device_mapper_major = -1;
static int _emcpower_major = -1;
static int _power2_major = -1;
int dm_major(void)
{
return _device_mapper_major;
}
int md_major(void)
{
return _md_major;
}
int blkext_major(void)
{
return _blkext_major;
}
int dev_subsystem_part_major(const struct device *dev)
{
dev_t primary_dev;
if (MAJOR(dev->dev) == _md_major)
return 1;
if (MAJOR(dev->dev) == _drbd_major)
return 1;
if (MAJOR(dev->dev) == _emcpower_major)
return 1;
if (MAJOR(dev->dev) == _power2_major)
return 1;
if ((MAJOR(dev->dev) == _blkext_major) &&
(get_primary_dev(dev, &primary_dev)) &&
(MAJOR(primary_dev) == _md_major))
return 1;
return 0;
}
const char *dev_subsystem_name(const struct device *dev)
{
if (MAJOR(dev->dev) == _md_major)
return "MD";
if (MAJOR(dev->dev) == _drbd_major)
return "DRBD";
if (MAJOR(dev->dev) == _emcpower_major)
return "EMCPOWER";
if (MAJOR(dev->dev) == _power2_major)
return "POWER2";
if (MAJOR(dev->dev) == _blkext_major)
return "BLKEXT";
return "";
}
static int _passes_lvm_type_device_filter(struct dev_filter *f __attribute__((unused)),
struct device *dev)
{ {
struct dev_types *dt = (struct dev_types *) f->private;
const char *name = dev_name(dev); const char *name = dev_name(dev);
int ret = 0; int ret = 0;
uint64_t size; uint64_t size;
/* Is this a recognised device type? */ /* Is this a recognised device type? */
if (!_partitions[MAJOR(dev->dev)].max_partitions) { if (!dt->dev_type_array[MAJOR(dev->dev)].max_partitions) {
log_debug_devs("%s: Skipping: Unrecognised LVM device type %" log_debug_devs("%s: Skipping: Unrecognised LVM device type %"
PRIu64, name, (uint64_t) MAJOR(dev->dev)); PRIu64, name, (uint64_t) MAJOR(dev->dev));
return 0; return 0;
@ -134,7 +51,7 @@ static int _passes_lvm_type_device_filter(struct dev_filter *f __attribute__((un
goto out; goto out;
} }
if (is_partitioned_dev(dev)) { if (dev_is_partitioned(dt, dev)) {
log_debug_devs("%s: Skipping: Partition table signature found", log_debug_devs("%s: Skipping: Partition table signature found",
name); name);
goto out; goto out;
@ -149,179 +66,6 @@ static int _passes_lvm_type_device_filter(struct dev_filter *f __attribute__((un
return ret; return ret;
} }
static int _scan_proc_dev(const char *proc, const struct dm_config_node *cn)
{
char line[80];
char proc_devices[PATH_MAX];
FILE *pd = NULL;
int i, j = 0;
int line_maj = 0;
int blocksection = 0;
size_t dev_len = 0;
const struct dm_config_value *cv;
const char *name;
char *nl;
if (!*proc) {
log_verbose("No proc filesystem found: using all block device "
"types");
for (i = 0; i < NUMBER_OF_MAJORS; i++)
_partitions[i].max_partitions = 1;
return 1;
}
/* All types unrecognised initially */
memset(_partitions, 0, sizeof(_partitions));
if (dm_snprintf(proc_devices, sizeof(proc_devices),
"%s/devices", proc) < 0) {
log_error("Failed to create /proc/devices string");
return 0;
}
if (!(pd = fopen(proc_devices, "r"))) {
log_sys_error("fopen", proc_devices);
return 0;
}
while (fgets(line, sizeof(line), pd) != NULL) {
i = 0;
while (line[i] == ' ')
i++;
/* If it's not a number it may be name of section */
line_maj = atoi(((char *) (line + i)));
if (line_maj < 0 || line_maj >= NUMBER_OF_MAJORS) {
/*
* Device numbers shown in /proc/devices are actually direct
* numbers passed to registering function, however the kernel
* uses only 12 bits, so use just 12 bits for major.
*/
if ((nl = strchr(line, '\n'))) *nl = '\0';
log_warn("WARNING: /proc/devices line: %s, replacing major with %d.",
line, line_maj & (NUMBER_OF_MAJORS - 1));
line_maj &= (NUMBER_OF_MAJORS - 1);
}
if (!line_maj) {
blocksection = (line[i] == 'B') ? 1 : 0;
continue;
}
/* We only want block devices ... */
if (!blocksection)
continue;
/* Find the start of the device major name */
while (line[i] != ' ' && line[i] != '\0')
i++;
while (line[i] == ' ')
i++;
/* Look for md device */
if (!strncmp("md", line + i, 2) && isspace(*(line + i + 2)))
_md_major = line_maj;
/* Look for blkext device */
if (!strncmp("blkext", line + i, 6) && isspace(*(line + i + 6)))
_blkext_major = line_maj;
/* Look for drbd device */
if (!strncmp("drbd", line + i, 4) && isspace(*(line + i + 4)))
_drbd_major = line_maj;
/* Look for EMC powerpath */
if (!strncmp("emcpower", line + i, 8) && isspace(*(line + i + 8)))
_emcpower_major = line_maj;
if (!strncmp("power2", line + i, 6) && isspace(*(line + i + 6)))
_power2_major = line_maj;
/* Look for device-mapper device */
/* FIXME Cope with multiple majors */
if (!strncmp("device-mapper", line + i, 13) && isspace(*(line + i + 13)))
_device_mapper_major = line_maj;
/* Major is SCSI device */
if (!strncmp("sd", line + i, 2) && isspace(*(line + i + 2)))
_partitions[line_maj].flags |= PARTITION_SCSI_DEVICE;
/* Go through the valid device names and if there is a
match store max number of partitions */
for (j = 0; _device_info[j].name[0]; j++) {
dev_len = strlen(_device_info[j].name);
if (dev_len <= strlen(line + i) &&
!strncmp(_device_info[j].name, line + i, dev_len) &&
(line_maj < NUMBER_OF_MAJORS)) {
_partitions[line_maj].max_partitions =
_device_info[j].max_partitions;
break;
}
}
if (!cn)
continue;
/* Check devices/types for local variations */
for (cv = cn->v; cv; cv = cv->next) {
if (cv->type != DM_CFG_STRING) {
log_error("Expecting string in devices/types "
"in config file");
if (fclose(pd))
log_sys_error("fclose", proc_devices);
return 0;
}
dev_len = strlen(cv->v.str);
name = cv->v.str;
cv = cv->next;
if (!cv || cv->type != DM_CFG_INT) {
log_error("Max partition count missing for %s "
"in devices/types in config file",
name);
if (fclose(pd))
log_sys_error("fclose", proc_devices);
return 0;
}
if (!cv->v.i) {
log_error("Zero partition count invalid for "
"%s in devices/types in config file",
name);
if (fclose(pd))
log_sys_error("fclose", proc_devices);
return 0;
}
if (dev_len <= strlen(line + i) &&
!strncmp(name, line + i, dev_len) &&
(line_maj < NUMBER_OF_MAJORS)) {
_partitions[line_maj].max_partitions = cv->v.i;
break;
}
}
}
if (fclose(pd))
log_sys_error("fclose", proc_devices);
return 1;
}
int max_partitions(int major)
{
if (major >= NUMBER_OF_MAJORS)
return 0;
return _partitions[major].max_partitions;
}
int major_is_scsi_device(int major)
{
if (major >= NUMBER_OF_MAJORS)
return 0;
return (_partitions[major].flags & PARTITION_SCSI_DEVICE) ? 1 : 0;
}
static void _lvm_type_filter_destroy(struct dev_filter *f) static void _lvm_type_filter_destroy(struct dev_filter *f)
{ {
if (f->use_count) if (f->use_count)
@ -330,8 +74,7 @@ static void _lvm_type_filter_destroy(struct dev_filter *f)
dm_free(f); dm_free(f);
} }
struct dev_filter *lvm_type_filter_create(const char *proc, struct dev_filter *lvm_type_filter_create(struct dev_types *dt)
const struct dm_config_node *cn)
{ {
struct dev_filter *f; struct dev_filter *f;
@ -343,12 +86,7 @@ struct dev_filter *lvm_type_filter_create(const char *proc,
f->passes_filter = _passes_lvm_type_device_filter; f->passes_filter = _passes_lvm_type_device_filter;
f->destroy = _lvm_type_filter_destroy; f->destroy = _lvm_type_filter_destroy;
f->use_count = 0; f->use_count = 0;
f->private = NULL; f->private = dt;
if (!_scan_proc_dev(proc, cn)) {
dm_free(f);
return_NULL;
}
return f; return f;
} }

View File

@ -16,30 +16,9 @@
#ifndef _LVM_FILTER_H #ifndef _LVM_FILTER_H
#define _LVM_FILTER_H #define _LVM_FILTER_H
#include "config.h" #include "dev-cache.h"
#include "dev-type.h"
#include <sys/stat.h> struct dev_filter *lvm_type_filter_create(struct dev_types *dt);
#ifdef linux
# define MAJOR(dev) ((dev & 0xfff00) >> 8)
# define MINOR(dev) ((dev & 0xff) | ((dev >> 12) & 0xfff00))
# define MKDEV(ma,mi) ((mi & 0xff) | (ma << 8) | ((mi & ~0xff) << 12))
#else
# define MAJOR(x) major((x))
# define MINOR(x) minor((x))
# define MKDEV(x,y) makedev((x),(y))
#endif
struct dev_filter *lvm_type_filter_create(const char *proc,
const struct dm_config_node *cn);
int dm_major(void);
int md_major(void);
int blkext_major(void);
int max_partitions(int major);
int major_is_scsi_device(int major);
int dev_subsystem_part_major(const struct device *dev);
const char *dev_subsystem_name(const struct device *dev);
#endif #endif

View File

@ -18,6 +18,7 @@
#include "xlate.h" #include "xlate.h"
#include "filter.h" #include "filter.h"
#include "lvmcache.h" #include "lvmcache.h"
#include "metadata-exported.h"
#include <fcntl.h> #include <fcntl.h>
@ -426,7 +427,7 @@ struct disk_list *read_disk(const struct format_type *fmt, struct device *dev,
return dl; return dl;
} }
static void _add_pv_to_list(struct dm_list *head, struct disk_list *data) static void _add_pv_to_list(struct cmd_context *cmd, struct dm_list *head, struct disk_list *data)
{ {
struct pv_disk *pvd; struct pv_disk *pvd;
struct disk_list *diskl; struct disk_list *diskl;
@ -435,14 +436,14 @@ static void _add_pv_to_list(struct dm_list *head, struct disk_list *data)
pvd = &diskl->pvd; pvd = &diskl->pvd;
if (!strncmp((char *)data->pvd.pv_uuid, (char *)pvd->pv_uuid, if (!strncmp((char *)data->pvd.pv_uuid, (char *)pvd->pv_uuid,
sizeof(pvd->pv_uuid))) { sizeof(pvd->pv_uuid))) {
if (!dev_subsystem_part_major(data->dev)) { if (!dev_subsystem_part_major(cmd->dev_types, data->dev)) {
log_very_verbose("Ignoring duplicate PV %s on " log_very_verbose("Ignoring duplicate PV %s on "
"%s", pvd->pv_uuid, "%s", pvd->pv_uuid,
dev_name(data->dev)); dev_name(data->dev));
return; return;
} }
log_very_verbose("Duplicate PV %s - using %s %s", log_very_verbose("Duplicate PV %s - using %s %s",
pvd->pv_uuid, dev_subsystem_name(data->dev), pvd->pv_uuid, dev_subsystem_name(cmd->dev_types, data->dev),
dev_name(data->dev)); dev_name(data->dev));
dm_list_del(&diskl->list); dm_list_del(&diskl->list);
break; break;
@ -469,7 +470,7 @@ static int _read_pv_in_vg(struct lvmcache_info *info, void *baton)
!(b->data = read_disk(lvmcache_fmt(info), lvmcache_device(info), b->mem, b->vg_name))) !(b->data = read_disk(lvmcache_fmt(info), lvmcache_device(info), b->mem, b->vg_name)))
return 0; /* stop here */ return 0; /* stop here */
_add_pv_to_list(b->head, b->data); _add_pv_to_list(lvmcache_fmt(info)->cmd, b->head, b->data);
return 1; return 1;
} }
@ -519,7 +520,7 @@ int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name,
/* Otherwise do a complete scan */ /* Otherwise do a complete scan */
for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter)) { for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter)) {
if ((baton.data = read_disk(fmt, dev, mem, vg_name))) { if ((baton.data = read_disk(fmt, dev, mem, vg_name))) {
_add_pv_to_list(head, baton.data); _add_pv_to_list(fmt->cmd, head, baton.data);
} }
} }
dev_iter_destroy(iter); dev_iter_destroy(iter);

View File

@ -20,6 +20,7 @@
#include "filter.h" #include "filter.h"
#include "xlate.h" #include "xlate.h"
#include "disk_rep.h" #include "disk_rep.h"
#include "toolcontext.h"
#include <assert.h> #include <assert.h>
@ -52,7 +53,7 @@ static int __read_pool_disk(const struct format_type *fmt, struct device *dev,
return 1; return 1;
} }
static void _add_pl_to_list(struct dm_list *head, struct pool_list *data) static void _add_pl_to_list(struct cmd_context *cmd, struct dm_list *head, struct pool_list *data)
{ {
struct pool_list *pl; struct pool_list *pl;
@ -62,14 +63,14 @@ static void _add_pl_to_list(struct dm_list *head, struct pool_list *data)
id_write_format(&pl->pv_uuid, uuid, ID_LEN + 7); id_write_format(&pl->pv_uuid, uuid, ID_LEN + 7);
if (!dev_subsystem_part_major(data->dev)) { if (!dev_subsystem_part_major(cmd->dev_types, data->dev)) {
log_very_verbose("Ignoring duplicate PV %s on " log_very_verbose("Ignoring duplicate PV %s on "
"%s", uuid, "%s", uuid,
dev_name(data->dev)); dev_name(data->dev));
return; return;
} }
log_very_verbose("Duplicate PV %s - using %s %s", log_very_verbose("Duplicate PV %s - using %s %s",
uuid, dev_subsystem_name(data->dev), uuid, dev_subsystem_name(cmd->dev_types, data->dev),
dev_name(data->dev)); dev_name(data->dev));
dm_list_del(&pl->list); dm_list_del(&pl->list);
break; break;
@ -288,7 +289,7 @@ static int _read_pool_pv(struct lvmcache_info *info, void *baton)
if (b->sp_count != b->pl->pd.pl_subpools) if (b->sp_count != b->pl->pd.pl_subpools)
return 0; return 0;
_add_pl_to_list(b->head, b->pl); _add_pl_to_list(lvmcache_fmt(info)->cmd, b->head, b->pl);
if (b->sp_count > b->pl->pd.pl_sp_id && b->sp_devs[b->pl->pd.pl_sp_id] == 0) if (b->sp_count > b->pl->pd.pl_sp_id && b->sp_devs[b->pl->pd.pl_sp_id] == 0)
b->sp_devs[b->pl->pd.pl_sp_id] = b->pl->pd.pl_sp_devs; b->sp_devs[b->pl->pd.pl_sp_id] = b->pl->pd.pl_sp_devs;

View File

@ -84,7 +84,7 @@ unsigned long set_pe_align(struct physical_volume *pv, unsigned long data_alignm
* Align to stripe-width 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_CFG)) { if (find_config_tree_bool(pv->fmt->cmd, devices_md_chunk_alignment_CFG)) {
temp_pe_align = dev_md_stripe_width(pv->dev); temp_pe_align = dev_md_stripe_width(pv->fmt->cmd->dev_types, pv->dev);
if (_alignment_overrides_default(temp_pe_align, default_pe_align)) if (_alignment_overrides_default(temp_pe_align, default_pe_align))
pv->pe_align = temp_pe_align; pv->pe_align = temp_pe_align;
} }
@ -97,11 +97,11 @@ unsigned long set_pe_align(struct physical_volume *pv, unsigned long data_alignm
* (e.g. MD's stripe width) * (e.g. MD's stripe width)
*/ */
if (find_config_tree_bool(pv->fmt->cmd, devices_data_alignment_detection_CFG)) { if (find_config_tree_bool(pv->fmt->cmd, devices_data_alignment_detection_CFG)) {
temp_pe_align = dev_minimum_io_size(pv->dev); temp_pe_align = dev_minimum_io_size(pv->fmt->cmd->dev_types, pv->dev);
if (_alignment_overrides_default(temp_pe_align, default_pe_align)) if (_alignment_overrides_default(temp_pe_align, default_pe_align))
pv->pe_align = temp_pe_align; pv->pe_align = temp_pe_align;
temp_pe_align = dev_optimal_io_size(pv->dev); temp_pe_align = dev_optimal_io_size(pv->fmt->cmd->dev_types, pv->dev);
if (_alignment_overrides_default(temp_pe_align, default_pe_align)) if (_alignment_overrides_default(temp_pe_align, default_pe_align))
pv->pe_align = temp_pe_align; pv->pe_align = temp_pe_align;
} }
@ -129,7 +129,7 @@ unsigned long set_pe_align_offset(struct physical_volume *pv,
goto out; goto out;
if (find_config_tree_bool(pv->fmt->cmd, devices_data_alignment_offset_detection_CFG)) { if (find_config_tree_bool(pv->fmt->cmd, devices_data_alignment_offset_detection_CFG)) {
int align_offset = dev_alignment_offset(pv->dev); int align_offset = dev_alignment_offset(pv->fmt->cmd->dev_types, pv->dev);
/* must handle a -1 alignment_offset; means dev is misaligned */ /* must handle a -1 alignment_offset; means dev is misaligned */
if (align_offset < 0) if (align_offset < 0)
align_offset = 0; align_offset = 0;

View File

@ -216,8 +216,8 @@ int discard_pv_segment(struct pv_segment *peg, uint32_t discard_area_reduction)
return 1; return 1;
} }
if (!dev_discard_max_bytes(peg->pv->dev) || if (!dev_discard_max_bytes(peg->pv->fmt->cmd->dev_types, peg->pv->dev) ||
!dev_discard_granularity(peg->pv->dev)) !dev_discard_granularity(peg->pv->fmt->cmd->dev_types, peg->pv->dev))
return 1; return 1;
discard_offset_sectors = (peg->pe + peg->lvseg->area_len - discard_area_reduction) * discard_offset_sectors = (peg->pe + peg->lvseg->area_len - discard_area_reduction) *