Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S937450AbdCJNmg (ORCPT ); Fri, 10 Mar 2017 08:42:36 -0500 Received: from shadbolt.e.decadent.org.uk ([88.96.1.126]:43564 "EHLO shadbolt.e.decadent.org.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S934306AbdCJLwZ (ORCPT ); Fri, 10 Mar 2017 06:52:25 -0500 Content-Type: text/plain; charset="UTF-8" Content-Disposition: inline Content-Transfer-Encoding: 8bit MIME-Version: 1.0 From: Ben Hutchings To: linux-kernel@vger.kernel.org, stable@vger.kernel.org CC: akpm@linux-foundation.org, "Nicholas Bellinger" , "Rob Millner" , "Christoph Hellwig" Date: Fri, 10 Mar 2017 11:46:23 +0000 Message-ID: X-Mailer: LinuxStableQueue (scripts by bwh) Subject: [PATCH 3.16 286/370] target: Fix early transport_generic_handle_tmr abort scenario In-Reply-To: X-SA-Exim-Connect-IP: 82.70.136.246 X-SA-Exim-Mail-From: ben@decadent.org.uk X-SA-Exim-Scanned: No (on shadbolt.decadent.org.uk); SAEximRunCond expanded to false Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 2864 Lines: 78 3.16.42-rc1 review patch. If anyone has any objections, please let me know. ------------------ From: Nicholas Bellinger 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 Tested-by: Rob Millner Cc: Rob Millner Reviewed-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger [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: Ben Hutchings --- drivers/target/target_core_transport.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -3093,7 +3093,6 @@ static void target_tmr_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;