Commit fd5564ba authored by Quinn Tran's avatar Quinn Tran Committed by Martin K. Petersen
Browse files

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: default avatarQuinn Tran <qutran@marvell.com>
Signed-off-by: default avatarHimanshu Madhani <hmadhani@marvell.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent c3b6a1d3
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1118,6 +1118,7 @@ qla2x00_wait_for_sess_deletion(scsi_qla_host_t *vha)
	qla2x00_mark_all_devices_lost(vha, 0);

	wait_event_timeout(vha->fcport_waitQ, test_fcport_count(vha), 10*HZ);
	flush_workqueue(vha->hw->wq);
}

/*
+8 −13
Original line number Diff line number Diff line
@@ -953,7 +953,7 @@ void qlt_free_session_done(struct work_struct *work)
	struct qla_hw_data *ha = vha->hw;
	unsigned long flags;
	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 =
		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);
	sess->free_pending = 0;

	ql_dbg(ql_dbg_tgt_mgt, vha, 0xf001,
	    "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))
		wake_up_all(&tgt->waitQ);

	if (vha->fcport_count == 0)
		wake_up_all(&vha->fcport_waitQ);

	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)) {
	if (!test_bit(PFLG_DRIVER_REMOVING, &base_vha->pci_flags) &&
	    (!tgt || !tgt->tgt_stop) && !LOOP_TRANSITION(vha)) {
		switch (vha->host->active_mode) {
		case MODE_INITIATOR:
		case MODE_DUAL:
@@ -1136,6 +1128,9 @@ void qlt_free_session_done(struct work_struct *work)
			break;
		}
	}

	if (vha->fcport_count == 0)
		wake_up_all(&vha->fcport_waitQ);
}

/* 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;

	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);