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 + -
显示快捷键?