diff options
| author | Nicholas Bellinger <nab@linux-iscsi.org> | 2013-10-01 20:04:40 -0400 |
|---|---|---|
| committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2013-10-03 07:24:07 -0400 |
| commit | db60df88ec39715fc3fb2a846cf35837e074c11d (patch) | |
| tree | 12b29dda83448869226325fad6ea67e2882c6b0b | |
| parent | d8855c154e748c9ccd7c78e6478560ed61438e7d (diff) | |
target: Fail on non zero scsi_status in compare_and_write_callback
This patch addresses a bug for backends such as IBLOCK that perform
asynchronous completion via transport_complete_cmd(), that will call
target_complete_failure_work() -> transport_generic_request_failure(),
upon exception status and invoke cmd->transport_complete_callback()
-> compare_and_write_callback() incorrectly during the failure case.
It adds a check for a non zero se_cmd->scsi_status within the first
invocation of compare_and_write_callback(), and will jump to out plus
up se_device->caw_sem before exiting the callback.
Reported-by: Thomas Glanzmann <thomas@glanzmann.de>
Tested-by: Thomas Glanzmann <thomas@glanzmann.de>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
| -rw-r--r-- | drivers/target/target_core_sbc.c | 11 |
1 files changed, 10 insertions, 1 deletions
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 1393d0ed746a..4714c6f8da4b 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c | |||
| @@ -372,7 +372,7 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd) | |||
| 372 | { | 372 | { |
| 373 | struct se_device *dev = cmd->se_dev; | 373 | struct se_device *dev = cmd->se_dev; |
| 374 | struct scatterlist *write_sg = NULL, *sg; | 374 | struct scatterlist *write_sg = NULL, *sg; |
| 375 | unsigned char *buf, *addr; | 375 | unsigned char *buf = NULL, *addr; |
| 376 | struct sg_mapping_iter m; | 376 | struct sg_mapping_iter m; |
| 377 | unsigned int offset = 0, len; | 377 | unsigned int offset = 0, len; |
| 378 | unsigned int nlbas = cmd->t_task_nolb; | 378 | unsigned int nlbas = cmd->t_task_nolb; |
| @@ -387,6 +387,15 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd) | |||
| 387 | */ | 387 | */ |
| 388 | if (!cmd->t_data_sg || !cmd->t_bidi_data_sg) | 388 | if (!cmd->t_data_sg || !cmd->t_bidi_data_sg) |
| 389 | return TCM_NO_SENSE; | 389 | return TCM_NO_SENSE; |
| 390 | /* | ||
| 391 | * Immediately exit + release dev->caw_sem if command has already | ||
| 392 | * been failed with a non-zero SCSI status. | ||
| 393 | */ | ||
| 394 | if (cmd->scsi_status) { | ||
| 395 | pr_err("compare_and_write_callback: non zero scsi_status:" | ||
| 396 | " 0x%02x\n", cmd->scsi_status); | ||
| 397 | goto out; | ||
| 398 | } | ||
| 390 | 399 | ||
| 391 | buf = kzalloc(cmd->data_length, GFP_KERNEL); | 400 | buf = kzalloc(cmd->data_length, GFP_KERNEL); |
| 392 | if (!buf) { | 401 | if (!buf) { |
