bdev: add function to return aio's errno

This helps user to locate whether bdev_io fails in
spdk bdev layer or inside Linux AIO.
SPDK_BDEV_IO_STATUS_AIO_ERROR indicates bdev_io fails
due to Linux AIO or its lower layer's failure.

New functions spdk_bdev_io_complete_aio_status and
spdk_bdev_io_get_aio_status can be used to report out
the errno from Linux AIO.

Change-Id: I32640e4a0459cca057278c02ea5a7522f3408a02
Signed-off-by: Liu Xiaodong <xiaodong.liu@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/5690
Community-CI: Broadcom CI
Community-CI: Mellanox Build Bot
Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
This commit is contained in:
Liu Xiaodong 2020-12-24 03:16:40 -05:00 committed by Jim Harris
parent bf10299893
commit 021ff6edff
6 changed files with 76 additions and 12 deletions

View File

@ -15,6 +15,11 @@ examine process. Along with corresponding `bdev_wait_for_examine` RPC, which
is now always called during `spdk_bdev_subsystem_config_json` making sure
every bdev is ready to be used.
A new API `spdk_bdev_io_get_aio_status` was added for getting the status of
bdev_io as Linux AIO errno. Also `spdk_bdev_io_complete_aio_status` function
and `SPDK_BDEV_IO_STATUS_AIO_ERROR` were added for bdev module to complete
a bdev_io with Linux AIO errno.
### blob
An `opts_size` element was added in the `spdk_bs_opts` structure to solve the

View File

@ -1678,6 +1678,14 @@ void spdk_bdev_io_get_nvme_fused_status(const struct spdk_bdev_io *bdev_io, uint
void spdk_bdev_io_get_scsi_status(const struct spdk_bdev_io *bdev_io,
int *sc, int *sk, int *asc, int *ascq);
/**
* Get the status of bdev_io as aio errno.
*
* \param bdev_io I/O to get the status from.
* \param aio_result Negative errno returned from AIO.
*/
void spdk_bdev_io_get_aio_status(const struct spdk_bdev_io *bdev_io, int *aio_result);
/**
* Get the iovec describing the data buffer of a bdev_io.
*

View File

@ -226,6 +226,7 @@ struct spdk_bdev_fn_table {
/** bdev I/O completion status */
enum spdk_bdev_io_status {
SPDK_BDEV_IO_STATUS_AIO_ERROR = -8,
SPDK_BDEV_IO_STATUS_ABORTED = -7,
SPDK_BDEV_IO_STATUS_FIRST_FUSED_FAILED = -6,
SPDK_BDEV_IO_STATUS_MISCOMPARE = -5,
@ -643,6 +644,8 @@ struct spdk_bdev_io {
/** SCSI additional sense code qualifier */
uint8_t ascq;
} scsi;
/** Only valid when status is SPDK_BDEV_IO_STATUS_AIO_ERROR */
int aio_result;
} error;
/**
@ -934,6 +937,14 @@ void spdk_bdev_io_complete_nvme_status(struct spdk_bdev_io *bdev_io, uint32_t cd
void spdk_bdev_io_complete_scsi_status(struct spdk_bdev_io *bdev_io, enum spdk_scsi_status sc,
enum spdk_scsi_sense sk, uint8_t asc, uint8_t ascq);
/**
* Complete a bdev_io with AIO errno.
*
* \param bdev_io I/O to complete.
* \param aio_result Negative errno returned from AIO.
*/
void spdk_bdev_io_complete_aio_status(struct spdk_bdev_io *bdev_io, int aio_result);
/**
* Get a thread that given bdev_io was submitted on.
*

View File

@ -5278,6 +5278,34 @@ spdk_bdev_io_get_scsi_status(const struct spdk_bdev_io *bdev_io,
}
}
void
spdk_bdev_io_complete_aio_status(struct spdk_bdev_io *bdev_io, int aio_result)
{
if (aio_result == 0) {
bdev_io->internal.status = SPDK_BDEV_IO_STATUS_SUCCESS;
} else {
bdev_io->internal.status = SPDK_BDEV_IO_STATUS_AIO_ERROR;
}
bdev_io->internal.error.aio_result = aio_result;
spdk_bdev_io_complete(bdev_io, bdev_io->internal.status);
}
void
spdk_bdev_io_get_aio_status(const struct spdk_bdev_io *bdev_io, int *aio_result)
{
assert(aio_result != NULL);
if (bdev_io->internal.status == SPDK_BDEV_IO_STATUS_AIO_ERROR) {
*aio_result = bdev_io->internal.error.aio_result;
} else if (bdev_io->internal.status == SPDK_BDEV_IO_STATUS_SUCCESS) {
*aio_result = 0;
} else {
*aio_result = -EIO;
}
}
void
spdk_bdev_io_complete_nvme_status(struct spdk_bdev_io *bdev_io, uint32_t cdw0, int sct, int sc)
{

View File

@ -87,6 +87,7 @@
spdk_bdev_io_get_nvme_status;
spdk_bdev_io_get_nvme_fused_status;
spdk_bdev_io_get_scsi_status;
spdk_bdev_io_get_aio_status;
spdk_bdev_io_get_iovec;
spdk_bdev_io_get_md_buf;
spdk_bdev_io_get_cb_arg;
@ -116,6 +117,7 @@
spdk_bdev_io_complete;
spdk_bdev_io_complete_nvme_status;
spdk_bdev_io_complete_scsi_status;
spdk_bdev_io_complete_aio_status;
spdk_bdev_io_get_thread;
spdk_bdev_io_get_io_channel;
spdk_bdev_notify_blockcnt_change;

View File

@ -191,7 +191,7 @@ bdev_aio_readv(struct file_disk *fdisk, struct spdk_io_channel *ch,
if (rc == -EAGAIN) {
spdk_bdev_io_complete(spdk_bdev_io_from_ctx(aio_task), SPDK_BDEV_IO_STATUS_NOMEM);
} else {
spdk_bdev_io_complete(spdk_bdev_io_from_ctx(aio_task), SPDK_BDEV_IO_STATUS_FAILED);
spdk_bdev_io_complete_aio_status(spdk_bdev_io_from_ctx(aio_task), rc);
SPDK_ERRLOG("%s: io_submit returned %d\n", __func__, rc);
}
return -1;
@ -225,7 +225,7 @@ bdev_aio_writev(struct file_disk *fdisk, struct spdk_io_channel *ch,
if (rc == -EAGAIN) {
spdk_bdev_io_complete(spdk_bdev_io_from_ctx(aio_task), SPDK_BDEV_IO_STATUS_NOMEM);
} else {
spdk_bdev_io_complete(spdk_bdev_io_from_ctx(aio_task), SPDK_BDEV_IO_STATUS_FAILED);
spdk_bdev_io_complete_aio_status(spdk_bdev_io_from_ctx(aio_task), rc);
SPDK_ERRLOG("%s: io_submit returned %d\n", __func__, rc);
}
return -1;
@ -239,8 +239,11 @@ bdev_aio_flush(struct file_disk *fdisk, struct bdev_aio_task *aio_task)
{
int rc = fsync(fdisk->fd);
spdk_bdev_io_complete(spdk_bdev_io_from_ctx(aio_task),
rc == 0 ? SPDK_BDEV_IO_STATUS_SUCCESS : SPDK_BDEV_IO_STATUS_FAILED);
if (rc == 0) {
spdk_bdev_io_complete(spdk_bdev_io_from_ctx(aio_task), SPDK_BDEV_IO_STATUS_SUCCESS);
} else {
spdk_bdev_io_complete_aio_status(spdk_bdev_io_from_ctx(aio_task), -errno);
}
}
static int
@ -326,9 +329,9 @@ static int
bdev_aio_io_channel_poll(struct bdev_aio_io_channel *io_ch)
{
int nr, i = 0;
enum spdk_bdev_io_status status;
struct bdev_aio_task *aio_task;
struct io_event events[SPDK_AIO_QUEUE_DEPTH];
uint64_t io_result;
nr = bdev_user_io_getevents(io_ch->io_ctx, SPDK_AIO_QUEUE_DEPTH, events);
@ -336,16 +339,23 @@ bdev_aio_io_channel_poll(struct bdev_aio_io_channel *io_ch)
return 0;
}
#define MAX_AIO_ERRNO 256
for (i = 0; i < nr; i++) {
aio_task = events[i].data;
if (events[i].res != aio_task->len) {
status = SPDK_BDEV_IO_STATUS_FAILED;
} else {
status = SPDK_BDEV_IO_STATUS_SUCCESS;
}
aio_task->ch->io_inflight--;
spdk_bdev_io_complete(spdk_bdev_io_from_ctx(aio_task), status);
io_result = events[i].res;
if (io_result == aio_task->len) {
spdk_bdev_io_complete(spdk_bdev_io_from_ctx(aio_task), SPDK_BDEV_IO_STATUS_SUCCESS);
} else if (io_result < MAX_AIO_ERRNO) {
/* Linux AIO will return its errno to io_event.res */
int aio_errno = io_result;
spdk_bdev_io_complete_aio_status(spdk_bdev_io_from_ctx(aio_task), -aio_errno);
} else {
SPDK_ERRLOG("failed to complete aio: requested len is %lu, but completed len is %lu.\n",
aio_task->len, io_result);
spdk_bdev_io_complete(spdk_bdev_io_from_ctx(aio_task), SPDK_BDEV_IO_STATUS_FAILED);
}
}
return nr;