From da3bef1b085a3f948be83ac85ba0ed592852ee3f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 19 Mar 2014 22:21:56 -0700 Subject: [PATCH] 3.13-stable patches 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 --- ...sert_conn-state-hung-shutdown-issues.patch | 277 ++++++++++++++++++ ...et-use-list_del_init-for-i_conn_node.patch | 159 ++++++++++ ...d-leak-for-tx_desc-comp_llnode_batch.patch | 150 ++++++++++ ...t_send_buf_count-for-rdma-read-write.patch | 98 +++++++ ...etions-for-frwrs-in-isert_cq_tx_work.patch | 72 +++++ queue-3.13/series | 5 + 6 files changed, 761 insertions(+) create mode 100644 queue-3.13/iscsi-iser-target-fix-isert_conn-state-hung-shutdown-issues.patch create mode 100644 queue-3.13/iscsi-iser-target-use-list_del_init-for-i_conn_node.patch create mode 100644 queue-3.13/iser-target-fix-command-leak-for-tx_desc-comp_llnode_batch.patch create mode 100644 queue-3.13/iser-target-fix-post_send_buf_count-for-rdma-read-write.patch create mode 100644 queue-3.13/iser-target-ignore-completions-for-frwrs-in-isert_cq_tx_work.patch 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 index 00000000000..9d3982b2b6d --- /dev/null +++ b/queue-3.13/iscsi-iser-target-fix-isert_conn-state-hung-shutdown-issues.patch @@ -0,0 +1,277 @@ +From defd884845297fd5690594bfe89656b01f16d87e Mon Sep 17 00:00:00 2001 +From: Nicholas Bellinger +Date: Mon, 3 Feb 2014 12:54:39 -0800 +Subject: iscsi/iser-target: Fix isert_conn->state hung shutdown issues + +From: Nicholas Bellinger + +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 +Cc: Or Gerlitz +Signed-off-by: Nicholas Bellinger +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..9e8181d71f6 --- /dev/null +++ b/queue-3.13/iscsi-iser-target-use-list_del_init-for-i_conn_node.patch @@ -0,0 +1,159 @@ +From 5159d763f60af693a3fcec45dce2021f66e528a4 Mon Sep 17 00:00:00 2001 +From: Nicholas Bellinger +Date: Mon, 3 Feb 2014 12:53:51 -0800 +Subject: iscsi/iser-target: Use list_del_init for ->i_conn_node + +From: Nicholas Bellinger + +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 +Cc: Or Gerlitz +Signed-off-by: Nicholas Bellinger +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..cb231ef8564 --- /dev/null +++ b/queue-3.13/iser-target-fix-command-leak-for-tx_desc-comp_llnode_batch.patch @@ -0,0 +1,150 @@ +From ebbe442183b7b8192c963266f1c89048fefc63a5 Mon Sep 17 00:00:00 2001 +From: Nicholas Bellinger +Date: Sun, 2 Mar 2014 14:51:12 -0800 +Subject: iser-target: Fix command leak for tx_desc->comp_llnode_batch + +From: Nicholas Bellinger + +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 +Cc: Or Gerlitz +Signed-off-by: Nicholas Bellinger +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..bbd422a6ffe --- /dev/null +++ b/queue-3.13/iser-target-fix-post_send_buf_count-for-rdma-read-write.patch @@ -0,0 +1,98 @@ +From b6b87a1df604678ed1be40158080db012a99ccca Mon Sep 17 00:00:00 2001 +From: Nicholas Bellinger +Date: Thu, 27 Feb 2014 09:05:03 -0800 +Subject: iser-target: Fix post_send_buf_count for RDMA READ/WRITE + +From: Nicholas Bellinger + +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 +Cc: Or Gerlitz +Signed-off-by: Nicholas Bellinger +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..a710a0d660b --- /dev/null +++ b/queue-3.13/iser-target-ignore-completions-for-frwrs-in-isert_cq_tx_work.patch @@ -0,0 +1,72 @@ +From 9bb4ca68fc48eea618b1af1c1cde2a251ae32d1b Mon Sep 17 00:00:00 2001 +From: Nicholas Bellinger +Date: Thu, 27 Feb 2014 07:02:48 -0800 +Subject: iser-target: Ignore completions for FRWRs in isert_cq_tx_work + +From: Nicholas Bellinger + +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 +Cc: Or Gerlitz +Signed-off-by: Nicholas Bellinger +Signed-off-by: Greg Kroah-Hartman + +--- + 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, diff --git a/queue-3.13/series b/queue-3.13/series index 263a8c4cc7a..2ff3cf4a3dd 100644 --- a/queue-3.13/series +++ b/queue-3.13/series @@ -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 -- 2.47.3