]> www.infradead.org Git - nvme.git/commitdiff
nvmet: Introduce nvmet_req_transfer_len()
authorDamien Le Moal <dlemoal@kernel.org>
Sat, 4 Jan 2025 04:59:41 +0000 (13:59 +0900)
committerKeith Busch <kbusch@kernel.org>
Sat, 11 Jan 2025 03:30:47 +0000 (19:30 -0800)
Add the new function nvmet_req_transfer_len() to parse a request command
to extract the transfer length of the command. This function
implementation relies on multiple helper functions for parsing I/O
commands (nvmet_io_cmd_transfer_len()), admin commands
(nvmet_admin_cmd_data_len()) and fabrics connect commands
(nvmet_connect_cmd_data_len).

Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Tested-by: Rick Wertenbroek <rick.wertenbroek@gmail.com>
Tested-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: Keith Busch <kbusch@kernel.org>
drivers/nvme/target/admin-cmd.c
drivers/nvme/target/core.c
drivers/nvme/target/discovery.c
drivers/nvme/target/fabrics-cmd-auth.c
drivers/nvme/target/fabrics-cmd.c
drivers/nvme/target/nvmet.h

index 78478a4a2e4dedd178063ddc0d12c8555cdde148..6f7e5b0c91c7279f3ee578f57e19bfe2438d0182 100644 (file)
@@ -1296,6 +1296,27 @@ out:
        nvmet_req_complete(req, status);
 }
 
+u32 nvmet_admin_cmd_data_len(struct nvmet_req *req)
+{
+       struct nvme_command *cmd = req->cmd;
+
+       if (nvme_is_fabrics(cmd))
+               return nvmet_fabrics_admin_cmd_data_len(req);
+       if (nvmet_is_disc_subsys(nvmet_req_subsys(req)))
+               return nvmet_discovery_cmd_data_len(req);
+
+       switch (cmd->common.opcode) {
+       case nvme_admin_get_log_page:
+               return nvmet_get_log_page_len(cmd);
+       case nvme_admin_identify:
+               return NVME_IDENTIFY_DATA_SIZE;
+       case nvme_admin_get_features:
+               return nvmet_feat_data_len(req, le32_to_cpu(cmd->common.cdw10));
+       default:
+               return 0;
+       }
+}
+
 u16 nvmet_parse_admin_cmd(struct nvmet_req *req)
 {
        struct nvme_command *cmd = req->cmd;
index 4909f3e5a55252a98b3733a9b84da6bf4e548ccb..9bca3e5768935abd556f4991ec0944dfbde1be98 100644 (file)
@@ -911,6 +911,33 @@ static inline u16 nvmet_io_cmd_check_access(struct nvmet_req *req)
        return 0;
 }
 
+static u32 nvmet_io_cmd_transfer_len(struct nvmet_req *req)
+{
+       struct nvme_command *cmd = req->cmd;
+       u32 metadata_len = 0;
+
+       if (nvme_is_fabrics(cmd))
+               return nvmet_fabrics_io_cmd_data_len(req);
+
+       if (!req->ns)
+               return 0;
+
+       switch (req->cmd->common.opcode) {
+       case nvme_cmd_read:
+       case nvme_cmd_write:
+       case nvme_cmd_zone_append:
+               if (req->sq->ctrl->pi_support && nvmet_ns_has_pi(req->ns))
+                       metadata_len = nvmet_rw_metadata_len(req);
+               return nvmet_rw_data_len(req) + metadata_len;
+       case nvme_cmd_dsm:
+               return nvmet_dsm_len(req);
+       case nvme_cmd_zone_mgmt_recv:
+               return (le32_to_cpu(req->cmd->zmr.numd) + 1) << 2;
+       default:
+               return 0;
+       }
+}
+
 static u16 nvmet_parse_io_cmd(struct nvmet_req *req)
 {
        struct nvme_command *cmd = req->cmd;
@@ -1059,6 +1086,16 @@ void nvmet_req_uninit(struct nvmet_req *req)
 }
 EXPORT_SYMBOL_GPL(nvmet_req_uninit);
 
+size_t nvmet_req_transfer_len(struct nvmet_req *req)
+{
+       if (likely(req->sq->qid != 0))
+               return nvmet_io_cmd_transfer_len(req);
+       if (unlikely(!req->sq->ctrl))
+               return nvmet_connect_cmd_data_len(req);
+       return nvmet_admin_cmd_data_len(req);
+}
+EXPORT_SYMBOL_GPL(nvmet_req_transfer_len);
+
 bool nvmet_check_transfer_len(struct nvmet_req *req, size_t len)
 {
        if (unlikely(len != req->transfer_len)) {
index 7a13f8e8d33de10abfb075790ed1ce94ba761e37..df72076405062f788ee9a57f4e4dd5c82c7954b1 100644 (file)
@@ -355,6 +355,20 @@ static void nvmet_execute_disc_get_features(struct nvmet_req *req)
        nvmet_req_complete(req, stat);
 }
 
+u32 nvmet_discovery_cmd_data_len(struct nvmet_req *req)
+{
+       struct nvme_command *cmd = req->cmd;
+
+       switch (cmd->common.opcode) {
+       case nvme_admin_get_log_page:
+               return nvmet_get_log_page_len(req->cmd);
+       case nvme_admin_identify:
+               return NVME_IDENTIFY_DATA_SIZE;
+       default:
+               return 0;
+       }
+}
+
 u16 nvmet_parse_discovery_cmd(struct nvmet_req *req)
 {
        struct nvme_command *cmd = req->cmd;
index 3f2857c17d956ae3f2c6351015d2ca541f69b221..2022757f08dc76be3b332e738352095e3a5ebf8d 100644 (file)
@@ -179,6 +179,11 @@ static u8 nvmet_auth_failure2(void *d)
        return data->rescode_exp;
 }
 
+u32 nvmet_auth_send_data_len(struct nvmet_req *req)
+{
+       return le32_to_cpu(req->cmd->auth_send.tl);
+}
+
 void nvmet_execute_auth_send(struct nvmet_req *req)
 {
        struct nvmet_ctrl *ctrl = req->sq->ctrl;
@@ -206,7 +211,7 @@ void nvmet_execute_auth_send(struct nvmet_req *req)
                        offsetof(struct nvmf_auth_send_command, spsp1);
                goto done;
        }
-       tl = le32_to_cpu(req->cmd->auth_send.tl);
+       tl = nvmet_auth_send_data_len(req);
        if (!tl) {
                status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
                req->error_loc =
@@ -429,6 +434,11 @@ static void nvmet_auth_failure1(struct nvmet_req *req, void *d, int al)
        data->rescode_exp = req->sq->dhchap_status;
 }
 
+u32 nvmet_auth_receive_data_len(struct nvmet_req *req)
+{
+       return le32_to_cpu(req->cmd->auth_receive.al);
+}
+
 void nvmet_execute_auth_receive(struct nvmet_req *req)
 {
        struct nvmet_ctrl *ctrl = req->sq->ctrl;
@@ -454,7 +464,7 @@ void nvmet_execute_auth_receive(struct nvmet_req *req)
                        offsetof(struct nvmf_auth_receive_command, spsp1);
                goto done;
        }
-       al = le32_to_cpu(req->cmd->auth_receive.al);
+       al = nvmet_auth_receive_data_len(req);
        if (!al) {
                status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
                req->error_loc =
index 8dbd7df8c9a0d82a9163fe41978b209f841c7157..a7ff05b3be29fb8038a8e8ff5e1139caf02f96fe 100644 (file)
@@ -85,6 +85,22 @@ static void nvmet_execute_prop_get(struct nvmet_req *req)
        nvmet_req_complete(req, status);
 }
 
+u32 nvmet_fabrics_admin_cmd_data_len(struct nvmet_req *req)
+{
+       struct nvme_command *cmd = req->cmd;
+
+       switch (cmd->fabrics.fctype) {
+#ifdef CONFIG_NVME_TARGET_AUTH
+       case nvme_fabrics_type_auth_send:
+               return nvmet_auth_send_data_len(req);
+       case nvme_fabrics_type_auth_receive:
+               return nvmet_auth_receive_data_len(req);
+#endif
+       default:
+               return 0;
+       }
+}
+
 u16 nvmet_parse_fabrics_admin_cmd(struct nvmet_req *req)
 {
        struct nvme_command *cmd = req->cmd;
@@ -114,6 +130,22 @@ u16 nvmet_parse_fabrics_admin_cmd(struct nvmet_req *req)
        return 0;
 }
 
+u32 nvmet_fabrics_io_cmd_data_len(struct nvmet_req *req)
+{
+       struct nvme_command *cmd = req->cmd;
+
+       switch (cmd->fabrics.fctype) {
+#ifdef CONFIG_NVME_TARGET_AUTH
+       case nvme_fabrics_type_auth_send:
+               return nvmet_auth_send_data_len(req);
+       case nvme_fabrics_type_auth_receive:
+               return nvmet_auth_receive_data_len(req);
+#endif
+       default:
+               return 0;
+       }
+}
+
 u16 nvmet_parse_fabrics_io_cmd(struct nvmet_req *req)
 {
        struct nvme_command *cmd = req->cmd;
@@ -337,6 +369,17 @@ out_ctrl_put:
        goto out;
 }
 
+u32 nvmet_connect_cmd_data_len(struct nvmet_req *req)
+{
+       struct nvme_command *cmd = req->cmd;
+
+       if (!nvme_is_fabrics(cmd) ||
+           cmd->fabrics.fctype != nvme_fabrics_type_connect)
+               return 0;
+
+       return sizeof(struct nvmf_connect_data);
+}
+
 u16 nvmet_parse_connect_cmd(struct nvmet_req *req)
 {
        struct nvme_command *cmd = req->cmd;
index ed7e8cd890e4bc25a9f135468991f37b4731a042..96c4c2489be7f9fa29aa2dcd960bd57fc8d417e6 100644 (file)
@@ -517,18 +517,24 @@ void nvmet_start_keep_alive_timer(struct nvmet_ctrl *ctrl);
 void nvmet_stop_keep_alive_timer(struct nvmet_ctrl *ctrl);
 
 u16 nvmet_parse_connect_cmd(struct nvmet_req *req);
+u32 nvmet_connect_cmd_data_len(struct nvmet_req *req);
 void nvmet_bdev_set_limits(struct block_device *bdev, struct nvme_id_ns *id);
 u16 nvmet_bdev_parse_io_cmd(struct nvmet_req *req);
 u16 nvmet_file_parse_io_cmd(struct nvmet_req *req);
 u16 nvmet_bdev_zns_parse_io_cmd(struct nvmet_req *req);
+u32 nvmet_admin_cmd_data_len(struct nvmet_req *req);
 u16 nvmet_parse_admin_cmd(struct nvmet_req *req);
+u32 nvmet_discovery_cmd_data_len(struct nvmet_req *req);
 u16 nvmet_parse_discovery_cmd(struct nvmet_req *req);
 u16 nvmet_parse_fabrics_admin_cmd(struct nvmet_req *req);
+u32 nvmet_fabrics_admin_cmd_data_len(struct nvmet_req *req);
 u16 nvmet_parse_fabrics_io_cmd(struct nvmet_req *req);
+u32 nvmet_fabrics_io_cmd_data_len(struct nvmet_req *req);
 
 bool nvmet_req_init(struct nvmet_req *req, struct nvmet_cq *cq,
                struct nvmet_sq *sq, const struct nvmet_fabrics_ops *ops);
 void nvmet_req_uninit(struct nvmet_req *req);
+size_t nvmet_req_transfer_len(struct nvmet_req *req);
 bool nvmet_check_transfer_len(struct nvmet_req *req, size_t len);
 bool nvmet_check_data_len_lte(struct nvmet_req *req, size_t data_len);
 void nvmet_req_complete(struct nvmet_req *req, u16 status);
@@ -822,7 +828,9 @@ static inline void nvmet_req_bio_put(struct nvmet_req *req, struct bio *bio)
 }
 
 #ifdef CONFIG_NVME_TARGET_AUTH
+u32 nvmet_auth_send_data_len(struct nvmet_req *req);
 void nvmet_execute_auth_send(struct nvmet_req *req);
+u32 nvmet_auth_receive_data_len(struct nvmet_req *req);
 void nvmet_execute_auth_receive(struct nvmet_req *req);
 int nvmet_auth_set_key(struct nvmet_host *host, const char *secret,
                       bool set_ctrl);