diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2014-02-03 15:54:39 -0500 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2014-03-04 20:54:09 -0500 |
commit | defd884845297fd5690594bfe89656b01f16d87e (patch) | |
tree | b8ae8a15462e2ccc2e0a6c1c1f7ace6507a47aa5 | |
parent | 5159d763f60af693a3fcec45dce2021f66e528a4 (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.c | 106 | ||||
-rw-r--r-- | drivers/infiniband/ulp/isert/ib_isert.h | 4 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target.c | 4 | ||||
-rw-r--r-- | include/target/iscsi/iscsi_transport.h | 1 |
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 | ||
714 | wake_up: | 714 | wake_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 | ||
1693 | static void | 1693 | static void |
1694 | isert_cq_comp_err(struct iser_tx_desc *tx_desc, struct isert_conn *isert_conn) | 1694 | isert_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 | |||
1705 | static void | ||
1706 | isert_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 | ||
1721 | static void | 1729 | static 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 | ||
2705 | static int isert_check_state(struct isert_conn *isert_conn, int state) | 2714 | static 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 | |||
2716 | static 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 | |||
2748 | static 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); |