Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1729792
| Path | csiph.com!feeder.erje.net!1.eu.feeder.erje.net!news.unit0.net!news.mixmin.net!aioe.org!news.servidellagleba.it!bofh.it!news.nic.it!robomod |
|---|---|
| From | Ben Hutchings <ben@decadent.org.uk> |
| Newsgroups | linux.kernel |
| Subject | [PATCH 3.16 103/233] iscsi-target: Always wait for kthread_should_stop() before kthread exit |
| Date | Sun, 10 Sep 2017 01:20:03 +0200 |
| Message-ID | <unXcD-3OU-71@gated-at.bofh.it> (permalink) |
| References | <unWqd-3ep-3@gated-at.bofh.it> |
| X-Original-To | linux-kernel@vger.kernel.org, stable@vger.kernel.org |
| Content-Type | text/plain; charset="UTF-8" |
| Content-Disposition | inline |
| Content-Transfer-Encoding | 8bit |
| MIME-Version | 1.0 |
| X-Mailer | LinuxStableQueue (scripts by bwh) |
| X-Sa-Exim-Connect-IP | 2a02:8011:400e:2:6f00:88c8:c921:d332 |
| X-Sa-Exim-Mail-From | ben@decadent.org.uk |
| X-Sa-Exim-Scanned | No (on shadbolt.decadent.org.uk); SAEximRunCond expanded to false |
| Sender | robomod@news.nic.it |
| List-ID | <linux-kernel.vger.kernel.org> |
| X-Mailing-List | linux-kernel@vger.kernel.org |
| Approved | robomod@news.nic.it |
| Lines | 174 |
| Organization | linux.* mail to news gateway |
| X-Original-Cc | akpm@linux-foundation.org, "Nicholas Bellinger" <nab@linux-iscsi.org>, "Jiang Yi" <jiangyilism@gmail.com> |
| X-Original-Date | Sat, 09 Sep 2017 22:47:14 +0100 |
| X-Original-Message-ID | <lsq.1504993634.212217244@decadent.org.uk> |
| X-Original-References | <lsq.1504993633.197134470@decadent.org.uk> |
| X-Original-Sender | linux-kernel-owner@vger.kernel.org |
| Xref | csiph.com linux.kernel:1729792 |
Show key headers only | View raw
3.16.48-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jiang Yi <jiangyilism@gmail.com>
commit 5e0cf5e6c43b9e19fc0284f69e5cd2b4a47523b0 upstream.
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)
Signed-off-by: Jiang Yi <jiangyilism@gmail.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
[bwh: Backported to 3.16: adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
drivers/target/iscsi/iscsi_target.c | 30 ++++++++++++++++++++++++------
drivers/target/iscsi/iscsi_target_erl0.c | 6 +++++-
drivers/target/iscsi/iscsi_target_erl0.h | 2 +-
drivers/target/iscsi/iscsi_target_login.c | 4 ++++
4 files changed, 34 insertions(+), 8 deletions(-)
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -3931,6 +3931,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.
@@ -3956,12 +3958,14 @@ get_immediate:
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:
@@ -3971,8 +3975,13 @@ transport_err:
* 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;
}
@@ -4073,6 +4082,8 @@ int iscsi_target_rx_thread(void *arg)
u32 checksum = 0, digest = 0;
struct iscsi_conn *conn = arg;
struct kvec iov;
+ bool conn_freed = false;
+
/*
* Allow ourselves to be interrupted by SIGINT so that a
* connection recovery / failure event can be triggered externally.
@@ -4084,7 +4095,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->transport_type == ISCSI_INFINIBAND) {
struct completion comp;
@@ -4169,7 +4180,15 @@ int iscsi_target_rx_thread(void *arg)
transport_err:
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;
}
--- a/drivers/target/iscsi/iscsi_target_erl0.c
+++ b/drivers/target/iscsi/iscsi_target_erl0.c
@@ -935,8 +935,10 @@ static void iscsit_handle_connection_cle
}
}
-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);
@@ -947,6 +949,7 @@ void iscsit_take_action_for_connection_e
if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT) {
spin_unlock_bh(&conn->state_lock);
iscsit_close_connection(conn);
+ *conn_freed = true;
return;
}
@@ -960,6 +963,7 @@ void iscsit_take_action_for_connection_e
spin_unlock_bh(&conn->state_lock);
iscsit_handle_connection_cleanup(conn);
+ *conn_freed = true;
}
/*
--- a/drivers/target/iscsi/iscsi_target_erl0.h
+++ b/drivers/target/iscsi/iscsi_target_erl0.h
@@ -9,7 +9,7 @@ extern int iscsit_stop_time2retain_timer
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 *);
extern int iscsit_recover_from_unknown_opcode(struct iscsi_conn *);
#endif /*** ISCSI_TARGET_ERL0_H ***/
--- a/drivers/target/iscsi/iscsi_target_login.c
+++ b/drivers/target/iscsi/iscsi_target_login.c
@@ -1496,5 +1496,9 @@ int iscsi_target_login_thread(void *arg)
break;
}
+ while (!kthread_should_stop()) {
+ msleep(100);
+ }
+
return 0;
}
Back to linux.kernel | Previous | Next | Find similar | Unroll thread
[PATCH 3.16 103/233] iscsi-target: Always wait for kthread_should_stop() before kthread exit Ben Hutchings <ben@decadent.org.uk> - 2017-09-10 01:20 +0200
csiph-web