From 21b049f939822fb7a2d13f2f2eac5f2a99cf9caa Mon Sep 17 00:00:00 2001 From: Shuhei Matsumoto Date: Thu, 17 Jan 2019 17:03:02 +0900 Subject: [PATCH] nvme_perf: Support NVMe formatted with DIX This patch adds DIF generation and verification for NVMe namespace formatted with DIX. Change-Id: Ic67c88c485aacffa40fd0c73ba164f2cb1f88991 Signed-off-by: Shuhei Matsumoto Reviewed-on: https://review.gerrithub.io/c/439969 Tested-by: SPDK CI Jenkins Reviewed-by: Changpeng Liu Reviewed-by: Jim Harris --- examples/nvme/perf/perf.c | 66 +++++++++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 10 deletions(-) diff --git a/examples/nvme/perf/perf.c b/examples/nvme/perf/perf.c index e2abcef3a3..c7cd0a9d0b 100644 --- a/examples/nvme/perf/perf.c +++ b/examples/nvme/perf/perf.c @@ -140,6 +140,7 @@ struct ns_worker_ctx { struct perf_task { struct ns_worker_ctx *ns_ctx; struct iovec iov; + struct iovec md_iov; uint64_t submit_tsc; bool is_read; struct spdk_dif_ctx dif_ctx; @@ -410,7 +411,7 @@ static void io_complete(void *ctx, const struct spdk_nvme_cpl *cpl); static void nvme_setup_payload(struct perf_task *task, uint8_t pattern) { - uint32_t max_io_size_bytes; + uint32_t max_io_size_bytes, max_io_md_size; /* maximum extended lba format size from all active namespace, * it's same with g_io_size_bytes for namespace without metadata. @@ -423,6 +424,17 @@ nvme_setup_payload(struct perf_task *task, uint8_t pattern) exit(1); } memset(task->iov.iov_base, pattern, task->iov.iov_len); + + max_io_md_size = g_max_io_md_size * g_max_io_size_blocks; + if (max_io_md_size != 0) { + task->md_iov.iov_base = spdk_dma_zmalloc(max_io_md_size, g_io_align, NULL); + task->md_iov.iov_len = max_io_md_size; + if (task->md_iov.iov_base == NULL) { + fprintf(stderr, "task->md_buf spdk_dma_zmalloc failed\n"); + spdk_dma_free(task->iov.iov_base); + exit(1); + } + } } static int @@ -430,15 +442,25 @@ nvme_submit_io(struct perf_task *task, struct ns_worker_ctx *ns_ctx, struct ns_entry *entry, uint64_t offset_in_ios) { uint64_t lba; - bool dif_enabled; int rc; + enum dif_mode { + DIF_MODE_NONE = 0, + DIF_MODE_DIF = 1, + DIF_MODE_DIX = 2, + } mode = DIF_MODE_NONE; + lba = offset_in_ios * entry->io_size_blocks; - dif_enabled = entry->md_size != 0 && entry->md_interleave && - !(entry->io_flags & SPDK_NVME_IO_FLAGS_PRACT); + if (entry->md_size != 0 && !(entry->io_flags & SPDK_NVME_IO_FLAGS_PRACT)) { + if (entry->md_interleave) { + mode = DIF_MODE_DIF; + } else { + mode = DIF_MODE_DIX; + } + } - if (dif_enabled) { + if (mode != DIF_MODE_NONE) { rc = spdk_dif_ctx_init(&task->dif_ctx, entry->block_size, entry->md_size, entry->md_interleave, entry->pi_loc, (enum spdk_dif_type)entry->pi_type, entry->io_flags, @@ -451,22 +473,34 @@ nvme_submit_io(struct perf_task *task, struct ns_worker_ctx *ns_ctx, if (task->is_read) { return spdk_nvme_ns_cmd_read_with_md(entry->u.nvme.ns, ns_ctx->u.nvme.qpair, - task->iov.iov_base, NULL, + task->iov.iov_base, task->md_iov.iov_base, lba, entry->io_size_blocks, io_complete, task, entry->io_flags, task->dif_ctx.apptag_mask, task->dif_ctx.app_tag); } else { - if (dif_enabled) { + switch (mode) { + case DIF_MODE_DIF: rc = spdk_dif_generate(&task->iov, 1, entry->io_size_blocks, &task->dif_ctx); if (rc != 0) { fprintf(stderr, "Generation of DIF failed\n"); return rc; } + break; + case DIF_MODE_DIX: + rc = spdk_dix_generate(&task->iov, 1, &task->md_iov, entry->io_size_blocks, + &task->dif_ctx); + if (rc != 0) { + fprintf(stderr, "Generation of DIX failed\n"); + return rc; + } + break; + default: + break; } return spdk_nvme_ns_cmd_write_with_md(entry->u.nvme.ns, ns_ctx->u.nvme.qpair, - task->iov.iov_base, NULL, + task->iov.iov_base, task->md_iov.iov_base, lba, entry->io_size_blocks, io_complete, task, entry->io_flags, @@ -486,14 +520,25 @@ nvme_verify_io(struct perf_task *task, struct ns_entry *entry) struct spdk_dif_error err_blk = {}; int rc; - if (task->is_read && entry->md_size != 0 && entry->md_interleave && - !(entry->io_flags & SPDK_NVME_IO_FLAGS_PRACT)) { + if (!task->is_read || entry->md_size == 0 || + (entry->io_flags & SPDK_NVME_IO_FLAGS_PRACT)) { + return; + } + + if (entry->md_interleave) { rc = spdk_dif_verify(&task->iov, 1, entry->io_size_blocks, &task->dif_ctx, &err_blk); if (rc != 0) { fprintf(stderr, "DIF error detected. type=%d, offset=%" PRIu32 "\n", err_blk.err_type, err_blk.err_offset); } + } else { + rc = spdk_dix_verify(&task->iov, 1, &task->md_iov, entry->io_size_blocks, + &task->dif_ctx, &err_blk); + if (rc != 0) { + fprintf(stderr, "DIX error detected. type=%d, offset=%" PRIu32 "\n", + err_blk.err_type, err_blk.err_offset); + } } } @@ -795,6 +840,7 @@ task_complete(struct perf_task *task) */ if (ns_ctx->is_draining) { spdk_dma_free(task->iov.iov_base); + spdk_dma_free(task->md_iov.iov_base); free(task); } else { submit_single_io(task);