diff options
author | Mikulas Patocka <mpatocka@redhat.com> | 2014-06-23 13:42:37 -0400 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2014-06-28 02:23:35 -0400 |
commit | 81a9c5e72bdf7109a65102ca61d8cbd722cf4021 (patch) | |
tree | 23e1accddfc6aedef0186db3061fe820b023dfc7 | |
parent | ac5ccdba3a1659b3517e7e99ef7d35a6a2d77cf4 (diff) |
iscsi-target: fix iscsit_del_np deadlock on unload
On uniprocessor preemptible kernel, target core deadlocks on unload. The
following events happen:
* iscsit_del_np is called
* it calls send_sig(SIGINT, np->np_thread, 1);
* the scheduler switches to the np_thread
* the np_thread is woken up, it sees that kthread_should_stop() returns
false, so it doesn't terminate
* the np_thread clears signals with flush_signals(current); and goes back
to sleep in iscsit_accept_np
* the scheduler switches back to iscsit_del_np
* iscsit_del_np calls kthread_stop(np->np_thread);
* the np_thread is waiting in iscsit_accept_np and it doesn't respond to
kthread_stop
The deadlock could be resolved if the administrator sends SIGINT signal to
the np_thread with killall -INT iscsi_np
The reproducible deadlock was introduced in commit
db6077fd0b7dd41dc6ff18329cec979379071f87, but the thread-stopping code was
racy even before.
This patch fixes the problem. Using kthread_should_stop to stop the
np_thread is unreliable, so we test np_thread_state instead. If
np_thread_state equals ISCSI_NP_THREAD_SHUTDOWN, the thread exits.
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Cc: stable@vger.kernel.org
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r-- | drivers/target/iscsi/iscsi_target_login.c | 13 |
1 files changed, 7 insertions, 6 deletions
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index fecb69535a15..5e71ac609418 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c | |||
@@ -1216,7 +1216,7 @@ old_sess_out: | |||
1216 | static int __iscsi_target_login_thread(struct iscsi_np *np) | 1216 | static int __iscsi_target_login_thread(struct iscsi_np *np) |
1217 | { | 1217 | { |
1218 | u8 *buffer, zero_tsih = 0; | 1218 | u8 *buffer, zero_tsih = 0; |
1219 | int ret = 0, rc, stop; | 1219 | int ret = 0, rc; |
1220 | struct iscsi_conn *conn = NULL; | 1220 | struct iscsi_conn *conn = NULL; |
1221 | struct iscsi_login *login; | 1221 | struct iscsi_login *login; |
1222 | struct iscsi_portal_group *tpg = NULL; | 1222 | struct iscsi_portal_group *tpg = NULL; |
@@ -1230,6 +1230,9 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) | |||
1230 | if (np->np_thread_state == ISCSI_NP_THREAD_RESET) { | 1230 | if (np->np_thread_state == ISCSI_NP_THREAD_RESET) { |
1231 | np->np_thread_state = ISCSI_NP_THREAD_ACTIVE; | 1231 | np->np_thread_state = ISCSI_NP_THREAD_ACTIVE; |
1232 | complete(&np->np_restart_comp); | 1232 | complete(&np->np_restart_comp); |
1233 | } else if (np->np_thread_state == ISCSI_NP_THREAD_SHUTDOWN) { | ||
1234 | spin_unlock_bh(&np->np_thread_lock); | ||
1235 | goto exit; | ||
1233 | } else { | 1236 | } else { |
1234 | np->np_thread_state = ISCSI_NP_THREAD_ACTIVE; | 1237 | np->np_thread_state = ISCSI_NP_THREAD_ACTIVE; |
1235 | } | 1238 | } |
@@ -1422,10 +1425,8 @@ old_sess_out: | |||
1422 | } | 1425 | } |
1423 | 1426 | ||
1424 | out: | 1427 | out: |
1425 | stop = kthread_should_stop(); | 1428 | return 1; |
1426 | /* Wait for another socket.. */ | 1429 | |
1427 | if (!stop) | ||
1428 | return 1; | ||
1429 | exit: | 1430 | exit: |
1430 | iscsi_stop_login_thread_timer(np); | 1431 | iscsi_stop_login_thread_timer(np); |
1431 | spin_lock_bh(&np->np_thread_lock); | 1432 | spin_lock_bh(&np->np_thread_lock); |
@@ -1442,7 +1443,7 @@ int iscsi_target_login_thread(void *arg) | |||
1442 | 1443 | ||
1443 | allow_signal(SIGINT); | 1444 | allow_signal(SIGINT); |
1444 | 1445 | ||
1445 | while (!kthread_should_stop()) { | 1446 | while (1) { |
1446 | ret = __iscsi_target_login_thread(np); | 1447 | ret = __iscsi_target_login_thread(np); |
1447 | /* | 1448 | /* |
1448 | * We break and exit here unless another sock_accept() call | 1449 | * We break and exit here unless another sock_accept() call |