bdev: complete parent IO only when all the children IO are finished

When parent IO was splitted into several children requests, SPDK
may return parent completion callback with error status before
all the children requests are finished.

Change-Id: I63221a0ae1a5925a7fcd9744b4f5d8079c641252
Signed-off-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/453611
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
This commit is contained in:
Changpeng Liu 2019-05-15 21:32:18 -04:00
parent 75a6265de9
commit c55c85f807
2 changed files with 25 additions and 5 deletions

View File

@ -1633,11 +1633,9 @@ _spdk_bdev_io_split_done(struct spdk_bdev_io *bdev_io, bool success, void *cb_ar
}
/*
* Parent I/O finishes when all blocks are consumed or there is any failure of
* child I/O and no outstanding child I/O.
* Parent I/O finishes when all blocks are consumed.
*/
if (parent_io->u.bdev.split_remaining_num_blocks == 0 ||
parent_io->internal.status != SPDK_BDEV_IO_STATUS_SUCCESS) {
if (parent_io->u.bdev.split_remaining_num_blocks == 0) {
parent_io->internal.cb(parent_io, parent_io->internal.status == SPDK_BDEV_IO_STATUS_SUCCESS,
parent_io->internal.caller_ctx);
return;

View File

@ -108,6 +108,7 @@ struct bdev_ut_channel {
static bool g_io_done;
static struct spdk_bdev_io *g_bdev_io;
static enum spdk_bdev_io_status g_io_status;
static enum spdk_bdev_io_status g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
static uint32_t g_bdev_ut_io_device;
static struct bdev_ut_channel *g_bdev_ut_channel;
@ -203,6 +204,7 @@ stub_complete_io(uint32_t num_to_complete)
{
struct bdev_ut_channel *ch = g_bdev_ut_channel;
struct spdk_bdev_io *bdev_io;
static enum spdk_bdev_io_status io_status;
uint32_t num_completed = 0;
while (num_completed < num_to_complete) {
@ -212,7 +214,9 @@ stub_complete_io(uint32_t num_to_complete)
bdev_io = TAILQ_FIRST(&ch->outstanding_io);
TAILQ_REMOVE(&ch->outstanding_io, bdev_io, module_link);
ch->outstanding_io_count--;
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
io_status = g_io_exp_status == SPDK_BDEV_IO_STATUS_SUCCESS ? SPDK_BDEV_IO_STATUS_SUCCESS :
g_io_exp_status;
spdk_bdev_io_complete(bdev_io, io_status);
num_completed++;
}
@ -1143,6 +1147,24 @@ bdev_io_split(void)
CU_ASSERT(TAILQ_EMPTY(&g_bdev_ut_channel->expected_io));
/* Children requests return an error status */
bdev->optimal_io_boundary = 16;
iov[0].iov_base = (void *)0x10000;
iov[0].iov_len = 512 * 64;
g_io_exp_status = SPDK_BDEV_IO_STATUS_FAILED;
g_io_done = false;
g_io_status = SPDK_BDEV_IO_STATUS_SUCCESS;
rc = spdk_bdev_readv_blocks(desc, io_ch, iov, 1, 1, 64, io_done, NULL);
CU_ASSERT(rc == 0);
CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 5);
stub_complete_io(4);
CU_ASSERT(g_io_done == false);
CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_SUCCESS);
stub_complete_io(1);
CU_ASSERT(g_io_done == true);
CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_FAILED);
spdk_put_io_channel(io_ch);
spdk_bdev_close(desc);
free_bdev(bdev);