Skip to content

Commit d32f6ad

Browse files
committed
nvme: replacing busy wait loop with poller to complete TCP connection asynchronously
longhorn/longhorn-9834 Signed-off-by: Chin-Ya Huang <chin-ya.huang@suse.com>
1 parent 1344af4 commit d32f6ad

1 file changed

Lines changed: 114 additions & 18 deletions

File tree

lib/nvme/nvme_transport.c

Lines changed: 114 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include "nvme_internal.h"
1313
#include "spdk/queue.h"
14+
#include "spdk/thread.h"
1415

1516
#define SPDK_MAX_NUM_OF_TRANSPORTS 16
1617

@@ -493,6 +494,95 @@ nvme_transport_connect_qpair_fail(struct spdk_nvme_qpair *qpair, void *unused)
493494
nvme_transport_ctrlr_disconnect_qpair(ctrlr, qpair);
494495
}
495496

497+
typedef void (*connect_complete_cb)(struct spdk_nvme_qpair *qpair, int status, void *cb_arg);
498+
499+
struct connect_ctx {
500+
struct spdk_nvme_qpair *qpair;
501+
struct spdk_nvme_poll_group *poll_group;
502+
struct spdk_poller *poller;
503+
504+
connect_complete_cb cb_fn;
505+
void *cb_arg;
506+
};
507+
508+
static void
509+
nvme_connect_complete(struct connect_ctx *ctx, int status)
510+
{
511+
if (ctx->cb_fn) {
512+
ctx->cb_fn(ctx->qpair, status, ctx->cb_arg);
513+
}
514+
515+
spdk_poller_unregister(&ctx->poller);
516+
free(ctx);
517+
}
518+
519+
static int
520+
nvme_connect_poller(void *arg)
521+
{
522+
struct connect_ctx *ctx = arg;
523+
struct spdk_nvme_qpair *qpair = ctx->qpair;
524+
int rc;
525+
526+
if (ctx->poll_group && spdk_nvme_ctrlr_is_fabrics(qpair->ctrlr)) {
527+
rc = spdk_nvme_poll_group_process_completions(ctx->poll_group, 0,
528+
nvme_transport_connect_qpair_fail);
529+
} else {
530+
rc = spdk_nvme_qpair_process_completions(qpair, 0);
531+
}
532+
533+
if (rc < 0) {
534+
nvme_connect_complete(ctx, rc);
535+
return SPDK_POLLER_BUSY;
536+
}
537+
538+
if (nvme_qpair_get_state(qpair) != NVME_QPAIR_CONNECTING) {
539+
nvme_connect_complete(ctx, 0);
540+
return SPDK_POLLER_BUSY;
541+
}
542+
543+
return SPDK_POLLER_BUSY;
544+
}
545+
546+
int
547+
start_async_qpair_connect(struct spdk_nvme_qpair *qpair,
548+
connect_complete_cb cb_fn,
549+
void *cb_arg)
550+
{
551+
struct connect_ctx *ctx;
552+
553+
if (!qpair || !qpair->poll_group) {
554+
return -EINVAL;
555+
}
556+
557+
ctx = calloc(1, sizeof(*ctx));
558+
if (!ctx) {
559+
return -ENOMEM;
560+
}
561+
562+
ctx->qpair = qpair;
563+
ctx->poll_group = qpair->poll_group->group;
564+
ctx->cb_fn = cb_fn;
565+
ctx->cb_arg = cb_arg;
566+
567+
ctx->poller = spdk_poller_register(nvme_connect_poller, ctx, 1000 /* 1ms */);
568+
if (!ctx->poller) {
569+
free(ctx);
570+
return -ENOMEM;
571+
}
572+
573+
return 0;
574+
}
575+
576+
static void
577+
nvme_qpair_connect_completion_cb(struct spdk_nvme_qpair *qpair, int status, void *cb_arg)
578+
{
579+
if (status == 0) {
580+
SPDK_NOTICELOG("NVMe qpair %p connected successfully.\n", (void *)qpair);
581+
} else {
582+
SPDK_ERRLOG("Failed to connect NVMe qpair %p (status: %d).\n", (void *)qpair, status);
583+
}
584+
}
585+
496586
int
497587
nvme_transport_ctrlr_connect_qpair(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_qpair *qpair)
498588
{
@@ -523,25 +613,31 @@ nvme_transport_ctrlr_connect_qpair(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nv
523613
}
524614
}
525615

526-
/* For the TCP transport, we poll the I/O queue periodically using g_opts.nvme_ioq_poll_period_us,
527-
* and do no wait synchronously for the qpair to connect. This allows the NVMe-oF
528-
* initiator to send the command and gives the target an opportunity to process
529-
* and respond without blocking. This unblocks when the initiator and target
530-
* are running on the same host.
531-
*/
532-
if (!qpair->async && (ctrlr->trid.trtype != SPDK_NVME_TRANSPORT_TCP)) {
533-
/* Busy wait until the qpair exits the connecting state */
534-
while (nvme_qpair_get_state(qpair) == NVME_QPAIR_CONNECTING) {
535-
if (qpair->poll_group && spdk_nvme_ctrlr_is_fabrics(ctrlr)) {
536-
rc = spdk_nvme_poll_group_process_completions(
537-
qpair->poll_group->group, 0,
538-
nvme_transport_connect_qpair_fail);
539-
} else {
540-
rc = spdk_nvme_qpair_process_completions(qpair, 0);
616+
if (!qpair->async) {
617+
if (ctrlr->trid.trtype != SPDK_NVME_TRANSPORT_TCP) {
618+
/* Busy wait until the qpair exits the connecting state */
619+
while (nvme_qpair_get_state(qpair) == NVME_QPAIR_CONNECTING) {
620+
if (qpair->poll_group && spdk_nvme_ctrlr_is_fabrics(ctrlr)) {
621+
rc = spdk_nvme_poll_group_process_completions(
622+
qpair->poll_group->group, 0,
623+
nvme_transport_connect_qpair_fail);
624+
} else {
625+
rc = spdk_nvme_qpair_process_completions(qpair, 0);
626+
}
627+
628+
if (rc < 0) {
629+
goto err;
630+
}
541631
}
542-
543-
if (rc < 0) {
544-
goto err;
632+
} else {
633+
/*
634+
* Non-blocking path for TCP transport. Use a poller to complete connection
635+
* asynchronously.
636+
*/
637+
rc = start_async_qpair_connect(qpair, nvme_qpair_connect_completion_cb, NULL);
638+
if (rc != 0) {
639+
SPDK_ERRLOG("Failed to start async connect: %d\n", rc);
640+
goto err;
545641
}
546642
}
547643
}

0 commit comments

Comments
 (0)