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 <shuhei.matsumoto.xt@hitachi.com>
Reviewed-on: https://review.gerrithub.io/c/439969
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
Shuhei Matsumoto 2019-01-17 17:03:02 +09:00 committed by Jim Harris
parent 35cdee26ad
commit 21b049f939

View File

@ -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);