diff options
author | Ming Lei <ming.lei@redhat.com> | 2017-11-02 11:24:38 -0400 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2017-11-04 14:40:13 -0400 |
commit | 923218f6166a84688973acdc39094f3bee1e9ad4 (patch) | |
tree | 1013b8c39764532780292633f7e4214c99480aaf /block/blk-mq-sched.c | |
parent | 244c65a3ccaa06fd15cc940315606674d3108b2f (diff) |
blk-mq: don't allocate driver tag upfront for flush rq
The idea behind it is simple:
1) for none scheduler, driver tag has to be borrowed for flush rq,
otherwise we may run out of tag, and that causes an IO hang. And
get/put driver tag is actually noop for none, so reordering tags
isn't necessary at all.
2) for a real I/O scheduler, we need not allocate a driver tag upfront
for flush rq. It works just fine to follow the same approach as
normal requests: allocate driver tag for each rq just before calling
->queue_rq().
One driver visible change is that the driver tag isn't shared in the
flush request sequence. That won't be a problem, since we always do that
in legacy path.
Then flush rq need not be treated specially wrt. get/put driver tag.
This cleans up the code - for instance, reorder_tags_to_front() can be
removed, and we needn't worry about request ordering in dispatch list
for avoiding I/O deadlock.
Also we have to put the driver tag before requeueing.
Signed-off-by: Ming Lei <ming.lei@redhat.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'block/blk-mq-sched.c')
-rw-r--r-- | block/blk-mq-sched.c | 42 |
1 files changed, 5 insertions, 37 deletions
diff --git a/block/blk-mq-sched.c b/block/blk-mq-sched.c index e7094f44afaf..01a43fed6b8c 100644 --- a/block/blk-mq-sched.c +++ b/block/blk-mq-sched.c | |||
@@ -356,29 +356,12 @@ static bool blk_mq_sched_bypass_insert(struct blk_mq_hw_ctx *hctx, | |||
356 | return true; | 356 | return true; |
357 | } | 357 | } |
358 | 358 | ||
359 | if (has_sched) { | 359 | if (has_sched) |
360 | rq->rq_flags |= RQF_SORTED; | 360 | rq->rq_flags |= RQF_SORTED; |
361 | WARN_ON(rq->tag != -1); | ||
362 | } | ||
363 | 361 | ||
364 | return false; | 362 | return false; |
365 | } | 363 | } |
366 | 364 | ||
367 | /* | ||
368 | * Add flush/fua to the queue. If we fail getting a driver tag, then | ||
369 | * punt to the requeue list. Requeue will re-invoke us from a context | ||
370 | * that's safe to block from. | ||
371 | */ | ||
372 | static void blk_mq_sched_insert_flush(struct blk_mq_hw_ctx *hctx, | ||
373 | struct request *rq, bool can_block) | ||
374 | { | ||
375 | if (blk_mq_get_driver_tag(rq, &hctx, can_block)) { | ||
376 | blk_insert_flush(rq); | ||
377 | blk_mq_run_hw_queue(hctx, true); | ||
378 | } else | ||
379 | blk_mq_add_to_requeue_list(rq, false, true); | ||
380 | } | ||
381 | |||
382 | void blk_mq_sched_insert_request(struct request *rq, bool at_head, | 365 | void blk_mq_sched_insert_request(struct request *rq, bool at_head, |
383 | bool run_queue, bool async, bool can_block) | 366 | bool run_queue, bool async, bool can_block) |
384 | { | 367 | { |
@@ -389,10 +372,12 @@ void blk_mq_sched_insert_request(struct request *rq, bool at_head, | |||
389 | 372 | ||
390 | /* flush rq in flush machinery need to be dispatched directly */ | 373 | /* flush rq in flush machinery need to be dispatched directly */ |
391 | if (!(rq->rq_flags & RQF_FLUSH_SEQ) && op_is_flush(rq->cmd_flags)) { | 374 | if (!(rq->rq_flags & RQF_FLUSH_SEQ) && op_is_flush(rq->cmd_flags)) { |
392 | blk_mq_sched_insert_flush(hctx, rq, can_block); | 375 | blk_insert_flush(rq); |
393 | return; | 376 | goto run; |
394 | } | 377 | } |
395 | 378 | ||
379 | WARN_ON(e && (rq->tag != -1)); | ||
380 | |||
396 | if (blk_mq_sched_bypass_insert(hctx, !!e, rq)) | 381 | if (blk_mq_sched_bypass_insert(hctx, !!e, rq)) |
397 | goto run; | 382 | goto run; |
398 | 383 | ||
@@ -419,23 +404,6 @@ void blk_mq_sched_insert_requests(struct request_queue *q, | |||
419 | struct blk_mq_hw_ctx *hctx = blk_mq_map_queue(q, ctx->cpu); | 404 | struct blk_mq_hw_ctx *hctx = blk_mq_map_queue(q, ctx->cpu); |
420 | struct elevator_queue *e = hctx->queue->elevator; | 405 | struct elevator_queue *e = hctx->queue->elevator; |
421 | 406 | ||
422 | if (e) { | ||
423 | struct request *rq, *next; | ||
424 | |||
425 | /* | ||
426 | * We bypass requests that already have a driver tag assigned, | ||
427 | * which should only be flushes. Flushes are only ever inserted | ||
428 | * as single requests, so we shouldn't ever hit the | ||
429 | * WARN_ON_ONCE() below (but let's handle it just in case). | ||
430 | */ | ||
431 | list_for_each_entry_safe(rq, next, list, queuelist) { | ||
432 | if (WARN_ON_ONCE(rq->tag != -1)) { | ||
433 | list_del_init(&rq->queuelist); | ||
434 | blk_mq_sched_bypass_insert(hctx, true, rq); | ||
435 | } | ||
436 | } | ||
437 | } | ||
438 | |||
439 | if (e && e->type->ops.mq.insert_requests) | 407 | if (e && e->type->ops.mq.insert_requests) |
440 | e->type->ops.mq.insert_requests(hctx, list, false); | 408 | e->type->ops.mq.insert_requests(hctx, list, false); |
441 | else | 409 | else |