The new nvmet_mdev_pci driver lives on the mdev bus and does not have direct access to the configfs interface. For the nvmet_fabrics_ops.add_port callout we will add a mdev port. However, the mdev bus driver design requires the device under that to be added in a separate step (from the driver->probe callout). For this callout we need a way to find the controllers under a port, so this patch adds some helpers to be able to loop over the static controllers created under a port. The nvmet-mdev-pci driver can then loop over the controllers under a port and create a mdev/vfio device for the nvmet controller. Signed-off-by: Mike Christie <michael.christie@xxxxxxxxxx> --- drivers/nvme/target/configfs.c | 10 ++++- drivers/nvme/target/core.c | 71 ++++++++++++++++++++++++++++++++++ drivers/nvme/target/nvmet.h | 8 ++++ 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c index a946a879b9d6..31c484d51a69 100644 --- a/drivers/nvme/target/configfs.c +++ b/drivers/nvme/target/configfs.c @@ -2069,16 +2069,19 @@ static ssize_t nvmet_ctrl_enable_store(struct config_item *item, ret = -EBUSY; goto out_put_ctrl; } + list_add_tail(&ctrl->port_entry, &port->static_ctrls); ret = nvmet_enable_port(port); if (ret) - goto out_put_ctrl; + goto out_del_entry; conf->ctrl = ctrl; up_read(&nvmet_config_sem); return count; +out_del_entry: + list_del(&ctrl->port_entry); out_put_ctrl: up_read(&nvmet_config_sem); nvmet_ctrl_put(ctrl); @@ -2169,6 +2172,10 @@ static void nvmet_ctrl_release(struct config_item *item) mod = conf->args.ops->owner; if (conf->ctrl) { + down_write(&nvmet_config_sem); + list_del(&conf->ctrl->port_entry); + up_write(&nvmet_config_sem); + conf->args.ops->delete_ctrl(conf->ctrl); nvmet_ctrl_put(conf->ctrl); } @@ -2401,6 +2408,7 @@ static struct config_group *nvmet_ports_make(struct config_group *group, INIT_LIST_HEAD(&port->entry); INIT_LIST_HEAD(&port->subsystems); + INIT_LIST_HEAD(&port->static_ctrls); INIT_LIST_HEAD(&port->referrals); port->inline_data_size = -1; /* < 0 == let the transport choose */ port->max_queue_size = -1; /* < 0 == let the transport choose */ diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c index 1385368270de..6dab9d0f6b2f 100644 --- a/drivers/nvme/target/core.c +++ b/drivers/nvme/target/core.c @@ -1551,6 +1551,76 @@ static void nvmet_fatal_error_handler(struct work_struct *work) ctrl->ops->delete_ctrl(ctrl); } +/** + * nvmet_find_get_static_ctrl - find a static controller by port and cntlid + * @port: port to search under + * @trtype: transport type of the controller + * @cntlid: controller ID + * + * Returns: On success this returns a nvmet_ctrl with the refcount increased + * by one that the caller must drop. + */ +struct nvmet_ctrl *nvmet_find_get_static_ctrl(struct nvmet_port *port, + int trtype, u16 cntlid) +{ + struct nvmet_ctrl *ctrl; + + down_read(&nvmet_config_sem); + + list_for_each_entry(ctrl, &port->static_ctrls, port_entry) { + if (ctrl->ops->type != trtype) + continue; + + if (ctrl->cntlid == cntlid) { + if (!kref_get_unless_zero(&ctrl->ref)) + ctrl = NULL; + + up_read(&nvmet_config_sem); + return ctrl; + } + } + + up_read(&nvmet_config_sem); + return NULL; +} +EXPORT_SYMBOL_GPL(nvmet_find_get_static_ctrl); + +/** + * nvmet_for_each_static_ctrl - execute fn over matching static controllers + * @port: port that the controller is using. + * @trtype: transport type of the controller. + * @fn: function to execute on each matching controller. + * @priv: driver specific struct passed to fn. + * + * This must be called with the nvmet_config_sem. + * + * Returns: passes fn's return value to caller. + */ +int nvmet_for_each_static_ctrl(struct nvmet_port *port, int trtype, + nvmet_ctlr_iter_fn *fn, void *priv) +{ + struct nvmet_ctrl *ctrl; + int ret = 0; + + lockdep_assert_held(&nvmet_config_sem); + + list_for_each_entry(ctrl, &port->static_ctrls, port_entry) { + if (ctrl->ops->type != trtype) + continue; + + if (!kref_get_unless_zero(&ctrl->ref)) + continue; + + ret = fn(priv, port, ctrl); + nvmet_ctrl_put(ctrl); + if (ret) + break; + } + + return ret; +} +EXPORT_SYMBOL_GPL(nvmet_for_each_static_ctrl); + struct nvmet_ctrl *nvmet_alloc_ctrl(struct nvmet_alloc_ctrl_args *args) { struct nvmet_subsys *subsys; @@ -1599,6 +1669,7 @@ struct nvmet_ctrl *nvmet_alloc_ctrl(struct nvmet_alloc_ctrl_args *args) INIT_WORK(&ctrl->async_event_work, nvmet_async_event_work); INIT_LIST_HEAD(&ctrl->async_events); + INIT_LIST_HEAD(&ctrl->port_entry); INIT_RADIX_TREE(&ctrl->p2p_ns_map, GFP_KERNEL); INIT_WORK(&ctrl->fatal_err_work, nvmet_fatal_error_handler); INIT_DELAYED_WORK(&ctrl->ka_work, nvmet_keep_alive_timer); diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h index 2b0e624b80e1..a16d1c74e3d9 100644 --- a/drivers/nvme/target/nvmet.h +++ b/drivers/nvme/target/nvmet.h @@ -196,6 +196,7 @@ struct nvmet_port { struct config_group group; struct config_group subsys_group; struct list_head subsystems; + struct list_head static_ctrls; struct config_group referrals_group; struct list_head referrals; struct list_head global_entry; @@ -268,6 +269,7 @@ struct nvmet_ctrl { struct list_head async_events; struct work_struct async_event_work; + struct list_head port_entry; struct list_head subsys_entry; struct kref ref; struct delayed_work ka_work; @@ -603,6 +605,12 @@ struct nvmet_alloc_ctrl_args { u16 status; }; +typedef int (nvmet_ctlr_iter_fn)(void *priv, struct nvmet_port *port, + struct nvmet_ctrl *ctrl); +int nvmet_for_each_static_ctrl(struct nvmet_port *port, int trtype, + nvmet_ctlr_iter_fn *fn, void *priv); +struct nvmet_ctrl *nvmet_find_get_static_ctrl(struct nvmet_port *port, + int trtype, u16 cntlid); struct nvmet_ctrl *nvmet_alloc_ctrl(struct nvmet_alloc_ctrl_args *args); struct nvmet_ctrl *nvmet_ctrl_find_get(const char *subsysnqn, const char *hostnqn, u16 cntlid, -- 2.43.0