From: Greg Kroah-Hartman Date: Fri, 14 Aug 2015 00:59:30 +0000 (-0700) Subject: 3.10-stable patches X-Git-Tag: v3.10.87~23 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7009bd64da9ef6b35e349e8a868f2dfe94aea7bf;p=thirdparty%2Fkernel%2Fstable-queue.git 3.10-stable patches added patches: iscsi-target-fix-iscsit_start_kthreads-failure-oops.patch --- diff --git a/queue-3.10/iscsi-target-fix-iscsit_start_kthreads-failure-oops.patch b/queue-3.10/iscsi-target-fix-iscsit_start_kthreads-failure-oops.patch new file mode 100644 index 00000000000..42eeed98a2b --- /dev/null +++ b/queue-3.10/iscsi-target-fix-iscsit_start_kthreads-failure-oops.patch @@ -0,0 +1,286 @@ +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 | 1 + drivers/target/iscsi/iscsi_target_nego.c | 34 +++++++++++++++++++++++ + 5 files changed, 66 insertions(+), 31 deletions(-) + +--- a/drivers/target/iscsi/iscsi_target.c ++++ b/drivers/target/iscsi/iscsi_target.c +@@ -3874,7 +3874,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; + } +@@ -3956,7 +3962,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; +@@ -3966,10 +3972,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 +@@ -589,6 +589,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 +@@ -84,6 +84,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); +@@ -718,6 +719,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: +@@ -728,7 +730,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) +@@ -738,7 +740,6 @@ int iscsi_post_login_handler( + struct se_session *se_sess = sess->se_sess; + struct iscsi_portal_group *tpg = ISCSI_TPG_S(sess); + struct se_portal_group *se_tpg = &tpg->tpg_se_tpg; +- int rc; + + iscsit_inc_conn_usage_count(conn); + +@@ -779,10 +780,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 +@@ -791,15 +788,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); +@@ -840,10 +842,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 +@@ -852,10 +850,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) +@@ -1331,20 +1331,9 @@ static int __iscsi_target_login_thread(s + if (iscsi_target_start_negotiation(login, conn) < 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; +- +- 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 = NULL; +--- a/drivers/target/iscsi/iscsi_target_login.h ++++ b/drivers/target/iscsi/iscsi_target_login.h +@@ -12,6 +12,7 @@ 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 iscsit_start_kthreads(struct iscsi_conn *); + extern int iscsi_target_login_thread(void *); + extern int iscsi_login_disable_FIM_keys(struct iscsi_param_list *, struct iscsi_conn *); + +--- a/drivers/target/iscsi/iscsi_target_nego.c ++++ b/drivers/target/iscsi/iscsi_target_nego.c +@@ -19,6 +19,7 @@ + ******************************************************************************/ + + #include ++#include + #include + #include + #include +@@ -352,10 +353,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); +@@ -364,6 +379,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 int iscsi_target_do_login_io(struct iscsi_conn *conn, struct iscsi_login *login) diff --git a/queue-3.10/series b/queue-3.10/series index 7f6cbe067d8..738daacdade 100644 --- a/queue-3.10/series +++ b/queue-3.10/series @@ -18,3 +18,4 @@ x86-xen-probe-target-addresses-in-set_aliased_prot-before-the-hypercall.patch 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 +iscsi-target-fix-iscsit_start_kthreads-failure-oops.patch