Messages in this thread Patch in this message | | | From | Daniel Wagner <> | Subject | [PATCH v2 5/5] nvme-fc: wait for initial connect attempt to finish | Date | Wed, 21 Feb 2024 14:24:04 +0100 |
| |
The TCP and RDMA transport are doing a synchronous connects, that is the syscal returns with the final result. The operation either fails or succeeds. The FC transport offloads the connect attempt to a workqueue and thus it's an asynchronous operation.
This async connect feature was introduced to mitigate problems with transient connect errors and the task to coordinate retries with userspace (nvme-cli).
Unfortunately, this makes the transports behave differently on the initial attempt. Streamline nvme-fc to wait for the initial connection attempt to succeed or fail.
In order to support also the async connection attempt introduce a new flag for userspace. The default is a synchronous initial connect attempt.
Link: https://lore.kernel.org/linux-nvme/0605ac36-16d5-2026-d3c6-62d346db6dfb@gmail.com/ Signed-off-by: Daniel Wagner <dwagner@suse.de> --- drivers/nvme/host/fabrics.c | 17 ++++++++++++++++- drivers/nvme/host/fabrics.h | 3 +++ drivers/nvme/host/fc.c | 26 +++++++++++++++++++++++++- 3 files changed, 44 insertions(+), 2 deletions(-)
diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c index 888285fe2289..52c95259debd 100644 --- a/drivers/nvme/host/fabrics.c +++ b/drivers/nvme/host/fabrics.c @@ -678,6 +678,7 @@ static const match_table_t opt_tokens = { #ifdef CONFIG_NVME_TCP_TLS { NVMF_OPT_TLS, "tls" }, #endif + { NVMF_OPT_CONNECT_ASYNC, "connect_async=%d" }, { NVMF_OPT_ERR, NULL } }; @@ -706,6 +707,7 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts, opts->tls = false; opts->tls_key = NULL; opts->keyring = NULL; + opts->connect_async = false; options = o = kstrdup(buf, GFP_KERNEL); if (!options) @@ -1024,6 +1026,19 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts, } opts->tls = true; break; + case NVMF_OPT_CONNECT_ASYNC: + if (match_int(args, &token)) { + ret = -EINVAL; + goto out; + } + if (token < 0 || token > 1) { + pr_err("Invalid connect_async %d value\n", + token); + ret = -EINVAL; + goto out; + } + opts->connect_async = token; + break; default: pr_warn("unknown parameter or missing value '%s' in ctrl creation request\n", p); @@ -1259,7 +1274,7 @@ EXPORT_SYMBOL_GPL(nvmf_ctrl_options_put); NVMF_OPT_HOST_ID | NVMF_OPT_DUP_CONNECT |\ NVMF_OPT_DISABLE_SQFLOW | NVMF_OPT_DISCOVERY |\ NVMF_OPT_FAIL_FAST_TMO | NVMF_OPT_DHCHAP_SECRET |\ - NVMF_OPT_DHCHAP_CTRL_SECRET) + NVMF_OPT_DHCHAP_CTRL_SECRET | NVMF_OPT_CONNECT_ASYNC) static struct nvme_ctrl * nvmf_create_ctrl(struct device *dev, const char *buf) diff --git a/drivers/nvme/host/fabrics.h b/drivers/nvme/host/fabrics.h index 8436533aed16..75bc61401e1b 100644 --- a/drivers/nvme/host/fabrics.h +++ b/drivers/nvme/host/fabrics.h @@ -73,6 +73,7 @@ enum { NVMF_OPT_TLS = 1 << 25, NVMF_OPT_KEYRING = 1 << 26, NVMF_OPT_TLS_KEY = 1 << 27, + NVMF_OPT_CONNECT_ASYNC = 1 << 28, }; /** @@ -116,6 +117,7 @@ enum { * @nr_poll_queues: number of queues for polling I/O * @tos: type of service * @fast_io_fail_tmo: Fast I/O fail timeout in seconds + * @connect_async: Don't wait for the intial connect attempt to succeed or fail */ struct nvmf_ctrl_options { struct kref ref; @@ -146,6 +148,7 @@ struct nvmf_ctrl_options { unsigned int nr_poll_queues; int tos; int fast_io_fail_tmo; + bool connect_async; }; int nvmf_ctrl_options_get(struct nvmf_ctrl_options *opts); diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index 7627d10a5812..ebc4ff6b3343 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c @@ -169,6 +169,7 @@ struct nvme_fc_ctrl { struct work_struct ioerr_work; struct delayed_work connect_work; + struct completion connect_completion; struct kref ref; unsigned long flags; @@ -803,6 +804,7 @@ nvme_fc_ctrl_connectivity_loss(struct nvme_fc_ctrl *ctrl) dev_warn(ctrl->ctrl.device, "NVME-FC{%d}: Couldn't schedule reset.\n", ctrl->cnum); + complete(&ctrl->connect_completion); nvme_fc_ctrl_put(ctrl); } break; @@ -871,6 +873,7 @@ nvme_fc_unregister_remoteport(struct nvme_fc_remote_port *portptr) dev_warn(ctrl->ctrl.device, "NVME-FC{%d}: controller connectivity lost.\n", ctrl->cnum); + complete(&ctrl->connect_completion); nvme_fc_ctrl_put(ctrl); } else nvme_fc_ctrl_connectivity_loss(ctrl); @@ -3326,6 +3329,7 @@ nvme_fc_reconnect_or_delete(struct nvme_fc_ctrl *ctrl, int status) ctrl->cnum, min_t(int, portptr->dev_loss_tmo, (ctrl->ctrl.opts->max_reconnects * ctrl->ctrl.opts->reconnect_delay))); + complete(&ctrl->connect_completion); nvme_fc_ctrl_put(ctrl); } } @@ -3385,10 +3389,12 @@ nvme_fc_connect_ctrl_work(struct work_struct *work) ret = nvme_fc_create_association(ctrl); if (ret) nvme_fc_reconnect_or_delete(ctrl, ret); - else + else { dev_info(ctrl->ctrl.device, "NVME-FC{%d}: controller connect complete\n", ctrl->cnum); + complete(&ctrl->connect_completion); + } } @@ -3494,6 +3500,7 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts, INIT_WORK(&ctrl->ctrl.reset_work, nvme_fc_reset_ctrl_work); INIT_DELAYED_WORK(&ctrl->connect_work, nvme_fc_connect_ctrl_work); + init_completion(&ctrl->connect_completion); INIT_WORK(&ctrl->ioerr_work, nvme_fc_ctrl_ioerr_work); spin_lock_init(&ctrl->lock); @@ -3541,6 +3548,9 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts, list_add_tail(&ctrl->ctrl_list, &rport->ctrl_list); spin_unlock_irqrestore(&rport->lock, flags); + if (!opts->connect_async) + nvme_fc_ctrl_get(ctrl); + if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_RESETTING) || !nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_CONNECTING)) { dev_err(ctrl->ctrl.device, @@ -3557,6 +3567,19 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts, flush_delayed_work(&ctrl->connect_work); + if (!opts->connect_async) { + enum nvme_ctrl_state state; + + wait_for_completion(&ctrl->connect_completion); + state = nvme_ctrl_state(&ctrl->ctrl); + nvme_fc_ctrl_put(ctrl); + + if (state != NVME_CTRL_LIVE) { + /* Cleanup is handled by the connect state machine */ + return ERR_PTR(-EIO); + } + } + dev_info(ctrl->ctrl.device, "NVME-FC{%d}: new ctrl: NQN \"%s\", hostnqn: %s\n", ctrl->cnum, nvmf_ctrl_subsysnqn(&ctrl->ctrl), opts->host->nqn); @@ -3913,6 +3936,7 @@ nvme_fc_delete_controllers(struct nvme_fc_rport *rport) dev_warn(ctrl->ctrl.device, "NVME-FC{%d}: transport unloading: deleting ctrl\n", ctrl->cnum); + complete(&ctrl->connect_completion); nvme_fc_ctrl_put(ctrl); } spin_unlock(&rport->lock); -- 2.43.1
| |