Commit f159b3c7 authored by Quinn Tran's avatar Quinn Tran Committed by Nicholas Bellinger

qla2xxx: Fix sess_lock & hardware_lock lock order problem.

The main lock that needs to be held for CMD or TMR submission
to upper layer is the sess_lock. The sess_lock is used to
serialize cmd submission and session deletion. The addition
of hardware_lock being held is not necessary. This patch removes
hardware_lock dependency from CMD/TMR submission.

Use hardware_lock only for error response in this case.

Path1
       CPU0                    CPU1
       ----                    ----
  lock(&(&ha->tgt.sess_lock)->rlock);
                               lock(&(&ha->hardware_lock)->rlock);
                               lock(&(&ha->tgt.sess_lock)->rlock);
  lock(&(&ha->hardware_lock)->rlock);

Path2/deadlock
*** DEADLOCK ***
Call Trace:
dump_stack+0x85/0xc2
print_circular_bug+0x1e3/0x250
__lock_acquire+0x1425/0x1620
lock_acquire+0xbf/0x210
_raw_spin_lock_irqsave+0x53/0x70
qlt_sess_work_fn+0x21d/0x480 [qla2xxx]
process_one_work+0x1f4/0x6e0

Cc: <stable@vger.kernel.org>
Cc: Bart Van Assche <Bart.VanAssche@sandisk.com>
Reported-by: default avatarBart Van Assche <Bart.VanAssche@sandisk.com>
Signed-off-by: default avatarQuinn Tran <quinn.tran@cavium.com>
Signed-off-by: default avatarHimanshu Madhani <himanshu.madhani@cavium.com>
Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent 8f6fc8d4
...@@ -5727,30 +5727,23 @@ static void qlt_abort_work(struct qla_tgt *tgt, ...@@ -5727,30 +5727,23 @@ static void qlt_abort_work(struct qla_tgt *tgt,
} }
} }
spin_lock_irqsave(&ha->hardware_lock, flags);
if (tgt->tgt_stop)
goto out_term;
rc = __qlt_24xx_handle_abts(vha, &prm->abts, sess); rc = __qlt_24xx_handle_abts(vha, &prm->abts, sess);
ha->tgt.tgt_ops->put_sess(sess);
spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2);
if (rc != 0) if (rc != 0)
goto out_term; goto out_term;
spin_unlock_irqrestore(&ha->hardware_lock, flags);
if (sess)
ha->tgt.tgt_ops->put_sess(sess);
spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2);
return; return;
out_term2: out_term2:
spin_lock_irqsave(&ha->hardware_lock, flags); if (sess)
ha->tgt.tgt_ops->put_sess(sess);
spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2);
out_term: out_term:
spin_lock_irqsave(&ha->hardware_lock, flags);
qlt_24xx_send_abts_resp(vha, &prm->abts, FCP_TMF_REJECTED, false); qlt_24xx_send_abts_resp(vha, &prm->abts, FCP_TMF_REJECTED, false);
spin_unlock_irqrestore(&ha->hardware_lock, flags); spin_unlock_irqrestore(&ha->hardware_lock, flags);
if (sess)
ha->tgt.tgt_ops->put_sess(sess);
spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2);
} }
static void qlt_tmr_work(struct qla_tgt *tgt, static void qlt_tmr_work(struct qla_tgt *tgt,
...@@ -5770,7 +5763,7 @@ static void qlt_tmr_work(struct qla_tgt *tgt, ...@@ -5770,7 +5763,7 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
spin_lock_irqsave(&ha->tgt.sess_lock, flags); spin_lock_irqsave(&ha->tgt.sess_lock, flags);
if (tgt->tgt_stop) if (tgt->tgt_stop)
goto out_term; goto out_term2;
s_id = prm->tm_iocb2.u.isp24.fcp_hdr.s_id; s_id = prm->tm_iocb2.u.isp24.fcp_hdr.s_id;
sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, s_id); sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, s_id);
...@@ -5782,11 +5775,11 @@ static void qlt_tmr_work(struct qla_tgt *tgt, ...@@ -5782,11 +5775,11 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
spin_lock_irqsave(&ha->tgt.sess_lock, flags); spin_lock_irqsave(&ha->tgt.sess_lock, flags);
if (!sess) if (!sess)
goto out_term; goto out_term2;
} else { } else {
if (sess->deleted) { if (sess->deleted) {
sess = NULL; sess = NULL;
goto out_term; goto out_term2;
} }
if (!kref_get_unless_zero(&sess->sess_kref)) { if (!kref_get_unless_zero(&sess->sess_kref)) {
...@@ -5794,7 +5787,7 @@ static void qlt_tmr_work(struct qla_tgt *tgt, ...@@ -5794,7 +5787,7 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
"%s: kref_get fail %8phC\n", "%s: kref_get fail %8phC\n",
__func__, sess->port_name); __func__, sess->port_name);
sess = NULL; sess = NULL;
goto out_term; goto out_term2;
} }
} }
...@@ -5804,17 +5797,19 @@ static void qlt_tmr_work(struct qla_tgt *tgt, ...@@ -5804,17 +5797,19 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
unpacked_lun = scsilun_to_int((struct scsi_lun *)&lun); unpacked_lun = scsilun_to_int((struct scsi_lun *)&lun);
rc = qlt_issue_task_mgmt(sess, unpacked_lun, fn, iocb, 0); rc = qlt_issue_task_mgmt(sess, unpacked_lun, fn, iocb, 0);
if (rc != 0)
goto out_term;
ha->tgt.tgt_ops->put_sess(sess); ha->tgt.tgt_ops->put_sess(sess);
spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
if (rc != 0)
goto out_term;
return; return;
out_term2:
if (sess)
ha->tgt.tgt_ops->put_sess(sess);
spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
out_term: out_term:
qlt_send_term_exchange(vha, NULL, &prm->tm_iocb2, 1, 0); qlt_send_term_exchange(vha, NULL, &prm->tm_iocb2, 1, 0);
ha->tgt.tgt_ops->put_sess(sess);
spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
} }
static void qlt_sess_work_fn(struct work_struct *work) static void qlt_sess_work_fn(struct work_struct *work)
......
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