1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-22 17:35:59 +03:00
lvm2/lib/filters/filter.c

293 lines
7.3 KiB
C
Raw Normal View History

2001-10-01 23:29:52 +04:00
/*
2004-03-30 23:35:44 +04:00
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
2001-10-01 23:29:52 +04:00
*
2004-03-30 23:35:44 +04:00
* This file is part of LVM2.
2001-10-01 23:29:52 +04:00
*
2004-03-30 23:35:44 +04:00
* 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.
2001-10-01 23:29:52 +04:00
*
* You should have received a copy of the GNU Lesser General Public License
2004-03-30 23:35:44 +04:00
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2001-10-01 23:29:52 +04:00
*/
2002-11-18 17:01:16 +03:00
#include "lib.h"
2001-10-01 23:29:52 +04:00
#include "dev-cache.h"
#include "filter.h"
#include "lvm-string.h"
#include "config.h"
#include "metadata.h"
#include "activate.h"
2001-10-01 23:29:52 +04:00
2001-10-09 21:20:02 +04:00
#include <dirent.h>
#include <unistd.h>
#include <ctype.h>
2001-10-23 16:33:57 +04:00
#include <fcntl.h>
2003-04-15 17:21:38 +04:00
#include <limits.h>
2001-10-09 21:20:02 +04:00
#define NUMBER_OF_MAJORS 4096
2001-10-09 21:20:02 +04:00
/* 0 means LVM won't use this major number. */
2004-11-23 14:44:04 +03:00
static int _max_partitions_by_major[NUMBER_OF_MAJORS];
2001-10-09 21:20:02 +04:00
typedef struct {
const char *name;
const int max_partitions;
2001-10-09 21:20:02 +04:00
} device_info_t;
static int _md_major = -1;
static int _device_mapper_major = -1;
int md_major(void)
{
return _md_major;
}
/*
* Devices are only checked for partition tables if their minor number
* is a multiple of the number corresponding to their type below
* i.e. this gives the granularity of whole-device minor numbers.
* Use 1 if the device is not partitionable.
*
* The list can be supplemented with devices/types in the config file.
*/
static const device_info_t device_info[] = {
{"ide", 64}, /* IDE disk */
2001-10-09 21:20:02 +04:00
{"sd", 16}, /* SCSI disk */
{"md", 1}, /* Multiple Disk driver (SoftRAID) */
{"loop", 1}, /* Loop device */
2001-10-09 21:20:02 +04:00
{"dasd", 4}, /* DASD disk (IBM S/390, zSeries) */
{"dac960", 8}, /* DAC960 */
{"nbd", 16}, /* Network Block Device */
{"ida", 16}, /* Compaq SMART2 */
{"cciss", 16}, /* Compaq CCISS array */
{"ubd", 16}, /* User-mode virtual block device */
{"ataraid", 16}, /* ATA Raid */
2003-11-06 20:10:35 +03:00
{"drbd", 16}, /* Distributed Replicated Block Device */
{"emcpower", 16}, /* EMC Powerpath */
2004-04-14 21:33:51 +04:00
{"power2", 16}, /* EMC Powerpath */
2004-06-01 22:33:50 +04:00
{"i2o_block", 16}, /* i2o Block Disk */
2004-08-18 23:13:01 +04:00
{"iseries/vd", 8}, /* iSeries disks */
2005-01-19 21:56:01 +03:00
{"gnbd", 1}, /* Network block device */
2005-04-06 20:43:59 +04:00
{"ramdisk", 1}, /* RAM disk */
2005-08-08 21:54:23 +04:00
{"aoe", 16}, /* ATA over Ethernet */
{"device-mapper", 1}, /* Other mapped devices */
2005-11-09 15:47:16 +03:00
{"xvd", 16}, /* Xen virtual block device */
{"vdisk", 8}, /* SUN's LDOM virtual block device */
2007-07-26 17:28:32 +04:00
{"ps3disk", 16}, /* PlayStation 3 internal disk */
2008-04-03 14:29:00 +04:00
{"virtblk", 8}, /* VirtIO disk */
2001-10-09 21:20:02 +04:00
{NULL, 0}
};
static int _passes_lvm_type_device_filter(struct dev_filter *f __attribute((unused)),
struct device *dev)
2001-10-01 23:29:52 +04:00
{
const char *name = dev_name(dev);
int ret = 0;
uint64_t size;
2001-10-23 16:33:57 +04:00
2001-10-09 21:20:02 +04:00
/* Is this a recognised device type? */
2004-11-23 14:44:04 +03:00
if (!_max_partitions_by_major[MAJOR(dev->dev)]) {
log_debug("%s: Skipping: Unrecognised LVM device type %"
PRIu64, name, (uint64_t) MAJOR(dev->dev));
2001-10-09 21:20:02 +04:00
return 0;
}
2001-10-23 16:33:57 +04:00
/* Skip suspended devices */
if (MAJOR(dev->dev) == _device_mapper_major &&
2007-01-26 02:03:48 +03:00
ignore_suspended_devices() && !device_is_usable(dev->dev)) {
log_debug("%s: Skipping: Suspended dm device", name);
return 0;
}
2001-10-23 16:33:57 +04:00
/* Check it's accessible */
if (!dev_open_flags(dev, O_RDONLY, 0, 1)) {
2004-11-23 14:44:04 +03:00
log_debug("%s: Skipping: open failed", name);
2001-10-23 16:33:57 +04:00
return 0;
}
2004-11-23 14:44:04 +03:00
/* Check it's not too small */
if (!dev_get_size(dev, &size)) {
log_debug("%s: Skipping: dev_get_size failed", name);
goto out;
}
if (size < PV_MIN_SIZE) {
log_debug("%s: Skipping: Too small to hold a PV", name);
goto out;
}
2004-11-23 14:44:04 +03:00
if (is_partitioned_dev(dev)) {
log_debug("%s: Skipping: Partition table signature found",
2004-11-23 14:44:04 +03:00
name);
goto out;
2004-11-23 14:44:04 +03:00
}
2001-10-23 16:33:57 +04:00
ret = 1;
out:
2004-11-23 14:44:04 +03:00
dev_close(dev);
2001-10-23 16:33:57 +04:00
2004-11-23 14:44:04 +03:00
return ret;
2001-10-01 23:29:52 +04:00
}
2004-11-23 14:44:04 +03:00
static int _scan_proc_dev(const char *proc, const struct config_node *cn)
2001-10-09 21:20:02 +04:00
{
char line[80];
char proc_devices[PATH_MAX];
FILE *pd = NULL;
2001-10-09 21:20:02 +04:00
int i, j = 0;
int line_maj = 0;
int blocksection = 0;
size_t dev_len = 0;
struct config_value *cv;
char *name;
2001-10-09 21:20:02 +04:00
2003-04-15 17:21:38 +04:00
if (!*proc) {
log_verbose("No proc filesystem found: using all block device "
"types");
for (i = 0; i < NUMBER_OF_MAJORS; i++)
2004-11-23 14:44:04 +03:00
_max_partitions_by_major[i] = 1;
return 1;
2003-04-15 17:21:38 +04:00
}
/* All types unrecognised initially */
2004-11-23 14:44:04 +03:00
memset(_max_partitions_by_major, 0, sizeof(int) * NUMBER_OF_MAJORS);
2006-08-21 16:54:53 +04:00
if (dm_snprintf(proc_devices, sizeof(proc_devices),
"%s/devices", proc) < 0) {
log_error("Failed to create /proc/devices string");
2004-11-23 14:44:04 +03:00
return 0;
}
if (!(pd = fopen(proc_devices, "r"))) {
log_sys_error("fopen", proc_devices);
2004-11-23 14:44:04 +03:00
return 0;
2001-10-09 21:20:02 +04:00
}
while (fgets(line, 80, pd) != NULL) {
2001-10-09 21:20:02 +04:00
i = 0;
while (line[i] == ' ' && line[i] != '\0')
i++;
/* If it's not a number it may be name of section */
line_maj = atoi(((char *) (line + i)));
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] == ' ' && line[i] != '\0')
i++;
/* Look for md device */
if (!strncmp("md", line + i, 2) && isspace(*(line + i + 2)))
_md_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;
2001-10-09 21:20:02 +04:00
/* Go through the valid device names and if there is a
match store max number of partitions */
2001-10-09 21:20:02 +04:00
for (j = 0; device_info[j].name != NULL; 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)) {
2004-11-23 14:44:04 +03:00
_max_partitions_by_major[line_maj] =
2001-10-09 21:20:02 +04:00
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 != CFG_STRING) {
log_error("Expecting string in devices/types "
"in config file");
if (fclose(pd))
log_sys_error("fclose", proc_devices);
2004-11-23 14:44:04 +03:00
return 0;
}
dev_len = strlen(cv->v.str);
name = cv->v.str;
cv = cv->next;
if (!cv || cv->type != 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);
2004-11-23 14:44:04 +03:00
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);
2004-11-23 14:44:04 +03:00
return 0;
}
if (dev_len <= strlen(line + i) &&
!strncmp(name, line + i, dev_len) &&
(line_maj < NUMBER_OF_MAJORS)) {
2004-11-23 14:44:04 +03:00
_max_partitions_by_major[line_maj] = cv->v.i;
2001-10-09 21:20:02 +04:00
break;
}
}
}
if (fclose(pd))
log_sys_error("fclose", proc_devices);
2004-11-23 14:44:04 +03:00
return 1;
}
int max_partitions(int major)
{
return _max_partitions_by_major[major];
2001-10-09 21:20:02 +04:00
}
struct dev_filter *lvm_type_filter_create(const char *proc,
2004-05-04 22:28:15 +04:00
const struct config_node *cn)
{
struct dev_filter *f;
if (!(f = dm_malloc(sizeof(struct dev_filter)))) {
log_error("LVM type filter allocation failed");
return NULL;
}
f->passes_filter = _passes_lvm_type_device_filter;
f->destroy = lvm_type_filter_destroy;
2004-11-23 14:44:04 +03:00
f->private = NULL;
2004-11-23 14:44:04 +03:00
if (!_scan_proc_dev(proc, cn)) {
dm_free(f);
2008-01-30 16:19:47 +03:00
return_NULL;
}
return f;
}
void lvm_type_filter_destroy(struct dev_filter *f)
{
dm_free(f);
return;
}