aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/target
diff options
context:
space:
mode:
authorNicholas Bellinger <nab@linux-iscsi.org>2012-08-16 18:33:10 -0400
committerNicholas Bellinger <nab@linux-iscsi.org>2012-08-23 18:26:52 -0400
commit4c054ba63ad47ef244cfcfa1cea38134620a5bae (patch)
tree5398137dd4d60f1166094abe6b4ee98524f5b602 /drivers/target
parentaf74115eed22698f771fec1287a864975c9a6671 (diff)
target: Fix ->data_length re-assignment bug with SCSI overflow
This patch fixes a long-standing bug with SCSI overflow handling where se_cmd->data_length was incorrectly being re-assigned to the larger CDB extracted allocation length, resulting in a number of fabric level errors that would end up causing a session reset in most cases. So instead now: - Only re-assign se_cmd->data_length durining UNDERFLOW (to use the smaller value) - Use existing se_cmd->data_length for OVERFLOW (to use the smaller value) This fix has been tested with the following CDB to generate an SCSI overflow: sg_raw -r512 /dev/sdc 28 0 0 0 0 0 0 0 9 0 Tested using iscsi-target, tcm_qla2xxx, loopback and tcm_vhost fabric ports. Here is a bit more detail on each case: - iscsi-target: Bug with open-iscsi with overflow, sg_raw returns -3584 bytes of data. - tcm_qla2xxx: Working as expected, returnins 512 bytes of data - loopback: sg_raw returns CHECK_CONDITION, from overflow rejection in transport_generic_map_mem_to_cmd() - tcm_vhost: Same as loopback Reported-by: Roland Dreier <roland@purestorage.com> Cc: Roland Dreier <roland@purestorage.com> Cc: Christoph Hellwig <hch@lst.de> Cc: Boaz Harrosh <bharrosh@panasas.com> Cc: <stable@vger.kernel.org> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/target')
-rw-r--r--drivers/target/target_core_transport.c9
1 files changed, 7 insertions, 2 deletions
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 4de3186dc44e..3425098ef728 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -1181,15 +1181,20 @@ int target_cmd_size_check(struct se_cmd *cmd, unsigned int size)
1181 /* Returns CHECK_CONDITION + INVALID_CDB_FIELD */ 1181 /* Returns CHECK_CONDITION + INVALID_CDB_FIELD */
1182 goto out_invalid_cdb_field; 1182 goto out_invalid_cdb_field;
1183 } 1183 }
1184 1184 /*
1185 * For the overflow case keep the existing fabric provided
1186 * ->data_length. Otherwise for the underflow case, reset
1187 * ->data_length to the smaller SCSI expected data transfer
1188 * length.
1189 */
1185 if (size > cmd->data_length) { 1190 if (size > cmd->data_length) {
1186 cmd->se_cmd_flags |= SCF_OVERFLOW_BIT; 1191 cmd->se_cmd_flags |= SCF_OVERFLOW_BIT;
1187 cmd->residual_count = (size - cmd->data_length); 1192 cmd->residual_count = (size - cmd->data_length);
1188 } else { 1193 } else {
1189 cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT; 1194 cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT;
1190 cmd->residual_count = (cmd->data_length - size); 1195 cmd->residual_count = (cmd->data_length - size);
1196 cmd->data_length = size;
1191 } 1197 }
1192 cmd->data_length = size;
1193 } 1198 }
1194 1199
1195 return 0; 1200 return 0;