From: Greg Kroah-Hartman Date: Fri, 14 Aug 2015 00:59:35 +0000 (-0700) Subject: 3.14-stable patches X-Git-Tag: v3.10.87~22 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6c22d48ef666b5f1590f797f9be06593b9cf3e97;p=thirdparty%2Fkernel%2Fstable-queue.git 3.14-stable patches added patches: iscsi-target-fix-iscsit_start_kthreads-failure-oops.patch --- diff --git a/queue-3.14/iscsi-target-fix-iscsit_start_kthreads-failure-oops.patch b/queue-3.14/iscsi-target-fix-iscsit_start_kthreads-failure-oops.patch new file mode 100644 index 00000000000..bdfbcf9a598 --- /dev/null +++ b/queue-3.14/iscsi-target-fix-iscsit_start_kthreads-failure-oops.patch @@ -0,0 +1,290 @@ +From e54198657b65625085834847ab6271087323ffea Mon Sep 17 00:00:00 2001 +From: Nicholas Bellinger +Date: Wed, 22 Jul 2015 23:14:19 -0700 +Subject: iscsi-target: Fix iscsit_start_kthreads failure OOPs + +From: Nicholas Bellinger + +commit e54198657b65625085834847ab6271087323ffea upstream. + +This patch fixes a regression introduced with the following commit +in v4.0-rc1 code, where a iscsit_start_kthreads() failure triggers +a NULL pointer dereference OOPs: + + commit 88dcd2dab5c23b1c9cfc396246d8f476c872f0ca + Author: Nicholas Bellinger + Date: Thu Feb 26 22:19:15 2015 -0800 + + iscsi-target: Convert iscsi_thread_set usage to kthread.h + +To address this bug, move iscsit_start_kthreads() immediately +preceeding the transmit of last login response, before signaling +a successful transition into full-feature-phase within existing +iscsi_target_do_tx_login_io() logic. + +This ensures that no target-side resource allocation failures can +occur after the final login response has been successfully sent. + +Also, it adds a iscsi_conn->rx_login_comp to allow the RX thread +to sleep to prevent other socket related failures until the final +iscsi_post_login_handler() call is able to complete. + +Cc: Sagi Grimberg +Signed-off-by: Nicholas Bellinger +Signed-off-by: Nicholas Bellinger +Signed-off-by: Greg Kroah-Hartman +--- + drivers/target/iscsi/iscsi_target.c | 18 ++++++++++-- + drivers/target/iscsi/iscsi_target_core.h | 1 + drivers/target/iscsi/iscsi_target_login.c | 43 +++++++++++------------------- + drivers/target/iscsi/iscsi_target_login.h | 3 +- + drivers/target/iscsi/iscsi_target_nego.c | 34 +++++++++++++++++++++++ + 5 files changed, 67 insertions(+), 32 deletions(-) + +--- a/drivers/target/iscsi/iscsi_target.c ++++ b/drivers/target/iscsi/iscsi_target.c +@@ -3937,7 +3937,13 @@ get_immediate: + } + + transport_err: +- iscsit_take_action_for_connection_exit(conn); ++ /* ++ * Avoid the normal connection failure code-path if this connection ++ * is still within LOGIN mode, and iscsi_np process context is ++ * responsible for cleaning up the early connection failure. ++ */ ++ if (conn->conn_state != TARG_CONN_STATE_IN_LOGIN) ++ iscsit_take_action_for_connection_exit(conn); + out: + return 0; + } +@@ -4023,7 +4029,7 @@ reject: + + int iscsi_target_rx_thread(void *arg) + { +- int ret; ++ int ret, rc; + u8 buffer[ISCSI_HDR_LEN], opcode; + u32 checksum = 0, digest = 0; + struct iscsi_conn *conn = arg; +@@ -4033,10 +4039,16 @@ int iscsi_target_rx_thread(void *arg) + * connection recovery / failure event can be triggered externally. + */ + allow_signal(SIGINT); ++ /* ++ * Wait for iscsi_post_login_handler() to complete before allowing ++ * incoming iscsi/tcp socket I/O, and/or failing the connection. ++ */ ++ rc = wait_for_completion_interruptible(&conn->rx_login_comp); ++ if (rc < 0) ++ return 0; + + if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) { + struct completion comp; +- int rc; + + init_completion(&comp); + rc = wait_for_completion_interruptible(&comp); +--- a/drivers/target/iscsi/iscsi_target_core.h ++++ b/drivers/target/iscsi/iscsi_target_core.h +@@ -604,6 +604,7 @@ struct iscsi_conn { + int bitmap_id; + int rx_thread_active; + struct task_struct *rx_thread; ++ struct completion rx_login_comp; + int tx_thread_active; + struct task_struct *tx_thread; + /* list_head for session connection list */ +--- a/drivers/target/iscsi/iscsi_target_login.c ++++ b/drivers/target/iscsi/iscsi_target_login.c +@@ -83,6 +83,7 @@ static struct iscsi_login *iscsi_login_i + init_completion(&conn->conn_logout_comp); + init_completion(&conn->rx_half_close_comp); + init_completion(&conn->tx_half_close_comp); ++ init_completion(&conn->rx_login_comp); + spin_lock_init(&conn->cmd_lock); + spin_lock_init(&conn->conn_usage_lock); + spin_lock_init(&conn->immed_queue_lock); +@@ -716,6 +717,7 @@ int iscsit_start_kthreads(struct iscsi_c + + return 0; + out_tx: ++ send_sig(SIGINT, conn->tx_thread, 1); + kthread_stop(conn->tx_thread); + conn->tx_thread_active = false; + out_bitmap: +@@ -726,7 +728,7 @@ out_bitmap: + return ret; + } + +-int iscsi_post_login_handler( ++void iscsi_post_login_handler( + struct iscsi_np *np, + struct iscsi_conn *conn, + u8 zero_tsih) +@@ -736,7 +738,6 @@ 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; +- int rc; + + iscsit_inc_conn_usage_count(conn); + +@@ -777,10 +778,6 @@ int iscsi_post_login_handler( + sess->sess_ops->InitiatorName); + spin_unlock_bh(&sess->conn_lock); + +- rc = iscsit_start_kthreads(conn); +- if (rc) +- return rc; +- + iscsi_post_login_start_timers(conn); + /* + * Determine CPU mask to ensure connection's RX and TX kthreads +@@ -789,15 +786,20 @@ int iscsi_post_login_handler( + iscsit_thread_get_cpumask(conn); + conn->conn_rx_reset_cpumask = 1; + conn->conn_tx_reset_cpumask = 1; +- ++ /* ++ * Wakeup the sleeping iscsi_target_rx_thread() now that ++ * iscsi_conn is in TARG_CONN_STATE_LOGGED_IN state. ++ */ ++ complete(&conn->rx_login_comp); + iscsit_dec_conn_usage_count(conn); ++ + if (stop_timer) { + spin_lock_bh(&se_tpg->session_lock); + iscsit_stop_time2retain_timer(sess); + spin_unlock_bh(&se_tpg->session_lock); + } + iscsit_dec_session_usage_count(sess); +- return 0; ++ return; + } + + iscsi_set_session_parameters(sess->sess_ops, conn->param_list, 1); +@@ -838,10 +840,6 @@ 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); + /* + * Determine CPU mask to ensure connection's RX and TX kthreads +@@ -850,10 +848,12 @@ int iscsi_post_login_handler( + iscsit_thread_get_cpumask(conn); + conn->conn_rx_reset_cpumask = 1; + conn->conn_tx_reset_cpumask = 1; +- ++ /* ++ * Wakeup the sleeping iscsi_target_rx_thread() now that ++ * iscsi_conn is in TARG_CONN_STATE_LOGGED_IN state. ++ */ ++ complete(&conn->rx_login_comp); + iscsit_dec_conn_usage_count(conn); +- +- return 0; + } + + static void iscsi_handle_login_thread_timeout(unsigned long data) +@@ -1418,23 +1418,12 @@ static int __iscsi_target_login_thread(s + if (ret < 0) + goto new_sess_out; + +- if (!conn->sess) { +- pr_err("struct iscsi_conn session pointer is NULL!\n"); +- goto new_sess_out; +- } +- + iscsi_stop_login_thread_timer(np); + +- if (signal_pending(current)) +- goto new_sess_out; +- + if (ret == 1) { + tpg_np = conn->tpg_np; + +- ret = iscsi_post_login_handler(np, conn, zero_tsih); +- if (ret < 0) +- goto new_sess_out; +- ++ iscsi_post_login_handler(np, conn, zero_tsih); + iscsit_deaccess_np(np, tpg, tpg_np); + } + +--- a/drivers/target/iscsi/iscsi_target_login.h ++++ b/drivers/target/iscsi/iscsi_target_login.h +@@ -12,7 +12,8 @@ extern int iscsit_accept_np(struct iscsi + extern int iscsit_get_login_rx(struct iscsi_conn *, struct iscsi_login *); + extern int iscsit_put_login_tx(struct iscsi_conn *, struct iscsi_login *, u32); + extern void iscsit_free_conn(struct iscsi_np *, struct iscsi_conn *); +-extern int iscsi_post_login_handler(struct iscsi_np *, struct iscsi_conn *, u8); ++extern int iscsit_start_kthreads(struct iscsi_conn *); ++extern void iscsi_post_login_handler(struct iscsi_np *, struct iscsi_conn *, u8); + extern void iscsi_target_login_sess_out(struct iscsi_conn *, struct iscsi_np *, + bool, bool); + extern int iscsi_target_login_thread(void *); +--- a/drivers/target/iscsi/iscsi_target_nego.c ++++ b/drivers/target/iscsi/iscsi_target_nego.c +@@ -17,6 +17,7 @@ + ******************************************************************************/ + + #include ++#include + #include + #include + #include +@@ -361,10 +362,24 @@ static int iscsi_target_do_tx_login_io(s + ntohl(login_rsp->statsn), login->rsp_length); + + padding = ((-login->rsp_length) & 3); ++ /* ++ * Before sending the last login response containing the transition ++ * bit for full-feature-phase, go ahead and start up TX/RX threads ++ * now to avoid potential resource allocation failures after the ++ * final login response has been sent. ++ */ ++ if (login->login_complete) { ++ int rc = iscsit_start_kthreads(conn); ++ if (rc) { ++ iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, ++ ISCSI_LOGIN_STATUS_NO_RESOURCES); ++ return -1; ++ } ++ } + + if (conn->conn_transport->iscsit_put_login_tx(conn, login, + login->rsp_length + padding) < 0) +- return -1; ++ goto err; + + login->rsp_length = 0; + mutex_lock(&sess->cmdsn_mutex); +@@ -373,6 +388,23 @@ static int iscsi_target_do_tx_login_io(s + mutex_unlock(&sess->cmdsn_mutex); + + return 0; ++ ++err: ++ if (login->login_complete) { ++ if (conn->rx_thread && conn->rx_thread_active) { ++ send_sig(SIGINT, conn->rx_thread, 1); ++ kthread_stop(conn->rx_thread); ++ } ++ if (conn->tx_thread && conn->tx_thread_active) { ++ send_sig(SIGINT, conn->tx_thread, 1); ++ kthread_stop(conn->tx_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); ++ } ++ return -1; + } + + static void iscsi_target_sk_data_ready(struct sock *sk, int count) diff --git a/queue-3.14/series b/queue-3.14/series index 23b4d142a72..5b81dccf39d 100644 --- a/queue-3.14/series +++ b/queue-3.14/series @@ -20,3 +20,4 @@ xen-gntdevt-fix-race-condition-in-gntdev_release.patch crypto-ixp4xx-remove-bogus-bug_on-on-scattered-dst-buffer.patch rbd-fix-copyup-completion-race.patch arm-omap2-hwmod-fix-_wait_target_ready-for-hwmods-without-sysc.patch +iscsi-target-fix-iscsit_start_kthreads-failure-oops.patch