lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Wed, 14 Apr 2010 22:46:47 -0700
From:	Divyesh Shah <dpshah@...gle.com>
To:	jens.axboe@...cle.com
Cc:	linux-kernel@...r.kernel.org, nauman@...gle.com, rickyb@...gle.com
Subject: [PATCH 4/4] block: Make base bucket for the histograms configurable

Signed-off-by: Divyesh Shah<dpshah@...gle.com>
---

 block/genhd.c         |   87 ++++++++++++++++++++++++++++++++++++++++++-------
 fs/partitions/check.c |    9 +++++
 include/linux/genhd.h |   19 +++++++++--
 3 files changed, 99 insertions(+), 16 deletions(-)

diff --git a/block/genhd.c b/block/genhd.c
index 8920994..c2ba04b 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -892,6 +892,12 @@ static DEVICE_ATTR(write_dma_histo, S_IRUGO | S_IWUSR,
 		part_write_dma_histo_show, part_write_histo_clear);
 static DEVICE_ATTR(seek_histo, S_IRUGO | S_IWUSR,
 		part_seek_histo_show, part_seek_histo_clear);
+static DEVICE_ATTR(base_histo_size, S_IRUGO | S_IWUSR,
+		part_base_histo_size_show, part_base_histo_size_write);
+static DEVICE_ATTR(base_histo_time, S_IRUGO | S_IWUSR,
+		part_base_histo_time_show, part_base_histo_time_write);
+static DEVICE_ATTR(base_histo_seek, S_IRUGO | S_IWUSR,
+		part_base_histo_seek_show, part_base_histo_seek_write);
 #endif
 #ifdef CONFIG_FAIL_MAKE_REQUEST
 static struct device_attribute dev_attr_fail =
@@ -920,6 +926,9 @@ static struct attribute *disk_attrs[] = {
 	&dev_attr_write_request_histo.attr,
 	&dev_attr_write_dma_histo.attr,
 	&dev_attr_seek_histo.attr,
+	&dev_attr_base_histo_size.attr,
+	&dev_attr_base_histo_time.attr,
+	&dev_attr_base_histo_seek.attr,
 #endif
 #ifdef CONFIG_FAIL_MAKE_REQUEST
 	&dev_attr_fail.attr,
@@ -1206,6 +1215,7 @@ struct gendisk *alloc_disk_node(int minors, int node_id)
 			return NULL;
 		}
 		disk->part_tbl->part[0] = &disk->part0;
+		init_part_histo_defaults(&disk->part0);
 
 		disk->minors = minors;
 		rand_initialize_disk(disk);
@@ -1307,6 +1317,13 @@ int invalidate_partition(struct gendisk *disk, int partno)
 EXPORT_SYMBOL(invalidate_partition);
 
 #ifdef	CONFIG_BLOCK_HISTOGRAM
+/* Smallest transfer size identifiable (in sectors) by histograms. */
+static const int base_histo_size = 4;
+/* Smallest transfer time identifiable (in ms) by histograms. */
+static const int base_histo_time = 10;
+/* Smallest seek distance identifiable (in log base 2 sectors). */
+static const int base_histo_seek = 3;
+
 typedef void (part_histo_reset) (struct disk_stats *, int);
 
 /*
@@ -1371,18 +1388,22 @@ static int block_disk_histogram_reset(struct hd_struct *part,
 void init_part_histo_defaults(struct hd_struct *part)
 {
 	part->last_end_sector = part->start_sect;
+	part->base_histo_size = base_histo_size;
+	part->base_histo_time = base_histo_time;
+	part->base_histo_seek = base_histo_seek;
 }
 
 /*
  * Map transfer size to histogram bucket. Transfer sizes are exponentially
  * increasing. For example: 4,8,16,... sectors.
  */
-static inline int stats_size_bucket(sector_t sectors)
+static inline int stats_size_bucket(sector_t sectors, int base_histo_size)
 {
 	int i;
 	/* To make sure bucket for x bytes captures all IOs <= x bytes. */
 	--sectors;
-	do_div(sectors, BASE_HISTO_SIZE);
+	BUG_ON(!base_histo_size);
+	do_div(sectors, base_histo_size);
 	if (sectors >= (1 << (CONFIG_HISTO_SIZE_BUCKETS - 2)))
 		return CONFIG_HISTO_SIZE_BUCKETS - 1;
 
@@ -1395,11 +1416,11 @@ static inline int stats_size_bucket(sector_t sectors)
  * Map transfer time to histogram bucket. This also uses an exponential
  * increment, but we like the 1,2,5,10,20,50 progression.
  */
-static inline int stats_time_bucket(int jiffies)
+static inline int stats_time_bucket(int jiffies, int base_histo_time)
 {
 	int i;
 	int ms = msecs_to_jiffies(jiffies);
-	int t = BASE_HISTO_TIME;
+	int t = base_histo_time;
 
 	for (i = 0;; t *= 10) {
 		if (++i >= CONFIG_HISTO_TIME_BUCKETS || ms <= t)
@@ -1415,9 +1436,10 @@ static inline int stats_time_bucket(int jiffies)
  * Map seek distance to histogram bucket. This also uses an exponential
  * increment : 8, 16, 32, ... sectors.
  */
-static inline int stats_seek_bucket(sector_t distance)
+static inline int stats_seek_bucket(sector_t distance, int base_histo_seek)
 {
-	return min(fls64(distance >> 3), CONFIG_HISTO_SEEK_BUCKETS);
+	return min(fls64(distance >> base_histo_seek),
+			CONFIG_HISTO_SEEK_BUCKETS);
 }
 
 /*
@@ -1433,16 +1455,17 @@ static inline void __block_histogram_completion(int cpu, struct hd_struct *part,
 {
 	sector_t sectors = blk_rq_size(req), end_sector = blk_rq_pos(req);
 	sector_t distance, start_sector = end_sector - sectors;
-	int size_idx = stats_size_bucket(sectors);
-	int req_time_idx = stats_time_bucket(req_ms);
-	int dma_time_idx = stats_time_bucket(dma_ms);
+	int size_idx = stats_size_bucket(sectors, part->base_histo_size);
+	int req_time_idx = stats_time_bucket(req_ms, part->base_histo_time);
+	int dma_time_idx = stats_time_bucket(dma_ms, part->base_histo_time);
 
 	if (start_sector >= part->last_end_sector)
 		distance = start_sector - part->last_end_sector;
 	else
 		distance = part->last_end_sector - start_sector;
 
-	part_stat_inc(cpu, part, seek_histo[stats_seek_bucket(distance)]);
+	part_stat_inc(cpu, part, seek_histo[stats_seek_bucket(distance,
+						      part->base_histo_seek)]);
 	part->last_end_sector = end_sector;
 
 	if (!rq_data_dir(req))
@@ -1502,7 +1525,7 @@ static int dump_histo(struct hd_struct *part, int direction, int type,
 {
 	ssize_t	rem = PAGE_SIZE;
 	char *optr = page;
-	int i, j, len, ms, size = BASE_HISTO_SIZE * 512;
+	int i, j, len, ms, size = part->base_histo_size * 512;
 	static const int mults[3] = {1, 2, 5};
 
 	/*
@@ -1515,7 +1538,7 @@ static int dump_histo(struct hd_struct *part, int direction, int type,
 	len = snprintf(page, rem, "       ");
 	page += len;
 	rem -= len;
-	for (i = 0, ms = BASE_HISTO_TIME; i < CONFIG_HISTO_TIME_BUCKETS;
+	for (i = 0, ms = part->base_histo_time; i < CONFIG_HISTO_TIME_BUCKETS;
 		ms *= 10) {
 		for (j = 0; j < 3 && i < CONFIG_HISTO_TIME_BUCKETS; ++j, ++i) {
 			len = snprintf(page, rem, "\t%d", ms * mults[j]);
@@ -1557,7 +1580,8 @@ static int dump_seek_histo(struct hd_struct *part, char* page)
 	for (i = 0; i < CONFIG_HISTO_SEEK_BUCKETS + 1; i++) {
 		if (i < CONFIG_HISTO_SEEK_BUCKETS)
 			len = snprintf(page, rem, "%ld\t%llu\n",
-				1UL << (i + 3), seek_histo_stat_read(part, i));
+				1UL << (i + part->base_histo_seek),
+				seek_histo_stat_read(part, i));
 		else
 			len = snprintf(page, rem, "inf\t%llu\n",
 					seek_histo_stat_read(part, i));
@@ -1634,4 +1658,41 @@ ssize_t part_seek_histo_clear(struct device *dev,
 	return (retval == 0 ? count : retval);
 }
 
+#define SHOW_BASE_FUNCTION(__VAR)					\
+ssize_t part_##__VAR##_show(struct device *dev,				\
+			struct device_attribute *attr, char *page)	\
+{									\
+	struct hd_struct *part = dev_to_part(dev);			\
+									\
+	return sprintf(page, "%d\n", part->__VAR);			\
+}
+
+SHOW_BASE_FUNCTION(base_histo_size);
+SHOW_BASE_FUNCTION(base_histo_time);
+SHOW_BASE_FUNCTION(base_histo_seek);
+#undef SHOW_BASE_FUNCTION
+
+#define WRITE_BASE_FUNCTION(__VAR, MIN, reset_fn)			\
+ssize_t part_##__VAR##_write(struct device *dev,			\
+	struct device_attribute *attr, const char *page, size_t count)	\
+{									\
+	struct hd_struct *part = dev_to_part(dev);			\
+	char *p = (char *)page;						\
+	unsigned long __data;						\
+	int data, retval = strict_strtoul(p, 10, &__data);		\
+									\
+	if (retval)							\
+		return retval;						\
+	data = __data;							\
+	part->__VAR = max(data, MIN);					\
+	block_disk_histogram_reset(part, reset_fn, READ);		\
+	block_disk_histogram_reset(part, reset_fn, WRITE);		\
+	return count;							\
+}
+
+WRITE_BASE_FUNCTION(base_histo_size, 1, __block_part_histogram_reset);
+WRITE_BASE_FUNCTION(base_histo_time, 1, __block_part_histogram_reset);
+WRITE_BASE_FUNCTION(base_histo_seek, 1, __block_part_seek_histogram_reset);
+#undef WRITE_BASE_FUNCTION
+
 #endif
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 47e2591..ddc0262 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -311,6 +311,12 @@ static DEVICE_ATTR(write_dma_histo, S_IRUGO | S_IWUSR,
 		part_write_dma_histo_show, part_write_histo_clear);
 static DEVICE_ATTR(seek_histo, S_IRUGO | S_IWUSR,
 		part_seek_histo_show, part_seek_histo_clear);
+static DEVICE_ATTR(base_histo_size, S_IRUGO | S_IWUSR,
+		part_base_histo_size_show, part_base_histo_size_write);
+static DEVICE_ATTR(base_histo_time, S_IRUGO | S_IWUSR,
+		part_base_histo_time_show, part_base_histo_time_write);
+static DEVICE_ATTR(base_histo_seek, S_IRUGO | S_IWUSR,
+		part_base_histo_seek_show, part_base_histo_seek_write);
 #endif
 #ifdef CONFIG_FAIL_MAKE_REQUEST
 static struct device_attribute dev_attr_fail =
@@ -331,6 +337,9 @@ static struct attribute *part_attrs[] = {
 	&dev_attr_write_request_histo.attr,
 	&dev_attr_write_dma_histo.attr,
 	&dev_attr_seek_histo.attr,
+	&dev_attr_base_histo_size.attr,
+	&dev_attr_base_histo_time.attr,
+	&dev_attr_base_histo_seek.attr,
 #endif
 #ifdef CONFIG_FAIL_MAKE_REQUEST
 	&dev_attr_fail.attr,
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index 746b36b..b64d983 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -80,9 +80,6 @@ struct partition {
 	__le32 nr_sects;		/* nr of sectors in partition */
 } __attribute__((packed));
 
-#define	BASE_HISTO_SIZE		4	/* smallest transfer size, sectors */
-#define	BASE_HISTO_TIME		10	/* shortest transfer time, ms */
-
 /* Index into the histo arrays */
 #define HISTO_REQUEST   0
 #define HISTO_DMA       1
@@ -135,6 +132,9 @@ struct hd_struct {
 #endif
 #ifdef CONFIG_BLOCK_HISTOGRAM
 	sector_t last_end_sector;
+	int base_histo_size;
+	int base_histo_time;
+	int base_histo_seek;
 #endif
 	struct rcu_head rcu_head;
 };
@@ -414,6 +414,19 @@ extern ssize_t part_seek_histo_clear(struct device *dev,
 		struct device_attribute *attr, const char *page, size_t count);
 
 extern void init_part_histo_defaults(struct hd_struct *part);
+
+extern ssize_t part_base_histo_size_show(struct device *dev,
+			struct device_attribute *attr, char *page);
+extern ssize_t part_base_histo_time_show(struct device *dev,
+			struct device_attribute *attr, char *page);
+extern ssize_t part_base_histo_seek_show(struct device *dev,
+			struct device_attribute *attr, char *page);
+extern ssize_t part_base_histo_size_write(struct device *dev,
+		struct device_attribute *attr, const char *page, size_t count);
+extern ssize_t part_base_histo_time_write(struct device *dev,
+		struct device_attribute *attr, const char *page, size_t count);
+extern ssize_t part_base_histo_seek_write(struct device *dev,
+		struct device_attribute *attr, const char *page, size_t count);
 #else
 static inline void block_histogram_completion(int cpu, struct hd_struct *part,
 						struct request *req) {}

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ