2 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
3 * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
5 * This file is part of LVM2.
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.
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
17 #include "lvm-types.h"
23 #include <libgen.h> /* dirname, basename */
25 /* See linux/genhd.h and fs/partitions/msdos */
27 #define PART_MAGIC 0xAA55
28 #define PART_MAGIC_OFFSET UINT64_C(0x1FE)
29 #define PART_OFFSET UINT64_C(0x1BE)
36 uint8_t sys_ind; /* partition type */
42 } __attribute__((packed));
44 static int _is_partitionable(struct device *dev)
46 int parts = max_partitions(MAJOR(dev->dev));
48 /* All MD devices are partitionable via blkext (as of 2.6.28) */
49 if (MAJOR(dev->dev) == md_major())
52 if ((parts <= 1) || (MINOR(dev->dev) % parts))
58 static int _has_partition_table(struct device *dev)
63 uint8_t skip[PART_OFFSET];
64 struct partition part[4];
66 } __attribute__((packed)) buf; /* sizeof() == SECTOR_SIZE */
68 if (!dev_read(dev, UINT64_C(0), sizeof(buf), &buf))
71 /* FIXME Check for other types of partition table too */
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) {
81 /* Must have at least one non-empty partition */
82 if (buf.part[p].nr_sects)
90 int is_partitioned_dev(struct device *dev)
92 if (!_is_partitionable(dev))
95 return _has_partition_table(dev);
100 #include <sys/mman.h>
107 #include <sys/ioctl.h>
108 #include <linux/fs.h>
109 #include <linux/major.h>
110 #include <linux/genhd.h>
112 int _get_partition_type(struct dev_filter *filter, struct device *d);
114 #define MINOR_PART(dev) (MINOR((dev)->dev) % max_partitions(MINOR((dev)->dev)))
116 int is_extended_partition(struct device *d)
118 return (MINOR_PART(d) > 4) ? 1 : 0;
121 struct device *dev_primary(struct dev_mgr *dm, struct device *d)
125 ret = dev_by_dev(dm, d->dev - MINOR_PART(dm, d));
126 /* FIXME: Needs replacing with a 'refresh' */
129 ret = dev_by_dev(dm, d->dev - MINOR_PART(dm, d));
136 int partition_type_is_lvm(struct dev_mgr *dm, struct device *d)
140 pt = _get_partition_type(dm, d);
143 if (is_whole_disk(dm, d))
144 /* FIXME: Overloaded pt=0 in error cases */
148 ("%s: missing partition table "
149 "on partitioned device", d->name);
154 if (is_whole_disk(dm, d)) {
155 log_error("%s: looks to possess partition table", d->name);
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);
166 if (pt == LVM_PARTITION) {
168 ("%s: old LVM partition type found - please change to 0x%x",
169 d->name, LVM_NEW_PARTITION);
176 int _get_partition_type(struct dev_mgr *dm, struct device *d)
179 struct device *primary;
181 ssize_t bytes_read = 0;
183 unsigned short *s_buffer;
184 struct partition *part;
186 loff_t extended_offset = 0;
189 int first_partition = 1;
190 int extended_partition = 0;
193 if (!(primary = dev_primary(dm, d))) {
195 ("Failed to find main device containing partition %s",
200 if (!(buffer = dm_malloc(SECTOR_SIZE))) {
201 log_error("Failed to allocate partition table buffer");
205 /* Get partition table */
206 if ((pv_handle = open(primary->name, O_RDONLY)) < 0) {
207 log_error("%s: open failed: %s", primary->name,
212 s_buffer = (unsigned short *) buffer;
213 part = (struct partition *) (buffer + 0x1be);
214 part_sought = MINOR_PART(dm, d);
219 if (llseek(pv_handle, offset * SECTOR_SIZE, SEEK_SET) == -1) {
220 log_error("%s: llseek failed: %s",
221 primary->name, strerror(errno));
225 while ((bytes_read < SECTOR_SIZE) &&
227 read(pv_handle, buffer + bytes_read,
228 SECTOR_SIZE - bytes_read)) != -1)
229 bytes_read += read_ret;
231 if (read_ret == -1) {
232 log_error("%s: read failed: %s", primary->name,
237 if (s_buffer[255] == 0xAA55) {
238 if (is_whole_disk(dm, d))
243 extended_partition = 0;
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)
256 } else if (first_partition == 1) {
257 if (p == part_sought) {
258 if (part[p].sys_ind == 0) {
259 /* missing primary? */
264 } else if (!part[p].sys_ind)
267 if (part_sought == part_found)
268 return part[p].sys_ind;
273 while (extended_partition == 1);
281 int get_primary_dev(const char *sysfs_dir,
282 const struct device *dev, dev_t *result)
284 char path[PATH_MAX+1];
285 char temp_path[PATH_MAX+1];
289 uint32_t pri_maj, pri_min;
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");
299 if (stat(path, &info) == -1) {
301 log_sys_error("stat", path);
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
312 if (readlink(dirname(path), temp_path, PATH_MAX) < 0) {
313 log_sys_error("readlink", path);
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");
323 /* finally, parse 'dev' attribute and create corresponding dev_t */
324 if (stat(path, &info) == -1) {
326 log_error("sysfs file %s does not exist", path);
328 log_sys_error("stat", path);
332 fp = fopen(path, "r");
334 log_sys_error("fopen", path);
338 if (!fgets(buffer, sizeof(buffer), fp)) {
339 log_sys_error("fgets", path);
343 if (sscanf(buffer, "%d:%d", &pri_maj, &pri_min) != 2) {
344 log_error("sysfs file %s not in expected MAJ:MIN format: %s",
348 *result = MKDEV(pri_maj, pri_min);
353 log_sys_error("fclose", path);
358 static unsigned long _dev_topology_attribute(const char *attribute,
359 const char *sysfs_dir,
362 const char *sysfs_fmt_str = "%s/dev/block/%d:%d/%s";
363 char path[PATH_MAX+1], buffer[64];
366 dev_t uninitialized_var(primary);
367 unsigned long result = 0UL;
369 if (!attribute || !*attribute)
372 if (!sysfs_dir || !*sysfs_dir)
375 if (dm_snprintf(path, PATH_MAX, sysfs_fmt_str, sysfs_dir,
376 (int)MAJOR(dev->dev), (int)MINOR(dev->dev),
378 log_error("dm_snprintf %s failed", attribute);
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
387 if (stat(path, &info) == -1) {
388 if (errno != ENOENT) {
389 log_sys_error("stat", path);
392 if (!get_primary_dev(sysfs_dir, dev, &primary))
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),
399 log_error("primary dm_snprintf %s failed", attribute);
402 if (stat(path, &info) == -1) {
404 log_sys_error("stat", path);
409 if (!(fp = fopen(path, "r"))) {
410 log_sys_error("fopen", path);
414 if (!fgets(buffer, sizeof(buffer), fp)) {
415 log_sys_error("fgets", path);
419 if (sscanf(buffer, "%lu", &result) != 1) {
420 log_error("sysfs file %s not in expected format: %s", path,
425 log_very_verbose("Device %s %s is %lu bytes.",
426 dev_name(dev), attribute, result);
430 log_sys_error("fclose", path);
432 return result >> SECTOR_SHIFT;
435 unsigned long dev_alignment_offset(const char *sysfs_dir,
438 return _dev_topology_attribute("alignment_offset",
442 unsigned long dev_minimum_io_size(const char *sysfs_dir,
445 return _dev_topology_attribute("queue/minimum_io_size",
449 unsigned long dev_optimal_io_size(const char *sysfs_dir,
452 return _dev_topology_attribute("queue/optimal_io_size",
458 int get_primary_dev(const char *sysfs_dir,
459 struct device *dev, dev_t *result)
464 unsigned long dev_alignment_offset(const char *sysfs_dir,
470 unsigned long dev_minimum_io_size(const char *sysfs_dir,
476 unsigned long dev_optimal_io_size(const char *sysfs_dir,