aboutsummaryrefslogtreecommitdiffstats
path: root/block/blk-mq-sched.c
diff options
context:
space:
mode:
authorMing Lei <ming.lei@redhat.com>2017-11-02 11:24:38 -0400
committerJens Axboe <axboe@kernel.dk>2017-11-04 14:40:13 -0400
commit923218f6166a84688973acdc39094f3bee1e9ad4 (patch)
tree1013b8c39764532780292633f7e4214c99480aaf /block/blk-mq-sched.c
parent244c65a3ccaa06fd15cc940315606674d3108b2f (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.c42
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 */
372static 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
382void blk_mq_sched_insert_request(struct request *rq, bool at_head, 365void 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