nvmet: avoid duplicate qid in connect cmd
authorAmit Engel <amit.engel@dell.com>
Sun, 8 Aug 2021 15:06:15 +0000 (18:06 +0300)
committerChristoph Hellwig <hch@lst.de>
Mon, 16 Aug 2021 12:42:25 +0000 (14:42 +0200)
According to the NVMe specification, if the host sends a Connect command
specifying a queue id which has already been created, a status value of
NVME_SC_CMD_SEQ_ERROR is returned.

Signed-off-by: Amit Engel <amit.engel@dell.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
drivers/nvme/target/core.c
drivers/nvme/target/fabrics-cmd.c

index ac7210a..66d05ee 100644 (file)
@@ -802,6 +802,7 @@ void nvmet_sq_destroy(struct nvmet_sq *sq)
                 * controller teardown as a result of a keep-alive expiration.
                 */
                ctrl->reset_tbkas = true;
+               sq->ctrl->sqs[sq->qid] = NULL;
                nvmet_ctrl_put(ctrl);
                sq->ctrl = NULL; /* allows reusing the queue later */
        }
index 8ef564c..6f14da5 100644 (file)
@@ -111,12 +111,6 @@ static u16 nvmet_install_queue(struct nvmet_ctrl *ctrl, struct nvmet_req *req)
        struct nvmet_ctrl *old;
        u16 ret;
 
-       old = cmpxchg(&req->sq->ctrl, NULL, ctrl);
-       if (old) {
-               pr_warn("queue already connected!\n");
-               req->error_loc = offsetof(struct nvmf_connect_command, opcode);
-               return NVME_SC_CONNECT_CTRL_BUSY | NVME_SC_DNR;
-       }
        if (!sqsize) {
                pr_warn("queue size zero!\n");
                req->error_loc = offsetof(struct nvmf_connect_command, sqsize);
@@ -125,6 +119,19 @@ static u16 nvmet_install_queue(struct nvmet_ctrl *ctrl, struct nvmet_req *req)
                goto err;
        }
 
+       if (ctrl->sqs[qid] != NULL) {
+               pr_warn("qid %u has already been created\n", qid);
+               req->error_loc = offsetof(struct nvmf_connect_command, qid);
+               return NVME_SC_CMD_SEQ_ERROR | NVME_SC_DNR;
+       }
+
+       old = cmpxchg(&req->sq->ctrl, NULL, ctrl);
+       if (old) {
+               pr_warn("queue already connected!\n");
+               req->error_loc = offsetof(struct nvmf_connect_command, opcode);
+               return NVME_SC_CONNECT_CTRL_BUSY | NVME_SC_DNR;
+       }
+
        /* note: convert queue size from 0's-based value to 1's-based value */
        nvmet_cq_setup(ctrl, req->cq, qid, sqsize + 1);
        nvmet_sq_setup(ctrl, req->sq, qid, sqsize + 1);
@@ -139,6 +146,7 @@ static u16 nvmet_install_queue(struct nvmet_ctrl *ctrl, struct nvmet_req *req)
                if (ret) {
                        pr_err("failed to install queue %d cntlid %d ret %x\n",
                                qid, ctrl->cntlid, ret);
+                       ctrl->sqs[qid] = NULL;
                        goto err;
                }
        }