aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/bnx2i
diff options
context:
space:
mode:
authorShlomo Pongratz <shlomop@mellanox.com>2014-02-07 01:41:38 -0500
committerJames Bottomley <JBottomley@Parallels.com>2014-03-15 13:19:18 -0400
commit659743b02c411075b26601725947b21df0bb29c8 (patch)
tree5c0350e508cdc32c97bf8d86da0ecfa5c15915f5 /drivers/scsi/bnx2i
parent5d0fddd0a72d3023bb0fa97e546f687aa6222be3 (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.c46
-rw-r--r--drivers/scsi/bnx2i/bnx2i_iscsi.c8
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);
1434fail: 1434fail:
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);
1502done: 1502done:
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);
1563done: 1563done:
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);
1602done: 1602done:
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;
1649done: 1649done:
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 }
1739done: 1739done:
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;