import source from lvm2 2.02.79
[external/device-mapper.git] / lib / device / device.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 "lvm-types.h"
18 #include "device.h"
19 #include "metadata.h"
20 #include "filter.h"
21 #include "xlate.h"
22
23 #include <libgen.h> /* dirname, basename */
24
25 /* See linux/genhd.h and fs/partitions/msdos */
26
27 #define PART_MAGIC 0xAA55
28 #define PART_MAGIC_OFFSET UINT64_C(0x1FE)
29 #define PART_OFFSET UINT64_C(0x1BE)
30
31 struct partition {
32         uint8_t boot_ind;
33         uint8_t head;
34         uint8_t sector;
35         uint8_t cyl;
36         uint8_t sys_ind;        /* partition type */
37         uint8_t end_head;
38         uint8_t end_sector;
39         uint8_t end_cyl;
40         uint32_t start_sect;
41         uint32_t nr_sects;
42 } __attribute__((packed));
43
44 static int _is_partitionable(struct device *dev)
45 {
46         int parts = max_partitions(MAJOR(dev->dev));
47
48         /* All MD devices are partitionable via blkext (as of 2.6.28) */
49         if (MAJOR(dev->dev) == md_major())
50                 return 1;
51
52         if ((parts <= 1) || (MINOR(dev->dev) % parts))
53                 return 0;
54
55         return 1;
56 }
57
58 static int _has_partition_table(struct device *dev)
59 {
60         int ret = 0;
61         unsigned p;
62         struct {
63                 uint8_t skip[PART_OFFSET];
64                 struct partition part[4];
65                 uint16_t magic;
66         } __attribute__((packed)) buf; /* sizeof() == SECTOR_SIZE */
67
68         if (!dev_read(dev, UINT64_C(0), sizeof(buf), &buf))
69                 return_0;
70
71         /* FIXME Check for other types of partition table too */
72
73         /* Check for msdos partition table */
74         if (buf.magic == xlate16(PART_MAGIC)) {
75                 for (p = 0; p < 4; ++p) {
76                         /* Table is invalid if boot indicator not 0 or 0x80 */
77                         if (buf.part[p].boot_ind & 0x7f) {
78                                 ret = 0;
79                                 break;
80                         }
81                         /* Must have at least one non-empty partition */
82                         if (buf.part[p].nr_sects)
83                                 ret = 1;
84                 }
85         }
86
87         return ret;
88 }
89
90 int is_partitioned_dev(struct device *dev)
91 {
92         if (!_is_partitionable(dev))
93                 return 0;
94
95         return _has_partition_table(dev);
96 }
97
98 #if 0
99 #include <sys/stat.h>
100 #include <sys/mman.h>
101 #include <stdio.h>
102 #include <unistd.h>
103 #include <fcntl.h>
104 #include <ctype.h>
105
106 #include <errno.h>
107 #include <sys/ioctl.h>
108 #include <linux/fs.h>
109 #include <linux/major.h>
110 #include <linux/genhd.h>
111
112 int _get_partition_type(struct dev_filter *filter, struct device *d);
113
114 #define MINOR_PART(dev) (MINOR((dev)->dev) % max_partitions(MINOR((dev)->dev)))
115
116 int is_extended_partition(struct device *d)
117 {
118         return (MINOR_PART(d) > 4) ? 1 : 0;
119 }
120
121 struct device *dev_primary(struct dev_mgr *dm, struct device *d)
122 {
123         struct device *ret;
124
125         ret = dev_by_dev(dm, d->dev - MINOR_PART(dm, d));
126         /* FIXME: Needs replacing with a 'refresh' */
127         if (!ret) {
128                 init_dev_scan(dm);
129                 ret = dev_by_dev(dm, d->dev - MINOR_PART(dm, d));
130         }
131
132         return ret;
133
134 }
135
136 int partition_type_is_lvm(struct dev_mgr *dm, struct device *d)
137 {
138         int pt;
139
140         pt = _get_partition_type(dm, d);
141
142         if (!pt) {
143                 if (is_whole_disk(dm, d))
144                         /* FIXME: Overloaded pt=0 in error cases */
145                         return 1;
146                 else {
147                         log_error
148                             ("%s: missing partition table "
149                              "on partitioned device", d->name);
150                         return 0;
151                 }
152         }
153
154         if (is_whole_disk(dm, d)) {
155                 log_error("%s: looks to possess partition table", d->name);
156                 return 0;
157         }
158
159         /* check part type */
160         if (pt != LVM_PARTITION && pt != LVM_NEW_PARTITION) {
161                 log_error("%s: invalid partition type 0x%x "
162                           "(must be 0x%x)", d->name, pt, LVM_NEW_PARTITION);
163                 return 0;
164         }
165
166         if (pt == LVM_PARTITION) {
167                 log_error
168                     ("%s: old LVM partition type found - please change to 0x%x",
169                      d->name, LVM_NEW_PARTITION);
170                 return 0;
171         }
172
173         return 1;
174 }
175
176 int _get_partition_type(struct dev_mgr *dm, struct device *d)
177 {
178         int pv_handle = -1;
179         struct device *primary;
180         ssize_t read_ret;
181         ssize_t bytes_read = 0;
182         char *buffer;
183         unsigned short *s_buffer;
184         struct partition *part;
185         loff_t offset = 0;
186         loff_t extended_offset = 0;
187         int part_sought;
188         int part_found = 0;
189         int first_partition = 1;
190         int extended_partition = 0;
191         int p;
192
193         if (!(primary = dev_primary(dm, d))) {
194                 log_error
195                     ("Failed to find main device containing partition %s",
196                      d->name);
197                 return 0;
198         }
199
200         if (!(buffer = dm_malloc(SECTOR_SIZE))) {
201                 log_error("Failed to allocate partition table buffer");
202                 return 0;
203         }
204
205         /* Get partition table */
206         if ((pv_handle = open(primary->name, O_RDONLY)) < 0) {
207                 log_error("%s: open failed: %s", primary->name,
208                           strerror(errno));
209                 return 0;
210         }
211
212         s_buffer = (unsigned short *) buffer;
213         part = (struct partition *) (buffer + 0x1be);
214         part_sought = MINOR_PART(dm, d);
215
216         do {
217                 bytes_read = 0;
218
219                 if (llseek(pv_handle, offset * SECTOR_SIZE, SEEK_SET) == -1) {
220                         log_error("%s: llseek failed: %s",
221                                   primary->name, strerror(errno));
222                         return 0;
223                 }
224
225                 while ((bytes_read < SECTOR_SIZE) &&
226                        (read_ret =
227                         read(pv_handle, buffer + bytes_read,
228                              SECTOR_SIZE - bytes_read)) != -1)
229                         bytes_read += read_ret;
230
231                 if (read_ret == -1) {
232                         log_error("%s: read failed: %s", primary->name,
233                                   strerror(errno));
234                         return 0;
235                 }
236
237                 if (s_buffer[255] == 0xAA55) {
238                         if (is_whole_disk(dm, d))
239                                 return -1;
240                 } else
241                         return 0;
242
243                 extended_partition = 0;
244
245                 /* Loop through primary partitions */
246                 for (p = 0; p < 4; p++) {
247                         if (part[p].sys_ind == DOS_EXTENDED_PARTITION ||
248                             part[p].sys_ind == LINUX_EXTENDED_PARTITION
249                             || part[p].sys_ind == WIN98_EXTENDED_PARTITION) {
250                                 extended_partition = 1;
251                                 offset = extended_offset + part[p].start_sect;
252                                 if (extended_offset == 0)
253                                         extended_offset = part[p].start_sect;
254                                 if (first_partition == 1)
255                                         part_found++;
256                         } else if (first_partition == 1) {
257                                 if (p == part_sought) {
258                                         if (part[p].sys_ind == 0) {
259                                                 /* missing primary? */
260                                                 return 0;
261                                         }
262                                 } else
263                                         part_found++;
264                         } else if (!part[p].sys_ind)
265                                 part_found++;
266
267                         if (part_sought == part_found)
268                                 return part[p].sys_ind;
269
270                 }
271                 first_partition = 0;
272         }
273         while (extended_partition == 1);
274
275         return 0;
276 }
277 #endif
278
279 #ifdef linux
280
281 int get_primary_dev(const char *sysfs_dir,
282                     const struct device *dev, dev_t *result)
283 {
284         char path[PATH_MAX+1];
285         char temp_path[PATH_MAX+1];
286         char buffer[64];
287         struct stat info;
288         FILE *fp;
289         uint32_t pri_maj, pri_min;
290         int ret = 0;
291
292         /* check if dev is a partition */
293         if (dm_snprintf(path, PATH_MAX, "%s/dev/block/%d:%d/partition",
294                         sysfs_dir, (int)MAJOR(dev->dev), (int)MINOR(dev->dev)) < 0) {
295                 log_error("dm_snprintf partition failed");
296                 return ret;
297         }
298
299         if (stat(path, &info) == -1) {
300                 if (errno != ENOENT)
301                         log_sys_error("stat", path);
302                 return ret;
303         }
304
305         /*
306          * extract parent's path from the partition's symlink, e.g.:
307          * - readlink /sys/dev/block/259:0 = ../../block/md0/md0p1
308          * - dirname ../../block/md0/md0p1 = ../../block/md0
309          * - basename ../../block/md0/md0  = md0
310          * Parent's 'dev' sysfs attribute  = /sys/block/md0/dev
311          */
312         if (readlink(dirname(path), temp_path, PATH_MAX) < 0) {
313                 log_sys_error("readlink", path);
314                 return ret;
315         }
316
317         if (dm_snprintf(path, PATH_MAX, "%s/block/%s/dev",
318                         sysfs_dir, basename(dirname(temp_path))) < 0) {
319                 log_error("dm_snprintf dev failed");
320                 return ret;
321         }
322
323         /* finally, parse 'dev' attribute and create corresponding dev_t */
324         if (stat(path, &info) == -1) {
325                 if (errno == ENOENT)
326                         log_error("sysfs file %s does not exist", path);
327                 else
328                         log_sys_error("stat", path);
329                 return ret;
330         }
331
332         fp = fopen(path, "r");
333         if (!fp) {
334                 log_sys_error("fopen", path);
335                 return ret;
336         }
337
338         if (!fgets(buffer, sizeof(buffer), fp)) {
339                 log_sys_error("fgets", path);
340                 goto out;
341         }
342
343         if (sscanf(buffer, "%d:%d", &pri_maj, &pri_min) != 2) {
344                 log_error("sysfs file %s not in expected MAJ:MIN format: %s",
345                           path, buffer);
346                 goto out;
347         }
348         *result = MKDEV(pri_maj, pri_min);
349         ret = 1;
350
351 out:
352         if (fclose(fp))
353                 log_sys_error("fclose", path);
354
355         return ret;
356 }
357
358 static unsigned long _dev_topology_attribute(const char *attribute,
359                                              const char *sysfs_dir,
360                                              struct device *dev)
361 {
362         const char *sysfs_fmt_str = "%s/dev/block/%d:%d/%s";
363         char path[PATH_MAX+1], buffer[64];
364         FILE *fp;
365         struct stat info;
366         dev_t uninitialized_var(primary);
367         unsigned long result = 0UL;
368
369         if (!attribute || !*attribute)
370                 return_0;
371
372         if (!sysfs_dir || !*sysfs_dir)
373                 return_0;
374
375         if (dm_snprintf(path, PATH_MAX, sysfs_fmt_str, sysfs_dir,
376                         (int)MAJOR(dev->dev), (int)MINOR(dev->dev),
377                         attribute) < 0) {
378                 log_error("dm_snprintf %s failed", attribute);
379                 return 0;
380         }
381
382         /*
383          * check if the desired sysfs attribute exists
384          * - if not: either the kernel doesn't have topology support
385          *   or the device could be a partition
386          */
387         if (stat(path, &info) == -1) {
388                 if (errno != ENOENT) {
389                         log_sys_error("stat", path);
390                         return 0;
391                 }
392                 if (!get_primary_dev(sysfs_dir, dev, &primary))
393                         return 0;
394
395                 /* get attribute from partition's primary device */
396                 if (dm_snprintf(path, PATH_MAX, sysfs_fmt_str, sysfs_dir,
397                                 (int)MAJOR(primary), (int)MINOR(primary),
398                                 attribute) < 0) {
399                         log_error("primary dm_snprintf %s failed", attribute);
400                         return 0;
401                 }
402                 if (stat(path, &info) == -1) {
403                         if (errno != ENOENT)
404                                 log_sys_error("stat", path);
405                         return 0;
406                 }
407         }
408
409         if (!(fp = fopen(path, "r"))) {
410                 log_sys_error("fopen", path);
411                 return 0;
412         }
413
414         if (!fgets(buffer, sizeof(buffer), fp)) {
415                 log_sys_error("fgets", path);
416                 goto out;
417         }
418
419         if (sscanf(buffer, "%lu", &result) != 1) {
420                 log_error("sysfs file %s not in expected format: %s", path,
421                           buffer);
422                 goto out;
423         }
424
425         log_very_verbose("Device %s %s is %lu bytes.",
426                          dev_name(dev), attribute, result);
427
428 out:
429         if (fclose(fp))
430                 log_sys_error("fclose", path);
431
432         return result >> SECTOR_SHIFT;
433 }
434
435 unsigned long dev_alignment_offset(const char *sysfs_dir,
436                                    struct device *dev)
437 {
438         return _dev_topology_attribute("alignment_offset",
439                                        sysfs_dir, dev);
440 }
441
442 unsigned long dev_minimum_io_size(const char *sysfs_dir,
443                                   struct device *dev)
444 {
445         return _dev_topology_attribute("queue/minimum_io_size",
446                                        sysfs_dir, dev);
447 }
448
449 unsigned long dev_optimal_io_size(const char *sysfs_dir,
450                                   struct device *dev)
451 {
452         return _dev_topology_attribute("queue/optimal_io_size",
453                                        sysfs_dir, dev);
454 }
455
456 #else
457
458 int get_primary_dev(const char *sysfs_dir,
459                     struct device *dev, dev_t *result)
460 {
461         return 0;
462 }
463
464 unsigned long dev_alignment_offset(const char *sysfs_dir,
465                                    struct device *dev)
466 {
467         return 0UL;
468 }
469
470 unsigned long dev_minimum_io_size(const char *sysfs_dir,
471                                   struct device *dev)
472 {
473         return 0UL;
474 }
475
476 unsigned long dev_optimal_io_size(const char *sysfs_dir,
477                                   struct device *dev)
478 {
479         return 0UL;
480 }
481
482 #endif