diff options
Diffstat (limited to 'drivers/target/iscsi/iscsi_target_nego.c')
| -rw-r--r-- | drivers/target/iscsi/iscsi_target_nego.c | 405 |
1 files changed, 227 insertions, 178 deletions
diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index 8a5e8d17a942..832588f21f91 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /******************************************************************************* * This file contains main functions related to iSCSI Parameter negotiation. * @@ -5,15 +6,6 @@ * * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. ******************************************************************************/ #include <linux/ctype.h> @@ -21,6 +13,7 @@ #include <linux/slab.h> #include <linux/sched/signal.h> #include <net/sock.h> +#include <trace/events/sock.h> #include <scsi/iscsi_proto.h> #include <target/target_core_base.h> #include <target/target_core_fabric.h> @@ -36,7 +29,6 @@ #include "iscsi_target_auth.h" #define MAX_LOGIN_PDUS 7 -#define TEXT_LEN 4096 void convert_null_to_semi(char *buf, int len) { @@ -71,31 +63,34 @@ int extract_param( int len; if (!in_buf || !pattern || !out_buf || !type) - return -1; + return -EINVAL; ptr = strstr(in_buf, pattern); if (!ptr) - return -1; + return -ENOENT; ptr = strstr(ptr, "="); if (!ptr) - return -1; + return -EINVAL; ptr += 1; if (*ptr == '0' && (*(ptr+1) == 'x' || *(ptr+1) == 'X')) { ptr += 2; /* skip 0x */ *type = HEX; + } else if (*ptr == '0' && (*(ptr+1) == 'b' || *(ptr+1) == 'B')) { + ptr += 2; /* skip 0b */ + *type = BASE64; } else *type = DECIMAL; len = strlen_semi(ptr); if (len < 0) - return -1; + return -EINVAL; if (len >= max_length) { pr_err("Length of input: %d exceeds max_length:" " %d\n", len, max_length); - return -1; + return -EINVAL; } memcpy(out_buf, ptr, len); out_buf[len] = '\0'; @@ -103,55 +98,44 @@ int extract_param( return 0; } +static struct iscsi_node_auth *iscsi_get_node_auth(struct iscsit_conn *conn) +{ + struct iscsi_portal_group *tpg; + struct iscsi_node_acl *nacl; + struct se_node_acl *se_nacl; + + if (conn->sess->sess_ops->SessionType) + return &iscsit_global->discovery_acl.node_auth; + + se_nacl = conn->sess->se_sess->se_node_acl; + if (!se_nacl) { + pr_err("Unable to locate struct se_node_acl for CHAP auth\n"); + return NULL; + } + + if (se_nacl->dynamic_node_acl) { + tpg = to_iscsi_tpg(se_nacl->se_tpg); + return &tpg->tpg_demo_auth; + } + + nacl = to_iscsi_nacl(se_nacl); + + return &nacl->node_auth; +} + static u32 iscsi_handle_authentication( - struct iscsi_conn *conn, + struct iscsit_conn *conn, char *in_buf, char *out_buf, int in_length, int *out_length, unsigned char *authtype) { - struct iscsi_session *sess = conn->sess; struct iscsi_node_auth *auth; - struct iscsi_node_acl *iscsi_nacl; - struct iscsi_portal_group *iscsi_tpg; - struct se_node_acl *se_nacl; - - if (!sess->sess_ops->SessionType) { - /* - * For SessionType=Normal - */ - se_nacl = conn->sess->se_sess->se_node_acl; - if (!se_nacl) { - pr_err("Unable to locate struct se_node_acl for" - " CHAP auth\n"); - return -1; - } - iscsi_nacl = container_of(se_nacl, struct iscsi_node_acl, - se_node_acl); - if (!iscsi_nacl) { - pr_err("Unable to locate struct iscsi_node_acl for" - " CHAP auth\n"); - return -1; - } - if (se_nacl->dynamic_node_acl) { - iscsi_tpg = container_of(se_nacl->se_tpg, - struct iscsi_portal_group, tpg_se_tpg); - - auth = &iscsi_tpg->tpg_demo_auth; - } else { - iscsi_nacl = container_of(se_nacl, struct iscsi_node_acl, - se_node_acl); - - auth = &iscsi_nacl->node_auth; - } - } else { - /* - * For SessionType=Discovery - */ - auth = &iscsit_global->discovery_acl.node_auth; - } + auth = iscsi_get_node_auth(conn); + if (!auth) + return -1; if (strstr("CHAP", authtype)) strcpy(conn->sess->auth_type, "CHAP"); @@ -160,31 +144,20 @@ static u32 iscsi_handle_authentication( if (strstr("None", authtype)) return 1; -#ifdef CANSRP - else if (strstr("SRP", authtype)) - return srp_main_loop(conn, auth, in_buf, out_buf, - &in_length, out_length); -#endif else if (strstr("CHAP", authtype)) return chap_main_loop(conn, auth, in_buf, out_buf, &in_length, out_length); - else if (strstr("SPKM1", authtype)) - return 2; - else if (strstr("SPKM2", authtype)) - return 2; - else if (strstr("KRB5", authtype)) - return 2; - else - return 2; + /* SRP, SPKM1, SPKM2 and KRB5 are unsupported */ + return 2; } -static void iscsi_remove_failed_auth_entry(struct iscsi_conn *conn) +static void iscsi_remove_failed_auth_entry(struct iscsit_conn *conn) { kfree(conn->auth_protocol); } int iscsi_target_check_login_request( - struct iscsi_conn *conn, + struct iscsit_conn *conn, struct iscsi_login *login) { int req_csg, req_nsg; @@ -239,7 +212,7 @@ int iscsi_target_check_login_request( if ((login_req->max_version != login->version_max) || (login_req->min_version != login->version_min)) { - pr_err("Login request changed Version Max/Nin" + pr_err("Login request changed Version Max/Min" " unexpectedly to 0x%02x/0x%02x, protocol error\n", login_req->max_version, login_req->min_version); iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, @@ -275,7 +248,7 @@ int iscsi_target_check_login_request( EXPORT_SYMBOL(iscsi_target_check_login_request); static int iscsi_target_check_first_request( - struct iscsi_conn *conn, + struct iscsit_conn *conn, struct iscsi_login *login) { struct iscsi_param *param = NULL; @@ -342,7 +315,7 @@ static int iscsi_target_check_first_request( return 0; } -static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_login *login) +static int iscsi_target_do_tx_login_io(struct iscsit_conn *conn, struct iscsi_login *login) { u32 padding = 0; struct iscsi_login_rsp *login_rsp; @@ -409,9 +382,10 @@ err: static void iscsi_target_sk_data_ready(struct sock *sk) { - struct iscsi_conn *conn = sk->sk_user_data; + struct iscsit_conn *conn = sk->sk_user_data; bool rc; + trace_sk_data_ready(sk); pr_debug("Entering iscsi_target_sk_data_ready: conn: %p\n", conn); write_lock_bh(&sk->sk_callback_lock); @@ -448,7 +422,7 @@ static void iscsi_target_sk_data_ready(struct sock *sk) static void iscsi_target_sk_state_change(struct sock *); -static void iscsi_target_set_sock_callbacks(struct iscsi_conn *conn) +static void iscsi_target_set_sock_callbacks(struct iscsit_conn *conn) { struct sock *sk; @@ -470,7 +444,7 @@ static void iscsi_target_set_sock_callbacks(struct iscsi_conn *conn) sk->sk_rcvtimeo = TA_LOGIN_TIMEOUT * HZ; } -static void iscsi_target_restore_sock_callbacks(struct iscsi_conn *conn) +static void iscsi_target_restore_sock_callbacks(struct iscsit_conn *conn) { struct sock *sk; @@ -494,19 +468,19 @@ static void iscsi_target_restore_sock_callbacks(struct iscsi_conn *conn) sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT; } -static int iscsi_target_do_login(struct iscsi_conn *, struct iscsi_login *); +static int iscsi_target_do_login(struct iscsit_conn *, struct iscsi_login *); static bool __iscsi_target_sk_check_close(struct sock *sk) { if (sk->sk_state == TCP_CLOSE_WAIT || sk->sk_state == TCP_CLOSE) { pr_debug("__iscsi_target_sk_check_close: TCP_CLOSE_WAIT|TCP_CLOSE," - "returning FALSE\n"); + "returning TRUE\n"); return true; } return false; } -static bool iscsi_target_sk_check_close(struct iscsi_conn *conn) +static bool iscsi_target_sk_check_close(struct iscsit_conn *conn) { bool state = false; @@ -521,7 +495,7 @@ static bool iscsi_target_sk_check_close(struct iscsi_conn *conn) return state; } -static bool iscsi_target_sk_check_flag(struct iscsi_conn *conn, unsigned int flag) +static bool iscsi_target_sk_check_flag(struct iscsit_conn *conn, unsigned int flag) { bool state = false; @@ -535,7 +509,7 @@ static bool iscsi_target_sk_check_flag(struct iscsi_conn *conn, unsigned int fla return state; } -static bool iscsi_target_sk_check_and_clear(struct iscsi_conn *conn, unsigned int flag) +static bool iscsi_target_sk_check_and_clear(struct iscsit_conn *conn, unsigned int flag) { bool state = false; @@ -552,55 +526,38 @@ static bool iscsi_target_sk_check_and_clear(struct iscsi_conn *conn, unsigned in return state; } -static void iscsi_target_login_drop(struct iscsi_conn *conn, struct iscsi_login *login) +static void iscsi_target_login_drop(struct iscsit_conn *conn, struct iscsi_login *login) { - struct iscsi_np *np = login->np; bool zero_tsih = login->zero_tsih; iscsi_remove_failed_auth_entry(conn); iscsi_target_nego_release(conn); - iscsi_target_login_sess_out(conn, np, zero_tsih, true); -} - -struct conn_timeout { - struct timer_list timer; - struct iscsi_conn *conn; -}; - -static void iscsi_target_login_timeout(struct timer_list *t) -{ - struct conn_timeout *timeout = from_timer(timeout, t, timer); - struct iscsi_conn *conn = timeout->conn; - - pr_debug("Entering iscsi_target_login_timeout >>>>>>>>>>>>>>>>>>>\n"); - - if (conn->login_kworker) { - pr_debug("Sending SIGINT to conn->login_kworker %s/%d\n", - conn->login_kworker->comm, conn->login_kworker->pid); - send_sig(SIGINT, conn->login_kworker, 1); - } + iscsi_target_login_sess_out(conn, zero_tsih, true); } static void iscsi_target_do_login_rx(struct work_struct *work) { - struct iscsi_conn *conn = container_of(work, - struct iscsi_conn, login_work.work); + struct iscsit_conn *conn = container_of(work, + struct iscsit_conn, login_work.work); struct iscsi_login *login = conn->login; struct iscsi_np *np = login->np; struct iscsi_portal_group *tpg = conn->tpg; struct iscsi_tpg_np *tpg_np = conn->tpg_np; - struct conn_timeout timeout; int rc, zero_tsih = login->zero_tsih; bool state; pr_debug("entering iscsi_target_do_login_rx, conn: %p, %s:%d\n", conn, current->comm, current->pid); + + spin_lock(&conn->login_worker_lock); + set_bit(LOGIN_FLAGS_WORKER_RUNNING, &conn->login_flags); + spin_unlock(&conn->login_worker_lock); /* * If iscsi_target_do_login_rx() has been invoked by ->sk_data_ready() * before initial PDU processing in iscsi_target_start_negotiation() * has completed, go ahead and retry until it's cleared. * - * Otherwise if the TCP connection drops while this is occuring, + * Otherwise if the TCP connection drops while this is occurring, * iscsi_target_start_negotiation() will detect the failure, call * cancel_delayed_work_sync(&conn->login_work), and cleanup the * remaining iscsi connection resources from iscsi_np process context. @@ -624,19 +581,16 @@ static void iscsi_target_do_login_rx(struct work_struct *work) goto err; } - conn->login_kworker = current; allow_signal(SIGINT); - - timeout.conn = conn; - timer_setup_on_stack(&timeout.timer, iscsi_target_login_timeout, 0); - mod_timer(&timeout.timer, jiffies + TA_LOGIN_TIMEOUT * HZ); - pr_debug("Starting login timer for %s/%d\n", current->comm, current->pid); + rc = iscsit_set_login_timer_kworker(conn, current); + if (rc < 0) { + /* The login timer has already expired */ + pr_debug("iscsi_target_do_login_rx, login failed\n"); + goto err; + } rc = conn->conn_transport->iscsit_get_login_rx(conn, login); - del_timer_sync(&timeout.timer); - destroy_timer_on_stack(&timeout.timer); flush_signals(current); - conn->login_kworker = NULL; if (rc < 0) goto err; @@ -644,13 +598,47 @@ static void iscsi_target_do_login_rx(struct work_struct *work) pr_debug("iscsi_target_do_login_rx after rx_login_io, %p, %s:%d\n", conn, current->comm, current->pid); + /* + * LOGIN_FLAGS_READ_ACTIVE is cleared so that sk_data_ready + * could be triggered again after this. + * + * LOGIN_FLAGS_WRITE_ACTIVE is cleared after we successfully + * process a login PDU, so that sk_state_chage can do login + * cleanup as needed if the socket is closed. If a delayed work is + * ongoing (LOGIN_FLAGS_WRITE_ACTIVE or LOGIN_FLAGS_READ_ACTIVE), + * sk_state_change will leave the cleanup to the delayed work or + * it will schedule a delayed work to do cleanup. + */ + if (conn->sock) { + struct sock *sk = conn->sock->sk; + + write_lock_bh(&sk->sk_callback_lock); + if (!test_bit(LOGIN_FLAGS_INITIAL_PDU, &conn->login_flags)) { + clear_bit(LOGIN_FLAGS_READ_ACTIVE, &conn->login_flags); + set_bit(LOGIN_FLAGS_WRITE_ACTIVE, &conn->login_flags); + } + write_unlock_bh(&sk->sk_callback_lock); + } + rc = iscsi_target_do_login(conn, login); if (rc < 0) { goto err; } else if (!rc) { - if (iscsi_target_sk_check_and_clear(conn, LOGIN_FLAGS_READ_ACTIVE)) + if (iscsi_target_sk_check_and_clear(conn, + LOGIN_FLAGS_WRITE_ACTIVE)) + goto err; + + /* + * Set the login timer thread pointer to NULL to prevent the + * login process from getting stuck if the initiator + * stops sending data. + */ + rc = iscsit_set_login_timer_kworker(conn, NULL); + if (rc < 0) goto err; } else if (rc == 1) { + iscsit_stop_login_timer(conn); + cancel_delayed_work(&conn->login_work); iscsi_target_nego_release(conn); iscsi_post_login_handler(np, conn, zero_tsih); iscsit_deaccess_np(np, tpg, tpg_np); @@ -659,13 +647,15 @@ static void iscsi_target_do_login_rx(struct work_struct *work) err: iscsi_target_restore_sock_callbacks(conn); + iscsit_stop_login_timer(conn); + cancel_delayed_work(&conn->login_work); iscsi_target_login_drop(conn, login); iscsit_deaccess_np(np, tpg, tpg_np); } static void iscsi_target_sk_state_change(struct sock *sk) { - struct iscsi_conn *conn; + struct iscsit_conn *conn; void (*orig_state_change)(struct sock *); bool state; @@ -689,9 +679,10 @@ static void iscsi_target_sk_state_change(struct sock *sk) state = __iscsi_target_sk_check_close(sk); pr_debug("__iscsi_target_sk_close_change: state: %d\n", state); - if (test_bit(LOGIN_FLAGS_READ_ACTIVE, &conn->login_flags)) { - pr_debug("Got LOGIN_FLAGS_READ_ACTIVE=1 sk_state_change" - " conn: %p\n", conn); + if (test_bit(LOGIN_FLAGS_READ_ACTIVE, &conn->login_flags) || + test_bit(LOGIN_FLAGS_WRITE_ACTIVE, &conn->login_flags)) { + pr_debug("Got LOGIN_FLAGS_{READ|WRITE}_ACTIVE=1" + " sk_state_change conn: %p\n", conn); if (state) set_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags); write_unlock_bh(&sk->sk_callback_lock); @@ -743,7 +734,7 @@ static void iscsi_target_sk_state_change(struct sock *sk) * ISID/TSIH combinations. */ static int iscsi_target_check_for_existing_instances( - struct iscsi_conn *conn, + struct iscsit_conn *conn, struct iscsi_login *login) { if (login->checked_for_existing) @@ -759,7 +750,7 @@ static int iscsi_target_check_for_existing_instances( } static int iscsi_target_do_authentication( - struct iscsi_conn *conn, + struct iscsit_conn *conn, struct iscsi_login *login) { int authret; @@ -817,8 +808,44 @@ static int iscsi_target_do_authentication( return 0; } +bool iscsi_conn_auth_required(struct iscsit_conn *conn) +{ + struct iscsi_node_acl *nacl; + struct se_node_acl *se_nacl; + + if (conn->sess->sess_ops->SessionType) { + /* + * For SessionType=Discovery + */ + return conn->tpg->tpg_attrib.authentication; + } + /* + * For SessionType=Normal + */ + se_nacl = conn->sess->se_sess->se_node_acl; + if (!se_nacl) { + pr_debug("Unknown ACL is trying to connect\n"); + return true; + } + + if (se_nacl->dynamic_node_acl) { + pr_debug("Dynamic ACL %s is trying to connect\n", + se_nacl->initiatorname); + return conn->tpg->tpg_attrib.authentication; + } + + pr_debug("Known ACL %s is trying to connect\n", + se_nacl->initiatorname); + + nacl = to_iscsi_nacl(se_nacl); + if (nacl->node_attrib.authentication == NA_AUTHENTICATION_INHERITED) + return conn->tpg->tpg_attrib.authentication; + + return nacl->node_attrib.authentication; +} + static int iscsi_target_handle_csg_zero( - struct iscsi_conn *conn, + struct iscsit_conn *conn, struct iscsi_login *login) { int ret; @@ -878,22 +905,26 @@ static int iscsi_target_handle_csg_zero( return -1; if (!iscsi_check_negotiated_keys(conn->param_list)) { - if (conn->tpg->tpg_attrib.authentication && - !strncmp(param->value, NONE, 4)) { - pr_err("Initiator sent AuthMethod=None but" - " Target is enforcing iSCSI Authentication," - " login failed.\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, - ISCSI_LOGIN_STATUS_AUTH_FAILED); - return -1; - } + bool auth_required = iscsi_conn_auth_required(conn); + + if (auth_required) { + if (!strncmp(param->value, NONE, 4)) { + pr_err("Initiator sent AuthMethod=None but" + " Target is enforcing iSCSI Authentication," + " login failed.\n"); + iscsit_tx_login_rsp(conn, + ISCSI_STATUS_CLS_INITIATOR_ERR, + ISCSI_LOGIN_STATUS_AUTH_FAILED); + return -1; + } - if (conn->tpg->tpg_attrib.authentication && - !login->auth_complete) - return 0; + if (!login->auth_complete) + return 0; - if (strncmp(param->value, NONE, 4) && !login->auth_complete) - return 0; + if (strncmp(param->value, NONE, 4) && + !login->auth_complete) + return 0; + } if ((login_req->flags & ISCSI_FLAG_LOGIN_NEXT_STAGE1) && (login_req->flags & ISCSI_FLAG_LOGIN_TRANSIT)) { @@ -908,7 +939,19 @@ do_auth: return iscsi_target_do_authentication(conn, login); } -static int iscsi_target_handle_csg_one(struct iscsi_conn *conn, struct iscsi_login *login) +static bool iscsi_conn_authenticated(struct iscsit_conn *conn, + struct iscsi_login *login) +{ + if (!iscsi_conn_auth_required(conn)) + return true; + + if (login->auth_complete) + return true; + + return false; +} + +static int iscsi_target_handle_csg_one(struct iscsit_conn *conn, struct iscsi_login *login) { int ret; u32 payload_length; @@ -951,11 +994,10 @@ static int iscsi_target_handle_csg_one(struct iscsi_conn *conn, struct iscsi_log return -1; } - if (!login->auth_complete && - conn->tpg->tpg_attrib.authentication) { + if (!iscsi_conn_authenticated(conn, login)) { pr_err("Initiator is requesting CSG: 1, has not been" - " successfully authenticated, and the Target is" - " enforcing iSCSI Authentication, login failed.\n"); + " successfully authenticated, and the Target is" + " enforcing iSCSI Authentication, login failed.\n"); iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, ISCSI_LOGIN_STATUS_AUTH_FAILED); return -1; @@ -970,7 +1012,14 @@ static int iscsi_target_handle_csg_one(struct iscsi_conn *conn, struct iscsi_log return 0; } -static int iscsi_target_do_login(struct iscsi_conn *conn, struct iscsi_login *login) +/* + * RETURN VALUE: + * + * 1 = Login successful + * -1 = Login failed + * 0 = More PDU exchanges required + */ +static int iscsi_target_do_login(struct iscsit_conn *conn, struct iscsi_login *login) { int pdu_count = 0; struct iscsi_login_req *login_req; @@ -1001,7 +1050,7 @@ static int iscsi_target_do_login(struct iscsi_conn *conn, struct iscsi_login *lo /* * Check to make sure the TCP connection has not * dropped asynchronously while session reinstatement - * was occuring in this kthread context, before + * was occurring in this kthread context, before * transitioning to full feature phase operation. */ if (iscsi_target_sk_check_close(conn)) @@ -1056,12 +1105,12 @@ static void iscsi_initiatorname_tolower( */ int iscsi_target_locate_portal( struct iscsi_np *np, - struct iscsi_conn *conn, + struct iscsit_conn *conn, struct iscsi_login *login) { char *i_buf = NULL, *s_buf = NULL, *t_buf = NULL; char *tmpbuf, *start = NULL, *end = NULL, *key, *value; - struct iscsi_session *sess = conn->sess; + struct iscsit_session *sess = conn->sess; struct iscsi_tiqn *tiqn; struct iscsi_tpg_np *tpg_np = NULL; struct iscsi_login_req *login_req; @@ -1073,18 +1122,17 @@ int iscsi_target_locate_portal( iscsi_target_set_sock_callbacks(conn); login->np = np; + conn->tpg = NULL; login_req = (struct iscsi_login_req *) login->req; payload_length = ntoh24(login_req->dlength); - tmpbuf = kzalloc(payload_length + 1, GFP_KERNEL); + tmpbuf = kmemdup_nul(login->req_buf, payload_length, GFP_KERNEL); if (!tmpbuf) { pr_err("Unable to allocate memory for tmpbuf.\n"); return -1; } - memcpy(tmpbuf, login->req_buf, payload_length); - tmpbuf[payload_length] = '\0'; start = tmpbuf; end = (start + payload_length); @@ -1142,26 +1190,20 @@ int iscsi_target_locate_portal( */ sessiontype = strncmp(s_buf, DISCOVERY, 9); if (!sessiontype) { - conn->tpg = iscsit_global->discovery_tpg; if (!login->leading_connection) goto get_target; sess->sess_ops->SessionType = 1; - /* - * Setup crc32c modules from libcrypto - */ - if (iscsi_login_setup_crypto(conn) < 0) { - pr_err("iscsi_login_setup_crypto() failed\n"); - ret = -1; - goto out; - } + /* * Serialize access across the discovery struct iscsi_portal_group to * process login attempt. */ + conn->tpg = iscsit_global->discovery_tpg; if (iscsit_access_np(np, conn->tpg) < 0) { iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE); + conn->tpg = NULL; ret = -1; goto out; } @@ -1209,17 +1251,7 @@ get_target: } conn->tpg_np = tpg_np; pr_debug("Located Portal Group Object: %hu\n", conn->tpg->tpgt); - /* - * Setup crc32c modules from libcrypto - */ - if (iscsi_login_setup_crypto(conn) < 0) { - pr_err("iscsi_login_setup_crypto() failed\n"); - kref_put(&tpg_np->tpg_np_kref, iscsit_login_kref_put); - iscsit_put_tiqn_for_login(tiqn); - conn->tpg = NULL; - ret = -1; - goto out; - } + /* * Serialize access across the struct iscsi_portal_group to * process login attempt. @@ -1236,7 +1268,7 @@ get_target: /* * conn->sess->node_acl will be set when the referenced - * struct iscsi_session is located from received ISID+TSIH in + * struct iscsit_session is located from received ISID+TSIH in * iscsi_login_non_zero_tsih_s2(). */ if (!login->leading_connection) { @@ -1276,7 +1308,7 @@ get_target: alloc_tags: tag_num = max_t(u32, ISCSIT_MIN_TAGS, queue_depth); tag_num = (tag_num * 2) + ISCSIT_EXTRA_TAGS; - tag_size = sizeof(struct iscsi_cmd) + conn->conn_transport->priv_size; + tag_size = sizeof(struct iscsit_cmd) + conn->conn_transport->priv_size; ret = transport_alloc_session_tags(sess->se_sess, tag_num, tag_size); if (ret < 0) { @@ -1291,7 +1323,7 @@ out: int iscsi_target_start_negotiation( struct iscsi_login *login, - struct iscsi_conn *conn) + struct iscsit_conn *conn) { int ret; @@ -1313,21 +1345,38 @@ int iscsi_target_start_negotiation( * and perform connection cleanup now. */ ret = iscsi_target_do_login(conn, login); - if (!ret && iscsi_target_sk_check_and_clear(conn, LOGIN_FLAGS_INITIAL_PDU)) - ret = -1; + if (!ret) { + spin_lock(&conn->login_worker_lock); + + if (iscsi_target_sk_check_and_clear(conn, LOGIN_FLAGS_INITIAL_PDU)) + ret = -1; + else if (!test_bit(LOGIN_FLAGS_WORKER_RUNNING, &conn->login_flags)) { + if (iscsit_set_login_timer_kworker(conn, NULL) < 0) { + /* + * The timeout has expired already. + * Schedule login_work to perform the cleanup. + */ + schedule_delayed_work(&conn->login_work, 0); + } + } + + spin_unlock(&conn->login_worker_lock); + } if (ret < 0) { - cancel_delayed_work_sync(&conn->login_work); iscsi_target_restore_sock_callbacks(conn); iscsi_remove_failed_auth_entry(conn); } - if (ret != 0) + if (ret != 0) { + iscsit_stop_login_timer(conn); + cancel_delayed_work_sync(&conn->login_work); iscsi_target_nego_release(conn); + } return ret; } -void iscsi_target_nego_release(struct iscsi_conn *conn) +void iscsi_target_nego_release(struct iscsit_conn *conn) { struct iscsi_login *login = conn->conn_login; |
