@@ -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 */
@@ -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);
@@ -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,
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@oracle.com> --- 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(-)