iscsi: Unify build and fast-forward iovecs to flush PDUs

Building iovecs had been done in spdk_iscsi_build_iovs() and
fast-forwarding iovecs for the partially written first PDU had
been done in-line separately.

This patch unifies these two operations into spdk_iscsi_build_iovs().

Fast-forwarding iovecs is necessary only for the first PDU, but the
operation is applied to all PDUs after this patch.

Extra overhead will be negligible because usually at most two
iovecs are consumed, one is for the base header segment and another
is for the data segment.

Change-Id: I8feafac6d280439eb7cf73136107adbac820ae09
Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/446174
Reviewed-by: Ziye Yang <ziye.yang@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
This commit is contained in:
Shuhei Matsumoto 2019-02-26 09:41:29 +09:00 committed by Jim Harris
parent 42596fb6b1
commit 879386d759
3 changed files with 140 additions and 35 deletions

View File

@ -1166,7 +1166,11 @@ spdk_iscsi_conn_flush_pdus_internal(struct spdk_iscsi_conn *conn)
/*
* Build up a list of iovecs for the first few PDUs in the
* connection's write_pdu_list.
* connection's write_pdu_list. For the first PDU, check if it was
* partially written out the last time this function was called, and
* if so adjust the iovec array accordingly. This check is done in
* spdk_iscsi_build_iovs() and so applied to remaining PDUs too.
* But extra overhead is negligible.
*/
while (pdu != NULL && ((num_iovs - iovcnt) >= 5)) {
pdu_length = spdk_iscsi_get_pdu_length(pdu,
@ -1177,24 +1181,8 @@ spdk_iscsi_conn_flush_pdus_internal(struct spdk_iscsi_conn *conn)
pdu = TAILQ_NEXT(pdu, tailq);
}
/*
* Check if the first PDU was partially written out the last time
* this function was called, and if so adjust the iovec array
* accordingly.
*/
writev_offset = TAILQ_FIRST(&conn->write_pdu_list)->writev_offset;
total_length -= writev_offset;
while (writev_offset > 0) {
if (writev_offset >= iov->iov_len) {
writev_offset -= iov->iov_len;
iov++;
iovcnt--;
} else {
iov->iov_len -= writev_offset;
iov->iov_base = (char *)iov->iov_base + writev_offset;
writev_offset = 0;
}
}
spdk_trace_record(TRACE_ISCSI_FLUSH_WRITEBUF_START, conn->id, total_length, 0, iovcnt);

View File

@ -569,11 +569,13 @@ spdk_iscsi_build_iovs(struct spdk_iscsi_conn *conn, struct iovec *iovs,
{
int iovcnt = 0;
int enable_digest;
int total_ahs_len;
int data_len;
uint32_t total_ahs_len;
uint32_t data_len;
uint32_t iov_offset;
total_ahs_len = pdu->bhs.total_ahs_len;
data_len = DGET24(pdu->bhs.data_segment_len);
data_len = ISCSI_ALIGN(data_len);
enable_digest = 1;
if (pdu->bhs.opcode == ISCSI_OP_LOGIN_RSP) {
@ -581,37 +583,60 @@ spdk_iscsi_build_iovs(struct spdk_iscsi_conn *conn, struct iovec *iovs,
enable_digest = 0;
}
/* BHS */
iovs[iovcnt].iov_base = &pdu->bhs;
iovs[iovcnt].iov_len = ISCSI_BHS_LEN;
iovcnt++;
iov_offset = pdu->writev_offset;
/* BHS */
if (iov_offset >= ISCSI_BHS_LEN) {
iov_offset -= ISCSI_BHS_LEN;
} else {
iovs[iovcnt].iov_base = (uint8_t *)&pdu->bhs + iov_offset;
iovs[iovcnt].iov_len = ISCSI_BHS_LEN - iov_offset;
iov_offset = 0;
iovcnt++;
}
/* AHS */
if (total_ahs_len > 0) {
iovs[iovcnt].iov_base = pdu->ahs;
iovs[iovcnt].iov_len = 4 * total_ahs_len;
iovcnt++;
if (iov_offset >= 4 * total_ahs_len) {
iov_offset -= 4 * total_ahs_len;
} else {
iovs[iovcnt].iov_base = pdu->ahs + iov_offset;
iovs[iovcnt].iov_len = 4 * total_ahs_len - iov_offset;
iov_offset = 0;
iovcnt++;
}
}
/* Header Digest */
if (enable_digest && conn->header_digest) {
iovs[iovcnt].iov_base = pdu->header_digest;
iovs[iovcnt].iov_len = ISCSI_DIGEST_LEN;
iovcnt++;
if (iov_offset >= ISCSI_DIGEST_LEN) {
iov_offset -= ISCSI_DIGEST_LEN;
} else {
iovs[iovcnt].iov_base = pdu->header_digest + iov_offset;
iovs[iovcnt].iov_len = ISCSI_DIGEST_LEN - iov_offset;
iov_offset = 0;
iovcnt++;
}
}
/* Data Segment */
if (data_len > 0) {
iovs[iovcnt].iov_base = pdu->data;
iovs[iovcnt].iov_len = ISCSI_ALIGN(data_len);
iovcnt++;
if (iov_offset >= data_len) {
iov_offset -= data_len;
} else {
iovs[iovcnt].iov_base = pdu->data + iov_offset;
iovs[iovcnt].iov_len = data_len - iov_offset;
iov_offset = 0;
iovcnt++;
}
}
/* Data Digest */
if (enable_digest && conn->data_digest && data_len != 0) {
iovs[iovcnt].iov_base = pdu->data_digest;
iovs[iovcnt].iov_len = ISCSI_DIGEST_LEN;
iovcnt++;
if (iov_offset < ISCSI_DIGEST_LEN) {
iovs[iovcnt].iov_base = pdu->data_digest + iov_offset;
iovs[iovcnt].iov_len = ISCSI_DIGEST_LEN - iov_offset;
iovcnt++;
}
}
return iovcnt;

View File

@ -1202,6 +1202,97 @@ abort_queued_datain_tasks_test(void)
spdk_put_pdu(pdu1);
}
static void
build_iovs_test(void)
{
struct spdk_iscsi_conn conn = {};
struct spdk_iscsi_pdu pdu = {};
struct iovec iovs[5] = {};
uint8_t *data;
int rc;
conn.header_digest = true;
conn.data_digest = true;
DSET24(&pdu.bhs.data_segment_len, 512);
data = calloc(1, 512);
SPDK_CU_ASSERT_FATAL(data != NULL);
pdu.data = data;
pdu.bhs.total_ahs_len = 0;
pdu.bhs.opcode = ISCSI_OP_SCSI;
pdu.writev_offset = 0;
rc = spdk_iscsi_build_iovs(&conn, iovs, &pdu);
CU_ASSERT(rc == 4);
CU_ASSERT(iovs[0].iov_base == (void *)&pdu.bhs);
CU_ASSERT(iovs[0].iov_len == ISCSI_BHS_LEN);
CU_ASSERT(iovs[1].iov_base == (void *)pdu.header_digest);
CU_ASSERT(iovs[1].iov_len == ISCSI_DIGEST_LEN);
CU_ASSERT(iovs[2].iov_base == (void *)pdu.data);
CU_ASSERT(iovs[2].iov_len == 512);
CU_ASSERT(iovs[3].iov_base == (void *)pdu.data_digest);
CU_ASSERT(iovs[3].iov_len == ISCSI_DIGEST_LEN);
pdu.writev_offset = ISCSI_BHS_LEN / 2;
rc = spdk_iscsi_build_iovs(&conn, iovs, &pdu);
CU_ASSERT(rc == 4);
CU_ASSERT(iovs[0].iov_base == (void *)((uint8_t *)&pdu.bhs + ISCSI_BHS_LEN / 2));
CU_ASSERT(iovs[0].iov_len == ISCSI_BHS_LEN / 2);
CU_ASSERT(iovs[1].iov_base == (void *)pdu.header_digest);
CU_ASSERT(iovs[1].iov_len == ISCSI_DIGEST_LEN);
CU_ASSERT(iovs[2].iov_base == (void *)pdu.data);
CU_ASSERT(iovs[2].iov_len == 512);
CU_ASSERT(iovs[3].iov_base == (void *)pdu.data_digest);
CU_ASSERT(iovs[3].iov_len == ISCSI_DIGEST_LEN);
pdu.writev_offset = ISCSI_BHS_LEN;
rc = spdk_iscsi_build_iovs(&conn, iovs, &pdu);
CU_ASSERT(rc == 3);
CU_ASSERT(iovs[0].iov_base == (void *)pdu.header_digest);
CU_ASSERT(iovs[0].iov_len == ISCSI_DIGEST_LEN);
CU_ASSERT(iovs[1].iov_base == (void *)pdu.data);
CU_ASSERT(iovs[1].iov_len == 512);
CU_ASSERT(iovs[2].iov_base == (void *)pdu.data_digest);
CU_ASSERT(iovs[2].iov_len == ISCSI_DIGEST_LEN);
pdu.writev_offset = ISCSI_BHS_LEN + ISCSI_DIGEST_LEN / 2;
rc = spdk_iscsi_build_iovs(&conn, iovs, &pdu);
CU_ASSERT(rc == 3);
CU_ASSERT(iovs[0].iov_base == (void *)((uint8_t *)pdu.header_digest + ISCSI_DIGEST_LEN / 2));
CU_ASSERT(iovs[0].iov_len == ISCSI_DIGEST_LEN / 2);
CU_ASSERT(iovs[1].iov_base == (void *)pdu.data);
CU_ASSERT(iovs[1].iov_len == 512);
CU_ASSERT(iovs[2].iov_base == (void *)pdu.data_digest);
CU_ASSERT(iovs[2].iov_len == ISCSI_DIGEST_LEN);
pdu.writev_offset = ISCSI_BHS_LEN + ISCSI_DIGEST_LEN;
rc = spdk_iscsi_build_iovs(&conn, iovs, &pdu);
CU_ASSERT(rc == 2);
CU_ASSERT(iovs[0].iov_base == (void *)pdu.data);
CU_ASSERT(iovs[0].iov_len == 512);
CU_ASSERT(iovs[1].iov_base == (void *)pdu.data_digest);
CU_ASSERT(iovs[1].iov_len == ISCSI_DIGEST_LEN);
pdu.writev_offset = ISCSI_BHS_LEN + ISCSI_DIGEST_LEN + 512;
rc = spdk_iscsi_build_iovs(&conn, iovs, &pdu);
CU_ASSERT(rc == 1);
CU_ASSERT(iovs[0].iov_base == (void *)pdu.data_digest);
CU_ASSERT(iovs[0].iov_len == ISCSI_DIGEST_LEN);
pdu.writev_offset = ISCSI_BHS_LEN + ISCSI_DIGEST_LEN + 512 + ISCSI_DIGEST_LEN / 2;
rc = spdk_iscsi_build_iovs(&conn, iovs, &pdu);
CU_ASSERT(rc == 1);
CU_ASSERT(iovs[0].iov_base == (void *)((uint8_t *)pdu.data_digest + ISCSI_DIGEST_LEN / 2));
CU_ASSERT(iovs[0].iov_len == ISCSI_DIGEST_LEN / 2);
pdu.writev_offset = ISCSI_BHS_LEN + ISCSI_DIGEST_LEN + 512 + ISCSI_DIGEST_LEN;
rc = spdk_iscsi_build_iovs(&conn, iovs, &pdu);
CU_ASSERT(rc == 0);
free(data);
}
int
main(int argc, char **argv)
{
@ -1238,6 +1329,7 @@ main(int argc, char **argv)
abort_queued_datain_task_test) == NULL
|| CU_add_test(suite, "abort_queued_datain_tasks_test",
abort_queued_datain_tasks_test) == NULL
|| CU_add_test(suite, "build_iovs_test", build_iovs_test) == NULL
) {
CU_cleanup_registry();
return CU_get_error();