Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1742604 > unrolled thread
| Started by | Ming Lei <ming.lei@redhat.com> |
|---|---|
| First post | 2017-09-30 13:30 +0200 |
| Last post | 2017-09-30 13:40 +0200 |
| Articles | 9 — 1 participant |
Back to article view | Back to linux.kernel
[PATCH V5 0/8] blk-mq: improve bio merge for none scheduler Ming Lei <ming.lei@redhat.com> - 2017-09-30 13:30 +0200
[PATCH V5 7/8] blk-mq-sched: refactor blk_mq_sched_try_merge() Ming Lei <ming.lei@redhat.com> - 2017-09-30 13:40 +0200
[PATCH V5 5/8] block: add check on elevator for supporting bio merge via hashtable from blk-mq sw queue Ming Lei <ming.lei@redhat.com> - 2017-09-30 13:40 +0200
[PATCH V5 2/8] blk-mq-sched: use q->queue_depth as hint for q->nr_requests Ming Lei <ming.lei@redhat.com> - 2017-09-30 13:40 +0200
[PATCH V5 8/8] blk-mq: improve bio merge from blk-mq sw queue Ming Lei <ming.lei@redhat.com> - 2017-09-30 13:40 +0200
[PATCH V5 4/8] block: move actual bio merge code into __elv_merge Ming Lei <ming.lei@redhat.com> - 2017-09-30 13:40 +0200
[PATCH V5 1/8] blk-mq-sched: introduce blk_mq_sched_queue_depth() Ming Lei <ming.lei@redhat.com> - 2017-09-30 13:40 +0200
[PATCH V5 3/8] block: introduce rqhash helpers Ming Lei <ming.lei@redhat.com> - 2017-09-30 13:40 +0200
[PATCH V5 6/8] block: introduce .last_merge and .hash to blk_mq_ctx Ming Lei <ming.lei@redhat.com> - 2017-09-30 13:40 +0200
| From | Ming Lei <ming.lei@redhat.com> |
|---|---|
| Date | 2017-09-30 13:30 +0200 |
| Subject | [PATCH V5 0/8] blk-mq: improve bio merge for none scheduler |
| Message-ID | <uvo81-3sE-5@gated-at.bofh.it> |
Hi,
Patch 1 ~ 2 uses q->queue_depth as hint for setting up
scheduler queue depth.
Patch 3 ~ 8 improve bio merge via hash table in sw queue,
which makes bio merge more efficient than current approch
in which only the last 8 requests in sw queue are checked.
Also this way has been used in block legacy path for long time,
and blk-mq scheduler uses hash table to do bio merge too.
V5:
- splitted from previous patchset of 'blk-mq-sched: improve
SCSI-MQ performance V4'
Ming Lei (8):
blk-mq-sched: introduce blk_mq_sched_queue_depth()
blk-mq-sched: use q->queue_depth as hint for q->nr_requests
block: introduce rqhash helpers
block: move actual bio merge code into __elv_merge
block: add check on elevator for supporting bio merge via hashtable
from blk-mq sw queue
block: introduce .last_merge and .hash to blk_mq_ctx
blk-mq-sched: refactor blk_mq_sched_try_merge()
blk-mq: improve bio merge from blk-mq sw queue
block/blk-mq-sched.c | 75 +++++++++++++++---------------------------
block/blk-mq-sched.h | 23 +++++++++++++
block/blk-mq.c | 55 ++++++++++++++++++++++++++++---
block/blk-mq.h | 5 +++
block/blk-settings.c | 2 ++
block/blk.h | 55 +++++++++++++++++++++++++++++++
block/elevator.c | 93 +++++++++++++++++++++++++++++++---------------------
7 files changed, 216 insertions(+), 92 deletions(-)
--
2.9.5
[toc] | [next] | [standalone]
| From | Ming Lei <ming.lei@redhat.com> |
|---|---|
| Date | 2017-09-30 13:40 +0200 |
| Subject | [PATCH V5 7/8] blk-mq-sched: refactor blk_mq_sched_try_merge() |
| Message-ID | <uvohH-3wm-1@gated-at.bofh.it> |
| In reply to | #1742604 |
This patch introduces one function __blk_mq_try_merge()
which will be resued for bio merge to sw queue in
the following patch.
No functional change.
Tested-by: Oleksandr Natalenko <oleksandr@natalenko.name>
Tested-by: Tom Nguyen <tom81094@gmail.com>
Tested-by: Paolo Valente <paolo.valente@linaro.org>
Reviewed-by: Bart Van Assche <bart.vanassche@wdc.com>
Signed-off-by: Ming Lei <ming.lei@redhat.com>
---
block/blk-mq-sched.c | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/block/blk-mq-sched.c b/block/blk-mq-sched.c
index 8c09959bc0d0..a58f4746317c 100644
--- a/block/blk-mq-sched.c
+++ b/block/blk-mq-sched.c
@@ -222,12 +222,11 @@ void blk_mq_sched_dispatch_requests(struct blk_mq_hw_ctx *hctx)
}
}
-bool blk_mq_sched_try_merge(struct request_queue *q, struct bio *bio,
- struct request **merged_request)
+static bool __blk_mq_try_merge(struct request_queue *q,
+ struct bio *bio, struct request **merged_request,
+ struct request *rq, enum elv_merge type)
{
- struct request *rq;
-
- switch (elv_merge(q, &rq, bio)) {
+ switch (type) {
case ELEVATOR_BACK_MERGE:
if (!blk_mq_sched_allow_merge(q, rq, bio))
return false;
@@ -250,6 +249,15 @@ bool blk_mq_sched_try_merge(struct request_queue *q, struct bio *bio,
return false;
}
}
+
+bool blk_mq_sched_try_merge(struct request_queue *q, struct bio *bio,
+ struct request **merged_request)
+{
+ struct request *rq;
+ enum elv_merge type = elv_merge(q, &rq, bio);
+
+ return __blk_mq_try_merge(q, bio, merged_request, rq, type);
+}
EXPORT_SYMBOL_GPL(blk_mq_sched_try_merge);
/*
--
2.9.5
[toc] | [prev] | [next] | [standalone]
| From | Ming Lei <ming.lei@redhat.com> |
|---|---|
| Date | 2017-09-30 13:40 +0200 |
| Subject | [PATCH V5 5/8] block: add check on elevator for supporting bio merge via hashtable from blk-mq sw queue |
| Message-ID | <uvohH-3wm-5@gated-at.bofh.it> |
| In reply to | #1742604 |
blk_mq_sched_try_merge() will be reused in following patches
to support bio merge to blk-mq sw queue, so add checkes to
related functions which are called from blk_mq_sched_try_merge().
Tested-by: Oleksandr Natalenko <oleksandr@natalenko.name>
Tested-by: Tom Nguyen <tom81094@gmail.com>
Tested-by: Paolo Valente <paolo.valente@linaro.org>
Signed-off-by: Ming Lei <ming.lei@redhat.com>
---
block/elevator.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/block/elevator.c b/block/elevator.c
index e11c7873fc21..2424aea85393 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -71,6 +71,10 @@ bool elv_bio_merge_ok(struct request *rq, struct bio *bio)
if (!blk_rq_merge_ok(rq, bio))
return false;
+ /* We need to support to merge bio from sw queue */
+ if (!rq->q->elevator)
+ return true;
+
if (!elv_iosched_allow_bio_merge(rq, bio))
return false;
@@ -449,6 +453,10 @@ static enum elv_merge __elv_merge(struct request_queue *q,
return ELEVATOR_BACK_MERGE;
}
+ /* no elevator when merging bio to blk-mq sw queue */
+ if (!e)
+ return ELEVATOR_NO_MERGE;
+
if (e->uses_mq && e->type->ops.mq.request_merge)
return e->type->ops.mq.request_merge(q, req, bio);
else if (!e->uses_mq && e->type->ops.sq.elevator_merge_fn)
@@ -711,6 +719,10 @@ struct request *elv_latter_request(struct request_queue *q, struct request *rq)
{
struct elevator_queue *e = q->elevator;
+ /* no elevator when merging bio to blk-mq sw queue */
+ if (!e)
+ return NULL;
+
if (e->uses_mq && e->type->ops.mq.next_request)
return e->type->ops.mq.next_request(q, rq);
else if (!e->uses_mq && e->type->ops.sq.elevator_latter_req_fn)
@@ -723,6 +735,10 @@ struct request *elv_former_request(struct request_queue *q, struct request *rq)
{
struct elevator_queue *e = q->elevator;
+ /* no elevator when merging bio to blk-mq sw queue */
+ if (!e)
+ return NULL;
+
if (e->uses_mq && e->type->ops.mq.former_request)
return e->type->ops.mq.former_request(q, rq);
if (!e->uses_mq && e->type->ops.sq.elevator_former_req_fn)
--
2.9.5
[toc] | [prev] | [next] | [standalone]
| From | Ming Lei <ming.lei@redhat.com> |
|---|---|
| Date | 2017-09-30 13:40 +0200 |
| Subject | [PATCH V5 2/8] blk-mq-sched: use q->queue_depth as hint for q->nr_requests |
| Message-ID | <uvohH-3wm-9@gated-at.bofh.it> |
| In reply to | #1742604 |
SCSI sets q->queue_depth from shost->cmd_per_lun, and
q->queue_depth is per request_queue and more related to
scheduler queue compared with hw queue depth, which can be
shared by queues, such as TAG_SHARED.
This patch tries to use q->queue_depth as hint for computing
q->nr_requests, which should be more effective than
current way.
Reviewed-by: Bart Van Assche <bart.vanassche@wdc.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Tested-by: Oleksandr Natalenko <oleksandr@natalenko.name>
Tested-by: Tom Nguyen <tom81094@gmail.com>
Tested-by: Paolo Valente <paolo.valente@linaro.org>
Signed-off-by: Ming Lei <ming.lei@redhat.com>
---
block/blk-mq-sched.h | 18 +++++++++++++++---
block/blk-mq.c | 27 +++++++++++++++++++++++++--
block/blk-mq.h | 1 +
block/blk-settings.c | 2 ++
4 files changed, 43 insertions(+), 5 deletions(-)
diff --git a/block/blk-mq-sched.h b/block/blk-mq-sched.h
index 1d47f3fda1d0..906b10c54f78 100644
--- a/block/blk-mq-sched.h
+++ b/block/blk-mq-sched.h
@@ -99,12 +99,24 @@ static inline bool blk_mq_sched_needs_restart(struct blk_mq_hw_ctx *hctx)
static inline unsigned blk_mq_sched_queue_depth(struct request_queue *q)
{
/*
- * Default to double of smaller one between hw queue_depth and 128,
+ * q->queue_depth is more close to scheduler queue, so use it
+ * as hint for computing scheduler queue depth if it is valid
+ */
+ unsigned q_depth = q->queue_depth ?: q->tag_set->queue_depth;
+
+ /*
+ * Default to double of smaller one between queue depth and 128,
* since we don't split into sync/async like the old code did.
* Additionally, this is a per-hw queue depth.
*/
- return 2 * min_t(unsigned int, q->tag_set->queue_depth,
- BLKDEV_MAX_RQ);
+ q_depth = 2 * min_t(unsigned int, q_depth, BLKDEV_MAX_RQ);
+
+ /*
+ * when queue depth of driver is too small, we set queue depth
+ * of scheduler queue as 128 which is the default setting of
+ * block legacy code.
+ */
+ return max_t(unsigned, q_depth, BLKDEV_MAX_RQ);
}
#endif
diff --git a/block/blk-mq.c b/block/blk-mq.c
index 7cb3f87334c0..561a663cdd0e 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -2694,7 +2694,9 @@ void blk_mq_free_tag_set(struct blk_mq_tag_set *set)
}
EXPORT_SYMBOL(blk_mq_free_tag_set);
-int blk_mq_update_nr_requests(struct request_queue *q, unsigned int nr)
+static int __blk_mq_update_nr_requests(struct request_queue *q,
+ bool sched_only,
+ unsigned int nr)
{
struct blk_mq_tag_set *set = q->tag_set;
struct blk_mq_hw_ctx *hctx;
@@ -2713,7 +2715,7 @@ int blk_mq_update_nr_requests(struct request_queue *q, unsigned int nr)
* If we're using an MQ scheduler, just update the scheduler
* queue depth. This is similar to what the old code would do.
*/
- if (!hctx->sched_tags) {
+ if (!sched_only && !hctx->sched_tags) {
ret = blk_mq_tag_update_depth(hctx, &hctx->tags,
min(nr, set->queue_depth),
false);
@@ -2733,6 +2735,27 @@ int blk_mq_update_nr_requests(struct request_queue *q, unsigned int nr)
return ret;
}
+int blk_mq_update_nr_requests(struct request_queue *q, unsigned int nr)
+{
+ return __blk_mq_update_nr_requests(q, false, nr);
+}
+
+/*
+ * When drivers update q->queue_depth, this API is called so that
+ * we can use this queue depth as hint for adjusting scheduler
+ * queue depth.
+ */
+int blk_mq_update_sched_queue_depth(struct request_queue *q)
+{
+ unsigned nr;
+
+ if (!q->mq_ops || !q->elevator)
+ return 0;
+
+ nr = blk_mq_sched_queue_depth(q);
+ return __blk_mq_update_nr_requests(q, true, nr);
+}
+
static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set,
int nr_hw_queues)
{
diff --git a/block/blk-mq.h b/block/blk-mq.h
index 915de58572e7..5bca6ce1f01d 100644
--- a/block/blk-mq.h
+++ b/block/blk-mq.h
@@ -37,6 +37,7 @@ bool blk_mq_get_driver_tag(struct request *rq, struct blk_mq_hw_ctx **hctx,
bool wait);
struct request *blk_mq_dequeue_from_ctx(struct blk_mq_hw_ctx *hctx,
struct blk_mq_ctx *start);
+int blk_mq_update_sched_queue_depth(struct request_queue *q);
/*
* Internal helpers for allocating/freeing the request map
diff --git a/block/blk-settings.c b/block/blk-settings.c
index 8559e9563c52..c2db38d2ec2b 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -878,6 +878,8 @@ void blk_set_queue_depth(struct request_queue *q, unsigned int depth)
{
q->queue_depth = depth;
wbt_set_queue_depth(q->rq_wb, depth);
+
+ WARN_ON(blk_mq_update_sched_queue_depth(q));
}
EXPORT_SYMBOL(blk_set_queue_depth);
--
2.9.5
[toc] | [prev] | [next] | [standalone]
| From | Ming Lei <ming.lei@redhat.com> |
|---|---|
| Date | 2017-09-30 13:40 +0200 |
| Subject | [PATCH V5 8/8] blk-mq: improve bio merge from blk-mq sw queue |
| Message-ID | <uvohH-3wm-7@gated-at.bofh.it> |
| In reply to | #1742604 |
This patch uses hash table to do bio merge from sw queue,
then we can align to blk-mq scheduler/block legacy's way
for bio merge.
Turns out bio merge via hash table is more efficient than
simple merge on the last 8 requests in sw queue. On SCSI SRP,
it is observed ~10% IOPS is increased in sequential IO test
with this patch.
It is also one step forward to real 'none' scheduler, in which
way the blk-mq scheduler framework can be more clean.
Tested-by: Oleksandr Natalenko <oleksandr@natalenko.name>
Tested-by: Tom Nguyen <tom81094@gmail.com>
Tested-by: Paolo Valente <paolo.valente@linaro.org>
Signed-off-by: Ming Lei <ming.lei@redhat.com>
---
block/blk-mq-sched.c | 49 ++++++++++++-------------------------------------
block/blk-mq.c | 28 +++++++++++++++++++++++++---
2 files changed, 37 insertions(+), 40 deletions(-)
diff --git a/block/blk-mq-sched.c b/block/blk-mq-sched.c
index a58f4746317c..8262ae71e0cd 100644
--- a/block/blk-mq-sched.c
+++ b/block/blk-mq-sched.c
@@ -260,50 +260,25 @@ bool blk_mq_sched_try_merge(struct request_queue *q, struct bio *bio,
}
EXPORT_SYMBOL_GPL(blk_mq_sched_try_merge);
-/*
- * Reverse check our software queue for entries that we could potentially
- * merge with. Currently includes a hand-wavy stop count of 8, to not spend
- * too much time checking for merges.
- */
-static bool blk_mq_attempt_merge(struct request_queue *q,
+static bool blk_mq_ctx_try_merge(struct request_queue *q,
struct blk_mq_ctx *ctx, struct bio *bio)
{
- struct request *rq;
- int checked = 8;
+ struct request *rq, *free = NULL;
+ enum elv_merge type;
+ bool merged;
lockdep_assert_held(&ctx->lock);
- list_for_each_entry_reverse(rq, &ctx->rq_list, queuelist) {
- bool merged = false;
-
- if (!checked--)
- break;
-
- if (!blk_rq_merge_ok(rq, bio))
- continue;
+ type = elv_merge_ctx(q, &rq, bio, ctx);
+ merged = __blk_mq_try_merge(q, bio, &free, rq, type);
- switch (blk_try_merge(rq, bio)) {
- case ELEVATOR_BACK_MERGE:
- if (blk_mq_sched_allow_merge(q, rq, bio))
- merged = bio_attempt_back_merge(q, rq, bio);
- break;
- case ELEVATOR_FRONT_MERGE:
- if (blk_mq_sched_allow_merge(q, rq, bio))
- merged = bio_attempt_front_merge(q, rq, bio);
- break;
- case ELEVATOR_DISCARD_MERGE:
- merged = bio_attempt_discard_merge(q, rq, bio);
- break;
- default:
- continue;
- }
+ if (free)
+ blk_mq_free_request(free);
- if (merged)
- ctx->rq_merged++;
- return merged;
- }
+ if (merged)
+ ctx->rq_merged++;
- return false;
+ return merged;
}
bool __blk_mq_sched_bio_merge(struct request_queue *q, struct bio *bio)
@@ -321,7 +296,7 @@ bool __blk_mq_sched_bio_merge(struct request_queue *q, struct bio *bio)
if (hctx->flags & BLK_MQ_F_SHOULD_MERGE) {
/* default per sw-queue merge */
spin_lock(&ctx->lock);
- ret = blk_mq_attempt_merge(q, ctx, bio);
+ ret = blk_mq_ctx_try_merge(q, ctx, bio);
spin_unlock(&ctx->lock);
}
diff --git a/block/blk-mq.c b/block/blk-mq.c
index 561a663cdd0e..9a3a561a63b5 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -849,6 +849,18 @@ static void blk_mq_timeout_work(struct work_struct *work)
blk_queue_exit(q);
}
+static void blk_mq_ctx_remove_rq_list(struct blk_mq_ctx *ctx,
+ struct list_head *head)
+{
+ struct request *rq;
+
+ lockdep_assert_held(&ctx->lock);
+
+ list_for_each_entry(rq, head, queuelist)
+ rqhash_del(rq);
+ ctx->last_merge = NULL;
+}
+
struct flush_busy_ctx_data {
struct blk_mq_hw_ctx *hctx;
struct list_head *list;
@@ -863,6 +875,7 @@ static bool flush_busy_ctx(struct sbitmap *sb, unsigned int bitnr, void *data)
sbitmap_clear_bit(sb, bitnr);
spin_lock(&ctx->lock);
list_splice_tail_init(&ctx->rq_list, flush_data->list);
+ blk_mq_ctx_remove_rq_list(ctx, flush_data->list);
spin_unlock(&ctx->lock);
return true;
}
@@ -892,17 +905,23 @@ static bool dispatch_rq_from_ctx(struct sbitmap *sb, unsigned int bitnr, void *d
struct dispatch_rq_data *dispatch_data = data;
struct blk_mq_hw_ctx *hctx = dispatch_data->hctx;
struct blk_mq_ctx *ctx = hctx->ctxs[bitnr];
+ struct request *rq = NULL;
spin_lock(&ctx->lock);
if (unlikely(!list_empty(&ctx->rq_list))) {
- dispatch_data->rq = list_entry_rq(ctx->rq_list.next);
- list_del_init(&dispatch_data->rq->queuelist);
+ rq = list_entry_rq(ctx->rq_list.next);
+ list_del_init(&rq->queuelist);
+ rqhash_del(rq);
if (list_empty(&ctx->rq_list))
sbitmap_clear_bit(sb, bitnr);
}
+ if (ctx->last_merge == rq)
+ ctx->last_merge = NULL;
spin_unlock(&ctx->lock);
- return !dispatch_data->rq;
+ dispatch_data->rq = rq;
+
+ return !rq;
}
struct request *blk_mq_dequeue_from_ctx(struct blk_mq_hw_ctx *hctx,
@@ -1433,6 +1452,8 @@ static inline void __blk_mq_insert_req_list(struct blk_mq_hw_ctx *hctx,
list_add(&rq->queuelist, &ctx->rq_list);
else
list_add_tail(&rq->queuelist, &ctx->rq_list);
+
+ rqhash_add(ctx->hash, rq);
}
void __blk_mq_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq,
@@ -1968,6 +1989,7 @@ static int blk_mq_hctx_notify_dead(unsigned int cpu, struct hlist_node *node)
spin_lock(&ctx->lock);
if (!list_empty(&ctx->rq_list)) {
list_splice_init(&ctx->rq_list, &tmp);
+ blk_mq_ctx_remove_rq_list(ctx, &tmp);
blk_mq_hctx_clear_pending(hctx, ctx);
}
spin_unlock(&ctx->lock);
--
2.9.5
[toc] | [prev] | [next] | [standalone]
| From | Ming Lei <ming.lei@redhat.com> |
|---|---|
| Date | 2017-09-30 13:40 +0200 |
| Subject | [PATCH V5 4/8] block: move actual bio merge code into __elv_merge |
| Message-ID | <uvohH-3wm-11@gated-at.bofh.it> |
| In reply to | #1742604 |
So that we can reuse __elv_merge() to merge bio
into requests from sw queue in the following patches.
No functional change.
Tested-by: Oleksandr Natalenko <oleksandr@natalenko.name>
Tested-by: Tom Nguyen <tom81094@gmail.com>
Tested-by: Paolo Valente <paolo.valente@linaro.org>
Signed-off-by: Ming Lei <ming.lei@redhat.com>
---
block/elevator.c | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)
diff --git a/block/elevator.c b/block/elevator.c
index 824cc3e69ac3..e11c7873fc21 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -409,8 +409,9 @@ void elv_dispatch_add_tail(struct request_queue *q, struct request *rq)
}
EXPORT_SYMBOL(elv_dispatch_add_tail);
-enum elv_merge elv_merge(struct request_queue *q, struct request **req,
- struct bio *bio)
+static enum elv_merge __elv_merge(struct request_queue *q,
+ struct request **req, struct bio *bio,
+ struct hlist_head *hash, struct request *last_merge)
{
struct elevator_queue *e = q->elevator;
struct request *__rq;
@@ -427,11 +428,11 @@ enum elv_merge elv_merge(struct request_queue *q, struct request **req,
/*
* First try one-hit cache.
*/
- if (q->last_merge && elv_bio_merge_ok(q->last_merge, bio)) {
- enum elv_merge ret = blk_try_merge(q->last_merge, bio);
+ if (last_merge && elv_bio_merge_ok(last_merge, bio)) {
+ enum elv_merge ret = blk_try_merge(last_merge, bio);
if (ret != ELEVATOR_NO_MERGE) {
- *req = q->last_merge;
+ *req = last_merge;
return ret;
}
}
@@ -442,7 +443,7 @@ enum elv_merge elv_merge(struct request_queue *q, struct request **req,
/*
* See if our hash lookup can find a potential backmerge.
*/
- __rq = elv_rqhash_find(q, bio->bi_iter.bi_sector);
+ __rq = rqhash_find(hash, bio->bi_iter.bi_sector);
if (__rq && elv_bio_merge_ok(__rq, bio)) {
*req = __rq;
return ELEVATOR_BACK_MERGE;
@@ -456,6 +457,12 @@ enum elv_merge elv_merge(struct request_queue *q, struct request **req,
return ELEVATOR_NO_MERGE;
}
+enum elv_merge elv_merge(struct request_queue *q, struct request **req,
+ struct bio *bio)
+{
+ return __elv_merge(q, req, bio, q->elevator->hash, q->last_merge);
+}
+
/*
* Attempt to do an insertion back merge. Only check for the case where
* we can append 'rq' to an existing request, so we can throw 'rq' away
--
2.9.5
[toc] | [prev] | [next] | [standalone]
| From | Ming Lei <ming.lei@redhat.com> |
|---|---|
| Date | 2017-09-30 13:40 +0200 |
| Subject | [PATCH V5 1/8] blk-mq-sched: introduce blk_mq_sched_queue_depth() |
| Message-ID | <uvohI-3wm-19@gated-at.bofh.it> |
| In reply to | #1742604 |
The following patch will use one hint to figure out
default queue depth for scheduler queue, so introduce
the helper of blk_mq_sched_queue_depth() for this purpose.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Bart Van Assche <bart.vanassche@wdc.com>
Tested-by: Oleksandr Natalenko <oleksandr@natalenko.name>
Tested-by: Tom Nguyen <tom81094@gmail.com>
Tested-by: Paolo Valente <paolo.valente@linaro.org>
Signed-off-by: Ming Lei <ming.lei@redhat.com>
---
block/blk-mq-sched.c | 8 +-------
block/blk-mq-sched.h | 11 +++++++++++
2 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/block/blk-mq-sched.c b/block/blk-mq-sched.c
index c5eac1eee442..8c09959bc0d0 100644
--- a/block/blk-mq-sched.c
+++ b/block/blk-mq-sched.c
@@ -588,13 +588,7 @@ int blk_mq_init_sched(struct request_queue *q, struct elevator_type *e)
return 0;
}
- /*
- * Default to double of smaller one between hw queue_depth and 128,
- * since we don't split into sync/async like the old code did.
- * Additionally, this is a per-hw queue depth.
- */
- q->nr_requests = 2 * min_t(unsigned int, q->tag_set->queue_depth,
- BLKDEV_MAX_RQ);
+ q->nr_requests = blk_mq_sched_queue_depth(q);
queue_for_each_hw_ctx(q, hctx, i) {
ret = blk_mq_sched_alloc_tags(q, hctx, i);
diff --git a/block/blk-mq-sched.h b/block/blk-mq-sched.h
index 9267d0b7c197..1d47f3fda1d0 100644
--- a/block/blk-mq-sched.h
+++ b/block/blk-mq-sched.h
@@ -96,4 +96,15 @@ static inline bool blk_mq_sched_needs_restart(struct blk_mq_hw_ctx *hctx)
return test_bit(BLK_MQ_S_SCHED_RESTART, &hctx->state);
}
+static inline unsigned blk_mq_sched_queue_depth(struct request_queue *q)
+{
+ /*
+ * Default to double of smaller one between hw queue_depth and 128,
+ * since we don't split into sync/async like the old code did.
+ * Additionally, this is a per-hw queue depth.
+ */
+ return 2 * min_t(unsigned int, q->tag_set->queue_depth,
+ BLKDEV_MAX_RQ);
+}
+
#endif
--
2.9.5
[toc] | [prev] | [next] | [standalone]
| From | Ming Lei <ming.lei@redhat.com> |
|---|---|
| Date | 2017-09-30 13:40 +0200 |
| Subject | [PATCH V5 3/8] block: introduce rqhash helpers |
| Message-ID | <uvohI-3wm-23@gated-at.bofh.it> |
| In reply to | #1742604 |
We need this helpers for supporting to use hashtable to improve
bio merge from sw queue in the following patches.
No functional change.
Tested-by: Oleksandr Natalenko <oleksandr@natalenko.name>
Tested-by: Tom Nguyen <tom81094@gmail.com>
Tested-by: Paolo Valente <paolo.valente@linaro.org>
Signed-off-by: Ming Lei <ming.lei@redhat.com>
---
block/blk.h | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
block/elevator.c | 36 +++++++-----------------------------
2 files changed, 59 insertions(+), 29 deletions(-)
diff --git a/block/blk.h b/block/blk.h
index fcb9775b997d..eb3436d4a73f 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -146,6 +146,58 @@ static inline void blk_clear_rq_complete(struct request *rq)
*/
#define ELV_ON_HASH(rq) ((rq)->rq_flags & RQF_HASHED)
+/*
+ * Merge hash stuff.
+ */
+#define rq_hash_key(rq) (blk_rq_pos(rq) + blk_rq_sectors(rq))
+
+#define bucket(head, key) &((head)[hash_min((key), ELV_HASH_BITS)])
+
+static inline void __rqhash_del(struct request *rq)
+{
+ hash_del(&rq->hash);
+ rq->rq_flags &= ~RQF_HASHED;
+}
+
+static inline void rqhash_del(struct request *rq)
+{
+ if (ELV_ON_HASH(rq))
+ __rqhash_del(rq);
+}
+
+static inline void rqhash_add(struct hlist_head *hash, struct request *rq)
+{
+ BUG_ON(ELV_ON_HASH(rq));
+ hlist_add_head(&rq->hash, bucket(hash, rq_hash_key(rq)));
+ rq->rq_flags |= RQF_HASHED;
+}
+
+static inline void rqhash_reposition(struct hlist_head *hash, struct request *rq)
+{
+ __rqhash_del(rq);
+ rqhash_add(hash, rq);
+}
+
+static inline struct request *rqhash_find(struct hlist_head *hash, sector_t offset)
+{
+ struct hlist_node *next;
+ struct request *rq = NULL;
+
+ hlist_for_each_entry_safe(rq, next, bucket(hash, offset), hash) {
+ BUG_ON(!ELV_ON_HASH(rq));
+
+ if (unlikely(!rq_mergeable(rq))) {
+ __rqhash_del(rq);
+ continue;
+ }
+
+ if (rq_hash_key(rq) == offset)
+ return rq;
+ }
+
+ return NULL;
+}
+
void blk_insert_flush(struct request *rq);
static inline struct request *__elv_next_request(struct request_queue *q)
diff --git a/block/elevator.c b/block/elevator.c
index 153926a90901..824cc3e69ac3 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -47,11 +47,6 @@ static DEFINE_SPINLOCK(elv_list_lock);
static LIST_HEAD(elv_list);
/*
- * Merge hash stuff.
- */
-#define rq_hash_key(rq) (blk_rq_pos(rq) + blk_rq_sectors(rq))
-
-/*
* Query io scheduler to see if the current process issuing bio may be
* merged with rq.
*/
@@ -268,14 +263,12 @@ EXPORT_SYMBOL(elevator_exit);
static inline void __elv_rqhash_del(struct request *rq)
{
- hash_del(&rq->hash);
- rq->rq_flags &= ~RQF_HASHED;
+ __rqhash_del(rq);
}
void elv_rqhash_del(struct request_queue *q, struct request *rq)
{
- if (ELV_ON_HASH(rq))
- __elv_rqhash_del(rq);
+ rqhash_del(rq);
}
EXPORT_SYMBOL_GPL(elv_rqhash_del);
@@ -283,37 +276,22 @@ void elv_rqhash_add(struct request_queue *q, struct request *rq)
{
struct elevator_queue *e = q->elevator;
- BUG_ON(ELV_ON_HASH(rq));
- hash_add(e->hash, &rq->hash, rq_hash_key(rq));
- rq->rq_flags |= RQF_HASHED;
+ rqhash_add(e->hash, rq);
}
EXPORT_SYMBOL_GPL(elv_rqhash_add);
void elv_rqhash_reposition(struct request_queue *q, struct request *rq)
{
- __elv_rqhash_del(rq);
- elv_rqhash_add(q, rq);
+ struct elevator_queue *e = q->elevator;
+
+ rqhash_reposition(e->hash, rq);
}
struct request *elv_rqhash_find(struct request_queue *q, sector_t offset)
{
struct elevator_queue *e = q->elevator;
- struct hlist_node *next;
- struct request *rq;
-
- hash_for_each_possible_safe(e->hash, rq, next, hash, offset) {
- BUG_ON(!ELV_ON_HASH(rq));
- if (unlikely(!rq_mergeable(rq))) {
- __elv_rqhash_del(rq);
- continue;
- }
-
- if (rq_hash_key(rq) == offset)
- return rq;
- }
-
- return NULL;
+ return rqhash_find(e->hash, offset);
}
/*
--
2.9.5
[toc] | [prev] | [next] | [standalone]
| From | Ming Lei <ming.lei@redhat.com> |
|---|---|
| Date | 2017-09-30 13:40 +0200 |
| Subject | [PATCH V5 6/8] block: introduce .last_merge and .hash to blk_mq_ctx |
| Message-ID | <uvohI-3wm-17@gated-at.bofh.it> |
| In reply to | #1742604 |
Prepare for supporting bio merge to sw queue if no
blk-mq io scheduler is taken.
Tested-by: Oleksandr Natalenko <oleksandr@natalenko.name>
Tested-by: Tom Nguyen <tom81094@gmail.com>
Tested-by: Paolo Valente <paolo.valente@linaro.org>
Signed-off-by: Ming Lei <ming.lei@redhat.com>
---
block/blk-mq.h | 4 ++++
block/blk.h | 3 +++
block/elevator.c | 22 +++++++++++++++++++---
3 files changed, 26 insertions(+), 3 deletions(-)
diff --git a/block/blk-mq.h b/block/blk-mq.h
index 5bca6ce1f01d..85ea8615fecf 100644
--- a/block/blk-mq.h
+++ b/block/blk-mq.h
@@ -18,6 +18,10 @@ struct blk_mq_ctx {
unsigned long rq_dispatched[2];
unsigned long rq_merged;
+ /* bio merge via request hash table */
+ struct request *last_merge;
+ DECLARE_HASHTABLE(hash, ELV_HASH_BITS);
+
/* incremented at completion time */
unsigned long ____cacheline_aligned_in_smp rq_completed[2];
diff --git a/block/blk.h b/block/blk.h
index eb3436d4a73f..fa4f232afc18 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -198,6 +198,9 @@ static inline struct request *rqhash_find(struct hlist_head *hash, sector_t offs
return NULL;
}
+enum elv_merge elv_merge_ctx(struct request_queue *q, struct request **req,
+ struct bio *bio, struct blk_mq_ctx *ctx);
+
void blk_insert_flush(struct request *rq);
static inline struct request *__elv_next_request(struct request_queue *q)
diff --git a/block/elevator.c b/block/elevator.c
index 2424aea85393..0e13e5c18982 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -471,6 +471,13 @@ enum elv_merge elv_merge(struct request_queue *q, struct request **req,
return __elv_merge(q, req, bio, q->elevator->hash, q->last_merge);
}
+enum elv_merge elv_merge_ctx(struct request_queue *q, struct request **req,
+ struct bio *bio, struct blk_mq_ctx *ctx)
+{
+ WARN_ON_ONCE(!q->mq_ops);
+ return __elv_merge(q, req, bio, ctx->hash, ctx->last_merge);
+}
+
/*
* Attempt to do an insertion back merge. Only check for the case where
* we can append 'rq' to an existing request, so we can throw 'rq' away
@@ -516,16 +523,25 @@ void elv_merged_request(struct request_queue *q, struct request *rq,
enum elv_merge type)
{
struct elevator_queue *e = q->elevator;
+ struct hlist_head *hash = e->hash;
+
+ /* we do bio merge on blk-mq sw queue */
+ if (q->mq_ops && !e) {
+ rq->mq_ctx->last_merge = rq;
+ hash = rq->mq_ctx->hash;
+ goto reposition;
+ }
+
+ q->last_merge = rq;
if (e->uses_mq && e->type->ops.mq.request_merged)
e->type->ops.mq.request_merged(q, rq, type);
else if (!e->uses_mq && e->type->ops.sq.elevator_merged_fn)
e->type->ops.sq.elevator_merged_fn(q, rq, type);
+ reposition:
if (type == ELEVATOR_BACK_MERGE)
- elv_rqhash_reposition(q, rq);
-
- q->last_merge = rq;
+ rqhash_reposition(hash, rq);
}
void elv_merge_requests(struct request_queue *q, struct request *rq,
--
2.9.5
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web