Tizen 2.1 base
[external/device-mapper.git] / lib / filters / filter.c
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 int dm_major(void)
46 {
47         return _device_mapper_major;
48 }
49
50 int md_major(void)
51 {
52         return _md_major;
53 }
54
55 int blkext_major(void)
56 {
57         return _blkext_major;
58 }
59
60 int dev_subsystem_part_major(const struct device *dev)
61 {
62         dev_t primary_dev;
63
64         if (MAJOR(dev->dev) == -1)
65                 return 0;
66
67         if (MAJOR(dev->dev) == _md_major)
68                 return 1;
69
70         if (MAJOR(dev->dev) == _drbd_major)
71                 return 1;
72
73         if ((MAJOR(dev->dev) == _blkext_major) &&
74             (get_primary_dev(sysfs_dir_path(), dev, &primary_dev)) &&
75             (MAJOR(primary_dev) == _md_major))
76                 return 1;
77
78         return 0;
79 }
80
81 const char *dev_subsystem_name(const struct device *dev)
82 {
83         if (MAJOR(dev->dev) == _md_major)
84                 return "MD";
85
86         if (MAJOR(dev->dev) == _drbd_major)
87                 return "DRBD";
88
89         if (MAJOR(dev->dev) == _blkext_major)
90                 return "BLKEXT";
91
92         return "";
93 }
94
95 /*
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.
100  *
101  * The list can be supplemented with devices/types in the config file.
102  */
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 */
131         {NULL, 0}
132 };
133
134 static int _passes_lvm_type_device_filter(struct dev_filter *f __attribute__((unused)),
135                                           struct device *dev)
136 {
137         const char *name = dev_name(dev);
138         int ret = 0;
139         uint64_t size;
140
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));
145                 return 0;
146         }
147
148         /* Check it's accessible */
149         if (!dev_open_flags(dev, O_RDONLY, 0, 1)) {
150                 log_debug("%s: Skipping: open failed", name);
151                 return 0;
152         }
153         
154         /* Check it's not too small */
155         if (!dev_get_size(dev, &size)) {
156                 log_debug("%s: Skipping: dev_get_size failed", name);
157                 goto out;
158         }
159
160         if (size < PV_MIN_SIZE) {
161                 log_debug("%s: Skipping: Too small to hold a PV", name);
162                 goto out;
163         }
164
165         if (is_partitioned_dev(dev)) {
166                 log_debug("%s: Skipping: Partition table signature found",
167                           name);
168                 goto out;
169         }
170
171         ret = 1;
172
173       out:
174         dev_close(dev);
175
176         return ret;
177 }
178
179 static int _scan_proc_dev(const char *proc, const struct config_node *cn)
180 {
181         char line[80];
182         char proc_devices[PATH_MAX];
183         FILE *pd = NULL;
184         int i, j = 0;
185         int line_maj = 0;
186         int blocksection = 0;
187         size_t dev_len = 0;
188         const struct config_value *cv;
189         const char *name;
190
191
192         if (!*proc) {
193                 log_verbose("No proc filesystem found: using all block device "
194                             "types");
195                 for (i = 0; i < NUMBER_OF_MAJORS; i++)
196                         _max_partitions_by_major[i] = 1;
197                 return 1;
198         }
199
200         /* All types unrecognised initially */
201         memset(_max_partitions_by_major, 0, sizeof(int) * NUMBER_OF_MAJORS);
202
203         if (dm_snprintf(proc_devices, sizeof(proc_devices),
204                          "%s/devices", proc) < 0) {
205                 log_error("Failed to create /proc/devices string");
206                 return 0;
207         }
208
209         if (!(pd = fopen(proc_devices, "r"))) {
210                 log_sys_error("fopen", proc_devices);
211                 return 0;
212         }
213
214         while (fgets(line, 80, pd) != NULL) {
215                 i = 0;
216                 while (line[i] == ' ' && line[i] != '\0')
217                         i++;
218
219                 /* If it's not a number it may be name of section */
220                 line_maj = atoi(((char *) (line + i)));
221                 if (!line_maj) {
222                         blocksection = (line[i] == 'B') ? 1 : 0;
223                         continue;
224                 }
225
226                 /* We only want block devices ... */
227                 if (!blocksection)
228                         continue;
229
230                 /* Find the start of the device major name */
231                 while (line[i] != ' ' && line[i] != '\0')
232                         i++;
233                 while (line[i] == ' ' && line[i] != '\0')
234                         i++;
235
236                 /* Look for md device */
237                 if (!strncmp("md", line + i, 2) && isspace(*(line + i + 2)))
238                         _md_major = line_maj;
239
240                 /* Look for blkext device */
241                 if (!strncmp("blkext", line + i, 6) && isspace(*(line + i + 6)))
242                         _blkext_major = line_maj;
243
244                 /* Look for drbd device */
245                 if (!strncmp("drbd", line + i, 4) && isspace(*(line + i + 4)))
246                         _drbd_major = line_maj;
247
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;
252
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;
262                                 break;
263                         }
264                 }
265
266                 if (!cn)
267                         continue;
268
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 "
273                                           "in config file");
274                                 if (fclose(pd))
275                                         log_sys_error("fclose", proc_devices);
276                                 return 0;
277                         }
278                         dev_len = strlen(cv->v.str);
279                         name = cv->v.str;
280                         cv = cv->next;
281                         if (!cv || cv->type != CFG_INT) {
282                                 log_error("Max partition count missing for %s "
283                                           "in devices/types in config file",
284                                           name);
285                                 if (fclose(pd))
286                                         log_sys_error("fclose", proc_devices);
287                                 return 0;
288                         }
289                         if (!cv->v.i) {
290                                 log_error("Zero partition count invalid for "
291                                           "%s in devices/types in config file",
292                                           name);
293                                 if (fclose(pd))
294                                         log_sys_error("fclose", proc_devices);
295                                 return 0;
296                         }
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;
301                                 break;
302                         }
303                 }
304         }
305
306         if (fclose(pd))
307                 log_sys_error("fclose", proc_devices);
308
309         return 1;
310 }
311
312 int max_partitions(int major)
313 {
314         return _max_partitions_by_major[major];
315 }
316
317 struct dev_filter *lvm_type_filter_create(const char *proc,
318                                           const struct config_node *cn)
319 {
320         struct dev_filter *f;
321
322         if (!(f = dm_malloc(sizeof(struct dev_filter)))) {
323                 log_error("LVM type filter allocation failed");
324                 return NULL;
325         }
326
327         f->passes_filter = _passes_lvm_type_device_filter;
328         f->destroy = lvm_type_filter_destroy;
329         f->use_count = 0;
330         f->private = NULL;
331
332         if (!_scan_proc_dev(proc, cn)) {
333                 dm_free(f);
334                 return_NULL;
335         }
336
337         return f;
338 }
339
340 void lvm_type_filter_destroy(struct dev_filter *f)
341 {
342         if (f->use_count)
343                 log_error(INTERNAL_ERROR "Destroying lvm_type filter while in use %u times.", f->use_count);
344
345         dm_free(f);
346 }