lib/bdev: Terminate parent I/O with failure immediately if one of child I/O failed

Previously, bdev_io_split_done() had continued splitting process
even if the status became failed. To abort split I/O, this patch
changes bdev_io_split_done() to terminate with failure before
continuing splitting process if the status became failed. Add
necessary unit test together.

Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Change-Id: Ifd1ea49c22523e8c06fb45ebdcb2c84a57afd2ef
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/2234
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Mellanox Build Bot
Community-CI: Broadcom CI
Reviewed-by: Aleksey Marchuk <alexeymar@mellanox.com>
Reviewed-by: Michael Haeuptle <michaelhaeuptle@gmail.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
Shuhei Matsumoto 2020-05-07 08:39:35 +09:00 committed by Tomasz Zawadzki
parent fc3e40618c
commit 089d178abb
2 changed files with 39 additions and 0 deletions

View File

@ -1952,6 +1952,9 @@ bdev_io_split_done(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
if (!success) {
parent_io->internal.status = SPDK_BDEV_IO_STATUS_FAILED;
/* If any child I/O failed, stop further splitting process. */
parent_io->u.bdev.split_current_offset_blocks += parent_io->u.bdev.split_remaining_num_blocks;
parent_io->u.bdev.split_remaining_num_blocks = 0;
}
parent_io->u.bdev.split_outstanding--;
if (parent_io->u.bdev.split_outstanding != 0) {

View File

@ -1546,6 +1546,42 @@ bdev_io_split_test(void)
CU_ASSERT(g_io_done == true);
CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_FAILED);
/* Test if a multi vector command terminated with failure before continueing
* splitting process when one of child I/O failed.
* The multi vector command is as same as the above 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 - 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;
iov[BDEV_IO_NUM_CHILD_IOV].iov_base = (void *)((BDEV_IO_NUM_CHILD_IOV + 1) * 0x10000);
iov[BDEV_IO_NUM_CHILD_IOV].iov_len = 256;
iov[BDEV_IO_NUM_CHILD_IOV + 1].iov_base = (void *)((BDEV_IO_NUM_CHILD_IOV + 2) * 0x10000);
iov[BDEV_IO_NUM_CHILD_IOV + 1].iov_len = 512;
bdev->optimal_io_boundary = BDEV_IO_NUM_CHILD_IOV;
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, BDEV_IO_NUM_CHILD_IOV * 2, 0,
BDEV_IO_NUM_CHILD_IOV + 1, io_done, NULL);
CU_ASSERT(rc == 0);
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);
CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_FAILED);
g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
/* for this test we will create the following conditions to hit the code path where
* we are trying to send and IO following a split that has no iovs because we had to
* trim them for alignment reasons.