diff mbox series

[07/11] target: fix backend plugging

Message ID 20210204113513.93204-8-michael.christie@oracle.com (mailing list archive)
State New, archived
Headers show
Series target: fix cmd plugging and completion | expand

Commit Message

Mike Christie Feb. 4, 2021, 11:35 a.m. UTC
target_core_iblock is plugging and unplugging on every command and this
is causing perf issues for drivers that prefer batched cmds. With the
last patches we can now take multiple cmds from a fabric driver queue
and then pass them down the backend drivers in a batch. This patch adds
this support by adding 2 callouts to the backend for plugging and
unplugging the device. The next 2 patches add support for iblock and
tcmu device plugging.

Note: These patches currently only work for drivers like vhost and loop
which can just run target_execute_cmd from their write_pending callout
because they have all their data already and they have access to their
transport queues so they can batch multiple cmds to lio core.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/target/target_core_transport.c | 53 +++++++++++++++++++++++++-
 include/target/target_core_backend.h   |  2 +
 include/target/target_core_base.h      |  8 ++++
 3 files changed, 62 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index dec89e911348..35aa201ed80b 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -227,6 +227,48 @@  static void target_release_sess_cmd_refcnt(struct percpu_ref *ref)
 	wake_up(&sess->cmd_count_wq);
 }
 
+static void target_plug_device(struct se_cmd *se_cmd)
+{
+	struct se_device *se_dev = se_cmd->se_dev;
+	struct se_sess_cmd_queue *sq = se_cmd->sq;
+	struct se_dev_plug *se_plug;
+
+	if (!(se_cmd->se_cmd_flags & SCF_BATCHED) ||
+	    !se_dev->transport->plug_device)
+		return;
+
+	se_plug = se_dev->transport->plug_device(se_cmd);
+	if (!se_plug)
+		return;
+
+	/*
+	 * We have a ref to the lun at this point, but the cmds could
+	 * complete before we unplug, so grab a ref to the se_device so we
+	 * can call back into the backend.
+	 */
+	config_group_get(&se_dev->dev_group);
+	se_plug->se_dev = se_dev;
+	llist_add(&se_plug->plug_node, &sq->plug_list);
+}
+
+static void target_unplug_device(struct se_dev_plug *se_plug)
+{
+	struct se_device *se_dev = se_plug->se_dev;
+
+	se_dev->transport->unplug_device(se_plug);
+	config_group_put(&se_dev->dev_group);
+}
+
+static void target_unplug_sq(struct se_sess_cmd_queue *sq)
+{
+	struct se_dev_plug *se_plug, *next_plug;
+	struct llist_node *plug_list;
+
+	plug_list = llist_del_all(&sq->plug_list);
+	llist_for_each_entry_safe(se_plug, next_plug, plug_list, plug_node)
+		target_unplug_device(se_plug);
+}
+
 static void target_queued_submit_work(struct work_struct *work)
 {
 	struct se_sess_cmd_queue *sq =
@@ -242,8 +284,14 @@  static void target_queued_submit_work(struct work_struct *work)
 		return;
 
 	cmd_list = llist_reverse_order(cmd_list);
-	llist_for_each_entry_safe(se_cmd, next_cmd, cmd_list, se_cmd_list)
+	llist_for_each_entry_safe(se_cmd, next_cmd, cmd_list, se_cmd_list) {
+		se_cmd->sq = sq;
+		se_cmd->se_cmd_flags |= SCF_BATCHED;
+
 		se_sess->tfo->submit_queued_cmd(se_cmd);
+	}
+
+	target_unplug_sq(sq);
 }
 
 static void target_queue_cmd_work(struct se_sess_cmd_queue *q,
@@ -284,6 +332,7 @@  static void target_init_sess_cmd_queues(struct se_session *se_sess,
 	int i;
 
 	for (i = 0; i < se_sess->q_cnt; i++) {
+		init_llist_head(&q[i].plug_list);
 		init_llist_head(&q[i].cmd_list);
 		INIT_WORK(&q[i].work, work_fn);
 		q[i].se_sess = se_sess;
@@ -1759,6 +1808,8 @@  int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess
 		return 0;
 	}
 
+	target_plug_device(se_cmd);
+
 	rc = target_cmd_parse_cdb(se_cmd);
 	if (rc != 0) {
 		transport_generic_request_failure(se_cmd, rc);
diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h
index 6336780d83a7..45b5ae885af6 100644
--- a/include/target/target_core_backend.h
+++ b/include/target/target_core_backend.h
@@ -34,6 +34,8 @@  struct target_backend_ops {
 	int (*configure_device)(struct se_device *);
 	void (*destroy_device)(struct se_device *);
 	void (*free_device)(struct se_device *device);
+	struct se_dev_plug *(*plug_device)(struct se_cmd *se_cmd);
+	void (*unplug_device)(struct se_dev_plug *se_plug);
 
 	ssize_t (*set_configfs_dev_params)(struct se_device *,
 					   const char *, ssize_t);
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index b7f92a15cd1c..10ac30f7f638 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -146,6 +146,7 @@  enum se_cmd_flags_table {
 	SCF_USE_CPUID				= (1 << 16),
 	SCF_TASK_ATTR_SET			= (1 << 17),
 	SCF_TREAT_READ_AS_NORMAL		= (1 << 18),
+	SCF_BATCHED				= (1 << 19),
 };
 
 /*
@@ -513,6 +514,7 @@  struct se_cmd {
 	struct completion	t_transport_stop_comp;
 
 	struct work_struct	work;
+	struct se_sess_cmd_queue *sq;
 
 	struct scatterlist	*t_data_sg;
 	struct scatterlist	*t_data_sg_orig;
@@ -612,9 +614,15 @@  static inline struct se_node_acl *fabric_stat_to_nacl(struct config_item *item)
 			acl_fabric_stat_group);
 }
 
+struct se_dev_plug {
+	struct se_device        *se_dev;
+	struct llist_node	plug_node;
+};
+
 struct se_sess_cmd_queue {
 	struct llist_head	cmd_list;
 	struct work_struct	work;
+	struct llist_head	plug_list;
 	struct se_session	*se_sess;
 };