aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/target
diff options
context:
space:
mode:
authorNicholas Bellinger <nab@linux-iscsi.org>2013-08-15 15:49:02 -0400
committerNicholas Bellinger <nab@linux-iscsi.org>2013-09-09 16:34:09 -0400
commita91eb7d9dc8e00de9618633dcb62643fd5eee498 (patch)
tree88835592b9894fa727d4f3f27c9dee8c53644a38 /drivers/target
parentdfecf611a1bb46dfe19fc5329a23ef12c1f0591d (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.c55
-rw-r--r--drivers/target/iscsi/iscsi_target.h6
-rw-r--r--drivers/target/iscsi/iscsi_target_core.h15
-rw-r--r--drivers/target/iscsi/iscsi_target_login.c162
-rw-r--r--drivers/target/iscsi/iscsi_target_login.h3
-rw-r--r--drivers/target/iscsi/iscsi_target_tpg.c18
-rw-r--r--drivers/target/iscsi/iscsi_target_tpg.h2
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
253int iscsit_deaccess_np(struct iscsi_np *np, struct iscsi_portal_group *tpg) 252void 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
260int 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(
410int iscsit_reset_np_thread( 417int 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 *);
7extern struct iscsi_tiqn *iscsit_add_tiqn(unsigned char *); 7extern struct iscsi_tiqn *iscsit_add_tiqn(unsigned char *);
8extern void iscsit_del_tiqn(struct iscsi_tiqn *); 8extern void iscsit_del_tiqn(struct iscsi_tiqn *);
9extern int iscsit_access_np(struct iscsi_np *, struct iscsi_portal_group *); 9extern int iscsit_access_np(struct iscsi_np *, struct iscsi_portal_group *);
10extern int iscsit_deaccess_np(struct iscsi_np *, struct iscsi_portal_group *); 10extern void iscsit_login_kref_put(struct kref *);
11extern int iscsit_deaccess_np(struct iscsi_np *, struct iscsi_portal_group *,
12 struct iscsi_tpg_np *);
11extern bool iscsit_check_np_match(struct __kernel_sockaddr_storage *, 13extern bool iscsit_check_np_match(struct __kernel_sockaddr_storage *,
12 struct iscsi_np *, int); 14 struct iscsi_np *, int);
13extern struct iscsi_np *iscsit_add_np(struct __kernel_sockaddr_storage *, 15extern struct iscsi_np *iscsit_add_np(struct __kernel_sockaddr_storage *,
14 char *, int); 16 char *, int);
15extern int iscsit_reset_np_thread(struct iscsi_np *, struct iscsi_tpg_np *, 17extern int iscsit_reset_np_thread(struct iscsi_np *, struct iscsi_tpg_np *,
16 struct iscsi_portal_group *); 18 struct iscsi_portal_group *, bool);
17extern int iscsit_del_np(struct iscsi_np *); 19extern int iscsit_del_np(struct iscsi_np *);
18extern int iscsit_reject_cmd(struct iscsi_cmd *cmd, u8, unsigned char *); 20extern int iscsit_reject_cmd(struct iscsi_cmd *cmd, u8, unsigned char *);
19extern void iscsit_set_unsoliticed_dataout(struct iscsi_cmd *); 21extern 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
699struct iscsi_node_attrib { 709struct 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
793struct iscsi_portal_group { 804struct 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
687static int iscsi_post_login_handler( 688int 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
1128void 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
1149old_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
1127static int __iscsi_target_login_thread(struct iscsi_np *np) 1199static 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
1314new_sess_out: 1395new_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);
1329old_sess_out: 1397old_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
1384out: 1408out:
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 *);
12extern int iscsit_get_login_rx(struct iscsi_conn *, struct iscsi_login *); 12extern int iscsit_get_login_rx(struct iscsi_conn *, struct iscsi_login *);
13extern int iscsit_put_login_tx(struct iscsi_conn *, struct iscsi_login *, u32); 13extern int iscsit_put_login_tx(struct iscsi_conn *, struct iscsi_login *, u32);
14extern void iscsit_free_conn(struct iscsi_np *, struct iscsi_conn *); 14extern void iscsit_free_conn(struct iscsi_np *, struct iscsi_conn *);
15extern int iscsi_post_login_handler(struct iscsi_np *, struct iscsi_conn *, u8);
16extern void iscsi_target_login_sess_out(struct iscsi_conn *, struct iscsi_np *,
17 bool, bool);
15extern int iscsi_target_login_thread(void *); 18extern int iscsi_target_login_thread(void *);
16extern int iscsi_login_disable_FIM_keys(struct iscsi_param_list *, struct iscsi_conn *); 19extern 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
176static void iscsit_clear_tpg_np_login_thread( 176static 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
188void iscsit_clear_tpg_np_login_threads( 189void 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 *);
9extern int iscsit_get_tpg(struct iscsi_portal_group *); 9extern int iscsit_get_tpg(struct iscsi_portal_group *);
10extern void iscsit_put_tpg(struct iscsi_portal_group *); 10extern void iscsit_put_tpg(struct iscsi_portal_group *);
11extern void iscsit_clear_tpg_np_login_threads(struct iscsi_portal_group *); 11extern void iscsit_clear_tpg_np_login_threads(struct iscsi_portal_group *, bool);
12extern void iscsit_tpg_dump_params(struct iscsi_portal_group *); 12extern void iscsit_tpg_dump_params(struct iscsi_portal_group *);
13extern int iscsit_tpg_add_portal_group(struct iscsi_tiqn *, struct iscsi_portal_group *); 13extern int iscsit_tpg_add_portal_group(struct iscsi_tiqn *, struct iscsi_portal_group *);
14extern int iscsit_tpg_del_portal_group(struct iscsi_tiqn *, struct iscsi_portal_group *, 14extern int iscsit_tpg_del_portal_group(struct iscsi_tiqn *, struct iscsi_portal_group *,