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

dif: Process partial data block properly in _dif_verify_split



For NVMe/TCP target, data segments which correspond to H2C or C2H PDU
will have any alignment, and _dif_verify_split will have to process
partial data block, particularly the following types:
- start and end are both within a data block.
- start is within a data block, and end is at the end of a block

On the other hand, _dif_verify_split had assumed that passed block
is always a complete block.

According to the refactoring done in the last patch, this patch
exposes offset_in_block, data_len, and guard as parameters of
_dif_verify_split() and make _dif_verify_split() process the
above two types of data block properly.

The next patch will utilize the updated _dif_verify_split to
add spdk_dif_verify_stream().

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


Reviewed-by: default avatarChangpeng Liu <changpeng.liu@intel.com>
Reviewed-by: default avatarDarek Stojaczyk <dariusz.stojaczyk@intel.com>
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
parent d69dc28b
Loading
Loading
Loading
Loading
+37 −10
Original line number Diff line number Diff line
@@ -579,22 +579,27 @@ dif_verify(struct _dif_sgl *sgl, uint32_t num_blocks,
}

static int
_dif_verify_split(struct _dif_sgl *sgl, uint32_t offset_blocks,
_dif_verify_split(struct _dif_sgl *sgl, uint32_t offset_in_block, uint32_t data_len,
		  uint16_t *_guard, uint32_t offset_blocks,
		  const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk)
{
	uint32_t offset_in_block, offset_in_dif, buf_len;
	uint32_t offset_in_dif, buf_len;
	void *buf;
	uint16_t guard = 0;
	uint16_t guard;
	struct spdk_dif dif = {};
	int rc;

	if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
		guard = ctx->guard_seed;
	}
	offset_in_block = 0;
	assert(_guard != NULL);
	assert(offset_in_block < ctx->guard_interval);
	assert(offset_in_block + data_len < ctx->guard_interval ||
	       offset_in_block + data_len == ctx->block_size);

	guard = *_guard;

	/* Compute CRC over split logical block data. */
	while (offset_in_block < ctx->guard_interval) {
	while (data_len != 0 && offset_in_block < ctx->guard_interval) {
		_dif_sgl_get_buf(sgl, &buf, &buf_len);
		buf_len = spdk_min(buf_len, data_len);
		buf_len = spdk_min(buf_len, ctx->guard_interval - offset_in_block);

		if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
@@ -603,6 +608,12 @@ _dif_verify_split(struct _dif_sgl *sgl, uint32_t offset_blocks,

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

	if (offset_in_block < ctx->guard_interval) {
		*_guard = guard;
		return 0;
	}

	/* Copy the split DIF field to the temporary DIF buffer, and then
@@ -622,7 +633,17 @@ _dif_verify_split(struct _dif_sgl *sgl, uint32_t offset_blocks,
		offset_in_block += buf_len;
	}

	return _dif_verify(&dif, guard, offset_blocks, ctx, err_blk);
	rc = _dif_verify(&dif, guard, offset_blocks, ctx, err_blk);
	if (rc != 0) {
		return rc;
	}

	if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
		guard = ctx->guard_seed;
	}

	*_guard = guard;
	return 0;
}

static int
@@ -630,10 +651,16 @@ dif_verify_split(struct _dif_sgl *sgl, uint32_t num_blocks,
		 const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk)
{
	uint32_t offset_blocks;
	uint16_t guard = 0;
	int rc;

	if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
		guard = ctx->guard_seed;
	}

	for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
		rc = _dif_verify_split(sgl, offset_blocks, ctx, err_blk);
		rc = _dif_verify_split(sgl, 0, ctx->block_size, &guard, offset_blocks,
				       ctx, err_blk);
		if (rc != 0) {
			return rc;
		}
+65 −0
Original line number Diff line number Diff line
@@ -2015,6 +2015,70 @@ set_md_interleave_iovs_multi_segments_test(void)
	free(buf2);
}

static void
_dif_verify_split_test(void)
{
	struct spdk_dif_ctx ctx = {};
	struct spdk_dif_error err_blk = {};
	struct iovec iov;
	uint8_t *buf;
	struct _dif_sgl sgl;
	uint16_t guard = 0, prev_guard = 0;
	uint32_t dif_flags;
	int rc;

	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
		    SPDK_DIF_FLAGS_REFTAG_CHECK;

	rc = spdk_dif_ctx_init(&ctx, 4096 + 128, 128, true, false, SPDK_DIF_TYPE1,
			       dif_flags, 0, 0, 0, 0, GUARD_SEED);
	CU_ASSERT(rc == 0);

	buf = calloc(1, 4096 + 128);
	SPDK_CU_ASSERT_FATAL(buf != NULL);
	_iov_set_buf(&iov, buf, 4096 + 128);

	rc = ut_data_pattern_generate(&iov, 1, 4096 + 128, 128, 1);
	CU_ASSERT(rc == 0);

	_dif_sgl_init(&sgl, &iov, 1);

	dif_generate(&sgl, 1, &ctx);

	_dif_sgl_init(&sgl, &iov, 1);

	guard = GUARD_SEED;
	prev_guard = GUARD_SEED;

	rc = _dif_verify_split(&sgl, 0, 1000, &guard, 0, &ctx, &err_blk);
	CU_ASSERT(rc == 0);
	CU_ASSERT(guard == spdk_crc16_t10dif(prev_guard, buf, 1000));
	CU_ASSERT(sgl.iov_offset == 1000);

	prev_guard = guard;

	rc = _dif_verify_split(&sgl, 1000, 3000, &guard, 0, &ctx, &err_blk);
	CU_ASSERT(rc == 0);
	CU_ASSERT(guard == spdk_crc16_t10dif(prev_guard, buf + 1000, 3000));
	CU_ASSERT(sgl.iov_offset == 4000);

	rc = _dif_verify_split(&sgl, 4000, 96 + 128, &guard, 0, &ctx, &err_blk);
	CU_ASSERT(rc == 0);
	CU_ASSERT(guard == GUARD_SEED);
	CU_ASSERT(sgl.iov_offset == 0);
	CU_ASSERT(sgl.iovcnt == 0);

	_dif_sgl_init(&sgl, &iov, 1);

	rc = dif_verify(&sgl, 1, &ctx, &err_blk);
	CU_ASSERT(rc == 0);

	rc = ut_data_pattern_verify(&iov, 1, 4096 + 128, 128, 1);
	CU_ASSERT(rc == 0);

	free(buf);
}

#define UT_CRC32C_XOR	0xffffffffUL

static void
@@ -2201,6 +2265,7 @@ main(int argc, char **argv)
		CU_add_test(suite, "_dif_generate_split_test", _dif_generate_split_test) == NULL ||
		CU_add_test(suite, "set_md_interleave_iovs_multi_segments_test",
			    set_md_interleave_iovs_multi_segments_test) == NULL ||
		CU_add_test(suite, "_dif_verify_split_test", _dif_verify_split_test) == NULL ||
		CU_add_test(suite, "update_crc32c_test", update_crc32c_test) == NULL
	) {
		CU_cleanup_registry();