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