[PATCH 1/7] nvmet: add support of Compare command
Dmitry Bogdanov
d.bogdanov at yadro.com
Wed Sep 11 23:42:53 PDT 2024
Report that Compare command is supported.
Make a common function for comparision of datas from the command and
from the backstore.
Signed-off-by: Dmitry Bogdanov <d.bogdanov at yadro.com>
---
drivers/nvme/target/admin-cmd.c | 4 ++-
drivers/nvme/target/core.c | 55 +++++++++++++++++++++++++++++++++
drivers/nvme/target/nvmet.h | 2 ++
3 files changed, 60 insertions(+), 1 deletion(-)
diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index d64480f01f4a..e555b9efebfb 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -176,6 +176,7 @@ static void nvmet_get_cmd_effects_nvm(struct nvme_effects_log *log)
log->iocs[nvme_cmd_read] =
log->iocs[nvme_cmd_flush] =
log->iocs[nvme_cmd_dsm] =
+ log->iocs[nvme_cmd_compare] =
cpu_to_le32(NVME_CMD_EFFECTS_CSUPP);
log->iocs[nvme_cmd_write] =
log->iocs[nvme_cmd_write_zeroes] =
@@ -433,7 +434,8 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
id->nn = cpu_to_le32(NVMET_MAX_NAMESPACES);
id->mnan = cpu_to_le32(NVMET_MAX_NAMESPACES);
id->oncs = cpu_to_le16(NVME_CTRL_ONCS_DSM |
- NVME_CTRL_ONCS_WRITE_ZEROES);
+ NVME_CTRL_ONCS_WRITE_ZEROES |
+ NVME_CTRL_ONCS_COMPARE);
/* XXX: don't report vwc if the underlying device is write through */
id->vwc = NVME_CTRL_VWC_PRESENT;
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index ed2424f8a396..b3194d66f7dc 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -751,6 +751,59 @@ static void nvmet_set_error(struct nvmet_req *req, u16 status)
req->cqe->status |= cpu_to_le16(1 << 14);
}
+int nvmet_compare_sg(struct nvmet_req *req)
+{
+ unsigned int data_len = nvmet_rw_data_len(req);
+ unsigned int offset = 0;
+ struct scatterlist *sg;
+ unsigned int len;
+ u8 *datap = NULL;
+ u8 *buf = NULL;
+ int ret = 0;
+ int i;
+
+ buf = kmalloc(data_len, GFP_ATOMIC);
+ if (!buf)
+ return NVME_SC_INTERNAL;
+
+ /* Copy READ data to the buffer */
+ ret = nvmet_copy_from_sgl(req, 0, buf, data_len);
+ if (ret)
+ goto error;
+
+ /* Compare on-disk data with the data provided by the initiator */
+ for_each_sg(req->cmp_sg, sg, req->sg_cnt, i) {
+ datap = kmap_atomic(sg_page(sg));
+ if (!datap) {
+ ret = NVME_SC_INTERNAL;
+ goto error;
+ }
+
+ len = min_t(unsigned int, sg->length, data_len);
+
+ if (memcmp(datap, buf + offset, len) != 0) {
+ ret = NVME_SC_COMPARE_FAILED;
+ goto error;
+ }
+
+ kunmap_atomic(datap);
+
+ offset += len;
+ if (offset == data_len)
+ break;
+ }
+
+ kfree(buf);
+
+ return 0;
+error:
+ if (datap)
+ kunmap_atomic(datap);
+
+ kfree(buf);
+ return ret;
+}
+
static void __nvmet_req_complete(struct nvmet_req *req, u16 status)
{
struct nvmet_ns *ns = req->ns;
@@ -887,6 +940,7 @@ static inline u16 nvmet_io_cmd_check_access(struct nvmet_req *req)
switch (req->cmd->common.opcode) {
case nvme_cmd_read:
case nvme_cmd_flush:
+ case nvme_cmd_compare:
break;
default:
return NVME_SC_NS_WRITE_PROTECTED;
@@ -953,6 +1007,7 @@ bool nvmet_req_init(struct nvmet_req *req, struct nvmet_cq *cq,
req->sq = sq;
req->ops = ops;
req->sg = NULL;
+ req->cmp_sg = NULL;
req->metadata_sg = NULL;
req->sg_cnt = 0;
req->metadata_sg_cnt = 0;
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 190f55e6d753..8a26b8b4dc63 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -373,6 +373,7 @@ struct nvmet_req {
struct nvmet_ns *ns;
struct scatterlist *sg;
struct scatterlist *metadata_sg;
+ struct scatterlist *cmp_sg;
struct bio_vec inline_bvec[NVMET_MAX_INLINE_BIOVEC];
union {
struct {
@@ -602,6 +603,7 @@ void nvmet_bdev_ns_revalidate(struct nvmet_ns *ns);
void nvmet_file_ns_revalidate(struct nvmet_ns *ns);
bool nvmet_ns_revalidate(struct nvmet_ns *ns);
u16 blk_to_nvme_status(struct nvmet_req *req, blk_status_t blk_sts);
+int nvmet_compare_sg(struct nvmet_req *req);
bool nvmet_bdev_zns_enable(struct nvmet_ns *ns);
void nvmet_execute_identify_ctrl_zns(struct nvmet_req *req);
--
2.25.1
More information about the Linux-nvme
mailing list