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: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-on: https://review.gerrithub.io/425876
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Chandler-Test-Pool: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Paul Luse <paul.e.luse@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-by: Darek Stojaczyk <dariusz.stojaczyk@intel.com>
This commit is contained in:
Shuhei Matsumoto 2018-09-25 15:01:48 +09:00 committed by Changpeng Liu
parent ff852667f8
commit 0df515a842
2 changed files with 78 additions and 5 deletions

View File

@ -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) {

View File

@ -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.
*/