Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+154 -107
+29 -26
drivers/target/iscsi/iscsi_target.c
··· 220 220 spin_unlock_bh(&np->np_thread_lock); 221 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 223 spin_unlock_bh(&np->np_thread_lock); 229 224 /* 230 225 * Determine if the portal group is accepting storage traffic. ··· 234 239 /* 235 240 * Here we serialize access across the TIQN+TPG Tuple. 236 241 */ 237 - ret = mutex_lock_interruptible(&tpg->np_login_lock); 242 + ret = down_interruptible(&tpg->np_login_sem); 238 243 if ((ret != 0) || signal_pending(current)) 239 244 return -1; 240 245 241 - spin_lock_bh(&np->np_thread_lock); 242 - np->np_login_tpg = tpg; 243 - spin_unlock_bh(&np->np_thread_lock); 246 + spin_lock_bh(&tpg->tpg_state_lock); 247 + if (tpg->tpg_state != TPG_STATE_ACTIVE) { 248 + spin_unlock_bh(&tpg->tpg_state_lock); 249 + up(&tpg->np_login_sem); 250 + return -1; 251 + } 252 + spin_unlock_bh(&tpg->tpg_state_lock); 244 253 245 254 return 0; 246 255 } 247 256 248 - int iscsit_deaccess_np(struct iscsi_np *np, struct iscsi_portal_group *tpg) 257 + void iscsit_login_kref_put(struct kref *kref) 258 + { 259 + struct iscsi_tpg_np *tpg_np = container_of(kref, 260 + struct iscsi_tpg_np, tpg_np_kref); 261 + 262 + complete(&tpg_np->tpg_np_comp); 263 + } 264 + 265 + int iscsit_deaccess_np(struct iscsi_np *np, struct iscsi_portal_group *tpg, 266 + struct iscsi_tpg_np *tpg_np) 249 267 { 250 268 struct iscsi_tiqn *tiqn = tpg->tpg_tiqn; 251 269 252 - spin_lock_bh(&np->np_thread_lock); 253 - np->np_login_tpg = NULL; 254 - spin_unlock_bh(&np->np_thread_lock); 270 + up(&tpg->np_login_sem); 255 271 256 - mutex_unlock(&tpg->np_login_lock); 272 + if (tpg_np) 273 + kref_put(&tpg_np->tpg_np_kref, iscsit_login_kref_put); 257 274 258 275 if (tiqn) 259 276 iscsit_put_tiqn_for_login(tiqn); ··· 417 410 int iscsit_reset_np_thread( 418 411 struct iscsi_np *np, 419 412 struct iscsi_tpg_np *tpg_np, 420 - struct iscsi_portal_group *tpg) 413 + struct iscsi_portal_group *tpg, 414 + bool shutdown) 421 415 { 422 416 spin_lock_bh(&np->np_thread_lock); 423 - if (tpg && tpg_np) { 424 - /* 425 - * The reset operation need only be performed when the 426 - * passed struct iscsi_portal_group has a login in progress 427 - * to one of the network portals. 428 - */ 429 - if (tpg_np->tpg_np->np_login_tpg != tpg) { 430 - spin_unlock_bh(&np->np_thread_lock); 431 - return 0; 432 - } 433 - } 434 417 if (np->np_thread_state == ISCSI_NP_THREAD_INACTIVE) { 435 418 spin_unlock_bh(&np->np_thread_lock); 436 419 return 0; ··· 434 437 spin_lock_bh(&np->np_thread_lock); 435 438 } 436 439 spin_unlock_bh(&np->np_thread_lock); 440 + 441 + if (tpg_np && shutdown) { 442 + kref_put(&tpg_np->tpg_np_kref, iscsit_login_kref_put); 443 + 444 + wait_for_completion(&tpg_np->tpg_np_comp); 445 + } 437 446 438 447 return 0; 439 448 }
+4 -2
drivers/target/iscsi/iscsi_target.h
··· 7 7 extern struct iscsi_tiqn *iscsit_add_tiqn(unsigned char *); 8 8 extern void iscsit_del_tiqn(struct iscsi_tiqn *); 9 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 13 extern bool iscsit_check_np_match(struct __kernel_sockaddr_storage *, 12 14 struct iscsi_np *, int); 13 15 extern struct iscsi_np *iscsit_add_np(struct __kernel_sockaddr_storage *, 14 16 char *, int); 15 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 19 extern int iscsit_del_np(struct iscsi_np *); 18 20 extern int iscsit_reject_cmd(struct iscsi_cmd *cmd, u8, unsigned char *); 19 21 extern void iscsit_set_unsoliticed_dataout(struct iscsi_cmd *);
+13 -2
drivers/target/iscsi/iscsi_target_core.h
··· 554 554 struct completion rx_half_close_comp; 555 555 /* socket used by this connection */ 556 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 564 struct timer_list nopin_timer; 558 565 struct timer_list nopin_response_timer; 559 566 struct timer_list transport_timer; ··· 591 584 void *context; 592 585 struct iscsi_login_thread_s *login_thread; 593 586 struct iscsi_portal_group *tpg; 587 + struct iscsi_tpg_np *tpg_np; 594 588 /* Pointer to parent session */ 595 589 struct iscsi_session *sess; 596 590 /* Pointer to thread_set in use for this conn's threads */ ··· 690 682 u8 version_max; 691 683 u8 login_complete; 692 684 u8 login_failed; 685 + bool zero_tsih; 693 686 char isid[6]; 694 687 u32 cmd_sn; 695 688 itt_t init_task_tag; ··· 703 694 char *req_buf; 704 695 char *rsp_buf; 705 696 struct iscsi_conn *conn; 697 + struct iscsi_np *np; 706 698 } ____cacheline_aligned; 707 699 708 700 struct iscsi_node_attrib { ··· 783 773 struct __kernel_sockaddr_storage np_sockaddr; 784 774 struct task_struct *np_thread; 785 775 struct timer_list np_login_timer; 786 - struct iscsi_portal_group *np_login_tpg; 787 776 void *np_context; 788 777 struct iscsit_transport *np_transport; 789 778 struct list_head np_list; ··· 797 788 struct list_head tpg_np_parent_list; 798 789 struct se_tpg_np se_tpg_np; 799 790 spinlock_t tpg_np_parent_lock; 791 + struct completion tpg_np_comp; 792 + struct kref tpg_np_kref; 800 793 }; 801 794 802 795 struct iscsi_portal_group { ··· 820 809 spinlock_t tpg_state_lock; 821 810 struct se_portal_group tpg_se_tpg; 822 811 struct mutex tpg_access_lock; 823 - struct mutex np_login_lock; 812 + struct semaphore np_login_sem; 824 813 struct iscsi_tpg_attrib tpg_attrib; 825 814 struct iscsi_node_auth tpg_demo_auth; 826 815 /* Pointer to default list of iSCSI parameters for TPG */
+93 -69
drivers/target/iscsi/iscsi_target_login.c
··· 50 50 pr_err("Unable to allocate memory for struct iscsi_login.\n"); 51 51 return NULL; 52 52 } 53 + conn->login = login; 53 54 login->conn = conn; 54 55 login->first_request = 1; 55 56 ··· 685 684 iscsit_start_nopin_timer(conn); 686 685 } 687 686 688 - static int iscsi_post_login_handler( 687 + int iscsi_post_login_handler( 689 688 struct iscsi_np *np, 690 689 struct iscsi_conn *conn, 691 690 u8 zero_tsih) ··· 1125 1124 return 0; 1126 1125 } 1127 1126 1127 + void iscsi_target_login_sess_out(struct iscsi_conn *conn, 1128 + struct iscsi_np *np, bool zero_tsih, bool new_sess) 1129 + { 1130 + if (new_sess == false) 1131 + goto old_sess_out; 1132 + 1133 + pr_err("iSCSI Login negotiation failed.\n"); 1134 + iscsit_collect_login_stats(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, 1135 + ISCSI_LOGIN_STATUS_INIT_ERR); 1136 + if (!zero_tsih || !conn->sess) 1137 + goto old_sess_out; 1138 + if (conn->sess->se_sess) 1139 + transport_free_session(conn->sess->se_sess); 1140 + if (conn->sess->session_index != 0) { 1141 + spin_lock_bh(&sess_idr_lock); 1142 + idr_remove(&sess_idr, conn->sess->session_index); 1143 + spin_unlock_bh(&sess_idr_lock); 1144 + } 1145 + kfree(conn->sess->sess_ops); 1146 + kfree(conn->sess); 1147 + 1148 + old_sess_out: 1149 + iscsi_stop_login_thread_timer(np); 1150 + /* 1151 + * If login negotiation fails check if the Time2Retain timer 1152 + * needs to be restarted. 1153 + */ 1154 + if (!zero_tsih && conn->sess) { 1155 + spin_lock_bh(&conn->sess->conn_lock); 1156 + if (conn->sess->session_state == TARG_SESS_STATE_FAILED) { 1157 + struct se_portal_group *se_tpg = 1158 + &ISCSI_TPG_C(conn)->tpg_se_tpg; 1159 + 1160 + atomic_set(&conn->sess->session_continuation, 0); 1161 + spin_unlock_bh(&conn->sess->conn_lock); 1162 + spin_lock_bh(&se_tpg->session_lock); 1163 + iscsit_start_time2retain_handler(conn->sess); 1164 + spin_unlock_bh(&se_tpg->session_lock); 1165 + } else 1166 + spin_unlock_bh(&conn->sess->conn_lock); 1167 + iscsit_dec_session_usage_count(conn->sess); 1168 + } 1169 + 1170 + if (!IS_ERR(conn->conn_rx_hash.tfm)) 1171 + crypto_free_hash(conn->conn_rx_hash.tfm); 1172 + if (!IS_ERR(conn->conn_tx_hash.tfm)) 1173 + crypto_free_hash(conn->conn_tx_hash.tfm); 1174 + 1175 + if (conn->conn_cpumask) 1176 + free_cpumask_var(conn->conn_cpumask); 1177 + 1178 + kfree(conn->conn_ops); 1179 + 1180 + if (conn->param_list) { 1181 + iscsi_release_param_list(conn->param_list); 1182 + conn->param_list = NULL; 1183 + } 1184 + iscsi_target_nego_release(conn); 1185 + 1186 + if (conn->sock) { 1187 + sock_release(conn->sock); 1188 + conn->sock = NULL; 1189 + } 1190 + 1191 + if (conn->conn_transport->iscsit_free_conn) 1192 + conn->conn_transport->iscsit_free_conn(conn); 1193 + 1194 + iscsit_put_transport(conn->conn_transport); 1195 + kfree(conn); 1196 + } 1197 + 1128 1198 static int __iscsi_target_login_thread(struct iscsi_np *np) 1129 1199 { 1130 1200 u8 *buffer, zero_tsih = 0; ··· 1204 1132 struct iscsi_login *login; 1205 1133 struct iscsi_portal_group *tpg = NULL; 1206 1134 struct iscsi_login_req *pdu; 1135 + struct iscsi_tpg_np *tpg_np; 1136 + bool new_sess = false; 1207 1137 1208 1138 flush_signals(current); 1209 1139 ··· 1347 1273 tpg = conn->tpg; 1348 1274 goto new_sess_out; 1349 1275 } 1276 + login->zero_tsih = zero_tsih; 1350 1277 1351 1278 tpg = conn->tpg; 1352 1279 if (!tpg) { ··· 1363 1288 goto old_sess_out; 1364 1289 } 1365 1290 1366 - if (iscsi_target_start_negotiation(login, conn) < 0) 1291 + ret = iscsi_target_start_negotiation(login, conn); 1292 + if (ret < 0) 1367 1293 goto new_sess_out; 1368 1294 1369 1295 if (!conn->sess) { ··· 1377 1301 if (signal_pending(current)) 1378 1302 goto new_sess_out; 1379 1303 1380 - ret = iscsi_post_login_handler(np, conn, zero_tsih); 1304 + if (ret == 1) { 1305 + tpg_np = conn->tpg_np; 1381 1306 1382 - if (ret < 0) 1383 - goto new_sess_out; 1307 + ret = iscsi_post_login_handler(np, conn, zero_tsih); 1308 + if (ret < 0) 1309 + goto new_sess_out; 1384 1310 1385 - iscsit_deaccess_np(np, tpg); 1311 + iscsit_deaccess_np(np, tpg, tpg_np); 1312 + } 1313 + 1386 1314 tpg = NULL; 1315 + tpg_np = NULL; 1387 1316 /* Get another socket */ 1388 1317 return 1; 1389 1318 1390 1319 new_sess_out: 1391 - pr_err("iSCSI Login negotiation failed.\n"); 1392 - iscsit_collect_login_stats(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, 1393 - ISCSI_LOGIN_STATUS_INIT_ERR); 1394 - if (!zero_tsih || !conn->sess) 1395 - goto old_sess_out; 1396 - if (conn->sess->se_sess) 1397 - transport_free_session(conn->sess->se_sess); 1398 - if (conn->sess->session_index != 0) { 1399 - spin_lock_bh(&sess_idr_lock); 1400 - idr_remove(&sess_idr, conn->sess->session_index); 1401 - spin_unlock_bh(&sess_idr_lock); 1402 - } 1403 - kfree(conn->sess->sess_ops); 1404 - kfree(conn->sess); 1320 + new_sess = true; 1405 1321 old_sess_out: 1406 - iscsi_stop_login_thread_timer(np); 1407 - /* 1408 - * If login negotiation fails check if the Time2Retain timer 1409 - * needs to be restarted. 1410 - */ 1411 - if (!zero_tsih && conn->sess) { 1412 - spin_lock_bh(&conn->sess->conn_lock); 1413 - if (conn->sess->session_state == TARG_SESS_STATE_FAILED) { 1414 - struct se_portal_group *se_tpg = 1415 - &ISCSI_TPG_C(conn)->tpg_se_tpg; 1416 - 1417 - atomic_set(&conn->sess->session_continuation, 0); 1418 - spin_unlock_bh(&conn->sess->conn_lock); 1419 - spin_lock_bh(&se_tpg->session_lock); 1420 - iscsit_start_time2retain_handler(conn->sess); 1421 - spin_unlock_bh(&se_tpg->session_lock); 1422 - } else 1423 - spin_unlock_bh(&conn->sess->conn_lock); 1424 - iscsit_dec_session_usage_count(conn->sess); 1425 - } 1426 - 1427 - if (!IS_ERR(conn->conn_rx_hash.tfm)) 1428 - crypto_free_hash(conn->conn_rx_hash.tfm); 1429 - if (!IS_ERR(conn->conn_tx_hash.tfm)) 1430 - crypto_free_hash(conn->conn_tx_hash.tfm); 1431 - 1432 - if (conn->conn_cpumask) 1433 - free_cpumask_var(conn->conn_cpumask); 1434 - 1435 - kfree(conn->conn_ops); 1436 - 1437 - if (conn->param_list) { 1438 - iscsi_release_param_list(conn->param_list); 1439 - conn->param_list = NULL; 1440 - } 1441 - iscsi_target_nego_release(conn); 1442 - 1443 - if (conn->sock) { 1444 - sock_release(conn->sock); 1445 - conn->sock = NULL; 1446 - } 1447 - 1448 - if (conn->conn_transport->iscsit_free_conn) 1449 - conn->conn_transport->iscsit_free_conn(conn); 1450 - 1451 - iscsit_put_transport(conn->conn_transport); 1452 - 1453 - kfree(conn); 1322 + tpg_np = conn->tpg_np; 1323 + iscsi_target_login_sess_out(conn, np, zero_tsih, new_sess); 1324 + new_sess = false; 1454 1325 1455 1326 if (tpg) { 1456 - iscsit_deaccess_np(np, tpg); 1327 + iscsit_deaccess_np(np, tpg, tpg_np); 1457 1328 tpg = NULL; 1329 + tpg_np = NULL; 1458 1330 } 1459 1331 1460 1332 out:
+3
drivers/target/iscsi/iscsi_target_login.h
··· 12 12 extern int iscsit_get_login_rx(struct iscsi_conn *, struct iscsi_login *); 13 13 extern int iscsit_put_login_tx(struct iscsi_conn *, struct iscsi_login *, u32); 14 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 18 extern int iscsi_target_login_thread(void *); 16 19 extern int iscsi_login_disable_FIM_keys(struct iscsi_param_list *, struct iscsi_conn *); 17 20
+11 -7
drivers/target/iscsi/iscsi_target_tpg.c
··· 49 49 INIT_LIST_HEAD(&tpg->tpg_gnp_list); 50 50 INIT_LIST_HEAD(&tpg->tpg_list); 51 51 mutex_init(&tpg->tpg_access_lock); 52 - mutex_init(&tpg->np_login_lock); 52 + sema_init(&tpg->np_login_sem, 1); 53 53 spin_lock_init(&tpg->tpg_state_lock); 54 54 spin_lock_init(&tpg->tpg_np_lock); 55 55 ··· 175 175 176 176 static void iscsit_clear_tpg_np_login_thread( 177 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 181 if (!tpg_np->tpg_np) { 181 182 pr_err("struct iscsi_tpg_np->tpg_np is NULL!\n"); 182 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 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 193 struct iscsi_tpg_np *tpg_np; 192 194 ··· 199 197 continue; 200 198 } 201 199 spin_unlock(&tpg->tpg_np_lock); 202 - iscsit_clear_tpg_np_login_thread(tpg_np, tpg); 200 + iscsit_clear_tpg_np_login_thread(tpg_np, tpg, shutdown); 203 201 spin_lock(&tpg->tpg_np_lock); 204 202 } 205 203 spin_unlock(&tpg->tpg_np_lock); ··· 269 267 spin_lock(&tpg->tpg_state_lock); 270 268 tpg->tpg_state = TPG_STATE_INACTIVE; 271 269 spin_unlock(&tpg->tpg_state_lock); 270 + 271 + iscsit_clear_tpg_np_login_threads(tpg, true); 272 272 273 273 if (iscsit_release_sessions_for_tpg(tpg, force) < 0) { 274 274 pr_err("Unable to delete iSCSI Target Portal Group:" ··· 372 368 tpg->tpg_state = TPG_STATE_INACTIVE; 373 369 spin_unlock(&tpg->tpg_state_lock); 374 370 375 - iscsit_clear_tpg_np_login_threads(tpg); 371 + iscsit_clear_tpg_np_login_threads(tpg, false); 376 372 377 373 if (iscsit_release_sessions_for_tpg(tpg, force) < 0) { 378 374 spin_lock(&tpg->tpg_state_lock); ··· 524 520 struct iscsi_portal_group *tpg, 525 521 struct iscsi_np *np) 526 522 { 527 - iscsit_clear_tpg_np_login_thread(tpg_np, tpg); 523 + iscsit_clear_tpg_np_login_thread(tpg_np, tpg, true); 528 524 529 525 pr_debug("CORE[%s] - Removed Network Portal: %s:%hu,%hu on %s\n", 530 526 tpg->tpg_tiqn->tiqn, np->np_ip, np->np_port, tpg->tpgt,
+1 -1
drivers/target/iscsi/iscsi_target_tpg.h
··· 8 8 struct iscsi_np *); 9 9 extern int iscsit_get_tpg(struct iscsi_portal_group *); 10 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 12 extern void iscsit_tpg_dump_params(struct iscsi_portal_group *); 13 13 extern int iscsit_tpg_add_portal_group(struct iscsi_tiqn *, struct iscsi_portal_group *); 14 14 extern int iscsit_tpg_del_portal_group(struct iscsi_tiqn *, struct iscsi_portal_group *,