4 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5 * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
7 * This file is part of LVM2.
9 * This copyrighted material is made available to anyone wishing to use,
10 * modify, copy, or redistribute it subject to the terms and conditions
11 * of the GNU Lesser General Public License v.2.1.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, write to the Free Software Foundation,
15 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 #include <libgen.h> /* dirname, basename */
20 #include "lvm-types.h"
26 /* See linux/genhd.h and fs/partitions/msdos */
28 #define PART_MAGIC 0xAA55
29 #define PART_MAGIC_OFFSET UINT64_C(0x1FE)
30 #define PART_OFFSET UINT64_C(0x1BE)
37 uint8_t sys_ind
; /* partition type */
43 } __attribute__((packed
));
45 static int _is_partitionable(struct device
*dev
)
47 int parts
= max_partitions(MAJOR(dev
->dev
));
49 /* All MD devices are partitionable via blkext (as of 2.6.28) */
50 if (MAJOR(dev
->dev
) == md_major())
53 if ((parts
<= 1) || (MINOR(dev
->dev
) % parts
))
59 static int _has_partition_table(struct device
*dev
)
63 uint16_t buf
[SECTOR_SIZE
/sizeof(uint16_t)];
65 struct partition
*part
;
72 if (!dev_read(dev
, UINT64_C(0), sizeof(buf
), &buf
))
75 /* FIXME Check for other types of partition table too */
77 /* Check for msdos partition table */
78 part_magic
= buf
+ PART_MAGIC_OFFSET
/sizeof(buf
[0]);
79 if ((*part_magic
== xlate16(PART_MAGIC
))) {
80 part
= (struct partition
*) (buf
+ PART_OFFSET
/sizeof(buf
[0]));
81 for (p
= 0; p
< 4; p
++, part
++) {
82 /* Table is invalid if boot indicator not 0 or 0x80 */
83 if ((part
->boot_ind
& 0x7f)) {
87 /* Must have at least one non-empty partition */
100 int is_partitioned_dev(struct device
*dev
)
102 if (!_is_partitionable(dev
))
105 return _has_partition_table(dev
);
109 #include <sys/stat.h>
110 #include <sys/mman.h>
117 #include <sys/ioctl.h>
118 #include <linux/fs.h>
119 #include <linux/major.h>
120 #include <linux/genhd.h>
122 int _get_partition_type(struct dev_filter
*filter
, struct device
*d
);
124 #define MINOR_PART(dev) (MINOR((dev)->dev) % max_partitions(MINOR((dev)->dev)))
126 int is_extended_partition(struct device
*d
)
128 return (MINOR_PART(d
) > 4) ? 1 : 0;
131 struct device
*dev_primary(struct dev_mgr
*dm
, struct device
*d
)
135 ret
= dev_by_dev(dm
, d
->dev
- MINOR_PART(dm
, d
));
136 /* FIXME: Needs replacing with a 'refresh' */
139 ret
= dev_by_dev(dm
, d
->dev
- MINOR_PART(dm
, d
));
146 int partition_type_is_lvm(struct dev_mgr
*dm
, struct device
*d
)
150 pt
= _get_partition_type(dm
, d
);
153 if (is_whole_disk(dm
, d
))
154 /* FIXME: Overloaded pt=0 in error cases */
158 ("%s: missing partition table "
159 "on partitioned device", d
->name
);
164 if (is_whole_disk(dm
, d
)) {
165 log_error("%s: looks to possess partition table", d
->name
);
169 /* check part type */
170 if (pt
!= LVM_PARTITION
&& pt
!= LVM_NEW_PARTITION
) {
171 log_error("%s: invalid partition type 0x%x "
172 "(must be 0x%x)", d
->name
, pt
, LVM_NEW_PARTITION
);
176 if (pt
== LVM_PARTITION
) {
178 ("%s: old LVM partition type found - please change to 0x%x",
179 d
->name
, LVM_NEW_PARTITION
);
186 int _get_partition_type(struct dev_mgr
*dm
, struct device
*d
)
189 struct device
*primary
;
191 ssize_t bytes_read
= 0;
193 unsigned short *s_buffer
;
194 struct partition
*part
;
196 loff_t extended_offset
= 0;
199 int first_partition
= 1;
200 int extended_partition
= 0;
203 if (!(primary
= dev_primary(dm
, d
))) {
205 ("Failed to find main device containing partition %s",
210 if (!(buffer
= dm_malloc(SECTOR_SIZE
))) {
211 log_error("Failed to allocate partition table buffer");
215 /* Get partition table */
216 if ((pv_handle
= open(primary
->name
, O_RDONLY
)) < 0) {
217 log_error("%s: open failed: %s", primary
->name
,
222 s_buffer
= (unsigned short *) buffer
;
223 part
= (struct partition
*) (buffer
+ 0x1be);
224 part_sought
= MINOR_PART(dm
, d
);
229 if (llseek(pv_handle
, offset
* SECTOR_SIZE
, SEEK_SET
) == -1) {
230 log_error("%s: llseek failed: %s",
231 primary
->name
, strerror(errno
));
235 while ((bytes_read
< SECTOR_SIZE
) &&
237 read(pv_handle
, buffer
+ bytes_read
,
238 SECTOR_SIZE
- bytes_read
)) != -1)
239 bytes_read
+= read_ret
;
241 if (read_ret
== -1) {
242 log_error("%s: read failed: %s", primary
->name
,
247 if (s_buffer
[255] == 0xAA55) {
248 if (is_whole_disk(dm
, d
))
253 extended_partition
= 0;
255 /* Loop through primary partitions */
256 for (p
= 0; p
< 4; p
++) {
257 if (part
[p
].sys_ind
== DOS_EXTENDED_PARTITION
||
258 part
[p
].sys_ind
== LINUX_EXTENDED_PARTITION
259 || part
[p
].sys_ind
== WIN98_EXTENDED_PARTITION
) {
260 extended_partition
= 1;
261 offset
= extended_offset
+ part
[p
].start_sect
;
262 if (extended_offset
== 0)
263 extended_offset
= part
[p
].start_sect
;
264 if (first_partition
== 1)
266 } else if (first_partition
== 1) {
267 if (p
== part_sought
) {
268 if (part
[p
].sys_ind
== 0) {
269 /* missing primary? */
274 } else if (!part
[p
].sys_ind
)
277 if (part_sought
== part_found
)
278 return part
[p
].sys_ind
;
283 while (extended_partition
== 1);
291 int get_primary_dev(const char *sysfs_dir
,
292 struct device
*dev
, dev_t
*result
)
294 char path
[PATH_MAX
+1];
295 char temp_path
[PATH_MAX
+1];
299 uint32_t pri_maj
, pri_min
;
302 /* check if dev is a partition */
303 if (dm_snprintf(path
, PATH_MAX
, "%s/dev/block/%d:%d/partition",
304 sysfs_dir
, (int)MAJOR(dev
->dev
), (int)MINOR(dev
->dev
)) < 0) {
305 log_error("dm_snprintf partition failed");
309 if (stat(path
, &info
) == -1) {
311 log_sys_error("stat", path
);
316 * extract parent's path from the partition's symlink, e.g.:
317 * - readlink /sys/dev/block/259:0 = ../../block/md0/md0p1
318 * - dirname ../../block/md0/md0p1 = ../../block/md0
319 * - basename ../../block/md0/md0 = md0
320 * Parent's 'dev' sysfs attribute = /sys/block/md0/dev
322 if (readlink(dirname(path
), temp_path
, PATH_MAX
) < 0) {
323 log_sys_error("readlink", path
);
327 if (dm_snprintf(path
, PATH_MAX
, "%s/block/%s/dev",
328 sysfs_dir
, basename(dirname(temp_path
))) < 0) {
329 log_error("dm_snprintf dev failed");
333 /* finally, parse 'dev' attribute and create corresponding dev_t */
334 if (stat(path
, &info
) == -1) {
336 log_error("sysfs file %s does not exist", path
);
338 log_sys_error("stat", path
);
342 fp
= fopen(path
, "r");
344 log_sys_error("fopen", path
);
348 if (!fgets(buffer
, sizeof(buffer
), fp
)) {
349 log_sys_error("fgets", path
);
353 if (sscanf(buffer
, "%d:%d", &pri_maj
, &pri_min
) != 2) {
354 log_error("sysfs file %s not in expected MAJ:MIN format: %s",
358 *result
= MKDEV(pri_maj
, pri_min
);
363 log_sys_error("fclose", path
);
368 static unsigned long _dev_topology_attribute(const char *attribute
,
369 const char *sysfs_dir
,
372 const char *sysfs_fmt_str
= "%s/dev/block/%d:%d/%s";
373 char path
[PATH_MAX
+1], buffer
[64];
376 dev_t
uninitialized_var(primary
);
377 unsigned long result
= 0UL;
379 if (!attribute
|| !*attribute
)
382 if (!sysfs_dir
|| !*sysfs_dir
)
385 if (dm_snprintf(path
, PATH_MAX
, sysfs_fmt_str
, sysfs_dir
,
386 (int)MAJOR(dev
->dev
), (int)MINOR(dev
->dev
),
388 log_error("dm_snprintf %s failed", attribute
);
393 * check if the desired sysfs attribute exists
394 * - if not: either the kernel doesn't have topology support
395 * or the device could be a partition
397 if (stat(path
, &info
) == -1) {
398 if (errno
!= ENOENT
) {
399 log_sys_error("stat", path
);
402 if (!get_primary_dev(sysfs_dir
, dev
, &primary
))
405 /* get attribute from partition's primary device */
406 if (dm_snprintf(path
, PATH_MAX
, sysfs_fmt_str
, sysfs_dir
,
407 (int)MAJOR(primary
), (int)MINOR(primary
),
409 log_error("primary dm_snprintf %s failed", attribute
);
412 if (stat(path
, &info
) == -1) {
414 log_sys_error("stat", path
);
419 if (!(fp
= fopen(path
, "r"))) {
420 log_sys_error("fopen", path
);
424 if (!fgets(buffer
, sizeof(buffer
), fp
)) {
425 log_sys_error("fgets", path
);
429 if (sscanf(buffer
, "%lu", &result
) != 1) {
430 log_error("sysfs file %s not in expected format: %s", path
,
435 log_very_verbose("Device %s %s is %lu bytes.",
436 dev_name(dev
), attribute
, result
);
440 log_sys_error("fclose", path
);
442 return result
>> SECTOR_SHIFT
;
445 unsigned long dev_alignment_offset(const char *sysfs_dir
,
448 return _dev_topology_attribute("alignment_offset",
452 unsigned long dev_minimum_io_size(const char *sysfs_dir
,
455 return _dev_topology_attribute("queue/minimum_io_size",
459 unsigned long dev_optimal_io_size(const char *sysfs_dir
,
462 return _dev_topology_attribute("queue/optimal_io_size",
468 int get_primary_dev(const char *sysfs_dir
,
469 struct device
*dev
, dev_t
*result
)
474 unsigned long dev_alignment_offset(const char *sysfs_dir
,
480 unsigned long dev_minimum_io_size(const char *sysfs_dir
,
486 unsigned long dev_optimal_io_size(const char *sysfs_dir
,