Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7abc17dc authored by Aleksandr Miloserdov's avatar Aleksandr Miloserdov Committed by Greg Kroah-Hartman
Browse files

scsi: target: core: Add cmd length set before cmd complete

[ Upstream commit 1c73e0c5e54d5f7d77f422a10b03ebe61eaed5ad ]

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: default avatarRoman Bolshakov <r.bolshakov@yadro.com>
Reviewed-by: default avatarBodo Stroesser <bostroesser@gmail.com>
Signed-off-by: default avatarAleksandr Miloserdov <a.miloserdov@yadro.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 1e1749c5
Loading
Loading
Loading
Loading
+11 −4
Original line number Diff line number Diff line
@@ -841,11 +841,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 {
@@ -855,6 +853,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);
}
+1 −0
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ int transport_backend_register(const struct target_backend_ops *);
void	target_backend_unregister(const struct target_backend_ops *);

void	target_complete_cmd(struct se_cmd *, u8);
void	target_set_cmd_data_length(struct se_cmd *, int);
void	target_complete_cmd_with_length(struct se_cmd *, u8, int);

void	transport_copy_sense_to_cmd(struct se_cmd *, unsigned char *);