From 021ff6edffcba83f76f876e068e9b540304228a1 Mon Sep 17 00:00:00 2001 From: Liu Xiaodong Date: Thu, 24 Dec 2020 03:16:40 -0500 Subject: [PATCH] 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 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/5690 Community-CI: Broadcom CI Community-CI: Mellanox Build Bot Reviewed-by: Shuhei Matsumoto Reviewed-by: Changpeng Liu Reviewed-by: Jim Harris Tested-by: SPDK CI Jenkins --- CHANGELOG.md | 5 +++++ include/spdk/bdev.h | 8 ++++++++ include/spdk/bdev_module.h | 11 +++++++++++ lib/bdev/bdev.c | 28 ++++++++++++++++++++++++++++ lib/bdev/spdk_bdev.map | 2 ++ module/bdev/aio/bdev_aio.c | 34 ++++++++++++++++++++++------------ 6 files changed, 76 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 123c8dbd2..89142fb5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/include/spdk/bdev.h b/include/spdk/bdev.h index 3bf618cf3..d8946464b 100644 --- a/include/spdk/bdev.h +++ b/include/spdk/bdev.h @@ -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. * diff --git a/include/spdk/bdev_module.h b/include/spdk/bdev_module.h index 77f95c68e..bbb9f9438 100644 --- a/include/spdk/bdev_module.h +++ b/include/spdk/bdev_module.h @@ -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. * diff --git a/lib/bdev/bdev.c b/lib/bdev/bdev.c index f9d145983..2a642d603 100644 --- a/lib/bdev/bdev.c +++ b/lib/bdev/bdev.c @@ -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) { diff --git a/lib/bdev/spdk_bdev.map b/lib/bdev/spdk_bdev.map index b827f9d27..267c8757e 100644 --- a/lib/bdev/spdk_bdev.map +++ b/lib/bdev/spdk_bdev.map @@ -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; diff --git a/module/bdev/aio/bdev_aio.c b/module/bdev/aio/bdev_aio.c index f2c4814ca..60801ac6e 100644 --- a/module/bdev/aio/bdev_aio.c +++ b/module/bdev/aio/bdev_aio.c @@ -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;