Commit 6dfe4344 authored by Quinn Tran's avatar Quinn Tran Committed by Martin K. Petersen

scsi: qla2xxx: Fix deletion race condition

System crash when using debug kernel due to link list corruption. The cause
of the link list corruption is due to session deletion was allowed to queue
up twice.  Here's the internal trace that show the same port was allowed to
double queue for deletion on different cpu.

20808683956 015 qla2xxx [0000:13:00.1]-e801:4: Scheduling sess ffff93ebf9306800 for deletion 50:06:0e:80:12:48:ff:50 fc4_type 1
20808683957 027 qla2xxx [0000:13:00.1]-e801:4: Scheduling sess ffff93ebf9306800 for deletion 50:06:0e:80:12:48:ff:50 fc4_type 1

Move the clearing/setting of deleted flag lock.

Cc: stable@vger.kernel.org
Fixes: 726b8548 ("qla2xxx: Add framework for async fabric discovery")
Signed-off-by: default avatarQuinn Tran <qutran@marvell.com>
Signed-off-by: default avatarNilesh Javali <njavali@marvell.com>
Link: https://lore.kernel.org/r/20230714070104.40052-2-njavali@marvell.comReviewed-by: default avatarHimanshu Madhani <himanshu.madhani@oracle.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 06c2afb8
...@@ -508,6 +508,7 @@ static ...@@ -508,6 +508,7 @@ static
void qla24xx_handle_adisc_event(scsi_qla_host_t *vha, struct event_arg *ea) void qla24xx_handle_adisc_event(scsi_qla_host_t *vha, struct event_arg *ea)
{ {
struct fc_port *fcport = ea->fcport; struct fc_port *fcport = ea->fcport;
unsigned long flags;
ql_dbg(ql_dbg_disc, vha, 0x20d2, ql_dbg(ql_dbg_disc, vha, 0x20d2,
"%s %8phC DS %d LS %d rc %d login %d|%d rscn %d|%d lid %d\n", "%s %8phC DS %d LS %d rc %d login %d|%d rscn %d|%d lid %d\n",
...@@ -522,9 +523,15 @@ void qla24xx_handle_adisc_event(scsi_qla_host_t *vha, struct event_arg *ea) ...@@ -522,9 +523,15 @@ void qla24xx_handle_adisc_event(scsi_qla_host_t *vha, struct event_arg *ea)
ql_dbg(ql_dbg_disc, vha, 0x2066, ql_dbg(ql_dbg_disc, vha, 0x2066,
"%s %8phC: adisc fail: post delete\n", "%s %8phC: adisc fail: post delete\n",
__func__, ea->fcport->port_name); __func__, ea->fcport->port_name);
spin_lock_irqsave(&vha->work_lock, flags);
/* deleted = 0 & logout_on_delete = force fw cleanup */ /* deleted = 0 & logout_on_delete = force fw cleanup */
fcport->deleted = 0; if (fcport->deleted == QLA_SESS_DELETED)
fcport->deleted = 0;
fcport->logout_on_delete = 1; fcport->logout_on_delete = 1;
spin_unlock_irqrestore(&vha->work_lock, flags);
qlt_schedule_sess_for_deletion(ea->fcport); qlt_schedule_sess_for_deletion(ea->fcport);
return; return;
} }
...@@ -1446,7 +1453,6 @@ void __qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea) ...@@ -1446,7 +1453,6 @@ void __qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea)
spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
ea->fcport->login_gen++; ea->fcport->login_gen++;
ea->fcport->deleted = 0;
ea->fcport->logout_on_delete = 1; ea->fcport->logout_on_delete = 1;
if (!ea->fcport->login_succ && !IS_SW_RESV_ADDR(ea->fcport->d_id)) { if (!ea->fcport->login_succ && !IS_SW_RESV_ADDR(ea->fcport->d_id)) {
...@@ -6090,6 +6096,8 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport) ...@@ -6090,6 +6096,8 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport)
void void
qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
{ {
unsigned long flags;
if (IS_SW_RESV_ADDR(fcport->d_id)) if (IS_SW_RESV_ADDR(fcport->d_id))
return; return;
...@@ -6099,7 +6107,11 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) ...@@ -6099,7 +6107,11 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
qla2x00_set_fcport_disc_state(fcport, DSC_UPD_FCPORT); qla2x00_set_fcport_disc_state(fcport, DSC_UPD_FCPORT);
fcport->login_retry = vha->hw->login_retry_count; fcport->login_retry = vha->hw->login_retry_count;
fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT); fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT);
spin_lock_irqsave(&vha->work_lock, flags);
fcport->deleted = 0; fcport->deleted = 0;
spin_unlock_irqrestore(&vha->work_lock, flags);
if (vha->hw->current_topology == ISP_CFG_NL) if (vha->hw->current_topology == ISP_CFG_NL)
fcport->logout_on_delete = 0; fcport->logout_on_delete = 0;
else else
......
...@@ -1068,10 +1068,6 @@ void qlt_free_session_done(struct work_struct *work) ...@@ -1068,10 +1068,6 @@ void qlt_free_session_done(struct work_struct *work)
(struct imm_ntfy_from_isp *)sess->iocb, SRB_NACK_LOGO); (struct imm_ntfy_from_isp *)sess->iocb, SRB_NACK_LOGO);
} }
spin_lock_irqsave(&vha->work_lock, flags);
sess->flags &= ~FCF_ASYNC_SENT;
spin_unlock_irqrestore(&vha->work_lock, flags);
spin_lock_irqsave(&ha->tgt.sess_lock, flags); spin_lock_irqsave(&ha->tgt.sess_lock, flags);
if (sess->se_sess) { if (sess->se_sess) {
sess->se_sess = NULL; sess->se_sess = NULL;
...@@ -1081,7 +1077,6 @@ void qlt_free_session_done(struct work_struct *work) ...@@ -1081,7 +1077,6 @@ void qlt_free_session_done(struct work_struct *work)
qla2x00_set_fcport_disc_state(sess, DSC_DELETED); qla2x00_set_fcport_disc_state(sess, DSC_DELETED);
sess->fw_login_state = DSC_LS_PORT_UNAVAIL; sess->fw_login_state = DSC_LS_PORT_UNAVAIL;
sess->deleted = QLA_SESS_DELETED;
if (sess->login_succ && !IS_SW_RESV_ADDR(sess->d_id)) { if (sess->login_succ && !IS_SW_RESV_ADDR(sess->d_id)) {
vha->fcport_count--; vha->fcport_count--;
...@@ -1133,10 +1128,15 @@ void qlt_free_session_done(struct work_struct *work) ...@@ -1133,10 +1128,15 @@ void qlt_free_session_done(struct work_struct *work)
sess->explicit_logout = 0; sess->explicit_logout = 0;
spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
sess->free_pending = 0;
qla2x00_dfs_remove_rport(vha, sess); qla2x00_dfs_remove_rport(vha, sess);
spin_lock_irqsave(&vha->work_lock, flags);
sess->flags &= ~FCF_ASYNC_SENT;
sess->deleted = QLA_SESS_DELETED;
sess->free_pending = 0;
spin_unlock_irqrestore(&vha->work_lock, flags);
ql_dbg(ql_dbg_disc, vha, 0xf001, ql_dbg(ql_dbg_disc, vha, 0xf001,
"Unregistration of sess %p %8phC finished fcp_cnt %d\n", "Unregistration of sess %p %8phC finished fcp_cnt %d\n",
sess, sess->port_name, vha->fcport_count); sess, sess->port_name, vha->fcport_count);
...@@ -1185,12 +1185,12 @@ void qlt_unreg_sess(struct fc_port *sess) ...@@ -1185,12 +1185,12 @@ void qlt_unreg_sess(struct fc_port *sess)
* management from being sent. * management from being sent.
*/ */
sess->flags |= FCF_ASYNC_SENT; sess->flags |= FCF_ASYNC_SENT;
sess->deleted = QLA_SESS_DELETION_IN_PROGRESS;
spin_unlock_irqrestore(&sess->vha->work_lock, flags); spin_unlock_irqrestore(&sess->vha->work_lock, flags);
if (sess->se_sess) if (sess->se_sess)
vha->hw->tgt.tgt_ops->clear_nacl_from_fcport_map(sess); vha->hw->tgt.tgt_ops->clear_nacl_from_fcport_map(sess);
sess->deleted = QLA_SESS_DELETION_IN_PROGRESS;
qla2x00_set_fcport_disc_state(sess, DSC_DELETE_PEND); qla2x00_set_fcport_disc_state(sess, DSC_DELETE_PEND);
sess->last_rscn_gen = sess->rscn_gen; sess->last_rscn_gen = sess->rscn_gen;
sess->last_login_gen = sess->login_gen; sess->last_login_gen = sess->login_gen;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment