diff options
author | Shlomo Pongratz <shlomop@mellanox.com> | 2014-02-07 01:41:38 -0500 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2014-03-15 13:19:18 -0400 |
commit | 659743b02c411075b26601725947b21df0bb29c8 (patch) | |
tree | 5c0350e508cdc32c97bf8d86da0ecfa5c15915f5 /drivers/scsi/bnx2i | |
parent | 5d0fddd0a72d3023bb0fa97e546f687aa6222be3 (diff) |
[SCSI] libiscsi: Reduce locking contention in fast path
Replace the session lock with two locks, a forward lock and
a backwards lock named frwd_lock and back_lock respectively.
The forward lock protects resources that change while sending a
request to the target, such as cmdsn, queued_cmdsn, and allocating
task from the commands' pool with kfifo_out.
The backward lock protects resources that change while processing
a response or in error path, such as cmdsn_exp, cmdsn_max, and
returning tasks to the commands' pool with kfifo_in.
Under a steady state fast-path situation, that is when one
or more processes/threads submit IO to an iscsi device and
a single kernel upcall (e.g softirq) is dealing with processing
of responses without errors, this patch eliminates the contention
between the queuecommand()/request response/scsi_done() flows
associated with iscsi sessions.
Between the forward and the backward locks exists a strict locking
hierarchy. The mutual exclusion zone protected by the forward lock can
enclose the mutual exclusion zone protected by the backward lock but not
vice versa.
For example, in iscsi_conn_teardown or in iscsi_xmit_data when there is
a failure and __iscsi_put_task is called, the backward lock is taken while
the forward lock is still taken. On the other hand, if in the RX path a nop
is to be sent, for example in iscsi_handle_reject or __iscsi_complete_pdu
than the forward lock is released and the backward lock is taken for the
duration of iscsi_send_nopout, later the backward lock is released and the
forward lock is retaken.
libiscsi_tcp uses two kernel fifos the r2t pool and the r2t queue.
The insertion and deletion from these queues didn't corespond to the
assumption taken by the new forward/backwards session locking paradigm.
That is, in iscsi_tcp_clenup_task which belongs to the RX (backwards)
path, r2t is taken out from r2t queue and inserted to the r2t pool.
In iscsi_tcp_get_curr_r2t which belong to the TX (forward) path, r2t
is also inserted to the r2t pool and another r2t is pulled from r2t
queue.
Only in iscsi_tcp_r2t_rsp which is called in the RX path but can requeue
to the TX path, r2t is taken from the r2t pool and inserted to the r2t
queue.
In order to cope with this situation, two spin locks were added,
pool2queue and queue2pool. The former protects extracting from the
r2t pool and inserting to the r2t queue, and the later protects the
extracing from the r2t queue and inserting to the r2t pool.
Signed-off-by: Shlomo Pongratz <shlomop@mellanox.com>
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
[minor fix up to apply cleanly and compile fix]
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/bnx2i')
-rw-r--r-- | drivers/scsi/bnx2i/bnx2i_hwi.c | 46 | ||||
-rw-r--r-- | drivers/scsi/bnx2i/bnx2i_iscsi.c | 8 |
2 files changed, 27 insertions, 27 deletions
diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c index e4cf23df4b4f..da9cf041dc5d 100644 --- a/drivers/scsi/bnx2i/bnx2i_hwi.c +++ b/drivers/scsi/bnx2i/bnx2i_hwi.c | |||
@@ -1361,7 +1361,7 @@ int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session, | |||
1361 | u32 datalen = 0; | 1361 | u32 datalen = 0; |
1362 | 1362 | ||
1363 | resp_cqe = (struct bnx2i_cmd_response *)cqe; | 1363 | resp_cqe = (struct bnx2i_cmd_response *)cqe; |
1364 | spin_lock_bh(&session->lock); | 1364 | spin_lock_bh(&session->back_lock); |
1365 | task = iscsi_itt_to_task(conn, | 1365 | task = iscsi_itt_to_task(conn, |
1366 | resp_cqe->itt & ISCSI_CMD_RESPONSE_INDEX); | 1366 | resp_cqe->itt & ISCSI_CMD_RESPONSE_INDEX); |
1367 | if (!task) | 1367 | if (!task) |
@@ -1432,7 +1432,7 @@ done: | |||
1432 | __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, | 1432 | __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, |
1433 | conn->data, datalen); | 1433 | conn->data, datalen); |
1434 | fail: | 1434 | fail: |
1435 | spin_unlock_bh(&session->lock); | 1435 | spin_unlock_bh(&session->back_lock); |
1436 | return 0; | 1436 | return 0; |
1437 | } | 1437 | } |
1438 | 1438 | ||
@@ -1457,7 +1457,7 @@ static int bnx2i_process_login_resp(struct iscsi_session *session, | |||
1457 | int pad_len; | 1457 | int pad_len; |
1458 | 1458 | ||
1459 | login = (struct bnx2i_login_response *) cqe; | 1459 | login = (struct bnx2i_login_response *) cqe; |
1460 | spin_lock(&session->lock); | 1460 | spin_lock(&session->back_lock); |
1461 | task = iscsi_itt_to_task(conn, | 1461 | task = iscsi_itt_to_task(conn, |
1462 | login->itt & ISCSI_LOGIN_RESPONSE_INDEX); | 1462 | login->itt & ISCSI_LOGIN_RESPONSE_INDEX); |
1463 | if (!task) | 1463 | if (!task) |
@@ -1500,7 +1500,7 @@ static int bnx2i_process_login_resp(struct iscsi_session *session, | |||
1500 | bnx2i_conn->gen_pdu.resp_buf, | 1500 | bnx2i_conn->gen_pdu.resp_buf, |
1501 | bnx2i_conn->gen_pdu.resp_wr_ptr - bnx2i_conn->gen_pdu.resp_buf); | 1501 | bnx2i_conn->gen_pdu.resp_wr_ptr - bnx2i_conn->gen_pdu.resp_buf); |
1502 | done: | 1502 | done: |
1503 | spin_unlock(&session->lock); | 1503 | spin_unlock(&session->back_lock); |
1504 | return 0; | 1504 | return 0; |
1505 | } | 1505 | } |
1506 | 1506 | ||
@@ -1525,7 +1525,7 @@ static int bnx2i_process_text_resp(struct iscsi_session *session, | |||
1525 | int pad_len; | 1525 | int pad_len; |
1526 | 1526 | ||
1527 | text = (struct bnx2i_text_response *) cqe; | 1527 | text = (struct bnx2i_text_response *) cqe; |
1528 | spin_lock(&session->lock); | 1528 | spin_lock(&session->back_lock); |
1529 | task = iscsi_itt_to_task(conn, text->itt & ISCSI_LOGIN_RESPONSE_INDEX); | 1529 | task = iscsi_itt_to_task(conn, text->itt & ISCSI_LOGIN_RESPONSE_INDEX); |
1530 | if (!task) | 1530 | if (!task) |
1531 | goto done; | 1531 | goto done; |
@@ -1561,7 +1561,7 @@ static int bnx2i_process_text_resp(struct iscsi_session *session, | |||
1561 | bnx2i_conn->gen_pdu.resp_wr_ptr - | 1561 | bnx2i_conn->gen_pdu.resp_wr_ptr - |
1562 | bnx2i_conn->gen_pdu.resp_buf); | 1562 | bnx2i_conn->gen_pdu.resp_buf); |
1563 | done: | 1563 | done: |
1564 | spin_unlock(&session->lock); | 1564 | spin_unlock(&session->back_lock); |
1565 | return 0; | 1565 | return 0; |
1566 | } | 1566 | } |
1567 | 1567 | ||
@@ -1584,7 +1584,7 @@ static int bnx2i_process_tmf_resp(struct iscsi_session *session, | |||
1584 | struct iscsi_tm_rsp *resp_hdr; | 1584 | struct iscsi_tm_rsp *resp_hdr; |
1585 | 1585 | ||
1586 | tmf_cqe = (struct bnx2i_tmf_response *)cqe; | 1586 | tmf_cqe = (struct bnx2i_tmf_response *)cqe; |
1587 | spin_lock(&session->lock); | 1587 | spin_lock(&session->back_lock); |
1588 | task = iscsi_itt_to_task(conn, | 1588 | task = iscsi_itt_to_task(conn, |
1589 | tmf_cqe->itt & ISCSI_TMF_RESPONSE_INDEX); | 1589 | tmf_cqe->itt & ISCSI_TMF_RESPONSE_INDEX); |
1590 | if (!task) | 1590 | if (!task) |
@@ -1600,7 +1600,7 @@ static int bnx2i_process_tmf_resp(struct iscsi_session *session, | |||
1600 | 1600 | ||
1601 | __iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0); | 1601 | __iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0); |
1602 | done: | 1602 | done: |
1603 | spin_unlock(&session->lock); | 1603 | spin_unlock(&session->back_lock); |
1604 | return 0; | 1604 | return 0; |
1605 | } | 1605 | } |
1606 | 1606 | ||
@@ -1623,7 +1623,7 @@ static int bnx2i_process_logout_resp(struct iscsi_session *session, | |||
1623 | struct iscsi_logout_rsp *resp_hdr; | 1623 | struct iscsi_logout_rsp *resp_hdr; |
1624 | 1624 | ||
1625 | logout = (struct bnx2i_logout_response *) cqe; | 1625 | logout = (struct bnx2i_logout_response *) cqe; |
1626 | spin_lock(&session->lock); | 1626 | spin_lock(&session->back_lock); |
1627 | task = iscsi_itt_to_task(conn, | 1627 | task = iscsi_itt_to_task(conn, |
1628 | logout->itt & ISCSI_LOGOUT_RESPONSE_INDEX); | 1628 | logout->itt & ISCSI_LOGOUT_RESPONSE_INDEX); |
1629 | if (!task) | 1629 | if (!task) |
@@ -1647,7 +1647,7 @@ static int bnx2i_process_logout_resp(struct iscsi_session *session, | |||
1647 | 1647 | ||
1648 | bnx2i_conn->ep->state = EP_STATE_LOGOUT_RESP_RCVD; | 1648 | bnx2i_conn->ep->state = EP_STATE_LOGOUT_RESP_RCVD; |
1649 | done: | 1649 | done: |
1650 | spin_unlock(&session->lock); | 1650 | spin_unlock(&session->back_lock); |
1651 | return 0; | 1651 | return 0; |
1652 | } | 1652 | } |
1653 | 1653 | ||
@@ -1668,12 +1668,12 @@ static void bnx2i_process_nopin_local_cmpl(struct iscsi_session *session, | |||
1668 | struct iscsi_task *task; | 1668 | struct iscsi_task *task; |
1669 | 1669 | ||
1670 | nop_in = (struct bnx2i_nop_in_msg *)cqe; | 1670 | nop_in = (struct bnx2i_nop_in_msg *)cqe; |
1671 | spin_lock(&session->lock); | 1671 | spin_lock(&session->back_lock); |
1672 | task = iscsi_itt_to_task(conn, | 1672 | task = iscsi_itt_to_task(conn, |
1673 | nop_in->itt & ISCSI_NOP_IN_MSG_INDEX); | 1673 | nop_in->itt & ISCSI_NOP_IN_MSG_INDEX); |
1674 | if (task) | 1674 | if (task) |
1675 | __iscsi_put_task(task); | 1675 | __iscsi_put_task(task); |
1676 | spin_unlock(&session->lock); | 1676 | spin_unlock(&session->back_lock); |
1677 | } | 1677 | } |
1678 | 1678 | ||
1679 | /** | 1679 | /** |
@@ -1712,7 +1712,7 @@ static int bnx2i_process_nopin_mesg(struct iscsi_session *session, | |||
1712 | 1712 | ||
1713 | nop_in = (struct bnx2i_nop_in_msg *)cqe; | 1713 | nop_in = (struct bnx2i_nop_in_msg *)cqe; |
1714 | 1714 | ||
1715 | spin_lock(&session->lock); | 1715 | spin_lock(&session->back_lock); |
1716 | hdr = (struct iscsi_nopin *)&bnx2i_conn->gen_pdu.resp_hdr; | 1716 | hdr = (struct iscsi_nopin *)&bnx2i_conn->gen_pdu.resp_hdr; |
1717 | memset(hdr, 0, sizeof(struct iscsi_hdr)); | 1717 | memset(hdr, 0, sizeof(struct iscsi_hdr)); |
1718 | hdr->opcode = nop_in->op_code; | 1718 | hdr->opcode = nop_in->op_code; |
@@ -1738,7 +1738,7 @@ static int bnx2i_process_nopin_mesg(struct iscsi_session *session, | |||
1738 | } | 1738 | } |
1739 | done: | 1739 | done: |
1740 | __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0); | 1740 | __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0); |
1741 | spin_unlock(&session->lock); | 1741 | spin_unlock(&session->back_lock); |
1742 | 1742 | ||
1743 | return tgt_async_nop; | 1743 | return tgt_async_nop; |
1744 | } | 1744 | } |
@@ -1771,7 +1771,7 @@ static void bnx2i_process_async_mesg(struct iscsi_session *session, | |||
1771 | return; | 1771 | return; |
1772 | } | 1772 | } |
1773 | 1773 | ||
1774 | spin_lock(&session->lock); | 1774 | spin_lock(&session->back_lock); |
1775 | resp_hdr = (struct iscsi_async *) &bnx2i_conn->gen_pdu.resp_hdr; | 1775 | resp_hdr = (struct iscsi_async *) &bnx2i_conn->gen_pdu.resp_hdr; |
1776 | memset(resp_hdr, 0, sizeof(struct iscsi_hdr)); | 1776 | memset(resp_hdr, 0, sizeof(struct iscsi_hdr)); |
1777 | resp_hdr->opcode = async_cqe->op_code; | 1777 | resp_hdr->opcode = async_cqe->op_code; |
@@ -1790,7 +1790,7 @@ static void bnx2i_process_async_mesg(struct iscsi_session *session, | |||
1790 | 1790 | ||
1791 | __iscsi_complete_pdu(bnx2i_conn->cls_conn->dd_data, | 1791 | __iscsi_complete_pdu(bnx2i_conn->cls_conn->dd_data, |
1792 | (struct iscsi_hdr *)resp_hdr, NULL, 0); | 1792 | (struct iscsi_hdr *)resp_hdr, NULL, 0); |
1793 | spin_unlock(&session->lock); | 1793 | spin_unlock(&session->back_lock); |
1794 | } | 1794 | } |
1795 | 1795 | ||
1796 | 1796 | ||
@@ -1817,7 +1817,7 @@ static void bnx2i_process_reject_mesg(struct iscsi_session *session, | |||
1817 | } else | 1817 | } else |
1818 | bnx2i_unsol_pdu_adjust_rq(bnx2i_conn); | 1818 | bnx2i_unsol_pdu_adjust_rq(bnx2i_conn); |
1819 | 1819 | ||
1820 | spin_lock(&session->lock); | 1820 | spin_lock(&session->back_lock); |
1821 | hdr = (struct iscsi_reject *) &bnx2i_conn->gen_pdu.resp_hdr; | 1821 | hdr = (struct iscsi_reject *) &bnx2i_conn->gen_pdu.resp_hdr; |
1822 | memset(hdr, 0, sizeof(struct iscsi_hdr)); | 1822 | memset(hdr, 0, sizeof(struct iscsi_hdr)); |
1823 | hdr->opcode = reject->op_code; | 1823 | hdr->opcode = reject->op_code; |
@@ -1828,7 +1828,7 @@ static void bnx2i_process_reject_mesg(struct iscsi_session *session, | |||
1828 | hdr->ffffffff = cpu_to_be32(RESERVED_ITT); | 1828 | hdr->ffffffff = cpu_to_be32(RESERVED_ITT); |
1829 | __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, conn->data, | 1829 | __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, conn->data, |
1830 | reject->data_length); | 1830 | reject->data_length); |
1831 | spin_unlock(&session->lock); | 1831 | spin_unlock(&session->back_lock); |
1832 | } | 1832 | } |
1833 | 1833 | ||
1834 | /** | 1834 | /** |
@@ -1848,13 +1848,13 @@ static void bnx2i_process_cmd_cleanup_resp(struct iscsi_session *session, | |||
1848 | struct iscsi_task *task; | 1848 | struct iscsi_task *task; |
1849 | 1849 | ||
1850 | cmd_clean_rsp = (struct bnx2i_cleanup_response *)cqe; | 1850 | cmd_clean_rsp = (struct bnx2i_cleanup_response *)cqe; |
1851 | spin_lock(&session->lock); | 1851 | spin_lock(&session->back_lock); |
1852 | task = iscsi_itt_to_task(conn, | 1852 | task = iscsi_itt_to_task(conn, |
1853 | cmd_clean_rsp->itt & ISCSI_CLEANUP_RESPONSE_INDEX); | 1853 | cmd_clean_rsp->itt & ISCSI_CLEANUP_RESPONSE_INDEX); |
1854 | if (!task) | 1854 | if (!task) |
1855 | printk(KERN_ALERT "bnx2i: cmd clean ITT %x not active\n", | 1855 | printk(KERN_ALERT "bnx2i: cmd clean ITT %x not active\n", |
1856 | cmd_clean_rsp->itt & ISCSI_CLEANUP_RESPONSE_INDEX); | 1856 | cmd_clean_rsp->itt & ISCSI_CLEANUP_RESPONSE_INDEX); |
1857 | spin_unlock(&session->lock); | 1857 | spin_unlock(&session->back_lock); |
1858 | complete(&bnx2i_conn->cmd_cleanup_cmpl); | 1858 | complete(&bnx2i_conn->cmd_cleanup_cmpl); |
1859 | } | 1859 | } |
1860 | 1860 | ||
@@ -1921,11 +1921,11 @@ static int bnx2i_queue_scsi_cmd_resp(struct iscsi_session *session, | |||
1921 | int rc = 0; | 1921 | int rc = 0; |
1922 | int cpu; | 1922 | int cpu; |
1923 | 1923 | ||
1924 | spin_lock(&session->lock); | 1924 | spin_lock(&session->back_lock); |
1925 | task = iscsi_itt_to_task(bnx2i_conn->cls_conn->dd_data, | 1925 | task = iscsi_itt_to_task(bnx2i_conn->cls_conn->dd_data, |
1926 | cqe->itt & ISCSI_CMD_RESPONSE_INDEX); | 1926 | cqe->itt & ISCSI_CMD_RESPONSE_INDEX); |
1927 | if (!task || !task->sc) { | 1927 | if (!task || !task->sc) { |
1928 | spin_unlock(&session->lock); | 1928 | spin_unlock(&session->back_lock); |
1929 | return -EINVAL; | 1929 | return -EINVAL; |
1930 | } | 1930 | } |
1931 | sc = task->sc; | 1931 | sc = task->sc; |
@@ -1935,7 +1935,7 @@ static int bnx2i_queue_scsi_cmd_resp(struct iscsi_session *session, | |||
1935 | else | 1935 | else |
1936 | cpu = sc->request->cpu; | 1936 | cpu = sc->request->cpu; |
1937 | 1937 | ||
1938 | spin_unlock(&session->lock); | 1938 | spin_unlock(&session->back_lock); |
1939 | 1939 | ||
1940 | p = &per_cpu(bnx2i_percpu, cpu); | 1940 | p = &per_cpu(bnx2i_percpu, cpu); |
1941 | spin_lock(&p->p_work_lock); | 1941 | spin_lock(&p->p_work_lock); |
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c index 854dad7d5b03..c00642f10f1f 100644 --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c | |||
@@ -1169,10 +1169,10 @@ static void bnx2i_cleanup_task(struct iscsi_task *task) | |||
1169 | if (task->state == ISCSI_TASK_ABRT_TMF) { | 1169 | if (task->state == ISCSI_TASK_ABRT_TMF) { |
1170 | bnx2i_send_cmd_cleanup_req(hba, task->dd_data); | 1170 | bnx2i_send_cmd_cleanup_req(hba, task->dd_data); |
1171 | 1171 | ||
1172 | spin_unlock_bh(&conn->session->lock); | 1172 | spin_unlock_bh(&conn->session->back_lock); |
1173 | wait_for_completion_timeout(&bnx2i_conn->cmd_cleanup_cmpl, | 1173 | wait_for_completion_timeout(&bnx2i_conn->cmd_cleanup_cmpl, |
1174 | msecs_to_jiffies(ISCSI_CMD_CLEANUP_TIMEOUT)); | 1174 | msecs_to_jiffies(ISCSI_CMD_CLEANUP_TIMEOUT)); |
1175 | spin_lock_bh(&conn->session->lock); | 1175 | spin_lock_bh(&conn->session->back_lock); |
1176 | } | 1176 | } |
1177 | bnx2i_iscsi_unmap_sg_list(task->dd_data); | 1177 | bnx2i_iscsi_unmap_sg_list(task->dd_data); |
1178 | } | 1178 | } |
@@ -2059,7 +2059,7 @@ int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep) | |||
2059 | goto out; | 2059 | goto out; |
2060 | 2060 | ||
2061 | if (session) { | 2061 | if (session) { |
2062 | spin_lock_bh(&session->lock); | 2062 | spin_lock_bh(&session->frwd_lock); |
2063 | if (bnx2i_ep->state != EP_STATE_TCP_FIN_RCVD) { | 2063 | if (bnx2i_ep->state != EP_STATE_TCP_FIN_RCVD) { |
2064 | if (session->state == ISCSI_STATE_LOGGING_OUT) { | 2064 | if (session->state == ISCSI_STATE_LOGGING_OUT) { |
2065 | if (bnx2i_ep->state == EP_STATE_LOGOUT_SENT) { | 2065 | if (bnx2i_ep->state == EP_STATE_LOGOUT_SENT) { |
@@ -2075,7 +2075,7 @@ int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep) | |||
2075 | } else | 2075 | } else |
2076 | close = 1; | 2076 | close = 1; |
2077 | 2077 | ||
2078 | spin_unlock_bh(&session->lock); | 2078 | spin_unlock_bh(&session->frwd_lock); |
2079 | } | 2079 | } |
2080 | 2080 | ||
2081 | bnx2i_ep->state = EP_STATE_DISCONN_START; | 2081 | bnx2i_ep->state = EP_STATE_DISCONN_START; |