We don't want to set CMD_T_FABRIC_STOP on commands with CMD_T_ABORTED set, because we can end up with hangs where: 1. __transport_wait_for_tasks sets CMD_T_FABRIC_STOP but because CMD_T_ABORTED is set we hit the: if (fabric_stop && *aborted) return false; and wait in transport_generic_free_cmd's aborted wait on the free_compl. 2. transport_cmd_check_stop_to_fabric sees CMD_T_FABRIC_STOP set and does the complete_all call on the t_transport_stop_comp and returns. 3. We are now hung because we are waiting on the free_compl which won't happen because transport_cmd_check_stop_to_fabric completed the transport completion and didn't do the check_stop_free call which normally drops the refcount which is needed for the free_compl to get waken up. This patch has us either set the CMD_T_FABRIC_STOP bit and wait on t_transport_stop_comp, or set the CMD_T_ABORTED and wait on free_compl completion. Signed-off-by: Mike Christie <michael.christie@xxxxxxxxxx> --- drivers/target/target_core_transport.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 3c732b1b5389..1e42fd3ac8a8 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -3245,11 +3245,14 @@ __transport_wait_for_tasks(struct se_cmd *cmd, bool fabric_stop, { lockdep_assert_held(&cmd->t_state_lock); - if (fabric_stop) - cmd->transport_state |= CMD_T_FABRIC_STOP; - if (cmd->transport_state & CMD_T_ABORTED) *aborted = true; + /* + * We can be either CMD_T_FABRIC_STOP and wait below or CMD_T_ABORTED + * and return early below and wait in transport_generic_free_cmd. + */ + if (fabric_stop && !*aborted) + cmd->transport_state |= CMD_T_FABRIC_STOP; if (cmd->transport_state & CMD_T_TAS) *tas = true; -- 2.31.1