Commit fe4a9791 authored by Christoph Hellwig's avatar Christoph Hellwig

nvme-loop: add support for multiple ports

This is useful at least for multipath testing.
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarJohannes Thumshirn <jthumshirn@suse.de>
parent 90ea5ca4
...@@ -45,6 +45,7 @@ struct nvme_loop_ctrl { ...@@ -45,6 +45,7 @@ struct nvme_loop_ctrl {
struct nvme_ctrl ctrl; struct nvme_ctrl ctrl;
struct nvmet_ctrl *target_ctrl; struct nvmet_ctrl *target_ctrl;
struct nvmet_port *port;
}; };
static inline struct nvme_loop_ctrl *to_loop_ctrl(struct nvme_ctrl *ctrl) static inline struct nvme_loop_ctrl *to_loop_ctrl(struct nvme_ctrl *ctrl)
...@@ -63,7 +64,8 @@ struct nvme_loop_queue { ...@@ -63,7 +64,8 @@ struct nvme_loop_queue {
unsigned long flags; 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 LIST_HEAD(nvme_loop_ctrl_list);
static DEFINE_MUTEX(nvme_loop_ctrl_mutex); 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, ...@@ -169,7 +171,7 @@ static blk_status_t nvme_loop_queue_rq(struct blk_mq_hw_ctx *hctx,
blk_mq_start_request(req); blk_mq_start_request(req);
iod->cmd.common.flags |= NVME_CMD_SGL_METABUF; 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, if (!nvmet_req_init(&iod->req, &queue->nvme_cq,
&queue->nvme_sq, &nvme_loop_ops)) &queue->nvme_sq, &nvme_loop_ops))
return BLK_STS_OK; return BLK_STS_OK;
...@@ -517,6 +519,7 @@ static const struct nvme_ctrl_ops nvme_loop_ctrl_ops = { ...@@ -517,6 +519,7 @@ static const struct nvme_ctrl_ops nvme_loop_ctrl_ops = {
.free_ctrl = nvme_loop_free_ctrl, .free_ctrl = nvme_loop_free_ctrl,
.submit_async_event = nvme_loop_submit_async_event, .submit_async_event = nvme_loop_submit_async_event,
.delete_ctrl = nvme_loop_delete_ctrl_host, .delete_ctrl = nvme_loop_delete_ctrl_host,
.get_address = nvmf_get_address,
}; };
static int nvme_loop_create_io_queues(struct nvme_loop_ctrl *ctrl) static int nvme_loop_create_io_queues(struct nvme_loop_ctrl *ctrl)
...@@ -565,6 +568,23 @@ static int nvme_loop_create_io_queues(struct nvme_loop_ctrl *ctrl) ...@@ -565,6 +568,23 @@ static int nvme_loop_create_io_queues(struct nvme_loop_ctrl *ctrl)
return ret; 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, static struct nvme_ctrl *nvme_loop_create_ctrl(struct device *dev,
struct nvmf_ctrl_options *opts) struct nvmf_ctrl_options *opts)
{ {
...@@ -589,6 +609,7 @@ static struct nvme_ctrl *nvme_loop_create_ctrl(struct device *dev, ...@@ -589,6 +609,7 @@ static struct nvme_ctrl *nvme_loop_create_ctrl(struct device *dev,
ctrl->ctrl.sqsize = opts->queue_size - 1; ctrl->ctrl.sqsize = opts->queue_size - 1;
ctrl->ctrl.kato = opts->kato; ctrl->ctrl.kato = opts->kato;
ctrl->port = nvme_loop_find_port(&ctrl->ctrl);
ctrl->queues = kcalloc(opts->nr_io_queues + 1, sizeof(*ctrl->queues), ctrl->queues = kcalloc(opts->nr_io_queues + 1, sizeof(*ctrl->queues),
GFP_KERNEL); GFP_KERNEL);
...@@ -646,27 +667,17 @@ static struct nvme_ctrl *nvme_loop_create_ctrl(struct device *dev, ...@@ -646,27 +667,17 @@ static struct nvme_ctrl *nvme_loop_create_ctrl(struct device *dev,
static int nvme_loop_add_port(struct nvmet_port *port) static int nvme_loop_add_port(struct nvmet_port *port)
{ {
/* mutex_lock(&nvme_loop_ports_mutex);
* XXX: disalow adding more than one port so list_add_tail(&port->entry, &nvme_loop_ports);
* there is no connection rejections when a mutex_unlock(&nvme_loop_ports_mutex);
* 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;
return 0; return 0;
} }
static void nvme_loop_remove_port(struct nvmet_port *port) static void nvme_loop_remove_port(struct nvmet_port *port)
{ {
if (port == nvmet_loop_port) mutex_lock(&nvme_loop_ports_mutex);
nvmet_loop_port = NULL; list_del_init(&port->entry);
mutex_unlock(&nvme_loop_ports_mutex);
} }
static const struct nvmet_fabrics_ops nvme_loop_ops = { static const struct nvmet_fabrics_ops nvme_loop_ops = {
...@@ -682,6 +693,7 @@ static struct nvmf_transport_ops nvme_loop_transport = { ...@@ -682,6 +693,7 @@ static struct nvmf_transport_ops nvme_loop_transport = {
.name = "loop", .name = "loop",
.module = THIS_MODULE, .module = THIS_MODULE,
.create_ctrl = nvme_loop_create_ctrl, .create_ctrl = nvme_loop_create_ctrl,
.allowed_opts = NVMF_OPT_TRADDR,
}; };
static int __init nvme_loop_init_module(void) static int __init nvme_loop_init_module(void)
......
...@@ -85,7 +85,7 @@ struct nvmet_sq { ...@@ -85,7 +85,7 @@ struct nvmet_sq {
/** /**
* struct nvmet_port - Common structure to keep port * struct nvmet_port - Common structure to keep port
* information for the target. * 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 * @disc_addr: Address information is stored in a format defined
* for a discovery log page entry. * for a discovery log page entry.
* @group: ConfigFS group for this element's folder. * @group: ConfigFS group for this element's folder.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment