diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2013-08-15 16:40:17 -0400 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2013-09-09 17:13:31 -0400 |
commit | d381a8010a052813a88e20e089be4a58aad8b40a (patch) | |
tree | 89118ae7b5c1bf6fe1be03d4ca6a952fa562d68e | |
parent | a91eb7d9dc8e00de9618633dcb62643fd5eee498 (diff) |
iscsi-target: Add login negotiation multi-plexing support
This patch adds support for login negotiation multi-plexing in
iscsi-target code.
This involves handling the first login request PDU + payload and
login response PDU + payload within __iscsi_target_login_thread()
process context, and then changing struct sock->sk_data_ready()
so that all subsequent exchanges are handled by workqueue process
context, to allow other incoming login requests to be received
in parallel by __iscsi_target_login_thread().
Upon login negotiation completion (or failure), ->sk_data_ready()
is replaced with the original kernel sockets handler saved in
iscsi_conn->orig_data_ready.
v3 changes:
- Convert iscsi_target_sk_data_ready() lock access to
write[lock,unlock]_bh()
- Only clear LOGIN_FLAGS_READ_ACTIVE when iscsi_target_do_login()
returns zero
- Add LOGIN_FLAGS_READY + LOGIN_FLAGS_CLOSED bit checks to
iscsi_target_sk_data_ready()
- Make INIT_DELAYED_WORK() + iscsi_target_set_sock_callbacks() setup
happen earlier by moving from iscsi_target_start_negotiation() into
iscsi_target_locate_portal()
- Set LOGIN_FLAGS_READY bit in iscsi_target_start_negotiation()
after iscsi_target_do_login() returns zero.
v2 changes:
- Add login_timer in iscsi_target_do_login_rx() to avoid
possible endless sleep with MSG_WAITALL for traditional
iscsi-target in certain network configurations.
- Convert lprintk() -> pr_debug()
- Remove forward declarations of iscsi_target_set_sock_callbacks(),
iscsi_target_restore_sock_callbacks() and iscsi_target_sk_data_ready()
- Make iscsi_target_set_sock_callbacks + iscsi_target_restore_sock_callbacks()
static (Fengguang)
- Make iscsi_target_do_login_rx() safe for iser-target w/o conn->sock
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r-- | drivers/target/iscsi/iscsi_target_core.h | 1 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_nego.c | 234 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_tpg.c | 7 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_tpg.h | 2 |
4 files changed, 234 insertions, 10 deletions
diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h index 46228465d190..43228dc786c9 100644 --- a/drivers/target/iscsi/iscsi_target_core.h +++ b/drivers/target/iscsi/iscsi_target_core.h | |||
@@ -564,6 +564,7 @@ struct iscsi_conn { | |||
564 | struct timer_list nopin_timer; | 564 | struct timer_list nopin_timer; |
565 | struct timer_list nopin_response_timer; | 565 | struct timer_list nopin_response_timer; |
566 | struct timer_list transport_timer; | 566 | struct timer_list transport_timer; |
567 | struct task_struct *login_kworker; | ||
567 | /* Spinlock used for add/deleting cmd's from conn_cmd_list */ | 568 | /* Spinlock used for add/deleting cmd's from conn_cmd_list */ |
568 | spinlock_t cmd_lock; | 569 | spinlock_t cmd_lock; |
569 | spinlock_t conn_usage_lock; | 570 | spinlock_t conn_usage_lock; |
diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index c4675b4ceb49..9defee0f0aeb 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c | |||
@@ -377,14 +377,207 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log | |||
377 | return 0; | 377 | return 0; |
378 | } | 378 | } |
379 | 379 | ||
380 | static void iscsi_target_sk_data_ready(struct sock *sk, int count) | ||
381 | { | ||
382 | struct iscsi_conn *conn = sk->sk_user_data; | ||
383 | bool rc; | ||
384 | |||
385 | pr_debug("Entering iscsi_target_sk_data_ready: conn: %p\n", conn); | ||
386 | |||
387 | write_lock_bh(&sk->sk_callback_lock); | ||
388 | if (!sk->sk_user_data) { | ||
389 | write_unlock_bh(&sk->sk_callback_lock); | ||
390 | return; | ||
391 | } | ||
392 | if (!test_bit(LOGIN_FLAGS_READY, &conn->login_flags)) { | ||
393 | write_unlock_bh(&sk->sk_callback_lock); | ||
394 | pr_debug("Got LOGIN_FLAGS_READY=0, conn: %p >>>>\n", conn); | ||
395 | return; | ||
396 | } | ||
397 | if (test_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags)) { | ||
398 | write_unlock_bh(&sk->sk_callback_lock); | ||
399 | pr_debug("Got LOGIN_FLAGS_CLOSED=1, conn: %p >>>>\n", conn); | ||
400 | return; | ||
401 | } | ||
402 | if (test_and_set_bit(LOGIN_FLAGS_READ_ACTIVE, &conn->login_flags)) { | ||
403 | write_unlock_bh(&sk->sk_callback_lock); | ||
404 | pr_debug("Got LOGIN_FLAGS_READ_ACTIVE=1, conn: %p >>>>\n", conn); | ||
405 | return; | ||
406 | } | ||
407 | |||
408 | rc = schedule_delayed_work(&conn->login_work, 0); | ||
409 | if (rc == false) { | ||
410 | pr_debug("iscsi_target_sk_data_ready, schedule_delayed_work" | ||
411 | " got false\n"); | ||
412 | } | ||
413 | write_unlock_bh(&sk->sk_callback_lock); | ||
414 | } | ||
415 | |||
416 | static void iscsi_target_set_sock_callbacks(struct iscsi_conn *conn) | ||
417 | { | ||
418 | struct sock *sk; | ||
419 | |||
420 | if (!conn->sock) | ||
421 | return; | ||
422 | |||
423 | sk = conn->sock->sk; | ||
424 | pr_debug("Entering iscsi_target_set_sock_callbacks: conn: %p\n", conn); | ||
425 | |||
426 | write_lock_bh(&sk->sk_callback_lock); | ||
427 | sk->sk_user_data = conn; | ||
428 | conn->orig_data_ready = sk->sk_data_ready; | ||
429 | sk->sk_data_ready = iscsi_target_sk_data_ready; | ||
430 | write_unlock_bh(&sk->sk_callback_lock); | ||
431 | } | ||
432 | |||
433 | static void iscsi_target_restore_sock_callbacks(struct iscsi_conn *conn) | ||
434 | { | ||
435 | struct sock *sk; | ||
436 | |||
437 | if (!conn->sock) | ||
438 | return; | ||
439 | |||
440 | sk = conn->sock->sk; | ||
441 | pr_debug("Entering iscsi_target_restore_sock_callbacks: conn: %p\n", conn); | ||
442 | |||
443 | write_lock_bh(&sk->sk_callback_lock); | ||
444 | if (!sk->sk_user_data) { | ||
445 | write_unlock_bh(&sk->sk_callback_lock); | ||
446 | return; | ||
447 | } | ||
448 | sk->sk_user_data = NULL; | ||
449 | sk->sk_data_ready = conn->orig_data_ready; | ||
450 | write_unlock_bh(&sk->sk_callback_lock); | ||
451 | } | ||
452 | |||
453 | static int iscsi_target_do_login(struct iscsi_conn *, struct iscsi_login *); | ||
454 | |||
455 | static bool iscsi_target_sk_state_check(struct sock *sk) | ||
456 | { | ||
457 | if (sk->sk_state == TCP_CLOSE_WAIT || sk->sk_state == TCP_CLOSE) { | ||
458 | pr_debug("iscsi_target_sk_state_check: TCP_CLOSE_WAIT|TCP_CLOSE," | ||
459 | "returning FALSE\n"); | ||
460 | return false; | ||
461 | } | ||
462 | return true; | ||
463 | } | ||
464 | |||
465 | static void iscsi_target_login_drop(struct iscsi_conn *conn, struct iscsi_login *login) | ||
466 | { | ||
467 | struct iscsi_np *np = login->np; | ||
468 | bool zero_tsih = login->zero_tsih; | ||
469 | |||
470 | iscsi_remove_failed_auth_entry(conn); | ||
471 | iscsi_target_nego_release(conn); | ||
472 | iscsi_target_login_sess_out(conn, np, zero_tsih, true); | ||
473 | } | ||
474 | |||
475 | static void iscsi_target_login_timeout(unsigned long data) | ||
476 | { | ||
477 | struct iscsi_conn *conn = (struct iscsi_conn *)data; | ||
478 | |||
479 | pr_debug("Entering iscsi_target_login_timeout >>>>>>>>>>>>>>>>>>>\n"); | ||
480 | |||
481 | if (conn->login_kworker) { | ||
482 | pr_debug("Sending SIGINT to conn->login_kworker %s/%d\n", | ||
483 | conn->login_kworker->comm, conn->login_kworker->pid); | ||
484 | send_sig(SIGINT, conn->login_kworker, 1); | ||
485 | } | ||
486 | } | ||
487 | |||
488 | static void iscsi_target_do_login_rx(struct work_struct *work) | ||
489 | { | ||
490 | struct iscsi_conn *conn = container_of(work, | ||
491 | struct iscsi_conn, login_work.work); | ||
492 | struct iscsi_login *login = conn->login; | ||
493 | struct iscsi_np *np = login->np; | ||
494 | struct iscsi_portal_group *tpg = conn->tpg; | ||
495 | struct iscsi_tpg_np *tpg_np = conn->tpg_np; | ||
496 | struct timer_list login_timer; | ||
497 | int rc, zero_tsih = login->zero_tsih; | ||
498 | bool state; | ||
499 | |||
500 | pr_debug("entering iscsi_target_do_login_rx, conn: %p, %s:%d\n", | ||
501 | conn, current->comm, current->pid); | ||
502 | |||
503 | spin_lock(&tpg->tpg_state_lock); | ||
504 | state = (tpg->tpg_state == TPG_STATE_ACTIVE); | ||
505 | spin_unlock(&tpg->tpg_state_lock); | ||
506 | |||
507 | if (state == false) { | ||
508 | pr_debug("iscsi_target_do_login_rx: tpg_state != TPG_STATE_ACTIVE\n"); | ||
509 | iscsi_target_restore_sock_callbacks(conn); | ||
510 | iscsi_target_login_drop(conn, login); | ||
511 | iscsit_deaccess_np(np, tpg, tpg_np); | ||
512 | return; | ||
513 | } | ||
514 | |||
515 | if (conn->sock) { | ||
516 | struct sock *sk = conn->sock->sk; | ||
517 | |||
518 | read_lock_bh(&sk->sk_callback_lock); | ||
519 | state = iscsi_target_sk_state_check(sk); | ||
520 | read_unlock_bh(&sk->sk_callback_lock); | ||
521 | |||
522 | if (state == false) { | ||
523 | pr_debug("iscsi_target_do_login_rx, TCP state CLOSE\n"); | ||
524 | iscsi_target_restore_sock_callbacks(conn); | ||
525 | iscsi_target_login_drop(conn, login); | ||
526 | iscsit_deaccess_np(np, tpg, tpg_np); | ||
527 | return; | ||
528 | } | ||
529 | } | ||
530 | |||
531 | conn->login_kworker = current; | ||
532 | allow_signal(SIGINT); | ||
533 | |||
534 | init_timer(&login_timer); | ||
535 | login_timer.expires = (get_jiffies_64() + TA_LOGIN_TIMEOUT * HZ); | ||
536 | login_timer.data = (unsigned long)conn; | ||
537 | login_timer.function = iscsi_target_login_timeout; | ||
538 | add_timer(&login_timer); | ||
539 | pr_debug("Starting login_timer for %s/%d\n", current->comm, current->pid); | ||
540 | |||
541 | rc = conn->conn_transport->iscsit_get_login_rx(conn, login); | ||
542 | del_timer_sync(&login_timer); | ||
543 | flush_signals(current); | ||
544 | conn->login_kworker = NULL; | ||
545 | |||
546 | if (rc < 0) { | ||
547 | iscsi_target_restore_sock_callbacks(conn); | ||
548 | iscsi_target_login_drop(conn, login); | ||
549 | iscsit_deaccess_np(np, tpg, tpg_np); | ||
550 | return; | ||
551 | } | ||
552 | |||
553 | pr_debug("iscsi_target_do_login_rx after rx_login_io, %p, %s:%d\n", | ||
554 | conn, current->comm, current->pid); | ||
555 | |||
556 | rc = iscsi_target_do_login(conn, login); | ||
557 | if (rc < 0) { | ||
558 | iscsi_target_restore_sock_callbacks(conn); | ||
559 | iscsi_target_login_drop(conn, login); | ||
560 | iscsit_deaccess_np(np, tpg, tpg_np); | ||
561 | } else if (!rc) { | ||
562 | if (conn->sock) { | ||
563 | struct sock *sk = conn->sock->sk; | ||
564 | |||
565 | write_lock_bh(&sk->sk_callback_lock); | ||
566 | clear_bit(LOGIN_FLAGS_READ_ACTIVE, &conn->login_flags); | ||
567 | write_unlock_bh(&sk->sk_callback_lock); | ||
568 | } | ||
569 | } else if (rc == 1) { | ||
570 | iscsi_target_nego_release(conn); | ||
571 | iscsi_post_login_handler(np, conn, zero_tsih); | ||
572 | iscsit_deaccess_np(np, tpg, tpg_np); | ||
573 | } | ||
574 | } | ||
575 | |||
380 | static int iscsi_target_do_login_io(struct iscsi_conn *conn, struct iscsi_login *login) | 576 | static int iscsi_target_do_login_io(struct iscsi_conn *conn, struct iscsi_login *login) |
381 | { | 577 | { |
382 | if (iscsi_target_do_tx_login_io(conn, login) < 0) | 578 | if (iscsi_target_do_tx_login_io(conn, login) < 0) |
383 | return -1; | 579 | return -1; |
384 | 580 | ||
385 | if (conn->conn_transport->iscsit_get_login_rx(conn, login) < 0) | ||
386 | return -1; | ||
387 | |||
388 | return 0; | 581 | return 0; |
389 | } | 582 | } |
390 | 583 | ||
@@ -643,10 +836,11 @@ static int iscsi_target_do_login(struct iscsi_conn *conn, struct iscsi_login *lo | |||
643 | if (login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT) { | 836 | if (login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT) { |
644 | login->tsih = conn->sess->tsih; | 837 | login->tsih = conn->sess->tsih; |
645 | login->login_complete = 1; | 838 | login->login_complete = 1; |
839 | iscsi_target_restore_sock_callbacks(conn); | ||
646 | if (iscsi_target_do_tx_login_io(conn, | 840 | if (iscsi_target_do_tx_login_io(conn, |
647 | login) < 0) | 841 | login) < 0) |
648 | return -1; | 842 | return -1; |
649 | return 0; | 843 | return 1; |
650 | } | 844 | } |
651 | break; | 845 | break; |
652 | default: | 846 | default: |
@@ -663,6 +857,7 @@ static int iscsi_target_do_login(struct iscsi_conn *conn, struct iscsi_login *lo | |||
663 | login_rsp->flags &= ~ISCSI_FLAG_LOGIN_TRANSIT; | 857 | login_rsp->flags &= ~ISCSI_FLAG_LOGIN_TRANSIT; |
664 | login_rsp->flags &= ~ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK; | 858 | login_rsp->flags &= ~ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK; |
665 | } | 859 | } |
860 | break; | ||
666 | } | 861 | } |
667 | 862 | ||
668 | return 0; | 863 | return 0; |
@@ -695,10 +890,16 @@ int iscsi_target_locate_portal( | |||
695 | char *tmpbuf, *start = NULL, *end = NULL, *key, *value; | 890 | char *tmpbuf, *start = NULL, *end = NULL, *key, *value; |
696 | struct iscsi_session *sess = conn->sess; | 891 | struct iscsi_session *sess = conn->sess; |
697 | struct iscsi_tiqn *tiqn; | 892 | struct iscsi_tiqn *tiqn; |
893 | struct iscsi_tpg_np *tpg_np = NULL; | ||
698 | struct iscsi_login_req *login_req; | 894 | struct iscsi_login_req *login_req; |
699 | u32 payload_length; | 895 | u32 payload_length; |
700 | int sessiontype = 0, ret = 0; | 896 | int sessiontype = 0, ret = 0; |
701 | 897 | ||
898 | INIT_DELAYED_WORK(&conn->login_work, iscsi_target_do_login_rx); | ||
899 | iscsi_target_set_sock_callbacks(conn); | ||
900 | |||
901 | login->np = np; | ||
902 | |||
702 | login_req = (struct iscsi_login_req *) login->req; | 903 | login_req = (struct iscsi_login_req *) login->req; |
703 | payload_length = ntoh24(login_req->dlength); | 904 | payload_length = ntoh24(login_req->dlength); |
704 | 905 | ||
@@ -822,7 +1023,7 @@ get_target: | |||
822 | /* | 1023 | /* |
823 | * Locate Target Portal Group from Storage Node. | 1024 | * Locate Target Portal Group from Storage Node. |
824 | */ | 1025 | */ |
825 | conn->tpg = iscsit_get_tpg_from_np(tiqn, np); | 1026 | conn->tpg = iscsit_get_tpg_from_np(tiqn, np, &tpg_np); |
826 | if (!conn->tpg) { | 1027 | if (!conn->tpg) { |
827 | pr_err("Unable to locate Target Portal Group" | 1028 | pr_err("Unable to locate Target Portal Group" |
828 | " on %s\n", tiqn->tiqn); | 1029 | " on %s\n", tiqn->tiqn); |
@@ -832,12 +1033,16 @@ get_target: | |||
832 | ret = -1; | 1033 | ret = -1; |
833 | goto out; | 1034 | goto out; |
834 | } | 1035 | } |
1036 | conn->tpg_np = tpg_np; | ||
835 | pr_debug("Located Portal Group Object: %hu\n", conn->tpg->tpgt); | 1037 | pr_debug("Located Portal Group Object: %hu\n", conn->tpg->tpgt); |
836 | /* | 1038 | /* |
837 | * Setup crc32c modules from libcrypto | 1039 | * Setup crc32c modules from libcrypto |
838 | */ | 1040 | */ |
839 | if (iscsi_login_setup_crypto(conn) < 0) { | 1041 | if (iscsi_login_setup_crypto(conn) < 0) { |
840 | pr_err("iscsi_login_setup_crypto() failed\n"); | 1042 | pr_err("iscsi_login_setup_crypto() failed\n"); |
1043 | kref_put(&tpg_np->tpg_np_kref, iscsit_login_kref_put); | ||
1044 | iscsit_put_tiqn_for_login(tiqn); | ||
1045 | conn->tpg = NULL; | ||
841 | ret = -1; | 1046 | ret = -1; |
842 | goto out; | 1047 | goto out; |
843 | } | 1048 | } |
@@ -846,11 +1051,12 @@ get_target: | |||
846 | * process login attempt. | 1051 | * process login attempt. |
847 | */ | 1052 | */ |
848 | if (iscsit_access_np(np, conn->tpg) < 0) { | 1053 | if (iscsit_access_np(np, conn->tpg) < 0) { |
1054 | kref_put(&tpg_np->tpg_np_kref, iscsit_login_kref_put); | ||
849 | iscsit_put_tiqn_for_login(tiqn); | 1055 | iscsit_put_tiqn_for_login(tiqn); |
850 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, | 1056 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, |
851 | ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE); | 1057 | ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE); |
852 | ret = -1; | ||
853 | conn->tpg = NULL; | 1058 | conn->tpg = NULL; |
1059 | ret = -1; | ||
854 | goto out; | 1060 | goto out; |
855 | } | 1061 | } |
856 | 1062 | ||
@@ -897,10 +1103,22 @@ int iscsi_target_start_negotiation( | |||
897 | int ret; | 1103 | int ret; |
898 | 1104 | ||
899 | ret = iscsi_target_do_login(conn, login); | 1105 | ret = iscsi_target_do_login(conn, login); |
900 | if (ret != 0) | 1106 | if (!ret) { |
1107 | if (conn->sock) { | ||
1108 | struct sock *sk = conn->sock->sk; | ||
1109 | |||
1110 | write_lock_bh(&sk->sk_callback_lock); | ||
1111 | set_bit(LOGIN_FLAGS_READY, &conn->login_flags); | ||
1112 | write_unlock_bh(&sk->sk_callback_lock); | ||
1113 | } | ||
1114 | } else if (ret < 0) { | ||
1115 | cancel_delayed_work_sync(&conn->login_work); | ||
1116 | iscsi_target_restore_sock_callbacks(conn); | ||
901 | iscsi_remove_failed_auth_entry(conn); | 1117 | iscsi_remove_failed_auth_entry(conn); |
1118 | } | ||
1119 | if (ret != 0) | ||
1120 | iscsi_target_nego_release(conn); | ||
902 | 1121 | ||
903 | iscsi_target_nego_release(conn); | ||
904 | return ret; | 1122 | return ret; |
905 | } | 1123 | } |
906 | 1124 | ||
diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index 4bf8913992a5..e070ce2de60a 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c | |||
@@ -129,7 +129,8 @@ void iscsit_release_discovery_tpg(void) | |||
129 | 129 | ||
130 | struct iscsi_portal_group *iscsit_get_tpg_from_np( | 130 | struct iscsi_portal_group *iscsit_get_tpg_from_np( |
131 | struct iscsi_tiqn *tiqn, | 131 | struct iscsi_tiqn *tiqn, |
132 | struct iscsi_np *np) | 132 | struct iscsi_np *np, |
133 | struct iscsi_tpg_np **tpg_np_out) | ||
133 | { | 134 | { |
134 | struct iscsi_portal_group *tpg = NULL; | 135 | struct iscsi_portal_group *tpg = NULL; |
135 | struct iscsi_tpg_np *tpg_np; | 136 | struct iscsi_tpg_np *tpg_np; |
@@ -147,6 +148,8 @@ struct iscsi_portal_group *iscsit_get_tpg_from_np( | |||
147 | spin_lock(&tpg->tpg_np_lock); | 148 | spin_lock(&tpg->tpg_np_lock); |
148 | list_for_each_entry(tpg_np, &tpg->tpg_gnp_list, tpg_np_list) { | 149 | list_for_each_entry(tpg_np, &tpg->tpg_gnp_list, tpg_np_list) { |
149 | if (tpg_np->tpg_np == np) { | 150 | if (tpg_np->tpg_np == np) { |
151 | *tpg_np_out = tpg_np; | ||
152 | kref_get(&tpg_np->tpg_np_kref); | ||
150 | spin_unlock(&tpg->tpg_np_lock); | 153 | spin_unlock(&tpg->tpg_np_lock); |
151 | spin_unlock(&tiqn->tiqn_tpg_lock); | 154 | spin_unlock(&tiqn->tiqn_tpg_lock); |
152 | return tpg; | 155 | return tpg; |
@@ -494,6 +497,8 @@ struct iscsi_tpg_np *iscsit_tpg_add_network_portal( | |||
494 | INIT_LIST_HEAD(&tpg_np->tpg_np_child_list); | 497 | INIT_LIST_HEAD(&tpg_np->tpg_np_child_list); |
495 | INIT_LIST_HEAD(&tpg_np->tpg_np_parent_list); | 498 | INIT_LIST_HEAD(&tpg_np->tpg_np_parent_list); |
496 | spin_lock_init(&tpg_np->tpg_np_parent_lock); | 499 | spin_lock_init(&tpg_np->tpg_np_parent_lock); |
500 | init_completion(&tpg_np->tpg_np_comp); | ||
501 | kref_init(&tpg_np->tpg_np_kref); | ||
497 | tpg_np->tpg_np = np; | 502 | tpg_np->tpg_np = np; |
498 | tpg_np->tpg = tpg; | 503 | tpg_np->tpg = tpg; |
499 | 504 | ||
diff --git a/drivers/target/iscsi/iscsi_target_tpg.h b/drivers/target/iscsi/iscsi_target_tpg.h index 60ef4a9ad91b..b77693e2c209 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.h +++ b/drivers/target/iscsi/iscsi_target_tpg.h | |||
@@ -5,7 +5,7 @@ extern struct iscsi_portal_group *iscsit_alloc_portal_group(struct iscsi_tiqn *, | |||
5 | extern int iscsit_load_discovery_tpg(void); | 5 | extern int iscsit_load_discovery_tpg(void); |
6 | extern void iscsit_release_discovery_tpg(void); | 6 | extern void iscsit_release_discovery_tpg(void); |
7 | extern struct iscsi_portal_group *iscsit_get_tpg_from_np(struct iscsi_tiqn *, | 7 | extern struct iscsi_portal_group *iscsit_get_tpg_from_np(struct iscsi_tiqn *, |
8 | struct iscsi_np *); | 8 | struct iscsi_np *, struct iscsi_tpg_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 *, bool); | 11 | extern void iscsit_clear_tpg_np_login_threads(struct iscsi_portal_group *, bool); |