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