Commit 66bace41 authored by Konrad Sztyber's avatar Konrad Sztyber Committed by Jim Harris
Browse files

bdevperf: use separate metadata buffers



Use separate buffers for metadata transfer if bdev supports it.

Change-Id: Ie0fa3d3c1f5b14f99c13f2d6b5b22edc216c6d64
Signed-off-by: default avatarKonrad Sztyber <konrad.sztyber@intel.com>
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/451468


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
Reviewed-by: default avatarShuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
parent d69fe7b7
Loading
Loading
Loading
Loading
+105 −27
Original line number Diff line number Diff line
@@ -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;
	}

	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:
@@ -571,10 +631,17 @@ bdevperf_submit_task(void *arg)
		if (g_zcopy) {
			rc = spdk_bdev_zcopy_start(desc, ch, task->offset_blocks, target->io_size_blocks,
						   true, bdevperf_zcopy_complete, task);
		} else {
			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:
		assert(false);
@@ -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;