summaryrefslogtreecommitdiff
path: root/drivers/target/target_core_transport.c
diff options
context:
space:
mode:
authorAleksandr Miloserdov <a.miloserdov@yadro.com>2021-02-09 10:22:01 +0300
committerMartin K. Petersen <martin.petersen@oracle.com>2021-02-22 22:21:29 -0500
commit1c73e0c5e54d5f7d77f422a10b03ebe61eaed5ad (patch)
tree5bd664dd5b431e3e94380a219201b4fee7b218b8 /drivers/target/target_core_transport.c
parentd39bfd0686fd2b21f857c61bb2753db3a932cb24 (diff)
downloadlwn-1c73e0c5e54d5f7d77f422a10b03ebe61eaed5ad.tar.gz
lwn-1c73e0c5e54d5f7d77f422a10b03ebe61eaed5ad.zip
scsi: target: core: Add cmd length set before cmd complete
TCM doesn't properly handle underflow case for service actions. One way to prevent it is to always complete command with target_complete_cmd_with_length(), however it requires access to data_sg, which is not always available. This change introduces target_set_cmd_data_length() function which allows to set command data length before completing it. Link: https://lore.kernel.org/r/20210209072202.41154-2-a.miloserdov@yadro.com Reviewed-by: Roman Bolshakov <r.bolshakov@yadro.com> Reviewed-by: Bodo Stroesser <bostroesser@gmail.com> Signed-off-by: Aleksandr Miloserdov <a.miloserdov@yadro.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/target/target_core_transport.c')
-rw-r--r--drivers/target/target_core_transport.c15
1 files changed, 11 insertions, 4 deletions
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 93ea17cbad79..5ecb9f18a53d 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -879,11 +879,9 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status)
}
EXPORT_SYMBOL(target_complete_cmd);
-void target_complete_cmd_with_length(struct se_cmd *cmd, u8 scsi_status, int length)
+void target_set_cmd_data_length(struct se_cmd *cmd, int length)
{
- if ((scsi_status == SAM_STAT_GOOD ||
- cmd->se_cmd_flags & SCF_TREAT_READ_AS_NORMAL) &&
- length < cmd->data_length) {
+ if (length < cmd->data_length) {
if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) {
cmd->residual_count += cmd->data_length - length;
} else {
@@ -893,6 +891,15 @@ void target_complete_cmd_with_length(struct se_cmd *cmd, u8 scsi_status, int len
cmd->data_length = length;
}
+}
+EXPORT_SYMBOL(target_set_cmd_data_length);
+
+void target_complete_cmd_with_length(struct se_cmd *cmd, u8 scsi_status, int length)
+{
+ if (scsi_status == SAM_STAT_GOOD ||
+ cmd->se_cmd_flags & SCF_TREAT_READ_AS_NORMAL) {
+ target_set_cmd_data_length(cmd, length);
+ }
target_complete_cmd(cmd, scsi_status);
}