nvme: use return value from blk_execute_rq()
authorKeith Busch <kbusch@kernel.org>
Thu, 10 Jun 2021 21:44:37 +0000 (14:44 -0700)
committerJens Axboe <axboe@kernel.dk>
Wed, 30 Jun 2021 21:35:45 +0000 (15:35 -0600)
We don't have an nvme status to report if the driver's .queue_rq()
returns an error without dispatching the requested nvme command. Check
the return value from blk_execute_rq() for all passthrough commands so
the caller may know their command was not successful.

If the command is from the target passthrough interface and fails to
dispatch, synthesize the response back to the host as a internal target
error.

Signed-off-by: Keith Busch <kbusch@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
Link: https://lore.kernel.org/r/20210610214437.641245-5-kbusch@kernel.org
Signed-off-by: Jens Axboe <axboe@kernel.dk>
drivers/nvme/host/core.c
drivers/nvme/host/ioctl.c
drivers/nvme/host/nvme.h
drivers/nvme/target/passthru.c

index e0d3f0aa25da6234637b9882c2939fd01d096016..11779be4218686a353b230772bef20d28a2de510 100644 (file)
@@ -609,6 +609,7 @@ EXPORT_SYMBOL_NS_GPL(nvme_put_ns, NVME_TARGET_PASSTHRU);
 
 static inline void nvme_clear_nvme_request(struct request *req)
 {
+       nvme_req(req)->status = 0;
        nvme_req(req)->retries = 0;
        nvme_req(req)->flags = 0;
        req->rq_flags |= RQF_DONTPREP;
@@ -1031,6 +1032,25 @@ blk_status_t nvme_setup_cmd(struct nvme_ns *ns, struct request *req)
 }
 EXPORT_SYMBOL_GPL(nvme_setup_cmd);
 
+/*
+ * Return values:
+ * 0:  success
+ * >0: nvme controller's cqe status response
+ * <0: kernel error in lieu of controller response
+ */
+static int nvme_execute_rq(struct gendisk *disk, struct request *rq,
+               bool at_head)
+{
+       blk_status_t status;
+
+       status = blk_execute_rq(disk, rq, at_head);
+       if (nvme_req(rq)->flags & NVME_REQ_CANCELLED)
+               return -EINTR;
+       if (nvme_req(rq)->status)
+               return nvme_req(rq)->status;
+       return blk_status_to_errno(status);
+}
+
 /*
  * Returns 0 on success.  If the result is negative, it's a Linux error code;
  * if the result is positive, it's an NVM Express status code
@@ -1059,13 +1079,9 @@ int __nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
                        goto out;
        }
 
-       blk_execute_rq(NULL, req, at_head);
-       if (result)
+       ret = nvme_execute_rq(NULL, req, at_head);
+       if (result && ret >= 0)
                *result = nvme_req(req)->result;
-       if (nvme_req(req)->flags & NVME_REQ_CANCELLED)
-               ret = -EINTR;
-       else
-               ret = nvme_req(req)->status;
  out:
        blk_mq_free_request(req);
        return ret;
@@ -1153,18 +1169,21 @@ static void nvme_passthru_end(struct nvme_ctrl *ctrl, u32 effects)
        }
 }
 
-void nvme_execute_passthru_rq(struct request *rq)
+int nvme_execute_passthru_rq(struct request *rq)
 {
        struct nvme_command *cmd = nvme_req(rq)->cmd;
        struct nvme_ctrl *ctrl = nvme_req(rq)->ctrl;
        struct nvme_ns *ns = rq->q->queuedata;
        struct gendisk *disk = ns ? ns->disk : NULL;
        u32 effects;
+       int  ret;
 
        effects = nvme_passthru_start(ctrl, ns, cmd->common.opcode);
-       blk_execute_rq(disk, rq, 0);
+       ret = nvme_execute_rq(disk, rq, false);
        if (effects) /* nothing to be done for zero cmd effects */
                nvme_passthru_end(ctrl, effects);
+
+       return ret;
 }
 EXPORT_SYMBOL_NS_GPL(nvme_execute_passthru_rq, NVME_TARGET_PASSTHRU);
 
index d93928d1e5bd46612530891aa9b6c0b1cef52f7c..305ddd415e45a3facbe91e86121bcd12509776b1 100644 (file)
@@ -93,11 +93,7 @@ static int nvme_submit_user_cmd(struct request_queue *q,
                }
        }
 
-       nvme_execute_passthru_rq(req);
-       if (nvme_req(req)->flags & NVME_REQ_CANCELLED)
-               ret = -EINTR;
-       else
-               ret = nvme_req(req)->status;
+       ret = nvme_execute_passthru_rq(req);
        if (result)
                *result = le64_to_cpu(nvme_req(req)->result.u64);
        if (meta && !ret && !write) {
index 3b12ad78ee7a6abad3f2fec81ee3115c6bd9d6b5..18ef8dd03a90e2fd2c807befb0ef154fc1efa426 100644 (file)
@@ -876,7 +876,7 @@ static inline bool nvme_ctrl_sgl_supported(struct nvme_ctrl *ctrl)
 
 u32 nvme_command_effects(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
                         u8 opcode);
-void nvme_execute_passthru_rq(struct request *rq);
+int nvme_execute_passthru_rq(struct request *rq);
 struct nvme_ctrl *nvme_ctrl_from_file(struct file *file);
 struct nvme_ns *nvme_find_get_ns(struct nvme_ctrl *ctrl, unsigned nsid);
 void nvme_put_ns(struct nvme_ns *ns);
index fced52de33ce9331e4f6d2c76b7abb193cdc5b06..225cd1ffbe45881fd133f9af9f4fb45ec620cf1d 100644 (file)
@@ -153,11 +153,10 @@ static void nvmet_passthru_execute_cmd_work(struct work_struct *w)
 {
        struct nvmet_req *req = container_of(w, struct nvmet_req, p.work);
        struct request *rq = req->p.rq;
-       u16 status;
+       int status;
 
-       nvme_execute_passthru_rq(rq);
+       status = nvme_execute_passthru_rq(rq);
 
-       status = nvme_req(rq)->status;
        if (status == NVME_SC_SUCCESS &&
            req->cmd->common.opcode == nvme_admin_identify) {
                switch (req->cmd->identify.cns) {
@@ -168,7 +167,8 @@ static void nvmet_passthru_execute_cmd_work(struct work_struct *w)
                        nvmet_passthru_override_id_ns(req);
                        break;
                }
-       }
+       } else if (status < 0)
+               status = NVME_SC_INTERNAL;
 
        req->cqe->result = nvme_req(rq)->result;
        nvmet_req_complete(req, status);