提交 4c054ba6 编写于 作者: N Nicholas Bellinger

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: NRoland 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: NNicholas Bellinger <nab@linux-iscsi.org>
上级 af74115e
...@@ -1181,15 +1181,20 @@ int target_cmd_size_check(struct se_cmd *cmd, unsigned int size) ...@@ -1181,15 +1181,20 @@ int target_cmd_size_check(struct se_cmd *cmd, unsigned int size)
/* Returns CHECK_CONDITION + INVALID_CDB_FIELD */ /* Returns CHECK_CONDITION + INVALID_CDB_FIELD */
goto out_invalid_cdb_field; goto out_invalid_cdb_field;
} }
/*
* For the overflow case keep the existing fabric provided
* ->data_length. Otherwise for the underflow case, reset
* ->data_length to the smaller SCSI expected data transfer
* length.
*/
if (size > cmd->data_length) { if (size > cmd->data_length) {
cmd->se_cmd_flags |= SCF_OVERFLOW_BIT; cmd->se_cmd_flags |= SCF_OVERFLOW_BIT;
cmd->residual_count = (size - cmd->data_length); cmd->residual_count = (size - cmd->data_length);
} else { } else {
cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT; cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT;
cmd->residual_count = (cmd->data_length - size); cmd->residual_count = (cmd->data_length - size);
cmd->data_length = size;
} }
cmd->data_length = size;
} }
return 0; return 0;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册