diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2013-08-15 15:49:02 -0400 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2013-09-09 16:34:09 -0400 |
commit | a91eb7d9dc8e00de9618633dcb62643fd5eee498 (patch) | |
tree | 88835592b9894fa727d4f3f27c9dee8c53644a38 /drivers/target | |
parent | dfecf611a1bb46dfe19fc5329a23ef12c1f0591d (diff) |
iscsi-target: Prepare login code for multi-plexing support
This patch prepares the iscsi-target login code for multi-plexing
support. This includes:
- Adding iscsi_tpg_np->tpg_np_kref + iscsit_login_kref_put() for
handling callback of iscsi_tpg_np->tpg_np_comp
- Adding kref_put() in iscsit_deaccess_np()
- Adding kref_put() and wait_for_completion() in
iscsit_reset_np_thread()
- Refactor login failure path release logic into
iscsi_target_login_sess_out()
- Update __iscsi_target_login_thread() to handle
iscsi_post_login_handler() asynchronous completion
- Add shutdown parameter for iscsit_clear_tpg_np_login_thread*()
v3 changes:
- Convert iscsi_portal_group->np_login_lock to ->np_login_sem
- Add LOGIN_FLAGS definitions
v2 changes:
- Remove duplicate call to iscsi_post_login_handler() in
__iscsi_target_login_thread()
- Drop unused iscsi_np->np_login_tpg
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/target')
-rw-r--r-- | drivers/target/iscsi/iscsi_target.c | 55 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target.h | 6 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_core.h | 15 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_login.c | 162 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_login.h | 3 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_tpg.c | 18 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_tpg.h | 2 |
7 files changed, 154 insertions, 107 deletions
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index c4aeac314b2e..1dff3e01f92c 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c | |||
@@ -220,11 +220,6 @@ int iscsit_access_np(struct iscsi_np *np, struct iscsi_portal_group *tpg) | |||
220 | spin_unlock_bh(&np->np_thread_lock); | 220 | spin_unlock_bh(&np->np_thread_lock); |
221 | return -1; | 221 | return -1; |
222 | } | 222 | } |
223 | if (np->np_login_tpg) { | ||
224 | pr_err("np->np_login_tpg() is not NULL!\n"); | ||
225 | spin_unlock_bh(&np->np_thread_lock); | ||
226 | return -1; | ||
227 | } | ||
228 | spin_unlock_bh(&np->np_thread_lock); | 223 | spin_unlock_bh(&np->np_thread_lock); |
229 | /* | 224 | /* |
230 | * Determine if the portal group is accepting storage traffic. | 225 | * Determine if the portal group is accepting storage traffic. |
@@ -239,26 +234,38 @@ int iscsit_access_np(struct iscsi_np *np, struct iscsi_portal_group *tpg) | |||
239 | /* | 234 | /* |
240 | * Here we serialize access across the TIQN+TPG Tuple. | 235 | * Here we serialize access across the TIQN+TPG Tuple. |
241 | */ | 236 | */ |
242 | ret = mutex_lock_interruptible(&tpg->np_login_lock); | 237 | ret = down_interruptible(&tpg->np_login_sem); |
243 | if ((ret != 0) || signal_pending(current)) | 238 | if ((ret != 0) || signal_pending(current)) |
244 | return -1; | 239 | return -1; |
245 | 240 | ||
246 | spin_lock_bh(&np->np_thread_lock); | 241 | spin_lock_bh(&tpg->tpg_state_lock); |
247 | np->np_login_tpg = tpg; | 242 | if (tpg->tpg_state != TPG_STATE_ACTIVE) { |
248 | spin_unlock_bh(&np->np_thread_lock); | 243 | spin_unlock_bh(&tpg->tpg_state_lock); |
244 | up(&tpg->np_login_sem); | ||
245 | return -1; | ||
246 | } | ||
247 | spin_unlock_bh(&tpg->tpg_state_lock); | ||
249 | 248 | ||
250 | return 0; | 249 | return 0; |
251 | } | 250 | } |
252 | 251 | ||
253 | int iscsit_deaccess_np(struct iscsi_np *np, struct iscsi_portal_group *tpg) | 252 | void iscsit_login_kref_put(struct kref *kref) |
253 | { | ||
254 | struct iscsi_tpg_np *tpg_np = container_of(kref, | ||
255 | struct iscsi_tpg_np, tpg_np_kref); | ||
256 | |||
257 | complete(&tpg_np->tpg_np_comp); | ||
258 | } | ||
259 | |||
260 | int iscsit_deaccess_np(struct iscsi_np *np, struct iscsi_portal_group *tpg, | ||
261 | struct iscsi_tpg_np *tpg_np) | ||
254 | { | 262 | { |
255 | struct iscsi_tiqn *tiqn = tpg->tpg_tiqn; | 263 | struct iscsi_tiqn *tiqn = tpg->tpg_tiqn; |
256 | 264 | ||
257 | spin_lock_bh(&np->np_thread_lock); | 265 | up(&tpg->np_login_sem); |
258 | np->np_login_tpg = NULL; | ||
259 | spin_unlock_bh(&np->np_thread_lock); | ||
260 | 266 | ||
261 | mutex_unlock(&tpg->np_login_lock); | 267 | if (tpg_np) |
268 | kref_put(&tpg_np->tpg_np_kref, iscsit_login_kref_put); | ||
262 | 269 | ||
263 | if (tiqn) | 270 | if (tiqn) |
264 | iscsit_put_tiqn_for_login(tiqn); | 271 | iscsit_put_tiqn_for_login(tiqn); |
@@ -410,20 +417,10 @@ struct iscsi_np *iscsit_add_np( | |||
410 | int iscsit_reset_np_thread( | 417 | int iscsit_reset_np_thread( |
411 | struct iscsi_np *np, | 418 | struct iscsi_np *np, |
412 | struct iscsi_tpg_np *tpg_np, | 419 | struct iscsi_tpg_np *tpg_np, |
413 | struct iscsi_portal_group *tpg) | 420 | struct iscsi_portal_group *tpg, |
421 | bool shutdown) | ||
414 | { | 422 | { |
415 | spin_lock_bh(&np->np_thread_lock); | 423 | spin_lock_bh(&np->np_thread_lock); |
416 | if (tpg && tpg_np) { | ||
417 | /* | ||
418 | * The reset operation need only be performed when the | ||
419 | * passed struct iscsi_portal_group has a login in progress | ||
420 | * to one of the network portals. | ||
421 | */ | ||
422 | if (tpg_np->tpg_np->np_login_tpg != tpg) { | ||
423 | spin_unlock_bh(&np->np_thread_lock); | ||
424 | return 0; | ||
425 | } | ||
426 | } | ||
427 | if (np->np_thread_state == ISCSI_NP_THREAD_INACTIVE) { | 424 | if (np->np_thread_state == ISCSI_NP_THREAD_INACTIVE) { |
428 | spin_unlock_bh(&np->np_thread_lock); | 425 | spin_unlock_bh(&np->np_thread_lock); |
429 | return 0; | 426 | return 0; |
@@ -438,6 +435,12 @@ int iscsit_reset_np_thread( | |||
438 | } | 435 | } |
439 | spin_unlock_bh(&np->np_thread_lock); | 436 | spin_unlock_bh(&np->np_thread_lock); |
440 | 437 | ||
438 | if (tpg_np && shutdown) { | ||
439 | kref_put(&tpg_np->tpg_np_kref, iscsit_login_kref_put); | ||
440 | |||
441 | wait_for_completion(&tpg_np->tpg_np_comp); | ||
442 | } | ||
443 | |||
441 | return 0; | 444 | return 0; |
442 | } | 445 | } |
443 | 446 | ||
diff --git a/drivers/target/iscsi/iscsi_target.h b/drivers/target/iscsi/iscsi_target.h index 2c437cb8ca00..f82f6273526e 100644 --- a/drivers/target/iscsi/iscsi_target.h +++ b/drivers/target/iscsi/iscsi_target.h | |||
@@ -7,13 +7,15 @@ extern void iscsit_put_tiqn_for_login(struct iscsi_tiqn *); | |||
7 | extern struct iscsi_tiqn *iscsit_add_tiqn(unsigned char *); | 7 | extern struct iscsi_tiqn *iscsit_add_tiqn(unsigned char *); |
8 | extern void iscsit_del_tiqn(struct iscsi_tiqn *); | 8 | extern void iscsit_del_tiqn(struct iscsi_tiqn *); |
9 | extern int iscsit_access_np(struct iscsi_np *, struct iscsi_portal_group *); | 9 | extern int iscsit_access_np(struct iscsi_np *, struct iscsi_portal_group *); |
10 | extern int iscsit_deaccess_np(struct iscsi_np *, struct iscsi_portal_group *); | 10 | extern void iscsit_login_kref_put(struct kref *); |
11 | extern int iscsit_deaccess_np(struct iscsi_np *, struct iscsi_portal_group *, | ||
12 | struct iscsi_tpg_np *); | ||
11 | extern bool iscsit_check_np_match(struct __kernel_sockaddr_storage *, | 13 | extern bool iscsit_check_np_match(struct __kernel_sockaddr_storage *, |
12 | struct iscsi_np *, int); | 14 | struct iscsi_np *, int); |
13 | extern struct iscsi_np *iscsit_add_np(struct __kernel_sockaddr_storage *, | 15 | extern struct iscsi_np *iscsit_add_np(struct __kernel_sockaddr_storage *, |
14 | char *, int); | 16 | char *, int); |
15 | extern int iscsit_reset_np_thread(struct iscsi_np *, struct iscsi_tpg_np *, | 17 | extern int iscsit_reset_np_thread(struct iscsi_np *, struct iscsi_tpg_np *, |
16 | struct iscsi_portal_group *); | 18 | struct iscsi_portal_group *, bool); |
17 | extern int iscsit_del_np(struct iscsi_np *); | 19 | extern int iscsit_del_np(struct iscsi_np *); |
18 | extern int iscsit_reject_cmd(struct iscsi_cmd *cmd, u8, unsigned char *); | 20 | extern int iscsit_reject_cmd(struct iscsi_cmd *cmd, u8, unsigned char *); |
19 | extern void iscsit_set_unsoliticed_dataout(struct iscsi_cmd *); | 21 | extern void iscsit_set_unsoliticed_dataout(struct iscsi_cmd *); |
diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h index 4f77a78edef9..46228465d190 100644 --- a/drivers/target/iscsi/iscsi_target_core.h +++ b/drivers/target/iscsi/iscsi_target_core.h | |||
@@ -554,6 +554,13 @@ struct iscsi_conn { | |||
554 | struct completion rx_half_close_comp; | 554 | struct completion rx_half_close_comp; |
555 | /* socket used by this connection */ | 555 | /* socket used by this connection */ |
556 | struct socket *sock; | 556 | struct socket *sock; |
557 | void (*orig_data_ready)(struct sock *, int); | ||
558 | #define LOGIN_FLAGS_READ_ACTIVE 1 | ||
559 | #define LOGIN_FLAGS_CLOSED 2 | ||
560 | #define LOGIN_FLAGS_READY 4 | ||
561 | unsigned long login_flags; | ||
562 | struct delayed_work login_work; | ||
563 | struct iscsi_login *login; | ||
557 | struct timer_list nopin_timer; | 564 | struct timer_list nopin_timer; |
558 | struct timer_list nopin_response_timer; | 565 | struct timer_list nopin_response_timer; |
559 | struct timer_list transport_timer; | 566 | struct timer_list transport_timer; |
@@ -584,6 +591,7 @@ struct iscsi_conn { | |||
584 | void *context; | 591 | void *context; |
585 | struct iscsi_login_thread_s *login_thread; | 592 | struct iscsi_login_thread_s *login_thread; |
586 | struct iscsi_portal_group *tpg; | 593 | struct iscsi_portal_group *tpg; |
594 | struct iscsi_tpg_np *tpg_np; | ||
587 | /* Pointer to parent session */ | 595 | /* Pointer to parent session */ |
588 | struct iscsi_session *sess; | 596 | struct iscsi_session *sess; |
589 | /* Pointer to thread_set in use for this conn's threads */ | 597 | /* Pointer to thread_set in use for this conn's threads */ |
@@ -682,6 +690,7 @@ struct iscsi_login { | |||
682 | u8 version_max; | 690 | u8 version_max; |
683 | u8 login_complete; | 691 | u8 login_complete; |
684 | u8 login_failed; | 692 | u8 login_failed; |
693 | bool zero_tsih; | ||
685 | char isid[6]; | 694 | char isid[6]; |
686 | u32 cmd_sn; | 695 | u32 cmd_sn; |
687 | itt_t init_task_tag; | 696 | itt_t init_task_tag; |
@@ -694,6 +703,7 @@ struct iscsi_login { | |||
694 | char *req_buf; | 703 | char *req_buf; |
695 | char *rsp_buf; | 704 | char *rsp_buf; |
696 | struct iscsi_conn *conn; | 705 | struct iscsi_conn *conn; |
706 | struct iscsi_np *np; | ||
697 | } ____cacheline_aligned; | 707 | } ____cacheline_aligned; |
698 | 708 | ||
699 | struct iscsi_node_attrib { | 709 | struct iscsi_node_attrib { |
@@ -773,7 +783,6 @@ struct iscsi_np { | |||
773 | struct __kernel_sockaddr_storage np_sockaddr; | 783 | struct __kernel_sockaddr_storage np_sockaddr; |
774 | struct task_struct *np_thread; | 784 | struct task_struct *np_thread; |
775 | struct timer_list np_login_timer; | 785 | struct timer_list np_login_timer; |
776 | struct iscsi_portal_group *np_login_tpg; | ||
777 | void *np_context; | 786 | void *np_context; |
778 | struct iscsit_transport *np_transport; | 787 | struct iscsit_transport *np_transport; |
779 | struct list_head np_list; | 788 | struct list_head np_list; |
@@ -788,6 +797,8 @@ struct iscsi_tpg_np { | |||
788 | struct list_head tpg_np_parent_list; | 797 | struct list_head tpg_np_parent_list; |
789 | struct se_tpg_np se_tpg_np; | 798 | struct se_tpg_np se_tpg_np; |
790 | spinlock_t tpg_np_parent_lock; | 799 | spinlock_t tpg_np_parent_lock; |
800 | struct completion tpg_np_comp; | ||
801 | struct kref tpg_np_kref; | ||
791 | }; | 802 | }; |
792 | 803 | ||
793 | struct iscsi_portal_group { | 804 | struct iscsi_portal_group { |
@@ -809,7 +820,7 @@ struct iscsi_portal_group { | |||
809 | spinlock_t tpg_state_lock; | 820 | spinlock_t tpg_state_lock; |
810 | struct se_portal_group tpg_se_tpg; | 821 | struct se_portal_group tpg_se_tpg; |
811 | struct mutex tpg_access_lock; | 822 | struct mutex tpg_access_lock; |
812 | struct mutex np_login_lock; | 823 | struct semaphore np_login_sem; |
813 | struct iscsi_tpg_attrib tpg_attrib; | 824 | struct iscsi_tpg_attrib tpg_attrib; |
814 | struct iscsi_node_auth tpg_demo_auth; | 825 | struct iscsi_node_auth tpg_demo_auth; |
815 | /* Pointer to default list of iSCSI parameters for TPG */ | 826 | /* Pointer to default list of iSCSI parameters for TPG */ |
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 0e85238bdf48..d903c0c702d6 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c | |||
@@ -50,6 +50,7 @@ static struct iscsi_login *iscsi_login_init_conn(struct iscsi_conn *conn) | |||
50 | pr_err("Unable to allocate memory for struct iscsi_login.\n"); | 50 | pr_err("Unable to allocate memory for struct iscsi_login.\n"); |
51 | return NULL; | 51 | return NULL; |
52 | } | 52 | } |
53 | conn->login = login; | ||
53 | login->conn = conn; | 54 | login->conn = conn; |
54 | login->first_request = 1; | 55 | login->first_request = 1; |
55 | 56 | ||
@@ -684,7 +685,7 @@ static void iscsi_post_login_start_timers(struct iscsi_conn *conn) | |||
684 | iscsit_start_nopin_timer(conn); | 685 | iscsit_start_nopin_timer(conn); |
685 | } | 686 | } |
686 | 687 | ||
687 | static int iscsi_post_login_handler( | 688 | int iscsi_post_login_handler( |
688 | struct iscsi_np *np, | 689 | struct iscsi_np *np, |
689 | struct iscsi_conn *conn, | 690 | struct iscsi_conn *conn, |
690 | u8 zero_tsih) | 691 | u8 zero_tsih) |
@@ -1124,6 +1125,77 @@ iscsit_conn_set_transport(struct iscsi_conn *conn, struct iscsit_transport *t) | |||
1124 | return 0; | 1125 | return 0; |
1125 | } | 1126 | } |
1126 | 1127 | ||
1128 | void iscsi_target_login_sess_out(struct iscsi_conn *conn, | ||
1129 | struct iscsi_np *np, bool zero_tsih, bool new_sess) | ||
1130 | { | ||
1131 | if (new_sess == false) | ||
1132 | goto old_sess_out; | ||
1133 | |||
1134 | pr_err("iSCSI Login negotiation failed.\n"); | ||
1135 | iscsit_collect_login_stats(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, | ||
1136 | ISCSI_LOGIN_STATUS_INIT_ERR); | ||
1137 | if (!zero_tsih || !conn->sess) | ||
1138 | goto old_sess_out; | ||
1139 | if (conn->sess->se_sess) | ||
1140 | transport_free_session(conn->sess->se_sess); | ||
1141 | if (conn->sess->session_index != 0) { | ||
1142 | spin_lock_bh(&sess_idr_lock); | ||
1143 | idr_remove(&sess_idr, conn->sess->session_index); | ||
1144 | spin_unlock_bh(&sess_idr_lock); | ||
1145 | } | ||
1146 | kfree(conn->sess->sess_ops); | ||
1147 | kfree(conn->sess); | ||
1148 | |||
1149 | old_sess_out: | ||
1150 | iscsi_stop_login_thread_timer(np); | ||
1151 | /* | ||
1152 | * If login negotiation fails check if the Time2Retain timer | ||
1153 | * needs to be restarted. | ||
1154 | */ | ||
1155 | if (!zero_tsih && conn->sess) { | ||
1156 | spin_lock_bh(&conn->sess->conn_lock); | ||
1157 | if (conn->sess->session_state == TARG_SESS_STATE_FAILED) { | ||
1158 | struct se_portal_group *se_tpg = | ||
1159 | &ISCSI_TPG_C(conn)->tpg_se_tpg; | ||
1160 | |||
1161 | atomic_set(&conn->sess->session_continuation, 0); | ||
1162 | spin_unlock_bh(&conn->sess->conn_lock); | ||
1163 | spin_lock_bh(&se_tpg->session_lock); | ||
1164 | iscsit_start_time2retain_handler(conn->sess); | ||
1165 | spin_unlock_bh(&se_tpg->session_lock); | ||
1166 | } else | ||
1167 | spin_unlock_bh(&conn->sess->conn_lock); | ||
1168 | iscsit_dec_session_usage_count(conn->sess); | ||
1169 | } | ||
1170 | |||
1171 | if (!IS_ERR(conn->conn_rx_hash.tfm)) | ||
1172 | crypto_free_hash(conn->conn_rx_hash.tfm); | ||
1173 | if (!IS_ERR(conn->conn_tx_hash.tfm)) | ||
1174 | crypto_free_hash(conn->conn_tx_hash.tfm); | ||
1175 | |||
1176 | if (conn->conn_cpumask) | ||
1177 | free_cpumask_var(conn->conn_cpumask); | ||
1178 | |||
1179 | kfree(conn->conn_ops); | ||
1180 | |||
1181 | if (conn->param_list) { | ||
1182 | iscsi_release_param_list(conn->param_list); | ||
1183 | conn->param_list = NULL; | ||
1184 | } | ||
1185 | iscsi_target_nego_release(conn); | ||
1186 | |||
1187 | if (conn->sock) { | ||
1188 | sock_release(conn->sock); | ||
1189 | conn->sock = NULL; | ||
1190 | } | ||
1191 | |||
1192 | if (conn->conn_transport->iscsit_free_conn) | ||
1193 | conn->conn_transport->iscsit_free_conn(conn); | ||
1194 | |||
1195 | iscsit_put_transport(conn->conn_transport); | ||
1196 | kfree(conn); | ||
1197 | } | ||
1198 | |||
1127 | static int __iscsi_target_login_thread(struct iscsi_np *np) | 1199 | static int __iscsi_target_login_thread(struct iscsi_np *np) |
1128 | { | 1200 | { |
1129 | u8 *buffer, zero_tsih = 0; | 1201 | u8 *buffer, zero_tsih = 0; |
@@ -1132,6 +1204,8 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) | |||
1132 | struct iscsi_login *login; | 1204 | struct iscsi_login *login; |
1133 | struct iscsi_portal_group *tpg = NULL; | 1205 | struct iscsi_portal_group *tpg = NULL; |
1134 | struct iscsi_login_req *pdu; | 1206 | struct iscsi_login_req *pdu; |
1207 | struct iscsi_tpg_np *tpg_np; | ||
1208 | bool new_sess = false; | ||
1135 | 1209 | ||
1136 | flush_signals(current); | 1210 | flush_signals(current); |
1137 | 1211 | ||
@@ -1273,6 +1347,7 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) | |||
1273 | tpg = conn->tpg; | 1347 | tpg = conn->tpg; |
1274 | goto new_sess_out; | 1348 | goto new_sess_out; |
1275 | } | 1349 | } |
1350 | login->zero_tsih = zero_tsih; | ||
1276 | 1351 | ||
1277 | tpg = conn->tpg; | 1352 | tpg = conn->tpg; |
1278 | if (!tpg) { | 1353 | if (!tpg) { |
@@ -1288,7 +1363,8 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) | |||
1288 | goto old_sess_out; | 1363 | goto old_sess_out; |
1289 | } | 1364 | } |
1290 | 1365 | ||
1291 | if (iscsi_target_start_negotiation(login, conn) < 0) | 1366 | ret = iscsi_target_start_negotiation(login, conn); |
1367 | if (ret < 0) | ||
1292 | goto new_sess_out; | 1368 | goto new_sess_out; |
1293 | 1369 | ||
1294 | if (!conn->sess) { | 1370 | if (!conn->sess) { |
@@ -1301,84 +1377,32 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) | |||
1301 | if (signal_pending(current)) | 1377 | if (signal_pending(current)) |
1302 | goto new_sess_out; | 1378 | goto new_sess_out; |
1303 | 1379 | ||
1304 | ret = iscsi_post_login_handler(np, conn, zero_tsih); | 1380 | if (ret == 1) { |
1381 | tpg_np = conn->tpg_np; | ||
1305 | 1382 | ||
1306 | if (ret < 0) | 1383 | ret = iscsi_post_login_handler(np, conn, zero_tsih); |
1307 | goto new_sess_out; | 1384 | if (ret < 0) |
1385 | goto new_sess_out; | ||
1386 | |||
1387 | iscsit_deaccess_np(np, tpg, tpg_np); | ||
1388 | } | ||
1308 | 1389 | ||
1309 | iscsit_deaccess_np(np, tpg); | ||
1310 | tpg = NULL; | 1390 | tpg = NULL; |
1391 | tpg_np = NULL; | ||
1311 | /* Get another socket */ | 1392 | /* Get another socket */ |
1312 | return 1; | 1393 | return 1; |
1313 | 1394 | ||
1314 | new_sess_out: | 1395 | new_sess_out: |
1315 | pr_err("iSCSI Login negotiation failed.\n"); | 1396 | new_sess = true; |
1316 | iscsit_collect_login_stats(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, | ||
1317 | ISCSI_LOGIN_STATUS_INIT_ERR); | ||
1318 | if (!zero_tsih || !conn->sess) | ||
1319 | goto old_sess_out; | ||
1320 | if (conn->sess->se_sess) | ||
1321 | transport_free_session(conn->sess->se_sess); | ||
1322 | if (conn->sess->session_index != 0) { | ||
1323 | spin_lock_bh(&sess_idr_lock); | ||
1324 | idr_remove(&sess_idr, conn->sess->session_index); | ||
1325 | spin_unlock_bh(&sess_idr_lock); | ||
1326 | } | ||
1327 | kfree(conn->sess->sess_ops); | ||
1328 | kfree(conn->sess); | ||
1329 | old_sess_out: | 1397 | old_sess_out: |
1330 | iscsi_stop_login_thread_timer(np); | 1398 | tpg_np = conn->tpg_np; |
1331 | /* | 1399 | iscsi_target_login_sess_out(conn, np, zero_tsih, new_sess); |
1332 | * If login negotiation fails check if the Time2Retain timer | 1400 | new_sess = false; |
1333 | * needs to be restarted. | ||
1334 | */ | ||
1335 | if (!zero_tsih && conn->sess) { | ||
1336 | spin_lock_bh(&conn->sess->conn_lock); | ||
1337 | if (conn->sess->session_state == TARG_SESS_STATE_FAILED) { | ||
1338 | struct se_portal_group *se_tpg = | ||
1339 | &ISCSI_TPG_C(conn)->tpg_se_tpg; | ||
1340 | |||
1341 | atomic_set(&conn->sess->session_continuation, 0); | ||
1342 | spin_unlock_bh(&conn->sess->conn_lock); | ||
1343 | spin_lock_bh(&se_tpg->session_lock); | ||
1344 | iscsit_start_time2retain_handler(conn->sess); | ||
1345 | spin_unlock_bh(&se_tpg->session_lock); | ||
1346 | } else | ||
1347 | spin_unlock_bh(&conn->sess->conn_lock); | ||
1348 | iscsit_dec_session_usage_count(conn->sess); | ||
1349 | } | ||
1350 | |||
1351 | if (!IS_ERR(conn->conn_rx_hash.tfm)) | ||
1352 | crypto_free_hash(conn->conn_rx_hash.tfm); | ||
1353 | if (!IS_ERR(conn->conn_tx_hash.tfm)) | ||
1354 | crypto_free_hash(conn->conn_tx_hash.tfm); | ||
1355 | |||
1356 | if (conn->conn_cpumask) | ||
1357 | free_cpumask_var(conn->conn_cpumask); | ||
1358 | |||
1359 | kfree(conn->conn_ops); | ||
1360 | |||
1361 | if (conn->param_list) { | ||
1362 | iscsi_release_param_list(conn->param_list); | ||
1363 | conn->param_list = NULL; | ||
1364 | } | ||
1365 | iscsi_target_nego_release(conn); | ||
1366 | |||
1367 | if (conn->sock) { | ||
1368 | sock_release(conn->sock); | ||
1369 | conn->sock = NULL; | ||
1370 | } | ||
1371 | |||
1372 | if (conn->conn_transport->iscsit_free_conn) | ||
1373 | conn->conn_transport->iscsit_free_conn(conn); | ||
1374 | |||
1375 | iscsit_put_transport(conn->conn_transport); | ||
1376 | |||
1377 | kfree(conn); | ||
1378 | 1401 | ||
1379 | if (tpg) { | 1402 | if (tpg) { |
1380 | iscsit_deaccess_np(np, tpg); | 1403 | iscsit_deaccess_np(np, tpg, tpg_np); |
1381 | tpg = NULL; | 1404 | tpg = NULL; |
1405 | tpg_np = NULL; | ||
1382 | } | 1406 | } |
1383 | 1407 | ||
1384 | out: | 1408 | out: |
diff --git a/drivers/target/iscsi/iscsi_target_login.h b/drivers/target/iscsi/iscsi_target_login.h index 63efd2878451..29d098324b7f 100644 --- a/drivers/target/iscsi/iscsi_target_login.h +++ b/drivers/target/iscsi/iscsi_target_login.h | |||
@@ -12,6 +12,9 @@ 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); | ||
16 | extern void iscsi_target_login_sess_out(struct iscsi_conn *, struct iscsi_np *, | ||
17 | bool, bool); | ||
15 | extern int iscsi_target_login_thread(void *); | 18 | extern int iscsi_target_login_thread(void *); |
16 | extern int iscsi_login_disable_FIM_keys(struct iscsi_param_list *, struct iscsi_conn *); | 19 | extern int iscsi_login_disable_FIM_keys(struct iscsi_param_list *, struct iscsi_conn *); |
17 | 20 | ||
diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index 439260b7d87f..4bf8913992a5 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c | |||
@@ -49,7 +49,7 @@ struct iscsi_portal_group *iscsit_alloc_portal_group(struct iscsi_tiqn *tiqn, u1 | |||
49 | INIT_LIST_HEAD(&tpg->tpg_gnp_list); | 49 | INIT_LIST_HEAD(&tpg->tpg_gnp_list); |
50 | INIT_LIST_HEAD(&tpg->tpg_list); | 50 | INIT_LIST_HEAD(&tpg->tpg_list); |
51 | mutex_init(&tpg->tpg_access_lock); | 51 | mutex_init(&tpg->tpg_access_lock); |
52 | mutex_init(&tpg->np_login_lock); | 52 | sema_init(&tpg->np_login_sem, 1); |
53 | spin_lock_init(&tpg->tpg_state_lock); | 53 | spin_lock_init(&tpg->tpg_state_lock); |
54 | spin_lock_init(&tpg->tpg_np_lock); | 54 | spin_lock_init(&tpg->tpg_np_lock); |
55 | 55 | ||
@@ -175,18 +175,20 @@ void iscsit_put_tpg(struct iscsi_portal_group *tpg) | |||
175 | 175 | ||
176 | static void iscsit_clear_tpg_np_login_thread( | 176 | static void iscsit_clear_tpg_np_login_thread( |
177 | struct iscsi_tpg_np *tpg_np, | 177 | struct iscsi_tpg_np *tpg_np, |
178 | struct iscsi_portal_group *tpg) | 178 | struct iscsi_portal_group *tpg, |
179 | bool shutdown) | ||
179 | { | 180 | { |
180 | if (!tpg_np->tpg_np) { | 181 | if (!tpg_np->tpg_np) { |
181 | pr_err("struct iscsi_tpg_np->tpg_np is NULL!\n"); | 182 | pr_err("struct iscsi_tpg_np->tpg_np is NULL!\n"); |
182 | return; | 183 | return; |
183 | } | 184 | } |
184 | 185 | ||
185 | iscsit_reset_np_thread(tpg_np->tpg_np, tpg_np, tpg); | 186 | iscsit_reset_np_thread(tpg_np->tpg_np, tpg_np, tpg, shutdown); |
186 | } | 187 | } |
187 | 188 | ||
188 | void iscsit_clear_tpg_np_login_threads( | 189 | void iscsit_clear_tpg_np_login_threads( |
189 | struct iscsi_portal_group *tpg) | 190 | struct iscsi_portal_group *tpg, |
191 | bool shutdown) | ||
190 | { | 192 | { |
191 | struct iscsi_tpg_np *tpg_np; | 193 | struct iscsi_tpg_np *tpg_np; |
192 | 194 | ||
@@ -197,7 +199,7 @@ void iscsit_clear_tpg_np_login_threads( | |||
197 | continue; | 199 | continue; |
198 | } | 200 | } |
199 | spin_unlock(&tpg->tpg_np_lock); | 201 | spin_unlock(&tpg->tpg_np_lock); |
200 | iscsit_clear_tpg_np_login_thread(tpg_np, tpg); | 202 | iscsit_clear_tpg_np_login_thread(tpg_np, tpg, shutdown); |
201 | spin_lock(&tpg->tpg_np_lock); | 203 | spin_lock(&tpg->tpg_np_lock); |
202 | } | 204 | } |
203 | spin_unlock(&tpg->tpg_np_lock); | 205 | spin_unlock(&tpg->tpg_np_lock); |
@@ -268,6 +270,8 @@ int iscsit_tpg_del_portal_group( | |||
268 | tpg->tpg_state = TPG_STATE_INACTIVE; | 270 | tpg->tpg_state = TPG_STATE_INACTIVE; |
269 | spin_unlock(&tpg->tpg_state_lock); | 271 | spin_unlock(&tpg->tpg_state_lock); |
270 | 272 | ||
273 | iscsit_clear_tpg_np_login_threads(tpg, true); | ||
274 | |||
271 | if (iscsit_release_sessions_for_tpg(tpg, force) < 0) { | 275 | if (iscsit_release_sessions_for_tpg(tpg, force) < 0) { |
272 | pr_err("Unable to delete iSCSI Target Portal Group:" | 276 | pr_err("Unable to delete iSCSI Target Portal Group:" |
273 | " %hu while active sessions exist, and force=0\n", | 277 | " %hu while active sessions exist, and force=0\n", |
@@ -368,7 +372,7 @@ int iscsit_tpg_disable_portal_group(struct iscsi_portal_group *tpg, int force) | |||
368 | tpg->tpg_state = TPG_STATE_INACTIVE; | 372 | tpg->tpg_state = TPG_STATE_INACTIVE; |
369 | spin_unlock(&tpg->tpg_state_lock); | 373 | spin_unlock(&tpg->tpg_state_lock); |
370 | 374 | ||
371 | iscsit_clear_tpg_np_login_threads(tpg); | 375 | iscsit_clear_tpg_np_login_threads(tpg, false); |
372 | 376 | ||
373 | if (iscsit_release_sessions_for_tpg(tpg, force) < 0) { | 377 | if (iscsit_release_sessions_for_tpg(tpg, force) < 0) { |
374 | spin_lock(&tpg->tpg_state_lock); | 378 | spin_lock(&tpg->tpg_state_lock); |
@@ -520,7 +524,7 @@ static int iscsit_tpg_release_np( | |||
520 | struct iscsi_portal_group *tpg, | 524 | struct iscsi_portal_group *tpg, |
521 | struct iscsi_np *np) | 525 | struct iscsi_np *np) |
522 | { | 526 | { |
523 | iscsit_clear_tpg_np_login_thread(tpg_np, tpg); | 527 | iscsit_clear_tpg_np_login_thread(tpg_np, tpg, true); |
524 | 528 | ||
525 | pr_debug("CORE[%s] - Removed Network Portal: %s:%hu,%hu on %s\n", | 529 | pr_debug("CORE[%s] - Removed Network Portal: %s:%hu,%hu on %s\n", |
526 | tpg->tpg_tiqn->tiqn, np->np_ip, np->np_port, tpg->tpgt, | 530 | tpg->tpg_tiqn->tiqn, np->np_ip, np->np_port, tpg->tpgt, |
diff --git a/drivers/target/iscsi/iscsi_target_tpg.h b/drivers/target/iscsi/iscsi_target_tpg.h index dda48c141a8c..60ef4a9ad91b 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.h +++ b/drivers/target/iscsi/iscsi_target_tpg.h | |||
@@ -8,7 +8,7 @@ extern struct iscsi_portal_group *iscsit_get_tpg_from_np(struct iscsi_tiqn *, | |||
8 | struct iscsi_np *); | 8 | struct iscsi_np *); |
9 | extern int iscsit_get_tpg(struct iscsi_portal_group *); | 9 | extern int iscsit_get_tpg(struct iscsi_portal_group *); |
10 | extern void iscsit_put_tpg(struct iscsi_portal_group *); | 10 | extern void iscsit_put_tpg(struct iscsi_portal_group *); |
11 | extern void iscsit_clear_tpg_np_login_threads(struct iscsi_portal_group *); | 11 | extern void iscsit_clear_tpg_np_login_threads(struct iscsi_portal_group *, bool); |
12 | extern void iscsit_tpg_dump_params(struct iscsi_portal_group *); | 12 | extern void iscsit_tpg_dump_params(struct iscsi_portal_group *); |
13 | extern int iscsit_tpg_add_portal_group(struct iscsi_tiqn *, struct iscsi_portal_group *); | 13 | extern int iscsit_tpg_add_portal_group(struct iscsi_tiqn *, struct iscsi_portal_group *); |
14 | extern int iscsit_tpg_del_portal_group(struct iscsi_tiqn *, struct iscsi_portal_group *, | 14 | extern int iscsit_tpg_del_portal_group(struct iscsi_tiqn *, struct iscsi_portal_group *, |