⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 initiator_error_rec.c

📁 iscsi源代码 UNH的progect 有initiator端和target端的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*	initiator/initiator_error_rec.c * *	vi: set autoindent tabstop=8 shiftwidth=8 : * *	This file contains auxilliary functions for iscsi initiator *      code that are responsible for dealing with error recovery. * *	Copyright (C) 2001-2004 InterOperability Lab (IOL) *	University of New Hampshire (UNH) *	Durham, NH 03824 * *	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, 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. * *	You should have received a copy of the GNU General Public License *	along with this program; if not, write to the Free Software *	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, *	USA. * *	The name IOL and/or UNH may not be used to endorse or promote *	products derived from this software without specific prior * 	written permission.*/#include "iscsi_initiator.h"#include "initiator_utilities.h"#include "initiator_error_rec.h"static DECLARE_MUTEX_LOCKED(init_sess_recovery_sem);static struct task_struct *init_rec_thread = NULL;/************************************************************************* The Main Error Recovery Handler Called from iscsi_initiator when it* finds any error.* When called, session lock must be locked* Returns >0 on success*	  =0 on failure, session lock is locked*	  <0 on failure, session lock is NOT locked************************************************************************/intinit_do_error_recovery(struct init_error_rec *err_rec){	int retval = 0;		/* assume this will fail with lock held */	struct connection *curr_conn;	TRACE(TRACE_ENTER_LEAVE, "Enter init_do_error_recovery \n");	if (err_rec == NULL) {		TRACE_ERROR("Error Recovery structure is NULL\n");		goto out;	}	if (err_rec->curr_conn == NULL) {		TRACE_ERROR		    ("NULL Connection Pointer in Error Recovery struct\n");		goto out;	}	curr_conn = err_rec->curr_conn;	switch (curr_conn->my_session->oper_param->ErrorRecoveryLevel) {	case SESSION_RECOVERY:		retval = init_session_recovery(err_rec);		break;	case DIGEST_RECOVERY:	case CONNECTION_RECOVERY:		retval = init_digest_recovery(err_rec);		break;	}out:	TRACE(TRACE_ENTER_LEAVE, "Leave init_do_error_recovery, retval %d\n",	      retval);	return retval;}/************************************************************************ * executed only by rx thread. * the current_session->sess_lock MUST be held by the calling process/thread. * This function handles the session recovery. It creates a recovery * thread that will do session recovery. * While the recovery thread is running the rx thread is blocked waiting for it. * Returns <0 forced failure, session lock is NOT locked * In all cases, current thread should not continue after the return! ************************************************************************/intinit_session_recovery(struct init_error_rec *err_rec){	struct connection *current_connection;	struct session *current_session;	TRACE(TRACE_ENTER_LEAVE, "Enter init_session_recovery \n");	if (!global_hostdata->init_sessrec_flg) {		/* globally mark that session recovery is in progress, so		 * attempts by SCSI to queue new commands are caught		 */		global_hostdata->init_sessrec_flg = 1;		current_connection = err_rec->curr_conn;		current_session = current_connection->my_session;		init_MUTEX_LOCKED(&init_sess_recovery_sem);		/* Release any resources held by this thread */		UNH_UNLOCK(&current_session->sess_lock,			   current_connection->rx_lock_flags);		TRACE(TRACE_ISCSI, "Starting initiator session recovery\n");		/* Create a recovery thread */		kernel_thread((int (*)(void *)) init_recovery_thread,				(void *) err_rec, 0);		/* Wait till the recovery thread completes processing */		down_interruptible(&init_sess_recovery_sem);	}	TRACE(TRACE_ENTER_LEAVE, "Leave init_session_recovery\n");	return -ESRCH;	/* any error will do, so give "No such process" */}/* Create a new recovery session for the failing session before cleaning-up * the failing session */struct sess_rec_group *set_rec_group(struct scsi_cmnd * Cmnd){	struct sess_rec_group *sess_grp;	struct sess_rec_group *prev_sess_grp;	struct sess_rec_cmnd *cmnd;	TRACE(TRACE_ENTER_LEAVE, "Enter set_rec_group\n");	prev_sess_grp = sess_grp = global_hostdata->sess_rec_head;	for (; sess_grp != NULL; sess_grp = sess_grp->next) {/* Ming Zhang, mingz@ele.uri.edu */#ifdef K26		if (sess_grp->cmnd_list_head->Cmnd->device->id == Cmnd->device->id)#else		if (sess_grp->cmnd_list_head->Cmnd->target == Cmnd->target)#endif			break;		prev_sess_grp = sess_grp;	}	if (sess_grp == NULL) {		sess_grp = (struct sess_rec_group *)				    my_kmalloc(sizeof(struct sess_rec_group),					       "sess_rec_group");		if (!sess_grp) {			goto out;		}		memset(sess_grp, 0, sizeof(struct sess_rec_group));		if (global_hostdata->sess_rec_head == NULL) {			TRACE(TRACE_DEBUG, "Previous Recovery list empty - "			      "creating new list\n");			global_hostdata->sess_rec_head = sess_grp;		} else {			prev_sess_grp->next = sess_grp;		}	}	cmnd =	    (struct sess_rec_cmnd *)my_kmalloc(sizeof(struct sess_rec_cmnd),						"sess_rec_cmnd");	if (unlikely(cmnd == NULL)) {		my_kfree((void **)&sess_grp, "sess_rec_group");		goto out;	}	memset(cmnd, 0, sizeof(struct sess_rec_cmnd));	cmnd->Cmnd = Cmnd;	if (sess_grp->cmnd_list_head == NULL) {		sess_grp->cmnd_list_head = cmnd;	} else {		sess_grp->cmnd_list_tail->next = cmnd;	}	sess_grp->cmnd_list_tail = cmnd;out:	TRACE(TRACE_ENTER_LEAVE, "Leave set_rec_group sess_grp %p\n", sess_grp);	return sess_grp;}voidclean_rec_group(struct sess_rec_group *sess){	struct sess_rec_group *sess_grp = global_hostdata->sess_rec_head;	struct sess_rec_group *prev_sess_grp = NULL;	struct sess_rec_cmnd *cmnd = NULL, *tmp_cmnd = NULL;	TRACE(TRACE_ENTER_LEAVE, "Enter clean_rec_group \n");	for (; sess_grp != NULL; sess_grp = sess_grp->next) {		if (sess_grp == sess)			break;		prev_sess_grp = sess;	}	cmnd = sess_grp->cmnd_list_head;	while (cmnd != NULL) {		tmp_cmnd = cmnd;		cmnd = cmnd->next;		my_kfree((void **) &tmp_cmnd, "sess_rec_cmnd");	}	if (sess_grp == global_hostdata->sess_rec_head) {		global_hostdata->sess_rec_head = sess_grp->next;	} else		prev_sess_grp->next = sess_grp->next;	if (sess_grp)		my_kfree((void **) &sess_grp, "sess_rec_group");	TRACE(TRACE_ENTER_LEAVE, "Leave clean_rec_group \n");}/************************************************************************* This thread handles the session recovery. Session Recovery will       ** abort all pending tasks and close all transport connections           ** Section (6.12.4)                                                      *************************************************************************/voidinit_recovery_thread(void *arg){	unsigned long flags;	int target, lun, cid;	int received = 1;	__u32 size;	struct response_pdu *header = NULL;	struct init_error_rec *err_rec;	struct connection *conn;	struct session *session;	struct sess_rec_cmnd *cmnd = NULL;	struct sess_rec_group *sess_grp = NULL;	struct sockaddr *old_ip_address, *new_ip_address;	int new_ip_length;#if defined(CONFIG_ISCSI_DEBUG)	__u32 save_trace;#endif	/* Lock kernel to daemonize thread and update init_rec_thread pointer */	lock_kernel();/* Ming Zhang, mingz@ele.uri.edu */#ifdef K26	daemonize(#else	daemonize();	/* NOTE: in struct task_struct have declaration char comm[16] */	strcpy(current->comm,#endif		"ini_recovery");#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 4, 18)	/*	 * Arne Redlich, agr1@users.sourceforge.net:	 * This prevents the recovery thread from becoming a zombie after exit.	 */	reparent_to_init();#endif	siginitsetinv(&current->blocked, ISCSI_SHUTDOWN_SIGBITS);	/* mark that the recovery thread is alive */	init_rec_thread = current;	unlock_kernel();	err_rec = (struct init_error_rec *)arg;	conn = err_rec->curr_conn;	session = conn->my_session;	printk("%s Starting pid %d conn %p\n", current->comm, current->pid,		conn);	/* turn on some tracing */	TRACE_GET(save_trace);	TRACE_SET(save_trace |(TRACE_ISCSI_FULL|TRACE_ISCSI));	/* Like the rx thread it is replacing,	 * this thread normally holds exclusive access to the iscsi structures.	 */	UNH_LOCK(&session->sess_lock, conn->rx_lock_flags);	target = session->scsi_target_id;	old_ip_address = conn->ip_address;	cid = conn->connection_id;	/* Abort all queued scsi commands with an appropriate	 * scsi service response Section - 6.12.4	 */	if (!(conn->connection_flags & CONN_HIT_EOF)) {		/* the connection is still open, try for a graceful shutdown */		drive_logout(session, conn, LOGOUT_CLOSE_SESSION);		if (conn->rx_buf == NULL) {			TRACE_ERROR("scsi Response Header is NULL\n");			/* release our exclusive access to iscsi structures */			UNH_UNLOCK(&session->sess_lock, conn->rx_lock_flags);			goto rec_thread_out;		}		header = (struct response_pdu *)conn->rx_buf;		size = ntohl(header->length);		if (size > 0) {			/* target response has data attached, toss it */			received = recv_ignore_data(conn, size);		}		while (received > 0) {			if ((received = recv_pdu_header(conn)) <= 0) {				/* connection died or we got a kill signal,				 * stop trying to read more input				 */				break;			}			/* ignore header digests while waiting for logout			 * during recovery			 */			header = (struct response_pdu *)conn->rx_buf;			size = ntohl(header->length);			if (size > MASK_24_BITS) {				/* bigger than 2^24 - 1 */				TRACE_ERROR("TotalAHSLength 0x%02x, "					    "expected 0x00\n", size >> 24);				break;			}			/* mark that we got some activity from the target */			conn->connection_flags |= GOT_ACTIVITY;			/* Print the received iSCSI header */			TRACE_BUFFER(TRACE_BUF, conn->rx_buf,				     ISCSI_HDR_LEN, "%s got message\n",				     current->comm);			if (conn->connection_flags & NEED_TX_WAKEUP) {				/* get the tx thread started again */				TRACE(TRACE_ISCSI_FULL,				      "%s wake up tx_thread\n", current->comm);				up(&conn->tx_sem);			}			if (size > 0) {				/* target response has data attached, toss it */				received = recv_ignore_data(conn, size);			}			if (header->opcode == ISCSI_TARG_LOGOUT_RSP) {				TRACE(TRACE_DEBUG, "Got LogOut Response\n");				break;			}		}	}	/* release exclusive access to iscsi structures if we already have it */	if (received >= 0) {		UNH_UNLOCK(&session->sess_lock, conn->rx_lock_flags);	}	/* remove all the luns in this session, thereby removing the session */	if ((lun = remove_luns(session, global_host, global_hostdata))		< 0) {		lun = 0;	}	/* at this point all structures and threads for original session	 * and all its connections should be gone!	 */	dup_inet_struct(old_ip_address, &new_ip_address, &new_ip_length);	if (create_session(target, new_ip_address, new_ip_length, lun, cid,							global_host) != 1) {		TRACE_ERROR("Unable to create recovery session for target %d "			    "lun %d cid %d\n", target, lun, cid);		goto rec_thread_out;	}	UNH_LOCK(&host_data_lock, flags);	session = find_session_by_id(target, global_hostdata);	if (session == NULL || (conn = session->connection_head) == NULL) {		TRACE_ERROR("Unable to find recovery session for target %d "			    "lun %d cid %d\n", target, lun, cid);		goto rec_thread_out_locked;	}	sess_grp = global_hostdata->sess_rec_head;	for (; sess_grp != NULL; sess_grp = sess_grp->next) {		if (sess_grp->cmnd_list_head) {/* Ming Zhang, mingz@ele.uri.edu */#ifdef K26			if (sess_grp->cmnd_list_head->Cmnd->device->id#else			if (sess_grp->cmnd_list_head->Cmnd->target#endif				== session->scsi_target_id)				break;		}	}	if (sess_grp) {		cmnd = sess_grp->cmnd_list_head;		for (; cmnd != NULL; cmnd = cmnd->next) {			UNH_LOCK(&session->sess_lock, conn->rx_lock_flags);			scsi_to_iscsi(cmnd->Cmnd, session);			UNH_UNLOCK(&session->sess_lock, conn->rx_lock_flags);		}		clean_rec_group(sess_grp);	}rec_thread_out_locked:		UNH_UNLOCK(&host_data_lock, flags);rec_thread_out:	global_hostdata->init_sessrec_flg = 0;	init_rec_thread = NULL;	up(&init_sess_recovery_sem);	TRACE_SET(save_trace);	printk("%s Exiting pid %d\n", current->comm, current->pid);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -