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 */ |
