Commit 3c7894ff authored by Shuhei Matsumoto's avatar Shuhei Matsumoto Committed by Changpeng Liu
Browse files

ut/bdev: Prepare test code for submitting batched split I/Os



Current test code works only for sequential split I/Os. The next
patch will support submitting batchedsplit I/Os.

Prepare test code as a separate patch to make review easier.

Change-Id: I05b732c9a656ecab74a2594bf50ddf42eb41584e
Signed-off-by: default avatarShuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-on: https://review.gerrithub.io/425877


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Chandler-Test-Pool: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: default avatarPaul Luse <paul.e.luse@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarChangpeng Liu <changpeng.liu@intel.com>
parent 0df515a8
Loading
Loading
Loading
Loading
+91 −79
Original line number Diff line number Diff line
@@ -88,14 +88,19 @@ stub_destruct(void *ctx)
	return 0;
}

struct ut_expected_io {
	uint8_t				type;
	uint64_t			offset;
	uint64_t			length;
	int				iovcnt;
	struct iovec			iov[BDEV_IO_NUM_CHILD_IOV];
	TAILQ_ENTRY(ut_expected_io)	link;
};

struct bdev_ut_channel {
	TAILQ_HEAD(, spdk_bdev_io)	outstanding_io;
	uint32_t			outstanding_io_count;
	uint8_t				expected_iotype;
	uint64_t			expected_offset;
	uint64_t			expected_length;
	int				expected_iovcnt;
	struct iovec			expected_iov[BDEV_IO_NUM_CHILD_IOV];
	TAILQ_HEAD(, ut_expected_io)	expected_io;
};

static bool g_io_done;
@@ -103,39 +108,73 @@ static enum spdk_bdev_io_status g_io_status;
static uint32_t g_bdev_ut_io_device;
static struct bdev_ut_channel *g_bdev_ut_channel;

static struct ut_expected_io *
ut_alloc_expected_io(uint8_t type, uint64_t offset, uint64_t length, int iovcnt)
{
	struct ut_expected_io *expected_io;

	expected_io = calloc(1, sizeof(*expected_io));
	SPDK_CU_ASSERT_FATAL(expected_io != NULL);

	expected_io->type = type;
	expected_io->offset = offset;
	expected_io->length = length;
	expected_io->iovcnt = iovcnt;

	return expected_io;
}

static void
ut_expected_io_set_iov(struct ut_expected_io *expected_io, int pos, void *base, size_t len)
{
	expected_io->iov[pos].iov_base = base;
	expected_io->iov[pos].iov_len = len;
}

static void
stub_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io)
{
	struct bdev_ut_channel *ch = spdk_io_channel_get_ctx(_ch);
	struct ut_expected_io *expected_io;
	struct iovec *iov, *expected_iov;
	int i;

	TAILQ_INSERT_TAIL(&ch->outstanding_io, bdev_io, module_link);
	ch->outstanding_io_count++;

	if (ch->expected_iotype != SPDK_BDEV_IO_TYPE_INVALID) {
		CU_ASSERT(bdev_io->type == ch->expected_iotype);
	expected_io = TAILQ_FIRST(&ch->expected_io);
	if (expected_io == NULL) {
		return;
	}
	TAILQ_REMOVE(&ch->expected_io, expected_io, link);

	if (expected_io->type != SPDK_BDEV_IO_TYPE_INVALID) {
		CU_ASSERT(bdev_io->type == expected_io->type);
	}

	if (ch->expected_length == 0) {
	if (expected_io->length == 0) {
		free(expected_io);
		return;
	}

	CU_ASSERT(ch->expected_offset == bdev_io->u.bdev.offset_blocks);
	CU_ASSERT(ch->expected_length = bdev_io->u.bdev.num_blocks);
	CU_ASSERT(expected_io->offset == bdev_io->u.bdev.offset_blocks);
	CU_ASSERT(expected_io->length = bdev_io->u.bdev.num_blocks);

	if (ch->expected_iovcnt == 0) {
	if (expected_io->iovcnt == 0) {
		free(expected_io);
		/* UNMAP, WRITE_ZEROES and FLUSH don't have iovs, so we can just return now. */
		return;
	}

	CU_ASSERT(ch->expected_iovcnt == bdev_io->u.bdev.iovcnt);
	for (i = 0; i < ch->expected_iovcnt; i++) {
	CU_ASSERT(expected_io->iovcnt == bdev_io->u.bdev.iovcnt);
	for (i = 0; i < expected_io->iovcnt; i++) {
		iov = &bdev_io->u.bdev.iovs[i];
		expected_iov = &ch->expected_iov[i];
		expected_iov = &expected_io->iov[i];
		CU_ASSERT(iov->iov_len == expected_iov->iov_len);
		CU_ASSERT(iov->iov_base == expected_iov->iov_base);
	}

	free(expected_io);
}

static uint32_t
@@ -188,6 +227,7 @@ bdev_ut_create_ch(void *io_device, void *ctx_buf)

	TAILQ_INIT(&ch->outstanding_io);
	ch->outstanding_io_count = 0;
	TAILQ_INIT(&ch->expected_io);
	return 0;
}

@@ -792,6 +832,7 @@ bdev_io_split(void)
		.bdev_io_cache_size = 64,
	};
	struct iovec iov[BDEV_IO_NUM_CHILD_IOV * 2];
	struct ut_expected_io *expected_io;
	uint64_t i;
	int rc;

@@ -813,12 +854,9 @@ bdev_io_split(void)
	g_io_done = false;

	/* First test that the I/O does not get split if split_on_optimal_io_boundary == false. */
	g_bdev_ut_channel->expected_iotype = SPDK_BDEV_IO_TYPE_READ;
	g_bdev_ut_channel->expected_offset = 14;
	g_bdev_ut_channel->expected_length = 8;
	g_bdev_ut_channel->expected_iovcnt = 1;
	g_bdev_ut_channel->expected_iov[0].iov_base = (void *)0xF000;
	g_bdev_ut_channel->expected_iov[0].iov_len = 8 * 512;
	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 14, 8, 1);
	ut_expected_io_set_iov(expected_io, 0, (void *)0xF000, 8 * 512);
	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);

	rc = spdk_bdev_read_blocks(desc, io_ch, (void *)0xF000, 14, 8, io_done, NULL);
	CU_ASSERT(rc == 0);
@@ -840,12 +878,9 @@ bdev_io_split(void)
	 * will submit the first child immediately.
	 */
	g_io_done = false;
	g_bdev_ut_channel->expected_iotype = SPDK_BDEV_IO_TYPE_READ;
	g_bdev_ut_channel->expected_offset = 14;
	g_bdev_ut_channel->expected_length = 2;
	g_bdev_ut_channel->expected_iovcnt = 1;
	g_bdev_ut_channel->expected_iov[0].iov_base = (void *)0xF000;
	g_bdev_ut_channel->expected_iov[0].iov_len = 2 * 512;
	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 14, 2, 1);
	ut_expected_io_set_iov(expected_io, 0, (void *)0xF000, 2 * 512);
	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);

	rc = spdk_bdev_read_blocks(desc, io_ch, (void *)0xF000, 14, 8, io_done, NULL);
	CU_ASSERT(rc == 0);
@@ -854,11 +889,9 @@ bdev_io_split(void)
	/* Now set up the expected values for the second child.  The second child will
	 * get submitted once the first child is completed by stub_complete_io().
	 */
	g_bdev_ut_channel->expected_offset = 16;
	g_bdev_ut_channel->expected_length = 6;
	g_bdev_ut_channel->expected_iovcnt = 1;
	g_bdev_ut_channel->expected_iov[0].iov_base = (void *)(0xF000 + 2 * 512);
	g_bdev_ut_channel->expected_iov[0].iov_len = 6 * 512;
	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 16, 6, 1);
	ut_expected_io_set_iov(expected_io, 0, (void *)(0xF000 + 2 * 512), 6 * 512);
	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);

	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
	stub_complete_io(1);
@@ -882,36 +915,27 @@ bdev_io_split(void)
	iov[2].iov_len = 11 * 512;

	g_io_done = false;
	g_bdev_ut_channel->expected_iotype = SPDK_BDEV_IO_TYPE_WRITE;
	g_bdev_ut_channel->expected_offset = 14;
	g_bdev_ut_channel->expected_length = 2;
	g_bdev_ut_channel->expected_iovcnt = 2;
	g_bdev_ut_channel->expected_iov[0].iov_base = (void *)0x10000;
	g_bdev_ut_channel->expected_iov[0].iov_len = 512;
	g_bdev_ut_channel->expected_iov[1].iov_base = (void *)0x20000;
	g_bdev_ut_channel->expected_iov[1].iov_len = 512;
	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 14, 2, 2);
	ut_expected_io_set_iov(expected_io, 0, (void *)0x10000, 512);
	ut_expected_io_set_iov(expected_io, 1, (void *)0x20000, 512);
	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);

	rc = spdk_bdev_writev_blocks(desc, io_ch, iov, 3, 14, 32, io_done, NULL);
	CU_ASSERT(rc == 0);
	CU_ASSERT(g_io_done == false);

	g_bdev_ut_channel->expected_offset = 16;
	g_bdev_ut_channel->expected_length = 16;
	g_bdev_ut_channel->expected_iovcnt = 1;
	g_bdev_ut_channel->expected_iov[0].iov_base = (void *)(0x20000 + 512);
	g_bdev_ut_channel->expected_iov[0].iov_len = 16 * 512;
	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 16, 16, 1);
	ut_expected_io_set_iov(expected_io, 0, (void *)(0x20000 + 512), 16 * 512);
	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);

	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
	stub_complete_io(1);
	CU_ASSERT(g_io_done == false);

	g_bdev_ut_channel->expected_offset = 32;
	g_bdev_ut_channel->expected_length = 14;
	g_bdev_ut_channel->expected_iovcnt = 2;
	g_bdev_ut_channel->expected_iov[0].iov_base = (void *)(0x20000 + 17 * 512);
	g_bdev_ut_channel->expected_iov[0].iov_len = 3 * 512;
	g_bdev_ut_channel->expected_iov[1].iov_base = (void *)0x30000;
	g_bdev_ut_channel->expected_iov[1].iov_len = 11 * 512;
	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 32, 14, 2);
	ut_expected_io_set_iov(expected_io, 0, (void *)(0x20000 + 17 * 512), 3 * 512);
	ut_expected_io_set_iov(expected_io, 1, (void *)0x30000, 11 * 512);
	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);

	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
	stub_complete_io(1);
@@ -931,27 +955,25 @@ bdev_io_split(void)

	bdev->optimal_io_boundary = BDEV_IO_NUM_CHILD_IOV;
	g_io_done = false;
	g_bdev_ut_channel->expected_iotype = SPDK_BDEV_IO_TYPE_READ;
	g_bdev_ut_channel->expected_offset = 0;
	g_bdev_ut_channel->expected_length = BDEV_IO_NUM_CHILD_IOV;
	g_bdev_ut_channel->expected_iovcnt = BDEV_IO_NUM_CHILD_IOV;
	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 0, BDEV_IO_NUM_CHILD_IOV,
					   BDEV_IO_NUM_CHILD_IOV);
	for (i = 0; i < BDEV_IO_NUM_CHILD_IOV; i++) {
		g_bdev_ut_channel->expected_iov[i].iov_base = (void *)((i + 1) * 0x10000);
		g_bdev_ut_channel->expected_iov[i].iov_len = 512;
		ut_expected_io_set_iov(expected_io, i, (void *)((i + 1) * 0x10000), 512);
	}
	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);

	rc = spdk_bdev_readv_blocks(desc, io_ch, iov, BDEV_IO_NUM_CHILD_IOV * 2, 0,
				    BDEV_IO_NUM_CHILD_IOV * 2, io_done, NULL);
	CU_ASSERT(rc == 0);
	CU_ASSERT(g_io_done == false);

	g_bdev_ut_channel->expected_offset = BDEV_IO_NUM_CHILD_IOV;
	g_bdev_ut_channel->expected_length = BDEV_IO_NUM_CHILD_IOV;
	g_bdev_ut_channel->expected_iovcnt = BDEV_IO_NUM_CHILD_IOV;
	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, BDEV_IO_NUM_CHILD_IOV,
					   BDEV_IO_NUM_CHILD_IOV, BDEV_IO_NUM_CHILD_IOV);
	for (i = 0; i < BDEV_IO_NUM_CHILD_IOV; i++) {
		g_bdev_ut_channel->expected_iov[i].iov_base = (void *)((i + 1 + BDEV_IO_NUM_CHILD_IOV) * 0x10000);
		g_bdev_ut_channel->expected_iov[i].iov_len = 512;
		ut_expected_io_set_iov(expected_io, i,
				       (void *)((i + 1 + BDEV_IO_NUM_CHILD_IOV) * 0x10000), 512);
	}
	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);

	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
	stub_complete_io(1);
@@ -987,10 +1009,8 @@ bdev_io_split(void)
	 */
	bdev->optimal_io_boundary = 15;
	g_io_done = false;
	g_bdev_ut_channel->expected_iotype = SPDK_BDEV_IO_TYPE_WRITE_ZEROES;
	g_bdev_ut_channel->expected_offset = 9;
	g_bdev_ut_channel->expected_length = 36;
	g_bdev_ut_channel->expected_iovcnt = 0;
	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE_ZEROES, 9, 36, 0);
	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);

	rc = spdk_bdev_write_zeroes_blocks(desc, io_ch, 9, 36, io_done, NULL);
	CU_ASSERT(rc == 0);
@@ -1002,10 +1022,8 @@ bdev_io_split(void)
	/* Test an UNMAP.  This should also not be split. */
	bdev->optimal_io_boundary = 16;
	g_io_done = false;
	g_bdev_ut_channel->expected_iotype = SPDK_BDEV_IO_TYPE_UNMAP;
	g_bdev_ut_channel->expected_offset = 15;
	g_bdev_ut_channel->expected_length = 2;
	g_bdev_ut_channel->expected_iovcnt = 0;
	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_UNMAP, 15, 2, 0);
	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);

	rc = spdk_bdev_unmap_blocks(desc, io_ch, 15, 2, io_done, NULL);
	CU_ASSERT(rc == 0);
@@ -1017,10 +1035,8 @@ bdev_io_split(void)
	/* Test a FLUSH.  This should also not be split. */
	bdev->optimal_io_boundary = 16;
	g_io_done = false;
	g_bdev_ut_channel->expected_iotype = SPDK_BDEV_IO_TYPE_FLUSH;
	g_bdev_ut_channel->expected_offset = 15;
	g_bdev_ut_channel->expected_length = 2;
	g_bdev_ut_channel->expected_iovcnt = 0;
	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_FLUSH, 15, 2, 0);
	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);

	rc = spdk_bdev_flush_blocks(desc, io_ch, 15, 2, io_done, NULL);
	CU_ASSERT(rc == 0);
@@ -1029,11 +1045,7 @@ bdev_io_split(void)
	stub_complete_io(1);
	CU_ASSERT(g_io_done == true);

	/* Reset values so next test is not affected by leftover values. */
	g_bdev_ut_channel->expected_iotype = SPDK_BDEV_IO_TYPE_INVALID;
	g_bdev_ut_channel->expected_offset = 0;
	g_bdev_ut_channel->expected_length = 0;
	g_bdev_ut_channel->expected_iovcnt = 0;
	CU_ASSERT(TAILQ_EMPTY(&g_bdev_ut_channel->expected_io));

	spdk_put_io_channel(io_ch);
	spdk_bdev_close(desc);