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: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com> Change-Id: Id24b6d6662896b5685125a46ee20cbf216668838 Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/469966 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com> Reviewed-by: Changpeng Liu <changpeng.liu@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
parent
ca080c1309
commit
4b741fe65e
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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,164 +4597,187 @@ spdk_iscsi_read_pdu(struct spdk_iscsi_conn *conn)
|
||||
uint32_t data_len;
|
||||
int rc;
|
||||
|
||||
if (conn->pdu_in_progress == NULL) {
|
||||
conn->pdu_in_progress = spdk_get_pdu();
|
||||
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;
|
||||
}
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* AHS */
|
||||
ahs_len = pdu->bhs.total_ahs_len * 4;
|
||||
assert(ahs_len <= ISCSI_AHS_LEN);
|
||||
if (pdu->ahs_valid_bytes < ahs_len) {
|
||||
rc = spdk_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 = spdk_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 = spdk_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;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
if (data_len <= spdk_get_max_immediate_data_size()) {
|
||||
pool = g_spdk_iscsi.pdu_immediate_data_pool;
|
||||
pdu->data_buf_len = SPDK_BDEV_BUF_SIZE_WITH_MD(spdk_get_max_immediate_data_size());
|
||||
} else if (data_len <= SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH) {
|
||||
pool = g_spdk_iscsi.pdu_data_out_pool;
|
||||
pdu->data_buf_len = SPDK_BDEV_BUF_SIZE_WITH_MD(SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
|
||||
} else {
|
||||
SPDK_ERRLOG("Data(%d) > MaxSegment(%d)\n",
|
||||
data_len, SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
|
||||
conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
pdu->mobj = spdk_mempool_get(pool);
|
||||
if (pdu->mobj == NULL) {
|
||||
return 0;
|
||||
}
|
||||
pdu->data_buf = pdu->mobj->buf;
|
||||
pdu->data = pdu->mobj->buf;
|
||||
pdu->data_from_mempool = true;
|
||||
pdu->data_segment_len = data_len;
|
||||
|
||||
if (spdk_unlikely(spdk_iscsi_get_dif_ctx(conn, pdu, &pdu->dif_ctx))) {
|
||||
pdu->dif_insert_or_strip = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* copy the actual data into local buffer */
|
||||
if (pdu->data_valid_bytes < data_len) {
|
||||
rc = iscsi_conn_read_data_segment(conn, pdu, data_len);
|
||||
if (rc < 0) {
|
||||
conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
pdu->data_valid_bytes += rc;
|
||||
if (pdu->data_valid_bytes < data_len) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* copy out the data digest */
|
||||
if (conn->data_digest && data_len != 0 &&
|
||||
pdu->ddigest_valid_bytes < ISCSI_DIGEST_LEN) {
|
||||
rc = spdk_iscsi_conn_read_data(conn,
|
||||
ISCSI_DIGEST_LEN - pdu->ddigest_valid_bytes,
|
||||
pdu->data_digest + pdu->ddigest_valid_bytes);
|
||||
if (rc < 0) {
|
||||
conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
pdu->ddigest_valid_bytes += rc;
|
||||
if (pdu->ddigest_valid_bytes < ISCSI_DIGEST_LEN) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
/* check data digest */
|
||||
if (conn->data_digest && data_len != 0) {
|
||||
crc32c = spdk_iscsi_pdu_calc_data_digest(pdu);
|
||||
rc = MATCH_DIGEST_WORD(pdu->data_digest, crc32c);
|
||||
if (rc == 0) {
|
||||
SPDK_ERRLOG("data digest error (%s)\n", conn->initiator_name);
|
||||
conn->pdu_recv_state = ISCSI_PDU_RECV_STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (conn->is_logged_out) {
|
||||
SPDK_ERRLOG("pdu received after logout\n");
|
||||
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);
|
||||
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:
|
||||
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);
|
||||
|
||||
pdu = conn->pdu_in_progress;
|
||||
|
||||
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;
|
||||
}
|
||||
pdu->bhs_valid_bytes += rc;
|
||||
if (pdu->bhs_valid_bytes < ISCSI_BHS_LEN) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* AHS */
|
||||
ahs_len = pdu->bhs.total_ahs_len * 4;
|
||||
assert(ahs_len <= ISCSI_AHS_LEN);
|
||||
if (pdu->ahs_valid_bytes < ahs_len) {
|
||||
rc = spdk_iscsi_conn_read_data(conn,
|
||||
ahs_len - pdu->ahs_valid_bytes,
|
||||
pdu->ahs + pdu->ahs_valid_bytes);
|
||||
if (rc < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
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 = spdk_iscsi_conn_read_data(conn,
|
||||
ISCSI_DIGEST_LEN - pdu->hdigest_valid_bytes,
|
||||
pdu->header_digest + pdu->hdigest_valid_bytes);
|
||||
if (rc < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
pdu->hdigest_valid_bytes += rc;
|
||||
if (pdu->hdigest_valid_bytes < ISCSI_DIGEST_LEN) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (conn->header_digest) {
|
||||
crc32c = spdk_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);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
data_len = ISCSI_ALIGN(DGET24(pdu->bhs.data_segment_len));
|
||||
|
||||
if (data_len != 0 && pdu->data_buf == NULL) {
|
||||
if (data_len <= spdk_get_max_immediate_data_size()) {
|
||||
pool = g_spdk_iscsi.pdu_immediate_data_pool;
|
||||
pdu->data_buf_len = SPDK_BDEV_BUF_SIZE_WITH_MD(spdk_get_max_immediate_data_size());
|
||||
} else if (data_len <= SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH) {
|
||||
pool = g_spdk_iscsi.pdu_data_out_pool;
|
||||
pdu->data_buf_len = SPDK_BDEV_BUF_SIZE_WITH_MD(SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
|
||||
} else {
|
||||
SPDK_ERRLOG("Data(%d) > MaxSegment(%d)\n",
|
||||
data_len, SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
|
||||
goto error;
|
||||
}
|
||||
pdu->mobj = spdk_mempool_get(pool);
|
||||
if (pdu->mobj == NULL) {
|
||||
return 0;
|
||||
}
|
||||
pdu->data_buf = pdu->mobj->buf;
|
||||
pdu->data = pdu->mobj->buf;
|
||||
pdu->data_from_mempool = true;
|
||||
pdu->data_segment_len = data_len;
|
||||
|
||||
if (spdk_unlikely(spdk_iscsi_get_dif_ctx(conn, pdu, &pdu->dif_ctx))) {
|
||||
pdu->dif_insert_or_strip = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* copy the actual data into local buffer */
|
||||
if (pdu->data_valid_bytes < data_len) {
|
||||
rc = iscsi_conn_read_data_segment(conn, pdu, data_len);
|
||||
if (rc < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
pdu->data_valid_bytes += rc;
|
||||
if (pdu->data_valid_bytes < data_len) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* copy out the data digest */
|
||||
if (conn->data_digest && data_len != 0 &&
|
||||
pdu->ddigest_valid_bytes < ISCSI_DIGEST_LEN) {
|
||||
rc = spdk_iscsi_conn_read_data(conn,
|
||||
ISCSI_DIGEST_LEN - pdu->ddigest_valid_bytes,
|
||||
pdu->data_digest + pdu->ddigest_valid_bytes);
|
||||
if (rc < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
pdu->ddigest_valid_bytes += rc;
|
||||
if (pdu->ddigest_valid_bytes < ISCSI_DIGEST_LEN) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
/* check data digest */
|
||||
if (conn->data_digest && data_len != 0) {
|
||||
crc32c = spdk_iscsi_pdu_calc_data_digest(pdu);
|
||||
rc = MATCH_DIGEST_WORD(pdu->data_digest, crc32c);
|
||||
if (rc == 0) {
|
||||
SPDK_ERRLOG("data digest error (%s)\n", conn->initiator_name);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (conn->is_logged_out) {
|
||||
SPDK_ERRLOG("pdu received after logout\n");
|
||||
spdk_put_pdu(pdu);
|
||||
return SPDK_ISCSI_CONNECTION_FATAL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
error:
|
||||
spdk_put_pdu(pdu);
|
||||
conn->pdu_in_progress = NULL;
|
||||
return SPDK_ISCSI_CONNECTION_FATAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
|
Loading…
Reference in New Issue
Block a user