[PATCH, RFC] libblkid: start adding I/O topology support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch is a first draft at adding support for the sysfs I/O
topologies exported by kernels 2.6.30 or newer.  The parsing code is
taken straight from patches that Mike Snitzer sent to the LVM list.

Right now we only add the attributes to the tags, as a demonstration
how it this can be embedded into libblkid.  Unfortunately that means
it's not available unless we actually have a filesystem/raid/volume
created on a device, which makes it useless for tools creating
filesystem or volumes, which would be the primary user of this
information.  We will have to add lowlevel probing functions for these
tools which could also return the information in binary format
instead of having to go to and back from ASCII for the tagged format.

I'm not entirely sure how such APIs would fit into the blkid library
design, e.g, should be pass a blkid_probe argument to it which would
be overkill or just a plain dev_t or path?


Index: util-linux-ng/shlibs/blkid/src/Makefile.am
===================================================================
--- util-linux-ng.orig/shlibs/blkid/src/Makefile.am	2009-07-20 00:24:58.770922580 +0200
+++ util-linux-ng/shlibs/blkid/src/Makefile.am	2009-07-20 00:25:23.483194577 +0200
@@ -25,7 +25,7 @@ usrlib_exec_LTLIBRARIES = libblkid.la
 libblkid_la_SOURCES = cache.c dev.c devname.c devno.c getsize.c llseek.c  \
 		     probe.c read.c resolve.c save.c tag.c version.c verify.c \
 		     encode.c blkid.h list.h blkidP.h probers/probers.h \
-		     config.c evaluate.c \
+		     config.c evaluate.c topology.c \
 		     $(blkidinc_HEADERS) \
 		     $(top_srcdir)/lib/blkdev.c \
 		     $(top_srcdir)/lib/linux_version.c \
Index: util-linux-ng/shlibs/blkid/src/blkidP.h
===================================================================
--- util-linux-ng.orig/shlibs/blkid/src/blkidP.h	2009-07-20 00:24:58.775898703 +0200
+++ util-linux-ng/shlibs/blkid/src/blkidP.h	2009-07-20 00:25:23.484172425 +0200
@@ -341,4 +341,7 @@ extern int blkid_probe_set_uuid_as(blkid
 #define BLKID_ENC_UTF16BE	0
 #define BLKID_ENC_UTF16LE	1
 
+/* topology.c */
+extern void blkid_set_topology_tags(blkid_dev dev);
+
 #endif /* _BLKID_BLKIDP_H */
Index: util-linux-ng/shlibs/blkid/src/topology.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ util-linux-ng/shlibs/blkid/src/topology.c	2009-07-20 00:25:32.802900903 +0200
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2009 Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <libgen.h>
+#include <limits.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "blkidP.h"
+
+#define SECTOR_SIZE 512L
+
+
+static int get_primary_dev(dev_t dev, dev_t *result)
+{
+	char path[PATH_MAX+1];
+	char temp_path[PATH_MAX+1];
+	char buffer[64];
+	struct stat info;
+	FILE *fp;
+	int pri_maj, pri_min;
+	int len;
+
+	/* check if dev is a partition */
+	len = snprintf(path, PATH_MAX, "/sys/dev/block/%d:%d/partition",
+			major(dev), minor(dev));
+	if (len < 0 || ((unsigned) len + 1 > PATH_MAX)) {
+		fprintf(stderr, "snprintf partition failed");
+		return 0;
+	}
+
+	if (stat(path, &info) < 0)
+		return 0;
+
+	/*
+	 * extract parent's path from the partition's symlink, e.g.:
+	 * - readlink /sys/dev/block/259:0 = ../../block/md0/md0p1
+	 * - dirname ../../block/md0/md0p1 = ../../block/md0
+	 * - basename ../../block/md0/md0  = md0
+	 * Parent's 'dev' sysfs attribute  = /sys/block/md0/dev
+	 */
+	if (readlink(dirname(path), temp_path, PATH_MAX) < 0) {
+		perror("readlink");
+		return 0;
+	}
+
+	len = snprintf(path, PATH_MAX, "/sys/block/%s/dev",
+			basename(dirname(temp_path)));
+	if (len < 0 || ((unsigned) len + 1 > PATH_MAX)) {
+		perror("snprintf");
+		return 0;
+	}
+
+	/* finally, parse 'dev' attribute and create corresponding dev_t */
+	if (stat(path, &info) < 0) {
+		fprintf(stderr, "sysfs file %s does not exist", path);
+		return 0;
+	}
+
+	fp = fopen(path, "r");
+	if (!fp) {
+		perror("fopen");
+		return 0;
+	}
+
+	if (!fgets(buffer, sizeof(buffer), fp)) {
+		perror("fgets");
+		goto out;
+	}
+
+	if (sscanf(buffer, "%d:%d", &pri_maj, &pri_min) != 2) {
+		fprintf(stderr, "sysfs file %s not in expected MAJ:MIN format: %s",
+			  path, buffer);
+		goto out;
+	}
+	*result = makedev(pri_maj, pri_min);
+	fclose(fp);
+	return 1;
+
+out:
+	fclose(fp);
+	return 0;
+ }
+
+static unsigned long
+dev_topology_attribute(const char *attribute, dev_t dev)
+{
+	const char *sysfs_fmt_str = "/sys/dev/block/%d:%d/%s";
+	char path[PATH_MAX+1], buffer[64];
+	int len;
+	FILE *fp;
+	struct stat info;
+	unsigned long result = 0UL;
+
+	len = snprintf(path, PATH_MAX, sysfs_fmt_str,
+		       major(dev), minor(dev), attribute);
+	if (len < 0 || ((unsigned) len + 1 > PATH_MAX)) {
+		fprintf(stderr, "snprintf %s failed", attribute);
+		return 0;
+	}
+
+	/*
+	 * 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) {
+		dev_t primary;
+
+		if (!get_primary_dev(dev, &primary))
+			return 0;
+
+		/* get attribute from partition's primary device */
+		len = snprintf(path, PATH_MAX, sysfs_fmt_str,
+					major(primary), minor(primary),
+					attribute);
+		if (len < 0 || ((unsigned) len + 1 > PATH_MAX)) {
+			fprintf(stderr, "pri dm_snprintf %s failed", attribute);
+			return 0;
+		}
+		if (stat(path, &info) < 0) {
+			fprintf(stderr, "Can't stat primary device %s\n",
+				path);
+			return 0;
+		}
+	}
+
+	fp = fopen(path, "r");
+	if (!fp) {
+		if (errno != ENOENT)
+			perror("fopen");
+		return 0;
+	}
+
+	if (!fgets(buffer, sizeof(buffer), fp)) {
+		perror("fgets");
+		goto out;
+	}
+
+	if (sscanf(buffer, "%lu", &result) != 1) {
+		fprintf(stderr, "sysfs file %s not in expected format: %s", path,
+			  buffer);
+		goto out;
+	}
+
+out:
+	fclose(fp);
+
+	return result * SECTOR_SIZE;
+}
+
+static struct blkid_topology_tag {
+	const char *tag_name;
+	const char *sysfs_name;
+} blkid_topology_tags[] = {
+	{ "ALIGNMENT_OFFSET",	"alignment_offset" },
+	{ "MINIMUM_IO_SIZE",	"queue/minimum_io_size" },
+	{ "OPTIMAL_IO_SIZE",	"queue/optimal_io_size" },
+};
+
+void blkid_set_topology_tags(blkid_dev dev)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(blkid_topology_tags); i++) {
+		struct blkid_topology_tag *tag = &blkid_topology_tags[i];
+		unsigned long val;
+		char buf[64];
+		size_t len;
+
+		/*
+		 * Don't bother reporting any of the topology information
+		 * if it's zero.
+		 */
+		val = dev_topology_attribute(tag->sysfs_name, dev->bid_devno);
+		if (!val)
+			continue;
+
+		len = snprintf(buf, 64, "%ld", val);
+		if (len < 0 || ((unsigned) len + 1 > 64))
+			continue;
+
+		blkid_set_tag(dev, tag->tag_name, buf, len);
+	}
+}
Index: util-linux-ng/shlibs/blkid/src/verify.c
===================================================================
--- util-linux-ng.orig/shlibs/blkid/src/verify.c	2009-07-20 00:24:58.823149278 +0200
+++ util-linux-ng/shlibs/blkid/src/verify.c	2009-07-20 00:25:23.489920923 +0200
@@ -150,6 +150,7 @@ blkid_dev blkid_verify(blkid_cache cache
 found_type:
 	if (dev) {
 		dev->bid_devno = st.st_rdev;
+		blkid_set_topology_tags(dev);
 		dev->bid_time = time(0);
 		dev->bid_flags |= BLKID_BID_FL_VERIFIED;
 		cache->bic_flags |= BLKID_BIC_FL_CHANGED;
--
To unsubscribe from this list: send the line "unsubscribe util-linux-ng" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux