Skip to content

Commit

Permalink
Merge pull request #1 from pzakha/dlpx-72513-aws
Browse files Browse the repository at this point in the history
DLPX-72513 cmd_kref leak prevents reestablishing connection for iSCSI initiator
  • Loading branch information
pzakha authored Feb 3, 2021
2 parents 691510c + 048b332 commit a48be38
Showing 1 changed file with 42 additions and 7 deletions.
49 changes: 42 additions & 7 deletions drivers/target/iscsi/iscsi_target.c
Original file line number Diff line number Diff line change
Expand Up @@ -483,9 +483,7 @@ EXPORT_SYMBOL(iscsit_queue_rsp);
void iscsit_aborted_task(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
{
spin_lock_bh(&conn->cmd_lock);
if (!list_empty(&cmd->i_conn_node) &&
!(cmd->se_cmd.transport_state & CMD_T_FABRIC_STOP))
list_del_init(&cmd->i_conn_node);
list_del_init(&cmd->i_conn_node);
spin_unlock_bh(&conn->cmd_lock);

__iscsit_free_cmd(cmd, true);
Expand Down Expand Up @@ -4071,7 +4069,8 @@ int iscsi_target_rx_thread(void *arg)

static void iscsit_release_commands_from_conn(struct iscsi_conn *conn)
{
LIST_HEAD(tmp_list);
LIST_HEAD(tmp_cmd_list);
LIST_HEAD(tmp_tmr_list);
struct iscsi_cmd *cmd = NULL, *cmd_tmp = NULL;
struct iscsi_session *sess = conn->sess;
/*
Expand All @@ -4080,21 +4079,57 @@ static void iscsit_release_commands_from_conn(struct iscsi_conn *conn)
* has been reset -> returned sleeping pre-handler state.
*/
spin_lock_bh(&conn->cmd_lock);
list_splice_init(&conn->conn_cmd_list, &tmp_list);
list_splice_init(&conn->conn_cmd_list, &tmp_cmd_list);

list_for_each_entry(cmd, &tmp_list, i_conn_node) {
list_for_each_entry_safe(cmd, cmd_tmp, &tmp_cmd_list, i_conn_node) {
struct se_cmd *se_cmd = &cmd->se_cmd;

if (se_cmd->se_tfo != NULL) {
spin_lock_irq(&se_cmd->t_state_lock);
se_cmd->transport_state |= CMD_T_FABRIC_STOP;
spin_unlock_irq(&se_cmd->t_state_lock);
}

if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)
list_move_tail(&cmd->i_conn_node, &tmp_tmr_list);
}
spin_unlock_bh(&conn->cmd_lock);

list_for_each_entry_safe(cmd, cmd_tmp, &tmp_list, i_conn_node) {
/*
* We must wait for TMRs to be processed first. Any commands that were
* aborted by those TMRs will have been freed and removed from the
* tmp_cmd_list once we have finished traversing tmp_tmr_list.
*/
list_for_each_entry_safe(cmd, cmd_tmp, &tmp_tmr_list, i_conn_node) {
struct se_cmd *se_cmd = &cmd->se_cmd;

spin_lock_bh(&conn->cmd_lock);
list_del_init(&cmd->i_conn_node);
spin_unlock_bh(&conn->cmd_lock);

iscsit_increment_maxcmdsn(cmd, sess);
pr_debug("%s: freeing TMR icmd 0x%px cmd 0x%px\n",
__func__, cmd, se_cmd);
iscsit_free_cmd(cmd, true);
pr_debug("%s: TMR freed\n", __func__);
}

list_for_each_entry_safe(cmd, cmd_tmp, &tmp_cmd_list, i_conn_node) {
struct se_cmd *se_cmd = &cmd->se_cmd;

/*
* We shouldn't be freeing any aborted commands here. Those
* commands should be freed by iscsit_aborted_task, and the
* last reference will be released by target_put_cmd_and_wait,
* called from core_tmr_drain_tmr_list or core_tmr_abort_task.
*/
spin_lock_irq(&se_cmd->t_state_lock);
WARN_ON(se_cmd->transport_state & CMD_T_ABORTED);
spin_unlock_irq(&se_cmd->t_state_lock);

spin_lock_bh(&conn->cmd_lock);
list_del_init(&cmd->i_conn_node);
spin_unlock_bh(&conn->cmd_lock);

iscsit_increment_maxcmdsn(cmd, sess);
iscsit_free_cmd(cmd, true);
Expand Down

0 comments on commit a48be38

Please sign in to comment.