]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.14-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 31 Jul 2015 00:59:14 +0000 (17:59 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 31 Jul 2015 00:59:14 +0000 (17:59 -0700)
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

queue-3.14/iscsi-target-convert-iscsi_thread_set-usage-to-kthread.h.patch [new file with mode: 0644]
queue-3.14/iser-target-fix-possible-deadlock-in-rdma_cm-connection-error.patch [new file with mode: 0644]
queue-3.14/iser-target-release-stale-iser-connections.patch [new file with mode: 0644]
queue-3.14/series

diff --git a/queue-3.14/iscsi-target-convert-iscsi_thread_set-usage-to-kthread.h.patch b/queue-3.14/iscsi-target-convert-iscsi_thread_set-usage-to-kthread.h.patch
new file mode 100644 (file)
index 0000000..d65c2fa
--- /dev/null
@@ -0,0 +1,463 @@
+From 88dcd2dab5c23b1c9cfc396246d8f476c872f0ca Mon Sep 17 00:00:00 2001
+From: Nicholas Bellinger <nab@linux-iscsi.org>
+Date: Thu, 26 Feb 2015 22:19:15 -0800
+Subject: iscsi-target: Convert iscsi_thread_set usage to kthread.h
+
+From: Nicholas Bellinger <nab@linux-iscsi.org>
+
+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 <sagig@mellanox.com>
+Tested-by: Sagi Grimberg <sagig@mellanox.com>
+Cc: Slava Shwartsman <valyushash@gmail.com>
+Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+
+---
+ 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 |   59 +++++++++++++++--
+ 4 files changed, 114 insertions(+), 69 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_qr_cache = kmem_cache_create("lio_qr_cache",
+@@ -553,7 +550,7 @@ static int __init iscsi_target_init_modu
+       if (!lio_qr_cache) {
+               pr_err("nable to kmem_cache_create() for"
+                               " lio_qr_cache\n");
+-              goto ts_out2;
++              goto bitmap_out;
+       }
+       lio_dr_cache = kmem_cache_create("lio_dr_cache",
+@@ -597,10 +594,8 @@ dr_out:
+       kmem_cache_destroy(lio_dr_cache);
+ qr_out:
+       kmem_cache_destroy(lio_qr_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:
+@@ -610,8 +605,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_qr_cache);
+@@ -621,6 +614,7 @@ static void __exit iscsi_target_cleanup_
+       iscsi_target_deregister_configfs();
++      vfree(iscsit_global->ts_bitmap);
+       kfree(iscsit_global);
+ }
+@@ -3653,17 +3647,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);
+@@ -3855,7 +3848,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:
+@@ -3883,8 +3876,6 @@ check_rsp_state:
+ err:
+       return -1;
+-restart:
+-      return -EAGAIN;
+ }
+ static int iscsit_handle_response_queue(struct iscsi_conn *conn)
+@@ -3911,21 +3902,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
+@@ -3934,11 +3917,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:
+@@ -3949,15 +3930,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;
+ }
+@@ -4046,8 +4026,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
+@@ -4055,11 +4034,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;
+@@ -4069,7 +4043,7 @@ restart:
+               if (rc < 0)
+                       goto transport_err;
+-              goto out;
++              goto transport_err;
+       }
+       while (!kthread_should_stop()) {
+@@ -4145,8 +4119,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;
+ }
+@@ -4208,7 +4180,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);
+@@ -4487,15 +4476,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);
+ }
+@@ -4503,13 +4490,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
+@@ -601,6 +601,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;
+@@ -869,10 +874,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
+@@ -864,7 +864,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);
+@@ -889,10 +892,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
+@@ -681,6 +681,51 @@ static void iscsi_post_login_start_timer
+               iscsit_start_nopin_timer(conn);
+ }
++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,
+@@ -691,7 +736,7 @@ int iscsi_post_login_handler(
+       struct se_session *se_sess = sess->se_sess;
+       struct iscsi_portal_group *tpg = sess->tpg;
+       struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
+-      struct iscsi_thread_set *ts;
++      int rc;
+       iscsit_inc_conn_usage_count(conn);
+@@ -706,7 +751,6 @@ 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);
+@@ -733,9 +777,11 @@ 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.
+@@ -792,8 +838,11 @@ 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.14/iser-target-fix-possible-deadlock-in-rdma_cm-connection-error.patch b/queue-3.14/iser-target-fix-possible-deadlock-in-rdma_cm-connection-error.patch
new file mode 100644 (file)
index 0000000..76cac71
--- /dev/null
@@ -0,0 +1,81 @@
+From 4a579da2586bd3b79b025947ea24ede2bbfede62 Mon Sep 17 00:00:00 2001
+From: Sagi Grimberg <sagig@mellanox.com>
+Date: Sun, 29 Mar 2015 15:52:04 +0300
+Subject: iser-target: Fix possible deadlock in RDMA_CM connection error
+
+From: Sagi Grimberg <sagig@mellanox.com>
+
+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 <sagig@mellanox.com>
+Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+
+---
+ 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
+@@ -206,7 +206,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;
+@@ -647,9 +647,9 @@ 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");
+@@ -657,7 +657,8 @@ isert_connect_release(struct isert_conn
+               isert_conn_free_fastreg_pool(isert_conn);
+       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 *)
+@@ -815,12 +816,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
+@@ -850,7 +854,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.14/iser-target-release-stale-iser-connections.patch b/queue-3.14/iser-target-release-stale-iser-connections.patch
new file mode 100644 (file)
index 0000000..58b2bb0
--- /dev/null
@@ -0,0 +1,93 @@
+From 2f1b6b7d9a815f341b18dfd26a363f37d4d3c96a Mon Sep 17 00:00:00 2001
+From: Sagi Grimberg <sagig@mellanox.com>
+Date: Thu, 4 Jun 2015 19:49:20 +0300
+Subject: iser-target: release stale iser connections
+
+From: Sagi Grimberg <sagig@mellanox.com>
+
+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 <sagig@mellanox.com>
+Signed-off-by: Jenny Falkovich <jennyf@mellanox.com>
+Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+
+---
+ 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
+@@ -59,6 +59,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)
+ {
+@@ -534,6 +536,7 @@ isert_connect_request(struct rdma_cm_id
+       mutex_init(&isert_conn->conn_mutex);
+       spin_lock_init(&isert_conn->conn_lock);
+       INIT_LIST_HEAD(&isert_conn->conn_fr_pool);
++      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;
+@@ -800,6 +803,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);
+@@ -807,12 +811,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;
+ }
+@@ -2948,7 +2965,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);
+ }
index b85d829c0385c053ed51a3e7433298ca2d9eb9ba..f5e2838892c472ebaf1fc42f186ffc946ac56b12 100644 (file)
@@ -95,3 +95,6 @@ btrfs-fix-memory-leak-in-the-extent_same-ioctl.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