Commit ced3e207 authored by Shuhei Matsumoto's avatar Shuhei Matsumoto Committed by Changpeng Liu
Browse files

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: default avatarShuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/458923


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarDarek Stojaczyk <dariusz.stojaczyk@intel.com>
Reviewed-by: default avatarChangpeng Liu <changpeng.liu@intel.com>
parent 2c4d3133
Loading
Loading
Loading
Loading
+63 −4
Original line number Diff line number Diff line
@@ -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,9 +371,16 @@ nvme_tcp_build_iovs(struct iovec *iov, int iovcnt, struct nvme_tcp_pdu *pdu,

	/* Data Segment */
	plen += pdu->data_len;
	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 */
	if (enable_digest && ddgst_enable) {
@@ -362,9 +414,16 @@ 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 (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 */
	if (ddgst_enable) {
+70 −1
Original line number Diff line number Diff line
@@ -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();