1 /* $NetBSD: filter_netbsd.c,v 1.3 2009/12/02 01:53:25 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 * Copyright (C) 2008 Adam Hamsik. All rights reserved. 7 * 8 * This file is part of LVM2. 9 * 10 * This copyrighted material is made available to anyone wishing to use, 11 * modify, copy, or redistribute it subject to the terms and conditions 12 * of the GNU Lesser General Public License v.2.1. 13 * 14 * You should have received a copy of the GNU Lesser General Public License 15 * along with this program; if not, write to the Free Software Foundation, 16 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 */ 18 19 #include "lib.h" 20 #include "dev-cache.h" 21 #include "filter.h" 22 #include "lvm-string.h" 23 #include "config.h" 24 #include "metadata.h" 25 #include "activate.h" 26 27 #include <sys/sysctl.h> 28 29 #include <ctype.h> 30 #include <dirent.h> 31 #include <fcntl.h> 32 #include <limits.h> 33 #include <unistd.h> 34 35 #define NUMBER_OF_MAJORS 4096 36 37 #define LVM_SUCCESS 1 38 #define LVM_FAILURE 0 39 40 /* -1 means LVM won't use this major number. */ 41 static int _char_device_major[NUMBER_OF_MAJORS]; 42 static int _block_device_major[NUMBER_OF_MAJORS]; 43 44 typedef struct { 45 const char *name; 46 const int max_partitions; 47 } device_info_t; 48 49 static int _md_major = -1; 50 static int _device_mapper_major = -1; 51 52 int md_major(void) 53 { 54 return _md_major; 55 } 56 57 int dev_subsystem_part_major(const struct device *dev) 58 { 59 return 0; 60 } 61 62 const char *dev_subsystem_name(const struct device *dev) 63 { 64 return ""; 65 } 66 67 /* 68 * Devices are only checked for partition tables if their minor number 69 * is a multiple of the number corresponding to their type below 70 * i.e. this gives the granularity of whole-device minor numbers. 71 * Use 1 if the device is not partitionable. 72 * 73 * The list can be supplemented with devices/types in the config file. 74 */ 75 static const device_info_t device_info[] = { 76 {"wd", 64}, 77 {"sd", 64}, 78 {"dk", 1}, 79 {"wd", 64}, 80 {"vnd", 1}, 81 {"raid", 64}, 82 {"cgd", 1}, 83 {"ccd", 1}, 84 {"xbd", 64}, 85 {NULL, -1} 86 }; 87 88 /* 89 * Test if device passes filter tests and can be inserted in to cache. 90 */ 91 static int _passes_lvm_type_device_filter(struct dev_filter *f __attribute((unused)), 92 struct device *dev) 93 { 94 const char *name = dev_name(dev); 95 int ret = 0; 96 uint64_t size; 97 98 /* Is this a recognised device type? */ 99 if (_char_device_major[MAJOR(dev->dev)] == -1 ){ 100 log_debug("%s: Skipping: Unrecognised LVM device type %" 101 PRIu64, name, (uint64_t) MAJOR(dev->dev)); 102 return LVM_FAILURE; 103 } 104 105 /* Skip suspended devices */ 106 if (MAJOR(dev->dev) == _device_mapper_major && 107 ignore_suspended_devices() && !device_is_usable(dev->dev)) { 108 log_debug("%s: Skipping: Suspended dm device", name); 109 return LVM_FAILURE; 110 } 111 112 /* Check it's accessible */ 113 if (!dev_open_flags(dev, O_RDONLY, 0, 1)) { 114 log_debug("%s: Skipping: open failed", name); 115 return LVM_FAILURE; 116 } 117 118 /* Check it's not too small */ 119 if (!dev_get_size(dev, &size)) { 120 log_debug("%s: Skipping: dev_get_size failed", name); 121 goto out; 122 } 123 124 if (size < PV_MIN_SIZE) { 125 log_debug("%s: Skipping: Too small to hold a PV", name); 126 goto out; 127 } 128 129 if (is_partitioned_dev(dev)) { 130 log_debug("%s: Skipping: Partition table signature found", 131 name); 132 goto out; 133 } 134 135 ret = LVM_SUCCESS; 136 137 out: 138 dev_close(dev); 139 140 return ret; 141 } 142 143 static int _scan_dev(const struct config_node *cn) 144 { 145 size_t val_len,i,j; 146 char *name; 147 148 struct kinfo_drivers *kd; 149 struct config_value *cv; 150 151 /* All types unrecognised initially */ 152 memset(_char_device_major, -1, sizeof(int) * NUMBER_OF_MAJORS); 153 memset(_block_device_major, -1, sizeof(int) * NUMBER_OF_MAJORS); 154 155 /* get size kernel drivers array from kernel*/ 156 if (sysctlbyname("kern.drivers", NULL, &val_len, NULL, 0) < 0) { 157 printf("sysctlbyname failed"); 158 return LVM_FAILURE; 159 } 160 161 if ((kd = malloc(val_len)) == NULL){ 162 printf("malloc kd info error\n"); 163 return LVM_FAILURE; 164 } 165 166 /* get array from kernel */ 167 if (sysctlbyname("kern.drivers", kd, &val_len, NULL, 0) < 0) { 168 printf("sysctlbyname failed kd"); 169 return LVM_FAILURE; 170 } 171 172 for (i = 0, val_len /= sizeof(*kd); i < val_len; i++) { 173 174 if (!strncmp("device-mapper", kd[i].d_name, 13) || 175 !strncmp("dm", kd[i].d_name, 2)) 176 _device_mapper_major = kd[i].d_bmajor; 177 178 /* We select only devices with correct char/block major number. */ 179 if (kd[i].d_cmajor != -1 && kd[i].d_bmajor != -1) { 180 /* Go through the valid device names and if there is a 181 match store max number of partitions */ 182 for (j = 0; device_info[j].name != NULL; j++){ 183 if (!strcmp(device_info[j].name, kd[i].d_name)){ 184 _char_device_major[kd[i].d_cmajor] = 185 device_info[j].max_partitions; 186 _block_device_major[kd[i].d_bmajor] = 187 device_info[j].max_partitions; 188 break; 189 } 190 } 191 } 192 193 if (!cn) 194 continue; 195 196 /* Check devices/types for local variations */ 197 for (cv = cn->v; cv; cv = cv->next) { 198 if (cv->type != CFG_STRING) { 199 log_error("Expecting string in devices/types " 200 "in config file"); 201 free(kd); 202 return LVM_FAILURE; 203 } 204 205 name = cv->v.str; 206 cv = cv->next; 207 if (!cv || cv->type != CFG_INT) { 208 log_error("Max partition count missing for %s " 209 "in devices/types in config file", 210 name); 211 free(kd); 212 return LVM_FAILURE; 213 } 214 if (!cv->v.i) { 215 log_error("Zero partition count invalid for " 216 "%s in devices/types in config file", 217 name); 218 free(kd); 219 return LVM_FAILURE; 220 } 221 222 if (!strncmp(name, kd[i].d_name, strlen(name))){ 223 _char_device_major[kd[i].d_cmajor] = 224 device_info[j].max_partitions; 225 _block_device_major[kd[i].d_bmajor] = 226 device_info[j].max_partitions; 227 break; 228 } 229 } 230 } 231 232 free(kd); 233 234 return LVM_SUCCESS; 235 } 236 237 int max_partitions(int major) 238 { 239 return _char_device_major[major]; 240 } 241 242 struct dev_filter *lvm_type_filter_create(const char *proc, 243 const struct config_node *cn) 244 { 245 struct dev_filter *f; 246 247 if (!(f = dm_malloc(sizeof(struct dev_filter)))) { 248 log_error("LVM type filter allocation failed"); 249 return NULL; 250 } 251 252 f->passes_filter = _passes_lvm_type_device_filter; 253 f->destroy = lvm_type_filter_destroy; 254 f->private = NULL; 255 256 if (!_scan_dev(cn)) { 257 dm_free(f); 258 return_NULL; 259 } 260 261 return f; 262 } 263 264 void lvm_type_filter_destroy(struct dev_filter *f) 265 { 266 dm_free(f); 267 return; 268 } 269