From cc33d69328271f795e5b9ca7bd3f6500e0399acf Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Wed, 16 Sep 2009 14:40:41 +0200 Subject: [PATCH] libblkid: add topology support Signed-off-by: Karel Zak --- configure.ac | 1 + shlibs/blkid/src/Makefile.am | 7 +- shlibs/blkid/src/blkid.h | 19 ++ shlibs/blkid/src/blkid.sym | 5 + shlibs/blkid/src/blkidP.h | 4 +- shlibs/blkid/src/probe.c | 15 ++ shlibs/blkid/src/topology/Makefile.am | 7 + shlibs/blkid/src/topology/topology.c | 298 ++++++++++++++++++++++++++ 8 files changed, 353 insertions(+), 3 deletions(-) create mode 100644 shlibs/blkid/src/topology/Makefile.am create mode 100644 shlibs/blkid/src/topology/topology.c diff --git a/configure.ac b/configure.ac index 091d76b8..1c914d19 100644 --- a/configure.ac +++ b/configure.ac @@ -922,6 +922,7 @@ shlibs/blkid/blkid.pc shlibs/blkid/Makefile shlibs/blkid/src/Makefile shlibs/blkid/src/superblocks/Makefile +shlibs/blkid/src/topology/Makefile shlibs/uuid/uuid.pc shlibs/uuid/Makefile shlibs/uuid/man/Makefile diff --git a/shlibs/blkid/src/Makefile.am b/shlibs/blkid/src/Makefile.am index 10d1baa8..23a9161a 100644 --- a/shlibs/blkid/src/Makefile.am +++ b/shlibs/blkid/src/Makefile.am @@ -1,6 +1,6 @@ include $(top_srcdir)/config/include-Makefile.am -SUBDIRS = superblocks . +SUBDIRS = superblocks topology . common_ldadd = common_cflags = @@ -32,7 +32,10 @@ libblkid_la_SOURCES = cache.c dev.c devname.c devno.c getsize.c llseek.c \ $(top_srcdir)/lib/canonicalize.c \ $(top_srcdir)/lib/md5.c -libblkid_la_LIBADD = superblocks/libblkid_superblocks.la $(common_ldadd) +libblkid_la_LIBADD = superblocks/libblkid_superblocks.la \ + topology/libblkid_topology.la \ + $(common_ldadd) + libblkid_la_DEPENDENCIES = $(libblkid_la_LIBADD) blkid.sym libblkid_la_LDFLAGS = -Wl,--version-script=$(ul_libblkid_srcdir)/blkid.sym \ diff --git a/shlibs/blkid/src/blkid.h b/shlibs/blkid/src/blkid.h index 326c37ce..6549845d 100644 --- a/shlibs/blkid/src/blkid.h +++ b/shlibs/blkid/src/blkid.h @@ -34,6 +34,13 @@ typedef struct blkid_struct_dev *blkid_dev; typedef struct blkid_struct_cache *blkid_cache; typedef struct blkid_struct_probe *blkid_probe; +/** + * blkid_topology: + * + * device topology information + */ +typedef struct blkid_struct_topology *blkid_topology; + typedef int64_t blkid_loff_t; typedef struct blkid_struct_tag_iterate *blkid_tag_iterate; @@ -167,6 +174,18 @@ extern int blkid_probe_filter_superblocks_type(blkid_probe pr, int flag, char *n #define BLKID_USAGE_OTHER (1 << 4) extern int blkid_probe_filter_superblocks_usage(blkid_probe pr, int flag, int usage); +/* + * topology probing + */ +extern int blkid_probe_enable_topology(blkid_probe pr, int enable); + +/* binary interface */ +extern blkid_topology blkid_probe_get_topology(blkid_probe pr); + +extern unsigned long blkid_topology_get_alignment_offset(blkid_topology tp); +extern unsigned long blkid_topology_get_minimum_io_size(blkid_topology tp); +extern unsigned long blkid_topology_get_optimal_io_size(blkid_topology tp); + /* * NAME=value low-level interface */ diff --git a/shlibs/blkid/src/blkid.sym b/shlibs/blkid/src/blkid.sym index 4c2f1c2e..32ef6cac 100644 --- a/shlibs/blkid/src/blkid.sym +++ b/shlibs/blkid/src/blkid.sym @@ -74,12 +74,17 @@ global: blkid_devno_to_wholedisk; blkid_do_fullprobe; blkid_probe_enable_superblocks; + blkid_probe_enable_topology; blkid_probe_filter_superblocks_type; blkid_probe_filter_superblocks_usage; blkid_probe_get_devno; blkid_probe_get_sectorsize; blkid_probe_get_size; + blkid_probe_get_topology; blkid_probe_invert_superblocks_filter; blkid_probe_reset_superblocks_filter; blkid_probe_set_superblocks_flags; + blkid_topology_get_alignment_offset; + blkid_topology_get_minimum_io_size; + blkid_topology_get_optimal_io_size; } BLKID_2.15; diff --git a/shlibs/blkid/src/blkidP.h b/shlibs/blkid/src/blkidP.h index c5617044..d590cd9d 100644 --- a/shlibs/blkid/src/blkidP.h +++ b/shlibs/blkid/src/blkidP.h @@ -91,7 +91,7 @@ typedef struct blkid_struct_tag *blkid_tag; */ enum { BLKID_CHAIN_SUBLKS, /* FS/RAID superblocks (enabled by default) */ -/* BLKID_CHAIN_TOPLGY, Block device topology */ + BLKID_CHAIN_TOPLGY, /* Block device topology */ /* BLKID_CHAIN_PARTS, Partition tables */ BLKID_NCHAINS /* number of chains */ @@ -407,6 +407,8 @@ extern int blkid_probe_set_value(blkid_probe pr, const char *name, unsigned char *data, size_t len); extern int blkid_probe_vsprintf_value(blkid_probe pr, const char *name, const char *fmt, va_list ap); +extern int blkid_probe_sprintf_value(blkid_probe pr, const char *name, + const char *fmt, ...); extern void blkid_unparse_uuid(const unsigned char *uuid, char *str, size_t len); diff --git a/shlibs/blkid/src/probe.c b/shlibs/blkid/src/probe.c index d4662322..beda26a2 100644 --- a/shlibs/blkid/src/probe.c +++ b/shlibs/blkid/src/probe.c @@ -97,12 +97,14 @@ /* chains */ extern const struct blkid_chaindrv superblocks_drv; +extern const struct blkid_chaindrv topology_drv; /* * All supported chains */ static const struct blkid_chaindrv *chains_drvs[] = { [BLKID_CHAIN_SUBLKS] = &superblocks_drv, + [BLKID_CHAIN_TOPLGY] = &topology_drv, }; static void blkid_probe_reset_vals(blkid_probe pr); @@ -808,6 +810,19 @@ int blkid_probe_vsprintf_value(blkid_probe pr, const char *name, return 0; } +int blkid_probe_sprintf_value(blkid_probe pr, const char *name, + const char *fmt, ...) +{ + int rc; + va_list ap; + + va_start(ap, fmt); + rc = blkid_probe_vsprintf_value(pr, name, fmt, ap); + va_end(ap); + + return rc; +} + /** * blkid_probe_get_devno: * @pr: probe diff --git a/shlibs/blkid/src/topology/Makefile.am b/shlibs/blkid/src/topology/Makefile.am new file mode 100644 index 00000000..9ba10e4d --- /dev/null +++ b/shlibs/blkid/src/topology/Makefile.am @@ -0,0 +1,7 @@ +include $(top_srcdir)/config/include-Makefile.am + +AM_CPPFLAGS += -I$(ul_libblkid_srcdir) +libblkid_topology_la_LIBADD = + +noinst_LTLIBRARIES = libblkid_topology.la +libblkid_topology_la_SOURCES = topology.c diff --git a/shlibs/blkid/src/topology/topology.c b/shlibs/blkid/src/topology/topology.c new file mode 100644 index 00000000..8ebd5b08 --- /dev/null +++ b/shlibs/blkid/src/topology/topology.c @@ -0,0 +1,298 @@ +/* + * 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. + * + * NOTE: this chain supports one probing method only, so it's implemented + * without array of probing functions (idinfos array). + * + * This chain does not support probing functions filtering. The chain + * could be enable or disabled only. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "blkdev.h" +#include "blkidP.h" + +/** + * SECTION:topology + * @title: Topology information + * @short_description: block device tolology information. + * + * The tolology 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: + * + * @MINIMUM_IO_SIZE: minimum size which is the device's preferred unit of I/O + * + * @OPTIMAL_IO_SIZE: usually the stripe width for RAID or zero + * + * @ALIGNMENT_OFFSET: indicates how many bytes the beginning o the device is + * offset from the disk's natural alignment. + * + * Binary interface: + * + * blkid_probe_get_tolology() + * + * blkid_topology_get_'VALUENAME'() + */ +static int topology_probe(blkid_probe pr, struct blkid_chain *chn); +static void topology_free(blkid_probe pr, void *data); + +/* + * Driver definition + */ +const struct blkid_chaindrv topology_drv = { + .id = BLKID_CHAIN_TOPLGY, + .name = "topology", + .dflt_enabled = FALSE, + .probe = topology_probe, + .safeprobe = topology_probe, + .free_data = topology_free +}; + +/* + * Binary interface + */ +struct blkid_struct_topology { + unsigned long alignment_offset; + unsigned long minimum_io_size; + unsigned long optimal_io_size; +}; + +/** + * 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. + * + * Returns: blkid_tolopogy, 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]); +} + +static unsigned long +dev_topology_attribute(const char *attribute, dev_t dev, dev_t *primary) +{ + const char *sysfs_fmt_str = "/sys/dev/block/%d:%d/%s"; + char path[PATH_MAX]; + int len; + FILE *fp = NULL; + struct stat info; + unsigned long result = 0UL; + + len = snprintf(path, sizeof(path), sysfs_fmt_str, + major(dev), minor(dev), attribute); + if (len < 0 || len + 1 > sizeof(path)) + goto err; + + /* + * check if the desired sysfs attribute exists + * - if not: either the kernel doesn't have topology support or the + * device could be a partition + */ + if (stat(path, &info) < 0) { + if (!*primary && + blkid_devno_to_wholedisk(dev, NULL, 0, primary)) + goto err; + + /* get attribute from partition's primary device */ + len = snprintf(path, sizeof(path), sysfs_fmt_str, + major(*primary), minor(*primary), attribute); + if (len < 0 || len + 1 > sizeof(path)) + goto err; + } + + fp = fopen(path, "r"); + if (!fp) { + DBG(DEBUG_LOWPROBE, printf( + "topology: %s: fopen failed, errno=%d\n", path, errno)); + goto err; + } + + if (fscanf(fp, "%lu", &result) != 1) { + DBG(DEBUG_LOWPROBE, printf( + "topology: %s: unexpected file format\n", path)); + goto err; + } + + fclose(fp); + + DBG(DEBUG_LOWPROBE, + printf("topology: attribute %s = %lu (sectors)\n", attribute, result)); + + return result * DEFAULT_SECTOR_SIZE; +err: + if (fp) + fclose(fp); + DBG(DEBUG_LOWPROBE, + printf("topology: failed to read %s attribute\n", attribute)); + return 0; +} + +/* + * Topology values + */ +static struct topology_val { + const char *val_name; /* NAME=value */ + const char *sysfs_name; /* /sys/dev/block/:/NAME */ + const size_t bin_offset; /* blkid_struct_topology member */ +} topology_vals[] = { + { "ALIGNMENT_OFFSET", "alignment_offset", + offsetof(struct blkid_struct_topology, alignment_offset) }, + { "MINIMUM_IO_SIZE", "queue/minimum_io_size", + offsetof(struct blkid_struct_topology, minimum_io_size) }, + {"OPTIMAL_IO_SIZE", "queue/optimal_io_size", + offsetof(struct blkid_struct_topology, optimal_io_size) } +}; + +static int topology_set_value(blkid_probe pr, struct blkid_chain *chn, + struct topology_val *val, unsigned long data) +{ + if (chn->binary) { + unsigned long *v = + (unsigned long *) (chn->data + val->bin_offset); + *v = data; + return 0; + } + return blkid_probe_sprintf_value(pr, val->val_name, "%llu", data); +} + +/* + * The blkid_do_probe() backend. + */ +static int topology_probe(blkid_probe pr, struct blkid_chain *chn) +{ + dev_t dev, pri_dev = 0; + int i, rc = 0, count = 0; + + if (!pr) + return -1; + + blkid_probe_chain_reset_vals(pr, chn); + + dev = blkid_probe_get_devno(pr); + if (!dev) + return 1; /* no result */ + + if (chn->binary) { + DBG(DEBUG_LOWPROBE, printf("initialize topology binary data\n")); + + 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 -1; + } + } + + DBG(DEBUG_LOWPROBE, printf("--> starting probing loop [TOPOLOGY]\n")); + + for (i = 0; i < ARRAY_SIZE(topology_vals); i++) { + struct topology_val *val = &topology_vals[i]; + unsigned long data; + + /* + * Don't bother reporting any of the topology information + * if it's zero. + */ + data = dev_topology_attribute(val->sysfs_name, dev, &pri_dev); + if (!data) + continue; + + rc = topology_set_value(pr, chn, val, data); + if (rc) + break; /* error */ + count++; + } + + + if (rc == 0 && count == 0) + rc = 1; /* no result */ + + DBG(DEBUG_LOWPROBE, + printf("<-- leaving probing loop [TOPOLOGY, rc=%d]\n", rc)); + return rc; +} + +static void topology_free(blkid_probe pr, void *data) +{ + free(data); +} + +/** + * 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 ? tp->alignment_offset : 0; +} + +/** + * 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 ? tp->minimum_io_size : 0; +} + +/** + * 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 ? tp->optimal_io_size : 0; +} + -- 2.39.5