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

📄 iscsi_target.c

📁 iscsi源代码 UNH的progect 有initiator端和target端的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	daemonize();	snprintf(current->comm, sizeof(current->comm),#endif			 "iscsi_tx_%d", conn->conn_id);#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 4, 18)	/*	 * Arne Redlich, agr1@users.sourceforge.net:	 * This prevents the tx_thread from becoming a zombie after it exits.	 */	reparent_to_init();#endif	siginitsetinv(&current->blocked, ISCSI_SHUTDOWN_SIGBITS);	/* mark that this tx thread is alive */	conn->tx_thread = current;	unlock_kernel();	printk("%s Starting pid %d\n", current->comm, current->pid);	if (conn->nop_period) {		/* set up to start the nopin timer first time through the main loop */		set_bit(NEED_NOPIN_BIT, &conn->control);		set_bit(SILENCE_BIT, &conn->control);	}	TRACE_GET(save_mask);	while (1) {		/* block until somebody adds/changes a command for this conn */		if (down_interruptible(&conn->tx_sem))			goto iscsi_tx_thread_out;		/* can't set session sooner because it is not set up in conn until		 * AFTER login is complete on this connection.  But nothing will wake		 * up this tx thread until AFTER that login is complete, so we are safe.		 */		session = conn->session;		TRACE(TRACE_DEBUG, "%s awake, session %p, conn %p\n", current->comm,			  session, conn);		skipover = 0;				/* don't skip anything yet */		TRACE_GET(save_mask);		if (test_and_clear_bit(NEED_NOPIN_BIT, &conn->control)) {			/* bit was set, either first time through			 * or timer expired after an interval of silence from initiator			 */			if (!timer_pending(&conn->nop_timer)) {				/* first time thru here -- timer not going yet, start it up */				restart_nop_timer(conn);			} else {				/* not first time thru here, timer must have expired */				if ((count = atomic_read(&conn->outstanding_nopins))) {					TRACE_ERROR("%s No reply to %u outstanding NopIns\n",								current->comm, count);					if (count >= MAX_OUTSTANDING_NOPINS) {						TRACE_ERROR("%s Max outstanding NopIns exceeded\n",									current->comm);						goto iscsi_tx_thread_out;					}					TRACE_SET(save_mask | TRACE_DEBUG | TRACE_ISCSI							  | TRACE_ISCSI_FULL | TRACE_ENTER_LEAVE);				}				if (generate_nopin(conn, session) < 0)						goto iscsi_tx_thread_out;				atomic_inc(&conn->outstanding_nopins);			}		}restart_after_dequeue:	/* back here after dequeueing a command from the list,						 * at which time skipover will be set so we can skip						 * ahead to our place in the list (which may have been						 * changed by other tx threads while we were busy).						 */		if (!list_empty(&conn->reject_list)) {			/* process connection's queue of pending rejects */			if (dequeue_reject(conn, 1))				goto iscsi_tx_thread_out;		}		/* lock the session-wide list of commands */		if (down_interruptible(&session->cmnd_sem))			goto iscsi_tx_thread_out;		/* look at and count each command belonging to this session */		count = 0;		prev_cmnd = NULL;		cmnd = session->cmnd_list;		while (cmnd != NULL) {			TRACE(TRACE_DEBUG, "%s pick up cmnd %p\n", current->comm, cmnd);			if (cmnd->conn == conn && ++count >= skipover) {			  /* this command is for this connection, handle it */			  if (!(conn->connection_flags & CONN_LOGGED_OUT)) {				TRACE(TRACE_DEBUG, "%s handle cmnd no. %d, ITT %u, "					  "opcode 0x%02x, state %d\n",					  current->comm, count, cmnd->init_task_tag,					  cmnd->opcode_byte, cmnd->state);				TRACE(TRACE_DEBUG, "%s ImmData %u, UnsolData %u, data_len %u, "					  "data_done %u, r2t_data %d\n",					  current->comm,					  cmnd->immediate_data_present,					  cmnd->unsolicited_data_present,					  cmnd->data_length,					  cmnd->data_done,					  cmnd->r2t_data);				switch (cmnd->state) {				case ISCSI_SEND_TEXT_RESPONSE:					{						up(&session->cmnd_sem);						if (handle_discovery_rsp(cmnd, conn, session) < 0) {							TRACE_ERROR("%s Trouble in handle_discovery_rsp\n",										current->comm);							goto iscsi_tx_thread_out;						}						if (down_interruptible(&session->cmnd_sem))							goto iscsi_tx_thread_out;						break;					}				case ISCSI_ASK_FOR_MORE_TEXT:					{						up(&session->cmnd_sem);						if (ask_for_more_text(cmnd, conn, session) < 0) {							TRACE_ERROR("%s Trouble in ask_for_more_text\n",										current->comm);							goto iscsi_tx_thread_out;						}						if (down_interruptible(&session->cmnd_sem))							goto iscsi_tx_thread_out;						break;					}				case ISCSI_LOGOUT:					{						/* take this command out of the session-wide list */						if (prev_cmnd == NULL)							session->cmnd_list = cmnd->next;						else							prev_cmnd->next = cmnd->next;						up(&session->cmnd_sem);						if (handle_logout_rsp(cmnd, conn, session) < 0) {							TRACE_ERROR("%s Trouble in handle_logout_rsp\n",										current->comm);						}						/* always exit the tx thread after a logout response */						iscsi_dequeue(cmnd, conn);						goto iscsi_tx_thread_out;					}				case ISCSI_PING:					{						up(&session->cmnd_sem);						if (handle_nopin(cmnd, conn, session) < 0) {							TRACE_ERROR("%s Trouble in handle_nopin\n",										current->comm);							goto iscsi_tx_thread_out;						}						if (down_interruptible(&session->cmnd_sem))							goto iscsi_tx_thread_out;						break;					}				case ISCSI_DONE:					{						up(&session->cmnd_sem);						if (handle_iscsi_done(cmnd, conn, session) < 0) {							TRACE_ERROR("%s Trouble in handle_iscsi_done\n",										current->comm);							goto iscsi_tx_thread_out;						}						if (down_interruptible(&session->cmnd_sem))							goto iscsi_tx_thread_out;						break;					}				case ISCSI_RESEND_STATUS:					{						up(&session->cmnd_sem);						if (send_iscsi_response(cmnd, conn, session) < 0) {							TRACE_ERROR("%s Trouble in send_iscsi_response\n",										current->comm);							goto iscsi_tx_thread_out;						}						if (down_interruptible(&session->cmnd_sem))							goto iscsi_tx_thread_out;						break;					}				case ISCSI_MGT_FN_DONE:					{						up(&session->cmnd_sem);						if (handle_iscsi_mgt_fn_done(cmnd, conn, session) < 0) {							TRACE_ERROR("%s Trouble in iscsi_mgt_fn_done\n",										current->comm);							goto iscsi_tx_thread_out;						}						if (down_interruptible(&session->cmnd_sem))							goto iscsi_tx_thread_out;						break;					}				case ISCSI_BUFFER_RDY:					{						up(&session->cmnd_sem);						if (iscsi_tx_r2t(cmnd, conn, session) < 0) {							TRACE_ERROR("%s Trouble in iscsi_tx_r2t\n",										current->comm);							goto iscsi_tx_thread_out;						}						if (down_interruptible(&session->cmnd_sem))							goto iscsi_tx_thread_out;						break;					}				case ISCSI_DEQUEUE:					{						TRACE(TRACE_DEBUG, "dequeue command, ITT %u, CmndSN %u,"							  " count %u, skipover %u\n", cmnd->init_task_tag,							  cmnd->cmd_sn, count, skipover);						/* take this command out of the session-wide list */						if (prev_cmnd == NULL)							session->cmnd_list = cmnd->next;						else							prev_cmnd->next = cmnd->next;						up(&session->cmnd_sem);						iscsi_dequeue(cmnd, conn);						skipover = count;						goto restart_after_dequeue;					}				case ISCSI_QUEUE_CMND_RDY:					{						if (send_unsolicited_data(cmnd, conn, session) < 0) {							TRACE_ERROR("%s Trouble in send_unsolicited_data\n",										current->comm);							up(&session->cmnd_sem);							goto iscsi_tx_thread_out;						}						break;					}				case ISCSI_QUEUE_CMND:				case ISCSI_QUEUE_OTHER:				case ISCSI_CMND_RECEIVED:				case ISCSI_NEW_CMND:				case ISCSI_SENT:				case ISCSI_NOPIN_SENT:				case ISCSI_ALL_R2TS_SENT:				case ISCSI_IMMEDIATE_DATA_IN:				case ISCSI_UNSOLICITED_DATA_IN:				case ISCSI_DATA_IN:				case ISCSI_BLOCKED_SENDING_TEXT:				case ISCSI_AWAIT_MORE_TEXT:					{						/* Not much to do */						break;					}				default:		/* NEVER HERE */					{						up(&session->cmnd_sem);						TRACE_ERROR("%s Unknown command state %u\n",									current->comm, cmnd->state);						goto iscsi_tx_thread_out;					}				} /* switch */			  }			} /* if */			prev_cmnd = cmnd;			cmnd = cmnd->next;		} /* while */		/* unlock the session-wide list of commands */		up(&session->cmnd_sem);		TRACE(TRACE_DEBUG, "%s handled %d commands\n", current->comm, count);		TRACE_SET(save_mask);		/*		 * Moved check to see if connection is active here so that the		 * tx_thread can transmit one last packet, i.e., the logout response		 */		if (!conn->active)			goto iscsi_tx_thread_out;	} /* while */iscsi_tx_thread_out:	TRACE_SET(save_mask);	conn->active = 0;	conn->tx_thread = NULL;	del_timer_sync(&conn->nop_timer);	if (conn->rx_thread) {		/* rx thread still going, shut it down */		send_sig(ISCSI_SHUTDOWN_SIGNAL, conn->rx_thread, 1);	} else {		/* rx thread has shut down, if socket is still open, release it */		iscsi_release_socket(conn);	}	up(&conn->kill_tx_sem);	printk("%s Exiting pid %d\n", current->comm, current->pid);	return 0;}/* called after reading unsolicited data attached to a WRITE SCSI command pdu, * or solicited data attached to a DataOut pdu. */static void __attribute__ ((no_instrument_function))update_after_read(struct generic_pdu *hdr, struct iscsi_cmnd *cmnd){	cmnd->data_done += hdr->length;	cmnd->immediate_data_present = 0;	if (hdr->flags & F_BIT) {		/* end of this (solicited or unsolicited) sequence,		 * reset the counters for the next solicited burst (if any)		 */		cmnd->data_sn = 0;		cmnd->unsolicited_data_present = 0;	}}/* * iscsi_rx_data: will receive a fixed amount of data. * INPUT: struct iscsi_conn (what connection), struct iovec, number of iovecs, * total amount of data in bytes * OUTPUT: > 0 total bytes read if everything is okay * 	       < 0 if trouble (-ECONNRESET means end-of-file) *		   = 0 for PAYLOAD_DIGERR */intiscsi_rx_data(struct iscsi_conn *conn, struct iovec *iov, int niov, int data){	struct msghdr msg;	int msg_iovlen;	int rx_loop, total_rx;	__u32 checksum, data_crc;	int i;	struct iovec *iov_copy, *iov_ptr;	mm_segment_t oldfs;	total_rx = 0;	TRACE(TRACE_ENTER_LEAVE, "Enter iscsi_rx_data, niov %d, data %d\n",		  niov, data);	if (!conn->conn_socket) {		TRACE_ERROR("%s Transport endpoint is not connected\n", current->comm);		total_rx = -ENOTCONN;		/* Transport endpoint is not connected */		goto out;	}	iov_copy =		(struct iovec *)my_kmalloc(niov * sizeof(struct iovec), "iovec");	if (iov_copy == NULL) {		total_rx = -ENOMEM;		goto out;	}	while (total_rx < data) {		/* get a clean copy of the original io vector to work with */		memcpy(iov_copy, iov, niov * sizeof(struct iovec));		msg_iovlen = niov;		iov_ptr = iov_copy;		if ((rx_loop = total_rx)) {			/* have done only partial read, recalculate iov and niov -- cdeng */			TRACE(TRACE_ISCSI,				  "iscsi_rx_data: data %d, received so far %d, recompute iov\n",				  data, total_rx);			do {				if (iov_ptr->iov_len <= rx_loop) {					rx_loop -= iov_ptr->iov_len;					iov_ptr++;					msg_iovlen--;				} else {					iov_ptr->iov_base += rx_loop;					iov_ptr->iov_len -= rx_loop;					rx_loop = 0;				}			} while (rx_loop);		}		memset(&msg, 0, sizeof(struct msghdr));		msg.msg_iovlen = msg_iovlen;		msg.msg_iov = iov_ptr;		oldfs = get_fs();		set_fs(get_ds());		rx_loop = sock_recvmsg(conn->conn_socket, &msg, (data - total_rx),							   MSG_WAITALL);		set_fs(oldfs);		/* this receive from initiator broke the silence */		clear_bit(SILENCE_BIT, &conn->control);		if (rx_loop <= 0) {			my_kfree((void **)&iov_copy, "iovec");			total_rx = -ECONNRESET;		/* Connection reset by peer */			goto out;		}		total_rx += rx_loop;		TRACE(TRACE_DEBUG, "iscsi_rx_data: rx_loop %d total_rx %d\n", rx_loop,			  total_rx);	}	my_kfree((void**)&iov_copy, "iovec");	if (niov > 1 && conn->data_crc) {		/* this really is for a data segment, and data digests are in effect */		data_crc = 0;		for (i = 0; i < niov - 1; i++)			do_crc(iov[i].iov_base, iov[i].iov_len, &data_crc);		checksum = *(__u32 *) (iov[niov - 1].iov_base);		if (checksum != data_crc) {			TRACE_ERROR("%s Got data crc 0x%08x, expected 0x%08x\n",						current->comm, ntohl(checksum), ntohl(data_crc));			/* Data Digest Error Recovery - SAI */			total_rx = PAYLOAD_DIGERR;			goto out;		} else {			TRACE(TRACE_ISCSI_FULL, "Got data crc 0x%08x\n", ntohl(checksum));		}	}out:	TRACE(TRACE_ENTER_LEAVE, "Leave iscsi_rx_data, total_rx %d\n", total_rx);	return total_rx;}/* read data segment from cmd's connection into a single buffer  * that is newly allocated to hold bufsize bytes of data * returns > 0 total number of bytes read (including pad & crc) if all ok, *		   = 0 if recovered from payload digest error ok *		   < 0 error * if ok, sets result to newly allocated buffer, else leaves result unchanged */static intread_single_data_seg(__u8 *buffer, struct iscsi_cmnd *cmd,					 int bufsize, char **result){	struct iovec iov[3];	int size, niov = 1, padding, err;	__u32 digest, pad_bytes;	char *data_buf;	struct targ_error_rec err_rec;	size = bufsize;	padding = (-size) & 3;	if (padding) {		iov[niov].iov_base = &pad_bytes;		iov[niov].iov_len = padding;		size += padding;		niov++;	}	if (cmd->conn->data_crc) {		iov[niov].iov_base = &digest;		iov[niov].iov_len = CRC_LEN;		size += CRC_LEN;		niov++;	}	if ((data_buf = (char *)my_kmalloc(bufsize, "data_buf"))) {		iov[0].iov_base = data_buf;		iov[0].iov_len = bufsize;		err = iscsi_rx_data(cmd->conn, iov, niov, size);		if (err != size) {			/* Payload Digest Error Recovery - SAI */			if (err == PAYLOAD_DIGERR) {

⌨️ 快捷键说明

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