mirror of
https://github.com/torvalds/linux.git
synced 2026-07-31 19:47:08 +02:00
Merge patch series "scsi: target: Add support for completing commands from backend context"
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%. Link: https://patch.msgid.link/20260222232946.7637-1-michael.christie@oracle.com Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
commit
1bf5c303eb
|
|
@ -3925,6 +3925,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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1841,6 +1841,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,
|
||||
};
|
||||
|
|
@ -1881,6 +1882,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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1107,6 +1107,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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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_FABRIC_DEFAULT_COMPL;
|
||||
|
||||
/* Skip allocating lun_stats since we can't export them. */
|
||||
xcopy_lun = &dev->xcopy_lun;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -434,6 +434,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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2016,6 +2016,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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2950,6 +2950,8 @@ 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,
|
||||
.direct_compl_supp = 1,
|
||||
.default_submit_type = TARGET_QUEUE_SUBMIT,
|
||||
.direct_submit_supp = 1,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1832,6 +1832,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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -111,6 +111,15 @@
|
|||
/* Peripheral Device Text Identification Information */
|
||||
#define PD_TEXT_ID_INFO_LEN 256
|
||||
|
||||
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,
|
||||
|
|
@ -741,6 +750,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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user