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

📄 iscsi_tcp.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		set_bit(XMSTATE_BIT_CMD_HDR_XMIT, &tcp_ctask->xmstate);	}	if (test_bit(XMSTATE_BIT_CMD_HDR_XMIT, &tcp_ctask->xmstate)) {		rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->imm_count);		if (rc)			return rc;		clear_bit(XMSTATE_BIT_CMD_HDR_XMIT, &tcp_ctask->xmstate);		if (sc->sc_data_direction != DMA_TO_DEVICE)			return 0;		if (ctask->imm_count) {			set_bit(XMSTATE_BIT_IMM_DATA, &tcp_ctask->xmstate);			iscsi_set_padding(tcp_ctask, ctask->imm_count);			if (ctask->conn->datadgst_en) {				iscsi_data_digest_init(ctask->conn->dd_data,						       tcp_ctask);				tcp_ctask->immdigest = 0;			}		}		if (ctask->unsol_count) {			set_bit(XMSTATE_BIT_UNS_HDR, &tcp_ctask->xmstate);			set_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate);		}	}	return rc;}static intiscsi_send_padding(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask){	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;	int sent = 0, rc;	if (test_bit(XMSTATE_BIT_W_PAD, &tcp_ctask->xmstate)) {		iscsi_buf_init_iov(&tcp_ctask->sendbuf, (char*)&tcp_ctask->pad,				   tcp_ctask->pad_count);		if (conn->datadgst_en)			crypto_hash_update(&tcp_conn->tx_hash,					   &tcp_ctask->sendbuf.sg,					   tcp_ctask->sendbuf.sg.length);	} else if (!test_bit(XMSTATE_BIT_W_RESEND_PAD, &tcp_ctask->xmstate))		return 0;	clear_bit(XMSTATE_BIT_W_PAD, &tcp_ctask->xmstate);	clear_bit(XMSTATE_BIT_W_RESEND_PAD, &tcp_ctask->xmstate);	debug_scsi("sending %d pad bytes for itt 0x%x\n",		   tcp_ctask->pad_count, ctask->itt);	rc = iscsi_sendpage(conn, &tcp_ctask->sendbuf, &tcp_ctask->pad_count,			   &sent);	if (rc) {		debug_scsi("padding send failed %d\n", rc);		set_bit(XMSTATE_BIT_W_RESEND_PAD, &tcp_ctask->xmstate);	}	return rc;}static intiscsi_send_digest(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,			struct iscsi_buf *buf, uint32_t *digest){	struct iscsi_tcp_cmd_task *tcp_ctask;	struct iscsi_tcp_conn *tcp_conn;	int rc, sent = 0;	if (!conn->datadgst_en)		return 0;	tcp_ctask = ctask->dd_data;	tcp_conn = conn->dd_data;	if (!test_bit(XMSTATE_BIT_W_RESEND_DATA_DIGEST, &tcp_ctask->xmstate)) {		crypto_hash_final(&tcp_conn->tx_hash, (u8*)digest);		iscsi_buf_init_iov(buf, (char*)digest, 4);	}	clear_bit(XMSTATE_BIT_W_RESEND_DATA_DIGEST, &tcp_ctask->xmstate);	rc = iscsi_sendpage(conn, buf, &tcp_ctask->digest_count, &sent);	if (!rc)		debug_scsi("sent digest 0x%x for itt 0x%x\n", *digest,			  ctask->itt);	else {		debug_scsi("sending digest 0x%x failed for itt 0x%x!\n",			  *digest, ctask->itt);		set_bit(XMSTATE_BIT_W_RESEND_DATA_DIGEST, &tcp_ctask->xmstate);	}	return rc;}static intiscsi_send_data(struct iscsi_cmd_task *ctask, struct iscsi_buf *sendbuf,		struct scatterlist **sg, int *sent, int *count,		struct iscsi_buf *digestbuf, uint32_t *digest){	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;	struct iscsi_conn *conn = ctask->conn;	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;	int rc, buf_sent, offset;	while (*count) {		buf_sent = 0;		offset = sendbuf->sent;		rc = iscsi_sendpage(conn, sendbuf, count, &buf_sent);		*sent = *sent + buf_sent;		if (buf_sent && conn->datadgst_en)			partial_sg_digest_update(&tcp_conn->tx_hash,				&sendbuf->sg, sendbuf->sg.offset + offset,				buf_sent);		if (!iscsi_buf_left(sendbuf) && *sg != tcp_ctask->bad_sg) {			iscsi_buf_init_sg(sendbuf, *sg);			*sg = *sg + 1;		}		if (rc)			return rc;	}	rc = iscsi_send_padding(conn, ctask);	if (rc)		return rc;	return iscsi_send_digest(conn, ctask, digestbuf, digest);}static intiscsi_send_unsol_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask){	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;	struct iscsi_data_task *dtask;	int rc;	set_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate);	if (test_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate)) {		dtask = &tcp_ctask->unsol_dtask;		iscsi_prep_unsolicit_data_pdu(ctask, &dtask->hdr);		iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)&dtask->hdr,				   sizeof(struct iscsi_hdr));		if (conn->hdrdgst_en)			iscsi_hdr_digest(conn, &tcp_ctask->headbuf,					(u8*)dtask->hdrext);		clear_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate);		iscsi_set_padding(tcp_ctask, ctask->data_count);	}	rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->data_count);	if (rc) {		clear_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate);		set_bit(XMSTATE_BIT_UNS_HDR, &tcp_ctask->xmstate);		return rc;	}	if (conn->datadgst_en) {		dtask = &tcp_ctask->unsol_dtask;		iscsi_data_digest_init(ctask->conn->dd_data, tcp_ctask);		dtask->digest = 0;	}	debug_scsi("uns dout [itt 0x%x dlen %d sent %d]\n",		   ctask->itt, ctask->unsol_count, tcp_ctask->sent);	return 0;}static intiscsi_send_unsol_pdu(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask){	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;	int rc;	if (test_and_clear_bit(XMSTATE_BIT_UNS_HDR, &tcp_ctask->xmstate)) {		BUG_ON(!ctask->unsol_count);send_hdr:		rc = iscsi_send_unsol_hdr(conn, ctask);		if (rc)			return rc;	}	if (test_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate)) {		struct iscsi_data_task *dtask = &tcp_ctask->unsol_dtask;		int start = tcp_ctask->sent;		rc = iscsi_send_data(ctask, &tcp_ctask->sendbuf, &tcp_ctask->sg,				     &tcp_ctask->sent, &ctask->data_count,				     &dtask->digestbuf, &dtask->digest);		ctask->unsol_count -= tcp_ctask->sent - start;		if (rc)			return rc;		clear_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate);		/*		 * Done with the Data-Out. Next, check if we need		 * to send another unsolicited Data-Out.		 */		if (ctask->unsol_count) {			debug_scsi("sending more uns\n");			set_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate);			goto send_hdr;		}	}	return 0;}static int iscsi_send_sol_pdu(struct iscsi_conn *conn,			      struct iscsi_cmd_task *ctask){	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;	struct iscsi_session *session = conn->session;	struct iscsi_r2t_info *r2t;	struct iscsi_data_task *dtask;	int left, rc;	if (test_bit(XMSTATE_BIT_SOL_HDR_INIT, &tcp_ctask->xmstate)) {		if (!tcp_ctask->r2t) {			spin_lock_bh(&session->lock);			__kfifo_get(tcp_ctask->r2tqueue, (void*)&tcp_ctask->r2t,				    sizeof(void*));			spin_unlock_bh(&session->lock);		}send_hdr:		r2t = tcp_ctask->r2t;		dtask = &r2t->dtask;		if (conn->hdrdgst_en)			iscsi_hdr_digest(conn, &r2t->headbuf,					(u8*)dtask->hdrext);		clear_bit(XMSTATE_BIT_SOL_HDR_INIT, &tcp_ctask->xmstate);		set_bit(XMSTATE_BIT_SOL_HDR, &tcp_ctask->xmstate);	}	if (test_bit(XMSTATE_BIT_SOL_HDR, &tcp_ctask->xmstate)) {		r2t = tcp_ctask->r2t;		dtask = &r2t->dtask;		rc = iscsi_sendhdr(conn, &r2t->headbuf, r2t->data_count);		if (rc)			return rc;		clear_bit(XMSTATE_BIT_SOL_HDR, &tcp_ctask->xmstate);		set_bit(XMSTATE_BIT_SOL_DATA, &tcp_ctask->xmstate);		if (conn->datadgst_en) {			iscsi_data_digest_init(conn->dd_data, tcp_ctask);			dtask->digest = 0;		}		iscsi_set_padding(tcp_ctask, r2t->data_count);		debug_scsi("sol dout [dsn %d itt 0x%x dlen %d sent %d]\n",			r2t->solicit_datasn - 1, ctask->itt, r2t->data_count,			r2t->sent);	}	if (test_bit(XMSTATE_BIT_SOL_DATA, &tcp_ctask->xmstate)) {		r2t = tcp_ctask->r2t;		dtask = &r2t->dtask;		rc = iscsi_send_data(ctask, &r2t->sendbuf, &r2t->sg,				     &r2t->sent, &r2t->data_count,				     &dtask->digestbuf, &dtask->digest);		if (rc)			return rc;		clear_bit(XMSTATE_BIT_SOL_DATA, &tcp_ctask->xmstate);		/*		 * Done with this Data-Out. Next, check if we have		 * to send another Data-Out for this R2T.		 */		BUG_ON(r2t->data_length - r2t->sent < 0);		left = r2t->data_length - r2t->sent;		if (left) {			iscsi_solicit_data_cont(conn, ctask, r2t, left);			goto send_hdr;		}		/*		 * Done with this R2T. Check if there are more		 * outstanding R2Ts ready to be processed.		 */		spin_lock_bh(&session->lock);		tcp_ctask->r2t = NULL;		__kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,			    sizeof(void*));		if (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t,				sizeof(void*))) {			tcp_ctask->r2t = r2t;			spin_unlock_bh(&session->lock);			goto send_hdr;		}		spin_unlock_bh(&session->lock);	}	return 0;}/** * iscsi_tcp_ctask_xmit - xmit normal PDU task * @conn: iscsi connection * @ctask: iscsi command task * * Notes: *	The function can return -EAGAIN in which case caller must *	call it again later, or recover. '0' return code means successful *	xmit. *	The function is devided to logical helpers (above) for the different *	xmit stages. * *iscsi_send_cmd_hdr() *	XMSTATE_BIT_CMD_HDR_INIT - prepare Header and Data buffers Calculate *	                           Header Digest *	XMSTATE_BIT_CMD_HDR_XMIT - Transmit header in progress * *iscsi_send_padding *	XMSTATE_BIT_W_PAD        - Prepare and send pading *	XMSTATE_BIT_W_RESEND_PAD - retry send pading * *iscsi_send_digest *	XMSTATE_BIT_W_RESEND_DATA_DIGEST - Finalize and send Data Digest *	XMSTATE_BIT_W_RESEND_DATA_DIGEST - retry sending digest * *iscsi_send_unsol_hdr *	XMSTATE_BIT_UNS_INIT     - prepare un-solicit data header and digest *	XMSTATE_BIT_UNS_HDR      - send un-solicit header * *iscsi_send_unsol_pdu *	XMSTATE_BIT_UNS_DATA     - send un-solicit data in progress * *iscsi_send_sol_pdu *	XMSTATE_BIT_SOL_HDR_INIT - solicit data header and digest initialize *	XMSTATE_BIT_SOL_HDR      - send solicit header *	XMSTATE_BIT_SOL_DATA     - send solicit data * *iscsi_tcp_ctask_xmit *	XMSTATE_BIT_IMM_DATA     - xmit managment data (??) **/static intiscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask){	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;	int rc = 0;	debug_scsi("ctask deq [cid %d xmstate %x itt 0x%x]\n",		conn->id, tcp_ctask->xmstate, ctask->itt);	rc = iscsi_send_cmd_hdr(conn, ctask);	if (rc)		return rc;	if (ctask->sc->sc_data_direction != DMA_TO_DEVICE)		return 0;	if (test_bit(XMSTATE_BIT_IMM_DATA, &tcp_ctask->xmstate)) {		rc = iscsi_send_data(ctask, &tcp_ctask->sendbuf, &tcp_ctask->sg,				     &tcp_ctask->sent, &ctask->imm_count,				     &tcp_ctask->immbuf, &tcp_ctask->immdigest);		if (rc)			return rc;		clear_bit(XMSTATE_BIT_IMM_DATA, &tcp_ctask->xmstate);	}	rc = iscsi_send_unsol_pdu(conn, ctask);	if (rc)		return rc;	rc = iscsi_send_sol_pdu(conn, ctask);	if (rc)		return rc;	return rc;}static struct iscsi_cls_conn *iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx){	struct iscsi_conn *conn;	struct iscsi_cls_conn *cls_conn;	struct iscsi_tcp_conn *tcp_conn;	cls_conn = iscsi_conn_setup(cls_session, conn_idx);	if (!cls_conn)		return NULL;	conn = cls_conn->dd_data;	/*	 * due to strange issues with iser these are not set	 * in iscsi_conn_setup	 */	conn->max_recv_dlength = ISCSI_DEF_MAX_RECV_SEG_LEN;	tcp_conn = kzalloc(sizeof(*tcp_conn), GFP_KERNEL);	if (!tcp_conn)		goto tcp_conn_alloc_fail;	conn->dd_data = tcp_conn;	tcp_conn->iscsi_conn = conn;	tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;	/* initial operational parameters */	tcp_conn->hdr_size = sizeof(struct iscsi_hdr);	tcp_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0,						  CRYPTO_ALG_ASYNC);	tcp_conn->tx_hash.flags = 0;	if (IS_ERR(tcp_conn->tx_hash.tfm)) {		printk(KERN_ERR "Could not create connection due to crc32c "		       "loading error %ld. Make sure the crc32c module is "		       "built as a module or into the kernel\n",			PTR_ERR(tcp_conn->tx_hash.tfm));		goto free_tcp_conn;	}	tcp_conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0,						  CRYPTO_ALG_ASYNC);	tcp_conn->rx_hash.flags = 0;	if (IS_ERR(tcp_conn->rx_hash.tfm)) {		printk(KERN_ERR "Could not create connection due to crc32c "		       "loading error %ld. Make sure the crc32c module is "		       "built as a module or into the kernel\n",			PTR_ERR(tcp_conn->rx_hash.tfm));		goto free_tx_tfm;	}	return cls_conn;free_tx_tfm:	crypto_free_hash(tcp_conn->tx_hash.tfm);free_tcp_conn:	kfree(tcp_conn);tcp_conn_alloc_fail:	iscsi_conn_teardown(cls_conn);	return NULL;}static voidiscsi_tcp_release_conn(struct iscsi_conn *conn){	struct iscsi_session *session = conn->session;	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;	struct socket *sock = tcp_conn->sock;	if (!sock)		return;	sock_hold(sock->sk);	iscsi_conn_restore_callbacks(tcp_conn);	sock_put(sock->sk);	spin_lock_bh(&session->lock);	tcp_conn->sock = NULL;	conn->recv_lock = NULL;	spin_unlock_bh(&session->lock);	sockfd_put(sock);}static voidiscsi_tcp_conn_destroy(struct iscsi_cls_conn *cls_conn){	struct iscsi_conn *conn = cls_conn->dd_data;	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;	iscsi_tcp_release_conn(conn);	iscsi_conn_teardown(cls_conn);	if (tcp_conn->tx_hash.tfm)		crypto_free_hash(tcp_conn->tx_hash.tfm);	if (tcp_conn->rx_hash.tfm)

⌨️ 快捷键说明

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