qla2xxx: Check + fail when npiv_vports_inuse exists in shutdown
This patch adds an check to qlt_stop_phase1() to avoid shutdown when the base_vha contains a non-zero fc_host->npiv_vports_inuse count. This includes holding qla_tgt_mutex in qlt_stop_phase1() between the fc_host->npiv_vports_inuse check + setting of tgt->tgt_stop to avoid a possible race between qlt_lport_register() -> tcm_qla2xxx -> tcm_qla2xxx_lport_register_npiv_cb() calling fc_vport_create(). Cc: Sawan Chandak <sawan.chandak@qlogic.com> Cc: Quinn Tran <quinn.tran@qlogic.com> Cc: Saurav Kashyap <saurav.kashyap@qlogic.com> Cc: Giridhar Malavali <giridhar.malavali@qlogic.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
This commit is contained in:
parent
ddb95145a3
commit
3c231bdae1
|
@ -790,17 +790,32 @@ static inline int test_tgt_sess_count(struct qla_tgt *tgt)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called by tcm_qla2xxx configfs code */
|
/* Called by tcm_qla2xxx configfs code */
|
||||||
void qlt_stop_phase1(struct qla_tgt *tgt)
|
int qlt_stop_phase1(struct qla_tgt *tgt)
|
||||||
{
|
{
|
||||||
struct scsi_qla_host *vha = tgt->vha;
|
struct scsi_qla_host *vha = tgt->vha;
|
||||||
struct qla_hw_data *ha = tgt->ha;
|
struct qla_hw_data *ha = tgt->ha;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
|
mutex_lock(&qla_tgt_mutex);
|
||||||
|
if (!vha->fc_vport) {
|
||||||
|
struct Scsi_Host *sh = vha->host;
|
||||||
|
struct fc_host_attrs *fc_host = shost_to_fc_host(sh);
|
||||||
|
bool npiv_vports;
|
||||||
|
|
||||||
|
spin_lock_irqsave(sh->host_lock, flags);
|
||||||
|
npiv_vports = (fc_host->npiv_vports_inuse);
|
||||||
|
spin_unlock_irqrestore(sh->host_lock, flags);
|
||||||
|
|
||||||
|
if (npiv_vports) {
|
||||||
|
mutex_unlock(&qla_tgt_mutex);
|
||||||
|
return -EPERM;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (tgt->tgt_stop || tgt->tgt_stopped) {
|
if (tgt->tgt_stop || tgt->tgt_stopped) {
|
||||||
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04e,
|
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04e,
|
||||||
"Already in tgt->tgt_stop or tgt_stopped state\n");
|
"Already in tgt->tgt_stop or tgt_stopped state\n");
|
||||||
dump_stack();
|
mutex_unlock(&qla_tgt_mutex);
|
||||||
return;
|
return -EPERM;
|
||||||
}
|
}
|
||||||
|
|
||||||
ql_dbg(ql_dbg_tgt, vha, 0xe003, "Stopping target for host %ld(%p)\n",
|
ql_dbg(ql_dbg_tgt, vha, 0xe003, "Stopping target for host %ld(%p)\n",
|
||||||
|
@ -815,6 +830,7 @@ void qlt_stop_phase1(struct qla_tgt *tgt)
|
||||||
qlt_clear_tgt_db(tgt, true);
|
qlt_clear_tgt_db(tgt, true);
|
||||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||||
mutex_unlock(&vha->vha_tgt.tgt_mutex);
|
mutex_unlock(&vha->vha_tgt.tgt_mutex);
|
||||||
|
mutex_unlock(&qla_tgt_mutex);
|
||||||
|
|
||||||
flush_delayed_work(&tgt->sess_del_work);
|
flush_delayed_work(&tgt->sess_del_work);
|
||||||
|
|
||||||
|
@ -841,6 +857,7 @@ void qlt_stop_phase1(struct qla_tgt *tgt)
|
||||||
|
|
||||||
/* Wait for sessions to clear out (just in case) */
|
/* Wait for sessions to clear out (just in case) */
|
||||||
wait_event(tgt->waitQ, test_tgt_sess_count(tgt));
|
wait_event(tgt->waitQ, test_tgt_sess_count(tgt));
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(qlt_stop_phase1);
|
EXPORT_SYMBOL(qlt_stop_phase1);
|
||||||
|
|
||||||
|
|
|
@ -1001,7 +1001,7 @@ extern void qlt_modify_vp_config(struct scsi_qla_host *,
|
||||||
extern void qlt_probe_one_stage1(struct scsi_qla_host *, struct qla_hw_data *);
|
extern void qlt_probe_one_stage1(struct scsi_qla_host *, struct qla_hw_data *);
|
||||||
extern int qlt_mem_alloc(struct qla_hw_data *);
|
extern int qlt_mem_alloc(struct qla_hw_data *);
|
||||||
extern void qlt_mem_free(struct qla_hw_data *);
|
extern void qlt_mem_free(struct qla_hw_data *);
|
||||||
extern void qlt_stop_phase1(struct qla_tgt *);
|
extern int qlt_stop_phase1(struct qla_tgt *);
|
||||||
extern void qlt_stop_phase2(struct qla_tgt *);
|
extern void qlt_stop_phase2(struct qla_tgt *);
|
||||||
extern irqreturn_t qla83xx_msix_atio_q(int, void *);
|
extern irqreturn_t qla83xx_msix_atio_q(int, void *);
|
||||||
extern void qlt_83xx_iospace_config(struct qla_hw_data *);
|
extern void qlt_83xx_iospace_config(struct qla_hw_data *);
|
||||||
|
|
Loading…
Reference in New Issue