[PATCH 5/7] blk-mq: Only allocate request stat data when it is enabled

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

 



From: Jes Sorensen <jsorensen@xxxxxx>

This reduces the data used for request stats to two pointers in
struct request_queue, when this is not enabled.

Signed-off-by: Jes Sorensen <jsorensen@xxxxxx>
---
 block/blk-mq.c         | 20 ++++++++++----------
 block/blk-stat.h       |  2 ++
 block/blk-sysfs.c      | 36 ++++++++++++++++++++++++++++++++----
 include/linux/blkdev.h |  2 +-
 4 files changed, 45 insertions(+), 15 deletions(-)

diff --git a/block/blk-mq.c b/block/blk-mq.c
index 4aff0903546c..04652e59b0e9 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -63,7 +63,7 @@ static int blk_mq_poll_stats_bkt(const struct request *rq)
 /*
  * 8 buckets for each of read, write, and discard
  */
-static int blk_req_stats_bkt(const struct request *rq)
+int blk_req_stats_bkt(const struct request *rq)
 {
 	int grp, bucket;
 
@@ -82,7 +82,7 @@ static int blk_req_stats_bkt(const struct request *rq)
 /*
  * Copy out the stats to their official location
  */
-static void blk_req_stats_cb(struct blk_stat_callback *cb)
+void blk_req_stats_cb(struct blk_stat_callback *cb)
 {
 	struct request_queue *q = cb->data;
 	int bucket;
@@ -102,8 +102,14 @@ static void blk_req_stats_cb(struct blk_stat_callback *cb)
 
 void blk_req_stats_free(struct request_queue *q)
 {
-	blk_stat_remove_callback(q, q->reqstat_cb);
-	blk_stat_free_callback(q->reqstat_cb);
+	if (test_bit(QUEUE_FLAG_REQSTATS, &q->queue_flags)) {
+		blk_stat_remove_callback(q, q->reqstat_cb);
+		blk_queue_flag_clear(QUEUE_FLAG_REQSTATS, q);
+		blk_stat_free_callback(q->reqstat_cb);
+		q->reqstat_cb = NULL;
+		kfree(q->req_stat);
+		q->req_stat = NULL;
+	}
 }
 
 /*
@@ -2956,12 +2962,6 @@ struct request_queue *blk_mq_init_allocated_queue(struct blk_mq_tag_set *set,
 	if (!q->nr_hw_queues)
 		goto err_hctxs;
 
-	q->reqstat_cb = blk_stat_alloc_callback(blk_req_stats_cb,
-						blk_req_stats_bkt,
-						BLK_REQ_STATS_BKTS, q);
-	if (!q->reqstat_cb)
-		goto err_hctxs;
-
 	INIT_WORK(&q->timeout_work, blk_mq_timeout_work);
 	blk_queue_rq_timeout(q, set->timeout ? set->timeout : 30 * HZ);
 
diff --git a/block/blk-stat.h b/block/blk-stat.h
index e592bbf50d38..d23090b53e12 100644
--- a/block/blk-stat.h
+++ b/block/blk-stat.h
@@ -168,5 +168,7 @@ void blk_rq_stat_add(struct blk_rq_stat *, u64, u64);
 void blk_rq_stat_sum(struct blk_rq_stat *, struct blk_rq_stat *);
 void blk_rq_stat_init(struct blk_rq_stat *);
 
+int blk_req_stats_bkt(const struct request *rq);
+void blk_req_stats_cb(struct blk_stat_callback *cb);
 void blk_req_stats_free(struct request_queue *q);
 #endif
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index aeb69c57ffb7..b1469b3ce511 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -16,6 +16,7 @@
 #include "blk-mq.h"
 #include "blk-mq-debugfs.h"
 #include "blk-wbt.h"
+#include "blk-stat.h"
 
 struct queue_sysfs_entry {
 	struct attribute attr;
@@ -534,6 +535,9 @@ static ssize_t queue_stat_show(struct request_queue *q, char *p)
 	char name[3][8] = {"read", "write", "discard"};
 	int bkt, off, i;
 
+	if (!q->req_stat)
+		return -ENODEV;
+
 	off = 0;
 	for (i = 0; i < 3; i++) {
 		off += sprintf(p + off, "%s: ", name[i]);
@@ -571,18 +575,42 @@ static ssize_t queue_reqstat_store(struct request_queue *q, const char *page,
 		return ret;
 
 	if (reqstat_on) {
+		if (!q->req_stat) {
+			q->req_stat = kcalloc(BLK_REQ_STATS_BKTS,
+					      sizeof(struct blk_rq_stat),
+					      GFP_KERNEL);
+			if (!q->req_stat) {
+				ret = -ENOMEM;
+				goto err_out;
+			}
+			q->reqstat_cb =
+				blk_stat_alloc_callback(blk_req_stats_cb,
+							blk_req_stats_bkt,
+							BLK_REQ_STATS_BKTS,
+							q);
+			if (!q->reqstat_cb) {
+				ret = -ENOMEM;
+				goto err_out;
+			}
+		}
 		if (!blk_queue_flag_test_and_set(QUEUE_FLAG_REQSTATS, q))
 			blk_stat_add_callback(q, q->reqstat_cb);
 		if (!blk_stat_is_active(q->reqstat_cb))
 			blk_stat_activate_msecs(q->reqstat_cb, 100);
 	} else {
-		if (test_bit(QUEUE_FLAG_REQSTATS, &q->queue_flags)) {
-			blk_stat_remove_callback(q, q->reqstat_cb);
-			blk_queue_flag_clear(QUEUE_FLAG_REQSTATS, q);
-		}
+		blk_req_stats_free(q);
 	}
 
+ out:
 	return ret;
+ err_out:
+	if (q->reqstat_cb) {
+		blk_stat_free_callback(q->reqstat_cb);
+		q->reqstat_cb = NULL;
+	}
+	kfree(q->req_stat);
+	q->req_stat = NULL;
+	goto out;
 }
 
 static struct queue_sysfs_entry queue_requests_entry = {
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 58abab51ed9f..1731c4ec4d34 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -484,7 +484,7 @@ struct request_queue {
 	struct blk_rq_stat	poll_stat[BLK_MQ_POLL_STATS_BKTS];
 
 	struct blk_stat_callback	*reqstat_cb;
-	struct blk_rq_stat	req_stat[BLK_REQ_STATS_BKTS];
+	struct blk_rq_stat	*req_stat;
 
 	struct timer_list	timeout;
 	struct work_struct	timeout_work;
-- 
2.17.1




[Index of Archives]     [Linux RAID]     [Linux SCSI]     [Linux ATA RAID]     [IDE]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Device Mapper]

  Powered by Linux