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

dif: Compute CRC-32C for extended LBA payload



Data digest computation should take extended LBA payload but
could not do yet.

This patch adds an new API spdk_dif_update_crc32c() to compute
CRC-32C value for extended LBA payload.

In the next patch, spdk_dif_update_crc32c will be used in iSCSI
target first.

Change-Id: I327f384bb7dfd8b68279b0acec0ee78a40264a26
Signed-off-by: default avatarShuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/456171


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarZiye Yang <ziye.yang@intel.com>
Reviewed-by: default avatarChangpeng Liu <changpeng.liu@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
parent 85e6f154
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -163,6 +163,20 @@ int spdk_dif_generate(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
int spdk_dif_verify(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
		    const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk);

/**
 * Calculate CRC-32C checksum for extended LBA payload.
 *
 * \param iovs iovec array describing the extended LBA payload.
 * \param iovcnt Number of elements in the iovec array.
 * \param num_blocks Number of blocks of the payload.
 * \param crc32c Initial and updated CRC-32C value.
 * \param ctx DIF context.
 *
 * \return 0 on success and negated errno otherwise.
 */
int spdk_dif_update_crc32c(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
			   uint32_t *crc32c, const struct spdk_dif_ctx *ctx);

/**
 * Copy data and generate DIF for extended LBA payload.
 *
+85 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@

#include "spdk/dif.h"
#include "spdk/crc16.h"
#include "spdk/crc32.h"
#include "spdk/endian.h"
#include "spdk/log.h"
#include "spdk/util.h"
@@ -597,6 +598,90 @@ spdk_dif_verify(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
	}
}

static uint32_t
dif_update_crc32c(struct _dif_sgl *sgl, uint32_t num_blocks,
		  uint32_t crc32c,  const struct spdk_dif_ctx *ctx)
{
	uint32_t offset_blocks;
	void *buf;

	for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
		_dif_sgl_get_buf(sgl, &buf, NULL);

		crc32c = spdk_crc32c_update(buf, ctx->block_size - ctx->md_size, crc32c);

		_dif_sgl_advance(sgl, ctx->block_size);
	}

	return crc32c;
}

static uint32_t
_dif_update_crc32c_split(struct _dif_sgl *sgl, uint32_t crc32c,
			 const struct spdk_dif_ctx *ctx)
{
	uint32_t data_block_size, offset_in_block, buf_len;
	void *buf;

	data_block_size = ctx->block_size - ctx->md_size;
	offset_in_block = 0;

	while (offset_in_block < ctx->block_size) {
		_dif_sgl_get_buf(sgl, &buf, &buf_len);

		if (offset_in_block < data_block_size) {
			buf_len = spdk_min(buf_len, data_block_size - offset_in_block);
			crc32c = spdk_crc32c_update(buf, buf_len, crc32c);
		} else {
			buf_len = spdk_min(buf_len, ctx->block_size - offset_in_block);
		}

		_dif_sgl_advance(sgl, buf_len);
		offset_in_block += buf_len;
	}

	return crc32c;
}

static uint32_t
dif_update_crc32c_split(struct _dif_sgl *sgl, uint32_t num_blocks,
			uint32_t crc32c, const struct spdk_dif_ctx *ctx)
{
	uint32_t offset_blocks;

	for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
		crc32c = _dif_update_crc32c_split(sgl, crc32c, ctx);
	}

	return crc32c;
}

int
spdk_dif_update_crc32c(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
		       uint32_t *_crc32c, const struct spdk_dif_ctx *ctx)
{
	struct _dif_sgl sgl;

	if (_crc32c == NULL) {
		return -EINVAL;
	}

	_dif_sgl_init(&sgl, iovs, iovcnt);

	if (!_dif_sgl_is_valid(&sgl, ctx->block_size * num_blocks)) {
		SPDK_ERRLOG("Size of iovec array is not valid.\n");
		return -EINVAL;
	}

	if (_dif_sgl_is_bytes_multiple(&sgl, ctx->block_size)) {
		*_crc32c = dif_update_crc32c(&sgl, num_blocks, *_crc32c, ctx);
	} else {
		*_crc32c = dif_update_crc32c_split(&sgl, num_blocks, *_crc32c, ctx);
	}

	return 0;
}

static void
dif_generate_copy(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
		  uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
+95 −1
Original line number Diff line number Diff line
@@ -1677,6 +1677,99 @@ dif_generate_stream_test(void)
	_iov_free_buf(&iov);
}

#define UT_CRC32C_XOR	0xffffffffUL

static void
update_crc32c_test(void)
{
	struct spdk_dif_ctx ctx = {};
	struct iovec iovs[7];
	uint32_t crc32c1, crc32c2, crc32c3, crc32c4;
	uint32_t dif_flags;
	int i, rc;

	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
		    SPDK_DIF_FLAGS_REFTAG_CHECK;

	rc = spdk_dif_ctx_init(&ctx, 512 + 8, 8, true, false, SPDK_DIF_TYPE1,
			       dif_flags, 0, 0, 0, 0);
	CU_ASSERT(rc == 0);

	/* data[0][255:0] */
	_iov_alloc_buf(&iovs[0], 256);

	/* data[0][511:256], md[0][0] */
	_iov_alloc_buf(&iovs[1], 256 + 1);

	/* md[0][4:1] */
	_iov_alloc_buf(&iovs[2], 4);

	/* md[0][7:5], data[1][122:0] */
	_iov_alloc_buf(&iovs[3], 3 + 123);

	/* data[1][511:123], md[1][5:0] */
	_iov_alloc_buf(&iovs[4], 399 + 6);

	/* md[1][7:6], data[2][511:0], md[2][7:0], data[3][431:0] */
	_iov_alloc_buf(&iovs[5], 2 + 512 + 8 + 432);

	/* data[3][511:432], md[3][7:0] */
	_iov_alloc_buf(&iovs[6], 80 + 8);

	rc = ut_data_pattern_generate(iovs, 7, 512 + 8, 8, 4);
	CU_ASSERT(rc == 0);

	crc32c1 = UT_CRC32C_XOR;

	rc = spdk_dif_update_crc32c(iovs, 7, 4, &crc32c1, &ctx);
	CU_ASSERT(rc == 0);

	/* Test if DIF doesn't affect CRC for split case. */
	rc = spdk_dif_generate(iovs, 7, 4, &ctx);
	CU_ASSERT(rc == 0);

	crc32c2 = UT_CRC32C_XOR;

	rc = spdk_dif_update_crc32c(iovs, 7, 4, &crc32c2, &ctx);
	CU_ASSERT(rc == 0);

	CU_ASSERT(crc32c1 == crc32c2);

	for (i = 0; i < 7; i++) {
		_iov_free_buf(&iovs[i]);
	}

	/* Test if CRC is same regardless of splitting. */
	for (i = 0; i < 4; i++) {
		_iov_alloc_buf(&iovs[i], 512 + 8);
	}

	rc = ut_data_pattern_generate(iovs, 4, 512 + 8, 8, 4);
	CU_ASSERT(rc == 0);

	crc32c3 = UT_CRC32C_XOR;

	rc = spdk_dif_update_crc32c(iovs, 4, 4, &crc32c3, &ctx);
	CU_ASSERT(rc == 0);

	CU_ASSERT(crc32c1 == crc32c3);

	/* Test if DIF doesn't affect CRC for non-split case. */
	rc = spdk_dif_generate(iovs, 4, 4, &ctx);
	CU_ASSERT(rc == 0);

	crc32c4 = UT_CRC32C_XOR;

	rc = spdk_dif_update_crc32c(iovs, 4, 4, &crc32c4, &ctx);
	CU_ASSERT(rc == 0);

	CU_ASSERT(crc32c1 == crc32c4);

	for (i = 0; i < 4; i++) {
		_iov_free_buf(&iovs[i]);
	}
}

int
main(int argc, char **argv)
{
@@ -1764,7 +1857,8 @@ main(int argc, char **argv)
		CU_add_test(suite, "set_md_interleave_iovs_test", set_md_interleave_iovs_test) == NULL ||
		CU_add_test(suite, "set_md_interleave_iovs_split_test",
			    set_md_interleave_iovs_split_test) == NULL ||
		CU_add_test(suite, "dif_generate_stream_test", dif_generate_stream_test) == NULL
		CU_add_test(suite, "dif_generate_stream_test", dif_generate_stream_test) == NULL ||
		CU_add_test(suite, "update_crc32c_test", update_crc32c_test) == NULL
	) {
		CU_cleanup_registry();
		return CU_get_error();