1 /* $NetBSD: filter.c,v 1.1.1.2 2009/12/02 00:26:47 haad Exp $ */ 2 3 /* 4 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. 5 * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. 6 * 7 * This file is part of LVM2. 8 * 9 * This copyrighted material is made available to anyone wishing to use, 10 * modify, copy, or redistribute it subject to the terms and conditions 11 * of the GNU Lesser General Public License v.2.1. 12 * 13 * You should have received a copy of the GNU Lesser General Public License 14 * along with this program; if not, write to the Free Software Foundation, 15 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 16 */ 17 18 #include "lib.h" 19 #include "dev-cache.h" 20 #include "filter.h" 21 #include "lvm-string.h" 22 #include "config.h" 23 #include "metadata.h" 24 #include "activate.h" 25 26 #include <dirent.h> 27 #include <unistd.h> 28 #include <ctype.h> 29 #include <fcntl.h> 30 #include <limits.h> 31 32 #define NUMBER_OF_MAJORS 4096 33 34 /* 0 means LVM won't use this major number. */ 35 static int _max_partitions_by_major[NUMBER_OF_MAJORS]; 36 37 typedef struct { 38 const char *name; 39 const int max_partitions; 40 } device_info_t; 41 42 static int _md_major = -1; 43 static int _blkext_major = -1; 44 static int _drbd_major = -1; 45 static int _device_mapper_major = -1; 46 47 int md_major(void) 48 { 49 return _md_major; 50 } 51 52 int blkext_major(void) 53 { 54 return _blkext_major; 55 } 56 57 int dev_subsystem_part_major(const struct device *dev) 58 { 59 if (MAJOR(dev->dev) == -1) 60 return 0; 61 62 if (MAJOR(dev->dev) == _md_major) 63 return 1; 64 65 if (MAJOR(dev->dev) == _drbd_major) 66 return 1; 67 68 return 0; 69 } 70 71 const char *dev_subsystem_name(const struct device *dev) 72 { 73 if (MAJOR(dev->dev) == _md_major) 74 return "MD"; 75 76 if (MAJOR(dev->dev) == _drbd_major) 77 return "DRBD"; 78 79 return ""; 80 } 81 82 /* 83 * Devices are only checked for partition tables if their minor number 84 * is a multiple of the number corresponding to their type below 85 * i.e. this gives the granularity of whole-device minor numbers. 86 * Use 1 if the device is not partitionable. 87 * 88 * The list can be supplemented with devices/types in the config file. 89 */ 90 static const device_info_t device_info[] = { 91 {"ide", 64}, /* IDE disk */ 92 {"sd", 16}, /* SCSI disk */ 93 {"md", 1}, /* Multiple Disk driver (SoftRAID) */ 94 {"mdp", 1}, /* Partitionable MD */ 95 {"loop", 1}, /* Loop device */ 96 {"dasd", 4}, /* DASD disk (IBM S/390, zSeries) */ 97 {"dac960", 8}, /* DAC960 */ 98 {"nbd", 16}, /* Network Block Device */ 99 {"ida", 16}, /* Compaq SMART2 */ 100 {"cciss", 16}, /* Compaq CCISS array */ 101 {"ubd", 16}, /* User-mode virtual block device */ 102 {"ataraid", 16}, /* ATA Raid */ 103 {"drbd", 16}, /* Distributed Replicated Block Device */ 104 {"emcpower", 16}, /* EMC Powerpath */ 105 {"power2", 16}, /* EMC Powerpath */ 106 {"i2o_block", 16}, /* i2o Block Disk */ 107 {"iseries/vd", 8}, /* iSeries disks */ 108 {"gnbd", 1}, /* Network block device */ 109 {"ramdisk", 1}, /* RAM disk */ 110 {"aoe", 16}, /* ATA over Ethernet */ 111 {"device-mapper", 1}, /* Other mapped devices */ 112 {"xvd", 16}, /* Xen virtual block device */ 113 {"vdisk", 8}, /* SUN's LDOM virtual block device */ 114 {"ps3disk", 16}, /* PlayStation 3 internal disk */ 115 {"virtblk", 8}, /* VirtIO disk */ 116 {"mmc", 16}, /* MMC block device */ 117 {"blkext", 1}, /* Extended device partitions */ 118 {NULL, 0} 119 }; 120 121 static int _passes_lvm_type_device_filter(struct dev_filter *f __attribute((unused)), 122 struct device *dev) 123 { 124 const char *name = dev_name(dev); 125 int ret = 0; 126 uint64_t size; 127 128 /* Is this a recognised device type? */ 129 if (!_max_partitions_by_major[MAJOR(dev->dev)]) { 130 log_debug("%s: Skipping: Unrecognised LVM device type %" 131 PRIu64, name, (uint64_t) MAJOR(dev->dev)); 132 return 0; 133 } 134 135 /* Skip suspended devices */ 136 if (MAJOR(dev->dev) == _device_mapper_major && 137 ignore_suspended_devices() && !device_is_usable(dev->dev)) { 138 log_debug("%s: Skipping: Suspended dm device", name); 139 return 0; 140 } 141 142 /* Check it's accessible */ 143 if (!dev_open_flags(dev, O_RDONLY, 0, 1)) { 144 log_debug("%s: Skipping: open failed", name); 145 return 0; 146 } 147 148 /* Check it's not too small */ 149 if (!dev_get_size(dev, &size)) { 150 log_debug("%s: Skipping: dev_get_size failed", name); 151 goto out; 152 } 153 154 if (size < PV_MIN_SIZE) { 155 log_debug("%s: Skipping: Too small to hold a PV", name); 156 goto out; 157 } 158 159 if (is_partitioned_dev(dev)) { 160 log_debug("%s: Skipping: Partition table signature found", 161 name); 162 goto out; 163 } 164 165 ret = 1; 166 167 out: 168 dev_close(dev); 169 170 return ret; 171 } 172 173 static int _scan_proc_dev(const char *proc, const struct config_node *cn) 174 { 175 char line[80]; 176 char proc_devices[PATH_MAX]; 177 FILE *pd = NULL; 178 int i, j = 0; 179 int line_maj = 0; 180 int blocksection = 0; 181 size_t dev_len = 0; 182 struct config_value *cv; 183 char *name; 184 185 186 if (!*proc) { 187 log_verbose("No proc filesystem found: using all block device " 188 "types"); 189 for (i = 0; i < NUMBER_OF_MAJORS; i++) 190 _max_partitions_by_major[i] = 1; 191 return 1; 192 } 193 194 /* All types unrecognised initially */ 195 memset(_max_partitions_by_major, 0, sizeof(int) * NUMBER_OF_MAJORS); 196 197 if (dm_snprintf(proc_devices, sizeof(proc_devices), 198 "%s/devices", proc) < 0) { 199 log_error("Failed to create /proc/devices string"); 200 return 0; 201 } 202 203 if (!(pd = fopen(proc_devices, "r"))) { 204 log_sys_error("fopen", proc_devices); 205 return 0; 206 } 207 208 while (fgets(line, 80, pd) != NULL) { 209 i = 0; 210 while (line[i] == ' ' && line[i] != '\0') 211 i++; 212 213 /* If it's not a number it may be name of section */ 214 line_maj = atoi(((char *) (line + i))); 215 if (!line_maj) { 216 blocksection = (line[i] == 'B') ? 1 : 0; 217 continue; 218 } 219 220 /* We only want block devices ... */ 221 if (!blocksection) 222 continue; 223 224 /* Find the start of the device major name */ 225 while (line[i] != ' ' && line[i] != '\0') 226 i++; 227 while (line[i] == ' ' && line[i] != '\0') 228 i++; 229 230 /* Look for md device */ 231 if (!strncmp("md", line + i, 2) && isspace(*(line + i + 2))) 232 _md_major = line_maj; 233 234 /* Look for blkext device */ 235 if (!strncmp("blkext", line + i, 6) && isspace(*(line + i + 6))) 236 _blkext_major = line_maj; 237 238 /* Look for drbd device */ 239 if (!strncmp("drbd", line + i, 4) && isspace(*(line + i + 4))) 240 _drbd_major = line_maj; 241 242 /* Look for device-mapper device */ 243 /* FIXME Cope with multiple majors */ 244 if (!strncmp("device-mapper", line + i, 13) && isspace(*(line + i + 13))) 245 _device_mapper_major = line_maj; 246 247 /* Go through the valid device names and if there is a 248 match store max number of partitions */ 249 for (j = 0; device_info[j].name != NULL; j++) { 250 dev_len = strlen(device_info[j].name); 251 if (dev_len <= strlen(line + i) && 252 !strncmp(device_info[j].name, line + i, dev_len) && 253 (line_maj < NUMBER_OF_MAJORS)) { 254 _max_partitions_by_major[line_maj] = 255 device_info[j].max_partitions; 256 break; 257 } 258 } 259 260 if (!cn) 261 continue; 262 263 /* Check devices/types for local variations */ 264 for (cv = cn->v; cv; cv = cv->next) { 265 if (cv->type != CFG_STRING) { 266 log_error("Expecting string in devices/types " 267 "in config file"); 268 if (fclose(pd)) 269 log_sys_error("fclose", proc_devices); 270 return 0; 271 } 272 dev_len = strlen(cv->v.str); 273 name = cv->v.str; 274 cv = cv->next; 275 if (!cv || cv->type != CFG_INT) { 276 log_error("Max partition count missing for %s " 277 "in devices/types in config file", 278 name); 279 if (fclose(pd)) 280 log_sys_error("fclose", proc_devices); 281 return 0; 282 } 283 if (!cv->v.i) { 284 log_error("Zero partition count invalid for " 285 "%s in devices/types in config file", 286 name); 287 if (fclose(pd)) 288 log_sys_error("fclose", proc_devices); 289 return 0; 290 } 291 if (dev_len <= strlen(line + i) && 292 !strncmp(name, line + i, dev_len) && 293 (line_maj < NUMBER_OF_MAJORS)) { 294 _max_partitions_by_major[line_maj] = cv->v.i; 295 break; 296 } 297 } 298 } 299 300 if (fclose(pd)) 301 log_sys_error("fclose", proc_devices); 302 303 return 1; 304 } 305 306 int max_partitions(int major) 307 { 308 return _max_partitions_by_major[major]; 309 } 310 311 struct dev_filter *lvm_type_filter_create(const char *proc, 312 const struct config_node *cn) 313 { 314 struct dev_filter *f; 315 316 if (!(f = dm_malloc(sizeof(struct dev_filter)))) { 317 log_error("LVM type filter allocation failed"); 318 return NULL; 319 } 320 321 f->passes_filter = _passes_lvm_type_device_filter; 322 f->destroy = lvm_type_filter_destroy; 323 f->private = NULL; 324 325 if (!_scan_proc_dev(proc, cn)) { 326 dm_free(f); 327 return_NULL; 328 } 329 330 return f; 331 } 332 333 void lvm_type_filter_destroy(struct dev_filter *f) 334 { 335 dm_free(f); 336 return; 337 } 338