* [PATCH 1/4] scsi: target: Add support for completing commands from backend context
2026-02-22 23:27 [PATCH 1/4] scsi: target: direct completion support Mike Christie
@ 2026-02-22 23:27 ` Mike Christie
2026-03-11 2:06 ` Martin K. Petersen
2026-02-22 23:27 ` [PATCH 2/4] scsi: target: Use driver completion preference by default Mike Christie
` (3 subsequent siblings)
4 siblings, 1 reply; 7+ messages in thread
From: Mike Christie @ 2026-02-22 23:27 UTC (permalink / raw)
To: martin.petersen, linux-scsi, target-devel; +Cc: Mike Christie
To complete a command several drivers just drop their reference and
add it to list to be processed by a driver specific thread. So there's
no need to go from backend context to the LIO thread then to the
driver's thread. When avoiding the LIO thread, IOPS can increase from
20-30% for workloads like:
fio --filename=/dev/sdb --direct=1 --rw=randrw --bs=8K \
--ioengine=libaio --iodepth=128 --numjobs=$jobs
where increasing jobs increases the performance improvement
(this is using NVMe drives with LIO's submit_type=1 to directly
submit).
This patch adds the infrastructure so drivers and userspace can
control how to complete a command like is done for the submission
path. In this patch there is no behavior change and we continue to
defer to the LIO workqueue thread. In the next patches we will
allow drivers to report what they support and allow userspace to
control the behavior.
Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
drivers/target/target_core_device.c | 1 +
drivers/target/target_core_transport.c | 60 +++++++++++++++++++++-----
include/target/target_core_base.h | 12 +++++-
include/target/target_core_fabric.h | 12 ++++--
4 files changed, 70 insertions(+), 15 deletions(-)
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
index 8ccb8541db1c..4e6736d469fd 100644
--- a/drivers/target/target_core_device.c
+++ b/drivers/target/target_core_device.c
@@ -813,6 +813,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
DA_UNMAP_ZEROES_DATA_DEFAULT;
dev->dev_attrib.max_write_same_len = DA_MAX_WRITE_SAME_LEN;
dev->dev_attrib.submit_type = TARGET_FABRIC_DEFAULT_SUBMIT;
+ dev->dev_attrib.submit_type = TARGET_QUEUE_COMPL;
/* Skip allocating lun_stats since we can't export them. */
xcopy_lun = &dev->xcopy_lun;
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 50d21888a0c9..2034a0761dfc 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -902,13 +902,59 @@ static bool target_cmd_interrupted(struct se_cmd *cmd)
return false;
}
+static void target_complete(struct se_cmd *cmd, int success)
+{
+ struct se_wwn *wwn = cmd->se_sess->se_tpg->se_tpg_wwn;
+ struct se_dev_attrib *da;
+ u8 compl_type;
+ int cpu;
+
+ if (!wwn) {
+ cpu = cmd->cpuid;
+ goto queue_work;
+ }
+
+ da = &cmd->se_dev->dev_attrib;
+ if (da->complete_type == TARGET_FABRIC_DEFAULT_COMPL)
+ compl_type = wwn->wwn_tf->tf_ops->default_compl_type;
+ else if (da->complete_type == TARGET_DIRECT_SUBMIT &&
+ wwn->wwn_tf->tf_ops->direct_compl_supp)
+ compl_type = TARGET_DIRECT_COMPL;
+ else
+ compl_type = TARGET_QUEUE_COMPL;
+
+ if (compl_type == TARGET_DIRECT_COMPL) {
+ /*
+ * Failure handling and processing secondary stages of
+ * complex commands can be too heavy to handle from the
+ * fabric driver so always defer.
+ */
+ if (success && !cmd->transport_complete_callback) {
+ target_complete_ok_work(&cmd->work);
+ return;
+ }
+
+ compl_type = TARGET_QUEUE_COMPL;
+ }
+
+queue_work:
+ INIT_WORK(&cmd->work, success ? target_complete_ok_work :
+ target_complete_failure_work);
+
+ if (!wwn || wwn->cmd_compl_affinity == SE_COMPL_AFFINITY_CPUID)
+ cpu = cmd->cpuid;
+ else
+ cpu = wwn->cmd_compl_affinity;
+
+ queue_work_on(cpu, target_completion_wq, &cmd->work);
+}
+
/* May be called from interrupt context so must not sleep. */
void target_complete_cmd_with_sense(struct se_cmd *cmd, u8 scsi_status,
sense_reason_t sense_reason)
{
- struct se_wwn *wwn = cmd->se_sess->se_tpg->se_tpg_wwn;
- int success, cpu;
unsigned long flags;
+ int success;
if (target_cmd_interrupted(cmd))
return;
@@ -933,15 +979,7 @@ void target_complete_cmd_with_sense(struct se_cmd *cmd, u8 scsi_status,
cmd->transport_state |= (CMD_T_COMPLETE | CMD_T_ACTIVE);
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- INIT_WORK(&cmd->work, success ? target_complete_ok_work :
- target_complete_failure_work);
-
- if (!wwn || wwn->cmd_compl_affinity == SE_COMPL_AFFINITY_CPUID)
- cpu = cmd->cpuid;
- else
- cpu = wwn->cmd_compl_affinity;
-
- queue_work_on(cpu, target_completion_wq, &cmd->work);
+ target_complete(cmd, success);
}
EXPORT_SYMBOL(target_complete_cmd_with_sense);
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index 7016d93fa383..aef61826922a 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -108,6 +108,15 @@
#define SE_MODE_PAGE_BUF 512
#define SE_SENSE_BUF 96
+enum target_compl_type {
+ /* Use the fabric driver's default completion type */
+ TARGET_FABRIC_DEFAULT_COMPL,
+ /* Complete from the backend calling context */
+ TARGET_DIRECT_COMPL,
+ /* Defer completion to the LIO workqueue */
+ TARGET_QUEUE_COMPL,
+};
+
enum target_submit_type {
/* Use the fabric driver's default submission type */
TARGET_FABRIC_DEFAULT_SUBMIT,
@@ -737,6 +746,7 @@ struct se_dev_attrib {
u32 atomic_granularity;
u32 atomic_max_with_boundary;
u32 atomic_max_boundary;
+ u8 complete_type;
u8 submit_type;
struct se_device *da_dev;
struct config_group da_group;
diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h
index 3378ff9ee271..3f68efb5c7d3 100644
--- a/include/target/target_core_fabric.h
+++ b/include/target/target_core_fabric.h
@@ -118,15 +118,21 @@ struct target_core_fabric_ops {
* its entirety before a command is aborted.
*/
unsigned int write_pending_must_be_called:1;
+ /*
+ * Set this if the driver does not require calling queue_data_in
+ * queue_status and check_stop_free from a worker thread when
+ * completing successful commands.
+ */
+ unsigned int direct_compl_supp:1;
/*
* Set this if the driver supports submitting commands to the backend
* from target_submit/target_submit_cmd.
*/
unsigned int direct_submit_supp:1;
- /*
- * Set this to a target_submit_type value.
- */
+ /* Set this to a target_submit_type value. */
u8 default_submit_type;
+ /* Set this to the target_compl_type value. */
+ u8 default_compl_type;
};
int target_register_template(const struct target_core_fabric_ops *fo);
--
2.43.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 2/4] scsi: target: Use driver completion preference by default
2026-02-22 23:27 [PATCH 1/4] scsi: target: direct completion support Mike Christie
2026-02-22 23:27 ` [PATCH 1/4] scsi: target: Add support for completing commands from backend context Mike Christie
@ 2026-02-22 23:27 ` Mike Christie
2026-02-22 23:27 ` [PATCH 3/4] scsi: target: Allow userspace to set the completion type Mike Christie
` (2 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Mike Christie @ 2026-02-22 23:27 UTC (permalink / raw)
To: martin.petersen, linux-scsi, target-devel; +Cc: Mike Christie
This has us use the driver's completion preference by default. There
is no behavior changes with this patch and we queue completion to
LIO's completion workqueue by default.
Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
drivers/infiniband/ulp/srpt/ib_srpt.c | 1 +
drivers/scsi/elx/efct/efct_lio.c | 2 ++
drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c | 1 +
drivers/scsi/qla2xxx/tcm_qla2xxx.c | 2 ++
drivers/target/iscsi/iscsi_target_configfs.c | 1 +
drivers/target/loopback/tcm_loop.c | 1 +
drivers/target/sbp/sbp_target.c | 1 +
drivers/target/target_core_device.c | 2 +-
drivers/target/tcm_fc/tfc_conf.c | 1 +
drivers/usb/gadget/function/f_tcm.c | 1 +
drivers/vhost/scsi.c | 1 +
drivers/xen/xen-scsiback.c | 1 +
12 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c
index 71269446353d..84b8ff5953a8 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
@@ -3926,6 +3926,7 @@ static const struct target_core_fabric_ops srpt_template = {
.tfc_wwn_attrs = srpt_wwn_attrs,
.tfc_tpg_attrib_attrs = srpt_tpg_attrib_attrs,
+ .default_compl_type = TARGET_QUEUE_COMPL,
.default_submit_type = TARGET_DIRECT_SUBMIT,
.direct_submit_supp = 1,
};
diff --git a/drivers/scsi/elx/efct/efct_lio.c b/drivers/scsi/elx/efct/efct_lio.c
index bd3d489e56ae..9634178af680 100644
--- a/drivers/scsi/elx/efct/efct_lio.c
+++ b/drivers/scsi/elx/efct/efct_lio.c
@@ -1612,6 +1612,7 @@ static const struct target_core_fabric_ops efct_lio_ops = {
.sess_get_initiator_sid = NULL,
.tfc_tpg_base_attrs = efct_lio_tpg_attrs,
.tfc_tpg_attrib_attrs = efct_lio_tpg_attrib_attrs,
+ .default_compl_type = TARGET_QUEUE_COMPL,
.default_submit_type = TARGET_DIRECT_SUBMIT,
.direct_submit_supp = 1,
};
@@ -1650,6 +1651,7 @@ static const struct target_core_fabric_ops efct_lio_npiv_ops = {
.tfc_tpg_base_attrs = efct_lio_npiv_tpg_attrs,
.tfc_tpg_attrib_attrs = efct_lio_npiv_tpg_attrib_attrs,
+ .default_compl_type = TARGET_QUEUE_COMPL,
.default_submit_type = TARGET_DIRECT_SUBMIT,
.direct_submit_supp = 1,
};
diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
index f259746bc804..a093a4e5d8df 100644
--- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
+++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
@@ -3968,6 +3968,7 @@ static const struct target_core_fabric_ops ibmvscsis_ops = {
.tfc_wwn_attrs = ibmvscsis_wwn_attrs,
+ .default_compl_type = TARGET_QUEUE_COMPL,
.default_submit_type = TARGET_DIRECT_SUBMIT,
.direct_submit_supp = 1,
};
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index 2fff68935338..3db9c52a9edc 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -1840,6 +1840,7 @@ static const struct target_core_fabric_ops tcm_qla2xxx_ops = {
.tfc_tpg_base_attrs = tcm_qla2xxx_tpg_attrs,
.tfc_tpg_attrib_attrs = tcm_qla2xxx_tpg_attrib_attrs,
+ .default_compl_type = TARGET_QUEUE_COMPL,
.default_submit_type = TARGET_DIRECT_SUBMIT,
.direct_submit_supp = 1,
};
@@ -1880,6 +1881,7 @@ static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = {
.tfc_wwn_attrs = tcm_qla2xxx_wwn_attrs,
+ .default_compl_type = TARGET_QUEUE_COMPL,
.default_submit_type = TARGET_DIRECT_SUBMIT,
.direct_submit_supp = 1,
};
diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c
index efe8cdb20060..704ec94383c3 100644
--- a/drivers/target/iscsi/iscsi_target_configfs.c
+++ b/drivers/target/iscsi/iscsi_target_configfs.c
@@ -1591,6 +1591,7 @@ const struct target_core_fabric_ops iscsi_ops = {
.write_pending_must_be_called = 1,
+ .default_compl_type = TARGET_QUEUE_COMPL,
.default_submit_type = TARGET_DIRECT_SUBMIT,
.direct_submit_supp = 1,
};
diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c
index 01a8e349dc4d..fd9beb1f5041 100644
--- a/drivers/target/loopback/tcm_loop.c
+++ b/drivers/target/loopback/tcm_loop.c
@@ -1106,6 +1106,7 @@ static const struct target_core_fabric_ops loop_ops = {
.tfc_wwn_attrs = tcm_loop_wwn_attrs,
.tfc_tpg_base_attrs = tcm_loop_tpg_attrs,
.tfc_tpg_attrib_attrs = tcm_loop_tpg_attrib_attrs,
+ .default_compl_type = TARGET_QUEUE_COMPL,
.default_submit_type = TARGET_QUEUE_SUBMIT,
.direct_submit_supp = 0,
};
diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c
index 9f167ff8da7b..78cd242d7004 100644
--- a/drivers/target/sbp/sbp_target.c
+++ b/drivers/target/sbp/sbp_target.c
@@ -2278,6 +2278,7 @@ static const struct target_core_fabric_ops sbp_ops = {
.tfc_tpg_base_attrs = sbp_tpg_base_attrs,
.tfc_tpg_attrib_attrs = sbp_tpg_attrib_attrs,
+ .default_compl_type = TARGET_QUEUE_COMPL,
.default_submit_type = TARGET_DIRECT_SUBMIT,
.direct_submit_supp = 1,
};
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
index 4e6736d469fd..619a82e78df6 100644
--- a/drivers/target/target_core_device.c
+++ b/drivers/target/target_core_device.c
@@ -813,7 +813,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
DA_UNMAP_ZEROES_DATA_DEFAULT;
dev->dev_attrib.max_write_same_len = DA_MAX_WRITE_SAME_LEN;
dev->dev_attrib.submit_type = TARGET_FABRIC_DEFAULT_SUBMIT;
- dev->dev_attrib.submit_type = TARGET_QUEUE_COMPL;
+ dev->dev_attrib.submit_type = TARGET_FABRIC_DEFAULT_COMPL;
/* Skip allocating lun_stats since we can't export them. */
xcopy_lun = &dev->xcopy_lun;
diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c
index f686d95d3273..679fb5ec9a7a 100644
--- a/drivers/target/tcm_fc/tfc_conf.c
+++ b/drivers/target/tcm_fc/tfc_conf.c
@@ -433,6 +433,7 @@ static const struct target_core_fabric_ops ft_fabric_ops = {
.tfc_wwn_attrs = ft_wwn_attrs,
.tfc_tpg_nacl_base_attrs = ft_nacl_base_attrs,
+ .default_compl_type = TARGET_QUEUE_COMPL,
.default_submit_type = TARGET_DIRECT_SUBMIT,
.direct_submit_supp = 1,
};
diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c
index 6e8804f04baa..64b569218ccb 100644
--- a/drivers/usb/gadget/function/f_tcm.c
+++ b/drivers/usb/gadget/function/f_tcm.c
@@ -2015,6 +2015,7 @@ static const struct target_core_fabric_ops usbg_ops = {
.tfc_wwn_attrs = usbg_wwn_attrs,
.tfc_tpg_base_attrs = usbg_base_attrs,
+ .default_compl_type = TARGET_QUEUE_COMPL,
.default_submit_type = TARGET_DIRECT_SUBMIT,
.direct_submit_supp = 1,
};
diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
index f43c1fe9fad9..1f00145116f4 100644
--- a/drivers/vhost/scsi.c
+++ b/drivers/vhost/scsi.c
@@ -2958,6 +2958,7 @@ static const struct target_core_fabric_ops vhost_scsi_ops = {
.tfc_tpg_base_attrs = vhost_scsi_tpg_attrs,
.tfc_tpg_attrib_attrs = vhost_scsi_tpg_attrib_attrs,
+ .default_compl_type = TARGET_QUEUE_COMPL,
.default_submit_type = TARGET_QUEUE_SUBMIT,
.direct_submit_supp = 1,
};
diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c
index 0c51edfd13dc..8949da55f3c8 100644
--- a/drivers/xen/xen-scsiback.c
+++ b/drivers/xen/xen-scsiback.c
@@ -1833,6 +1833,7 @@ static const struct target_core_fabric_ops scsiback_ops = {
.tfc_tpg_base_attrs = scsiback_tpg_attrs,
.tfc_tpg_param_attrs = scsiback_param_attrs,
+ .default_compl_type = TARGET_QUEUE_COMPL,
.default_submit_type = TARGET_DIRECT_SUBMIT,
.direct_submit_supp = 1,
};
--
2.43.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 3/4] scsi: target: Allow userspace to set the completion type
2026-02-22 23:27 [PATCH 1/4] scsi: target: direct completion support Mike Christie
2026-02-22 23:27 ` [PATCH 1/4] scsi: target: Add support for completing commands from backend context Mike Christie
2026-02-22 23:27 ` [PATCH 2/4] scsi: target: Use driver completion preference by default Mike Christie
@ 2026-02-22 23:27 ` Mike Christie
2026-02-22 23:27 ` [PATCH 4/4] vhost-scsi: Report direction completion support Mike Christie
2026-03-01 2:06 ` [PATCH 1/4] scsi: target: direct " Martin K. Petersen
4 siblings, 0 replies; 7+ messages in thread
From: Mike Christie @ 2026-02-22 23:27 UTC (permalink / raw)
To: martin.petersen, linux-scsi, target-devel; +Cc: Mike Christie
This allows userspace to request if we complete in the backend
context or the frontend driver. It works the same as submission
where you can write 0 to 2 to complete_type:
0 - Use the fabric driver's preference.
1 - Complete from the backend calling context if the fabric
supports it.
2 - Queue the completion to LIO's completion workqueue.
Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
drivers/target/target_core_configfs.c | 22 ++++++++++++++++++
drivers/target/target_core_fabric_configfs.c | 24 ++++++++++++++++++++
2 files changed, 46 insertions(+)
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index f7868b41c5e6..1c1c83c6752c 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -578,6 +578,7 @@ DEF_CONFIGFS_ATTRIB_SHOW(unmap_zeroes_data);
DEF_CONFIGFS_ATTRIB_SHOW(max_write_same_len);
DEF_CONFIGFS_ATTRIB_SHOW(emulate_rsoc);
DEF_CONFIGFS_ATTRIB_SHOW(submit_type);
+DEF_CONFIGFS_ATTRIB_SHOW(complete_type);
DEF_CONFIGFS_ATTRIB_SHOW(atomic_max_len);
DEF_CONFIGFS_ATTRIB_SHOW(atomic_alignment);
DEF_CONFIGFS_ATTRIB_SHOW(atomic_granularity);
@@ -1269,6 +1270,24 @@ static ssize_t submit_type_store(struct config_item *item, const char *page,
return count;
}
+static ssize_t complete_type_store(struct config_item *item, const char *page,
+ size_t count)
+{
+ struct se_dev_attrib *da = to_attrib(item);
+ int ret;
+ u8 val;
+
+ ret = kstrtou8(page, 0, &val);
+ if (ret < 0)
+ return ret;
+
+ if (val > TARGET_QUEUE_COMPL)
+ return -EINVAL;
+
+ da->complete_type = val;
+ return count;
+}
+
CONFIGFS_ATTR(, emulate_model_alias);
CONFIGFS_ATTR(, emulate_dpo);
CONFIGFS_ATTR(, emulate_fua_write);
@@ -1305,6 +1324,7 @@ CONFIGFS_ATTR(, max_write_same_len);
CONFIGFS_ATTR(, alua_support);
CONFIGFS_ATTR(, pgr_support);
CONFIGFS_ATTR(, submit_type);
+CONFIGFS_ATTR(, complete_type);
CONFIGFS_ATTR_RO(, atomic_max_len);
CONFIGFS_ATTR_RO(, atomic_alignment);
CONFIGFS_ATTR_RO(, atomic_granularity);
@@ -1353,6 +1373,7 @@ struct configfs_attribute *sbc_attrib_attrs[] = {
&attr_pgr_support,
&attr_emulate_rsoc,
&attr_submit_type,
+ &attr_complete_type,
&attr_atomic_alignment,
&attr_atomic_max_len,
&attr_atomic_granularity,
@@ -1376,6 +1397,7 @@ struct configfs_attribute *passthrough_attrib_attrs[] = {
&attr_alua_support,
&attr_pgr_support,
&attr_submit_type,
+ &attr_complete_type,
NULL,
};
EXPORT_SYMBOL(passthrough_attrib_attrs);
diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c
index 13159928e365..cab48c372e8f 100644
--- a/drivers/target/target_core_fabric_configfs.c
+++ b/drivers/target/target_core_fabric_configfs.c
@@ -1065,6 +1065,28 @@ target_fabric_wwn_cmd_completion_affinity_store(struct config_item *item,
}
CONFIGFS_ATTR(target_fabric_wwn_, cmd_completion_affinity);
+static ssize_t
+target_fabric_wwn_default_complete_type_show(struct config_item *item,
+ char *page)
+{
+ struct se_wwn *wwn = container_of(to_config_group(item), struct se_wwn,
+ param_group);
+ return sysfs_emit(page, "%u\n",
+ wwn->wwn_tf->tf_ops->default_compl_type);
+}
+CONFIGFS_ATTR_RO(target_fabric_wwn_, default_complete_type);
+
+static ssize_t
+target_fabric_wwn_direct_complete_supported_show(struct config_item *item,
+ char *page)
+{
+ struct se_wwn *wwn = container_of(to_config_group(item), struct se_wwn,
+ param_group);
+ return sysfs_emit(page, "%u\n",
+ wwn->wwn_tf->tf_ops->direct_compl_supp);
+}
+CONFIGFS_ATTR_RO(target_fabric_wwn_, direct_complete_supported);
+
static ssize_t
target_fabric_wwn_default_submit_type_show(struct config_item *item,
char *page)
@@ -1089,6 +1111,8 @@ CONFIGFS_ATTR_RO(target_fabric_wwn_, direct_submit_supported);
static struct configfs_attribute *target_fabric_wwn_param_attrs[] = {
&target_fabric_wwn_attr_cmd_completion_affinity,
+ &target_fabric_wwn_attr_default_complete_type,
+ &target_fabric_wwn_attr_direct_complete_supported,
&target_fabric_wwn_attr_default_submit_type,
&target_fabric_wwn_attr_direct_submit_supported,
NULL,
--
2.43.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 4/4] vhost-scsi: Report direction completion support
2026-02-22 23:27 [PATCH 1/4] scsi: target: direct completion support Mike Christie
` (2 preceding siblings ...)
2026-02-22 23:27 ` [PATCH 3/4] scsi: target: Allow userspace to set the completion type Mike Christie
@ 2026-02-22 23:27 ` Mike Christie
2026-03-01 2:06 ` [PATCH 1/4] scsi: target: direct " Martin K. Petersen
4 siblings, 0 replies; 7+ messages in thread
From: Mike Christie @ 2026-02-22 23:27 UTC (permalink / raw)
To: martin.petersen, linux-scsi, target-devel; +Cc: Mike Christie
This has vhost-scsi report that it supports direct completions.
When using a worker task per queue or group of queues with fast
backends then enabling direct completion and submissions increases
performance 20-30% with workloads like:
fio --filename=/dev/sdb --direct=1 --rw=randrw --bs=8K \
--ioengine=libaio --iodepth=128 --numjobs=$jobs
As jobs matches and passes the number of vCPUs in the VM then
the benefit increases.
However, when using a single worker then queueing completions
and submissions is best as the worker is busy handling mapping data
and setting/tearing down commands.
Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
drivers/vhost/scsi.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
index 1f00145116f4..653c08bb2520 100644
--- a/drivers/vhost/scsi.c
+++ b/drivers/vhost/scsi.c
@@ -2959,6 +2959,7 @@ static const struct target_core_fabric_ops vhost_scsi_ops = {
.tfc_tpg_attrib_attrs = vhost_scsi_tpg_attrib_attrs,
.default_compl_type = TARGET_QUEUE_COMPL,
+ .direct_compl_supp = 1,
.default_submit_type = TARGET_QUEUE_SUBMIT,
.direct_submit_supp = 1,
};
--
2.43.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH 1/4] scsi: target: direct completion support
2026-02-22 23:27 [PATCH 1/4] scsi: target: direct completion support Mike Christie
` (3 preceding siblings ...)
2026-02-22 23:27 ` [PATCH 4/4] vhost-scsi: Report direction completion support Mike Christie
@ 2026-03-01 2:06 ` Martin K. Petersen
4 siblings, 0 replies; 7+ messages in thread
From: Martin K. Petersen @ 2026-03-01 2:06 UTC (permalink / raw)
To: Mike Christie; +Cc: martin.petersen, linux-scsi, target-devel
Mike,
> The following patches made over Linus's current tree allow users to
> tell the target layer to perform direct completions instead of always
> deferring to LIO's completion workqueue. When the frontend driver
> already has multiple worker threads (or you are doing a LUN per target
> with a single thread per target) then bypassing the LIO workqueue can
> increase performance 20-30%.
Applied to 7.1/scsi-staging, thanks!
--
Martin K. Petersen
^ permalink raw reply [flat|nested] 7+ messages in thread