SPDK iSCSIターゲットの要求処理

投稿者: | 2022年7月18日

PDUの受信処理。

int
iscsi_handle_incoming_pdus(struct spdk_iscsi_conn *conn)
{
	int i, rc;

	/* Read new PDUs from network */
	for (i = 0; i < GET_PDU_LOOP_COUNT; i++) {
		rc = iscsi_read_pdu(conn); ★本体
		if (rc == 0) {
			break;
		} else if (rc < 0) {
			return rc;
		}

		if (conn->is_stopped) {
			break;
		}
	}

	return i;
}

iscsi_read_pduはconnのステートに応じて処理。

static int
iscsi_read_pdu(struct spdk_iscsi_conn *conn)
{
	enum iscsi_pdu_recv_state prev_state;
	struct spdk_iscsi_pdu *pdu;
	uint32_t crc32c;
	int ahs_len;
	int rc;

	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 = iscsi_get_pdu(conn);
			if (conn->pdu_in_progress == NULL) {
				return SPDK_ISCSI_CONNECTION_FATAL;
			}
			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 = iscsi_conn_read_data(conn,
							  ISCSI_BHS_LEN - pdu->bhs_valid_bytes,
							  (uint8_t *)&pdu->bhs + pdu->bhs_valid_bytes);
				if (rc < 0) {
					conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
					break;
				}
				pdu->bhs_valid_bytes += rc;
				if (pdu->bhs_valid_bytes < ISCSI_BHS_LEN) {
					return 0;
				}
			}

			/* conn->is_logged_out must be checked after completing to process
			 * logout request, i.e., before processing PDU header in this state
			 * machine, otherwise logout response may not be sent to initiator
			 * and initiator may get logout timeout.
			 */
			if (spdk_unlikely(conn->is_logged_out)) {
				SPDK_DEBUGLOG(iscsi, "pdu received after logout\n");
				conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
				break;
			}

			pdu->data_segment_len = ISCSI_ALIGN(DGET24(pdu->bhs.data_segment_len));
			pdu->data_buf_len = pdu->data_segment_len;

			/* AHS */
			ahs_len = pdu->bhs.total_ahs_len * 4;
			if (ahs_len > ISCSI_AHS_LEN) {
				SPDK_DEBUGLOG(iscsi, "pdu ahs length %d is invalid\n", ahs_len);
				conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
				break;
			}

			if (pdu->ahs_valid_bytes < ahs_len) {
				rc = iscsi_conn_read_data(conn,
							  ahs_len - pdu->ahs_valid_bytes,
							  pdu->ahs + pdu->ahs_valid_bytes);
				if (rc < 0) {
					conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
					break;
				}

				pdu->ahs_valid_bytes += rc;
				if (pdu->ahs_valid_bytes < ahs_len) {
					return 0;
				}
			}

			/* Header Digest */
			if (conn->header_digest &&
			    pdu->hdigest_valid_bytes < ISCSI_DIGEST_LEN) {
				rc = iscsi_conn_read_data(conn,
							  ISCSI_DIGEST_LEN - pdu->hdigest_valid_bytes,
							  pdu->header_digest + pdu->hdigest_valid_bytes);
				if (rc < 0) {
					conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
					break;
				}

				pdu->hdigest_valid_bytes += rc;
				if (pdu->hdigest_valid_bytes < ISCSI_DIGEST_LEN) {
					return 0;
				}
			}

			if (conn->header_digest) {
				crc32c = iscsi_pdu_calc_header_digest(pdu);
				rc = MATCH_DIGEST_WORD(pdu->header_digest, crc32c);
				if (rc == 0) {
					SPDK_ERRLOG("header digest error (%s)\n", conn->initiator_name);
					conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
					break;
				}
			}

			rc = iscsi_pdu_hdr_handle(conn, pdu);
			if (rc < 0) {
				SPDK_ERRLOG("Critical error is detected. Close the connection\n");
				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:
			if (pdu->data_segment_len != 0) {
				rc = iscsi_pdu_payload_read(conn, pdu);
				if (rc > 0) {
					return 0;
				} else if (rc < 0) {
					conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
					break;
				}
			}

			/* All data for this PDU has now been read from the socket. */
			spdk_trace_record(TRACE_ISCSI_READ_PDU, conn->id, pdu->data_valid_bytes,
					  (uintptr_t)pdu, pdu->bhs.opcode);

			if (!pdu->is_rejected) {
				rc = iscsi_pdu_payload_handle(conn, pdu);
			} else {
				rc = 0;
			}
			if (rc == 0) {
				spdk_trace_record(TRACE_ISCSI_TASK_EXECUTED, 0, 0, (uintptr_t)pdu);
				iscsi_put_pdu(pdu);
				conn->pdu_in_progress = NULL;
				conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_AWAIT_PDU_READY;
				return 1;
			} else {
				conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
			}
			break;
		case ISCSI_PDU_RECV_STATE_ERROR:
			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;
}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です