Skip to content

Commit 4230e99

Browse files
pzakhaDelphix Engineering
authored andcommitted
DLPX-72513 cmd_kref leak prevents reestablishing connection for iSCSI initiator
When a LUN_RESET TMR is being processed and an iSCSI connection is closed at the same time, cmd_kref goes to -1 causing multiple issues, that culminate in several threads hanging, which prevents the closed iSCSI connection from being re-established.
1 parent ec904d9 commit 4230e99

File tree

1 file changed

+42
-6
lines changed

1 file changed

+42
-6
lines changed

drivers/target/iscsi/iscsi_target.c

Lines changed: 42 additions & 6 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-
list_del_init(&cmd->i_conn_node);
486+
list_del_init(&cmd->i_conn_node);
488487
spin_unlock_bh(&conn->cmd_lock);
489488

490489
__iscsit_free_cmd(cmd, true);
@@ -4070,7 +4069,8 @@ int iscsi_target_rx_thread(void *arg)
40704069

40714070
static void iscsit_release_commands_from_conn(struct iscsi_conn *conn)
40724071
{
4073-
LIST_HEAD(tmp_list);
4072+
LIST_HEAD(tmp_cmd_list);
4073+
LIST_HEAD(tmp_tmr_list);
40744074
struct iscsi_cmd *cmd = NULL, *cmd_tmp = NULL;
40754075
struct iscsi_session *sess = conn->sess;
40764076
/*
@@ -4079,9 +4079,9 @@ static void iscsit_release_commands_from_conn(struct iscsi_conn *conn)
40794079
* has been reset -> returned sleeping pre-handler state.
40804080
*/
40814081
spin_lock_bh(&conn->cmd_lock);
4082-
list_splice_init(&conn->conn_cmd_list, &tmp_list);
4082+
list_splice_init(&conn->conn_cmd_list, &tmp_cmd_list);
40834083

4084-
list_for_each_entry_safe(cmd, cmd_tmp, &tmp_list, i_conn_node) {
4084+
list_for_each_entry_safe(cmd, cmd_tmp, &tmp_cmd_list, i_conn_node) {
40854085
struct se_cmd *se_cmd = &cmd->se_cmd;
40864086

40874087
if (se_cmd->se_tfo != NULL) {
@@ -4099,11 +4099,47 @@ static void iscsit_release_commands_from_conn(struct iscsi_conn *conn)
40994099
}
41004100
spin_unlock_irq(&se_cmd->t_state_lock);
41014101
}
4102+
4103+
if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)
4104+
list_move_tail(&cmd->i_conn_node, &tmp_tmr_list);
41024105
}
41034106
spin_unlock_bh(&conn->cmd_lock);
41044107

4105-
list_for_each_entry_safe(cmd, cmd_tmp, &tmp_list, i_conn_node) {
4108+
/*
4109+
* We must wait for TMRs to be processed first. Any commands that were
4110+
* aborted by those TMRs will have been freed and removed from the
4111+
* tmp_cmd_list once we have finished traversing tmp_tmr_list.
4112+
*/
4113+
list_for_each_entry_safe(cmd, cmd_tmp, &tmp_tmr_list, i_conn_node) {
4114+
struct se_cmd *se_cmd = &cmd->se_cmd;
4115+
4116+
spin_lock_bh(&conn->cmd_lock);
41064117
list_del_init(&cmd->i_conn_node);
4118+
spin_unlock_bh(&conn->cmd_lock);
4119+
4120+
iscsit_increment_maxcmdsn(cmd, sess);
4121+
pr_debug("%s: freeing TMR icmd 0x%px cmd 0x%px\n",
4122+
__func__, cmd, se_cmd);
4123+
iscsit_free_cmd(cmd, true);
4124+
pr_debug("%s: TMR freed\n", __func__);
4125+
}
4126+
4127+
list_for_each_entry_safe(cmd, cmd_tmp, &tmp_cmd_list, i_conn_node) {
4128+
struct se_cmd *se_cmd = &cmd->se_cmd;
4129+
4130+
/*
4131+
* We shouldn't be freeing any aborted commands here. Those
4132+
* commands should be freed by iscsit_aborted_task, and the
4133+
* last reference will be released by target_put_cmd_and_wait,
4134+
* called from core_tmr_drain_tmr_list or core_tmr_abort_task.
4135+
*/
4136+
spin_lock_irq(&se_cmd->t_state_lock);
4137+
WARN_ON(se_cmd->transport_state & CMD_T_ABORTED);
4138+
spin_unlock_irq(&se_cmd->t_state_lock);
4139+
4140+
spin_lock_bh(&conn->cmd_lock);
4141+
list_del_init(&cmd->i_conn_node);
4142+
spin_unlock_bh(&conn->cmd_lock);
41074143

41084144
iscsit_increment_maxcmdsn(cmd, sess);
41094145
iscsit_free_cmd(cmd, true);

0 commit comments

Comments
 (0)