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:
parent
35cdee26ad
commit
21b049f939
@ -140,6 +140,7 @@ struct ns_worker_ctx {
|
|||||||
struct perf_task {
|
struct perf_task {
|
||||||
struct ns_worker_ctx *ns_ctx;
|
struct ns_worker_ctx *ns_ctx;
|
||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
|
struct iovec md_iov;
|
||||||
uint64_t submit_tsc;
|
uint64_t submit_tsc;
|
||||||
bool is_read;
|
bool is_read;
|
||||||
struct spdk_dif_ctx dif_ctx;
|
struct spdk_dif_ctx dif_ctx;
|
||||||
@ -410,7 +411,7 @@ static void io_complete(void *ctx, const struct spdk_nvme_cpl *cpl);
|
|||||||
static void
|
static void
|
||||||
nvme_setup_payload(struct perf_task *task, uint8_t pattern)
|
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,
|
/* maximum extended lba format size from all active namespace,
|
||||||
* it's same with g_io_size_bytes for namespace without metadata.
|
* 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);
|
exit(1);
|
||||||
}
|
}
|
||||||
memset(task->iov.iov_base, pattern, task->iov.iov_len);
|
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
|
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)
|
struct ns_entry *entry, uint64_t offset_in_ios)
|
||||||
{
|
{
|
||||||
uint64_t lba;
|
uint64_t lba;
|
||||||
bool dif_enabled;
|
|
||||||
int rc;
|
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;
|
lba = offset_in_ios * entry->io_size_blocks;
|
||||||
|
|
||||||
dif_enabled = entry->md_size != 0 && entry->md_interleave &&
|
if (entry->md_size != 0 && !(entry->io_flags & SPDK_NVME_IO_FLAGS_PRACT)) {
|
||||||
!(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,
|
rc = spdk_dif_ctx_init(&task->dif_ctx, entry->block_size, entry->md_size,
|
||||||
entry->md_interleave, entry->pi_loc,
|
entry->md_interleave, entry->pi_loc,
|
||||||
(enum spdk_dif_type)entry->pi_type, entry->io_flags,
|
(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) {
|
if (task->is_read) {
|
||||||
return spdk_nvme_ns_cmd_read_with_md(entry->u.nvme.ns, ns_ctx->u.nvme.qpair,
|
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,
|
lba,
|
||||||
entry->io_size_blocks, io_complete,
|
entry->io_size_blocks, io_complete,
|
||||||
task, entry->io_flags,
|
task, entry->io_flags,
|
||||||
task->dif_ctx.apptag_mask, task->dif_ctx.app_tag);
|
task->dif_ctx.apptag_mask, task->dif_ctx.app_tag);
|
||||||
} else {
|
} else {
|
||||||
if (dif_enabled) {
|
switch (mode) {
|
||||||
|
case DIF_MODE_DIF:
|
||||||
rc = spdk_dif_generate(&task->iov, 1, entry->io_size_blocks, &task->dif_ctx);
|
rc = spdk_dif_generate(&task->iov, 1, entry->io_size_blocks, &task->dif_ctx);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
fprintf(stderr, "Generation of DIF failed\n");
|
fprintf(stderr, "Generation of DIF failed\n");
|
||||||
return rc;
|
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,
|
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,
|
lba,
|
||||||
entry->io_size_blocks, io_complete,
|
entry->io_size_blocks, io_complete,
|
||||||
task, entry->io_flags,
|
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 = {};
|
struct spdk_dif_error err_blk = {};
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (task->is_read && entry->md_size != 0 && entry->md_interleave &&
|
if (!task->is_read || entry->md_size == 0 ||
|
||||||
!(entry->io_flags & SPDK_NVME_IO_FLAGS_PRACT)) {
|
(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,
|
rc = spdk_dif_verify(&task->iov, 1, entry->io_size_blocks, &task->dif_ctx,
|
||||||
&err_blk);
|
&err_blk);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
fprintf(stderr, "DIF error detected. type=%d, offset=%" PRIu32 "\n",
|
fprintf(stderr, "DIF error detected. type=%d, offset=%" PRIu32 "\n",
|
||||||
err_blk.err_type, err_blk.err_offset);
|
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) {
|
if (ns_ctx->is_draining) {
|
||||||
spdk_dma_free(task->iov.iov_base);
|
spdk_dma_free(task->iov.iov_base);
|
||||||
|
spdk_dma_free(task->md_iov.iov_base);
|
||||||
free(task);
|
free(task);
|
||||||
} else {
|
} else {
|
||||||
submit_single_io(task);
|
submit_single_io(task);
|
||||||
|
Loading…
Reference in New Issue
Block a user