diff options
-rw-r--r-- | drivers/target/iscsi/iscsi_target.c | 18 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_login.c | 45 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_login.h | 3 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_nego.c | 34 | ||||
-rw-r--r-- | include/target/iscsi/iscsi_target_core.h | 1 |
5 files changed, 68 insertions, 33 deletions
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index afab32376126..202a42858f25 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c | |||
@@ -3998,7 +3998,13 @@ get_immediate: | |||
3998 | } | 3998 | } |
3999 | 3999 | ||
4000 | transport_err: | 4000 | transport_err: |
4001 | iscsit_take_action_for_connection_exit(conn); | 4001 | /* |
4002 | * Avoid the normal connection failure code-path if this connection | ||
4003 | * is still within LOGIN mode, and iscsi_np process context is | ||
4004 | * responsible for cleaning up the early connection failure. | ||
4005 | */ | ||
4006 | if (conn->conn_state != TARG_CONN_STATE_IN_LOGIN) | ||
4007 | iscsit_take_action_for_connection_exit(conn); | ||
4002 | out: | 4008 | out: |
4003 | return 0; | 4009 | return 0; |
4004 | } | 4010 | } |
@@ -4082,7 +4088,7 @@ reject: | |||
4082 | 4088 | ||
4083 | int iscsi_target_rx_thread(void *arg) | 4089 | int iscsi_target_rx_thread(void *arg) |
4084 | { | 4090 | { |
4085 | int ret; | 4091 | int ret, rc; |
4086 | u8 buffer[ISCSI_HDR_LEN], opcode; | 4092 | u8 buffer[ISCSI_HDR_LEN], opcode; |
4087 | u32 checksum = 0, digest = 0; | 4093 | u32 checksum = 0, digest = 0; |
4088 | struct iscsi_conn *conn = arg; | 4094 | struct iscsi_conn *conn = arg; |
@@ -4092,10 +4098,16 @@ int iscsi_target_rx_thread(void *arg) | |||
4092 | * connection recovery / failure event can be triggered externally. | 4098 | * connection recovery / failure event can be triggered externally. |
4093 | */ | 4099 | */ |
4094 | allow_signal(SIGINT); | 4100 | allow_signal(SIGINT); |
4101 | /* | ||
4102 | * Wait for iscsi_post_login_handler() to complete before allowing | ||
4103 | * incoming iscsi/tcp socket I/O, and/or failing the connection. | ||
4104 | */ | ||
4105 | rc = wait_for_completion_interruptible(&conn->rx_login_comp); | ||
4106 | if (rc < 0) | ||
4107 | return 0; | ||
4095 | 4108 | ||
4096 | if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) { | 4109 | if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) { |
4097 | struct completion comp; | 4110 | struct completion comp; |
4098 | int rc; | ||
4099 | 4111 | ||
4100 | init_completion(&comp); | 4112 | init_completion(&comp); |
4101 | rc = wait_for_completion_interruptible(&comp); | 4113 | rc = wait_for_completion_interruptible(&comp); |
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 3d0fe4ff5590..7e8f65e5448f 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c | |||
@@ -82,6 +82,7 @@ static struct iscsi_login *iscsi_login_init_conn(struct iscsi_conn *conn) | |||
82 | init_completion(&conn->conn_logout_comp); | 82 | init_completion(&conn->conn_logout_comp); |
83 | init_completion(&conn->rx_half_close_comp); | 83 | init_completion(&conn->rx_half_close_comp); |
84 | init_completion(&conn->tx_half_close_comp); | 84 | init_completion(&conn->tx_half_close_comp); |
85 | init_completion(&conn->rx_login_comp); | ||
85 | spin_lock_init(&conn->cmd_lock); | 86 | spin_lock_init(&conn->cmd_lock); |
86 | spin_lock_init(&conn->conn_usage_lock); | 87 | spin_lock_init(&conn->conn_usage_lock); |
87 | spin_lock_init(&conn->immed_queue_lock); | 88 | spin_lock_init(&conn->immed_queue_lock); |
@@ -644,7 +645,7 @@ static void iscsi_post_login_start_timers(struct iscsi_conn *conn) | |||
644 | iscsit_start_nopin_timer(conn); | 645 | iscsit_start_nopin_timer(conn); |
645 | } | 646 | } |
646 | 647 | ||
647 | static int iscsit_start_kthreads(struct iscsi_conn *conn) | 648 | int iscsit_start_kthreads(struct iscsi_conn *conn) |
648 | { | 649 | { |
649 | int ret = 0; | 650 | int ret = 0; |
650 | 651 | ||
@@ -679,6 +680,7 @@ static int iscsit_start_kthreads(struct iscsi_conn *conn) | |||
679 | 680 | ||
680 | return 0; | 681 | return 0; |
681 | out_tx: | 682 | out_tx: |
683 | send_sig(SIGINT, conn->tx_thread, 1); | ||
682 | kthread_stop(conn->tx_thread); | 684 | kthread_stop(conn->tx_thread); |
683 | conn->tx_thread_active = false; | 685 | conn->tx_thread_active = false; |
684 | out_bitmap: | 686 | out_bitmap: |
@@ -689,7 +691,7 @@ out_bitmap: | |||
689 | return ret; | 691 | return ret; |
690 | } | 692 | } |
691 | 693 | ||
692 | int iscsi_post_login_handler( | 694 | void iscsi_post_login_handler( |
693 | struct iscsi_np *np, | 695 | struct iscsi_np *np, |
694 | struct iscsi_conn *conn, | 696 | struct iscsi_conn *conn, |
695 | u8 zero_tsih) | 697 | u8 zero_tsih) |
@@ -699,7 +701,6 @@ int iscsi_post_login_handler( | |||
699 | struct se_session *se_sess = sess->se_sess; | 701 | struct se_session *se_sess = sess->se_sess; |
700 | struct iscsi_portal_group *tpg = sess->tpg; | 702 | struct iscsi_portal_group *tpg = sess->tpg; |
701 | struct se_portal_group *se_tpg = &tpg->tpg_se_tpg; | 703 | struct se_portal_group *se_tpg = &tpg->tpg_se_tpg; |
702 | int rc; | ||
703 | 704 | ||
704 | iscsit_inc_conn_usage_count(conn); | 705 | iscsit_inc_conn_usage_count(conn); |
705 | 706 | ||
@@ -739,10 +740,6 @@ int iscsi_post_login_handler( | |||
739 | sess->sess_ops->InitiatorName); | 740 | sess->sess_ops->InitiatorName); |
740 | spin_unlock_bh(&sess->conn_lock); | 741 | spin_unlock_bh(&sess->conn_lock); |
741 | 742 | ||
742 | rc = iscsit_start_kthreads(conn); | ||
743 | if (rc) | ||
744 | return rc; | ||
745 | |||
746 | iscsi_post_login_start_timers(conn); | 743 | iscsi_post_login_start_timers(conn); |
747 | /* | 744 | /* |
748 | * Determine CPU mask to ensure connection's RX and TX kthreads | 745 | * Determine CPU mask to ensure connection's RX and TX kthreads |
@@ -751,15 +748,20 @@ int iscsi_post_login_handler( | |||
751 | iscsit_thread_get_cpumask(conn); | 748 | iscsit_thread_get_cpumask(conn); |
752 | conn->conn_rx_reset_cpumask = 1; | 749 | conn->conn_rx_reset_cpumask = 1; |
753 | conn->conn_tx_reset_cpumask = 1; | 750 | conn->conn_tx_reset_cpumask = 1; |
754 | 751 | /* | |
752 | * Wakeup the sleeping iscsi_target_rx_thread() now that | ||
753 | * iscsi_conn is in TARG_CONN_STATE_LOGGED_IN state. | ||
754 | */ | ||
755 | complete(&conn->rx_login_comp); | ||
755 | iscsit_dec_conn_usage_count(conn); | 756 | iscsit_dec_conn_usage_count(conn); |
757 | |||
756 | if (stop_timer) { | 758 | if (stop_timer) { |
757 | spin_lock_bh(&se_tpg->session_lock); | 759 | spin_lock_bh(&se_tpg->session_lock); |
758 | iscsit_stop_time2retain_timer(sess); | 760 | iscsit_stop_time2retain_timer(sess); |
759 | spin_unlock_bh(&se_tpg->session_lock); | 761 | spin_unlock_bh(&se_tpg->session_lock); |
760 | } | 762 | } |
761 | iscsit_dec_session_usage_count(sess); | 763 | iscsit_dec_session_usage_count(sess); |
762 | return 0; | 764 | return; |
763 | } | 765 | } |
764 | 766 | ||
765 | iscsi_set_session_parameters(sess->sess_ops, conn->param_list, 1); | 767 | iscsi_set_session_parameters(sess->sess_ops, conn->param_list, 1); |
@@ -800,10 +802,6 @@ int iscsi_post_login_handler( | |||
800 | " iSCSI Target Portal Group: %hu\n", tpg->nsessions, tpg->tpgt); | 802 | " iSCSI Target Portal Group: %hu\n", tpg->nsessions, tpg->tpgt); |
801 | spin_unlock_bh(&se_tpg->session_lock); | 803 | spin_unlock_bh(&se_tpg->session_lock); |
802 | 804 | ||
803 | rc = iscsit_start_kthreads(conn); | ||
804 | if (rc) | ||
805 | return rc; | ||
806 | |||
807 | iscsi_post_login_start_timers(conn); | 805 | iscsi_post_login_start_timers(conn); |
808 | /* | 806 | /* |
809 | * Determine CPU mask to ensure connection's RX and TX kthreads | 807 | * Determine CPU mask to ensure connection's RX and TX kthreads |
@@ -812,10 +810,12 @@ int iscsi_post_login_handler( | |||
812 | iscsit_thread_get_cpumask(conn); | 810 | iscsit_thread_get_cpumask(conn); |
813 | conn->conn_rx_reset_cpumask = 1; | 811 | conn->conn_rx_reset_cpumask = 1; |
814 | conn->conn_tx_reset_cpumask = 1; | 812 | conn->conn_tx_reset_cpumask = 1; |
815 | 813 | /* | |
814 | * Wakeup the sleeping iscsi_target_rx_thread() now that | ||
815 | * iscsi_conn is in TARG_CONN_STATE_LOGGED_IN state. | ||
816 | */ | ||
817 | complete(&conn->rx_login_comp); | ||
816 | iscsit_dec_conn_usage_count(conn); | 818 | iscsit_dec_conn_usage_count(conn); |
817 | |||
818 | return 0; | ||
819 | } | 819 | } |
820 | 820 | ||
821 | static void iscsi_handle_login_thread_timeout(unsigned long data) | 821 | static void iscsi_handle_login_thread_timeout(unsigned long data) |
@@ -1380,23 +1380,12 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) | |||
1380 | if (ret < 0) | 1380 | if (ret < 0) |
1381 | goto new_sess_out; | 1381 | goto new_sess_out; |
1382 | 1382 | ||
1383 | if (!conn->sess) { | ||
1384 | pr_err("struct iscsi_conn session pointer is NULL!\n"); | ||
1385 | goto new_sess_out; | ||
1386 | } | ||
1387 | |||
1388 | iscsi_stop_login_thread_timer(np); | 1383 | iscsi_stop_login_thread_timer(np); |
1389 | 1384 | ||
1390 | if (signal_pending(current)) | ||
1391 | goto new_sess_out; | ||
1392 | |||
1393 | if (ret == 1) { | 1385 | if (ret == 1) { |
1394 | tpg_np = conn->tpg_np; | 1386 | tpg_np = conn->tpg_np; |
1395 | 1387 | ||
1396 | ret = iscsi_post_login_handler(np, conn, zero_tsih); | 1388 | iscsi_post_login_handler(np, conn, zero_tsih); |
1397 | if (ret < 0) | ||
1398 | goto new_sess_out; | ||
1399 | |||
1400 | iscsit_deaccess_np(np, tpg, tpg_np); | 1389 | iscsit_deaccess_np(np, tpg, tpg_np); |
1401 | } | 1390 | } |
1402 | 1391 | ||
diff --git a/drivers/target/iscsi/iscsi_target_login.h b/drivers/target/iscsi/iscsi_target_login.h index 1c7358081533..57aa0d0fd820 100644 --- 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_np *, struct iscsi_conn *); | |||
12 | extern int iscsit_get_login_rx(struct iscsi_conn *, struct iscsi_login *); | 12 | extern int iscsit_get_login_rx(struct iscsi_conn *, struct iscsi_login *); |
13 | extern int iscsit_put_login_tx(struct iscsi_conn *, struct iscsi_login *, u32); | 13 | extern int iscsit_put_login_tx(struct iscsi_conn *, struct iscsi_login *, u32); |
14 | extern void iscsit_free_conn(struct iscsi_np *, struct iscsi_conn *); | 14 | extern void iscsit_free_conn(struct iscsi_np *, struct iscsi_conn *); |
15 | extern int iscsi_post_login_handler(struct iscsi_np *, struct iscsi_conn *, u8); | 15 | extern int iscsit_start_kthreads(struct iscsi_conn *); |
16 | extern void iscsi_post_login_handler(struct iscsi_np *, struct iscsi_conn *, u8); | ||
16 | extern void iscsi_target_login_sess_out(struct iscsi_conn *, struct iscsi_np *, | 17 | extern void iscsi_target_login_sess_out(struct iscsi_conn *, struct iscsi_np *, |
17 | bool, bool); | 18 | bool, bool); |
18 | extern int iscsi_target_login_thread(void *); | 19 | extern int iscsi_target_login_thread(void *); |
diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index 8c02fa34716f..f9cde9141836 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c | |||
@@ -17,6 +17,7 @@ | |||
17 | ******************************************************************************/ | 17 | ******************************************************************************/ |
18 | 18 | ||
19 | #include <linux/ctype.h> | 19 | #include <linux/ctype.h> |
20 | #include <linux/kthread.h> | ||
20 | #include <scsi/iscsi_proto.h> | 21 | #include <scsi/iscsi_proto.h> |
21 | #include <target/target_core_base.h> | 22 | #include <target/target_core_base.h> |
22 | #include <target/target_core_fabric.h> | 23 | #include <target/target_core_fabric.h> |
@@ -361,10 +362,24 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log | |||
361 | ntohl(login_rsp->statsn), login->rsp_length); | 362 | ntohl(login_rsp->statsn), login->rsp_length); |
362 | 363 | ||
363 | padding = ((-login->rsp_length) & 3); | 364 | padding = ((-login->rsp_length) & 3); |
365 | /* | ||
366 | * Before sending the last login response containing the transition | ||
367 | * bit for full-feature-phase, go ahead and start up TX/RX threads | ||
368 | * now to avoid potential resource allocation failures after the | ||
369 | * final login response has been sent. | ||
370 | */ | ||
371 | if (login->login_complete) { | ||
372 | int rc = iscsit_start_kthreads(conn); | ||
373 | if (rc) { | ||
374 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, | ||
375 | ISCSI_LOGIN_STATUS_NO_RESOURCES); | ||
376 | return -1; | ||
377 | } | ||
378 | } | ||
364 | 379 | ||
365 | if (conn->conn_transport->iscsit_put_login_tx(conn, login, | 380 | if (conn->conn_transport->iscsit_put_login_tx(conn, login, |
366 | login->rsp_length + padding) < 0) | 381 | login->rsp_length + padding) < 0) |
367 | return -1; | 382 | goto err; |
368 | 383 | ||
369 | login->rsp_length = 0; | 384 | login->rsp_length = 0; |
370 | mutex_lock(&sess->cmdsn_mutex); | 385 | mutex_lock(&sess->cmdsn_mutex); |
@@ -373,6 +388,23 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log | |||
373 | mutex_unlock(&sess->cmdsn_mutex); | 388 | mutex_unlock(&sess->cmdsn_mutex); |
374 | 389 | ||
375 | return 0; | 390 | return 0; |
391 | |||
392 | err: | ||
393 | if (login->login_complete) { | ||
394 | if (conn->rx_thread && conn->rx_thread_active) { | ||
395 | send_sig(SIGINT, conn->rx_thread, 1); | ||
396 | kthread_stop(conn->rx_thread); | ||
397 | } | ||
398 | if (conn->tx_thread && conn->tx_thread_active) { | ||
399 | send_sig(SIGINT, conn->tx_thread, 1); | ||
400 | kthread_stop(conn->tx_thread); | ||
401 | } | ||
402 | spin_lock(&iscsit_global->ts_bitmap_lock); | ||
403 | bitmap_release_region(iscsit_global->ts_bitmap, conn->bitmap_id, | ||
404 | get_order(1)); | ||
405 | spin_unlock(&iscsit_global->ts_bitmap_lock); | ||
406 | } | ||
407 | return -1; | ||
376 | } | 408 | } |
377 | 409 | ||
378 | static void iscsi_target_sk_data_ready(struct sock *sk) | 410 | static void iscsi_target_sk_data_ready(struct sock *sk) |
diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h index 34117b8b72e4..0aedbb2c10e0 100644 --- a/include/target/iscsi/iscsi_target_core.h +++ b/include/target/iscsi/iscsi_target_core.h | |||
@@ -595,6 +595,7 @@ struct iscsi_conn { | |||
595 | int bitmap_id; | 595 | int bitmap_id; |
596 | int rx_thread_active; | 596 | int rx_thread_active; |
597 | struct task_struct *rx_thread; | 597 | struct task_struct *rx_thread; |
598 | struct completion rx_login_comp; | ||
598 | int tx_thread_active; | 599 | int tx_thread_active; |
599 | struct task_struct *tx_thread; | 600 | struct task_struct *tx_thread; |
600 | /* list_head for session connection list */ | 601 | /* list_head for session connection list */ |