aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/target
diff options
context:
space:
mode:
authorNicholas Bellinger <nab@linux-iscsi.org>2016-12-07 01:45:46 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-02-14 18:25:36 -0500
commit88e865c5d813e400ad0b135c39fe5842e95df6f4 (patch)
treec73e3ada46ef733f497175a2da4ff7ffd2f35c05 /drivers/target
parent4b99bb2e3643d2be438393b95a0572593c5205cf (diff)
target: Fix early transport_generic_handle_tmr abort scenario
commit c54eeffbe9338fa982dc853d816fda9202a13b5a upstream. This patch fixes a bug where incoming task management requests can be explicitly aborted during an active LUN_RESET, but who's struct work_struct are canceled in-flight before execution. This occurs when core_tmr_drain_tmr_list() invokes cancel_work_sync() for the incoming se_tmr_req->task_cmd->work, resulting in cmd->work for target_tmr_work() never getting invoked and the aborted TMR waiting indefinately within transport_wait_for_tasks(). To address this case, perform a CMD_T_ABORTED check early in transport_generic_handle_tmr(), and invoke the normal path via transport_cmd_check_stop_to_fabric() to complete any TMR kthreads blocked waiting for CMD_T_STOP in transport_wait_for_tasks(). Also, move the TRANSPORT_ISTATE_PROCESSING assignment earlier into transport_generic_handle_tmr() so the existing check in core_tmr_drain_tmr_list() avoids attempting abort the incoming se_tmr_req->task_cmd->work if it has already been queued into se_device->tmr_wq. Reported-by: Rob Millner <rlm@daterainc.com> Tested-by: Rob Millner <rlm@daterainc.com> Cc: Rob Millner <rlm@daterainc.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/target')
-rw-r--r--drivers/target/target_core_transport.c17
1 files changed, 15 insertions, 2 deletions
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 7dfefd66df93..f5aed8901d70 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -3086,7 +3086,6 @@ static void target_tmr_work(struct work_struct *work)
3086 spin_unlock_irqrestore(&cmd->t_state_lock, flags); 3086 spin_unlock_irqrestore(&cmd->t_state_lock, flags);
3087 goto check_stop; 3087 goto check_stop;
3088 } 3088 }
3089 cmd->t_state = TRANSPORT_ISTATE_PROCESSING;
3090 spin_unlock_irqrestore(&cmd->t_state_lock, flags); 3089 spin_unlock_irqrestore(&cmd->t_state_lock, flags);
3091 3090
3092 cmd->se_tfo->queue_tm_rsp(cmd); 3091 cmd->se_tfo->queue_tm_rsp(cmd);
@@ -3099,11 +3098,25 @@ int transport_generic_handle_tmr(
3099 struct se_cmd *cmd) 3098 struct se_cmd *cmd)
3100{ 3099{
3101 unsigned long flags; 3100 unsigned long flags;
3101 bool aborted = false;
3102 3102
3103 spin_lock_irqsave(&cmd->t_state_lock, flags); 3103 spin_lock_irqsave(&cmd->t_state_lock, flags);
3104 cmd->transport_state |= CMD_T_ACTIVE; 3104 if (cmd->transport_state & CMD_T_ABORTED) {
3105 aborted = true;
3106 } else {
3107 cmd->t_state = TRANSPORT_ISTATE_PROCESSING;
3108 cmd->transport_state |= CMD_T_ACTIVE;
3109 }
3105 spin_unlock_irqrestore(&cmd->t_state_lock, flags); 3110 spin_unlock_irqrestore(&cmd->t_state_lock, flags);
3106 3111
3112 if (aborted) {
3113 pr_warn_ratelimited("handle_tmr caught CMD_T_ABORTED TMR %d"
3114 "ref_tag: %llu tag: %llu\n", cmd->se_tmr_req->function,
3115 cmd->se_tmr_req->ref_task_tag, cmd->tag);
3116 transport_cmd_check_stop_to_fabric(cmd);
3117 return 0;
3118 }
3119
3107 INIT_WORK(&cmd->work, target_tmr_work); 3120 INIT_WORK(&cmd->work, target_tmr_work);
3108 queue_work(cmd->se_dev->tmr_wq, &cmd->work); 3121 queue_work(cmd->se_dev->tmr_wq, &cmd->work);
3109 return 0; 3122 return 0;