diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2011-11-16 02:59:00 -0500 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2011-12-06 01:00:54 -0500 |
commit | 7e46cf02687e40197ae07c623e660be2a2720064 (patch) | |
tree | 47e6b57863e2716dfa5a6347b12a23c063e446cd /drivers/target | |
parent | fef58a6096770ed6ab49103a430cc755254a74d9 (diff) |
iscsi-target: Fix residual count hanlding + remove iscsi_cmd->residual_count
This patch fixes iscsi-target handling of underflow where residual data is
causing an OOPs by using the incorrect iscsi_cmd_t->data_length initially
assigned in iscsit_allocate_se_cmd(). It resets iscsi_cmd_t->data_length
from se_cmd_t->data_length after transport_generic_allocate_tasks()
has been invoked in iscsit_handle_scsi_cmd() RX context, and converts
iscsi_cmd->residual_count usage to access iscsi_cmd->se_cmd.residual_count
to get the proper residual count set by target-core.
Reported-by: <lists@internyc.net>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Andy Grover <agrover@redhat.com>
Cc: stable@kernel.org
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/target')
-rw-r--r-- | drivers/target/iscsi/iscsi_target.c | 10 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_core.h | 1 |
2 files changed, 6 insertions, 5 deletions
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 4d81e1007c92..26834eff8960 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c | |||
@@ -1039,6 +1039,8 @@ done: | |||
1039 | */ | 1039 | */ |
1040 | send_check_condition = 1; | 1040 | send_check_condition = 1; |
1041 | } else { | 1041 | } else { |
1042 | cmd->data_length = cmd->se_cmd.data_length; | ||
1043 | |||
1042 | if (iscsit_decide_list_to_build(cmd, payload_length) < 0) | 1044 | if (iscsit_decide_list_to_build(cmd, payload_length) < 0) |
1043 | return iscsit_add_reject_from_cmd( | 1045 | return iscsit_add_reject_from_cmd( |
1044 | ISCSI_REASON_BOOKMARK_NO_RESOURCES, | 1046 | ISCSI_REASON_BOOKMARK_NO_RESOURCES, |
@@ -2508,10 +2510,10 @@ static int iscsit_send_data_in( | |||
2508 | if (hdr->flags & ISCSI_FLAG_DATA_STATUS) { | 2510 | if (hdr->flags & ISCSI_FLAG_DATA_STATUS) { |
2509 | if (cmd->se_cmd.se_cmd_flags & SCF_OVERFLOW_BIT) { | 2511 | if (cmd->se_cmd.se_cmd_flags & SCF_OVERFLOW_BIT) { |
2510 | hdr->flags |= ISCSI_FLAG_DATA_OVERFLOW; | 2512 | hdr->flags |= ISCSI_FLAG_DATA_OVERFLOW; |
2511 | hdr->residual_count = cpu_to_be32(cmd->residual_count); | 2513 | hdr->residual_count = cpu_to_be32(cmd->se_cmd.residual_count); |
2512 | } else if (cmd->se_cmd.se_cmd_flags & SCF_UNDERFLOW_BIT) { | 2514 | } else if (cmd->se_cmd.se_cmd_flags & SCF_UNDERFLOW_BIT) { |
2513 | hdr->flags |= ISCSI_FLAG_DATA_UNDERFLOW; | 2515 | hdr->flags |= ISCSI_FLAG_DATA_UNDERFLOW; |
2514 | hdr->residual_count = cpu_to_be32(cmd->residual_count); | 2516 | hdr->residual_count = cpu_to_be32(cmd->se_cmd.residual_count); |
2515 | } | 2517 | } |
2516 | } | 2518 | } |
2517 | hton24(hdr->dlength, datain.length); | 2519 | hton24(hdr->dlength, datain.length); |
@@ -3013,10 +3015,10 @@ static int iscsit_send_status( | |||
3013 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; | 3015 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; |
3014 | if (cmd->se_cmd.se_cmd_flags & SCF_OVERFLOW_BIT) { | 3016 | if (cmd->se_cmd.se_cmd_flags & SCF_OVERFLOW_BIT) { |
3015 | hdr->flags |= ISCSI_FLAG_CMD_OVERFLOW; | 3017 | hdr->flags |= ISCSI_FLAG_CMD_OVERFLOW; |
3016 | hdr->residual_count = cpu_to_be32(cmd->residual_count); | 3018 | hdr->residual_count = cpu_to_be32(cmd->se_cmd.residual_count); |
3017 | } else if (cmd->se_cmd.se_cmd_flags & SCF_UNDERFLOW_BIT) { | 3019 | } else if (cmd->se_cmd.se_cmd_flags & SCF_UNDERFLOW_BIT) { |
3018 | hdr->flags |= ISCSI_FLAG_CMD_UNDERFLOW; | 3020 | hdr->flags |= ISCSI_FLAG_CMD_UNDERFLOW; |
3019 | hdr->residual_count = cpu_to_be32(cmd->residual_count); | 3021 | hdr->residual_count = cpu_to_be32(cmd->se_cmd.residual_count); |
3020 | } | 3022 | } |
3021 | hdr->response = cmd->iscsi_response; | 3023 | hdr->response = cmd->iscsi_response; |
3022 | hdr->cmd_status = cmd->se_cmd.scsi_status; | 3024 | hdr->cmd_status = cmd->se_cmd.scsi_status; |
diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h index 3723d90d5ae5..0e96a6b13174 100644 --- a/drivers/target/iscsi/iscsi_target_core.h +++ b/drivers/target/iscsi/iscsi_target_core.h | |||
@@ -398,7 +398,6 @@ struct iscsi_cmd { | |||
398 | u32 pdu_send_order; | 398 | u32 pdu_send_order; |
399 | /* Current struct iscsi_pdu in struct iscsi_cmd->pdu_list */ | 399 | /* Current struct iscsi_pdu in struct iscsi_cmd->pdu_list */ |
400 | u32 pdu_start; | 400 | u32 pdu_start; |
401 | u32 residual_count; | ||
402 | /* Next struct iscsi_seq to send in struct iscsi_cmd->seq_list */ | 401 | /* Next struct iscsi_seq to send in struct iscsi_cmd->seq_list */ |
403 | u32 seq_send_order; | 402 | u32 seq_send_order; |
404 | /* Number of struct iscsi_seq in struct iscsi_cmd->seq_list */ | 403 | /* Number of struct iscsi_seq in struct iscsi_cmd->seq_list */ |