Commit 4b741fe6 authored by Shuhei Matsumoto's avatar Shuhei Matsumoto Committed by Tomasz Zawadzki
Browse files

lib/iscsi: Introduce state machine into receive PDUs operation



Add PDU receive state to each connection, and each connection
transits among states during receiving incoming PDUs.

Four states, AWAIT_PDU_READY, AWAIT_PDU_HDR, AWAIT_PDU_PAYLOAD,
and ERROR are same as SPDK NVMe-TCP target.

Move clearing conn->pdu_in_progress just before putting pdu
when PDU processing completes normally to match with error case.

Signed-off-by: default avatarShuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Change-Id: Id24b6d6662896b5685125a46ee20cbf216668838
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/469966


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
Reviewed-by: default avatarChangpeng Liu <changpeng.liu@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
parent ca080c13
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -251,6 +251,8 @@ spdk_iscsi_conn_construct(struct spdk_iscsi_portal *portal,
		conn->outstanding_r2t_tasks[i] = NULL;
	}

	conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_AWAIT_PDU_READY;

	TAILQ_INIT(&conn->write_pdu_list);
	TAILQ_INIT(&conn->snack_pdu_list);
	TAILQ_INIT(&conn->queued_r2t_tasks);
+15 −0
Original line number Diff line number Diff line
@@ -67,6 +67,20 @@
#define TRACE_ISCSI_TASK_EXECUTED		SPDK_TPOINT_ID(TRACE_GROUP_ISCSI, 0x6)
#define TRACE_ISCSI_PDU_COMPLETED		SPDK_TPOINT_ID(TRACE_GROUP_ISCSI, 0x7)

enum iscsi_pdu_recv_state {
	/* Ready to wait for PDU */
	ISCSI_PDU_RECV_STATE_AWAIT_PDU_READY,

	/* Active connection waiting for any PDU header */
	ISCSI_PDU_RECV_STATE_AWAIT_PDU_HDR,

	/* Active connection waiting for payload */
	ISCSI_PDU_RECV_STATE_AWAIT_PDU_PAYLOAD,

	/* Active connection does not wait for payload */
	ISCSI_PDU_RECV_STATE_ERROR,
};

struct spdk_poller;

struct spdk_iscsi_conn {
@@ -109,6 +123,7 @@ struct spdk_iscsi_conn {
	struct spdk_poller *shutdown_timer;

	struct spdk_iscsi_pdu *pdu_in_progress;
	enum iscsi_pdu_recv_state pdu_recv_state;

	TAILQ_HEAD(, spdk_iscsi_pdu) write_pdu_list;
	TAILQ_HEAD(, spdk_iscsi_pdu) snack_pdu_list;
+164 −140
Original line number Diff line number Diff line
@@ -4589,6 +4589,7 @@ iscsi_execute(struct spdk_iscsi_conn *conn, struct spdk_iscsi_pdu *pdu)
int
spdk_iscsi_read_pdu(struct spdk_iscsi_conn *conn)
{
	enum iscsi_pdu_recv_state prev_state;
	struct spdk_iscsi_pdu *pdu;
	struct spdk_mempool *pool;
	uint32_t crc32c;
@@ -4596,21 +4597,28 @@ spdk_iscsi_read_pdu(struct spdk_iscsi_conn *conn)
	uint32_t data_len;
	int rc;

	if (conn->pdu_in_progress == NULL) {
	do {
		prev_state = conn->pdu_recv_state;
		pdu = conn->pdu_in_progress;

		switch (conn->pdu_recv_state) {
		case ISCSI_PDU_RECV_STATE_AWAIT_PDU_READY:
			assert(conn->pdu_in_progress == NULL);

			conn->pdu_in_progress = spdk_get_pdu();
			if (conn->pdu_in_progress == NULL) {
				return SPDK_ISCSI_CONNECTION_FATAL;
			}
	}

	pdu = conn->pdu_in_progress;

			conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_AWAIT_PDU_HDR;
			break;
		case ISCSI_PDU_RECV_STATE_AWAIT_PDU_HDR:
			if (pdu->bhs_valid_bytes < ISCSI_BHS_LEN) {
				rc = spdk_iscsi_conn_read_data(conn,
							       ISCSI_BHS_LEN - pdu->bhs_valid_bytes,
							       (uint8_t *)&pdu->bhs + pdu->bhs_valid_bytes);
				if (rc < 0) {
			goto error;
					conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
					break;
				}
				pdu->bhs_valid_bytes += rc;
				if (pdu->bhs_valid_bytes < ISCSI_BHS_LEN) {
@@ -4626,7 +4634,8 @@ spdk_iscsi_read_pdu(struct spdk_iscsi_conn *conn)
							       ahs_len - pdu->ahs_valid_bytes,
							       pdu->ahs + pdu->ahs_valid_bytes);
				if (rc < 0) {
			goto error;
					conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
					break;
				}

				pdu->ahs_valid_bytes += rc;
@@ -4642,7 +4651,8 @@ spdk_iscsi_read_pdu(struct spdk_iscsi_conn *conn)
							       ISCSI_DIGEST_LEN - pdu->hdigest_valid_bytes,
							       pdu->header_digest + pdu->hdigest_valid_bytes);
				if (rc < 0) {
			goto error;
					conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
					break;
				}

				pdu->hdigest_valid_bytes += rc;
@@ -4656,10 +4666,14 @@ spdk_iscsi_read_pdu(struct spdk_iscsi_conn *conn)
				rc = MATCH_DIGEST_WORD(pdu->header_digest, crc32c);
				if (rc == 0) {
					SPDK_ERRLOG("header digest error (%s)\n", conn->initiator_name);
			goto error;
					conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
					break;
				}
			}

			conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_AWAIT_PDU_PAYLOAD;
			break;
		case ISCSI_PDU_RECV_STATE_AWAIT_PDU_PAYLOAD:
			data_len = ISCSI_ALIGN(DGET24(pdu->bhs.data_segment_len));

			if (data_len != 0 && pdu->data_buf == NULL) {
@@ -4672,7 +4686,8 @@ spdk_iscsi_read_pdu(struct spdk_iscsi_conn *conn)
				} else {
					SPDK_ERRLOG("Data(%d) > MaxSegment(%d)\n",
						    data_len, SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
			goto error;
					conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
					break;
				}
				pdu->mobj = spdk_mempool_get(pool);
				if (pdu->mobj == NULL) {
@@ -4692,7 +4707,8 @@ spdk_iscsi_read_pdu(struct spdk_iscsi_conn *conn)
			if (pdu->data_valid_bytes < data_len) {
				rc = iscsi_conn_read_data_segment(conn, pdu, data_len);
				if (rc < 0) {
			goto error;
					conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
					break;
				}

				pdu->data_valid_bytes += rc;
@@ -4708,7 +4724,8 @@ spdk_iscsi_read_pdu(struct spdk_iscsi_conn *conn)
							       ISCSI_DIGEST_LEN - pdu->ddigest_valid_bytes,
							       pdu->data_digest + pdu->ddigest_valid_bytes);
				if (rc < 0) {
			goto error;
					conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
					break;
				}

				pdu->ddigest_valid_bytes += rc;
@@ -4718,8 +4735,6 @@ spdk_iscsi_read_pdu(struct spdk_iscsi_conn *conn)
			}

			/* All data for this PDU has now been read from the socket. */
	conn->pdu_in_progress = NULL;

			spdk_trace_record(TRACE_ISCSI_READ_PDU, conn->id, pdu->data_valid_bytes,
					  (uintptr_t)pdu, pdu->bhs.opcode);

@@ -4729,31 +4744,40 @@ spdk_iscsi_read_pdu(struct spdk_iscsi_conn *conn)
				rc = MATCH_DIGEST_WORD(pdu->data_digest, crc32c);
				if (rc == 0) {
					SPDK_ERRLOG("data digest error (%s)\n", conn->initiator_name);
			goto error;
					conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
					break;
				}
			}

			if (conn->is_logged_out) {
				SPDK_ERRLOG("pdu received after logout\n");
		spdk_put_pdu(pdu);
		return SPDK_ISCSI_CONNECTION_FATAL;
				conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
				break;
			}

			rc = iscsi_execute(conn, pdu);
			if (rc == 0) {
				spdk_trace_record(TRACE_ISCSI_TASK_EXECUTED, 0, 0, (uintptr_t)pdu, 0);
	}
				spdk_put_pdu(pdu);
	if (rc < 0) {
		return SPDK_ISCSI_CONNECTION_FATAL;
	}

				conn->pdu_in_progress = NULL;
				conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_AWAIT_PDU_READY;
				return 1;

error:
			} else {
				conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
			}
			break;
		case ISCSI_PDU_RECV_STATE_ERROR:
			spdk_put_pdu(pdu);
			conn->pdu_in_progress = NULL;
			return SPDK_ISCSI_CONNECTION_FATAL;
		default:
			assert(false);
			SPDK_ERRLOG("code should not come here\n");
			break;
		}
	} while (prev_state != conn->pdu_recv_state);

	return 0;
}

bool