[Stgt-devel] [PATCH] head and data digest

FUJITA Tomonori fujita.tomonori
Sun Apr 22 16:16:42 CEST 2007


This patch adds head and data digest features (not heavily
tested). It's against the latest git tree.

Please test this and let me know the results.

Do we provide all features of iscsitarget?

diff --git a/usr/iscsi/conn.c b/usr/iscsi/conn.c
index e4e36aa..fcd2385 100644
--- a/usr/iscsi/conn.c
+++ b/usr/iscsi/conn.c
@@ -176,18 +176,3 @@ int conn_take_fd(struct iscsi_connection
 
 	return 0;
 }
-
-void conn_read_pdu(struct iscsi_connection *conn)
-{
-	conn->rx_iostate = IOSTATE_READ_BHS;
-	conn->rx_buffer = (void *)&conn->req.bhs;
-	conn->rx_size = BHS_SIZE;
-}
-
-void conn_write_pdu(struct iscsi_connection *conn)
-{
-	conn->tx_iostate = IOSTATE_WRITE_BHS;
-	memset(&conn->rsp, 0, sizeof(conn->rsp));
-	conn->tx_buffer = (void *)&conn->rsp.bhs;
-	conn->tx_size = BHS_SIZE;
-}
diff --git a/usr/iscsi/iscsid.c b/usr/iscsi/iscsid.c
index 2377952..fbde08c 100644
--- a/usr/iscsi/iscsid.c
+++ b/usr/iscsi/iscsid.c
@@ -38,9 +38,53 @@ #include "iscsid.h"
 #include "tgtd.h"
 #include "util.h"
 #include "driver.h"
+#include "crc32c.h"
 
 #define MAX_QUEUE_CMD	32
 
+enum {
+	IOSTATE_FREE,
+
+	IOSTATE_RX_BHS,
+	IOSTATE_RX_INIT_AHS,
+	IOSTATE_RX_AHS,
+	IOSTATE_RX_INIT_HDIGEST,
+	IOSTATE_RX_HDIGEST,
+	IOSTATE_RX_CHECK_HDIGEST,
+	IOSTATE_RX_INIT_DATA,
+	IOSTATE_RX_DATA,
+	IOSTATE_RX_INIT_DDIGEST,
+	IOSTATE_RX_DDIGEST,
+	IOSTATE_RX_CHECK_DDIGEST,
+	IOSTATE_RX_END,
+
+	IOSTATE_TX_BHS,
+	IOSTATE_TX_INIT_AHS,
+	IOSTATE_TX_AHS,
+	IOSTATE_TX_INIT_HDIGEST,
+	IOSTATE_TX_HDIGEST,
+	IOSTATE_TX_INIT_DATA,
+	IOSTATE_TX_DATA,
+	IOSTATE_TX_INIT_DDIGEST,
+	IOSTATE_TX_DDIGEST,
+	IOSTATE_TX_END,
+};
+
+void conn_read_pdu(struct iscsi_connection *conn)
+{
+	conn->rx_iostate = IOSTATE_RX_BHS;
+	conn->rx_buffer = (void *)&conn->req.bhs;
+	conn->rx_size = BHS_SIZE;
+}
+
+static void conn_write_pdu(struct iscsi_connection *conn)
+{
+	conn->tx_iostate = IOSTATE_TX_BHS;
+	memset(&conn->rsp, 0, sizeof(conn->rsp));
+	conn->tx_buffer = (void *)&conn->rsp.bhs;
+	conn->tx_size = BHS_SIZE;
+}
+
 static struct iscsi_key login_keys[] = {
 	{"InitiatorName",},
 	{"InitiatorAlias",},
@@ -1492,6 +1536,11 @@ static int iscsi_task_rx_start(struct is
 		break;
 	}
 
+	if (conn->rx_task) {
+		conn->req.ahs = conn->rx_task->ahs;
+		conn->req.data = conn->rx_task->data;
+	}
+
 	return err;
 }
 
@@ -1662,167 +1711,314 @@ nodata:
 	return -EAGAIN;
 }
 
+static int do_recv(int fd, struct iscsi_connection *conn, int next_state)
+{
+	int ret;
+
+	ret = conn->tp->ep_read(fd, conn->rx_buffer, conn->rx_size);
+	if (!ret) {
+		conn->state = STATE_CLOSE;
+		return 0;
+	} else if (ret < 0) {
+		if (errno == EINTR || errno == EAGAIN)
+			return 0;
+		else
+			return -EIO;
+	}
+
+	conn->rx_size -= ret;
+	conn->rx_buffer += ret;
+	if (!conn->rx_size)
+		conn->rx_iostate = next_state;
+
+	return ret;
+}
+
 static void iscsi_rx_handler(int fd, struct iscsi_connection *conn)
 {
-	int res;
+	int ret = 0, hdigest, ddigest;
+	uint32_t crc;
 
+	if (conn->state == STATE_SCSI) {
+		struct param *p = conn->session_param;
+		hdigest = p[ISCSI_PARAM_HDRDGST_EN].val & DIGEST_CRC32C;
+		ddigest = p[ISCSI_PARAM_DATADGST_EN].val & DIGEST_CRC32C;
+	} else
+		hdigest = ddigest = 0;
+again:
 	switch (conn->rx_iostate) {
-	case IOSTATE_READ_BHS:
-	case IOSTATE_READ_AHS_DATA:
-	read_again:
-		res = conn->tp->ep_read(fd, conn->rx_buffer, conn->rx_size);
-		if (!res) {
-			conn->state = STATE_CLOSE;
+	case IOSTATE_RX_BHS:
+		ret = do_recv(fd, conn, IOSTATE_RX_INIT_AHS);
+		if (ret <= 0 || conn->rx_iostate != IOSTATE_RX_INIT_AHS)
 			break;
-		} else if (res < 0) {
-			if (errno == EINTR)
-				goto read_again;
-			else if (errno == EAGAIN)
-				break;
-			else {
+	case IOSTATE_RX_INIT_AHS:
+		if (conn->state == STATE_SCSI) {
+			ret = iscsi_task_rx_start(conn);
+			if (ret) {
 				conn->state = STATE_CLOSE;
-				dprintf("%d %d, %m\n", res, errno);
+				break;
 			}
+		} else {
+			conn->rx_buffer = conn->req_buffer;
+			conn->req.ahs = conn->rx_buffer;
+			conn->req.data = conn->rx_buffer + conn->rx_size;
+		}
+		conn->req.ahssize = conn->req.bhs.hlength * 4;
+		conn->req.datasize = ntoh24(conn->req.bhs.dlength);
+		conn->rx_size = roundup(conn->req.ahssize, 4);
+		if (conn->rx_size) {
+			ret = do_recv(fd, conn, IOSTATE_RX_AHS);
+			if (ret <= 0)
+				break;
+		} else
+			conn->rx_iostate = hdigest ?
+				IOSTATE_RX_INIT_HDIGEST : IOSTATE_RX_INIT_DATA;
+
+		if (conn->rx_iostate == IOSTATE_RX_INIT_DATA)
+			goto again;
+		else if (conn->rx_iostate != IOSTATE_RX_AHS)
+			break;
+	case IOSTATE_RX_AHS:
+		ret = do_recv(fd, conn, hdigest ?
+			      IOSTATE_RX_INIT_HDIGEST : IOSTATE_RX_INIT_DATA);
+		if (ret <= 0 || conn->rx_iostate != IOSTATE_RX_INIT_HDIGEST)
 			break;
+	case IOSTATE_RX_INIT_HDIGEST:
+		conn->rx_buffer = conn->rx_digest;
+		conn->rx_size = sizeof(conn->rx_digest);
+		conn->rx_iostate = IOSTATE_RX_HDIGEST;
+	case IOSTATE_RX_HDIGEST:
+		ret = do_recv(fd, conn, IOSTATE_RX_CHECK_HDIGEST);
+		if (ret <= 0 || conn->rx_iostate != IOSTATE_RX_CHECK_HDIGEST)
+			break;
+	case IOSTATE_RX_CHECK_HDIGEST:
+		crc = ~0;
+		crc = crc32c(crc, &conn->req.bhs, BHS_SIZE);
+		if (conn->req.ahssize)
+			crc = crc32c(crc, conn->req.ahs,
+				     roundup(conn->req.ahssize, 4));
+		crc = ~__cpu_to_le32(crc);
+		if (*((uint32_t *)conn->rx_digest) != crc) {
+			eprintf("rx hdr digest error 0x%x calc 0x%x\n",
+				*((uint32_t *)conn->rx_digest), crc);
+			conn->state = STATE_CLOSE;
 		}
-		conn->rx_size -= res;
-		conn->rx_buffer += res;
-		if (conn->rx_size)
+		conn->rx_iostate = IOSTATE_RX_INIT_DATA;
+	case IOSTATE_RX_INIT_DATA:
+		conn->rx_size = roundup(conn->req.datasize, 4);
+		if (conn->rx_size) {
+			conn->rx_iostate = IOSTATE_RX_DATA;
+			conn->rx_buffer = conn->req.data;
+		} else {
+			conn->rx_iostate = IOSTATE_RX_END;
 			break;
+		}
+	case IOSTATE_RX_DATA:
+		ret = do_recv(fd, conn, ddigest ?
+			      IOSTATE_RX_INIT_DDIGEST : IOSTATE_RX_END);
+		if (ret <= 0 || conn->rx_iostate != IOSTATE_RX_INIT_DDIGEST)
+			break;
+	case IOSTATE_RX_INIT_DDIGEST:
+		conn->rx_buffer = conn->rx_digest;
+		conn->rx_size = sizeof(conn->rx_digest);
+		conn->rx_iostate = IOSTATE_RX_DDIGEST;
+	case IOSTATE_RX_DDIGEST:
+		ret = do_recv(fd, conn, IOSTATE_RX_CHECK_DDIGEST);
+		if (ret <= 0 || conn->rx_iostate != IOSTATE_RX_CHECK_DDIGEST)
+			break;
+	case IOSTATE_RX_CHECK_DDIGEST:
+		crc = ~0;
+		crc = crc32c(crc, conn->req.data, roundup(conn->req.datasize, 4));
+		crc = ~__cpu_to_le32(crc);
+		conn->rx_iostate = IOSTATE_RX_END;
+		if (*((uint32_t *)conn->rx_digest) != crc) {
+			eprintf("rx hdr digest error 0x%x calc 0x%x\n",
+				*((uint32_t *)conn->rx_digest), crc);
+			conn->state = STATE_CLOSE;
+		}
+		break;
+	default:
+		eprintf("error %d %d\n", conn->state, conn->rx_iostate);
+		exit(1);
+	}
 
-		switch (conn->rx_iostate) {
-		case IOSTATE_READ_BHS:
-			conn->req.ahssize = conn->req.bhs.hlength * 4;
-			conn->req.datasize = ntoh24(conn->req.bhs.dlength);
+	if (ret < 0 ||
+	    conn->rx_iostate != IOSTATE_RX_END ||
+	    conn->state == STATE_CLOSE)
+		return;
 
-			if (conn->state == STATE_SCSI) {
-				res = iscsi_task_rx_start(conn);
-				if (res) {
-					conn->state = STATE_CLOSE;
-					break;
-				}
-			} else {
-				conn->rx_buffer = conn->req_buffer;
-				conn->req.ahs = conn->rx_buffer;
-				conn->rx_size = roundup(conn->req.ahssize, 4);
-				conn->req.data = conn->rx_buffer + conn->rx_size;
-				conn->rx_size += roundup(conn->req.datasize, 4);
-			}
+	if (conn->rx_size) {
+		eprintf("error %d %d %d\n", conn->state, conn->rx_iostate,
+			conn->rx_size);
+		exit(1);
+	}
 
-			if (conn->rx_size) {
-				conn->rx_iostate = IOSTATE_READ_AHS_DATA;
-				goto read_again;
-			}
+	if (conn->state == STATE_SCSI) {
+		ret = iscsi_task_rx_done(conn);
+		if (ret)
+			conn->state = STATE_CLOSE;
+		else
+			conn_read_pdu(conn);
+	} else {
+		conn_write_pdu(conn);
+		tgt_event_modify(fd, EPOLLOUT);
+		ret = cmnd_execute(conn);
+		if (ret)
+			conn->state = STATE_CLOSE;
+	}
+}
 
-		case IOSTATE_READ_AHS_DATA:
-			if (conn->state == STATE_SCSI) {
-				res = iscsi_task_rx_done(conn);
-				if (!res)
-					conn_read_pdu(conn);
-			} else {
-				conn_write_pdu(conn);
-				tgt_event_modify(fd, EPOLLOUT);
-				res = cmnd_execute(conn);
-			}
+static int do_send(int fd, struct iscsi_connection *conn, int next_state)
+{
+	int ret;
+again:
+	ret = conn->tp->ep_write_begin(fd, conn->tx_buffer, conn->tx_size);
+	if (ret < 0) {
+		if (errno != EINTR && errno != EAGAIN)
+			conn->state = STATE_CLOSE;
+		else if (errno == EINTR || errno == EAGAIN)
+			goto again;
 
-			if (res)
-				conn->state = STATE_CLOSE;
-			break;
-		}
-		break;
+		return -EIO;
 	}
+
+	conn->tx_size -= ret;
+	conn->tx_buffer += ret;
+	if (conn->tx_size)
+		goto again;
+	conn->tx_iostate = next_state;
+
+	return 0;
 }
 
 static void iscsi_tx_handler(int fd, struct iscsi_connection *conn)
 {
-	int res;
+	int ret = 0, hdigest, ddigest;
+	uint32_t crc;
+
+	if (conn->state == STATE_SCSI) {
+		struct param *p = conn->session_param;
+		hdigest = p[ISCSI_PARAM_HDRDGST_EN].val & DIGEST_CRC32C;
+		ddigest = p[ISCSI_PARAM_DATADGST_EN].val & DIGEST_CRC32C;
+	} else
+		hdigest = ddigest = 0;
 
 	if (conn->state == STATE_SCSI && !conn->tx_task) {
-		res = iscsi_task_tx_start(conn);
-		if (res)
+		ret = iscsi_task_tx_start(conn);
+		if (ret)
 			return;
 	}
 
 	switch (conn->tx_iostate) {
-	case IOSTATE_WRITE_BHS:
-	case IOSTATE_WRITE_AHS:
-	case IOSTATE_WRITE_DATA:
-	write_again:
-		res = conn->tp->ep_write_begin(fd, conn->tx_buffer,
-					       conn->tx_size);
-		if (res < 0) {
-			if (errno != EINTR && errno != EAGAIN)
-				conn->state = STATE_CLOSE;
-			else if (errno == EINTR)
-				goto write_again;
+	case IOSTATE_TX_BHS:
+		ret = do_send(fd, conn, IOSTATE_TX_INIT_AHS);
+		if (ret < 0)
 			break;
-		}
+	case IOSTATE_TX_INIT_AHS:
+		if (conn->rsp.ahssize) {
+			conn->tx_iostate = IOSTATE_TX_AHS;
+			conn->tx_buffer = conn->rsp.ahs;
+			conn->tx_size = conn->rsp.ahssize;
 
-		conn->tx_size -= res;
-		conn->tx_buffer += res;
-		if (conn->tx_size)
-			goto write_again;
-
-		switch (conn->tx_iostate) {
-		case IOSTATE_WRITE_BHS:
-			if (conn->rsp.ahssize) {
-				conn->tx_iostate = IOSTATE_WRITE_AHS;
-				conn->tx_buffer = conn->rsp.ahs;
-				conn->tx_size = conn->rsp.ahssize;
-				goto write_again;
-			}
-		case IOSTATE_WRITE_AHS:
-			if (conn->rsp.datasize) {
-				int pad;
-
-				conn->tx_iostate = IOSTATE_WRITE_DATA;
-				conn->tx_buffer = conn->rsp.data;
-				conn->tx_size = conn->rsp.datasize;
-				pad = conn->tx_size & (PAD_WORD_LEN - 1);
-				if (pad) {
-					pad = PAD_WORD_LEN - pad;
-					memset(conn->tx_buffer + conn->tx_size,
-					       0, pad);
-					conn->tx_size += pad;
-				}
-				goto write_again;
-			}
-		case IOSTATE_WRITE_DATA:
-			conn->tp->ep_write_end(fd);
-			cmnd_finish(conn);
+			conn->tx_iostate = IOSTATE_TX_AHS;
+		} else
+			conn->tx_iostate = hdigest ?
+				IOSTATE_TX_INIT_HDIGEST : IOSTATE_TX_INIT_DATA;
 
-			switch (conn->state) {
-			case STATE_KERNEL:
-				res = conn_take_fd(conn, fd);
-				if (res)
-					conn->state = STATE_CLOSE;
-				else {
-					conn->state = STATE_SCSI;
-					conn_read_pdu(conn);
-					tgt_event_modify(fd, EPOLLIN);
-				}
-				break;
-			case STATE_EXIT:
-			case STATE_CLOSE:
-				break;
-			case STATE_SCSI:
-				iscsi_task_tx_done(conn);
-				break;
-			default:
-				conn_read_pdu(conn);
-				tgt_event_modify(fd, EPOLLIN);
-				break;
+		if (conn->tx_iostate != IOSTATE_TX_AHS)
+			break;
+	case IOSTATE_TX_AHS:
+		conn->tx_iostate = hdigest ?
+			IOSTATE_TX_INIT_HDIGEST : IOSTATE_TX_INIT_DATA;
+		if (conn->tx_iostate != IOSTATE_TX_INIT_HDIGEST)
+			break;
+	case IOSTATE_TX_INIT_HDIGEST:
+		crc = ~0;
+		crc = crc32c(crc, &conn->rsp.bhs, BHS_SIZE);
+		*(uint32_t *)conn->tx_digest = ~__cpu_to_le32(crc);
+		conn->tx_iostate = IOSTATE_TX_HDIGEST;
+		conn->tx_buffer = conn->tx_digest;
+		conn->tx_size = sizeof(conn->tx_digest);
+	case IOSTATE_TX_HDIGEST:
+		ret = do_send(fd, conn, IOSTATE_TX_INIT_DATA);
+		if (ret < 0)
+			break;
+	case IOSTATE_TX_INIT_DATA:
+		if (conn->rsp.datasize) {
+			int pad;
+
+			conn->tx_iostate = IOSTATE_TX_DATA;
+			conn->tx_buffer = conn->rsp.data;
+			conn->tx_size = conn->rsp.datasize;
+			pad = conn->tx_size & (PAD_WORD_LEN - 1);
+			if (pad) {
+				pad = PAD_WORD_LEN - pad;
+				memset(conn->tx_buffer + conn->tx_size, 0, pad);
+				conn->tx_size += pad;
 			}
+		} else
+			conn->tx_iostate = IOSTATE_TX_END;
+		if (conn->tx_iostate != IOSTATE_TX_DATA)
 			break;
-		}
-
+	case IOSTATE_TX_DATA:
+		ret = do_send(fd, conn, ddigest ?
+			      IOSTATE_TX_INIT_DDIGEST : IOSTATE_TX_END);
+		if (ret < 0)
+			return;
+		if (conn->tx_iostate != IOSTATE_TX_INIT_DDIGEST)
+			break;
+	case IOSTATE_TX_INIT_DDIGEST:
+		crc = ~0;
+		crc = crc32c(crc, conn->rsp.data,
+			     roundup(conn->rsp.datasize, 4));
+		*(uint32_t *)conn->tx_digest = ~__cpu_to_le32(crc);
+		conn->tx_iostate = IOSTATE_TX_DDIGEST;
+		conn->tx_buffer = conn->tx_digest;
+		conn->tx_size = sizeof(conn->tx_digest);
+	case IOSTATE_TX_DDIGEST:
+		ret = do_send(fd, conn, IOSTATE_TX_END);
 		break;
 	default:
-		eprintf("illegal iostate %d %d\n", conn->tx_iostate,
-			conn->tx_iostate);
-		conn->state = STATE_CLOSE;
+		eprintf("error %d %d\n", conn->state, conn->tx_iostate);
+		exit(1);
+	}
+
+	if (ret < 0 ||
+	    conn->tx_iostate != IOSTATE_TX_END ||
+	    conn->state == STATE_CLOSE)
+		return;
+
+	if (conn->tx_size) {
+		eprintf("error %d %d %d\n", conn->state, conn->tx_iostate,
+			conn->tx_size);
+		exit(1);
 	}
 
+	conn->tp->ep_write_end(fd);
+	cmnd_finish(conn);
+
+	switch (conn->state) {
+	case STATE_KERNEL:
+		ret = conn_take_fd(conn, fd);
+		if (ret)
+			conn->state = STATE_CLOSE;
+		else {
+			conn->state = STATE_SCSI;
+			conn_read_pdu(conn);
+			tgt_event_modify(fd, EPOLLIN);
+		}
+		break;
+	case STATE_EXIT:
+	case STATE_CLOSE:
+		break;
+	case STATE_SCSI:
+		iscsi_task_tx_done(conn);
+		break;
+	default:
+		conn_read_pdu(conn);
+		tgt_event_modify(fd, EPOLLIN);
+		break;
+	}
 }
 
 void iscsi_event_handler(int fd, int events, void *data)
@@ -1838,8 +2034,10 @@ void iscsi_event_handler(int fd, int eve
 	if (conn->state != STATE_CLOSE && events & EPOLLOUT)
 		iscsi_tx_handler(fd, conn);
 
-	if (conn->state == STATE_CLOSE)
+	if (conn->state == STATE_CLOSE) {
 		conn_close(conn, fd);
+		dprintf("connection closed\n");
+	}
 }
 
 struct tgt_driver iscsi = {
diff --git a/usr/iscsi/iscsid.h b/usr/iscsi/iscsid.h
index 84d74f3..29abc5d 100644
--- a/usr/iscsi/iscsid.h
+++ b/usr/iscsi/iscsid.h
@@ -174,6 +174,9 @@ struct iscsi_connection {
 
 	struct list_head tx_clist;
 
+	unsigned char rx_digest[4];
+	unsigned char tx_digest[4];
+
 	int auth_state;
 	union {
 		struct {
@@ -187,13 +190,6 @@ struct iscsi_connection {
 	struct iscsi_transport *tp;
 };
 
-#define IOSTATE_FREE		0
-#define IOSTATE_READ_BHS	1
-#define IOSTATE_READ_AHS_DATA	2
-#define IOSTATE_WRITE_BHS	3
-#define IOSTATE_WRITE_AHS	4
-#define IOSTATE_WRITE_DATA	5
-
 #define STATE_FREE		0
 #define STATE_SECURITY		1
 #define STATE_SECURITY_AUTH	2
@@ -263,14 +259,13 @@ extern void conn_put(struct iscsi_connec
 extern int conn_get(struct iscsi_connection *conn);
 extern struct iscsi_connection * conn_find(struct iscsi_session *session, uint32_t cid);
 extern int conn_take_fd(struct iscsi_connection *conn, int fd);
-extern void conn_read_pdu(struct iscsi_connection *conn);
-extern void conn_write_pdu(struct iscsi_connection *conn);
 extern void conn_add_to_session(struct iscsi_connection *conn, struct iscsi_session *session);
 
 /* iscsid.c */
 extern void iscsi_event_handler(int fd, int events, void *data);
 extern char *text_key_find(struct iscsi_connection *conn, char *searchKey);
 extern void text_key_add(struct iscsi_connection *conn, char *key, char *value);
+extern void conn_read_pdu(struct iscsi_connection *conn);
 
 /* iscsid.c iscsi_task */
 extern void iscsi_free_task(struct iscsi_task *task);



More information about the stgt mailing list