]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.13-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 20 Mar 2014 05:21:56 +0000 (22:21 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 20 Mar 2014 05:21:56 +0000 (22:21 -0700)
added patches:
iscsi-iser-target-fix-isert_conn-state-hung-shutdown-issues.patch
iscsi-iser-target-use-list_del_init-for-i_conn_node.patch
iser-target-fix-command-leak-for-tx_desc-comp_llnode_batch.patch
iser-target-fix-post_send_buf_count-for-rdma-read-write.patch
iser-target-ignore-completions-for-frwrs-in-isert_cq_tx_work.patch

queue-3.13/iscsi-iser-target-fix-isert_conn-state-hung-shutdown-issues.patch [new file with mode: 0644]
queue-3.13/iscsi-iser-target-use-list_del_init-for-i_conn_node.patch [new file with mode: 0644]
queue-3.13/iser-target-fix-command-leak-for-tx_desc-comp_llnode_batch.patch [new file with mode: 0644]
queue-3.13/iser-target-fix-post_send_buf_count-for-rdma-read-write.patch [new file with mode: 0644]
queue-3.13/iser-target-ignore-completions-for-frwrs-in-isert_cq_tx_work.patch [new file with mode: 0644]
queue-3.13/series

diff --git a/queue-3.13/iscsi-iser-target-fix-isert_conn-state-hung-shutdown-issues.patch b/queue-3.13/iscsi-iser-target-fix-isert_conn-state-hung-shutdown-issues.patch
new file mode 100644 (file)
index 0000000..9d3982b
--- /dev/null
@@ -0,0 +1,277 @@
+From defd884845297fd5690594bfe89656b01f16d87e Mon Sep 17 00:00:00 2001
+From: Nicholas Bellinger <nab@linux-iscsi.org>
+Date: Mon, 3 Feb 2014 12:54:39 -0800
+Subject: iscsi/iser-target: Fix isert_conn->state hung shutdown issues
+
+From: Nicholas Bellinger <nab@linux-iscsi.org>
+
+commit defd884845297fd5690594bfe89656b01f16d87e upstream.
+
+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>
+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 |  106 ++++++++++++++------------------
+ drivers/infiniband/ulp/isert/ib_isert.h |    4 -
+ drivers/target/iscsi/iscsi_target.c     |    4 +
+ include/target/iscsi/iscsi_transport.h  |    1 
+ 4 files changed, 55 insertions(+), 60 deletions(-)
+
+--- a/drivers/infiniband/ulp/isert/ib_isert.c
++++ b/drivers/infiniband/ulp/isert/ib_isert.c
+@@ -497,8 +497,8 @@ isert_connect_request(struct rdma_cm_id
+       isert_conn->state = ISER_CONN_INIT;
+       INIT_LIST_HEAD(&isert_conn->conn_accept_node);
+       init_completion(&isert_conn->conn_login_comp);
+-      init_waitqueue_head(&isert_conn->conn_wait);
+-      init_waitqueue_head(&isert_conn->conn_wait_comp_err);
++      init_completion(&isert_conn->conn_wait);
++      init_completion(&isert_conn->conn_wait_comp_err);
+       kref_init(&isert_conn->conn_kref);
+       kref_get(&isert_conn->conn_kref);
+       mutex_init(&isert_conn->conn_mutex);
+@@ -671,11 +671,11 @@ isert_disconnect_work(struct work_struct
+       pr_debug("isert_disconnect_work(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
+       mutex_lock(&isert_conn->conn_mutex);
+-      isert_conn->state = ISER_CONN_DOWN;
++      if (isert_conn->state == ISER_CONN_UP)
++              isert_conn->state = ISER_CONN_TERMINATING;
+       if (isert_conn->post_recv_buf_count == 0 &&
+           atomic_read(&isert_conn->post_send_buf_count) == 0) {
+-              pr_debug("Calling wake_up(&isert_conn->conn_wait);\n");
+               mutex_unlock(&isert_conn->conn_mutex);
+               goto wake_up;
+       }
+@@ -695,7 +695,7 @@ isert_disconnect_work(struct work_struct
+       mutex_unlock(&isert_conn->conn_mutex);
+ wake_up:
+-      wake_up(&isert_conn->conn_wait);
++      complete(&isert_conn->conn_wait);
+       isert_put_conn(isert_conn);
+ }
+@@ -1572,7 +1572,7 @@ isert_do_control_comp(struct work_struct
+               pr_debug("Calling iscsit_logout_post_handler >>>>>>>>>>>>>>\n");
+               /*
+                * Call atomic_dec(&isert_conn->post_send_buf_count)
+-               * from isert_free_conn()
++               * from isert_wait_conn()
+                */
+               isert_conn->logout_posted = true;
+               iscsit_logout_post_handler(cmd, cmd->conn);
+@@ -1674,31 +1674,39 @@ isert_send_completion(struct iser_tx_des
+ }
+ static void
+-isert_cq_comp_err(struct iser_tx_desc *tx_desc, struct isert_conn *isert_conn)
++isert_cq_tx_comp_err(struct iser_tx_desc *tx_desc, struct isert_conn *isert_conn)
+ {
+       struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
++      struct isert_cmd *isert_cmd = tx_desc->isert_cmd;
++
++      if (!isert_cmd)
++              isert_unmap_tx_desc(tx_desc, ib_dev);
++      else
++              isert_completion_put(tx_desc, isert_cmd, ib_dev);
++}
++
++static void
++isert_cq_rx_comp_err(struct isert_conn *isert_conn)
++{
++      struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
++      struct iscsi_conn *conn = isert_conn->conn;
+-      if (tx_desc) {
+-              struct isert_cmd *isert_cmd = tx_desc->isert_cmd;
++      if (isert_conn->post_recv_buf_count)
++              return;
+-              if (!isert_cmd)
+-                      isert_unmap_tx_desc(tx_desc, ib_dev);
+-              else
+-                      isert_completion_put(tx_desc, isert_cmd, ib_dev);
++      if (conn->sess) {
++              target_sess_cmd_list_set_waiting(conn->sess->se_sess);
++              target_wait_for_sess_cmds(conn->sess->se_sess);
+       }
+-      if (isert_conn->post_recv_buf_count == 0 &&
+-          atomic_read(&isert_conn->post_send_buf_count) == 0) {
+-              pr_debug("isert_cq_comp_err >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
+-              pr_debug("Calling wake_up from isert_cq_comp_err\n");
++      while (atomic_read(&isert_conn->post_send_buf_count))
++              msleep(3000);
+-              mutex_lock(&isert_conn->conn_mutex);
+-              if (isert_conn->state != ISER_CONN_DOWN)
+-                      isert_conn->state = ISER_CONN_TERMINATING;
+-              mutex_unlock(&isert_conn->conn_mutex);
++      mutex_lock(&isert_conn->conn_mutex);
++      isert_conn->state = ISER_CONN_DOWN;
++      mutex_unlock(&isert_conn->conn_mutex);
+-              wake_up(&isert_conn->conn_wait_comp_err);
+-      }
++      complete(&isert_conn->conn_wait_comp_err);
+ }
+ static void
+@@ -1723,8 +1731,9 @@ isert_cq_tx_work(struct work_struct *wor
+                       pr_debug("TX wc.status != IB_WC_SUCCESS >>>>>>>>>>>>>>\n");
+                       pr_debug("TX wc.status: 0x%08x\n", wc.status);
+                       pr_debug("TX wc.vendor_err: 0x%08x\n", wc.vendor_err);
++
+                       atomic_dec(&isert_conn->post_send_buf_count);
+-                      isert_cq_comp_err(tx_desc, isert_conn);
++                      isert_cq_tx_comp_err(tx_desc, isert_conn);
+               }
+       }
+@@ -1767,7 +1776,7 @@ isert_cq_rx_work(struct work_struct *wor
+                                        wc.vendor_err);
+                       }
+                       isert_conn->post_recv_buf_count--;
+-                      isert_cq_comp_err(NULL, isert_conn);
++                      isert_cq_rx_comp_err(isert_conn);
+               }
+       }
+@@ -2689,22 +2698,11 @@ isert_free_np(struct iscsi_np *np)
+       kfree(isert_np);
+ }
+-static int isert_check_state(struct isert_conn *isert_conn, int state)
+-{
+-      int ret;
+-
+-      mutex_lock(&isert_conn->conn_mutex);
+-      ret = (isert_conn->state == state);
+-      mutex_unlock(&isert_conn->conn_mutex);
+-
+-      return ret;
+-}
+-
+-static void isert_free_conn(struct iscsi_conn *conn)
++static void isert_wait_conn(struct iscsi_conn *conn)
+ {
+       struct isert_conn *isert_conn = conn->context;
+-      pr_debug("isert_free_conn: Starting \n");
++      pr_debug("isert_wait_conn: Starting \n");
+       /*
+        * Decrement post_send_buf_count for special case when called
+        * from isert_do_control_comp() -> iscsit_logout_post_handler()
+@@ -2714,38 +2712,29 @@ static void isert_free_conn(struct iscsi
+               atomic_dec(&isert_conn->post_send_buf_count);
+       if (isert_conn->conn_cm_id && isert_conn->state != ISER_CONN_DOWN) {
+-              pr_debug("Calling rdma_disconnect from isert_free_conn\n");
++              pr_debug("Calling rdma_disconnect from isert_wait_conn\n");
+               rdma_disconnect(isert_conn->conn_cm_id);
+       }
+       /*
+        * Only wait for conn_wait_comp_err if the isert_conn made it
+        * into full feature phase..
+        */
+-      if (isert_conn->state == ISER_CONN_UP) {
+-              pr_debug("isert_free_conn: Before wait_event comp_err %d\n",
+-                       isert_conn->state);
+-              mutex_unlock(&isert_conn->conn_mutex);
+-
+-              wait_event(isert_conn->conn_wait_comp_err,
+-                        (isert_check_state(isert_conn, ISER_CONN_TERMINATING)));
+-
+-              wait_event(isert_conn->conn_wait,
+-                        (isert_check_state(isert_conn, ISER_CONN_DOWN)));
+-
+-              isert_put_conn(isert_conn);
+-              return;
+-      }
+       if (isert_conn->state == ISER_CONN_INIT) {
+               mutex_unlock(&isert_conn->conn_mutex);
+-              isert_put_conn(isert_conn);
+               return;
+       }
+-      pr_debug("isert_free_conn: wait_event conn_wait %d\n",
+-               isert_conn->state);
++      if (isert_conn->state == ISER_CONN_UP)
++              isert_conn->state = ISER_CONN_TERMINATING;
+       mutex_unlock(&isert_conn->conn_mutex);
+-      wait_event(isert_conn->conn_wait,
+-                (isert_check_state(isert_conn, ISER_CONN_DOWN)));
++      wait_for_completion(&isert_conn->conn_wait_comp_err);
++
++      wait_for_completion(&isert_conn->conn_wait);
++}
++
++static void isert_free_conn(struct iscsi_conn *conn)
++{
++      struct isert_conn *isert_conn = conn->context;
+       isert_put_conn(isert_conn);
+ }
+@@ -2758,6 +2747,7 @@ static struct iscsit_transport iser_targ
+       .iscsit_setup_np        = isert_setup_np,
+       .iscsit_accept_np       = isert_accept_np,
+       .iscsit_free_np         = isert_free_np,
++      .iscsit_wait_conn       = isert_wait_conn,
+       .iscsit_free_conn       = isert_free_conn,
+       .iscsit_get_login_rx    = isert_get_login_rx,
+       .iscsit_put_login_tx    = isert_put_login_tx,
+--- a/drivers/infiniband/ulp/isert/ib_isert.h
++++ b/drivers/infiniband/ulp/isert/ib_isert.h
+@@ -116,8 +116,8 @@ struct isert_conn {
+       struct isert_device     *conn_device;
+       struct work_struct      conn_logout_work;
+       struct mutex            conn_mutex;
+-      wait_queue_head_t       conn_wait;
+-      wait_queue_head_t       conn_wait_comp_err;
++      struct completion       conn_wait;
++      struct completion       conn_wait_comp_err;
+       struct kref             conn_kref;
+       struct list_head        conn_frwr_pool;
+       int                     conn_frwr_pool_size;
+--- a/drivers/target/iscsi/iscsi_target.c
++++ b/drivers/target/iscsi/iscsi_target.c
+@@ -4196,6 +4196,10 @@ int iscsit_close_connection(
+       iscsit_stop_timers_for_cmds(conn);
+       iscsit_stop_nopin_response_timer(conn);
+       iscsit_stop_nopin_timer(conn);
++
++      if (conn->conn_transport->iscsit_wait_conn)
++              conn->conn_transport->iscsit_wait_conn(conn);
++
+       iscsit_free_queue_reqs_for_conn(conn);
+       /*
+--- a/include/target/iscsi/iscsi_transport.h
++++ b/include/target/iscsi/iscsi_transport.h
+@@ -12,6 +12,7 @@ struct iscsit_transport {
+       int (*iscsit_setup_np)(struct iscsi_np *, struct __kernel_sockaddr_storage *);
+       int (*iscsit_accept_np)(struct iscsi_np *, struct iscsi_conn *);
+       void (*iscsit_free_np)(struct iscsi_np *);
++      void (*iscsit_wait_conn)(struct iscsi_conn *);
+       void (*iscsit_free_conn)(struct iscsi_conn *);
+       int (*iscsit_get_login_rx)(struct iscsi_conn *, struct iscsi_login *);
+       int (*iscsit_put_login_tx)(struct iscsi_conn *, struct iscsi_login *, u32);
diff --git a/queue-3.13/iscsi-iser-target-use-list_del_init-for-i_conn_node.patch b/queue-3.13/iscsi-iser-target-use-list_del_init-for-i_conn_node.patch
new file mode 100644 (file)
index 0000000..9e8181d
--- /dev/null
@@ -0,0 +1,159 @@
+From 5159d763f60af693a3fcec45dce2021f66e528a4 Mon Sep 17 00:00:00 2001
+From: Nicholas Bellinger <nab@linux-iscsi.org>
+Date: Mon, 3 Feb 2014 12:53:51 -0800
+Subject: iscsi/iser-target: Use list_del_init for ->i_conn_node
+
+From: Nicholas Bellinger <nab@linux-iscsi.org>
+
+commit 5159d763f60af693a3fcec45dce2021f66e528a4 upstream.
+
+There are a handful of uses of list_empty() for cmd->i_conn_node
+within iser-target code that expect to return false once a cmd
+has been removed from the per connect list.
+
+This patch changes all uses of list_del -> list_del_init in order
+to ensure that list_empty() returns false as expected.
+
+Acked-by: Sagi Grimberg <sagig@mellanox.com>
+Cc: Or Gerlitz <ogerlitz@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  |    6 +++---
+ drivers/target/iscsi/iscsi_target.c      |    6 +++---
+ drivers/target/iscsi/iscsi_target_erl2.c |   16 ++++++++--------
+ 3 files changed, 14 insertions(+), 14 deletions(-)
+
+--- a/drivers/infiniband/ulp/isert/ib_isert.c
++++ b/drivers/infiniband/ulp/isert/ib_isert.c
+@@ -1447,7 +1447,7 @@ isert_put_cmd(struct isert_cmd *isert_cm
+       case ISCSI_OP_SCSI_CMD:
+               spin_lock_bh(&conn->cmd_lock);
+               if (!list_empty(&cmd->i_conn_node))
+-                      list_del(&cmd->i_conn_node);
++                      list_del_init(&cmd->i_conn_node);
+               spin_unlock_bh(&conn->cmd_lock);
+               if (cmd->data_direction == DMA_TO_DEVICE)
+@@ -1459,7 +1459,7 @@ isert_put_cmd(struct isert_cmd *isert_cm
+       case ISCSI_OP_SCSI_TMFUNC:
+               spin_lock_bh(&conn->cmd_lock);
+               if (!list_empty(&cmd->i_conn_node))
+-                      list_del(&cmd->i_conn_node);
++                      list_del_init(&cmd->i_conn_node);
+               spin_unlock_bh(&conn->cmd_lock);
+               transport_generic_free_cmd(&cmd->se_cmd, 0);
+@@ -1469,7 +1469,7 @@ isert_put_cmd(struct isert_cmd *isert_cm
+       case ISCSI_OP_TEXT:
+               spin_lock_bh(&conn->cmd_lock);
+               if (!list_empty(&cmd->i_conn_node))
+-                      list_del(&cmd->i_conn_node);
++                      list_del_init(&cmd->i_conn_node);
+               spin_unlock_bh(&conn->cmd_lock);
+               /*
+--- a/drivers/target/iscsi/iscsi_target.c
++++ b/drivers/target/iscsi/iscsi_target.c
+@@ -785,7 +785,7 @@ static void iscsit_ack_from_expstatsn(st
+       spin_unlock_bh(&conn->cmd_lock);
+       list_for_each_entry_safe(cmd, cmd_p, &ack_list, i_conn_node) {
+-              list_del(&cmd->i_conn_node);
++              list_del_init(&cmd->i_conn_node);
+               iscsit_free_cmd(cmd, false);
+       }
+ }
+@@ -3708,7 +3708,7 @@ iscsit_immediate_queue(struct iscsi_conn
+               break;
+       case ISTATE_REMOVE:
+               spin_lock_bh(&conn->cmd_lock);
+-              list_del(&cmd->i_conn_node);
++              list_del_init(&cmd->i_conn_node);
+               spin_unlock_bh(&conn->cmd_lock);
+               iscsit_free_cmd(cmd, false);
+@@ -4151,7 +4151,7 @@ static void iscsit_release_commands_from
+       spin_lock_bh(&conn->cmd_lock);
+       list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_conn_node) {
+-              list_del(&cmd->i_conn_node);
++              list_del_init(&cmd->i_conn_node);
+               spin_unlock_bh(&conn->cmd_lock);
+               iscsit_increment_maxcmdsn(cmd, sess);
+--- a/drivers/target/iscsi/iscsi_target_erl2.c
++++ b/drivers/target/iscsi/iscsi_target_erl2.c
+@@ -138,7 +138,7 @@ void iscsit_free_connection_recovery_ent
+               list_for_each_entry_safe(cmd, cmd_tmp,
+                               &cr->conn_recovery_cmd_list, i_conn_node) {
+-                      list_del(&cmd->i_conn_node);
++                      list_del_init(&cmd->i_conn_node);
+                       cmd->conn = NULL;
+                       spin_unlock(&cr->conn_recovery_cmd_lock);
+                       iscsit_free_cmd(cmd, true);
+@@ -160,7 +160,7 @@ void iscsit_free_connection_recovery_ent
+               list_for_each_entry_safe(cmd, cmd_tmp,
+                               &cr->conn_recovery_cmd_list, i_conn_node) {
+-                      list_del(&cmd->i_conn_node);
++                      list_del_init(&cmd->i_conn_node);
+                       cmd->conn = NULL;
+                       spin_unlock(&cr->conn_recovery_cmd_lock);
+                       iscsit_free_cmd(cmd, true);
+@@ -216,7 +216,7 @@ int iscsit_remove_cmd_from_connection_re
+       }
+       cr = cmd->cr;
+-      list_del(&cmd->i_conn_node);
++      list_del_init(&cmd->i_conn_node);
+       return --cr->cmd_count;
+ }
+@@ -297,7 +297,7 @@ int iscsit_discard_unacknowledged_ooo_cm
+               if (!(cmd->cmd_flags & ICF_OOO_CMDSN))
+                       continue;
+-              list_del(&cmd->i_conn_node);
++              list_del_init(&cmd->i_conn_node);
+               spin_unlock_bh(&conn->cmd_lock);
+               iscsit_free_cmd(cmd, true);
+@@ -335,7 +335,7 @@ int iscsit_prepare_cmds_for_realligance(
+       /*
+        * Only perform connection recovery on ISCSI_OP_SCSI_CMD or
+        * ISCSI_OP_NOOP_OUT opcodes.  For all other opcodes call
+-       * list_del(&cmd->i_conn_node); to release the command to the
++       * list_del_init(&cmd->i_conn_node); to release the command to the
+        * session pool and remove it from the connection's list.
+        *
+        * Also stop the DataOUT timer, which will be restarted after
+@@ -351,7 +351,7 @@ int iscsit_prepare_cmds_for_realligance(
+                               " CID: %hu\n", cmd->iscsi_opcode,
+                               cmd->init_task_tag, cmd->cmd_sn, conn->cid);
+-                      list_del(&cmd->i_conn_node);
++                      list_del_init(&cmd->i_conn_node);
+                       spin_unlock_bh(&conn->cmd_lock);
+                       iscsit_free_cmd(cmd, true);
+                       spin_lock_bh(&conn->cmd_lock);
+@@ -371,7 +371,7 @@ int iscsit_prepare_cmds_for_realligance(
+                */
+               if (!(cmd->cmd_flags & ICF_OOO_CMDSN) && !cmd->immediate_cmd &&
+                    iscsi_sna_gte(cmd->cmd_sn, conn->sess->exp_cmd_sn)) {
+-                      list_del(&cmd->i_conn_node);
++                      list_del_init(&cmd->i_conn_node);
+                       spin_unlock_bh(&conn->cmd_lock);
+                       iscsit_free_cmd(cmd, true);
+                       spin_lock_bh(&conn->cmd_lock);
+@@ -393,7 +393,7 @@ int iscsit_prepare_cmds_for_realligance(
+               cmd->sess = conn->sess;
+-              list_del(&cmd->i_conn_node);
++              list_del_init(&cmd->i_conn_node);
+               spin_unlock_bh(&conn->cmd_lock);
+               iscsit_free_all_datain_reqs(cmd);
diff --git a/queue-3.13/iser-target-fix-command-leak-for-tx_desc-comp_llnode_batch.patch b/queue-3.13/iser-target-fix-command-leak-for-tx_desc-comp_llnode_batch.patch
new file mode 100644 (file)
index 0000000..cb231ef
--- /dev/null
@@ -0,0 +1,150 @@
+From ebbe442183b7b8192c963266f1c89048fefc63a5 Mon Sep 17 00:00:00 2001
+From: Nicholas Bellinger <nab@linux-iscsi.org>
+Date: Sun, 2 Mar 2014 14:51:12 -0800
+Subject: iser-target: Fix command leak for tx_desc->comp_llnode_batch
+
+From: Nicholas Bellinger <nab@linux-iscsi.org>
+
+commit ebbe442183b7b8192c963266f1c89048fefc63a5 upstream.
+
+This patch addresses a number of active I/O shutdown issues
+related to isert_cmd descriptors being leaked that are part
+of a completion interrupt coalescing batch.
+
+This includes adding logic in isert_cq_tx_comp_err() to
+drain any associated tx_desc->comp_llnode_batch, as well
+as isert_cq_drain_comp_llist() to drain any associated
+isert_conn->conn_comp_llist.
+
+Also, set tx_desc->llnode_active in isert_init_send_wr()
+in order to determine when work requests need to be skipped
+in isert_cq_tx_work() exception path code.
+
+Finally, update isert_init_send_wr() to only allow interrupt
+coalescing when ISER_CONN_UP.
+
+Acked-by: Sagi Grimberg <sagig@mellanox.com>
+Cc: Or Gerlitz <ogerlitz@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 |   50 ++++++++++++++++++++++++++++----
+ drivers/infiniband/ulp/isert/ib_isert.h |    2 -
+ 2 files changed, 46 insertions(+), 6 deletions(-)
+
+--- a/drivers/infiniband/ulp/isert/ib_isert.c
++++ b/drivers/infiniband/ulp/isert/ib_isert.c
+@@ -502,7 +502,6 @@ isert_connect_request(struct rdma_cm_id
+       kref_init(&isert_conn->conn_kref);
+       kref_get(&isert_conn->conn_kref);
+       mutex_init(&isert_conn->conn_mutex);
+-      mutex_init(&isert_conn->conn_comp_mutex);
+       spin_lock_init(&isert_conn->conn_lock);
+       cma_id->context = isert_conn;
+@@ -871,16 +870,17 @@ isert_init_send_wr(struct isert_conn *is
+        * Coalesce send completion interrupts by only setting IB_SEND_SIGNALED
+        * bit for every ISERT_COMP_BATCH_COUNT number of ib_post_send() calls.
+        */
+-      mutex_lock(&isert_conn->conn_comp_mutex);
+-      if (coalesce &&
++      mutex_lock(&isert_conn->conn_mutex);
++      if (coalesce && isert_conn->state == ISER_CONN_UP &&
+           ++isert_conn->conn_comp_batch < ISERT_COMP_BATCH_COUNT) {
++              tx_desc->llnode_active = true;
+               llist_add(&tx_desc->comp_llnode, &isert_conn->conn_comp_llist);
+-              mutex_unlock(&isert_conn->conn_comp_mutex);
++              mutex_unlock(&isert_conn->conn_mutex);
+               return;
+       }
+       isert_conn->conn_comp_batch = 0;
+       tx_desc->comp_llnode_batch = llist_del_all(&isert_conn->conn_comp_llist);
+-      mutex_unlock(&isert_conn->conn_comp_mutex);
++      mutex_unlock(&isert_conn->conn_mutex);
+       send_wr->send_flags = IB_SEND_SIGNALED;
+ }
+@@ -1676,10 +1676,45 @@ isert_send_completion(struct iser_tx_des
+ }
+ static void
++isert_cq_drain_comp_llist(struct isert_conn *isert_conn, struct ib_device *ib_dev)
++{
++      struct llist_node *llnode;
++      struct isert_rdma_wr *wr;
++      struct iser_tx_desc *t;
++
++      mutex_lock(&isert_conn->conn_mutex);
++      llnode = llist_del_all(&isert_conn->conn_comp_llist);
++      isert_conn->conn_comp_batch = 0;
++      mutex_unlock(&isert_conn->conn_mutex);
++
++      while (llnode) {
++              t = llist_entry(llnode, struct iser_tx_desc, comp_llnode);
++              llnode = llist_next(llnode);
++              wr = &t->isert_cmd->rdma_wr;
++
++              atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
++              isert_completion_put(t, t->isert_cmd, ib_dev);
++      }
++}
++
++static void
+ isert_cq_tx_comp_err(struct iser_tx_desc *tx_desc, struct isert_conn *isert_conn)
+ {
+       struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+       struct isert_cmd *isert_cmd = tx_desc->isert_cmd;
++      struct llist_node *llnode = tx_desc->comp_llnode_batch;
++      struct isert_rdma_wr *wr;
++      struct iser_tx_desc *t;
++
++      while (llnode) {
++              t = llist_entry(llnode, struct iser_tx_desc, comp_llnode);
++              llnode = llist_next(llnode);
++              wr = &t->isert_cmd->rdma_wr;
++
++              atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
++              isert_completion_put(t, t->isert_cmd, ib_dev);
++      }
++      tx_desc->comp_llnode_batch = NULL;
+       if (!isert_cmd)
+               isert_unmap_tx_desc(tx_desc, ib_dev);
+@@ -1696,6 +1731,8 @@ isert_cq_rx_comp_err(struct isert_conn *
+       if (isert_conn->post_recv_buf_count)
+               return;
++      isert_cq_drain_comp_llist(isert_conn, ib_dev);
++
+       if (conn->sess) {
+               target_sess_cmd_list_set_waiting(conn->sess->se_sess);
+               target_wait_for_sess_cmds(conn->sess->se_sess);
+@@ -1735,6 +1772,9 @@ isert_cq_tx_work(struct work_struct *wor
+                       pr_debug("TX wc.vendor_err: 0x%08x\n", wc.vendor_err);
+                       if (wc.wr_id != ISER_FASTREG_LI_WRID) {
++                              if (tx_desc->llnode_active)
++                                      continue;
++
+                               atomic_dec(&isert_conn->post_send_buf_count);
+                               isert_cq_tx_comp_err(tx_desc, isert_conn);
+                       }
+--- a/drivers/infiniband/ulp/isert/ib_isert.h
++++ b/drivers/infiniband/ulp/isert/ib_isert.h
+@@ -46,6 +46,7 @@ struct iser_tx_desc {
+       struct isert_cmd *isert_cmd;
+       struct llist_node *comp_llnode_batch;
+       struct llist_node comp_llnode;
++      bool            llnode_active;
+       struct ib_send_wr send_wr;
+ } __packed;
+@@ -127,7 +128,6 @@ struct isert_conn {
+ #define ISERT_COMP_BATCH_COUNT        8
+       int                     conn_comp_batch;
+       struct llist_head       conn_comp_llist;
+-      struct mutex            conn_comp_mutex;
+ };
+ #define ISERT_MAX_CQ 64
diff --git a/queue-3.13/iser-target-fix-post_send_buf_count-for-rdma-read-write.patch b/queue-3.13/iser-target-fix-post_send_buf_count-for-rdma-read-write.patch
new file mode 100644 (file)
index 0000000..bbd422a
--- /dev/null
@@ -0,0 +1,98 @@
+From b6b87a1df604678ed1be40158080db012a99ccca Mon Sep 17 00:00:00 2001
+From: Nicholas Bellinger <nab@linux-iscsi.org>
+Date: Thu, 27 Feb 2014 09:05:03 -0800
+Subject: iser-target: Fix post_send_buf_count for RDMA READ/WRITE
+
+From: Nicholas Bellinger <nab@linux-iscsi.org>
+
+commit b6b87a1df604678ed1be40158080db012a99ccca upstream.
+
+This patch fixes the incorrect setting of ->post_send_buf_count
+related to RDMA WRITEs + READs where isert_rdma_rw->send_wr_num
+was not being taken into account.
+
+This includes incrementing ->post_send_buf_count within
+isert_put_datain() + isert_get_dataout(), decrementing within
+__isert_send_completion() + isert_response_completion(), and
+clearing wr->send_wr_num within isert_completion_rdma_read()
+
+This is necessary because even though IB_SEND_SIGNALED is
+not set for RDMA WRITEs + READs, during a QP failure event
+the work requests will be returned with exception status
+from the TX completion queue.
+
+Acked-by: Sagi Grimberg <sagig@mellanox.com>
+Cc: Or Gerlitz <ogerlitz@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, 8 insertions(+), 6 deletions(-)
+
+--- a/drivers/infiniband/ulp/isert/ib_isert.c
++++ b/drivers/infiniband/ulp/isert/ib_isert.c
+@@ -1532,6 +1532,7 @@ isert_completion_rdma_read(struct iser_t
+       iscsit_stop_dataout_timer(cmd);
+       device->unreg_rdma_mem(isert_cmd, isert_conn);
+       cmd->write_data_done = wr->cur_rdma_length;
++      wr->send_wr_num = 0;
+       pr_debug("Cmd: %p RDMA_READ comp calling execute_cmd\n", isert_cmd);
+       spin_lock_bh(&cmd->istate_lock);
+@@ -1596,6 +1597,7 @@ isert_response_completion(struct iser_tx
+                         struct ib_device *ib_dev)
+ {
+       struct iscsi_cmd *cmd = isert_cmd->iscsi_cmd;
++      struct isert_rdma_wr *wr = &isert_cmd->rdma_wr;
+       if (cmd->i_state == ISTATE_SEND_TASKMGTRSP ||
+           cmd->i_state == ISTATE_SEND_LOGOUTRSP ||
+@@ -1607,7 +1609,7 @@ isert_response_completion(struct iser_tx
+               queue_work(isert_comp_wq, &isert_cmd->comp_work);
+               return;
+       }
+-      atomic_dec(&isert_conn->post_send_buf_count);
++      atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
+       cmd->i_state = ISTATE_SENT_STATUS;
+       isert_completion_put(tx_desc, isert_cmd, ib_dev);
+@@ -1645,7 +1647,7 @@ __isert_send_completion(struct iser_tx_d
+       case ISER_IB_RDMA_READ:
+               pr_debug("isert_send_completion: Got ISER_IB_RDMA_READ:\n");
+-              atomic_dec(&isert_conn->post_send_buf_count);
++              atomic_sub(wr->send_wr_num, &isert_conn->post_send_buf_count);
+               isert_completion_rdma_read(tx_desc, isert_cmd);
+               break;
+       default:
+@@ -2377,12 +2379,12 @@ isert_put_datain(struct iscsi_conn *conn
+       isert_init_send_wr(isert_conn, isert_cmd,
+                          &isert_cmd->tx_desc.send_wr, true);
+-      atomic_inc(&isert_conn->post_send_buf_count);
++      atomic_add(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
+       rc = ib_post_send(isert_conn->conn_qp, wr->send_wr, &wr_failed);
+       if (rc) {
+               pr_warn("ib_post_send() failed for IB_WR_RDMA_WRITE\n");
+-              atomic_dec(&isert_conn->post_send_buf_count);
++              atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
+       }
+       pr_debug("Cmd: %p posted RDMA_WRITE + Response for iSER Data READ\n",
+                isert_cmd);
+@@ -2410,12 +2412,12 @@ isert_get_dataout(struct iscsi_conn *con
+               return rc;
+       }
+-      atomic_inc(&isert_conn->post_send_buf_count);
++      atomic_add(wr->send_wr_num, &isert_conn->post_send_buf_count);
+       rc = ib_post_send(isert_conn->conn_qp, wr->send_wr, &wr_failed);
+       if (rc) {
+               pr_warn("ib_post_send() failed for IB_WR_RDMA_READ\n");
+-              atomic_dec(&isert_conn->post_send_buf_count);
++              atomic_sub(wr->send_wr_num, &isert_conn->post_send_buf_count);
+       }
+       pr_debug("Cmd: %p posted RDMA_READ memory for ISER Data WRITE\n",
+                isert_cmd);
diff --git a/queue-3.13/iser-target-ignore-completions-for-frwrs-in-isert_cq_tx_work.patch b/queue-3.13/iser-target-ignore-completions-for-frwrs-in-isert_cq_tx_work.patch
new file mode 100644 (file)
index 0000000..a710a0d
--- /dev/null
@@ -0,0 +1,72 @@
+From 9bb4ca68fc48eea618b1af1c1cde2a251ae32d1b Mon Sep 17 00:00:00 2001
+From: Nicholas Bellinger <nab@linux-iscsi.org>
+Date: Thu, 27 Feb 2014 07:02:48 -0800
+Subject: iser-target: Ignore completions for FRWRs in isert_cq_tx_work
+
+From: Nicholas Bellinger <nab@linux-iscsi.org>
+
+commit 9bb4ca68fc48eea618b1af1c1cde2a251ae32d1b upstream.
+
+This patch changes IB_WR_FAST_REG_MR + IB_WR_LOCAL_INV related
+work requests to include a ISER_FRWR_LI_WRID value in order to
+signal isert_cq_tx_work() that these requests should be ignored.
+
+This is necessary because even though IB_SEND_SIGNALED is not
+set for either work request, during a QP failure event the work
+requests will be returned with exception status from the TX
+completion queue.
+
+v2 changes:
+ - Rename ISER_FRWR_LI_WRID -> ISER_FASTREG_LI_WRID (Sagi)
+
+Acked-by: Sagi Grimberg <sagig@mellanox.com>
+Cc: Or Gerlitz <ogerlitz@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 |    8 ++++++--
+ drivers/infiniband/ulp/isert/ib_isert.h |    1 +
+ 2 files changed, 7 insertions(+), 2 deletions(-)
+
+--- a/drivers/infiniband/ulp/isert/ib_isert.c
++++ b/drivers/infiniband/ulp/isert/ib_isert.c
+@@ -1732,8 +1732,10 @@ isert_cq_tx_work(struct work_struct *wor
+                       pr_debug("TX wc.status: 0x%08x\n", wc.status);
+                       pr_debug("TX wc.vendor_err: 0x%08x\n", wc.vendor_err);
+-                      atomic_dec(&isert_conn->post_send_buf_count);
+-                      isert_cq_tx_comp_err(tx_desc, isert_conn);
++                      if (wc.wr_id != ISER_FASTREG_LI_WRID) {
++                              atomic_dec(&isert_conn->post_send_buf_count);
++                              isert_cq_tx_comp_err(tx_desc, isert_conn);
++                      }
+               }
+       }
+@@ -2198,6 +2200,7 @@ isert_fast_reg_mr(struct fast_reg_descri
+       if (!fr_desc->valid) {
+               memset(&inv_wr, 0, sizeof(inv_wr));
++              inv_wr.wr_id = ISER_FASTREG_LI_WRID;
+               inv_wr.opcode = IB_WR_LOCAL_INV;
+               inv_wr.ex.invalidate_rkey = fr_desc->data_mr->rkey;
+               wr = &inv_wr;
+@@ -2208,6 +2211,7 @@ isert_fast_reg_mr(struct fast_reg_descri
+       /* Prepare FASTREG WR */
+       memset(&fr_wr, 0, sizeof(fr_wr));
++      fr_wr.wr_id = ISER_FASTREG_LI_WRID;
+       fr_wr.opcode = IB_WR_FAST_REG_MR;
+       fr_wr.wr.fast_reg.iova_start =
+               fr_desc->data_frpl->page_list[0] + page_off;
+--- a/drivers/infiniband/ulp/isert/ib_isert.h
++++ b/drivers/infiniband/ulp/isert/ib_isert.h
+@@ -6,6 +6,7 @@
+ #define ISERT_RDMA_LISTEN_BACKLOG     10
+ #define ISCSI_ISER_SG_TABLESIZE               256
++#define ISER_FASTREG_LI_WRID          0xffffffffffffffffULL
+ enum isert_desc_type {
+       ISCSI_TX_CONTROL,
index 263a8c4cc7ac8e0c794581603e96656268962dc3..2ff3cf4a3dd43df2cb3926fadad3dea3e527ee66 100644 (file)
@@ -88,3 +88,8 @@ nfsv4-nfs4_stateid_is_current-should-return-true-for-an-invalid-stateid.patch
 cpufreq-use-cpufreq_cpu_get-to-avoid-cpufreq_get-race-conditions.patch
 cpufreq-skip-current-frequency-initialization-for-setpolicy-drivers.patch
 acpi-sleep-add-extra-checks-for-hw-reduced-acpi-mode-sleep-states.patch
+iscsi-iser-target-use-list_del_init-for-i_conn_node.patch
+iscsi-iser-target-fix-isert_conn-state-hung-shutdown-issues.patch
+iser-target-ignore-completions-for-frwrs-in-isert_cq_tx_work.patch
+iser-target-fix-post_send_buf_count-for-rdma-read-write.patch
+iser-target-fix-command-leak-for-tx_desc-comp_llnode_batch.patch