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