scsi: qla2xxx: Fix stale mem access on driver unload

On driver unload, 'remove_one' thread was allowed to advance, while session
cleanup still lag behind.  This patch ensures session deletion will finish
before remove_one can advance.

Link: https://lore.kernel.org/r/20190912180918.6436-4-hmadhani@marvell.com
Signed-off-by: Quinn Tran <qutran@marvell.com>
Signed-off-by: Himanshu Madhani <hmadhani@marvell.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Quinn Tran 2019-09-12 11:09:07 -07:00 committed by Martin K. Petersen
parent c3b6a1d397
commit fd5564ba54
2 changed files with 9 additions and 13 deletions

View File

@ -1118,6 +1118,7 @@ qla2x00_wait_for_sess_deletion(scsi_qla_host_t *vha)
qla2x00_mark_all_devices_lost(vha, 0); qla2x00_mark_all_devices_lost(vha, 0);
wait_event_timeout(vha->fcport_waitQ, test_fcport_count(vha), 10*HZ); wait_event_timeout(vha->fcport_waitQ, test_fcport_count(vha), 10*HZ);
flush_workqueue(vha->hw->wq);
} }
/* /*

View File

@ -953,7 +953,7 @@ void qlt_free_session_done(struct work_struct *work)
struct qla_hw_data *ha = vha->hw; struct qla_hw_data *ha = vha->hw;
unsigned long flags; unsigned long flags;
bool logout_started = false; bool logout_started = false;
scsi_qla_host_t *base_vha; scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
struct qlt_plogi_ack_t *own = struct qlt_plogi_ack_t *own =
sess->plogi_link[QLT_PLOGI_LINK_SAME_WWN]; sess->plogi_link[QLT_PLOGI_LINK_SAME_WWN];
@ -1105,6 +1105,7 @@ void qlt_free_session_done(struct work_struct *work)
} }
spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
sess->free_pending = 0;
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf001, ql_dbg(ql_dbg_tgt_mgt, vha, 0xf001,
"Unregistration of sess %p %8phC finished fcp_cnt %d\n", "Unregistration of sess %p %8phC finished fcp_cnt %d\n",
@ -1113,17 +1114,8 @@ void qlt_free_session_done(struct work_struct *work)
if (tgt && (tgt->sess_count == 0)) if (tgt && (tgt->sess_count == 0))
wake_up_all(&tgt->waitQ); wake_up_all(&tgt->waitQ);
if (vha->fcport_count == 0) if (!test_bit(PFLG_DRIVER_REMOVING, &base_vha->pci_flags) &&
wake_up_all(&vha->fcport_waitQ); (!tgt || !tgt->tgt_stop) && !LOOP_TRANSITION(vha)) {
base_vha = pci_get_drvdata(ha->pdev);
sess->free_pending = 0;
if (test_bit(PFLG_DRIVER_REMOVING, &base_vha->pci_flags))
return;
if ((!tgt || !tgt->tgt_stop) && !LOOP_TRANSITION(vha)) {
switch (vha->host->active_mode) { switch (vha->host->active_mode) {
case MODE_INITIATOR: case MODE_INITIATOR:
case MODE_DUAL: case MODE_DUAL:
@ -1136,6 +1128,9 @@ void qlt_free_session_done(struct work_struct *work)
break; break;
} }
} }
if (vha->fcport_count == 0)
wake_up_all(&vha->fcport_waitQ);
} }
/* ha->tgt.sess_lock supposed to be held on entry */ /* ha->tgt.sess_lock supposed to be held on entry */
@ -1165,7 +1160,7 @@ void qlt_unreg_sess(struct fc_port *sess)
sess->last_login_gen = sess->login_gen; sess->last_login_gen = sess->login_gen;
INIT_WORK(&sess->free_work, qlt_free_session_done); INIT_WORK(&sess->free_work, qlt_free_session_done);
schedule_work(&sess->free_work); queue_work(sess->vha->hw->wq, &sess->free_work);
} }
EXPORT_SYMBOL(qlt_unreg_sess); EXPORT_SYMBOL(qlt_unreg_sess);