aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicholas Bellinger <nab@linux-iscsi.org>2014-02-03 15:54:39 -0500
committerNicholas Bellinger <nab@linux-iscsi.org>2014-03-04 20:54:09 -0500
commitdefd884845297fd5690594bfe89656b01f16d87e (patch)
treeb8ae8a15462e2ccc2e0a6c1c1f7ace6507a47aa5
parent5159d763f60af693a3fcec45dce2021f66e528a4 (diff)
iscsi/iser-target: Fix isert_conn->state hung shutdown issues
This patch addresses a couple of different hug shutdown issues related to wait_event() + isert_conn->state. First, it changes isert_conn->conn_wait + isert_conn->conn_wait_comp_err from waitqueues to completions, and sets ISER_CONN_TERMINATING from within isert_disconnect_work(). Second, it splits isert_free_conn() into isert_wait_conn() that is called earlier in iscsit_close_connection() to ensure that all outstanding commands have completed before continuing. Finally, it breaks isert_cq_comp_err() into seperate TX / RX related code, and adds logic in isert_cq_rx_comp_err() to wait for outstanding commands to complete before setting ISER_CONN_DOWN and calling complete(&isert_conn->conn_wait_comp_err). Acked-by: Sagi Grimberg <sagig@mellanox.com> Cc: Or Gerlitz <ogerlitz@mellanox.com> Cc: <stable@vger.kernel.org> #3.10+ Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r--drivers/infiniband/ulp/isert/ib_isert.c106
-rw-r--r--drivers/infiniband/ulp/isert/ib_isert.h4
-rw-r--r--drivers/target/iscsi/iscsi_target.c4
-rw-r--r--include/target/iscsi/iscsi_transport.h1
4 files changed, 55 insertions, 60 deletions
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c
index 5eb2b88cf947..862d7b4b0411 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.c
+++ b/drivers/infiniband/ulp/isert/ib_isert.c
@@ -492,8 +492,8 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
492 isert_conn->state = ISER_CONN_INIT; 492 isert_conn->state = ISER_CONN_INIT;
493 INIT_LIST_HEAD(&isert_conn->conn_accept_node); 493 INIT_LIST_HEAD(&isert_conn->conn_accept_node);
494 init_completion(&isert_conn->conn_login_comp); 494 init_completion(&isert_conn->conn_login_comp);
495 init_waitqueue_head(&isert_conn->conn_wait); 495 init_completion(&isert_conn->conn_wait);
496 init_waitqueue_head(&isert_conn->conn_wait_comp_err); 496 init_completion(&isert_conn->conn_wait_comp_err);
497 kref_init(&isert_conn->conn_kref); 497 kref_init(&isert_conn->conn_kref);
498 kref_get(&isert_conn->conn_kref); 498 kref_get(&isert_conn->conn_kref);
499 mutex_init(&isert_conn->conn_mutex); 499 mutex_init(&isert_conn->conn_mutex);
@@ -688,11 +688,11 @@ isert_disconnect_work(struct work_struct *work)
688 688
689 pr_debug("isert_disconnect_work(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); 689 pr_debug("isert_disconnect_work(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
690 mutex_lock(&isert_conn->conn_mutex); 690 mutex_lock(&isert_conn->conn_mutex);
691 isert_conn->state = ISER_CONN_DOWN; 691 if (isert_conn->state == ISER_CONN_UP)
692 isert_conn->state = ISER_CONN_TERMINATING;
692 693
693 if (isert_conn->post_recv_buf_count == 0 && 694 if (isert_conn->post_recv_buf_count == 0 &&
694 atomic_read(&isert_conn->post_send_buf_count) == 0) { 695 atomic_read(&isert_conn->post_send_buf_count) == 0) {
695 pr_debug("Calling wake_up(&isert_conn->conn_wait);\n");
696 mutex_unlock(&isert_conn->conn_mutex); 696 mutex_unlock(&isert_conn->conn_mutex);
697 goto wake_up; 697 goto wake_up;
698 } 698 }
@@ -712,7 +712,7 @@ isert_disconnect_work(struct work_struct *work)
712 mutex_unlock(&isert_conn->conn_mutex); 712 mutex_unlock(&isert_conn->conn_mutex);
713 713
714wake_up: 714wake_up:
715 wake_up(&isert_conn->conn_wait); 715 complete(&isert_conn->conn_wait);
716 isert_put_conn(isert_conn); 716 isert_put_conn(isert_conn);
717} 717}
718 718
@@ -1589,7 +1589,7 @@ isert_do_control_comp(struct work_struct *work)
1589 pr_debug("Calling iscsit_logout_post_handler >>>>>>>>>>>>>>\n"); 1589 pr_debug("Calling iscsit_logout_post_handler >>>>>>>>>>>>>>\n");
1590 /* 1590 /*
1591 * Call atomic_dec(&isert_conn->post_send_buf_count) 1591 * Call atomic_dec(&isert_conn->post_send_buf_count)
1592 * from isert_free_conn() 1592 * from isert_wait_conn()
1593 */ 1593 */
1594 isert_conn->logout_posted = true; 1594 isert_conn->logout_posted = true;
1595 iscsit_logout_post_handler(cmd, cmd->conn); 1595 iscsit_logout_post_handler(cmd, cmd->conn);
@@ -1691,31 +1691,39 @@ isert_send_completion(struct iser_tx_desc *tx_desc,
1691} 1691}
1692 1692
1693static void 1693static void
1694isert_cq_comp_err(struct iser_tx_desc *tx_desc, struct isert_conn *isert_conn) 1694isert_cq_tx_comp_err(struct iser_tx_desc *tx_desc, struct isert_conn *isert_conn)
1695{ 1695{
1696 struct ib_device *ib_dev = isert_conn->conn_cm_id->device; 1696 struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
1697 struct isert_cmd *isert_cmd = tx_desc->isert_cmd;
1698
1699 if (!isert_cmd)
1700 isert_unmap_tx_desc(tx_desc, ib_dev);
1701 else
1702 isert_completion_put(tx_desc, isert_cmd, ib_dev);
1703}
1704
1705static void
1706isert_cq_rx_comp_err(struct isert_conn *isert_conn)
1707{
1708 struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
1709 struct iscsi_conn *conn = isert_conn->conn;
1697 1710
1698 if (tx_desc) { 1711 if (isert_conn->post_recv_buf_count)
1699 struct isert_cmd *isert_cmd = tx_desc->isert_cmd; 1712 return;
1700 1713
1701 if (!isert_cmd) 1714 if (conn->sess) {
1702 isert_unmap_tx_desc(tx_desc, ib_dev); 1715 target_sess_cmd_list_set_waiting(conn->sess->se_sess);
1703 else 1716 target_wait_for_sess_cmds(conn->sess->se_sess);
1704 isert_completion_put(tx_desc, isert_cmd, ib_dev);
1705 } 1717 }
1706 1718
1707 if (isert_conn->post_recv_buf_count == 0 && 1719 while (atomic_read(&isert_conn->post_send_buf_count))
1708 atomic_read(&isert_conn->post_send_buf_count) == 0) { 1720 msleep(3000);
1709 pr_debug("isert_cq_comp_err >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
1710 pr_debug("Calling wake_up from isert_cq_comp_err\n");
1711 1721
1712 mutex_lock(&isert_conn->conn_mutex); 1722 mutex_lock(&isert_conn->conn_mutex);
1713 if (isert_conn->state != ISER_CONN_DOWN) 1723 isert_conn->state = ISER_CONN_DOWN;
1714 isert_conn->state = ISER_CONN_TERMINATING; 1724 mutex_unlock(&isert_conn->conn_mutex);
1715 mutex_unlock(&isert_conn->conn_mutex);
1716 1725
1717 wake_up(&isert_conn->conn_wait_comp_err); 1726 complete(&isert_conn->conn_wait_comp_err);
1718 }
1719} 1727}
1720 1728
1721static void 1729static void
@@ -1740,8 +1748,9 @@ isert_cq_tx_work(struct work_struct *work)
1740 pr_debug("TX wc.status != IB_WC_SUCCESS >>>>>>>>>>>>>>\n"); 1748 pr_debug("TX wc.status != IB_WC_SUCCESS >>>>>>>>>>>>>>\n");
1741 pr_debug("TX wc.status: 0x%08x\n", wc.status); 1749 pr_debug("TX wc.status: 0x%08x\n", wc.status);
1742 pr_debug("TX wc.vendor_err: 0x%08x\n", wc.vendor_err); 1750 pr_debug("TX wc.vendor_err: 0x%08x\n", wc.vendor_err);
1751
1743 atomic_dec(&isert_conn->post_send_buf_count); 1752 atomic_dec(&isert_conn->post_send_buf_count);
1744 isert_cq_comp_err(tx_desc, isert_conn); 1753 isert_cq_tx_comp_err(tx_desc, isert_conn);
1745 } 1754 }
1746 } 1755 }
1747 1756
@@ -1784,7 +1793,7 @@ isert_cq_rx_work(struct work_struct *work)
1784 wc.vendor_err); 1793 wc.vendor_err);
1785 } 1794 }
1786 isert_conn->post_recv_buf_count--; 1795 isert_conn->post_recv_buf_count--;
1787 isert_cq_comp_err(NULL, isert_conn); 1796 isert_cq_rx_comp_err(isert_conn);
1788 } 1797 }
1789 } 1798 }
1790 1799
@@ -2702,22 +2711,11 @@ isert_free_np(struct iscsi_np *np)
2702 kfree(isert_np); 2711 kfree(isert_np);
2703} 2712}
2704 2713
2705static int isert_check_state(struct isert_conn *isert_conn, int state) 2714static void isert_wait_conn(struct iscsi_conn *conn)
2706{
2707 int ret;
2708
2709 mutex_lock(&isert_conn->conn_mutex);
2710 ret = (isert_conn->state == state);
2711 mutex_unlock(&isert_conn->conn_mutex);
2712
2713 return ret;
2714}
2715
2716static void isert_free_conn(struct iscsi_conn *conn)
2717{ 2715{
2718 struct isert_conn *isert_conn = conn->context; 2716 struct isert_conn *isert_conn = conn->context;
2719 2717
2720 pr_debug("isert_free_conn: Starting \n"); 2718 pr_debug("isert_wait_conn: Starting \n");
2721 /* 2719 /*
2722 * Decrement post_send_buf_count for special case when called 2720 * Decrement post_send_buf_count for special case when called
2723 * from isert_do_control_comp() -> iscsit_logout_post_handler() 2721 * from isert_do_control_comp() -> iscsit_logout_post_handler()
@@ -2727,38 +2725,29 @@ static void isert_free_conn(struct iscsi_conn *conn)
2727 atomic_dec(&isert_conn->post_send_buf_count); 2725 atomic_dec(&isert_conn->post_send_buf_count);
2728 2726
2729 if (isert_conn->conn_cm_id && isert_conn->state != ISER_CONN_DOWN) { 2727 if (isert_conn->conn_cm_id && isert_conn->state != ISER_CONN_DOWN) {
2730 pr_debug("Calling rdma_disconnect from isert_free_conn\n"); 2728 pr_debug("Calling rdma_disconnect from isert_wait_conn\n");
2731 rdma_disconnect(isert_conn->conn_cm_id); 2729 rdma_disconnect(isert_conn->conn_cm_id);
2732 } 2730 }
2733 /* 2731 /*
2734 * Only wait for conn_wait_comp_err if the isert_conn made it 2732 * Only wait for conn_wait_comp_err if the isert_conn made it
2735 * into full feature phase.. 2733 * into full feature phase..
2736 */ 2734 */
2737 if (isert_conn->state == ISER_CONN_UP) {
2738 pr_debug("isert_free_conn: Before wait_event comp_err %d\n",
2739 isert_conn->state);
2740 mutex_unlock(&isert_conn->conn_mutex);
2741
2742 wait_event(isert_conn->conn_wait_comp_err,
2743 (isert_check_state(isert_conn, ISER_CONN_TERMINATING)));
2744
2745 wait_event(isert_conn->conn_wait,
2746 (isert_check_state(isert_conn, ISER_CONN_DOWN)));
2747
2748 isert_put_conn(isert_conn);
2749 return;
2750 }
2751 if (isert_conn->state == ISER_CONN_INIT) { 2735 if (isert_conn->state == ISER_CONN_INIT) {
2752 mutex_unlock(&isert_conn->conn_mutex); 2736 mutex_unlock(&isert_conn->conn_mutex);
2753 isert_put_conn(isert_conn);
2754 return; 2737 return;
2755 } 2738 }
2756 pr_debug("isert_free_conn: wait_event conn_wait %d\n", 2739 if (isert_conn->state == ISER_CONN_UP)
2757 isert_conn->state); 2740 isert_conn->state = ISER_CONN_TERMINATING;
2758 mutex_unlock(&isert_conn->conn_mutex); 2741 mutex_unlock(&isert_conn->conn_mutex);
2759 2742
2760 wait_event(isert_conn->conn_wait, 2743 wait_for_completion(&isert_conn->conn_wait_comp_err);
2761 (isert_check_state(isert_conn, ISER_CONN_DOWN))); 2744
2745 wait_for_completion(&isert_conn->conn_wait);
2746}
2747
2748static void isert_free_conn(struct iscsi_conn *conn)
2749{
2750 struct isert_conn *isert_conn = conn->context;
2762 2751
2763 isert_put_conn(isert_conn); 2752 isert_put_conn(isert_conn);
2764} 2753}
@@ -2771,6 +2760,7 @@ static struct iscsit_transport iser_target_transport = {
2771 .iscsit_setup_np = isert_setup_np, 2760 .iscsit_setup_np = isert_setup_np,
2772 .iscsit_accept_np = isert_accept_np, 2761 .iscsit_accept_np = isert_accept_np,
2773 .iscsit_free_np = isert_free_np, 2762 .iscsit_free_np = isert_free_np,
2763 .iscsit_wait_conn = isert_wait_conn,
2774 .iscsit_free_conn = isert_free_conn, 2764 .iscsit_free_conn = isert_free_conn,
2775 .iscsit_get_login_rx = isert_get_login_rx, 2765 .iscsit_get_login_rx = isert_get_login_rx,
2776 .iscsit_put_login_tx = isert_put_login_tx, 2766 .iscsit_put_login_tx = isert_put_login_tx,
diff --git a/drivers/infiniband/ulp/isert/ib_isert.h b/drivers/infiniband/ulp/isert/ib_isert.h
index 708a069002f3..41e799ff8ecc 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.h
+++ b/drivers/infiniband/ulp/isert/ib_isert.h
@@ -116,8 +116,8 @@ struct isert_conn {
116 struct isert_device *conn_device; 116 struct isert_device *conn_device;
117 struct work_struct conn_logout_work; 117 struct work_struct conn_logout_work;
118 struct mutex conn_mutex; 118 struct mutex conn_mutex;
119 wait_queue_head_t conn_wait; 119 struct completion conn_wait;
120 wait_queue_head_t conn_wait_comp_err; 120 struct completion conn_wait_comp_err;
121 struct kref conn_kref; 121 struct kref conn_kref;
122 struct list_head conn_fr_pool; 122 struct list_head conn_fr_pool;
123 int conn_fr_pool_size; 123 int conn_fr_pool_size;
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index ece82b0d8ea3..b83ec378d04f 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -4196,6 +4196,10 @@ int iscsit_close_connection(
4196 iscsit_stop_timers_for_cmds(conn); 4196 iscsit_stop_timers_for_cmds(conn);
4197 iscsit_stop_nopin_response_timer(conn); 4197 iscsit_stop_nopin_response_timer(conn);
4198 iscsit_stop_nopin_timer(conn); 4198 iscsit_stop_nopin_timer(conn);
4199
4200 if (conn->conn_transport->iscsit_wait_conn)
4201 conn->conn_transport->iscsit_wait_conn(conn);
4202
4199 iscsit_free_queue_reqs_for_conn(conn); 4203 iscsit_free_queue_reqs_for_conn(conn);
4200 4204
4201 /* 4205 /*
diff --git a/include/target/iscsi/iscsi_transport.h b/include/target/iscsi/iscsi_transport.h
index ae5a17111968..4483fadfa68d 100644
--- a/include/target/iscsi/iscsi_transport.h
+++ b/include/target/iscsi/iscsi_transport.h
@@ -12,6 +12,7 @@ struct iscsit_transport {
12 int (*iscsit_setup_np)(struct iscsi_np *, struct __kernel_sockaddr_storage *); 12 int (*iscsit_setup_np)(struct iscsi_np *, struct __kernel_sockaddr_storage *);
13 int (*iscsit_accept_np)(struct iscsi_np *, struct iscsi_conn *); 13 int (*iscsit_accept_np)(struct iscsi_np *, struct iscsi_conn *);
14 void (*iscsit_free_np)(struct iscsi_np *); 14 void (*iscsit_free_np)(struct iscsi_np *);
15 void (*iscsit_wait_conn)(struct iscsi_conn *);
15 void (*iscsit_free_conn)(struct iscsi_conn *); 16 void (*iscsit_free_conn)(struct iscsi_conn *);
16 int (*iscsit_get_login_rx)(struct iscsi_conn *, struct iscsi_login *); 17 int (*iscsit_get_login_rx)(struct iscsi_conn *, struct iscsi_login *);
17 int (*iscsit_put_login_tx)(struct iscsi_conn *, struct iscsi_login *, u32); 18 int (*iscsit_put_login_tx)(struct iscsi_conn *, struct iscsi_login *, u32);