]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
nvme-rdma: add support for duplicate_connect option
authorJames Smart <jsmart2021@gmail.com>
Fri, 20 Oct 2017 23:17:09 +0000 (16:17 -0700)
committerChristoph Hellwig <hch@lst.de>
Fri, 27 Oct 2017 06:25:32 +0000 (09:25 +0300)
Adds support for the duplicate_connect option. When set to true,
checks whether there's an existing controller via the same target
address (traddr), target port (trsvcid), and if specified, host
address (host_traddr). Fails the connection request if there is
an existing controller.

Signed-off-by: James Smart <james.smart@broadcom.com>
Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
Signed-off-by: Christoph Hellwig <hch@lst.de>
drivers/nvme/host/rdma.c

index 62b58f9b7d00e9500d6ab2dea458fd6f568f9179..32b0a9ef26e678da8fdb8903123a4d5e6a3c896d 100644 (file)
@@ -1851,6 +1851,83 @@ static const struct nvme_ctrl_ops nvme_rdma_ctrl_ops = {
        .reinit_request         = nvme_rdma_reinit_request,
 };
 
+static inline bool
+__nvme_rdma_options_match(struct nvme_rdma_ctrl *ctrl,
+       struct nvmf_ctrl_options *opts)
+{
+       char *stdport = __stringify(NVME_RDMA_IP_PORT);
+
+
+       if (!nvmf_ctlr_matches_baseopts(&ctrl->ctrl, opts) ||
+           strcmp(opts->traddr, ctrl->ctrl.opts->traddr))
+               return false;
+
+       if (opts->mask & NVMF_OPT_TRSVCID &&
+           ctrl->ctrl.opts->mask & NVMF_OPT_TRSVCID) {
+               if (strcmp(opts->trsvcid, ctrl->ctrl.opts->trsvcid))
+                       return false;
+       } else if (opts->mask & NVMF_OPT_TRSVCID) {
+               if (strcmp(opts->trsvcid, stdport))
+                       return false;
+       } else if (ctrl->ctrl.opts->mask & NVMF_OPT_TRSVCID) {
+               if (strcmp(stdport, ctrl->ctrl.opts->trsvcid))
+                       return false;
+       }
+       /* else, it's a match as both have stdport. Fall to next checks */
+
+       /*
+        * checking the local address is rough. In most cases, one
+        * is not specified and the host port is selected by the stack.
+        *
+        * Assume no match if:
+        *  local address is specified and address is not the same
+        *  local address is not specified but remote is, or vice versa
+        *    (admin using specific host_traddr when it matters).
+        */
+       if (opts->mask & NVMF_OPT_HOST_TRADDR &&
+           ctrl->ctrl.opts->mask & NVMF_OPT_HOST_TRADDR) {
+               if (strcmp(opts->host_traddr, ctrl->ctrl.opts->host_traddr))
+                       return false;
+       } else if (opts->mask & NVMF_OPT_HOST_TRADDR ||
+                  ctrl->ctrl.opts->mask & NVMF_OPT_HOST_TRADDR)
+               return false;
+       /*
+        * if neither controller had an host port specified, assume it's
+        * a match as everything else matched.
+        */
+
+       return true;
+}
+
+/*
+ * Fails a connection request if it matches an existing controller
+ * (association) with the same tuple:
+ * <Host NQN, Host ID, local address, remote address, remote port, SUBSYS NQN>
+ *
+ * if local address is not specified in the request, it will match an
+ * existing controller with all the other parameters the same and no
+ * local port address specified as well.
+ *
+ * The ports don't need to be compared as they are intrinsically
+ * already matched by the port pointers supplied.
+ */
+static bool
+nvme_rdma_existing_controller(struct nvmf_ctrl_options *opts)
+{
+       struct nvme_rdma_ctrl *ctrl;
+       bool found = false;
+
+       mutex_lock(&nvme_rdma_ctrl_mutex);
+       list_for_each_entry(ctrl, &nvme_rdma_ctrl_list, list) {
+               found = __nvme_rdma_options_match(ctrl, opts);
+               if (found)
+                       break;
+       }
+       mutex_unlock(&nvme_rdma_ctrl_mutex);
+
+       return found;
+}
+
 static struct nvme_ctrl *nvme_rdma_create_ctrl(struct device *dev,
                struct nvmf_ctrl_options *opts)
 {
@@ -1887,6 +1964,11 @@ static struct nvme_ctrl *nvme_rdma_create_ctrl(struct device *dev,
                }
        }
 
+       if (!opts->duplicate_connect && nvme_rdma_existing_controller(opts)) {
+               ret = -EALREADY;
+               goto out_free_ctrl;
+       }
+
        ret = nvme_init_ctrl(&ctrl->ctrl, dev, &nvme_rdma_ctrl_ops,
                                0 /* no quirks, we're perfect! */);
        if (ret)