diff options
author | Quinn Tran <quinn.tran@cavium.com> | 2017-03-15 12:48:47 -0400 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2017-03-18 20:28:08 -0400 |
commit | f159b3c7cd45c550d0f73806451a10b6b6bc08ae (patch) | |
tree | 336f315eb431a87177eb963411e644587a3394d5 | |
parent | 8f6fc8d4e7ae2347d6261d11a7eb2b247d2954d8 (diff) |
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: Bart Van Assche <Bart.VanAssche@sandisk.com>
Signed-off-by: Quinn Tran <quinn.tran@cavium.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r-- | drivers/scsi/qla2xxx/qla_target.c | 41 |
1 files changed, 18 insertions, 23 deletions
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index a78c3e9bcb57..989f931af156 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c | |||
@@ -5727,30 +5727,23 @@ static void qlt_abort_work(struct qla_tgt *tgt, | |||
5727 | } | 5727 | } |
5728 | } | 5728 | } |
5729 | 5729 | ||
5730 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
5731 | |||
5732 | if (tgt->tgt_stop) | ||
5733 | goto out_term; | ||
5734 | |||
5735 | rc = __qlt_24xx_handle_abts(vha, &prm->abts, sess); | 5730 | rc = __qlt_24xx_handle_abts(vha, &prm->abts, sess); |
5731 | ha->tgt.tgt_ops->put_sess(sess); | ||
5732 | spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2); | ||
5733 | |||
5736 | if (rc != 0) | 5734 | if (rc != 0) |
5737 | goto out_term; | 5735 | goto out_term; |
5738 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
5739 | if (sess) | ||
5740 | ha->tgt.tgt_ops->put_sess(sess); | ||
5741 | spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2); | ||
5742 | return; | 5736 | return; |
5743 | 5737 | ||
5744 | out_term2: | 5738 | out_term2: |
5745 | spin_lock_irqsave(&ha->hardware_lock, flags); | 5739 | if (sess) |
5740 | ha->tgt.tgt_ops->put_sess(sess); | ||
5741 | spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2); | ||
5746 | 5742 | ||
5747 | out_term: | 5743 | out_term: |
5744 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
5748 | qlt_24xx_send_abts_resp(vha, &prm->abts, FCP_TMF_REJECTED, false); | 5745 | qlt_24xx_send_abts_resp(vha, &prm->abts, FCP_TMF_REJECTED, false); |
5749 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | 5746 | spin_unlock_irqrestore(&ha->hardware_lock, flags); |
5750 | |||
5751 | if (sess) | ||
5752 | ha->tgt.tgt_ops->put_sess(sess); | ||
5753 | spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2); | ||
5754 | } | 5747 | } |
5755 | 5748 | ||
5756 | static void qlt_tmr_work(struct qla_tgt *tgt, | 5749 | static void qlt_tmr_work(struct qla_tgt *tgt, |
@@ -5770,7 +5763,7 @@ static void qlt_tmr_work(struct qla_tgt *tgt, | |||
5770 | spin_lock_irqsave(&ha->tgt.sess_lock, flags); | 5763 | spin_lock_irqsave(&ha->tgt.sess_lock, flags); |
5771 | 5764 | ||
5772 | if (tgt->tgt_stop) | 5765 | if (tgt->tgt_stop) |
5773 | goto out_term; | 5766 | goto out_term2; |
5774 | 5767 | ||
5775 | s_id = prm->tm_iocb2.u.isp24.fcp_hdr.s_id; | 5768 | s_id = prm->tm_iocb2.u.isp24.fcp_hdr.s_id; |
5776 | sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, s_id); | 5769 | 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 | 5775 | ||
5783 | spin_lock_irqsave(&ha->tgt.sess_lock, flags); | 5776 | spin_lock_irqsave(&ha->tgt.sess_lock, flags); |
5784 | if (!sess) | 5777 | if (!sess) |
5785 | goto out_term; | 5778 | goto out_term2; |
5786 | } else { | 5779 | } else { |
5787 | if (sess->deleted) { | 5780 | if (sess->deleted) { |
5788 | sess = NULL; | 5781 | sess = NULL; |
5789 | goto out_term; | 5782 | goto out_term2; |
5790 | } | 5783 | } |
5791 | 5784 | ||
5792 | if (!kref_get_unless_zero(&sess->sess_kref)) { | 5785 | if (!kref_get_unless_zero(&sess->sess_kref)) { |
@@ -5794,7 +5787,7 @@ static void qlt_tmr_work(struct qla_tgt *tgt, | |||
5794 | "%s: kref_get fail %8phC\n", | 5787 | "%s: kref_get fail %8phC\n", |
5795 | __func__, sess->port_name); | 5788 | __func__, sess->port_name); |
5796 | sess = NULL; | 5789 | sess = NULL; |
5797 | goto out_term; | 5790 | goto out_term2; |
5798 | } | 5791 | } |
5799 | } | 5792 | } |
5800 | 5793 | ||
@@ -5804,17 +5797,19 @@ static void qlt_tmr_work(struct qla_tgt *tgt, | |||
5804 | unpacked_lun = scsilun_to_int((struct scsi_lun *)&lun); | 5797 | unpacked_lun = scsilun_to_int((struct scsi_lun *)&lun); |
5805 | 5798 | ||
5806 | rc = qlt_issue_task_mgmt(sess, unpacked_lun, fn, iocb, 0); | 5799 | rc = qlt_issue_task_mgmt(sess, unpacked_lun, fn, iocb, 0); |
5807 | if (rc != 0) | ||
5808 | goto out_term; | ||
5809 | |||
5810 | ha->tgt.tgt_ops->put_sess(sess); | 5800 | ha->tgt.tgt_ops->put_sess(sess); |
5811 | spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); | 5801 | spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); |
5802 | |||
5803 | if (rc != 0) | ||
5804 | goto out_term; | ||
5812 | return; | 5805 | return; |
5813 | 5806 | ||
5807 | out_term2: | ||
5808 | if (sess) | ||
5809 | ha->tgt.tgt_ops->put_sess(sess); | ||
5810 | spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); | ||
5814 | out_term: | 5811 | out_term: |
5815 | qlt_send_term_exchange(vha, NULL, &prm->tm_iocb2, 1, 0); | 5812 | qlt_send_term_exchange(vha, NULL, &prm->tm_iocb2, 1, 0); |
5816 | ha->tgt.tgt_ops->put_sess(sess); | ||
5817 | spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); | ||
5818 | } | 5813 | } |
5819 | 5814 | ||
5820 | static void qlt_sess_work_fn(struct work_struct *work) | 5815 | static void qlt_sess_work_fn(struct work_struct *work) |