bdev/nvme: Support abort IO by using spdk_nvme_ctrlr_cmd_abort_ext()

Change NVMe bdev module to enable abort as IO type.

Change _bdev_nvme_submit_request() to process abort request when the
IO type is abort.

The current thread tries aborting I/O command in the I/O qpair first.
If no I/O command to abort was found, send message to the thread which
is registered when creating controller. The controller thread tries
aborting admin command in the admin qpair next. If no admin command
to abort was found, complete the abort request with failure.

spdk_nvme_ctrlr_cmd_abort_ext() is used to try aborting command whose
cb_arg matches. qpair is set to NULL when trying to abort admin command.

Before calling spdk_nvme_ctrlr_cmd_abort_ext(), save the current
thread to process admin command completion correctly.

spdk_bdev_abort() supports any bdev module other than NVMe bdev
module and does not check CDW0 but checks only if the completion
status is success or failure. So add bdev_nvme_abort_done() and
converts the NVMe completion status to the bdev completion status.

Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Change-Id: If6aebae0ba2f6c5834ee926e161af9c4d825f341
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/2040
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Broadcom CI
Community-CI: Mellanox Build Bot
Reviewed-by: Michael Haeuptle <michaelhaeuptle@gmail.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Aleksey Marchuk <alexeymar@mellanox.com>
This commit is contained in:
Shuhei Matsumoto 2020-07-08 17:03:49 +09:00 committed by Tomasz Zawadzki
parent 613c9386ff
commit 47b0d4275c

View File

@ -163,6 +163,8 @@ static int bdev_nvme_io_passthru_md(struct nvme_bdev *nbdev, struct spdk_io_chan
struct nvme_bdev_io *bio,
struct spdk_nvme_cmd *cmd, void *buf, size_t nbytes, void *md_buf, size_t md_len);
static int bdev_nvme_reset(struct nvme_bdev_ctrlr *nvme_bdev_ctrlr, struct nvme_bdev_io *bio);
static int bdev_nvme_abort(struct nvme_bdev *nbdev, struct spdk_io_channel *ch,
struct nvme_bdev_io *bio, struct nvme_bdev_io *bio_to_abort);
typedef void (*populate_namespace_fn)(struct nvme_bdev_ctrlr *nvme_bdev_ctrlr,
struct nvme_bdev_ns *nvme_ns, struct nvme_async_probe_ctx *ctx);
@ -533,6 +535,7 @@ _bdev_nvme_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_
struct nvme_io_channel *nvme_ch = spdk_io_channel_get_ctx(ch);
struct nvme_bdev *nbdev = (struct nvme_bdev *)bdev_io->bdev->ctxt;
struct nvme_bdev_io *nbdev_io = (struct nvme_bdev_io *)bdev_io->driver_ctx;
struct nvme_bdev_io *nbdev_io_to_abort;
if (nvme_ch->qpair == NULL) {
/* The device is currently resetting */
@ -626,6 +629,13 @@ _bdev_nvme_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_
bdev_io->u.nvme_passthru.md_buf,
bdev_io->u.nvme_passthru.md_len);
case SPDK_BDEV_IO_TYPE_ABORT:
nbdev_io_to_abort = (struct nvme_bdev_io *)bdev_io->u.abort.bio_to_abort->driver_ctx;
return bdev_nvme_abort(nbdev,
ch,
nbdev_io,
nbdev_io_to_abort);
default:
return -EINVAL;
}
@ -659,6 +669,7 @@ bdev_nvme_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type)
case SPDK_BDEV_IO_TYPE_FLUSH:
case SPDK_BDEV_IO_TYPE_NVME_ADMIN:
case SPDK_BDEV_IO_TYPE_NVME_IO:
case SPDK_BDEV_IO_TYPE_ABORT:
return true;
case SPDK_BDEV_IO_TYPE_COMPARE:
@ -2245,6 +2256,28 @@ bdev_nvme_admin_passthru_completion(void *ctx)
bio->cpl.cdw0, bio->cpl.status.sct, bio->cpl.status.sc);
}
static void
bdev_nvme_abort_completion(void *ctx)
{
struct nvme_bdev_io *bio = ctx;
struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio);
if (spdk_nvme_cpl_is_abort_success(&bio->cpl)) {
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
} else {
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
}
}
static void
bdev_nvme_abort_done(void *ref, const struct spdk_nvme_cpl *cpl)
{
struct nvme_bdev_io *bio = ref;
bio->cpl = *cpl;
spdk_thread_send_msg(bio->orig_thread, bdev_nvme_abort_completion, bio);
}
static void
bdev_nvme_admin_passthru_done(void *ref, const struct spdk_nvme_cpl *cpl)
{
@ -2629,6 +2662,60 @@ bdev_nvme_io_passthru_md(struct nvme_bdev *nbdev, struct spdk_io_channel *ch,
(uint32_t)nbytes, md_buf, bdev_nvme_queued_done, bio);
}
static void
bdev_nvme_abort_admin_cmd(void *ctx)
{
struct nvme_bdev_io *bio = ctx;
struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio);
struct nvme_bdev *nbdev;
struct nvme_bdev_io *bio_to_abort;
int rc;
nbdev = (struct nvme_bdev *)bdev_io->bdev->ctxt;
bio_to_abort = (struct nvme_bdev_io *)bdev_io->u.abort.bio_to_abort->driver_ctx;
rc = spdk_nvme_ctrlr_cmd_abort_ext(nbdev->nvme_bdev_ctrlr->ctrlr,
NULL,
bio_to_abort,
bdev_nvme_abort_done, bio);
if (rc == -ENOENT) {
/* If no admin command was found in admin qpair, complete the abort
* request with failure.
*/
bio->cpl.cdw0 |= 1U;
bio->cpl.status.sc = SPDK_NVME_SC_SUCCESS;
bio->cpl.status.sct = SPDK_NVME_SCT_GENERIC;
spdk_thread_send_msg(bio->orig_thread, bdev_nvme_abort_completion, bio);
}
}
static int
bdev_nvme_abort(struct nvme_bdev *nbdev, struct spdk_io_channel *ch,
struct nvme_bdev_io *bio, struct nvme_bdev_io *bio_to_abort)
{
struct nvme_io_channel *nvme_ch = spdk_io_channel_get_ctx(ch);
int rc;
bio->orig_thread = spdk_io_channel_get_thread(ch);
rc = spdk_nvme_ctrlr_cmd_abort_ext(nbdev->nvme_bdev_ctrlr->ctrlr,
nvme_ch->qpair,
bio_to_abort,
bdev_nvme_abort_done, bio);
if (rc == -ENOENT) {
/* If no command was found in I/O qpair, the target command may be
* admin command. Only a single thread tries aborting admin command
* to clean I/O flow.
*/
spdk_thread_send_msg(nbdev->nvme_bdev_ctrlr->thread,
bdev_nvme_abort_admin_cmd, bio);
rc = 0;
}
return rc;
}
static void
bdev_nvme_get_spdk_running_config(FILE *fp)
{