2 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
3 * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
5 * This file is part of LVM2.
7 * This copyrighted material is made available to anyone wishing to use,
8 * modify, copy, or redistribute it subject to the terms and conditions
9 * of the GNU Lesser General Public License v.2.1.
11 * You should have received a copy of the GNU Lesser General Public License
12 * along with this program; if not, write to the Free Software Foundation,
13 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 #include "dev-cache.h"
19 #include "lvm-string.h"
30 #define NUMBER_OF_MAJORS 4096
32 /* 0 means LVM won't use this major number. */
33 static int _max_partitions_by_major[NUMBER_OF_MAJORS];
37 const int max_partitions;
40 static int _md_major = -1;
41 static int _blkext_major = -1;
42 static int _drbd_major = -1;
43 static int _device_mapper_major = -1;
47 return _device_mapper_major;
55 int blkext_major(void)
60 int dev_subsystem_part_major(const struct device *dev)
64 if (MAJOR(dev->dev) == -1)
67 if (MAJOR(dev->dev) == _md_major)
70 if (MAJOR(dev->dev) == _drbd_major)
73 if ((MAJOR(dev->dev) == _blkext_major) &&
74 (get_primary_dev(sysfs_dir_path(), dev, &primary_dev)) &&
75 (MAJOR(primary_dev) == _md_major))
81 const char *dev_subsystem_name(const struct device *dev)
83 if (MAJOR(dev->dev) == _md_major)
86 if (MAJOR(dev->dev) == _drbd_major)
89 if (MAJOR(dev->dev) == _blkext_major)
96 * Devices are only checked for partition tables if their minor number
97 * is a multiple of the number corresponding to their type below
98 * i.e. this gives the granularity of whole-device minor numbers.
99 * Use 1 if the device is not partitionable.
101 * The list can be supplemented with devices/types in the config file.
103 static const device_info_t device_info[] = {
104 {"ide", 64}, /* IDE disk */
105 {"sd", 16}, /* SCSI disk */
106 {"md", 1}, /* Multiple Disk driver (SoftRAID) */
107 {"mdp", 1}, /* Partitionable MD */
108 {"loop", 1}, /* Loop device */
109 {"dasd", 4}, /* DASD disk (IBM S/390, zSeries) */
110 {"dac960", 8}, /* DAC960 */
111 {"nbd", 16}, /* Network Block Device */
112 {"ida", 16}, /* Compaq SMART2 */
113 {"cciss", 16}, /* Compaq CCISS array */
114 {"ubd", 16}, /* User-mode virtual block device */
115 {"ataraid", 16}, /* ATA Raid */
116 {"drbd", 16}, /* Distributed Replicated Block Device */
117 {"emcpower", 16}, /* EMC Powerpath */
118 {"power2", 16}, /* EMC Powerpath */
119 {"i2o_block", 16}, /* i2o Block Disk */
120 {"iseries/vd", 8}, /* iSeries disks */
121 {"gnbd", 1}, /* Network block device */
122 {"ramdisk", 1}, /* RAM disk */
123 {"aoe", 16}, /* ATA over Ethernet */
124 {"device-mapper", 1}, /* Other mapped devices */
125 {"xvd", 16}, /* Xen virtual block device */
126 {"vdisk", 8}, /* SUN's LDOM virtual block device */
127 {"ps3disk", 16}, /* PlayStation 3 internal disk */
128 {"virtblk", 8}, /* VirtIO disk */
129 {"mmc", 16}, /* MMC block device */
130 {"blkext", 1}, /* Extended device partitions */
134 static int _passes_lvm_type_device_filter(struct dev_filter *f __attribute__((unused)),
137 const char *name = dev_name(dev);
141 /* Is this a recognised device type? */
142 if (!_max_partitions_by_major[MAJOR(dev->dev)]) {
143 log_debug("%s: Skipping: Unrecognised LVM device type %"
144 PRIu64, name, (uint64_t) MAJOR(dev->dev));
148 /* Check it's accessible */
149 if (!dev_open_flags(dev, O_RDONLY, 0, 1)) {
150 log_debug("%s: Skipping: open failed", name);
154 /* Check it's not too small */
155 if (!dev_get_size(dev, &size)) {
156 log_debug("%s: Skipping: dev_get_size failed", name);
160 if (size < PV_MIN_SIZE) {
161 log_debug("%s: Skipping: Too small to hold a PV", name);
165 if (is_partitioned_dev(dev)) {
166 log_debug("%s: Skipping: Partition table signature found",
179 static int _scan_proc_dev(const char *proc, const struct config_node *cn)
182 char proc_devices[PATH_MAX];
186 int blocksection = 0;
188 const struct config_value *cv;
193 log_verbose("No proc filesystem found: using all block device "
195 for (i = 0; i < NUMBER_OF_MAJORS; i++)
196 _max_partitions_by_major[i] = 1;
200 /* All types unrecognised initially */
201 memset(_max_partitions_by_major, 0, sizeof(int) * NUMBER_OF_MAJORS);
203 if (dm_snprintf(proc_devices, sizeof(proc_devices),
204 "%s/devices", proc) < 0) {
205 log_error("Failed to create /proc/devices string");
209 if (!(pd = fopen(proc_devices, "r"))) {
210 log_sys_error("fopen", proc_devices);
214 while (fgets(line, 80, pd) != NULL) {
216 while (line[i] == ' ' && line[i] != '\0')
219 /* If it's not a number it may be name of section */
220 line_maj = atoi(((char *) (line + i)));
222 blocksection = (line[i] == 'B') ? 1 : 0;
226 /* We only want block devices ... */
230 /* Find the start of the device major name */
231 while (line[i] != ' ' && line[i] != '\0')
233 while (line[i] == ' ' && line[i] != '\0')
236 /* Look for md device */
237 if (!strncmp("md", line + i, 2) && isspace(*(line + i + 2)))
238 _md_major = line_maj;
240 /* Look for blkext device */
241 if (!strncmp("blkext", line + i, 6) && isspace(*(line + i + 6)))
242 _blkext_major = line_maj;
244 /* Look for drbd device */
245 if (!strncmp("drbd", line + i, 4) && isspace(*(line + i + 4)))
246 _drbd_major = line_maj;
248 /* Look for device-mapper device */
249 /* FIXME Cope with multiple majors */
250 if (!strncmp("device-mapper", line + i, 13) && isspace(*(line + i + 13)))
251 _device_mapper_major = line_maj;
253 /* Go through the valid device names and if there is a
254 match store max number of partitions */
255 for (j = 0; device_info[j].name != NULL; j++) {
256 dev_len = strlen(device_info[j].name);
257 if (dev_len <= strlen(line + i) &&
258 !strncmp(device_info[j].name, line + i, dev_len) &&
259 (line_maj < NUMBER_OF_MAJORS)) {
260 _max_partitions_by_major[line_maj] =
261 device_info[j].max_partitions;
269 /* Check devices/types for local variations */
270 for (cv = cn->v; cv; cv = cv->next) {
271 if (cv->type != CFG_STRING) {
272 log_error("Expecting string in devices/types "
275 log_sys_error("fclose", proc_devices);
278 dev_len = strlen(cv->v.str);
281 if (!cv || cv->type != CFG_INT) {
282 log_error("Max partition count missing for %s "
283 "in devices/types in config file",
286 log_sys_error("fclose", proc_devices);
290 log_error("Zero partition count invalid for "
291 "%s in devices/types in config file",
294 log_sys_error("fclose", proc_devices);
297 if (dev_len <= strlen(line + i) &&
298 !strncmp(name, line + i, dev_len) &&
299 (line_maj < NUMBER_OF_MAJORS)) {
300 _max_partitions_by_major[line_maj] = cv->v.i;
307 log_sys_error("fclose", proc_devices);
312 int max_partitions(int major)
314 return _max_partitions_by_major[major];
317 struct dev_filter *lvm_type_filter_create(const char *proc,
318 const struct config_node *cn)
320 struct dev_filter *f;
322 if (!(f = dm_malloc(sizeof(struct dev_filter)))) {
323 log_error("LVM type filter allocation failed");
327 f->passes_filter = _passes_lvm_type_device_filter;
328 f->destroy = lvm_type_filter_destroy;
332 if (!_scan_proc_dev(proc, cn)) {
340 void lvm_type_filter_destroy(struct dev_filter *f)
343 log_error(INTERNAL_ERROR "Destroying lvm_type filter while in use %u times.", f->use_count);