FAILED: patch "[PATCH] iscsi-target: Always wait for kthread_should_stop() before" failed to apply to 4.4-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 4.4-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
Quoted 1 line
From
5e0cf5e6c43b9e19fc0284f69e5cd2b4a47523b0Mon Sep 17 00:00:00 2001
From: Jiang Yi <[email protected]>
Date: Tue, 16 May 2017 17:57:55 +0800
Subject: [PATCH] iscsi-target: Always wait for kthread_should_stop() before
kthread exit
There are three timing problems in the kthread usages of iscsi_target_mod:
- np_thread of struct iscsi_np
- rx_thread and tx_thread of struct iscsi_conn
In iscsit_close_connection(), it calls
send_sig(SIGINT, conn->tx_thread, 1);
kthread_stop(conn->tx_thread);
In conn->tx_thread, which is iscsi_target_tx_thread(), when it receive SIGINT the kthread will exit without checking the return value of kthread_should_stop().
So if iscsi_target_tx_thread() exit right between send_sig(SIGINT...) and kthread_stop(...), the kthread_stop() will try to stop an already stopped kthread.
This is invalid according to the documentation of kthread_stop().
(Fix -ECONNRESET logout handling in iscsi_target_tx_thread and
early iscsi_target_rx_thread failure case - nab)
drivers/target/iscsi/iscsi_target.c +24 -6
@@ -3790,6 +3790,8 @@ int iscsi_target_tx_thread(void *arg) {int ret =0 ;struct iscsi_conn *conn = arg; +bool conn_freed = false; +/* * Allow ourselves to be interrupted by SIGINT so that a * connection recovery / failure event can be triggered externally.
@@ -3815,12 +3817,14 @@ int iscsi_target_tx_thread(void *arg) goto transport_err; ret =iscsit_handle_response_queue (conn); -if (ret ==1 ) +if (ret ==1 ) { goto get_immediate; -else if (ret == -ECONNRESET ) + }else if (ret == -ECONNRESET ) { + conn_freed = true; goto out; -else if (ret <0 ) + }else if (ret <0 ) { goto transport_err; + } } transport_err:
@@ -3830,8 +3834,13 @@ int iscsi_target_tx_thread(void *arg)* responsible for cleaning up the early connection failure. */ if (conn->conn_state !=TARG_CONN_STATE_IN_LOGIN ) -iscsit_take_action_for_connection_exit (conn); +iscsit_take_action_for_connection_exit (conn, &conn_freed); out: +if (!conn_freed) { +while (!kthread_should_stop ()) { +msleep (100 ); + } + }return 0 ; }
@@ -4004,6 +4013,7 @@ int iscsi_target_rx_thread(void *arg) {int rc;struct iscsi_conn *conn = arg; +bool conn_freed = false;/* * Allow ourselves to be interrupted by SIGINT so that a
@@ -4016,7 +4026,7 @@ int iscsi_target_rx_thread(void *arg)*/ rc =wait_for_completion_interruptible (&conn->rx_login_comp);if (rc <0 ||iscsi_target_check_conn_state (conn)) -return 0 ; + goto out;if (!conn->conn_transport->iscsit_get_rx_pdu)return 0 ;
@@ -4025,7 +4035,15 @@ int iscsi_target_rx_thread(void *arg)if (!signal_pending (current))atomic_set (&conn->transport_failed,1 ); -iscsit_take_action_for_connection_exit (conn); +iscsit_take_action_for_connection_exit (conn, &conn_freed); + +out: +if (!conn_freed) { +while (!kthread_should_stop ()) { +msleep (100 ); + } + } +return 0 ; }
drivers/target/iscsi/iscsi_target_erl0.c +5 -1
@@ -930,8 +930,10 @@ static void iscsit_handle_connection_cleanup(struct iscsi_conn *conn) } } -void iscsit_take_action_for_connection_exit (struct iscsi_conn *conn) +void iscsit_take_action_for_connection_exit (struct iscsi_conn *conn,bool *conn_freed) { + *conn_freed = false; +spin_lock_bh (&conn->state_lock);if (atomic_read (&conn->connection_exit)) {spin_unlock_bh (&conn->state_lock);
@@ -942,6 +944,7 @@ void iscsit_take_action_for_connection_exit(struct iscsi_conn *conn)if (conn->conn_state ==TARG_CONN_STATE_IN_LOGOUT ) {spin_unlock_bh (&conn->state_lock);iscsit_close_connection (conn); + *conn_freed = true;return ; }
@@ -955,4 +958,5 @@ void iscsit_take_action_for_connection_exit(struct iscsi_conn *conn)spin_unlock_bh (&conn->state_lock);iscsit_handle_connection_cleanup (conn); + *conn_freed = true; }
drivers/target/iscsi/iscsi_target_erl0.h +1 -1
@@ -15,6 +15,6 @@ extern int iscsit_stop_time2retain_timer(struct iscsi_session *);extern void iscsit_connection_reinstatement_rcfr (struct iscsi_conn *);extern void iscsit_cause_connection_reinstatement (struct iscsi_conn *,int );extern void iscsit_fall_back_to_erl0 (struct iscsi_session *); -extern void iscsit_take_action_for_connection_exit (struct iscsi_conn *); +extern void iscsit_take_action_for_connection_exit (struct iscsi_conn *,bool *);#endif /*** ISCSI_TARGET_ERL0_H ***/
drivers/target/iscsi/iscsi_target_login.c +4 -0
@@ -1464,5 +1464,9 @@ int iscsi_target_login_thread(void *arg)break ; } +while (!kthread_should_stop ()) { +msleep (100 ); + } +return 0 ; }