mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-11-01 17:08:10 +00:00
[SCSI] libfc: fix a circular locking warning during sending RRQ
Currently the fc_exch_rrq is called with fc_exch's ex_lock held. The fc_exch_rrq allocates new exch and that requires taking ex_lock again after EM lock. This locking order causes warning, see more details on this warning at :- http://www.open-fcoe.org/pipermail/devel/2009-July/003251.html This patch fixes this by dropping the ex_lock before calling fc_exch_rrq(). The fc_exch_rrq needs to grab ex_lock lock again to schedule RRQ retry and in the meanwhile fc_exch_reset could occur before ex_lock is grabbed inside fc_exch_rrq. So to handle this case, this patch adds additional check to detect fc_exch_reset after ex_lock acquired and in case the fc_exch_reset occurred then abandons the RRQ retry and releases the exch. Signed-off-by: Vasu Dev <vasu.dev@intel.com> Signed-off-by: Robert Love <robert.w.love@intel.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
This commit is contained in:
parent
16ed55f9de
commit
a0cc1ecc09
1 changed files with 15 additions and 8 deletions
|
@ -415,9 +415,9 @@ static void fc_exch_timeout(struct work_struct *work)
|
|||
e_stat = ep->esb_stat;
|
||||
if (e_stat & ESB_ST_COMPLETE) {
|
||||
ep->esb_stat = e_stat & ~ESB_ST_REC_QUAL;
|
||||
spin_unlock_bh(&ep->ex_lock);
|
||||
if (e_stat & ESB_ST_REC_QUAL)
|
||||
fc_exch_rrq(ep);
|
||||
spin_unlock_bh(&ep->ex_lock);
|
||||
goto done;
|
||||
} else {
|
||||
resp = ep->resp;
|
||||
|
@ -1624,14 +1624,14 @@ static void fc_exch_rrq(struct fc_exch *ep)
|
|||
struct fc_lport *lp;
|
||||
struct fc_els_rrq *rrq;
|
||||
struct fc_frame *fp;
|
||||
struct fc_seq *rrq_sp;
|
||||
u32 did;
|
||||
|
||||
lp = ep->lp;
|
||||
|
||||
fp = fc_frame_alloc(lp, sizeof(*rrq));
|
||||
if (!fp)
|
||||
return;
|
||||
goto retry;
|
||||
|
||||
rrq = fc_frame_payload_get(fp, sizeof(*rrq));
|
||||
memset(rrq, 0, sizeof(*rrq));
|
||||
rrq->rrq_cmd = ELS_RRQ;
|
||||
|
@ -1647,13 +1647,20 @@ static void fc_exch_rrq(struct fc_exch *ep)
|
|||
fc_host_port_id(lp->host), FC_TYPE_ELS,
|
||||
FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
|
||||
|
||||
rrq_sp = fc_exch_seq_send(lp, fp, fc_exch_rrq_resp, NULL, ep,
|
||||
lp->e_d_tov);
|
||||
if (!rrq_sp) {
|
||||
ep->esb_stat |= ESB_ST_REC_QUAL;
|
||||
fc_exch_timer_set_locked(ep, ep->r_a_tov);
|
||||
if (fc_exch_seq_send(lp, fp, fc_exch_rrq_resp, NULL, ep, lp->e_d_tov))
|
||||
return;
|
||||
|
||||
retry:
|
||||
spin_lock_bh(&ep->ex_lock);
|
||||
if (ep->state & (FC_EX_RST_CLEANUP | FC_EX_DONE)) {
|
||||
spin_unlock_bh(&ep->ex_lock);
|
||||
/* drop hold for rec qual */
|
||||
fc_exch_release(ep);
|
||||
return;
|
||||
}
|
||||
ep->esb_stat |= ESB_ST_REC_QUAL;
|
||||
fc_exch_timer_set_locked(ep, ep->r_a_tov);
|
||||
spin_unlock_bh(&ep->ex_lock);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue