Commit 0df515a8 authored by Shuhei Matsumoto's avatar Shuhei Matsumoto Committed by Changpeng Liu
Browse files

bdev: Remove limitation of child iov size in bdev_io_split_with_payload()



When a bdev IO is split, if iovec size in a strip is more than 32,
the IO will fail.

Remove the limitation by spliting the split IO further.

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


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>
Reviewed-by: default avatarDarek Stojaczyk <dariusz.stojaczyk@intel.com>
parent ff852667
Loading
Loading
Loading
Loading
+12 −3
Original line number Diff line number Diff line
@@ -1163,7 +1163,7 @@ _spdk_bdev_io_split_with_payload(void *_bdev_io)
	to_next_boundary = spdk_min(remaining, to_next_boundary);
	to_next_boundary_bytes = to_next_boundary * blocklen;
	child_iovcnt = 0;
	while (to_next_boundary_bytes > 0) {
	while (to_next_boundary_bytes > 0 && child_iovcnt < BDEV_IO_NUM_CHILD_IOV) {
		child_iov_len = spdk_min(to_next_boundary_bytes, parent_iov->iov_len - parent_iov_offset);
		to_next_boundary_bytes -= child_iov_len;

@@ -1173,12 +1173,21 @@ _spdk_bdev_io_split_with_payload(void *_bdev_io)
		parent_iov++;
		parent_iov_offset = 0;
		child_iovcnt++;
		if (child_iovcnt == BDEV_IO_NUM_CHILD_IOV && to_next_boundary_bytes > 0) {
			/* We've run out of child iovs - we need to fail this I/O. */
	}

	if (to_next_boundary_bytes > 0) {
		/* We had to stop this child I/O early because we ran out of
		 *  child_iov space.  Make sure the iovs collected are valid and
		 *  then adjust to_next_boundary before starting the child I/O.
		 */
		if ((to_next_boundary_bytes % blocklen) != 0) {
			SPDK_ERRLOG("Remaining %" PRIu32 " is not multiple of block size %" PRIu32 "\n",
				    to_next_boundary_bytes, blocklen);
			bdev_io->internal.status = SPDK_BDEV_IO_STATUS_FAILED;
			bdev_io->internal.cb(bdev_io, false, bdev_io->internal.caller_ctx);
			return;
		}
		to_next_boundary -= to_next_boundary_bytes / blocklen;
	}

	if (bdev_io->type == SPDK_BDEV_IO_TYPE_READ) {
+66 −2
Original line number Diff line number Diff line
@@ -95,10 +95,11 @@ struct bdev_ut_channel {
	uint64_t			expected_offset;
	uint64_t			expected_length;
	int				expected_iovcnt;
	struct iovec			expected_iov[32];
	struct iovec			expected_iov[BDEV_IO_NUM_CHILD_IOV];
};

static bool g_io_done;
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;

@@ -639,6 +640,7 @@ static void
io_done(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
{
	g_io_done = true;
	g_io_status = bdev_io->internal.status;
	spdk_bdev_free_io(bdev_io);
}

@@ -789,7 +791,8 @@ bdev_io_split(void)
		.bdev_io_pool_size = 512,
		.bdev_io_cache_size = 64,
	};
	struct iovec iov[4];
	struct iovec iov[BDEV_IO_NUM_CHILD_IOV * 2];
	uint64_t i;
	int rc;

	rc = spdk_bdev_set_opts(&bdev_opts);
@@ -918,6 +921,67 @@ bdev_io_split(void)
	stub_complete_io(1);
	CU_ASSERT(g_io_done == true);

	/* Test multi vector command that needs to be split by strip and then needs to be
	 * split further due to the capacity of child iovs.
	 */
	for (i = 0; i < BDEV_IO_NUM_CHILD_IOV * 2; i++) {
		iov[i].iov_base = (void *)((i + 1) * 0x10000);
		iov[i].iov_len = 512;
	}

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

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

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

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

	/* Test multi vector command that needs to be split by strip and then needs to be
	 * split further due to the capacity of child iovs, but fails to split. The cause
	 * of failure of split is that the length of an iovec is not multiple of block size.
	 */
	for (i = 0; i < BDEV_IO_NUM_CHILD_IOV - 1; i++) {
		iov[i].iov_base = (void *)((i + 1) * 0x10000);
		iov[i].iov_len = 512;
	}
	iov[BDEV_IO_NUM_CHILD_IOV - 1].iov_base = (void *)(BDEV_IO_NUM_CHILD_IOV * 0x10000);
	iov[BDEV_IO_NUM_CHILD_IOV - 1].iov_len = 256;

	bdev->optimal_io_boundary = BDEV_IO_NUM_CHILD_IOV;
	g_io_done = false;
	g_io_status = 0;

	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 == true);
	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_FAILED);

	/* Test a WRITE_ZEROES that would span an I/O boundary.  WRITE_ZEROES should not be
	 * split, so test that.
	 */