|
11 | 11 |
|
12 | 12 | #include "nvme_internal.h" |
13 | 13 | #include "spdk/queue.h" |
| 14 | +#include "spdk/thread.h" |
14 | 15 |
|
15 | 16 | #define SPDK_MAX_NUM_OF_TRANSPORTS 16 |
16 | 17 |
|
@@ -493,6 +494,95 @@ nvme_transport_connect_qpair_fail(struct spdk_nvme_qpair *qpair, void *unused) |
493 | 494 | nvme_transport_ctrlr_disconnect_qpair(ctrlr, qpair); |
494 | 495 | } |
495 | 496 |
|
| 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 | + |
496 | 586 | int |
497 | 587 | nvme_transport_ctrlr_connect_qpair(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_qpair *qpair) |
498 | 588 | { |
@@ -523,25 +613,31 @@ nvme_transport_ctrlr_connect_qpair(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nv |
523 | 613 | } |
524 | 614 | } |
525 | 615 |
|
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 | + } |
541 | 631 | } |
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; |
545 | 641 | } |
546 | 642 | } |
547 | 643 | } |
|
0 commit comments