nvme-loop: add support for multiple ports
This is useful at least for multipath testing. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
This commit is contained in:
parent
90ea5ca45c
commit
fe4a97918d
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue