From: Greg Kroah-Hartman Date: Fri, 31 Jul 2015 01:03:03 +0000 (-0700) Subject: 3.10-stable patches X-Git-Tag: v4.1.4~16 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=fac69b92f0754afac54c8408ee3c799c4b72aab6;p=thirdparty%2Fkernel%2Fstable-queue.git 3.10-stable patches added patches: iscsi-target-convert-iscsi_thread_set-usage-to-kthread.h.patch iser-target-fix-possible-deadlock-in-rdma_cm-connection-error.patch iser-target-release-stale-iser-connections.patch --- diff --git a/queue-3.10/iscsi-target-convert-iscsi_thread_set-usage-to-kthread.h.patch b/queue-3.10/iscsi-target-convert-iscsi_thread_set-usage-to-kthread.h.patch new file mode 100644 index 00000000000..840c87b46f5 --- /dev/null +++ b/queue-3.10/iscsi-target-convert-iscsi_thread_set-usage-to-kthread.h.patch @@ -0,0 +1,464 @@ +From 88dcd2dab5c23b1c9cfc396246d8f476c872f0ca Mon Sep 17 00:00:00 2001 +From: Nicholas Bellinger +Date: Thu, 26 Feb 2015 22:19:15 -0800 +Subject: iscsi-target: Convert iscsi_thread_set usage to kthread.h + +From: Nicholas Bellinger + +commit 88dcd2dab5c23b1c9cfc396246d8f476c872f0ca upstream. + +This patch converts iscsi-target code to use modern kthread.h API +callers for creating RX/TX threads for each new iscsi_conn descriptor, +and releasing associated RX/TX threads during connection shutdown. + +This is done using iscsit_start_kthreads() -> kthread_run() to start +new kthreads from within iscsi_post_login_handler(), and invoking +kthread_stop() from existing iscsit_close_connection() code. + +Also, convert iscsit_logout_post_handler_closesession() code to use +cmpxchg when determing when iscsit_cause_connection_reinstatement() +needs to sleep waiting for completion. + +Reported-by: Sagi Grimberg +Tested-by: Sagi Grimberg +Cc: Slava Shwartsman +Signed-off-by: Nicholas Bellinger +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/target/iscsi/iscsi_target.c | 104 ++++++++++++------------------ + drivers/target/iscsi/iscsi_target_core.h | 7 ++ + drivers/target/iscsi/iscsi_target_erl0.c | 13 ++- + drivers/target/iscsi/iscsi_target_login.c | 61 +++++++++++++++-- + 4 files changed, 115 insertions(+), 70 deletions(-) + +--- a/drivers/target/iscsi/iscsi_target.c ++++ b/drivers/target/iscsi/iscsi_target.c +@@ -518,7 +518,7 @@ static struct iscsit_transport iscsi_tar + + static int __init iscsi_target_init_module(void) + { +- int ret = 0; ++ int ret = 0, size; + + pr_debug("iSCSI-Target "ISCSIT_VERSION"\n"); + +@@ -527,6 +527,7 @@ static int __init iscsi_target_init_modu + pr_err("Unable to allocate memory for iscsit_global\n"); + return -1; + } ++ spin_lock_init(&iscsit_global->ts_bitmap_lock); + mutex_init(&auth_id_lock); + spin_lock_init(&sess_idr_lock); + idr_init(&tiqn_idr); +@@ -536,15 +537,11 @@ static int __init iscsi_target_init_modu + if (ret < 0) + goto out; + +- ret = iscsi_thread_set_init(); +- if (ret < 0) ++ size = BITS_TO_LONGS(ISCSIT_BITMAP_BITS) * sizeof(long); ++ iscsit_global->ts_bitmap = vzalloc(size); ++ if (!iscsit_global->ts_bitmap) { ++ pr_err("Unable to allocate iscsit_global->ts_bitmap\n"); + goto configfs_out; +- +- if (iscsi_allocate_thread_sets(TARGET_THREAD_SET_COUNT) != +- TARGET_THREAD_SET_COUNT) { +- pr_err("iscsi_allocate_thread_sets() returned" +- " unexpected value!\n"); +- goto ts_out1; + } + + lio_cmd_cache = kmem_cache_create("lio_cmd_cache", +@@ -553,7 +550,7 @@ static int __init iscsi_target_init_modu + if (!lio_cmd_cache) { + pr_err("Unable to kmem_cache_create() for" + " lio_cmd_cache\n"); +- goto ts_out2; ++ goto bitmap_out; + } + + lio_qr_cache = kmem_cache_create("lio_qr_cache", +@@ -608,10 +605,8 @@ qr_out: + kmem_cache_destroy(lio_qr_cache); + cmd_out: + kmem_cache_destroy(lio_cmd_cache); +-ts_out2: +- iscsi_deallocate_thread_sets(); +-ts_out1: +- iscsi_thread_set_free(); ++bitmap_out: ++ vfree(iscsit_global->ts_bitmap); + configfs_out: + iscsi_target_deregister_configfs(); + out: +@@ -621,8 +616,6 @@ out: + + static void __exit iscsi_target_cleanup_module(void) + { +- iscsi_deallocate_thread_sets(); +- iscsi_thread_set_free(); + iscsit_release_discovery_tpg(); + iscsit_unregister_transport(&iscsi_target_transport); + kmem_cache_destroy(lio_cmd_cache); +@@ -633,6 +626,7 @@ static void __exit iscsi_target_cleanup_ + + iscsi_target_deregister_configfs(); + ++ vfree(iscsit_global->ts_bitmap); + kfree(iscsit_global); + } + +@@ -3590,17 +3584,16 @@ static int iscsit_send_reject( + + void iscsit_thread_get_cpumask(struct iscsi_conn *conn) + { +- struct iscsi_thread_set *ts = conn->thread_set; + int ord, cpu; + /* +- * thread_id is assigned from iscsit_global->ts_bitmap from +- * within iscsi_thread_set.c:iscsi_allocate_thread_sets() ++ * bitmap_id is assigned from iscsit_global->ts_bitmap from ++ * within iscsit_start_kthreads() + * +- * Here we use thread_id to determine which CPU that this +- * iSCSI connection's iscsi_thread_set will be scheduled to ++ * Here we use bitmap_id to determine which CPU that this ++ * iSCSI connection's RX/TX threads will be scheduled to + * execute upon. + */ +- ord = ts->thread_id % cpumask_weight(cpu_online_mask); ++ ord = conn->bitmap_id % cpumask_weight(cpu_online_mask); + for_each_online_cpu(cpu) { + if (ord-- == 0) { + cpumask_set_cpu(cpu, conn->conn_cpumask); +@@ -3792,7 +3785,7 @@ check_rsp_state: + switch (state) { + case ISTATE_SEND_LOGOUTRSP: + if (!iscsit_logout_post_handler(cmd, conn)) +- goto restart; ++ return -ECONNRESET; + /* fall through */ + case ISTATE_SEND_STATUS: + case ISTATE_SEND_ASYNCMSG: +@@ -3820,8 +3813,6 @@ check_rsp_state: + + err: + return -1; +-restart: +- return -EAGAIN; + } + + static int iscsit_handle_response_queue(struct iscsi_conn *conn) +@@ -3848,21 +3839,13 @@ static int iscsit_handle_response_queue( + int iscsi_target_tx_thread(void *arg) + { + int ret = 0; +- struct iscsi_conn *conn; +- struct iscsi_thread_set *ts = arg; ++ struct iscsi_conn *conn = arg; + /* + * Allow ourselves to be interrupted by SIGINT so that a + * connection recovery / failure event can be triggered externally. + */ + allow_signal(SIGINT); + +-restart: +- conn = iscsi_tx_thread_pre_handler(ts); +- if (!conn) +- goto out; +- +- ret = 0; +- + while (!kthread_should_stop()) { + /* + * Ensure that both TX and RX per connection kthreads +@@ -3871,11 +3854,9 @@ restart: + iscsit_thread_check_cpumask(conn, current, 1); + + wait_event_interruptible(conn->queues_wq, +- !iscsit_conn_all_queues_empty(conn) || +- ts->status == ISCSI_THREAD_SET_RESET); ++ !iscsit_conn_all_queues_empty(conn)); + +- if ((ts->status == ISCSI_THREAD_SET_RESET) || +- signal_pending(current)) ++ if (signal_pending(current)) + goto transport_err; + + get_immediate: +@@ -3886,15 +3867,14 @@ get_immediate: + ret = iscsit_handle_response_queue(conn); + if (ret == 1) + goto get_immediate; +- else if (ret == -EAGAIN) +- goto restart; ++ else if (ret == -ECONNRESET) ++ goto out; + else if (ret < 0) + goto transport_err; + } + + transport_err: + iscsit_take_action_for_connection_exit(conn); +- goto restart; + out: + return 0; + } +@@ -3979,8 +3959,7 @@ int iscsi_target_rx_thread(void *arg) + int ret; + u8 buffer[ISCSI_HDR_LEN], opcode; + u32 checksum = 0, digest = 0; +- struct iscsi_conn *conn = NULL; +- struct iscsi_thread_set *ts = arg; ++ struct iscsi_conn *conn = arg; + struct kvec iov; + /* + * Allow ourselves to be interrupted by SIGINT so that a +@@ -3988,11 +3967,6 @@ int iscsi_target_rx_thread(void *arg) + */ + allow_signal(SIGINT); + +-restart: +- conn = iscsi_rx_thread_pre_handler(ts); +- if (!conn) +- goto out; +- + if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) { + struct completion comp; + int rc; +@@ -4002,7 +3976,7 @@ restart: + if (rc < 0) + goto transport_err; + +- goto out; ++ goto transport_err; + } + + while (!kthread_should_stop()) { +@@ -4085,8 +4059,6 @@ transport_err: + if (!signal_pending(current)) + atomic_set(&conn->transport_failed, 1); + iscsit_take_action_for_connection_exit(conn); +- goto restart; +-out: + return 0; + } + +@@ -4148,7 +4120,24 @@ int iscsit_close_connection( + if (conn->conn_transport->transport_type == ISCSI_TCP) + complete(&conn->conn_logout_comp); + +- iscsi_release_thread_set(conn); ++ if (!strcmp(current->comm, ISCSI_RX_THREAD_NAME)) { ++ if (conn->tx_thread && ++ cmpxchg(&conn->tx_thread_active, true, false)) { ++ send_sig(SIGINT, conn->tx_thread, 1); ++ kthread_stop(conn->tx_thread); ++ } ++ } else if (!strcmp(current->comm, ISCSI_TX_THREAD_NAME)) { ++ if (conn->rx_thread && ++ cmpxchg(&conn->rx_thread_active, true, false)) { ++ send_sig(SIGINT, conn->rx_thread, 1); ++ kthread_stop(conn->rx_thread); ++ } ++ } ++ ++ spin_lock(&iscsit_global->ts_bitmap_lock); ++ bitmap_release_region(iscsit_global->ts_bitmap, conn->bitmap_id, ++ get_order(1)); ++ spin_unlock(&iscsit_global->ts_bitmap_lock); + + iscsit_stop_timers_for_cmds(conn); + iscsit_stop_nopin_response_timer(conn); +@@ -4427,15 +4416,13 @@ static void iscsit_logout_post_handler_c + struct iscsi_conn *conn) + { + struct iscsi_session *sess = conn->sess; +- +- iscsi_set_thread_clear(conn, ISCSI_CLEAR_TX_THREAD); +- iscsi_set_thread_set_signal(conn, ISCSI_SIGNAL_TX_THREAD); ++ int sleep = cmpxchg(&conn->tx_thread_active, true, false); + + atomic_set(&conn->conn_logout_remove, 0); + complete(&conn->conn_logout_comp); + + iscsit_dec_conn_usage_count(conn); +- iscsit_stop_session(sess, 1, 1); ++ iscsit_stop_session(sess, sleep, sleep); + iscsit_dec_session_usage_count(sess); + target_put_session(sess->se_sess); + } +@@ -4443,13 +4430,12 @@ static void iscsit_logout_post_handler_c + static void iscsit_logout_post_handler_samecid( + struct iscsi_conn *conn) + { +- iscsi_set_thread_clear(conn, ISCSI_CLEAR_TX_THREAD); +- iscsi_set_thread_set_signal(conn, ISCSI_SIGNAL_TX_THREAD); ++ int sleep = cmpxchg(&conn->tx_thread_active, true, false); + + atomic_set(&conn->conn_logout_remove, 0); + complete(&conn->conn_logout_comp); + +- iscsit_cause_connection_reinstatement(conn, 1); ++ iscsit_cause_connection_reinstatement(conn, sleep); + iscsit_dec_conn_usage_count(conn); + } + +--- a/drivers/target/iscsi/iscsi_target_core.h ++++ b/drivers/target/iscsi/iscsi_target_core.h +@@ -586,6 +586,11 @@ struct iscsi_conn { + struct iscsi_session *sess; + /* Pointer to thread_set in use for this conn's threads */ + struct iscsi_thread_set *thread_set; ++ int bitmap_id; ++ int rx_thread_active; ++ struct task_struct *rx_thread; ++ int tx_thread_active; ++ struct task_struct *tx_thread; + /* list_head for session connection list */ + struct list_head conn_list; + } ____cacheline_aligned; +@@ -862,10 +867,12 @@ struct iscsit_global { + /* Unique identifier used for the authentication daemon */ + u32 auth_id; + u32 inactive_ts; ++#define ISCSIT_BITMAP_BITS 262144 + /* Thread Set bitmap count */ + int ts_bitmap_count; + /* Thread Set bitmap pointer */ + unsigned long *ts_bitmap; ++ spinlock_t ts_bitmap_lock; + /* Used for iSCSI discovery session authentication */ + struct iscsi_node_acl discovery_acl; + struct iscsi_portal_group *discovery_tpg; +--- a/drivers/target/iscsi/iscsi_target_erl0.c ++++ b/drivers/target/iscsi/iscsi_target_erl0.c +@@ -866,7 +866,10 @@ void iscsit_connection_reinstatement_rcf + } + spin_unlock_bh(&conn->state_lock); + +- iscsi_thread_set_force_reinstatement(conn); ++ if (conn->tx_thread && conn->tx_thread_active) ++ send_sig(SIGINT, conn->tx_thread, 1); ++ if (conn->rx_thread && conn->rx_thread_active) ++ send_sig(SIGINT, conn->rx_thread, 1); + + sleep: + wait_for_completion(&conn->conn_wait_rcfr_comp); +@@ -891,10 +894,10 @@ void iscsit_cause_connection_reinstateme + return; + } + +- if (iscsi_thread_set_force_reinstatement(conn) < 0) { +- spin_unlock_bh(&conn->state_lock); +- return; +- } ++ if (conn->tx_thread && conn->tx_thread_active) ++ send_sig(SIGINT, conn->tx_thread, 1); ++ if (conn->rx_thread && conn->rx_thread_active) ++ send_sig(SIGINT, conn->rx_thread, 1); + + atomic_set(&conn->connection_reinstatement, 1); + if (!sleep) { +--- a/drivers/target/iscsi/iscsi_target_login.c ++++ b/drivers/target/iscsi/iscsi_target_login.c +@@ -683,7 +683,52 @@ static void iscsi_post_login_start_timer + iscsit_start_nopin_timer(conn); + } + +-static int iscsi_post_login_handler( ++int iscsit_start_kthreads(struct iscsi_conn *conn) ++{ ++ int ret = 0; ++ ++ spin_lock(&iscsit_global->ts_bitmap_lock); ++ conn->bitmap_id = bitmap_find_free_region(iscsit_global->ts_bitmap, ++ ISCSIT_BITMAP_BITS, get_order(1)); ++ spin_unlock(&iscsit_global->ts_bitmap_lock); ++ ++ if (conn->bitmap_id < 0) { ++ pr_err("bitmap_find_free_region() failed for" ++ " iscsit_start_kthreads()\n"); ++ return -ENOMEM; ++ } ++ ++ conn->tx_thread = kthread_run(iscsi_target_tx_thread, conn, ++ "%s", ISCSI_TX_THREAD_NAME); ++ if (IS_ERR(conn->tx_thread)) { ++ pr_err("Unable to start iscsi_target_tx_thread\n"); ++ ret = PTR_ERR(conn->tx_thread); ++ goto out_bitmap; ++ } ++ conn->tx_thread_active = true; ++ ++ conn->rx_thread = kthread_run(iscsi_target_rx_thread, conn, ++ "%s", ISCSI_RX_THREAD_NAME); ++ if (IS_ERR(conn->rx_thread)) { ++ pr_err("Unable to start iscsi_target_rx_thread\n"); ++ ret = PTR_ERR(conn->rx_thread); ++ goto out_tx; ++ } ++ conn->rx_thread_active = true; ++ ++ return 0; ++out_tx: ++ kthread_stop(conn->tx_thread); ++ conn->tx_thread_active = false; ++out_bitmap: ++ spin_lock(&iscsit_global->ts_bitmap_lock); ++ bitmap_release_region(iscsit_global->ts_bitmap, conn->bitmap_id, ++ get_order(1)); ++ spin_unlock(&iscsit_global->ts_bitmap_lock); ++ return ret; ++} ++ ++int iscsi_post_login_handler( + struct iscsi_np *np, + struct iscsi_conn *conn, + u8 zero_tsih) +@@ -693,7 +738,7 @@ static int iscsi_post_login_handler( + struct se_session *se_sess = sess->se_sess; + struct iscsi_portal_group *tpg = ISCSI_TPG_S(sess); + struct se_portal_group *se_tpg = &tpg->tpg_se_tpg; +- struct iscsi_thread_set *ts; ++ int rc; + + iscsit_inc_conn_usage_count(conn); + +@@ -708,7 +753,6 @@ static int iscsi_post_login_handler( + /* + * SCSI Initiator -> SCSI Target Port Mapping + */ +- ts = iscsi_get_thread_set(); + if (!zero_tsih) { + iscsi_set_session_parameters(sess->sess_ops, + conn->param_list, 0); +@@ -735,9 +779,11 @@ static int iscsi_post_login_handler( + sess->sess_ops->InitiatorName); + spin_unlock_bh(&sess->conn_lock); + +- iscsi_post_login_start_timers(conn); ++ rc = iscsit_start_kthreads(conn); ++ if (rc) ++ return rc; + +- iscsi_activate_thread_set(conn, ts); ++ iscsi_post_login_start_timers(conn); + /* + * Determine CPU mask to ensure connection's RX and TX kthreads + * are scheduled on the same CPU. +@@ -794,8 +840,11 @@ static int iscsi_post_login_handler( + " iSCSI Target Portal Group: %hu\n", tpg->nsessions, tpg->tpgt); + spin_unlock_bh(&se_tpg->session_lock); + ++ rc = iscsit_start_kthreads(conn); ++ if (rc) ++ return rc; ++ + iscsi_post_login_start_timers(conn); +- iscsi_activate_thread_set(conn, ts); + /* + * Determine CPU mask to ensure connection's RX and TX kthreads + * are scheduled on the same CPU. diff --git a/queue-3.10/iser-target-fix-possible-deadlock-in-rdma_cm-connection-error.patch b/queue-3.10/iser-target-fix-possible-deadlock-in-rdma_cm-connection-error.patch new file mode 100644 index 00000000000..d0afd37e1fe --- /dev/null +++ b/queue-3.10/iser-target-fix-possible-deadlock-in-rdma_cm-connection-error.patch @@ -0,0 +1,78 @@ +From 4a579da2586bd3b79b025947ea24ede2bbfede62 Mon Sep 17 00:00:00 2001 +From: Sagi Grimberg +Date: Sun, 29 Mar 2015 15:52:04 +0300 +Subject: iser-target: Fix possible deadlock in RDMA_CM connection error + +From: Sagi Grimberg + +commit 4a579da2586bd3b79b025947ea24ede2bbfede62 upstream. + +Before we reach to connection established we may get an +error event. In this case the core won't teardown this +connection (never established it), so we take care of freeing +it ourselves. + +Signed-off-by: Sagi Grimberg +Signed-off-by: Nicholas Bellinger +Signed-off-by: Greg Kroah-Hartman + + +--- + drivers/infiniband/ulp/isert/ib_isert.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +--- a/drivers/infiniband/ulp/isert/ib_isert.c ++++ b/drivers/infiniband/ulp/isert/ib_isert.c +@@ -202,7 +202,7 @@ fail: + static void + isert_free_rx_descriptors(struct isert_conn *isert_conn) + { +- struct ib_device *ib_dev = isert_conn->conn_cm_id->device; ++ struct ib_device *ib_dev = isert_conn->conn_device->ib_device; + struct iser_rx_desc *rx_desc; + int i; + +@@ -527,14 +527,15 @@ out: + static void + isert_connect_release(struct isert_conn *isert_conn) + { +- struct ib_device *ib_dev = isert_conn->conn_cm_id->device; + struct isert_device *device = isert_conn->conn_device; + int cq_index; ++ struct ib_device *ib_dev = device->ib_device; + + pr_debug("Entering isert_connect_release(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + + isert_free_rx_descriptors(isert_conn); +- rdma_destroy_id(isert_conn->conn_cm_id); ++ if (isert_conn->conn_cm_id) ++ rdma_destroy_id(isert_conn->conn_cm_id); + + if (isert_conn->conn_qp) { + cq_index = ((struct isert_cq_desc *) +@@ -689,12 +690,15 @@ isert_disconnected_handler(struct rdma_c + return 0; + } + +-static void ++static int + isert_connect_error(struct rdma_cm_id *cma_id) + { + struct isert_conn *isert_conn = cma_id->qp->qp_context; + ++ isert_conn->conn_cm_id = NULL; + isert_put_conn(isert_conn); ++ ++ return -1; + } + + static int +@@ -724,7 +728,7 @@ isert_cma_handler(struct rdma_cm_id *cma + case RDMA_CM_EVENT_REJECTED: /* FALLTHRU */ + case RDMA_CM_EVENT_UNREACHABLE: /* FALLTHRU */ + case RDMA_CM_EVENT_CONNECT_ERROR: +- isert_connect_error(cma_id); ++ ret = isert_connect_error(cma_id); + break; + default: + pr_err("Unhandled RDMA CMA event: %d\n", event->event); diff --git a/queue-3.10/iser-target-release-stale-iser-connections.patch b/queue-3.10/iser-target-release-stale-iser-connections.patch new file mode 100644 index 00000000000..e2e294ae1f8 --- /dev/null +++ b/queue-3.10/iser-target-release-stale-iser-connections.patch @@ -0,0 +1,93 @@ +From 2f1b6b7d9a815f341b18dfd26a363f37d4d3c96a Mon Sep 17 00:00:00 2001 +From: Sagi Grimberg +Date: Thu, 4 Jun 2015 19:49:20 +0300 +Subject: iser-target: release stale iser connections + +From: Sagi Grimberg + +commit 2f1b6b7d9a815f341b18dfd26a363f37d4d3c96a upstream. + +When receiving a new iser connect request we serialize +the pending requests by adding the newly created iser connection +to the np accept list and let the login thread process the connect +request one by one (np_accept_wait). + +In case we received a disconnect request before the iser_conn +has begun processing (still linked in np_accept_list) we should +detach it from the list and clean it up and not have the login +thread process a stale connection. We do it only when the connection +state is not already terminating (initiator driven disconnect) as +this might lead us to access np_accept_mutex after the np was released +in live shutdown scenarios. + +Signed-off-by: Sagi Grimberg +Signed-off-by: Jenny Falkovich +Signed-off-by: Nicholas Bellinger +Signed-off-by: Greg Kroah-Hartman + + +--- + drivers/infiniband/ulp/isert/ib_isert.c | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +--- a/drivers/infiniband/ulp/isert/ib_isert.c ++++ b/drivers/infiniband/ulp/isert/ib_isert.c +@@ -49,6 +49,8 @@ static int + isert_rdma_accept(struct isert_conn *isert_conn); + struct rdma_cm_id *isert_setup_id(struct isert_np *isert_np); + ++static void isert_release_work(struct work_struct *work); ++ + static void + isert_qp_event_callback(struct ib_event *e, void *context) + { +@@ -432,6 +434,7 @@ isert_connect_request(struct rdma_cm_id + init_completion(&isert_conn->conn_wait_comp_err); + kref_init(&isert_conn->conn_kref); + mutex_init(&isert_conn->conn_mutex); ++ INIT_WORK(&isert_conn->release_work, isert_release_work); + + isert_conn->conn_cm_id = cma_id; + isert_conn->responder_resources = event->param.conn.responder_resources; +@@ -674,6 +677,7 @@ isert_disconnected_handler(struct rdma_c + { + struct isert_np *isert_np = cma_id->context; + struct isert_conn *isert_conn; ++ bool terminating = false; + + if (isert_np->np_cm_id == cma_id) + return isert_np_cma_handler(cma_id->context, event); +@@ -681,12 +685,25 @@ isert_disconnected_handler(struct rdma_c + isert_conn = cma_id->qp->qp_context; + + mutex_lock(&isert_conn->conn_mutex); ++ terminating = (isert_conn->state == ISER_CONN_TERMINATING); + isert_conn_terminate(isert_conn); + mutex_unlock(&isert_conn->conn_mutex); + + pr_info("conn %p completing conn_wait\n", isert_conn); + complete(&isert_conn->conn_wait); + ++ if (terminating) ++ goto out; ++ ++ mutex_lock(&isert_np->np_accept_mutex); ++ if (!list_empty(&isert_conn->conn_accept_node)) { ++ list_del_init(&isert_conn->conn_accept_node); ++ isert_put_conn(isert_conn); ++ queue_work(isert_release_wq, &isert_conn->release_work); ++ } ++ mutex_unlock(&isert_np->np_accept_mutex); ++ ++out: + return 0; + } + +@@ -2422,7 +2439,6 @@ static void isert_wait_conn(struct iscsi + + wait_for_completion(&isert_conn->conn_wait_comp_err); + +- INIT_WORK(&isert_conn->release_work, isert_release_work); + queue_work(isert_release_wq, &isert_conn->release_work); + } + diff --git a/queue-3.10/series b/queue-3.10/series index 81f18946e36..d1370f0c9de 100644 --- a/queue-3.10/series +++ b/queue-3.10/series @@ -67,3 +67,6 @@ btrfs-use-kmem_cache_free-when-freeing-entry-in-inode-cache.patch fuse-initialize-fc-release-before-calling-it.patch crush-fix-a-bug-in-tree-bucket-decode.patch acpica-tables-fix-an-issue-that-facs-initialization-is-performed-twice.patch +iscsi-target-convert-iscsi_thread_set-usage-to-kthread.h.patch +iser-target-fix-possible-deadlock-in-rdma_cm-connection-error.patch +iser-target-release-stale-iser-connections.patch