Commit 37e1b6b5 authored by Nicholas Bellinger's avatar Nicholas Bellinger Committed by Ben Hutchings

target: Fix early transport_generic_handle_tmr abort scenario

commit c54eeffb 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: default avatarRob Millner <rlm@daterainc.com>
Tested-by: default avatarRob Millner <rlm@daterainc.com>
Cc: Rob Millner <rlm@daterainc.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
[bwh: Backported to 3.16:
 - Tags are 32-bit; print them with %u
 - Command tag must be looked up with get_task_tag op]
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
parent b5d330a1
......@@ -3093,7 +3093,6 @@ static void target_tmr_work(struct work_struct *work)
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
goto check_stop;
}
cmd->t_state = TRANSPORT_ISTATE_PROCESSING;
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
cmd->se_tfo->queue_tm_rsp(cmd);
......@@ -3106,11 +3105,25 @@ int transport_generic_handle_tmr(
struct se_cmd *cmd)
{
unsigned long flags;
bool aborted = false;
spin_lock_irqsave(&cmd->t_state_lock, flags);
cmd->transport_state |= CMD_T_ACTIVE;
if (cmd->transport_state & CMD_T_ABORTED) {
aborted = true;
} else {
cmd->t_state = TRANSPORT_ISTATE_PROCESSING;
cmd->transport_state |= CMD_T_ACTIVE;
}
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
if (aborted) {
pr_warn_ratelimited("handle_tmr caught CMD_T_ABORTED TMR %d"
"ref_tag: %u tag: %u\n", cmd->se_tmr_req->function,
cmd->se_tmr_req->ref_task_tag, cmd->se_tfo->get_task_tag(cmd));
transport_cmd_check_stop_to_fabric(cmd);
return 0;
}
INIT_WORK(&cmd->work, target_tmr_work);
queue_work(cmd->se_dev->tmr_wq, &cmd->work);
return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment