bigbiff bigbiff | e60683a | 2013-02-22 20:55:50 -0500 | [diff] [blame] | 1 | /* |
| 2 | * sysfs based topology -- gathers topology information from Linux sysfs |
| 3 | * |
| 4 | * Copyright (C) 2009 Karel Zak <kzak@redhat.com> |
| 5 | * |
| 6 | * This file may be redistributed under the terms of the |
| 7 | * GNU Lesser General Public License. |
| 8 | * |
| 9 | * For more information see Linux kernel Documentation/ABI/testing/sysfs-block. |
| 10 | */ |
| 11 | #include <stdio.h> |
| 12 | #include <string.h> |
| 13 | #include <stdlib.h> |
| 14 | #include <inttypes.h> |
| 15 | #include <sys/types.h> |
| 16 | #include <sys/stat.h> |
| 17 | #include <unistd.h> |
| 18 | #include <errno.h> |
| 19 | |
| 20 | #include "sysfs.h" |
| 21 | #include "topology.h" |
| 22 | |
| 23 | /* |
| 24 | * Sysfs topology values (since 2.6.31, May 2009). |
| 25 | */ |
| 26 | static struct topology_val { |
| 27 | |
| 28 | /* /sys/dev/block/<maj>:<min>/<ATTR> */ |
| 29 | const char *attr; |
| 30 | |
| 31 | /* functions to set probing resut */ |
| 32 | int (*set_ulong)(blkid_probe, unsigned long); |
| 33 | int (*set_int)(blkid_probe, int); |
| 34 | |
| 35 | } topology_vals[] = { |
| 36 | { "alignment_offset", NULL, blkid_topology_set_alignment_offset }, |
| 37 | { "queue/minimum_io_size", blkid_topology_set_minimum_io_size }, |
| 38 | { "queue/optimal_io_size", blkid_topology_set_optimal_io_size }, |
| 39 | { "queue/physical_block_size", blkid_topology_set_physical_sector_size }, |
| 40 | }; |
| 41 | |
| 42 | static int probe_sysfs_tp(blkid_probe pr, |
| 43 | const struct blkid_idmag *mag __attribute__((__unused__))) |
| 44 | { |
| 45 | dev_t dev, disk = 0; |
| 46 | int rc; |
| 47 | struct sysfs_cxt sysfs = UL_SYSFSCXT_EMPTY, |
| 48 | parent = UL_SYSFSCXT_EMPTY; |
| 49 | size_t i, count = 0; |
| 50 | |
| 51 | dev = blkid_probe_get_devno(pr); |
| 52 | if (!dev || sysfs_init(&sysfs, dev, NULL) != 0) |
| 53 | return 1; |
| 54 | |
| 55 | rc = 1; /* nothing (default) */ |
| 56 | |
| 57 | for (i = 0; i < ARRAY_SIZE(topology_vals); i++) { |
| 58 | struct topology_val *val = &topology_vals[i]; |
| 59 | int ok = sysfs_has_attribute(&sysfs, val->attr); |
| 60 | |
| 61 | rc = 1; /* nothing */ |
| 62 | |
| 63 | if (!ok) { |
| 64 | if (!disk) { |
| 65 | /* |
| 66 | * Read atrributes from "disk" if the current |
| 67 | * device is a partition. |
| 68 | */ |
| 69 | disk = blkid_probe_get_wholedisk_devno(pr); |
| 70 | if (disk && disk != dev) { |
| 71 | if (sysfs_init(&parent, disk, NULL) != 0) |
| 72 | goto done; |
| 73 | |
| 74 | sysfs.parent = &parent; |
| 75 | ok = sysfs_has_attribute(&sysfs, |
| 76 | val->attr); |
| 77 | } |
| 78 | } |
| 79 | if (!ok) |
| 80 | continue; /* attribute does not exist */ |
| 81 | } |
| 82 | |
| 83 | if (val->set_ulong) { |
| 84 | uint64_t data; |
| 85 | |
| 86 | if (sysfs_read_u64(&sysfs, val->attr, &data) != 0) |
| 87 | continue; |
| 88 | rc = val->set_ulong(pr, (unsigned long) data); |
| 89 | |
| 90 | } else if (val->set_int) { |
| 91 | int64_t data; |
| 92 | |
| 93 | if (sysfs_read_s64(&sysfs, val->attr, &data) != 0) |
| 94 | continue; |
| 95 | rc = val->set_int(pr, (int) data); |
| 96 | } |
| 97 | |
| 98 | if (rc < 0) |
| 99 | goto done; /* error */ |
| 100 | if (rc == 0) |
| 101 | count++; |
| 102 | } |
| 103 | |
| 104 | done: |
| 105 | sysfs_deinit(&sysfs); |
| 106 | sysfs_deinit(&parent); |
| 107 | |
| 108 | if (count) |
| 109 | return 0; /* success */ |
| 110 | return rc; /* error or nothing */ |
| 111 | } |
| 112 | |
| 113 | const struct blkid_idinfo sysfs_tp_idinfo = |
| 114 | { |
| 115 | .name = "sysfs", |
| 116 | .probefunc = probe_sysfs_tp, |
| 117 | .magics = BLKID_NONE_MAGIC |
| 118 | }; |
| 119 | |