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

📄 target_error_rec.c

📁 iscsi源代码 UNH的progect 有initiator端和target端的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*	target/target_error_rec.c     vi: set autoindent tabstop=4 shiftwidth=4 :*//*	Copyright (C) 2001-2003 InterOperability Lab (IOL)	University of New Hampshier (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 of IOL and/or UNH may not be used to endorse or promote products	derived from this software without specific prior written permission.*/#include "iscsi_target.h"#include "target_error_rec.h"static struct semaphore targ_sess_recovery_sem;/************************************************************************ *  The Main Error Recovery Handler Called from iscsi_initiator when it * *  finds any error.                                                    * *  Returns 0 if recovery completed ok, -1 otherwise                    * ************************************************************************/inttarg_do_error_recovery(struct targ_error_rec *err_rec){	int retval = 0;	struct iscsi_conn *curr_conn;	TRACE(TRACE_ENTER_LEAVE, "Entering targ_do_error_recovery\n");	if (err_rec == NULL) {		TRACE_ERROR("%s Error Recovery structure is NULL\n",					current->comm);		retval = -1;		goto out;	}	if (err_rec->curr_conn == NULL) {		TRACE_ERROR("%s NULL Connection Pointer in Error Recovery structure\n",					current->comm);		retval = -1;		goto out;	}	curr_conn = err_rec->curr_conn;	switch (curr_conn->session->oper_param->ErrorRecoveryLevel) {	case SESSION_RECOVERY:		targ_session_recovery(curr_conn);		break;	case DIGEST_RECOVERY:		retval = targ_digest_recovery(err_rec);		break;	case CONNECTION_RECOVERY:		TRACE_ERROR("%s ErrorRecoveryLevel %u Not Implemented yet\n",					current->comm, CONNECTION_RECOVERY);		retval = -1;		break;	}out:	TRACE(TRACE_ENTER_LEAVE, "Leaving targ_do_error_recovery, retval %d\n",		retval);	return retval;}/************************************************************************* This function handles the session recovery. It creates a recovery     ** thread that will do session recovery.                                 *************************************************************************/voidtarg_session_recovery(struct iscsi_conn *current_connection){	TRACE(TRACE_ENTER_LEAVE, "Enter targ_session_recovery\n");	TRACE(TRACE_ISCSI,		  "Executing Target Session Recovery - cancelling Receive Thread\n");	init_MUTEX_LOCKED(&targ_sess_recovery_sem);	/* Create a recovery thread */	if (kernel_thread(targ_recovery_thread,(void *)current_connection,0) < 0) {		TRACE_ERROR("%s Unable to start targ_recovery_thread\n", current->comm);	} else {		/* Wait till the recovery thread completes processing */		down_interruptible(&targ_sess_recovery_sem);	}	TRACE(TRACE_ENTER_LEAVE, "Leave targ_session_recovery\n");	return;}/************************************************************************* This thread handles the session recovery. Session Recovery will       ** abort all pending tasks and closes all transport connection           ** Section (6.12.4)                                                      *************************************************************************/inttarg_recovery_thread(void *arg){	struct iscsi_conn *conn;	struct iscsi_session *sess;	struct iscsi_global *host;	conn = (struct iscsi_conn *)arg;	sess = conn->session;	host = sess->devdata;	lock_kernel();/* Ming Zhang, mingz@ele.uri.edu */#ifdef K26	daemonize(#else	daemonize();	snprintf(current->comm, sizeof(current->comm),#endif			 "iscsi_reco_%d", host->ntsih);#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 4, 18)	/*	 * Arne Redlich, agr1@users.sourceforge.net:	 * This prevents the retran thread from becoming a zombie after it exits	 */	reparent_to_init();#endif	siginitsetinv(&current->blocked, ISCSI_SHUTDOWN_SIGBITS);	unlock_kernel();	printk("%s Starting pid %d\n", current->comm, current->pid);	if (!down_interruptible(&host->session_sem)) {		iscsi_release_session(sess);		up(&host->session_sem);	}	up(&targ_sess_recovery_sem);	printk("%s Exiting pid %d\n", current->comm, current->pid);	return 0;}/************************************************************************ * This function handles the digest errors and sequence errors that may * * have caused because of previous digest errors.                       * * Returns 0 if recovery is completed correctly, -1 otherwise           * ************************************************************************/inttarg_digest_recovery(struct targ_error_rec *err_rec){	int retval = 0, data_length = 0;	int size = 0, err_type = 0, data_offset = 0;	unsigned int opcode = 0;	struct iscsi_conn *curr_conn;	struct iscsi_init_scsi_data_out *data_out_hdr;	struct iscsi_cmnd *cmd;	curr_conn = err_rec->curr_conn;	err_type = err_rec->err_type;	cmd = err_rec->cmd;	TRACE(TRACE_ENTER_LEAVE, "Entering targ_digest_recovery\n");	if (err_rec->pdu_hdr == NULL) {		TRACE_ERROR("%s iscsi NULL PDU Header\n", current->comm);		retval = -1;		goto digest_out;	} else {		opcode = err_rec->pdu_hdr->opcode;		size = err_rec->pdu_hdr->length;		if (size > MASK_24_BITS) {			TRACE_ERROR("%s TotalAHSLength 0x%02x, expected 0x00\n",						current->comm, size >> 24);			retval = -1;			goto digest_out;		}	}	if (err_type == HEADER_DIGERR) {		if (size > 0) {			retval = targ_drop_pdu_data(curr_conn, size);		}		goto digest_out;	}	if (opcode == ISCSI_INIT_SCSI_DATA_OUT) {		if (cmd == NULL) {			retval = -1;			goto digest_out;		}		if (err_type == PAYLOAD_DIGERR) {			enqueue_reject(curr_conn, REASON_DATA_DIGEST_ERR);			retval = send_recovery_r2t(cmd, cmd->data_done, NULL,						   err_rec->pdu_hdr);		} else if (err_type == SEQUENCE_ERR) {			/* error recovery ver ref18_04 - SAI */			/* if there is a sequence error and the arrived data 			 * seq. indicates lost packets, queue the received 			 * packets and request re-transmission of lost packets 			 */			queue_data(err_rec);			data_length = cmd->data_length - cmd->data_done;			data_offset = cmd->data_length - data_length;			data_out_hdr = (struct iscsi_init_scsi_data_out *) err_rec->pdu_hdr;			size = (data_out_hdr->offset - data_offset);			retval = send_recovery_r2t(cmd, data_offset, NULL,						   err_rec->pdu_hdr);			//up(&curr_conn->tx_sem);		} else {			TRACE_ERROR("%s Unknown err_type %d for DataOut recovery\n",						current->comm, err_type);			retval = -1;		}	} else if (opcode == ISCSI_INIT_SCSI_CMND) {		if (err_type == PAYLOAD_DIGERR) {			/* digest error in immediate data attached to write */			enqueue_reject(curr_conn, REASON_DATA_DIGEST_ERR);		} else {			TRACE_ERROR("%s Unknown err_type %d for SCSI_CMND recovery\n",						current->comm, err_type);			retval = -1;		}	} else {		TRACE_ERROR("%s Unknown err_type %d for recovery\n", current->comm,					err_type);		retval = -1;	}digest_out:	TRACE(TRACE_ENTER_LEAVE, "Leaving targ_digest_recovery, retval %d\n",		retval);	return retval;}/******************************************************************* * Reads the data portion of the dropped PDU due to digest errors. * * The data read is also ignored.                                  *********************************************************************/inttarg_drop_pdu_data(struct iscsi_conn *curr_conn, int size){	int padding = 0, retval = 0, data_length = 0;	int total_rx = 0, rx_loop = 0;	char *buffer = NULL;	struct msghdr msg;	struct iovec iov;	mm_segment_t oldfs;	TRACE(TRACE_ENTER_LEAVE, "Entering targ_drop_pdu_data\n");	padding = -(size) & 3;	size += padding;	if (curr_conn->data_crc == 1) {		size += CRC_LEN;	}	TRACE(TRACE_DEBUG, "targ_drop_pdu: data_read %d total_data %d\n",		  data_length, size);	data_length = size;	while (data_length > 0) {		if (data_length > MAX_MALLOC_SIZE)			data_length = MAX_MALLOC_SIZE;		buffer = kmalloc(data_length * sizeof(char), GFP_KERNEL);		if (!buffer) {			TRACE_ERROR("%s Malloc Error: Unable to drop the data PDU\n",						current->comm);			retval = -ENOMEM;			goto end_drop_pdu;		}		for (total_rx = 0; total_rx < data_length;) {			memset(&msg, 0, sizeof(struct msghdr));			msg.msg_iovlen = 1;			msg.msg_iov = &iov;			iov.iov_len = data_length - total_rx;			iov.iov_base = buffer + total_rx;			oldfs = get_fs();			set_fs(get_ds());			rx_loop = sock_recvmsg(curr_conn->conn_socket, &msg,								   (data_length - total_rx), MSG_WAITALL);			set_fs(oldfs);			if (rx_loop <= 0) {				TRACE_ERROR("%s targ_drop_pdu: rx_loop %d total_rx %d\n",							current->comm, rx_loop, total_rx);				retval = -ECONNRESET;	/* Connection reset by peer */				kfree(buffer);				goto end_drop_pdu;			}			total_rx += rx_loop;			TRACE(TRACE_DEBUG, "targ_drop_pdu: rx_loop %d total_rx %d\n",				  rx_loop, total_rx);		}		size -= data_length;		data_length = size;		TRACE(TRACE_DEBUG,"targ_drop_pdu: data_read %d total_data %d\n",			  data_length, size);		kfree(buffer);	}end_drop_pdu:	TRACE(TRACE_ENTER_LEAVE, "Leaving targ_drop_pdu_data\n");	return retval;}void deal_with_r2t_timer(unsigned long data);/********************************************************************* * (re)start R2T Timer is used for tracking the R2T sent. This timer * helps re-transmit the most recent R2T sent to the initiator. ********************************************************************//* (re)start the R2T retransmit timer */voidrestart_r2t_timer(struct iscsi_session *session){	__u32 period = session->r2t_period;	TRACE(TRACE_TIMERS, "Enter restart_r2t_timer period %u\n", period);	if (period && session->r2t_timer && !timer_pending(session->r2t_timer)){		TRACE(TRACE_TIMERS, "Start r2t timer for %u ticks\n", period);		      session->r2t_timer->expires = jiffies + period;		      session->r2t_timer->data = (unsigned long) session;		      session->r2t_timer->function = deal_with_r2t_timer;		      add_timer(session->r2t_timer);	} else {		TRACE_ERROR("%s R2T timer not started for %u ticks\n", current->comm,					period);	}	TRACE(TRACE_TIMERS, "Leave restart_r2t_timer\n");}/********************************************************************** Called by kernel when R2T periodic session timer expires.*********************************************************************/voiddeal_with_r2t_timer(unsigned long data){	struct iscsi_session *session;	struct iscsi_cmnd *cmnd = NULL;	TRACE(TRACE_TIMERS, "Enter deal_with_r2t_timer\n");	session = (struct iscsi_session *) data;	for (cmnd = session->cmnd_list; cmnd != NULL; cmnd = cmnd->next) {		if (cmnd->outstanding_r2t > 0 &&			(jiffies > (cmnd->timestamp + session->r2t_period))) {			up(&session->retran_sem);			break;		}	}	restart_r2t_timer(session);	TRACE(TRACE_TIMERS, "Leave deal_with_r2t_timer\n");}

⌨️ 快捷键说明

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