From 66bace41d7dc3f791cf5f109723cbfda6d73ddbe Mon Sep 17 00:00:00 2001 From: Konrad Sztyber Date: Tue, 16 Apr 2019 10:17:59 +0200 Subject: [PATCH] bdevperf: use separate metadata buffers Use separate buffers for metadata transfer if bdev supports it. Change-Id: Ie0fa3d3c1f5b14f99c13f2d6b5b22edc216c6d64 Signed-off-by: Konrad Sztyber Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/451468 Tested-by: SPDK CI Jenkins Reviewed-by: Ben Walker Reviewed-by: Shuhei Matsumoto --- test/bdev/bdevperf/bdevperf.c | 132 +++++++++++++++++++++++++++------- 1 file changed, 105 insertions(+), 27 deletions(-) diff --git a/test/bdev/bdevperf/bdevperf.c b/test/bdev/bdevperf/bdevperf.c index b8fee1c4b..357884ca4 100644 --- a/test/bdev/bdevperf/bdevperf.c +++ b/test/bdev/bdevperf/bdevperf.c @@ -47,6 +47,7 @@ struct bdevperf_task { struct iovec iov; struct io_target *target; void *buf; + void *md_buf; uint64_t offset_blocks; enum spdk_bdev_io_type io_type; TAILQ_ENTRY(bdevperf_task) link; @@ -116,39 +117,72 @@ static int g_target_count = 0; static size_t g_min_alignment = 8; static void -generate_data(void *buf, int buf_len, int block_size, int md_size, +generate_data(void *buf, int buf_len, int block_size, void *md_buf, int md_size, int num_blocks, int seed) { - int offset_blocks = 0; + int offset_blocks = 0, md_offset, data_block_size; if (buf_len < num_blocks * block_size) { return; } + if (md_buf == NULL) { + data_block_size = block_size - md_size; + md_buf = (char *)buf + data_block_size; + md_offset = block_size; + } else { + data_block_size = block_size; + md_offset = md_size; + } + while (offset_blocks < num_blocks) { - memset(buf, seed, block_size - md_size); - memset(buf + block_size - md_size, 0, md_size); + memset(buf, seed, data_block_size); + memset(md_buf, seed, md_size); buf += block_size; + md_buf += md_offset; offset_blocks++; } } static bool -verify_data(void *wr_buf, int wr_buf_len, void *rd_buf, int rd_buf_len, - int block_size, int md_size, int num_blocks) +verify_data(void *wr_buf, int wr_buf_len, void *rd_buf, int rd_buf_len, int block_size, + void *wr_md_buf, void *rd_md_buf, int md_size, int num_blocks, bool md_check) { - int offset_blocks = 0; + int offset_blocks = 0, md_offset, data_block_size; if (wr_buf_len < num_blocks * block_size || rd_buf_len < num_blocks * block_size) { return false; } + assert((wr_md_buf != NULL) == (rd_md_buf != NULL)); + + if (wr_md_buf == NULL) { + data_block_size = block_size - md_size; + wr_md_buf = (char *)wr_buf + data_block_size; + rd_md_buf = (char *)rd_buf + data_block_size; + md_offset = block_size; + } else { + data_block_size = block_size; + md_offset = md_size; + } + while (offset_blocks < num_blocks) { - if (memcmp(wr_buf, rd_buf, block_size - md_size) != 0) { + if (memcmp(wr_buf, rd_buf, data_block_size) != 0) { return false; } + wr_buf += block_size; rd_buf += block_size; + + if (md_check) { + if (memcmp(wr_md_buf, rd_md_buf, md_size) != 0) { + return false; + } + + wr_md_buf += md_offset; + rd_md_buf += md_offset; + } + offset_blocks++; } @@ -191,6 +225,7 @@ bdevperf_free_target(struct io_target *target) TAILQ_FOREACH_SAFE(task, &target->task_list, link, tmp) { TAILQ_REMOVE(&target->task_list, task, link); spdk_dma_free(task->buf); + spdk_dma_free(task->md_buf); free(task); } @@ -227,7 +262,7 @@ bdevperf_construct_target(struct spdk_bdev *bdev, struct io_target **_target) { struct io_target *target; size_t align; - int block_size, md_size, data_block_size; + int block_size, data_block_size; int rc; *_target = NULL; @@ -266,14 +301,7 @@ bdevperf_construct_target(struct spdk_bdev *bdev, struct io_target **_target) target->offset_in_ios = 0; block_size = spdk_bdev_get_block_size(bdev); - md_size = spdk_bdev_get_md_size(bdev); - if (md_size != 0 && !spdk_bdev_is_md_interleaved(bdev)) { - SPDK_ERRLOG("Separate metadata is not expected.\n"); - free(target->name); - free(target); - return -EINVAL; - } - data_block_size = block_size - md_size; + data_block_size = spdk_bdev_get_data_block_size(bdev); target->io_size_blocks = g_io_size / data_block_size; if ((g_io_size % data_block_size) != 0) { SPDK_ERRLOG("IO size (%d) is not multiples of data block size of bdev %s (%"PRIu32")\n", @@ -364,8 +392,10 @@ bdevperf_complete(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) struct spdk_event *complete; struct iovec *iovs; int iovcnt; + bool md_check; target = task->target; + md_check = spdk_bdev_get_dif_type(target->bdev) == SPDK_DIF_DISABLE; if (!success) { if (!g_reset) { @@ -380,8 +410,9 @@ bdevperf_complete(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) assert(iovs != NULL); if (!verify_data(task->buf, g_buf_size, iovs[0].iov_base, iovs[0].iov_len, spdk_bdev_get_block_size(target->bdev), + task->md_buf, spdk_bdev_io_get_md_buf(bdev_io), spdk_bdev_get_md_size(target->bdev), - target->io_size_blocks) != 0) { + target->io_size_blocks, md_check) != 0) { printf("Buffer mismatch! Disk Offset: %lu\n", task->offset_blocks); target->is_draining = true; g_run_failed = true; @@ -423,8 +454,16 @@ bdevperf_verify_submit_read(void *cb_arg) target = task->target; /* Read the data back in */ - rc = spdk_bdev_read_blocks(target->bdev_desc, target->ch, NULL, task->offset_blocks, - target->io_size_blocks, bdevperf_complete, task); + if (spdk_bdev_is_md_separate(target->bdev)) { + rc = spdk_bdev_read_blocks_with_md(target->bdev_desc, target->ch, NULL, NULL, + task->offset_blocks, target->io_size_blocks, + bdevperf_complete, task); + } else { + rc = spdk_bdev_read_blocks(target->bdev_desc, target->ch, NULL, + task->offset_blocks, target->io_size_blocks, + bdevperf_complete, task); + } + if (rc == -ENOMEM) { task->bdev_io_wait.bdev = target->bdev; task->bdev_io_wait.cb_fn = bdevperf_verify_submit_read; @@ -481,7 +520,7 @@ bdevperf_prep_task(struct bdevperf_task *task) if (g_verify || g_reset) { generate_data(task->buf, g_buf_size, spdk_bdev_get_block_size(target->bdev), - spdk_bdev_get_md_size(target->bdev), + task->md_buf, spdk_bdev_get_md_size(target->bdev), target->io_size_blocks, rand_r(&seed) % 256); task->iov.iov_base = task->buf; task->iov.iov_len = g_buf_size; @@ -523,9 +562,19 @@ bdevperf_generate_dif(struct bdevperf_task *task) return rc; } - rc = spdk_dif_generate(&task->iov, 1, target->io_size_blocks, &dif_ctx); + if (spdk_bdev_is_md_interleaved(bdev)) { + rc = spdk_dif_generate(&task->iov, 1, target->io_size_blocks, &dif_ctx); + } else { + struct iovec md_iov = { + .iov_base = task->md_buf, + .iov_len = spdk_bdev_get_md_size(bdev) * target->io_size_blocks, + }; + + rc = spdk_dix_generate(&task->iov, 1, &md_iov, target->io_size_blocks, &dif_ctx); + } + if (rc != 0) { - fprintf(stderr, "Generation of DIF failed\n"); + fprintf(stderr, "Generation of DIF/DIX failed\n"); } return rc; @@ -551,8 +600,19 @@ bdevperf_submit_task(void *arg) } if (rc == 0) { cb_fn = (g_verify || g_reset) ? bdevperf_verify_write_complete : bdevperf_complete; - rc = spdk_bdev_writev_blocks(desc, ch, &task->iov, 1, task->offset_blocks, - target->io_size_blocks, cb_fn, task); + + if (spdk_bdev_is_md_separate(target->bdev)) { + rc = spdk_bdev_writev_blocks_with_md(desc, ch, &task->iov, 1, + task->md_buf, + task->offset_blocks, + target->io_size_blocks, + cb_fn, task); + } else { + rc = spdk_bdev_writev_blocks(desc, ch, &task->iov, 1, + task->offset_blocks, + target->io_size_blocks, + cb_fn, task); + } } break; case SPDK_BDEV_IO_TYPE_FLUSH: @@ -572,8 +632,15 @@ bdevperf_submit_task(void *arg) rc = spdk_bdev_zcopy_start(desc, ch, task->offset_blocks, target->io_size_blocks, true, bdevperf_zcopy_complete, task); } else { - rc = spdk_bdev_read_blocks(desc, ch, task->buf, task->offset_blocks, - target->io_size_blocks, bdevperf_complete, task); + if (spdk_bdev_is_md_separate(target->bdev)) { + rc = spdk_bdev_read_blocks_with_md(desc, ch, task->buf, task->md_buf, + task->offset_blocks, + target->io_size_blocks, + bdevperf_complete, task); + } else { + rc = spdk_bdev_read_blocks(desc, ch, task->buf, task->offset_blocks, + target->io_size_blocks, bdevperf_complete, task); + } } break; default: @@ -827,6 +894,17 @@ static struct bdevperf_task *bdevperf_construct_task_on_target(struct io_target return NULL; } + if (spdk_bdev_is_md_separate(target->bdev)) { + task->md_buf = spdk_dma_zmalloc(target->io_size_blocks * + spdk_bdev_get_md_size(target->bdev), 0, NULL); + if (!task->md_buf) { + fprintf(stderr, "Cannot allocate md buf for task=%p\n", task); + free(task->buf); + free(task); + return NULL; + } + } + task->target = target; return task;