summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoland Dreier <roland@purestorage.com>2013-01-03 00:47:57 +0400
committerNicholas Bellinger <nab@linux-iscsi.org>2013-01-11 09:00:07 +0400
commite627c615553a356f6f70215ebb3933c6e057553e (patch)
tree34f476cfe326bdf5f2b3027e7c09035c2ba2bc21
parentedec8dfefa1f372b2dd8197da555352e76a10c03 (diff)
downloadlinux-e627c615553a356f6f70215ebb3933c6e057553e.tar.xz
target: Fix missing CMD_T_ACTIVE bit regression for pending WRITEs
This patch fixes a regression bug introduced during v3.6.x code with the following commit to drop transport_add_cmd_to_queue(), which originally re-set CMD_T_ACTIVE during pending WRITE I/O submission: commit af8772926f019b7bddd7477b8de5f3b0f12bad21 Author: Christoph Hellwig <hch@infradead.org> Date: Sun Jul 8 15:58:49 2012 -0400 target: replace the processing thread with a TMR work queue The following sequence happens for write commands (or any other commands with a data out phase): - The transport calls target_submit_cmd(), which sets CMD_T_ACTIVE in cmd->transport_state and sets cmd->t_state to TRANSPORT_NEW_CMD. - Things go on transport_generic_new_cmd(), which notices that the command needs to transfer data, so it sets cmd->t_state to TRANSPORT_WRITE_PENDING and calls transport_cmd_check_stop(). - transport_cmd_check_stop() clears CMD_T_ACTIVE in cmd->transport_state and returns in the normal case. - Then we continue on to call ->se_tfo->write_pending(). - The data comes back from the initiator, and the transport calls target_execute_cmd(), which sets cmd->t_state to TRANSPORT_PROCESSING and calls into the backend to actually write the data. At this point, the backend might take a long time to complete the command, since it has to do real IO. If an abort request comes in for this command at this point, it will not wait for the command to finish since CMD_T_ACTIVE is not set. Then when the command does finally finish, we blow up with use-after-free. Avoid this by setting CMD_T_ACTIVE in target_execute_cmd() so that transport_wait_for_tasks() waits for the command to finish executing. This matches the behavior from before commit 1389533ef944 ("target: remove transport_generic_handle_data"), when data was signaled via transport_generic_handle_data(), which set CMD_T_ACTIVE because it called transport_add_cmd_to_queue(). Signed-off-by: Roland Dreier <roland@purestorage.com> Reported-by: Martin Svec <martin.svec@zoner.cz> Cc: Christoph Hellwig <hch@lst.de> Cc: stable@vger.kernel.org Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r--drivers/target/target_core_transport.c1
1 files changed, 1 insertions, 0 deletions
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 104bf3b45a01..1775bda6c43c 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -1688,6 +1688,7 @@ void target_execute_cmd(struct se_cmd *cmd)
}
cmd->t_state = TRANSPORT_PROCESSING;
+ cmd->transport_state |= CMD_T_ACTIVE;
spin_unlock_irq(&cmd->t_state_lock);
if (!target_handle_task_attr(cmd))