summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Busch <kbusch@kernel.org>2022-01-05 09:05:18 -0800
committerJens Axboe <axboe@kernel.dk>2022-01-05 12:25:42 -0700
commit6bfec7992ec79b63fb07330ae97f3fb43120aa37 (patch)
tree4c60031a5cd7a7dcf157102474fddabc70ddb524
parentd2528be7a8b09af9796a270debd14101a72bb552 (diff)
nvme-pci: fix queue_rqs list splitting
If command prep fails, current handling will orphan subsequent requests in the list. Consider a simple example: rqlist = [ 1 -> 2 ] When prep for request '1' fails, it will be appended to the 'requeue_list', leaving request '2' disconnected from the original rqlist and no longer tracked. Meanwhile, rqlist is still pointing to the failed request '1' and will attempt to submit the unprepped command. Fix this by updating the rqlist accordingly using the request list helper functions. Fixes: d62cbcf62f2f ("nvme: add support for mq_ops->queue_rqs()") Signed-off-by: Keith Busch <kbusch@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de> Link: https://lore.kernel.org/r/20220105170518.3181469-5-kbusch@kernel.org Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r--drivers/nvme/host/pci.c28
1 files changed, 14 insertions, 14 deletions
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 50deb8b69c40..d8585df2c2fd 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -999,30 +999,30 @@ static bool nvme_prep_rq_batch(struct nvme_queue *nvmeq, struct request *req)
static void nvme_queue_rqs(struct request **rqlist)
{
- struct request *req = rq_list_peek(rqlist), *prev = NULL;
+ struct request *req, *next, *prev = NULL;
struct request *requeue_list = NULL;
- do {
+ rq_list_for_each_safe(rqlist, req, next) {
struct nvme_queue *nvmeq = req->mq_hctx->driver_data;
if (!nvme_prep_rq_batch(nvmeq, req)) {
/* detach 'req' and add to remainder list */
- if (prev)
- prev->rq_next = req->rq_next;
- rq_list_add(&requeue_list, req);
- } else {
- prev = req;
+ rq_list_move(rqlist, &requeue_list, req, prev);
+
+ req = prev;
+ if (!req)
+ continue;
}
- req = rq_list_next(req);
- if (!req || (prev && req->mq_hctx != prev->mq_hctx)) {
+ if (!next || req->mq_hctx != next->mq_hctx) {
/* detach rest of list, and submit */
- if (prev)
- prev->rq_next = NULL;
+ req->rq_next = NULL;
nvme_submit_cmds(nvmeq, rqlist);
- *rqlist = req;
- }
- } while (req);
+ *rqlist = next;
+ prev = NULL;
+ } else
+ prev = req;
+ }
*rqlist = requeue_list;
}