Skip to content

Commit f361993

Browse files
mikechristiemartinkpetersen
authored andcommitted
scsi: target: iscsi: Fix cmd abort fabric stop race
Maurizio found a race where the abort and cmd stop paths can race as follows: 1. thread1 runs iscsit_release_commands_from_conn and sets CMD_T_FABRIC_STOP. 2. thread2 runs iscsit_aborted_task and then does __iscsit_free_cmd. It then returns from the aborted_task callout and we finish target_handle_abort and do: target_handle_abort -> transport_cmd_check_stop_to_fabric -> lio_check_stop_free -> target_put_sess_cmd The cmd is now freed. 3. thread1 now finishes iscsit_release_commands_from_conn and runs iscsit_free_cmd while accessing a command we just released. In __target_check_io_state we check for CMD_T_FABRIC_STOP and set the CMD_T_ABORTED if the driver is not cleaning up the cmd because of a session shutdown. However, iscsit_release_commands_from_conn only sets the CMD_T_FABRIC_STOP and does not check to see if the abort path has claimed completion ownership of the command. This adds a check in iscsit_release_commands_from_conn so only the abort or fabric stop path cleanup the command. Link: https://lore.kernel.org/r/[email protected] Reported-by: Maurizio Lombardi <[email protected]> Reviewed-by: Maurizio Lombardi <[email protected]> Signed-off-by: Mike Christie <[email protected]> Signed-off-by: Martin K. Petersen <[email protected]>
1 parent fe0a8a9 commit f361993

File tree

1 file changed

+13
-4
lines changed

1 file changed

+13
-4
lines changed

drivers/target/iscsi/iscsi_target.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -483,8 +483,7 @@ EXPORT_SYMBOL(iscsit_queue_rsp);
483483
void iscsit_aborted_task(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
484484
{
485485
spin_lock_bh(&conn->cmd_lock);
486-
if (!list_empty(&cmd->i_conn_node) &&
487-
!(cmd->se_cmd.transport_state & CMD_T_FABRIC_STOP))
486+
if (!list_empty(&cmd->i_conn_node))
488487
list_del_init(&cmd->i_conn_node);
489488
spin_unlock_bh(&conn->cmd_lock);
490489

@@ -4083,12 +4082,22 @@ static void iscsit_release_commands_from_conn(struct iscsi_conn *conn)
40834082
spin_lock_bh(&conn->cmd_lock);
40844083
list_splice_init(&conn->conn_cmd_list, &tmp_list);
40854084

4086-
list_for_each_entry(cmd, &tmp_list, i_conn_node) {
4085+
list_for_each_entry_safe(cmd, cmd_tmp, &tmp_list, i_conn_node) {
40874086
struct se_cmd *se_cmd = &cmd->se_cmd;
40884087

40894088
if (se_cmd->se_tfo != NULL) {
40904089
spin_lock_irq(&se_cmd->t_state_lock);
4091-
se_cmd->transport_state |= CMD_T_FABRIC_STOP;
4090+
if (se_cmd->transport_state & CMD_T_ABORTED) {
4091+
/*
4092+
* LIO's abort path owns the cleanup for this,
4093+
* so put it back on the list and let
4094+
* aborted_task handle it.
4095+
*/
4096+
list_move_tail(&cmd->i_conn_node,
4097+
&conn->conn_cmd_list);
4098+
} else {
4099+
se_cmd->transport_state |= CMD_T_FABRIC_STOP;
4100+
}
40924101
spin_unlock_irq(&se_cmd->t_state_lock);
40934102
}
40944103
}

0 commit comments

Comments
 (0)