Commit 9beb6b16 authored by Konrad Sztyber's avatar Konrad Sztyber Committed by Ben Walker
Browse files

bdev: fix completion for unsubmitted IOs



If an IO is completed, before submitting it to a module, it isn't put on
the io_submitted list, so we can't use bdev_io_complete() to complete
it, as it'll break that list.  To avoid that, a new function was added,
bdev_io_complete_unsubmitted(), that will safely complete the IOs in
such case.  For now, it's equivalent to executing user's completion
callback, but it'll serve as a good place to release any resources that
should be freed before an IO is completed.

Signed-off-by: default avatarKonrad Sztyber <konrad.sztyber@intel.com>
Change-Id: I1442ead9d272d9210553803bed1d1c989a2bf761
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/16970


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
Reviewed-by: default avatarAleksey Marchuk <alexeymar@nvidia.com>
parent 7b71fdc2
Loading
Loading
Loading
Loading
+30 −7
Original line number Diff line number Diff line
@@ -361,6 +361,7 @@ struct spdk_bdev_io_error_stat {
#define __io_ch_to_bdev_mgmt_ch(io_ch)	((struct spdk_bdev_mgmt_channel *)spdk_io_channel_get_ctx(io_ch))

static inline void bdev_io_complete(void *ctx);
static inline void bdev_io_complete_unsubmitted(struct spdk_bdev_io *bdev_io);

static void bdev_write_zero_buffer_done(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg);
static void bdev_write_zero_buffer_next(void *_bdev_io);
@@ -388,8 +389,6 @@ static int bdev_unlock_lba_range(struct spdk_bdev_desc *desc, struct spdk_io_cha
				 uint64_t offset, uint64_t length,
				 lock_range_cb cb_fn, void *cb_arg);

static inline void bdev_io_complete(void *ctx);

static bool bdev_abort_queued_io(bdev_io_tailq_t *queue, struct spdk_bdev_io *bio_to_abort);
static bool bdev_abort_buf_io(struct spdk_bdev_mgmt_channel *ch, struct spdk_bdev_io *bio_to_abort);

@@ -1416,7 +1415,8 @@ _bdev_memory_domain_get_io_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *b
{
	if (!success) {
		SPDK_ERRLOG("Failed to get data buffer, completing IO\n");
		bdev_io_complete(bdev_io);
		bdev_io->internal.status = SPDK_BDEV_IO_STATUS_FAILED;
		bdev_io_complete_unsubmitted(bdev_io);
	} else {
		bdev_io_submit(bdev_io);
	}
@@ -6484,6 +6484,18 @@ bdev_io_update_io_stat(struct spdk_bdev_io *bdev_io, uint64_t tsc_diff)
#endif
}

static inline void
_bdev_io_complete(void *ctx)
{
	struct spdk_bdev_io *bdev_io = ctx;

	assert(bdev_io->internal.cb != NULL);
	assert(spdk_get_thread() == spdk_bdev_io_get_thread(bdev_io));

	bdev_io->internal.cb(bdev_io, bdev_io->internal.status == SPDK_BDEV_IO_STATUS_SUCCESS,
			     bdev_io->internal.caller_ctx);
}

static inline void
bdev_io_complete(void *ctx)
{
@@ -6513,12 +6525,23 @@ bdev_io_complete(void *ctx)
	}

	bdev_io_update_io_stat(bdev_io, tsc_diff);
	_bdev_io_complete(bdev_io);
}

	assert(bdev_io->internal.cb != NULL);
	assert(spdk_get_thread() == spdk_bdev_io_get_thread(bdev_io));
/* The difference between this function and bdev_io_complete() is that this should be called to
 * complete IOs that haven't been submitted via bdev_io_submit(), as they weren't added onto the
 * io_submitted list and don't have submit_tsc updated.
 */
static inline void
bdev_io_complete_unsubmitted(struct spdk_bdev_io *bdev_io)
{
	/* Since the IO hasn't been submitted it's bound to be failed */
	assert(bdev_io->internal.status != SPDK_BDEV_IO_STATUS_SUCCESS);

	bdev_io->internal.cb(bdev_io, bdev_io->internal.status == SPDK_BDEV_IO_STATUS_SUCCESS,
			     bdev_io->internal.caller_ctx);
	/* At this point we don't know if the IO is completed from submission context or not, but,
	 * since this is an error path, we can always do an spdk_thread_send_msg(). */
	spdk_thread_send_msg(spdk_bdev_io_get_thread(bdev_io),
			     _bdev_io_complete, bdev_io);
}

static void bdev_destroy_cb(void *io_device);