iscsi-session.c
来自「iSCSI协议在LINUX下的源码.源代码是IBM公布的.主要是结合其OSD设备」· C语言 代码 · 共 1,649 行 · 第 1/3 页
C
1,649 行
} if (ioctld->username_in[0] && (!session->username_in || strcmp(ioctld->username_in, session->username_in))) { uname_in = strdup(ioctld->username_in, &rc); if (!uname_in) { iscsi_host_err(session, "Failed to change incoming " "username\n"); goto failed; } } if (ioctld->password_length && (!session->password || session->password_length != ioctld->password_length || memcmp(ioctld->password, session->password, session->password_length))) { pw = kmalloc(ioctld->password_length + 1, GFP_KERNEL); if (!pw) { iscsi_host_err(session, "Failed to change outgoing " "password\n"); rc = -ENOMEM; goto failed; } memcpy(pw, ioctld->password, ioctld->password_length); } if (ioctld->password_length_in && (!session->password_in || session->password_length_in != ioctld->password_length_in || memcmp(ioctld->password_in, session->password_in, session->password_length_in))) { pw_in = kmalloc(ioctld->password_length_in + 1, GFP_KERNEL); if (!pw_in) { iscsi_host_err(session, "Failed to change incoming " "password\n"); rc = -ENOMEM; goto failed; } memcpy(pw_in, ioctld->password_in, ioctld->password_length_in); } if (iname) { kfree(session->initiator_name); session->initiator_name = iname; rc = 1; } if (alias || (!ioctld->initiator_alias[0] && session->initiator_alias[0])) { kfree(session->initiator_alias); session->initiator_alias = alias; rc = 1; } if (uname || (!ioctld->username[0] && session->username)) { kfree(session->username); session->username = uname; rc = 1; } if (uname_in || (!ioctld->username_in[0] && session->username_in)) { kfree(session->username_in); session->username_in = uname_in; rc = 1; } if (pw || (!ioctld->password_length && session->password)) { kfree(session->password); session->password = pw; session->password_length = ioctld->password_length; rc = 1; } if (pw_in || (!ioctld->password_length_in && session->password_in)) { kfree(session->password_in); session->password_in = pw_in; session->password_length_in = ioctld->password_length_in; rc = 1; } return rc; failed: kfree(iname); kfree(alias); kfree(uname); kfree(uname_in); kfree(pw); kfree(pw_in); return rc;}intiscsi_update_session(struct iscsi_session *session, struct iscsi_session_ioctl *ioctld){ int rc = 0; int relogin = 0; if (down_interruptible(&session->config_mutex)) { iscsi_host_err(session, "Session configuration update aborted " "by signal\n"); return -EINTR; } if (test_bit(SESSION_TERMINATED, &session->control_bits)) return -EINVAL; if (ioctld->update && (ioctld->config_number < session->config_number)) /* this update is obsolete, ignore it */ goto err_exit; if (ioctld->username_in[0] || ioctld->password_length_in) session->bidirectional_auth = 1; else session->bidirectional_auth = 0; rc = alloc_auth_buffers(session); if (rc < 0) goto err_exit; rc = update_iscsi_strings(session, ioctld); if (rc > 0) relogin = 1; else if (rc < 0) goto err_exit; session->config_number = ioctld->config_number; up(&session->config_mutex); /* * the portals are guarded by a spinlock instead of the config * mutex, so that we can request portal changes while a login is * occuring. */ spin_lock(&session->portal_lock); if (iscsi_update_portal_info(&session->portal, &ioctld->portal)) relogin = 1; spin_unlock(&session->portal_lock); if (relogin) if (test_bit(SESSION_ESTABLISHED, &session->control_bits)) { spin_lock_bh(&session->task_lock); iscsi_request_logout(session, 3, session->active_timeout); spin_unlock_bh(&session->task_lock); } return 0; err_exit: up(&session->config_mutex); return rc;}static intcopy_iscsi_strings(struct iscsi_session *session, struct iscsi_session_ioctl *ioctld){ int rc; session->initiator_name = strdup(ioctld->initiator_name, &rc); if (rc == -EINVAL) { iscsi_host_err(session, "No InitiatorName\n"); return rc; } if (rc == -ENOMEM) { iscsi_host_err(session, "Cannot allocate InitiatorName\n"); return rc; } session->initiator_alias = strdup(ioctld->initiator_alias, &rc); /* Alias is not ciritical so just print an error */ if (!session->initiator_alias) iscsi_host_err(session, "Cannot create InitiatorAlias\n"); session->target_name = strdup(ioctld->target_name, &rc); if (rc == -EINVAL) { iscsi_err("No TargetName\n"); return rc; } if (rc == -ENOMEM) { iscsi_host_err(session, "Cannot allocate TargetName\n"); return rc; } session->username = strdup(ioctld->username, &rc); if (rc == -ENOMEM) { iscsi_host_err(session, "Failed to allocate outgoing " "username\n"); return rc; } session->username_in = strdup(ioctld->username_in, &rc); if (rc == -ENOMEM) { iscsi_host_err(session, "Failed to allocate incoming " "username\n"); return rc; } if (ioctld->password_length) { session->password = kmalloc(ioctld->password_length + 1, GFP_KERNEL); if (!session->password) { iscsi_host_err(session, "Failed to allocate outgoing " "password\n"); return -ENOMEM; } memcpy(session->password, ioctld->password, ioctld->password_length); session->password_length = ioctld->password_length; } if (ioctld->password_length_in) { session->password_in = kmalloc(ioctld->password_length_in + 1, GFP_KERNEL); if (!session->password_in) { iscsi_host_err(session, "Failed to allocate incoming " "password\n"); return -ENOMEM; } memcpy(session->password_in, ioctld->password_in, ioctld->password_length_in); session->password_length_in = ioctld->password_length_in; } return 0;}/** * reinit_session - init of session fields before attempting a re-login. * @session: session to initialize. **/static voidreinit_session(struct iscsi_session *session){ struct iscsi_nop_info *nop_info, *tmp; session->last_mgmt_itt = ISCSI_RSVD_TASK_TAG; /* * can't send any nop replies now */ session->nop_reply.ttt = ISCSI_RSVD_TASK_TAG; list_for_each_entry_safe(nop_info, tmp, &session->nop_reply_list, reply_list) { list_del(&nop_info->reply_list); kfree(nop_info); } session->logout_deadline = 0; session->logout_response_deadline = 0;}static voidinit_session_structure(struct iscsi_session *session, struct iscsi_session_ioctl *ioctld){ INIT_LIST_HEAD(&session->list); /* authentication parameters */ session->auth_client_block = NULL; session->auth_recv_string_block = NULL; session->auth_send_string_block = NULL; session->auth_recv_binary_block = NULL; session->auth_send_binary_block = NULL; session->socket = NULL; session->config_number = ioctld->config_number; spin_lock_init(&session->portal_lock); /* portal-specific parameters */ session->portal_group_tag = -1; /* retry and timer specific parameters */ sema_init(&session->config_mutex, 0); /* the first down should block */ INIT_LIST_HEAD(&session->pending_queue); INIT_LIST_HEAD(&session->active_queue); INIT_LIST_HEAD(&session->done_queue); spin_lock_init(&session->task_lock); INIT_LIST_HEAD(&(session->tx_task_head)); atomic_set(&session->num_active_tasks, 0); init_waitqueue_head(&session->tx_wait_q); init_waitqueue_head(&session->login_wait_q); sema_init(&session->tx_blocked, 0); session->next_itt = 1; session->time2wait = -1; session->last_mgmt_itt = ISCSI_RSVD_TASK_TAG; session->mgmt_task_complete = NULL; session->session_drop_time = 0;}static intcheck_login_timeouts(struct iscsi_session *session){ unsigned long session_timeout = 0; if (session->login_phase_timer) { session_timeout = session->login_phase_timer; if (time_before_eq(session_timeout, jiffies)) { iscsi_host_err(session, "Login phase timed out, timeout" " was set for %lu\n", session_timeout); session->login_phase_timer = 0; session_timeout = 0; signal_iscsi_threads(session); } } return session_timeout;}static unsigned longcheck_session_ping_timeout(struct iscsi_session *session, unsigned long timeout){ /* should have received something by now, kill the connection */ if ((session->last_kill == 0) || time_before_eq(session->last_kill + HZ, jiffies)) { session->last_kill = jiffies; iscsi_host_err(session, "%lu second timeout expired rx %lu, " "ping %lu, now %lu\n", timeout + session->ping_timeout, session->last_rx, session->last_ping, jiffies); iscsi_drop_session(session); return (jiffies + HZ); } else return 0;}static unsigned longcheck_session_idle_timeout(struct iscsi_session *session){ unsigned long active_timeout, idle_timeout; /* * session is idle, but may become active without the timer being * notified, so use smaller of (now + active_timeout, last_rx + * idle_timeout) */ idle_timeout = session->last_rx + (session->idle_timeout * HZ); active_timeout = jiffies + (session->active_timeout * HZ); if (time_before_eq(idle_timeout, active_timeout)) return idle_timeout; else return active_timeout;}static unsigned longhandle_iscsi_logout_timeout(struct iscsi_session *session){ unsigned long session_timeout = 0; /* * we're waiting for tasks to complete before logging out. No need to * check the CmdSN window, since we won't be starting any more tasks. */ if (time_before_eq(session->logout_response_deadline, jiffies)) { /* * passed the deadline for a logout response, just drop the * session */ iscsi_host_err(session, "Logout response timeout, dropping " "session\n"); session->logout_response_deadline = 0; session->logout_deadline = 0; iscsi_drop_session(session); } else { if (time_before_eq(session->logout_deadline, jiffies)) { /* send a logout */ session->logout_deadline = 0; iscsi_wake_tx_thread(TX_LOGOUT, session); if ((session_timeout == 0) || time_before(session->logout_response_deadline, session_timeout)) session_timeout = session->logout_response_deadline; } else { if ((session_timeout == 0) || time_before(session->logout_deadline, session_timeout)) session_timeout = session->logout_deadline; } } return session_timeout;}static voidcheck_iscsi_cmd_window_closed(struct iscsi_session *session, unsigned long *session_timeout){ if (test_bit(SESSION_WINDOW_CLOSED, &session->control_bits) && time_before_eq(session->last_window_check + HZ, jiffies)) { /* * command window closed, ping once a second to ensure * we find out when it re-opens. Target should send * us an update when it does, but we're not very * trusting of target correctness. */ session->last_window_check = jiffies; /* request a window update from the target with Nops */ iscsi_wake_tx_thread(TX_PING, session); if (((*session_timeout) == 0) || time_before(session->last_window_check + HZ, *session_timeout)) *session_timeout = session->last_window_check + HZ; }}static intcheck_full_feature_timeouts(struct iscsi_session *session){ unsigned long timeout; unsigned long session_timeout = 0; if (atomic_read(&session->num_active_tasks)) timeout = session->active_timeout; else timeout = session->idle_timeout; if (timeout) { if (session->ping_timeout && time_before_eq(session->last_rx + (timeout * HZ) + (session->ping_timeout * HZ), jiffies)) session_timeout = check_session_ping_timeout (session, timeout); else { if (time_before_eq (session->last_rx + (timeout * HZ), jiffies)) { if (time_before_eq (session->last_ping, session->last_rx)) { /* * send a ping to try to provoke some * traffic */ session->last_ping = jiffies - 1; iscsi_wake_tx_thread(TX_PING, session); } session_timeout = session->last_rx + (timeout * HZ) + (session->ping_timeout * HZ); } else { if (atomic_read(&session->num_active_tasks)) session_timeout = session->last_rx + (session->active_timeout * HZ); else session_timeout = check_session_idle_timeout (session); } } } if (test_bit(SESSION_LOGOUT_REQUESTED, &session->control_bits)) session_timeout = handle_iscsi_logout_timeout(session); else check_iscsi_cmd_window_closed(session, &session_timeout); return session_timeout;}/* * do timer processing for one session, and return the length of time * (in jiffies) til this session needs to be checked again. */static voidsession_timeout(unsigned long data){ struct iscsi_session *session = (struct iscsi_session *)data; unsigned long timeout = 0; if (test_bit(SESSION_TERMINATED, &session->control_bits)) return; if (!test_bit(SESSION_ESTABLISHED, &session->control_bits)) /* check login phase timeouts */ timeout = check_login_timeouts(session); else /* check full-feature phase timeouts. */ timeout = check_full_feature_timeouts(session); if (!timeout) timeout = DEF_SESSION_TIMEOUT; mod_timer(&session->session_timer, timeout);}voidiscsi_wake_tx_thread(int control_bit, struct iscsi_session *session){ set_bit(control_bit, &session->control_bits); set_bit(TX_WAKE, &session->control_bits); wake_up(&session->tx_wait_q);}/** * iscsi_wait_for_session - Wait for a session event to be established. * @session: session to wait on. * @ignore_timeout: If zero this will return when the replacement timeout fires. * * Description: * Returns 1 to indicate sesssion was established, or 0 to indicate * we timed out (if ignore_timeout == 0) or are terminating. **/intiscsi_wait_for_session(struct iscsi_session *session, int ignore_timeout){ int rc = 0; while (1) { wait_event_interruptible(session->login_wait_q, test_bit(SESSION_ESTABLISHED, &session->control_bits) || test_bit(SESSION_TERMINATING, &session->control_bits) || (!ignore_timeout && test_bit(SESSION_REPLACEMENT_TIMEDOUT, &session->control_bits))); if (signal_pending(current)) flush_signals(current); /* * need to test for termnination first to avoid falling * in the tx request loop for ever */ if (test_bit(SESSION_TERMINATING, &session->control_bits)) break; if (test_bit(SESSION_ESTABLISHED, &session->control_bits)) { rc = 1; break; } if (!ignore_timeout && test_bit(SESSION_REPLACEMENT_TIMEDOUT, &session->control_bits)) break; } return rc;}/* * TODO: fix properly (kill this crap) when more than one R2T * or MCS is supported, or maybe sooner.... */static struct { void (* request_fn)(struct iscsi_session *);} tx_request_fns[] = { { iscsi_send_nop_out }, { iscsi_send_task_mgmt }, { iscsi_run_pending_queue }, { iscsi_send_nop_replys }, { iscsi_send_r2t_data }, { iscsi_send_logout },};static voidwait_for_tx_requests(struct iscsi_session *session){ int req; wait_event_interruptible(session->tx_wait_q,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?