nvme/tcp: optimize nvme_tcp_build_iovecs function.
Borrow the ideas from iSCSI and optimize the nvme_tcp_build_iovecs function. Change-Id: I19b165b5f6dc34b4bf655157170dec5c2ce3e19a Signed-off-by: Ziye Yang <ziye.yang@intel.com> Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/446836 Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com> Reviewed-by: Changpeng Liu <changpeng.liu@intel.com> Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
This commit is contained in:
parent
51ab378862
commit
791d89bfa7
@ -137,6 +137,14 @@ enum nvme_tcp_qpair_state {
|
||||
NVME_TCP_QPAIR_STATE_EXITED = 3,
|
||||
};
|
||||
|
||||
struct _iov_ctx {
|
||||
struct iovec *iov;
|
||||
int num_iovs;
|
||||
uint32_t iov_offset;
|
||||
int iovcnt;
|
||||
uint32_t mapped_len;
|
||||
};
|
||||
|
||||
static uint32_t
|
||||
nvme_tcp_pdu_calc_header_digest(struct nvme_tcp_pdu *pdu)
|
||||
{
|
||||
@ -173,17 +181,52 @@ nvme_tcp_pdu_calc_data_digest(struct nvme_tcp_pdu *pdu)
|
||||
return crc32c;
|
||||
}
|
||||
|
||||
static int
|
||||
nvme_tcp_build_iovecs(struct iovec *iovec, struct nvme_tcp_pdu *pdu,
|
||||
bool hdgst_enable, bool ddgst_enable)
|
||||
static inline void
|
||||
_iov_ctx_init(struct _iov_ctx *ctx, struct iovec *iovs, int num_iovs,
|
||||
uint32_t iov_offset)
|
||||
{
|
||||
ctx->iov = iovs;
|
||||
ctx->num_iovs = num_iovs;
|
||||
ctx->iov_offset = iov_offset;
|
||||
ctx->iovcnt = 0;
|
||||
ctx->mapped_len = 0;
|
||||
}
|
||||
|
||||
int iovec_cnt = 0;
|
||||
static inline bool
|
||||
_iov_ctx_set_iov(struct _iov_ctx *ctx, uint8_t *data, uint32_t data_len)
|
||||
{
|
||||
if (ctx->iov_offset >= data_len) {
|
||||
ctx->iov_offset -= data_len;
|
||||
} else {
|
||||
ctx->iov->iov_base = data + ctx->iov_offset;
|
||||
ctx->iov->iov_len = data_len - ctx->iov_offset;
|
||||
ctx->mapped_len += data_len - ctx->iov_offset;
|
||||
ctx->iov_offset = 0;
|
||||
ctx->iov++;
|
||||
ctx->iovcnt++;
|
||||
if (ctx->iovcnt == ctx->num_iovs) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int
|
||||
nvme_tcp_build_iovecs(struct iovec *iovec, int num_iovs, struct nvme_tcp_pdu *pdu,
|
||||
bool hdgst_enable, bool ddgst_enable, uint32_t *_mapped_length)
|
||||
{
|
||||
struct _iov_ctx ctx;
|
||||
int enable_digest;
|
||||
int hlen;
|
||||
uint32_t plen;
|
||||
uint32_t hlen, plen;
|
||||
|
||||
if (num_iovs == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
_iov_ctx_init(&ctx, iovec, num_iovs, pdu->writev_offset);
|
||||
hlen = pdu->hdr.common.hlen;
|
||||
plen = hlen;
|
||||
enable_digest = 1;
|
||||
if (pdu->hdr.common.pdu_type == SPDK_NVME_TCP_PDU_TYPE_IC_REQ ||
|
||||
pdu->hdr.common.pdu_type == SPDK_NVME_TCP_PDU_TYPE_IC_RESP ||
|
||||
@ -198,39 +241,45 @@ nvme_tcp_build_iovecs(struct iovec *iovec, struct nvme_tcp_pdu *pdu,
|
||||
hlen += SPDK_NVME_TCP_DIGEST_LEN;
|
||||
}
|
||||
|
||||
/* PDU header + possible header digest */
|
||||
iovec[iovec_cnt].iov_base = &pdu->hdr.raw;
|
||||
iovec[iovec_cnt].iov_len = hlen;
|
||||
plen = iovec[iovec_cnt].iov_len;
|
||||
iovec_cnt++;
|
||||
|
||||
if (!pdu->data_len || !pdu->data) {
|
||||
/* PDU header + possible header digest */
|
||||
_iov_ctx_set_iov(&ctx, (uint8_t *)&pdu->hdr.raw, hlen);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Padding */
|
||||
/* Padding */
|
||||
if (pdu->padding_len > 0) {
|
||||
iovec[iovec_cnt - 1].iov_len += pdu->padding_len;
|
||||
plen = iovec[iovec_cnt - 1].iov_len;
|
||||
hlen += pdu->padding_len;
|
||||
plen = hlen;
|
||||
}
|
||||
|
||||
if (!_iov_ctx_set_iov(&ctx, (uint8_t *)&pdu->hdr.raw, hlen)) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Data Segment */
|
||||
iovec[iovec_cnt].iov_base = pdu->data;
|
||||
iovec[iovec_cnt].iov_len = pdu->data_len;
|
||||
plen += iovec[iovec_cnt].iov_len;
|
||||
iovec_cnt++;
|
||||
plen += pdu->data_len;
|
||||
if (!_iov_ctx_set_iov(&ctx, pdu->data, pdu->data_len)) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Data Digest */
|
||||
if (enable_digest && ddgst_enable) {
|
||||
iovec[iovec_cnt].iov_base = pdu->data_digest;
|
||||
iovec[iovec_cnt].iov_len = SPDK_NVME_TCP_DIGEST_LEN;
|
||||
plen += iovec[iovec_cnt].iov_len;
|
||||
iovec_cnt++;
|
||||
plen += SPDK_NVME_TCP_DIGEST_LEN;
|
||||
_iov_ctx_set_iov(&ctx, pdu->data_digest, SPDK_NVME_TCP_DIGEST_LEN);
|
||||
}
|
||||
|
||||
end:
|
||||
assert(plen == pdu->hdr.common.plen);
|
||||
return iovec_cnt;
|
||||
if (_mapped_length != NULL) {
|
||||
*_mapped_length = ctx.mapped_len;
|
||||
}
|
||||
|
||||
/* check the plen for the first time constructing iov */
|
||||
if (!pdu->writev_offset) {
|
||||
assert(plen == pdu->hdr.common.plen);
|
||||
}
|
||||
|
||||
return ctx.iovcnt;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -380,7 +380,7 @@ nvme_tcp_qpair_process_send_queue(struct nvme_tcp_qpair *tqpair)
|
||||
struct iovec *iov = iovec_array;
|
||||
int iovec_cnt = 0;
|
||||
int bytes = 0;
|
||||
uint32_t writev_offset;
|
||||
uint32_t mapped_length;
|
||||
struct nvme_tcp_pdu *pdu;
|
||||
int pdu_length;
|
||||
TAILQ_HEAD(, nvme_tcp_pdu) completed_pdus_list;
|
||||
@ -396,30 +396,12 @@ nvme_tcp_qpair_process_send_queue(struct nvme_tcp_qpair *tqpair)
|
||||
* tqpair 's send_queue.
|
||||
*/
|
||||
while (pdu != NULL && ((array_size - iovec_cnt) >= 3)) {
|
||||
iovec_cnt += nvme_tcp_build_iovecs(&iovec_array[iovec_cnt],
|
||||
iovec_cnt += nvme_tcp_build_iovecs(&iovec_array[iovec_cnt], array_size - iovec_cnt,
|
||||
pdu, tqpair->host_hdgst_enable,
|
||||
tqpair->host_ddgst_enable);
|
||||
tqpair->host_ddgst_enable, &mapped_length);
|
||||
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(&tqpair->send_queue)->writev_offset;
|
||||
while ((writev_offset > 0) && (iovec_cnt > 0)) {
|
||||
if (writev_offset >= iov->iov_len) {
|
||||
writev_offset -= iov->iov_len;
|
||||
iov++;
|
||||
iovec_cnt--;
|
||||
} else {
|
||||
iov->iov_len -= writev_offset;
|
||||
iov->iov_base = (char *)iov->iov_base + writev_offset;
|
||||
writev_offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bytes = spdk_sock_writev(tqpair->sock, iov, iovec_cnt);
|
||||
SPDK_DEBUGLOG(SPDK_LOG_NVME, "bytes=%d are out\n", bytes);
|
||||
if (bytes == -1) {
|
||||
|
@ -773,7 +773,7 @@ spdk_nvmf_tcp_qpair_flush_pdus_internal(struct spdk_nvmf_tcp_qpair *tqpair)
|
||||
int iovec_cnt = 0;
|
||||
int bytes = 0;
|
||||
int total_length = 0;
|
||||
uint32_t writev_offset;
|
||||
uint32_t mapped_length;
|
||||
struct nvme_tcp_pdu *pdu;
|
||||
int pdu_length;
|
||||
TAILQ_HEAD(, nvme_tcp_pdu) completed_pdus_list;
|
||||
@ -791,32 +791,15 @@ spdk_nvmf_tcp_qpair_flush_pdus_internal(struct spdk_nvmf_tcp_qpair *tqpair)
|
||||
*/
|
||||
while (pdu != NULL && ((array_size - iovec_cnt) >= 3)) {
|
||||
iovec_cnt += nvme_tcp_build_iovecs(&iovec_array[iovec_cnt],
|
||||
array_size - iovec_cnt,
|
||||
pdu,
|
||||
tqpair->host_hdgst_enable,
|
||||
tqpair->host_ddgst_enable);
|
||||
total_length += pdu->hdr.common.plen;
|
||||
tqpair->host_ddgst_enable,
|
||||
&mapped_length);
|
||||
total_length += mapped_length;
|
||||
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(&tqpair->send_queue)->writev_offset;
|
||||
total_length -= writev_offset;
|
||||
while ((writev_offset > 0) && (iovec_cnt > 0)) {
|
||||
if (writev_offset >= iov->iov_len) {
|
||||
writev_offset -= iov->iov_len;
|
||||
iov++;
|
||||
iovec_cnt--;
|
||||
} else {
|
||||
iov->iov_len -= writev_offset;
|
||||
iov->iov_base = (char *)iov->iov_base + writev_offset;
|
||||
writev_offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
spdk_trace_record(TRACE_TCP_FLUSH_WRITEBUF_START, 0, total_length, 0, iovec_cnt);
|
||||
|
||||
bytes = spdk_sock_writev(tqpair->sock, iov, iovec_cnt);
|
||||
|
Loading…
Reference in New Issue
Block a user