bdev/ocssd: request resubmission

If a spdk_bdev_io cannot be completed, because it is sent to a zone that
is currently busy, reschedule its submission.  This mechanism will be
used by appends, as mutliple append commands can be directed to the same
zone at the same time.

Change-Id: I60da2bd1835380812d22536ea275fb8fed9f8561
Signed-off-by: Konrad Sztyber <konrad.sztyber@intel.com>
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/477437
Reviewed-by: Mateusz Kozlowski <mateusz.kozlowski@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Community-CI: Broadcom SPDK FC-NVMe CI <spdk-ci.pdl@broadcom.com>
Community-CI: SPDK CI Jenkins <sys_sgci@intel.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
This commit is contained in:
Konrad Sztyber 2019-12-11 12:11:05 +01:00 committed by Tomasz Zawadzki
parent ffd53b6bad
commit 1ad438311e
5 changed files with 110 additions and 2 deletions

View File

@ -631,6 +631,13 @@ bdev_nvme_create_cb(void *io_device, void *ctx_buf)
return -1;
}
if (spdk_nvme_ctrlr_is_ocssd_supported(nvme_bdev_ctrlr->ctrlr)) {
if (bdev_ocssd_create_io_channel(ch)) {
spdk_nvme_ctrlr_free_io_qpair(ch->qpair);
return -1;
}
}
ch->poller = spdk_poller_register(bdev_nvme_poll, ch, g_opts.nvme_ioq_poll_period_us);
TAILQ_INIT(&ch->pending_resets);
@ -640,8 +647,13 @@ bdev_nvme_create_cb(void *io_device, void *ctx_buf)
static void
bdev_nvme_destroy_cb(void *io_device, void *ctx_buf)
{
struct nvme_bdev_ctrlr *nvme_bdev_ctrlr = io_device;
struct nvme_io_channel *ch = ctx_buf;
if (spdk_nvme_ctrlr_is_ocssd_supported(nvme_bdev_ctrlr->ctrlr)) {
bdev_ocssd_destroy_io_channel(ch);
}
spdk_nvme_ctrlr_free_io_qpair(ch->qpair);
spdk_poller_unregister(&ch->poller);
}

View File

@ -74,6 +74,11 @@ struct bdev_ocssd_io {
};
};
struct ocssd_io_channel {
struct spdk_poller *pending_poller;
TAILQ_HEAD(, spdk_bdev_io) pending_requests;
};
struct ocssd_bdev {
struct nvme_bdev nvme_bdev;
struct bdev_ocssd_zone *zones;
@ -582,6 +587,63 @@ bdev_ocssd_zone_management(struct spdk_io_channel *ioch, struct spdk_bdev_io *bd
}
}
static void bdev_ocssd_submit_request(struct spdk_io_channel *ioch, struct spdk_bdev_io *bdev_io);
static int
bdev_ocssd_poll_pending(void *ctx)
{
struct spdk_io_channel *ioch = ctx;
struct nvme_io_channel *nvme_ioch;
struct ocssd_io_channel *ocssd_ioch;
struct spdk_bdev_io *bdev_io;
TAILQ_HEAD(, spdk_bdev_io) pending_requests;
int num_requests = 0;
nvme_ioch = spdk_io_channel_get_ctx(ioch);
ocssd_ioch = nvme_ioch->ocssd_ioch;
TAILQ_INIT(&pending_requests);
TAILQ_SWAP(&ocssd_ioch->pending_requests, &pending_requests, spdk_bdev_io, module_link);
while ((bdev_io = TAILQ_FIRST(&pending_requests))) {
TAILQ_REMOVE(&pending_requests, bdev_io, module_link);
bdev_ocssd_submit_request(ioch, bdev_io);
num_requests++;
}
if (TAILQ_EMPTY(&ocssd_ioch->pending_requests)) {
spdk_poller_unregister(&ocssd_ioch->pending_poller);
}
return num_requests;
}
static void
bdev_ocssd_delay_request(struct spdk_io_channel *ioch, struct spdk_bdev_io *bdev_io)
{
struct nvme_io_channel *nvme_ioch = spdk_io_channel_get_ctx(ioch);
struct ocssd_io_channel *ocssd_ioch = nvme_ioch->ocssd_ioch;
TAILQ_INSERT_TAIL(&ocssd_ioch->pending_requests, bdev_io, module_link);
if (ocssd_ioch->pending_poller != NULL) {
return;
}
ocssd_ioch->pending_poller = spdk_poller_register(bdev_ocssd_poll_pending, ioch, 0);
if (ocssd_ioch->pending_poller == NULL) {
SPDK_ERRLOG("Failed to register pending requests poller\n");
/* If the poller cannot be registered, complete all of the pending
* requests immediately, as we have no means of resubmitting them.
*/
while ((bdev_io = TAILQ_FIRST(&ocssd_ioch->pending_requests))) {
TAILQ_REMOVE(&ocssd_ioch->pending_requests, bdev_io, module_link);
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
}
}
}
static void
bdev_ocssd_submit_request(struct spdk_io_channel *ioch, struct spdk_bdev_io *bdev_io)
{
@ -611,10 +673,16 @@ bdev_ocssd_submit_request(struct spdk_io_channel *ioch, struct spdk_bdev_io *bde
}
if (spdk_unlikely(rc != 0)) {
if (rc == -ENOMEM) {
switch (rc) {
case -ENOMEM:
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_NOMEM);
} else {
break;
case -EAGAIN:
bdev_ocssd_delay_request(ioch, bdev_io);
break;
default:
spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
break;
}
}
}
@ -1054,4 +1122,23 @@ bdev_ocssd_depopulate_namespace(struct nvme_bdev_ns *ns)
ns->type_ctx = NULL;
}
int
bdev_ocssd_create_io_channel(struct nvme_io_channel *ioch)
{
ioch->ocssd_ioch = calloc(1, sizeof(*ioch->ocssd_ioch));
if (ioch->ocssd_ioch == NULL) {
return -ENOMEM;
}
TAILQ_INIT(&ioch->ocssd_ioch->pending_requests);
return 0;
}
void
bdev_ocssd_destroy_io_channel(struct nvme_io_channel *ioch)
{
free(ioch->ocssd_ioch);
}
SPDK_LOG_REGISTER_COMPONENT("bdev_ocssd", SPDK_LOG_BDEV_OCSSD)

View File

@ -50,4 +50,7 @@ void bdev_ocssd_populate_namespace(struct nvme_bdev_ctrlr *nvme_bdev_ctrlr,
void bdev_ocssd_depopulate_namespace(struct nvme_bdev_ns *ns);
void bdev_ocssd_namespace_config_json(struct spdk_json_write_ctx *w, struct nvme_bdev_ns *ns);
int bdev_ocssd_create_io_channel(struct nvme_io_channel *ioch);
void bdev_ocssd_destroy_io_channel(struct nvme_io_channel *ioch);
#endif /* SPDK_BDEV_OCSSD_H */

View File

@ -128,6 +128,8 @@ struct nvme_async_probe_ctx {
uint32_t populates_in_progress;
};
struct ocssd_io_channel;
struct nvme_io_channel {
struct spdk_nvme_qpair *qpair;
struct spdk_poller *poller;
@ -137,6 +139,8 @@ struct nvme_io_channel {
uint64_t spin_ticks;
uint64_t start_ticks;
uint64_t end_ticks;
struct ocssd_io_channel *ocssd_ioch;
};
void nvme_ctrlr_populate_namespace_done(struct nvme_async_probe_ctx *ctx,

View File

@ -53,6 +53,8 @@ DEFINE_STUB_V(spdk_opal_close, (struct spdk_opal_dev *dev));
DEFINE_STUB(spdk_opal_revert_poll, int, (struct spdk_opal_dev *dev), 0);
DEFINE_STUB_V(spdk_bdev_io_complete_nvme_status, (struct spdk_bdev_io *bdev_io, uint32_t cdw0,
int sct, int sc));
DEFINE_STUB(spdk_bdev_io_get_io_channel, struct spdk_io_channel *, (struct spdk_bdev_io *bdev_io),
NULL);
struct nvme_request {
spdk_nvme_cmd_cb cb_fn;