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:
parent
ff852667f8
commit
0df515a842
@ -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) {
|
||||
|
@ -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.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user