bdevperf: use separate metadata buffers

Use separate buffers for metadata transfer if bdev supports it.

Change-Id: Ie0fa3d3c1f5b14f99c13f2d6b5b22edc216c6d64
Signed-off-by: Konrad Sztyber <konrad.sztyber@intel.com>
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/451468
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
This commit is contained in:
Konrad Sztyber 2019-04-16 10:17:59 +02:00 committed by Jim Harris
parent d69fe7b7b9
commit 66bace41d7

View File

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