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
md_major(void)52 int md_major(void)
53 {
54 return _md_major;
55 }
56
dev_subsystem_part_major(const struct device * dev)57 int dev_subsystem_part_major(const struct device *dev)
58 {
59 return 0;
60 }
61
dev_subsystem_name(const struct device * dev)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 */
_passes_lvm_type_device_filter(struct dev_filter * f __attribute ((unused)),struct device * dev)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
_scan_dev(const struct config_node * cn)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
max_partitions(int major)237 int max_partitions(int major)
238 {
239 return _char_device_major[major];
240 }
241
lvm_type_filter_create(const char * proc,const struct config_node * cn)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
lvm_type_filter_destroy(struct dev_filter * f)264 void lvm_type_filter_destroy(struct dev_filter *f)
265 {
266 dm_free(f);
267 return;
268 }
269