summaryrefslogtreecommitdiffstats
path: root/block/blk-mq.c
diff options
context:
space:
mode:
authorOmar Sandoval <osandov@fb.com>2017-04-07 10:56:26 -0400
committerJens Axboe <axboe@fb.com>2017-04-07 10:56:26 -0400
commit81380ca10778b99dce98940cfc993214712df335 (patch)
treece167a1c5f914d91949af26cfb4f38d964d3daa5 /block/blk-mq.c
parent8945927cb7cc5953cc1554053452f50248159c88 (diff)
blk-mq: use the right hctx when getting a driver tag fails
While dispatching requests, if we fail to get a driver tag, we mark the hardware queue as waiting for a tag and put the requests on a hctx->dispatch list to be run later when a driver tag is freed. However, blk_mq_dispatch_rq_list() may dispatch requests from multiple hardware queues if using a single-queue scheduler with a multiqueue device. If blk_mq_get_driver_tag() fails, it doesn't update the hardware queue we are processing. This means we end up using the hardware queue of the previous request, which may or may not be the same as that of the current request. If it isn't, the wrong hardware queue will end up waiting for a tag, and the requests will be on the wrong dispatch list, leading to a hang. The fix is twofold: 1. Make sure we save which hardware queue we were trying to get a request for in blk_mq_get_driver_tag() regardless of whether it succeeds or not. 2. Make blk_mq_dispatch_rq_list() take a request_queue instead of a blk_mq_hw_queue to make it clear that it must handle multiple hardware queues, since I've already messed this up on a couple of occasions. This didn't appear in testing with nvme and mq-deadline because nvme has more driver tags than the default number of scheduler tags. However, with the blk_mq_update_nr_hw_queues() fix, it showed up with nbd. Signed-off-by: Omar Sandoval <osandov@fb.com> Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'block/blk-mq.c')
-rw-r--r--block/blk-mq.c25
1 files changed, 13 insertions, 12 deletions
diff --git a/block/blk-mq.c b/block/blk-mq.c
index 935f2cc7c8c3..828f4bd193f2 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -845,12 +845,8 @@ bool blk_mq_get_driver_tag(struct request *rq, struct blk_mq_hw_ctx **hctx,
845 .flags = wait ? 0 : BLK_MQ_REQ_NOWAIT, 845 .flags = wait ? 0 : BLK_MQ_REQ_NOWAIT,
846 }; 846 };
847 847
848 if (rq->tag != -1) { 848 if (rq->tag != -1)
849done: 849 goto done;
850 if (hctx)
851 *hctx = data.hctx;
852 return true;
853 }
854 850
855 if (blk_mq_tag_is_reserved(data.hctx->sched_tags, rq->internal_tag)) 851 if (blk_mq_tag_is_reserved(data.hctx->sched_tags, rq->internal_tag))
856 data.flags |= BLK_MQ_REQ_RESERVED; 852 data.flags |= BLK_MQ_REQ_RESERVED;
@@ -862,10 +858,12 @@ done:
862 atomic_inc(&data.hctx->nr_active); 858 atomic_inc(&data.hctx->nr_active);
863 } 859 }
864 data.hctx->tags->rqs[rq->tag] = rq; 860 data.hctx->tags->rqs[rq->tag] = rq;
865 goto done;
866 } 861 }
867 862
868 return false; 863done:
864 if (hctx)
865 *hctx = data.hctx;
866 return rq->tag != -1;
869} 867}
870 868
871static void __blk_mq_put_driver_tag(struct blk_mq_hw_ctx *hctx, 869static void __blk_mq_put_driver_tag(struct blk_mq_hw_ctx *hctx,
@@ -962,14 +960,17 @@ static bool blk_mq_dispatch_wait_add(struct blk_mq_hw_ctx *hctx)
962 return true; 960 return true;
963} 961}
964 962
965bool blk_mq_dispatch_rq_list(struct blk_mq_hw_ctx *hctx, struct list_head *list) 963bool blk_mq_dispatch_rq_list(struct request_queue *q, struct list_head *list)
966{ 964{
967 struct request_queue *q = hctx->queue; 965 struct blk_mq_hw_ctx *hctx;
968 struct request *rq; 966 struct request *rq;
969 LIST_HEAD(driver_list); 967 LIST_HEAD(driver_list);
970 struct list_head *dptr; 968 struct list_head *dptr;
971 int errors, queued, ret = BLK_MQ_RQ_QUEUE_OK; 969 int errors, queued, ret = BLK_MQ_RQ_QUEUE_OK;
972 970
971 if (list_empty(list))
972 return false;
973
973 /* 974 /*
974 * Start off with dptr being NULL, so we start the first request 975 * Start off with dptr being NULL, so we start the first request
975 * immediately, even if we have more pending. 976 * immediately, even if we have more pending.
@@ -980,7 +981,7 @@ bool blk_mq_dispatch_rq_list(struct blk_mq_hw_ctx *hctx, struct list_head *list)
980 * Now process all the entries, sending them to the driver. 981 * Now process all the entries, sending them to the driver.
981 */ 982 */
982 errors = queued = 0; 983 errors = queued = 0;
983 while (!list_empty(list)) { 984 do {
984 struct blk_mq_queue_data bd; 985 struct blk_mq_queue_data bd;
985 986
986 rq = list_first_entry(list, struct request, queuelist); 987 rq = list_first_entry(list, struct request, queuelist);
@@ -1051,7 +1052,7 @@ bool blk_mq_dispatch_rq_list(struct blk_mq_hw_ctx *hctx, struct list_head *list)
1051 */ 1052 */
1052 if (!dptr && list->next != list->prev) 1053 if (!dptr && list->next != list->prev)
1053 dptr = &driver_list; 1054 dptr = &driver_list;
1054 } 1055 } while (!list_empty(list));
1055 1056
1056 hctx->dispatched[queued_to_index(queued)]++; 1057 hctx->dispatched[queued_to_index(queued)]++;
1057 1058