]> err.no Git - util-linux/commitdiff
libblkid: add topology support
authorKarel Zak <kzak@redhat.com>
Wed, 16 Sep 2009 12:40:41 +0000 (14:40 +0200)
committerKarel Zak <kzak@redhat.com>
Wed, 16 Sep 2009 12:40:41 +0000 (14:40 +0200)
Signed-off-by: Karel Zak <kzak@redhat.com>
configure.ac
shlibs/blkid/src/Makefile.am
shlibs/blkid/src/blkid.h
shlibs/blkid/src/blkid.sym
shlibs/blkid/src/blkidP.h
shlibs/blkid/src/probe.c
shlibs/blkid/src/topology/Makefile.am [new file with mode: 0644]
shlibs/blkid/src/topology/topology.c [new file with mode: 0644]

index 091d76b8a4e04688279d18a746b329eba6642742..1c914d1935d6611387edefe6aea7d25bd83cabff 100644 (file)
@@ -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
index 10d1baa8ca34e5b63fecce762d5f32bf0e21637b..23a9161a8aa8d08b6530170bf72c20ae06af68ef 100644 (file)
@@ -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 \
index 326c37ce17fcfa71f158577d45047686dba14132..6549845d4083b112cc252ab0cea1fe254372359b 100644 (file)
@@ -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
  */
index 4c2f1c2e295f4e237945eecf37491fc35bbb6a6b..32ef6cacef43fcd90d59482ef02900a252aab2c3 100644 (file)
@@ -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;
index c5617044bcd0a5e3617e40ac3815f0604759cb8d..d590cd9d90099ad8f6b06dbf8d9cb69880d84bde 100644 (file)
@@ -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);
 
index d466232272d28f1d1f91c51c35250bc917859d85..beda26a2629ff6bd2eb4dce37b24f79653a562a9 100644 (file)
 
 /* 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 (file)
index 0000000..9ba10e4
--- /dev/null
@@ -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 (file)
index 0000000..8ebd5b0
--- /dev/null
@@ -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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#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/<maj>:<min>/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;
+}
+