diff options
Diffstat (limited to 'libblkid/src/topology')
-rw-r--r-- | libblkid/src/topology/dm.c | 135 | ||||
-rw-r--r-- | libblkid/src/topology/evms.c | 77 | ||||
-rw-r--r-- | libblkid/src/topology/ioctl.c | 74 | ||||
-rw-r--r-- | libblkid/src/topology/lvm.c | 147 | ||||
-rw-r--r-- | libblkid/src/topology/md.c | 154 | ||||
-rw-r--r-- | libblkid/src/topology/sysfs.c | 119 | ||||
-rw-r--r-- | libblkid/src/topology/topology.c | 362 | ||||
-rw-r--r-- | libblkid/src/topology/topology.h | 24 |
8 files changed, 1092 insertions, 0 deletions
diff --git a/libblkid/src/topology/dm.c b/libblkid/src/topology/dm.c new file mode 100644 index 000000000..e061632ca --- /dev/null +++ b/libblkid/src/topology/dm.c @@ -0,0 +1,135 @@ +/* + * device-mapper (dm) topology + * -- this is fallback for old systems where the topology information is not + * exported by sysfs + * + * Copyright (C) 2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * + */ +#include <errno.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "topology.h" + +static int is_dm_device(dev_t devno) +{ + return blkid_driver_has_major("device-mapper", major(devno)); +} + +static int probe_dm_tp(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + const char *paths[] = { + "/usr/local/sbin/dmsetup", + "/usr/sbin/dmsetup", + "/sbin/dmsetup" + }; + int dmpipe[] = { -1, -1 }, stripes, stripesize; + char *cmd = NULL; + FILE *stream = NULL; + long long offset, size; + size_t i; + dev_t devno = blkid_probe_get_devno(pr); + + if (!devno) + goto nothing; /* probably not a block device */ + if (!is_dm_device(devno)) + goto nothing; + + for (i = 0; i < ARRAY_SIZE(paths); i++) { + struct stat sb; + if (stat(paths[i], &sb) == 0) { + cmd = (char *) paths[i]; + break; + } + } + + if (!cmd) + goto nothing; + if (pipe(dmpipe) < 0) { + DBG(LOWPROBE, ul_debug("Failed to open pipe: errno=%d", errno)); + goto nothing; + } + + switch (fork()) { + case 0: + { + char *dmargv[7], maj[16], min[16]; + + /* Plumbing */ + close(dmpipe[0]); + + if (dmpipe[1] != STDOUT_FILENO) + dup2(dmpipe[1], STDOUT_FILENO); + + /* The libblkid library could linked with setuid programs */ + if (setgid(getgid()) < 0) + exit(1); + if (setuid(getuid()) < 0) + exit(1); + + snprintf(maj, sizeof(maj), "%d", major(devno)); + snprintf(min, sizeof(min), "%d", minor(devno)); + + dmargv[0] = cmd; + dmargv[1] = "table"; + dmargv[2] = "-j"; + dmargv[3] = maj; + dmargv[4] = "-m"; + dmargv[5] = min; + dmargv[6] = NULL; + + execv(dmargv[0], dmargv); + + DBG(LOWPROBE, ul_debug("Failed to execute %s: errno=%d", cmd, errno)); + exit(1); + } + case -1: + DBG(LOWPROBE, ul_debug("Failed to forking: errno=%d", errno)); + goto nothing; + default: + break; + } + + stream = fdopen(dmpipe[0], "r" UL_CLOEXECSTR); + if (!stream) + goto nothing; + + if (fscanf(stream, "%lld %lld striped %d %d ", + &offset, &size, &stripes, &stripesize) != 0) + goto nothing; + + blkid_topology_set_minimum_io_size(pr, stripesize << 9); + blkid_topology_set_optimal_io_size(pr, (stripes * stripesize) << 9); + + fclose(stream); + close(dmpipe[1]); + return 0; + +nothing: + if (stream) + fclose(stream); + else if (dmpipe[0] != -1) + close(dmpipe[0]); + if (dmpipe[1] != -1) + close(dmpipe[1]); + return 1; +} + +const struct blkid_idinfo dm_tp_idinfo = +{ + .name = "dm", + .probefunc = probe_dm_tp, + .magics = BLKID_NONE_MAGIC +}; + diff --git a/libblkid/src/topology/evms.c b/libblkid/src/topology/evms.c new file mode 100644 index 000000000..7a4fd554d --- /dev/null +++ b/libblkid/src/topology/evms.c @@ -0,0 +1,77 @@ +/* + * Evms topology + * -- this is fallback for old systems where the toplogy information is not + * exported by sysfs + * + * Copyright (C) 2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * + */ +#include <errno.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "topology.h" + +#define EVMS_MAJOR 117 + +#ifndef _IOT__IOTBASE_u_int32_t +#define _IOT__IOTBASE_u_int32_t IOT_SIMPLE(uint32_t) +#endif +#define _IOT_evms_stripe_info _IOT (_IOTS(uint32_t), 2, 0, 0, 0, 0) +#define EVMS_GET_STRIPE_INFO _IOR(EVMS_MAJOR, 0xF0, struct evms_stripe_info) + +struct evms_stripe_info { + uint32_t size; /* stripe unit 512-byte blocks */ + uint32_t width; /* the number of stripe members or RAID data disks */ +} evms_stripe_info; + +static int is_evms_device(dev_t devno) +{ + if (major(devno) == EVMS_MAJOR) + return 1; + return blkid_driver_has_major("evms", major(devno)); +} + +static int probe_evms_tp(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + struct evms_stripe_info evms; + dev_t devno = blkid_probe_get_devno(pr); + + if (!devno) + goto nothing; /* probably not a block device */ + + if (!is_evms_device(devno)) + goto nothing; + + memset(&evms, 0, sizeof(evms)); + + if (ioctl(pr->fd, EVMS_GET_STRIPE_INFO, &evms)) + goto nothing; + + blkid_topology_set_minimum_io_size(pr, evms.size << 9); + blkid_topology_set_optimal_io_size(pr, (evms.size * evms.width) << 9); + + return 0; + +nothing: + return 1; +} + +const struct blkid_idinfo evms_tp_idinfo = +{ + .name = "evms", + .probefunc = probe_evms_tp, + .magics = BLKID_NONE_MAGIC +}; + diff --git a/libblkid/src/topology/ioctl.c b/libblkid/src/topology/ioctl.c new file mode 100644 index 000000000..3aba09e4f --- /dev/null +++ b/libblkid/src/topology/ioctl.c @@ -0,0 +1,74 @@ +/* + * ioctl based topology -- gathers topology information + * + * Copyright (C) 2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> + +#include "topology.h" + +/* + * ioctl topology values + */ +static struct topology_val { + + long ioc; + + /* functions to set probing result */ + int (*set_ulong)(blkid_probe, unsigned long); + int (*set_int)(blkid_probe, int); + +} topology_vals[] = { + { BLKALIGNOFF, NULL, blkid_topology_set_alignment_offset }, + { BLKIOMIN, blkid_topology_set_minimum_io_size }, + { BLKIOOPT, blkid_topology_set_optimal_io_size }, + { BLKPBSZGET, blkid_topology_set_physical_sector_size } + /* we read BLKSSZGET in topology.c */ +}; + +static int probe_ioctl_tp(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(topology_vals); i++) { + struct topology_val *val = &topology_vals[i]; + int rc = 1; + unsigned int data; + + if (ioctl(pr->fd, val->ioc, &data) == -1) + goto nothing; + + if (val->set_int) + rc = val->set_int(pr, (int) data); + else + rc = val->set_ulong(pr, (unsigned long) data); + if (rc) + goto err; + } + + return 0; +nothing: + return 1; +err: + return -1; +} + +const struct blkid_idinfo ioctl_tp_idinfo = +{ + .name = "ioctl", + .probefunc = probe_ioctl_tp, + .magics = BLKID_NONE_MAGIC +}; + diff --git a/libblkid/src/topology/lvm.c b/libblkid/src/topology/lvm.c new file mode 100644 index 000000000..bd079d47b --- /dev/null +++ b/libblkid/src/topology/lvm.c @@ -0,0 +1,147 @@ +/* + * lvm topology + * -- this is fallback for old systems where the topology information is not + * exported by sysfs + * + * Copyright (C) 2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * + */ +#include <errno.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "topology.h" + +#ifndef LVM_BLK_MAJOR +# define LVM_BLK_MAJOR 58 +#endif + +static int is_lvm_device(dev_t devno) +{ + if (major(devno) == LVM_BLK_MAJOR) + return 1; + return blkid_driver_has_major("lvm", major(devno)); +} + +static int probe_lvm_tp(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + const char *paths[] = { + "/usr/local/sbin/lvdisplay", + "/usr/sbin/lvdisplay", + "/sbin/lvdisplay" + }; + int lvpipe[] = { -1, -1 }, stripes = 0, stripesize = 0; + FILE *stream = NULL; + char *cmd = NULL, *devname = NULL, buf[1024]; + size_t i; + dev_t devno = blkid_probe_get_devno(pr); + + if (!devno) + goto nothing; /* probably not a block device */ + if (!is_lvm_device(devno)) + goto nothing; + + for (i = 0; i < ARRAY_SIZE(paths); i++) { + struct stat sb; + if (stat(paths[i], &sb) == 0) { + cmd = (char *) paths[i]; + break; + } + } + + if (!cmd) + goto nothing; + + devname = blkid_devno_to_devname(devno); + if (!devname) + goto nothing; + + if (pipe(lvpipe) < 0) { + DBG(LOWPROBE, ul_debug("Failed to open pipe: errno=%d", errno)); + goto nothing; + } + + switch (fork()) { + case 0: + { + char *lvargv[3]; + + /* Plumbing */ + close(lvpipe[0]); + + if (lvpipe[1] != STDOUT_FILENO) + dup2(lvpipe[1], STDOUT_FILENO); + + /* The libblkid library could linked with setuid programs */ + if (setgid(getgid()) < 0) + exit(1); + if (setuid(getuid()) < 0) + exit(1); + + lvargv[0] = cmd; + lvargv[1] = devname; + lvargv[2] = NULL; + + execv(lvargv[0], lvargv); + + DBG(LOWPROBE, ul_debug("Failed to execute %s: errno=%d", cmd, errno)); + exit(1); + } + case -1: + DBG(LOWPROBE, ul_debug("Failed to forking: errno=%d", errno)); + goto nothing; + default: + break; + } + + stream = fdopen(lvpipe[0], "r" UL_CLOEXECSTR); + if (!stream) + goto nothing; + + while (fgets(buf, sizeof(buf), stream) != NULL) { + if (!strncmp(buf, "Stripes", 7)) + sscanf(buf, "Stripes %d", &stripes); + + if (!strncmp(buf, "Stripe size", 11)) + sscanf(buf, "Stripe size (KByte) %d", &stripesize); + } + + if (!stripes) + goto nothing; + + blkid_topology_set_minimum_io_size(pr, stripesize << 10); + blkid_topology_set_optimal_io_size(pr, (stripes * stripesize) << 10); + + free(devname); + fclose(stream); + close(lvpipe[1]); + return 0; + +nothing: + free(devname); + if (stream) + fclose(stream); + else if (lvpipe[0] != -1) + close(lvpipe[0]); + if (lvpipe[1] != -1) + close(lvpipe[1]); + return 1; +} + +const struct blkid_idinfo lvm_tp_idinfo = +{ + .name = "lvm", + .probefunc = probe_lvm_tp, + .magics = BLKID_NONE_MAGIC +}; + diff --git a/libblkid/src/topology/md.c b/libblkid/src/topology/md.c new file mode 100644 index 000000000..5eba94787 --- /dev/null +++ b/libblkid/src/topology/md.c @@ -0,0 +1,154 @@ +/* + * Linux Software RAID (md) topology + * -- this is fallback for old systems where the topology information is not + * exported by sysfs + * + * Copyright (C) 2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * + */ +#include <errno.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "topology.h" + +#ifndef MD_MAJOR +#define MD_MAJOR 9 +#endif + +#ifndef _IOT__IOTBASE_uint32_t +#define _IOT__IOTBASE_uint32_t IOT_SIMPLE(uint32_t) +#endif +#define _IOT_md_array_info _IOT (_IOTS(uint32_t), 18, 0, 0, 0, 0) +#define GET_ARRAY_INFO _IOR (MD_MAJOR, 0x11, struct md_array_info) + +struct md_array_info { + /* + * Generic constant information + */ + uint32_t major_version; + uint32_t minor_version; + uint32_t patch_version; + uint32_t ctime; + uint32_t level; + uint32_t size; + uint32_t nr_disks; + uint32_t raid_disks; + uint32_t md_minor; + uint32_t not_persistent; + + /* + * Generic state information + */ + uint32_t utime; /* 0 Superblock update time */ + uint32_t state; /* 1 State bits (clean, ...) */ + uint32_t active_disks; /* 2 Number of currently active disks */ + uint32_t working_disks; /* 3 Number of working disks */ + uint32_t failed_disks; /* 4 Number of failed disks */ + uint32_t spare_disks; /* 5 Number of spare disks */ + + /* + * Personality information + */ + uint32_t layout; /* 0 the array's physical layout */ + uint32_t chunk_size; /* 1 chunk size in bytes */ + +}; + +static int is_md_device(dev_t devno) +{ + if (major(devno) == MD_MAJOR) + return 1; + return blkid_driver_has_major("md", major(devno)); +} + +static int probe_md_tp(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + int fd = -1; + dev_t disk = 0; + dev_t devno = blkid_probe_get_devno(pr); + struct md_array_info md; + + if (!devno) + goto nothing; /* probably not a block device */ + + if (!is_md_device(devno)) + goto nothing; + + if (blkid_devno_to_wholedisk(devno, NULL, 0, &disk)) + goto nothing; + + if (disk == devno) + fd = pr->fd; + else { + char *diskpath = blkid_devno_to_devname(disk); + + if (!diskpath) + goto nothing; + + fd = open(diskpath, O_RDONLY|O_CLOEXEC); + free(diskpath); + + if (fd == -1) + goto nothing; + } + + memset(&md, 0, sizeof(md)); + + if (ioctl(fd, GET_ARRAY_INFO, &md)) + goto nothing; + + if (fd >= 0 && fd != pr->fd) { + close(fd); + fd = -1; + } + + /* + * Ignore levels we don't want aligned (e.g. linear) + * and deduct disk(s) from stripe width on RAID4/5/6 + */ + switch (md.level) { + case 6: + md.raid_disks--; + /* fallthrough */ + case 5: + case 4: + md.raid_disks--; + /* fallthrough */ + case 1: + case 0: + case 10: + break; + default: + goto nothing; + } + + blkid_topology_set_minimum_io_size(pr, md.chunk_size); + blkid_topology_set_optimal_io_size(pr, md.chunk_size * md.raid_disks); + + return 0; + +nothing: + if (fd >= 0 && fd != pr->fd) + close(fd); + return 1; +} + +const struct blkid_idinfo md_tp_idinfo = +{ + .name = "md", + .probefunc = probe_md_tp, + .magics = BLKID_NONE_MAGIC +}; + diff --git a/libblkid/src/topology/sysfs.c b/libblkid/src/topology/sysfs.c new file mode 100644 index 000000000..a04b20a37 --- /dev/null +++ b/libblkid/src/topology/sysfs.c @@ -0,0 +1,119 @@ +/* + * sysfs based topology -- gathers topology information from Linux sysfs + * + * Copyright (C) 2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * + * For more information see Linux kernel Documentation/ABI/testing/sysfs-block. + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <inttypes.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> + +#include "sysfs.h" +#include "topology.h" + +/* + * Sysfs topology values (since 2.6.31, May 2009). + */ +static struct topology_val { + + /* /sys/dev/block/<maj>:<min>/<ATTR> */ + const char *attr; + + /* functions to set probing resut */ + int (*set_ulong)(blkid_probe, unsigned long); + int (*set_int)(blkid_probe, int); + +} topology_vals[] = { + { "alignment_offset", NULL, blkid_topology_set_alignment_offset }, + { "queue/minimum_io_size", blkid_topology_set_minimum_io_size }, + { "queue/optimal_io_size", blkid_topology_set_optimal_io_size }, + { "queue/physical_block_size", blkid_topology_set_physical_sector_size }, +}; + +static int probe_sysfs_tp(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + dev_t dev, disk = 0; + int rc; + struct sysfs_cxt sysfs = UL_SYSFSCXT_EMPTY, + parent = UL_SYSFSCXT_EMPTY; + size_t i, count = 0; + + dev = blkid_probe_get_devno(pr); + if (!dev || sysfs_init(&sysfs, dev, NULL) != 0) + return 1; + + rc = 1; /* nothing (default) */ + + for (i = 0; i < ARRAY_SIZE(topology_vals); i++) { + struct topology_val *val = &topology_vals[i]; + int ok = sysfs_has_attribute(&sysfs, val->attr); + + rc = 1; /* nothing */ + + if (!ok) { + if (!disk) { + /* + * Read atrributes from "disk" if the current + * device is a partition. + */ + disk = blkid_probe_get_wholedisk_devno(pr); + if (disk && disk != dev) { + if (sysfs_init(&parent, disk, NULL) != 0) + goto done; + + sysfs.parent = &parent; + ok = sysfs_has_attribute(&sysfs, + val->attr); + } + } + if (!ok) + continue; /* attribute does not exist */ + } + + if (val->set_ulong) { + uint64_t data; + + if (sysfs_read_u64(&sysfs, val->attr, &data) != 0) + continue; + rc = val->set_ulong(pr, (unsigned long) data); + + } else if (val->set_int) { + int64_t data; + + if (sysfs_read_s64(&sysfs, val->attr, &data) != 0) + continue; + rc = val->set_int(pr, (int) data); + } + + if (rc < 0) + goto done; /* error */ + if (rc == 0) + count++; + } + +done: + sysfs_deinit(&sysfs); + sysfs_deinit(&parent); + + if (count) + return 0; /* success */ + return rc; /* error or nothing */ +} + +const struct blkid_idinfo sysfs_tp_idinfo = +{ + .name = "sysfs", + .probefunc = probe_sysfs_tp, + .magics = BLKID_NONE_MAGIC +}; + diff --git a/libblkid/src/topology/topology.c b/libblkid/src/topology/topology.c new file mode 100644 index 000000000..93fa3802e --- /dev/null +++ b/libblkid/src/topology/topology.c @@ -0,0 +1,362 @@ +/* + * topology - gathers information about device topology + * + * Copyright 2009 Red Hat, Inc. All rights reserved. + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stddef.h> + +#include "topology.h" + +/** + * SECTION:topology + * @title: Topology information + * @short_description: block device topology information. + * + * The topology chain provides details about Linux block devices, for more + * information see: + * + * Linux kernel Documentation/ABI/testing/sysfs-block + * + * NAME=value (tags) interface is enabled by blkid_probe_enable_topology(), + * and provides: + * + * @LOGICAL_SECTOR_SIZE: this is the smallest unit the storage device can + * address. It is typically 512 bytes. + * + * @PHYSICAL_SECTOR_SIZE: this is the smallest unit a physical storage device + * can write atomically. It is usually the same as the + * logical sector size but may be bigger. + * + * @MINIMUM_IO_SIZE: minimum size which is the device's preferred unit of I/O. + * For RAID arrays it is often the stripe chunk size. + * + * @OPTIMAL_IO_SIZE: usually the stripe width for RAID or zero. For RAID arrays + * it is usually the stripe width or the internal track size. + * + * @ALIGNMENT_OFFSET: indicates how many bytes the beginning of the device is + * offset from the disk's natural alignment. + * + * The NAME=value tags are not defined when the corresponding topology value + * is zero. The MINIMUM_IO_SIZE should be always defined if kernel provides + * topology information. + * + * Binary interface: + * + * blkid_probe_get_topology() + * + * blkid_topology_get_'VALUENAME'() + */ +static int topology_probe(blkid_probe pr, struct blkid_chain *chn); +static void topology_free(blkid_probe pr, void *data); +static int topology_is_complete(blkid_probe pr); +static int topology_set_logical_sector_size(blkid_probe pr); + +/* + * Binary interface + */ +struct blkid_struct_topology { + unsigned long alignment_offset; + unsigned long minimum_io_size; + unsigned long optimal_io_size; + unsigned long logical_sector_size; + unsigned long physical_sector_size; +}; + +/* + * Topology chain probing functions + */ +static const struct blkid_idinfo *idinfos[] = +{ +#ifdef __linux__ + &ioctl_tp_idinfo, + &sysfs_tp_idinfo, + &md_tp_idinfo, + &dm_tp_idinfo, + &lvm_tp_idinfo, + &evms_tp_idinfo +#endif +}; + + +/* + * Driver definition + */ +const struct blkid_chaindrv topology_drv = { + .id = BLKID_CHAIN_TOPLGY, + .name = "topology", + .dflt_enabled = FALSE, + .idinfos = idinfos, + .nidinfos = ARRAY_SIZE(idinfos), + .probe = topology_probe, + .safeprobe = topology_probe, + .free_data = topology_free +}; + +/** + * blkid_probe_enable_topology: + * @pr: probe + * @enable: TRUE/FALSE + * + * Enables/disables the topology probing for non-binary interface. + * + * Returns: 0 on success, or -1 in case of error. + */ +int blkid_probe_enable_topology(blkid_probe pr, int enable) +{ + if (!pr) + return -1; + pr->chains[BLKID_CHAIN_TOPLGY].enabled = enable; + return 0; +} + +/** + * blkid_probe_get_topology: + * @pr: probe + * + * This is a binary interface for topology values. See also blkid_topology_* + * functions. + * + * This function is independent on blkid_do_[safe,full]probe() and + * blkid_probe_enable_topology() calls. + * + * WARNING: the returned object will be overwritten by the next + * blkid_probe_get_topology() call for the same @pr. If you want to + * use more blkid_topopogy objects in the same time you have to create + * more blkid_probe handlers (see blkid_new_probe()). + * + * Returns: blkid_topopogy, or NULL in case of error. + */ +blkid_topology blkid_probe_get_topology(blkid_probe pr) +{ + return (blkid_topology) blkid_probe_get_binary_data(pr, + &pr->chains[BLKID_CHAIN_TOPLGY]); +} + +/* + * The blkid_do_probe() backend. + */ +static int topology_probe(blkid_probe pr, struct blkid_chain *chn) +{ + size_t i; + + if (!pr || chn->idx < -1) + return -1; + + if (!S_ISBLK(pr->mode)) + return -EINVAL; /* nothing, works with block devices only */ + + if (chn->binary) { + DBG(LOWPROBE, ul_debug("initialize topology binary data")); + + if (chn->data) + /* reset binary data */ + memset(chn->data, 0, + sizeof(struct blkid_struct_topology)); + else { + chn->data = calloc(1, + sizeof(struct blkid_struct_topology)); + if (!chn->data) + return -ENOMEM; + } + } + + blkid_probe_chain_reset_vals(pr, chn); + + DBG(LOWPROBE, ul_debug("--> starting probing loop [TOPOLOGY idx=%d]", + chn->idx)); + + i = chn->idx < 0 ? 0 : chn->idx + 1U; + + for ( ; i < ARRAY_SIZE(idinfos); i++) { + const struct blkid_idinfo *id = idinfos[i]; + + chn->idx = i; + + if (id->probefunc) { + DBG(LOWPROBE, ul_debug("%s: call probefunc()", id->name)); + if (id->probefunc(pr, NULL) != 0) + continue; + } + + if (!topology_is_complete(pr)) + continue; + + /* generic for all probing drivers */ + topology_set_logical_sector_size(pr); + + DBG(LOWPROBE, ul_debug("<-- leaving probing loop (type=%s) [TOPOLOGY idx=%d]", + id->name, chn->idx)); + return BLKID_PROBE_OK; + } + + DBG(LOWPROBE, ul_debug("<-- leaving probing loop (failed) [TOPOLOGY idx=%d]", + chn->idx)); + return BLKID_PROBE_NONE; +} + +static void topology_free(blkid_probe pr __attribute__((__unused__)), + void *data) +{ + free(data); +} + +static int topology_set_value(blkid_probe pr, const char *name, + size_t structoff, unsigned long data) +{ + struct blkid_chain *chn = blkid_probe_get_chain(pr); + + if (!chn) + return -1; + if (!data) + return 0; /* ignore zeros */ + + if (chn->binary) { + memcpy(chn->data + structoff, &data, sizeof(data)); + return 0; + } + return blkid_probe_sprintf_value(pr, name, "%lu", data); +} + + +/* the topology info is complete when we have at least "minimum_io_size" which + * is provided by all blkid topology drivers */ +static int topology_is_complete(blkid_probe pr) +{ + struct blkid_chain *chn = blkid_probe_get_chain(pr); + + if (!chn) + return FALSE; + + if (chn->binary && chn->data) { + blkid_topology tp = (blkid_topology) chn->data; + if (tp->minimum_io_size) + return TRUE; + } + + return __blkid_probe_lookup_value(pr, "MINIMUM_IO_SIZE") ? TRUE : FALSE; +} + +int blkid_topology_set_alignment_offset(blkid_probe pr, int val) +{ + unsigned long xval; + + /* Welcome to Hell. The kernel is able to return -1 as an + * alignment_offset if no compatible sizes and alignments + * exist for stacked devices. + * + * There is no way how libblkid caller can respond to the value -1, so + * we will hide this corner case... + * + * (TODO: maybe we can export an extra boolean value 'misaligned' rather + * then complete hide this problem.) + */ + xval = val < 0 ? 0 : val; + + return topology_set_value(pr, + "ALIGNMENT_OFFSET", + offsetof(struct blkid_struct_topology, alignment_offset), + xval); +} + +int blkid_topology_set_minimum_io_size(blkid_probe pr, unsigned long val) +{ + return topology_set_value(pr, + "MINIMUM_IO_SIZE", + offsetof(struct blkid_struct_topology, minimum_io_size), + val); +} + +int blkid_topology_set_optimal_io_size(blkid_probe pr, unsigned long val) +{ + return topology_set_value(pr, + "OPTIMAL_IO_SIZE", + offsetof(struct blkid_struct_topology, optimal_io_size), + val); +} + +/* BLKSSZGET is provided on all systems since 2.3.3 -- so we don't have to + * waste time with sysfs. + */ +static int topology_set_logical_sector_size(blkid_probe pr) +{ + unsigned long val = blkid_probe_get_sectorsize(pr); + + if (!val) + return -1; + + return topology_set_value(pr, + "LOGICAL_SECTOR_SIZE", + offsetof(struct blkid_struct_topology, logical_sector_size), + val); +} + +int blkid_topology_set_physical_sector_size(blkid_probe pr, unsigned long val) +{ + return topology_set_value(pr, + "PHYSICAL_SECTOR_SIZE", + offsetof(struct blkid_struct_topology, physical_sector_size), + val); +} + +/** + * blkid_topology_get_alignment_offset: + * @tp: topology + * + * Returns: alignment offset in bytes or 0. + */ +unsigned long blkid_topology_get_alignment_offset(blkid_topology tp) +{ + return tp->alignment_offset; +} + +/** + * blkid_topology_get_minimum_io_size: + * @tp: topology + * + * Returns: minimum io size in bytes or 0. + */ +unsigned long blkid_topology_get_minimum_io_size(blkid_topology tp) +{ + return tp->minimum_io_size; +} + +/** + * blkid_topology_get_optimal_io_size + * @tp: topology + * + * Returns: optimal io size in bytes or 0. + */ +unsigned long blkid_topology_get_optimal_io_size(blkid_topology tp) +{ + return tp->optimal_io_size; +} + +/** + * blkid_topology_get_logical_sector_size + * @tp: topology + * + * Returns: logical sector size (BLKSSZGET ioctl) in bytes or 0. + */ +unsigned long blkid_topology_get_logical_sector_size(blkid_topology tp) +{ + return tp->logical_sector_size; +} + +/** + * blkid_topology_get_physical_sector_size + * @tp: topology + * + * Returns: logical sector size (BLKSSZGET ioctl) in bytes or 0. + */ +unsigned long blkid_topology_get_physical_sector_size(blkid_topology tp) +{ + return tp->physical_sector_size; +} + diff --git a/libblkid/src/topology/topology.h b/libblkid/src/topology/topology.h new file mode 100644 index 000000000..6d2f43345 --- /dev/null +++ b/libblkid/src/topology/topology.h @@ -0,0 +1,24 @@ +#ifndef BLKID_TOPOLOGY_H +#define BLKID_TOPOLOGY_H + +#include "blkidP.h" + +extern int blkid_topology_set_alignment_offset(blkid_probe pr, int val); +extern int blkid_topology_set_minimum_io_size(blkid_probe pr, unsigned long val); +extern int blkid_topology_set_optimal_io_size(blkid_probe pr, unsigned long val); +extern int blkid_topology_set_physical_sector_size(blkid_probe pr, unsigned long val); + +/* + * topology probers + */ +#ifdef __linux__ +extern const struct blkid_idinfo ioctl_tp_idinfo; +extern const struct blkid_idinfo md_tp_idinfo; +extern const struct blkid_idinfo evms_tp_idinfo; +extern const struct blkid_idinfo sysfs_tp_idinfo; +extern const struct blkid_idinfo dm_tp_idinfo; +extern const struct blkid_idinfo lvm_tp_idinfo; +#endif + +#endif /* BLKID_TOPOLOGY_H */ + |