nvme/tcp: Support extended LBA payload in nvme_tcp_build_iovs

When pdu->dif_ctx is not NULL, call spdk_dif_set_md_interleave_iovs
in nvme_tcp_build_iovs and nvme_tcp_build_payload_iovs to create
special SGL for the data segment to leave a space of metadata for
each block.

Add UT to verify if the update works correctly.

This update is very similar with the use case of
spdk_dif_set_md_interleave_iovs in iSCSI target.

Change-Id: Ie802cb4b7c541089579ecc2a630fc1e34004da55
Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/458923
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Darek Stojaczyk <dariusz.stojaczyk@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
This commit is contained in:
Shuhei Matsumoto 2019-07-03 13:53:36 +09:00 committed by Changpeng Liu
parent 2c4d313367
commit ced3e20709
2 changed files with 133 additions and 5 deletions

View File

@ -278,6 +278,51 @@ _nvme_tcp_sgl_append_multi(struct _nvme_tcp_sgl *s, struct iovec *iov, int iovcn
return true;
}
static inline uint32_t
_get_iov_array_size(struct iovec *iov, int iovcnt)
{
int i;
uint32_t size = 0;
for (i = 0; i < iovcnt; i++) {
size += iov[i].iov_len;
}
return size;
}
static inline bool
_nvme_tcp_sgl_append_multi_with_md(struct _nvme_tcp_sgl *s, struct iovec *iov, int iovcnt,
uint32_t data_len, const struct spdk_dif_ctx *dif_ctx)
{
int rc;
uint32_t mapped_len = 0;
if (s->iov_offset >= data_len) {
s->iov_offset -= _get_iov_array_size(iov, iovcnt);
} else {
rc = spdk_dif_set_md_interleave_iovs(s->iov, s->iovcnt, iov, iovcnt,
s->iov_offset, data_len - s->iov_offset,
&mapped_len, dif_ctx);
if (rc < 0) {
SPDK_ERRLOG("Failed to setup iovs for DIF insert/strip.\n");
return false;
}
s->total_size += mapped_len;
s->iov_offset = 0;
assert(s->iovcnt >= rc);
s->iovcnt -= rc;
s->iov += rc;
if (s->iovcnt == 0) {
return false;
}
}
return true;
}
static int
nvme_tcp_build_iovs(struct iovec *iov, int iovcnt, struct nvme_tcp_pdu *pdu,
bool hdgst_enable, bool ddgst_enable, uint32_t *_mapped_length)
@ -326,8 +371,15 @@ nvme_tcp_build_iovs(struct iovec *iov, int iovcnt, struct nvme_tcp_pdu *pdu,
/* Data Segment */
plen += pdu->data_len;
if (!_nvme_tcp_sgl_append_multi(sgl, pdu->data_iov, pdu->data_iovcnt)) {
goto end;
if (spdk_likely(!pdu->dif_ctx)) {
if (!_nvme_tcp_sgl_append_multi(sgl, pdu->data_iov, pdu->data_iovcnt)) {
goto end;
}
} else {
if (!_nvme_tcp_sgl_append_multi_with_md(sgl, pdu->data_iov, pdu->data_iovcnt,
pdu->data_len, pdu->dif_ctx)) {
goto end;
}
}
/* Data Digest */
@ -362,8 +414,15 @@ nvme_tcp_build_payload_iovs(struct iovec *iov, int iovcnt, struct nvme_tcp_pdu *
sgl = &pdu->sgl;
_nvme_tcp_sgl_init(sgl, iov, iovcnt, pdu->readv_offset);
if (!_nvme_tcp_sgl_append_multi(sgl, pdu->data_iov, pdu->data_iovcnt)) {
goto end;
if (spdk_likely(!pdu->dif_ctx)) {
if (!_nvme_tcp_sgl_append_multi(sgl, pdu->data_iov, pdu->data_iovcnt)) {
goto end;
}
} else {
if (!_nvme_tcp_sgl_append_multi_with_md(sgl, pdu->data_iov, pdu->data_iovcnt,
pdu->data_len, pdu->dif_ctx)) {
goto end;
}
}
/* Data Digest */

View File

@ -386,6 +386,73 @@ test_nvme_tcp_pdu_set_data_buf_with_md(void)
CU_ASSERT(pdu.data_iov[1].iov_len == 88);
}
static void
test_nvme_tcp_build_iovs_with_md(void)
{
struct nvme_tcp_pdu pdu = {};
struct iovec iovs[11] = {};
struct spdk_dif_ctx dif_ctx = {};
uint32_t mapped_length = 0;
int rc;
rc = spdk_dif_ctx_init(&dif_ctx, 520, 8, true, false, SPDK_DIF_DISABLE, 0,
0, 0, 0, 0, 0);
CU_ASSERT(rc == 0);
pdu.dif_ctx = &dif_ctx;
pdu.hdr.common.pdu_type = SPDK_NVME_TCP_PDU_TYPE_CAPSULE_CMD;
pdu.hdr.common.hlen = sizeof(struct spdk_nvme_tcp_cmd);
pdu.hdr.common.plen = pdu.hdr.common.hlen + SPDK_NVME_TCP_DIGEST_LEN + 512 * 8 +
SPDK_NVME_TCP_DIGEST_LEN;
pdu.data_len = 512 * 8;
pdu.padding_len = 0;
pdu.data_iov[0].iov_base = (void *)0xDEADBEEF;
pdu.data_iov[0].iov_len = (512 + 8) * 8;
pdu.data_iovcnt = 1;
pdu.writev_offset = 0;
rc = nvme_tcp_build_iovs(iovs, 11, &pdu, true, true, &mapped_length);
CU_ASSERT(rc == 10);
CU_ASSERT(iovs[0].iov_base == (void *)&pdu.hdr.raw);
CU_ASSERT(iovs[0].iov_len == sizeof(struct spdk_nvme_tcp_cmd) + SPDK_NVME_TCP_DIGEST_LEN);
CU_ASSERT(iovs[1].iov_base == (void *)0xDEADBEEF);
CU_ASSERT(iovs[1].iov_len == 512);
CU_ASSERT(iovs[2].iov_base == (void *)(0xDEADBEEF + 520));
CU_ASSERT(iovs[2].iov_len == 512);
CU_ASSERT(iovs[3].iov_base == (void *)(0xDEADBEEF + 520 * 2));
CU_ASSERT(iovs[3].iov_len == 512);
CU_ASSERT(iovs[4].iov_base == (void *)(0xDEADBEEF + 520 * 3));
CU_ASSERT(iovs[4].iov_len == 512);
CU_ASSERT(iovs[5].iov_base == (void *)(0xDEADBEEF + 520 * 4));
CU_ASSERT(iovs[5].iov_len == 512);
CU_ASSERT(iovs[6].iov_base == (void *)(0xDEADBEEF + 520 * 5));
CU_ASSERT(iovs[6].iov_len == 512);
CU_ASSERT(iovs[7].iov_base == (void *)(0xDEADBEEF + 520 * 6));
CU_ASSERT(iovs[7].iov_len == 512);
CU_ASSERT(iovs[8].iov_base == (void *)(0xDEADBEEF + 520 * 7));
CU_ASSERT(iovs[8].iov_len == 512);
CU_ASSERT(iovs[9].iov_base == (void *)pdu.data_digest);
CU_ASSERT(iovs[9].iov_len == SPDK_NVME_TCP_DIGEST_LEN);
CU_ASSERT(mapped_length == sizeof(struct spdk_nvme_tcp_cmd) + SPDK_NVME_TCP_DIGEST_LEN +
512 * 8 + SPDK_NVME_TCP_DIGEST_LEN);
pdu.writev_offset += sizeof(struct spdk_nvme_tcp_cmd) + SPDK_NVME_TCP_DIGEST_LEN +
512 * 6 + 256;
rc = nvme_tcp_build_iovs(iovs, 11, &pdu, true, true, &mapped_length);
CU_ASSERT(rc == 3);
CU_ASSERT(iovs[0].iov_base == (void *)(0xDEADBEEF + (520 * 6) + 256));
CU_ASSERT(iovs[0].iov_len == 256);
CU_ASSERT(iovs[1].iov_base == (void *)(0xDEADBEEF + 520 * 7));
CU_ASSERT(iovs[1].iov_len == 512);
CU_ASSERT(iovs[2].iov_base == (void *)pdu.data_digest);
CU_ASSERT(iovs[2].iov_len == SPDK_NVME_TCP_DIGEST_LEN);
CU_ASSERT(mapped_length == 256 + 512 + SPDK_NVME_TCP_DIGEST_LEN);
}
int main(int argc, char **argv)
{
CU_pSuite suite = NULL;
@ -408,7 +475,9 @@ int main(int argc, char **argv)
CU_add_test(suite, "build_sgl_request",
test_nvme_tcp_build_sgl_request) == NULL ||
CU_add_test(suite, "nvme_tcp_pdu_set_data_buf_with_md",
test_nvme_tcp_pdu_set_data_buf_with_md) == NULL
test_nvme_tcp_pdu_set_data_buf_with_md) == NULL ||
CU_add_test(suite, "nvme_tcp_build_iovs_with_md",
test_nvme_tcp_build_iovs_with_md) == NULL
) {
CU_cleanup_registry();
return CU_get_error();