]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
nvme-loop: add support for multiple ports
authorChristoph Hellwig <hch@lst.de>
Sat, 26 May 2018 12:11:25 +0000 (14:11 +0200)
committerChristoph Hellwig <hch@lst.de>
Wed, 30 May 2018 06:05:18 +0000 (08:05 +0200)
This is useful at least for multipath testing.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
drivers/nvme/target/loop.c
drivers/nvme/target/nvmet.h

index 02cc316fad39619f2ab66127ada19d38df76a20d..1304ec3a7edeaadd2daf26ff74f55cb75e784696 100644 (file)
@@ -45,6 +45,7 @@ struct nvme_loop_ctrl {
        struct nvme_ctrl        ctrl;
 
        struct nvmet_ctrl       *target_ctrl;
+       struct nvmet_port       *port;
 };
 
 static inline struct nvme_loop_ctrl *to_loop_ctrl(struct nvme_ctrl *ctrl)
@@ -63,7 +64,8 @@ struct nvme_loop_queue {
        unsigned long           flags;
 };
 
-static struct nvmet_port *nvmet_loop_port;
+static LIST_HEAD(nvme_loop_ports);
+static DEFINE_MUTEX(nvme_loop_ports_mutex);
 
 static LIST_HEAD(nvme_loop_ctrl_list);
 static DEFINE_MUTEX(nvme_loop_ctrl_mutex);
@@ -169,7 +171,7 @@ static blk_status_t nvme_loop_queue_rq(struct blk_mq_hw_ctx *hctx,
 
        blk_mq_start_request(req);
        iod->cmd.common.flags |= NVME_CMD_SGL_METABUF;
-       iod->req.port = nvmet_loop_port;
+       iod->req.port = queue->ctrl->port;
        if (!nvmet_req_init(&iod->req, &queue->nvme_cq,
                        &queue->nvme_sq, &nvme_loop_ops))
                return BLK_STS_OK;
@@ -517,6 +519,7 @@ static const struct nvme_ctrl_ops nvme_loop_ctrl_ops = {
        .free_ctrl              = nvme_loop_free_ctrl,
        .submit_async_event     = nvme_loop_submit_async_event,
        .delete_ctrl            = nvme_loop_delete_ctrl_host,
+       .get_address            = nvmf_get_address,
 };
 
 static int nvme_loop_create_io_queues(struct nvme_loop_ctrl *ctrl)
@@ -565,6 +568,23 @@ out_destroy_queues:
        return ret;
 }
 
+static struct nvmet_port *nvme_loop_find_port(struct nvme_ctrl *ctrl)
+{
+       struct nvmet_port *p, *found = NULL;
+
+       mutex_lock(&nvme_loop_ports_mutex);
+       list_for_each_entry(p, &nvme_loop_ports, entry) {
+               /* if no transport address is specified use the first port */
+               if ((ctrl->opts->mask & NVMF_OPT_TRADDR) &&
+                   strcmp(ctrl->opts->traddr, p->disc_addr.traddr))
+                       continue;
+               found = p;
+               break;
+       }
+       mutex_unlock(&nvme_loop_ports_mutex);
+       return found;
+}
+
 static struct nvme_ctrl *nvme_loop_create_ctrl(struct device *dev,
                struct nvmf_ctrl_options *opts)
 {
@@ -589,6 +609,7 @@ static struct nvme_ctrl *nvme_loop_create_ctrl(struct device *dev,
 
        ctrl->ctrl.sqsize = opts->queue_size - 1;
        ctrl->ctrl.kato = opts->kato;
+       ctrl->port = nvme_loop_find_port(&ctrl->ctrl);
 
        ctrl->queues = kcalloc(opts->nr_io_queues + 1, sizeof(*ctrl->queues),
                        GFP_KERNEL);
@@ -646,27 +667,17 @@ out_put_ctrl:
 
 static int nvme_loop_add_port(struct nvmet_port *port)
 {
-       /*
-        * XXX: disalow adding more than one port so
-        * there is no connection rejections when a
-        * a subsystem is assigned to a port for which
-        * loop doesn't have a pointer.
-        * This scenario would be possible if we allowed
-        * more than one port to be added and a subsystem
-        * was assigned to a port other than nvmet_loop_port.
-        */
-
-       if (nvmet_loop_port)
-               return -EPERM;
-
-       nvmet_loop_port = port;
+       mutex_lock(&nvme_loop_ports_mutex);
+       list_add_tail(&port->entry, &nvme_loop_ports);
+       mutex_unlock(&nvme_loop_ports_mutex);
        return 0;
 }
 
 static void nvme_loop_remove_port(struct nvmet_port *port)
 {
-       if (port == nvmet_loop_port)
-               nvmet_loop_port = NULL;
+       mutex_lock(&nvme_loop_ports_mutex);
+       list_del_init(&port->entry);
+       mutex_unlock(&nvme_loop_ports_mutex);
 }
 
 static const struct nvmet_fabrics_ops nvme_loop_ops = {
@@ -682,6 +693,7 @@ static struct nvmf_transport_ops nvme_loop_transport = {
        .name           = "loop",
        .module         = THIS_MODULE,
        .create_ctrl    = nvme_loop_create_ctrl,
+       .allowed_opts   = NVMF_OPT_TRADDR,
 };
 
 static int __init nvme_loop_init_module(void)
index 2d09afcfe505529eff0d8b066d11a978c9a9d45a..32ebffcf464ce0a9f6c1b66d418fc2083fd95593 100644 (file)
@@ -85,7 +85,7 @@ struct nvmet_sq {
 /**
  * struct nvmet_port - Common structure to keep port
  *                             information for the target.
- * @entry:             List head for holding a list of these elements.
+ * @entry:             Entry into referrals or transport list.
  * @disc_addr:         Address information is stored in a format defined
  *                             for a discovery log page entry.
  * @group:             ConfigFS group for this element's folder.