Commit 7e70c3d1 authored by Shuhei Matsumoto's avatar Shuhei Matsumoto Committed by Ben Walker
Browse files

dif: Add spdk_dix_remap_ref_tag to remap ref. tag for separate metadata payload



When using stacked virtual bdev (e.g. split virtual bdev), block
address space will be remapped during I/O processing and so reference
tag will have to be remapped accordingly.

This patch adds an API, spdk_dif_remap_ref_tag to satisfy the case.

UT code is added together in this patch.

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


Reviewed-by: default avatarChangpeng Liu <changpeng.liu@intel.com>
Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
parent f4a62a39
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -436,4 +436,22 @@ uint32_t spdk_dif_get_length_with_md(uint32_t data_len, const struct spdk_dif_ct
int spdk_dif_remap_ref_tag(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
			   const struct spdk_dif_ctx *dif_ctx,
			   struct spdk_dif_error *err_blk);

/**
 * Remap reference tag for separate metadata payload.
 *
 * When using stacked virtual bdev (e.g. split virtual bdev), block address space for I/O
 * will be remapped during I/O processing and so reference tag will have to be remapped
 * accordingly. This patch is for that case.
 *
 * \param md_iov A contiguous buffer for metadata.
 * \param num_blocks Number of blocks of the payload.
 * \param ctx DIF context.
 * \param err_blk Error information of the block in which DIF error is found.
 *
 * \return 0 on success and negated errno otherwise.
 */
int spdk_dix_remap_ref_tag(struct iovec *md_iov, uint32_t num_blocks,
			   const struct spdk_dif_ctx *dif_ctx,
			   struct spdk_dif_error *err_blk);
#endif /* SPDK_DIF_H */
+116 −0
Original line number Diff line number Diff line
@@ -1881,3 +1881,119 @@ spdk_dif_remap_ref_tag(struct iovec *iovs, int iovcnt, uint32_t num_blocks,

	return 0;
}

static int
_dix_remap_ref_tag(struct _dif_sgl *md_sgl, uint32_t offset_blocks,
		   const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk)
{
	uint32_t expected = 0, _actual, remapped;
	uint8_t *md_buf;
	struct spdk_dif *dif;

	_dif_sgl_get_buf(md_sgl, (void *)&md_buf, NULL);

	dif = (struct spdk_dif *)(md_buf + ctx->guard_interval);

	switch (ctx->dif_type) {
	case SPDK_DIF_TYPE1:
	case SPDK_DIF_TYPE2:
		/* If Type 1 or 2 is used, then all DIF checks are disabled when
		 * the Application Tag is 0xFFFF.
		 */
		if (dif->app_tag == 0xFFFF) {
			goto end;
		}
		break;
	case SPDK_DIF_TYPE3:
		/* If Type 3 is used, then all DIF checks are disabled when the
		 * Application Tag is 0xFFFF and the Reference Tag is 0xFFFFFFFF.
		 */
		if (dif->app_tag == 0xFFFF && dif->ref_tag == 0xFFFFFFFF) {
			goto end;
		}
		break;
	default:
		break;
	}

	/* For type 1 and 2, the Reference Tag is incremented for each
	 * subsequent logical block. For type 3, the Reference Tag
	 * remains the same as the initialReference Tag.
	 */
	if (ctx->dif_type != SPDK_DIF_TYPE3) {
		expected = ctx->init_ref_tag + ctx->ref_tag_offset + offset_blocks;
		remapped = ctx->remapped_init_ref_tag + ctx->ref_tag_offset + offset_blocks;
	} else {
		remapped = ctx->remapped_init_ref_tag;
	}

	/* Verify the stored Reference Tag. */
	switch (ctx->dif_type) {
	case SPDK_DIF_TYPE1:
	case SPDK_DIF_TYPE2:
		/* Compare the DIF Reference Tag field to the computed Reference Tag.
		 * The computed Reference Tag will be the least significant 4 bytes
		 * of the LBA when Type 1 is used, and application specific value
		 * if Type 2 is used.
		 */
		_actual = from_be32(&dif->ref_tag);
		if (_actual != expected) {
			_dif_error_set(err_blk, SPDK_DIF_REFTAG_ERROR, expected,
				       _actual, offset_blocks);
			SPDK_ERRLOG("Failed to compare Ref Tag: LBA=%" PRIu32 "," \
				    " Expected=%x, Actual=%x\n",
				    expected, expected, _actual);
			return -1;
		}
		break;
	case SPDK_DIF_TYPE3:
		/* For type 3, the computed Reference Tag remains unchanged.
		 * Hence ignore the Reference Tag field.
		 */
		break;
	default:
		break;
	}

	/* Update the stored Reference Tag to the remapped one. */
	to_be32(&dif->ref_tag, remapped);

end:
	_dif_sgl_advance(md_sgl, ctx->md_size);

	return 0;
}

int
spdk_dix_remap_ref_tag(struct iovec *md_iov, uint32_t num_blocks,
		       const struct spdk_dif_ctx *ctx,
		       struct spdk_dif_error *err_blk)
{
	struct _dif_sgl md_sgl;
	uint32_t offset_blocks;
	int rc;

	_dif_sgl_init(&md_sgl, md_iov, 1);

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

	if (_dif_is_disabled(ctx->dif_type)) {
		return 0;
	}

	if (!(ctx->dif_flags & SPDK_DIF_FLAGS_REFTAG_CHECK)) {
		return 0;
	}

	for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
		rc = _dix_remap_ref_tag(&md_sgl, offset_blocks, ctx, err_blk);
		if (rc != 0) {
			return rc;
		}
	}

	return 0;
}
+109 −1
Original line number Diff line number Diff line
@@ -2490,6 +2490,110 @@ dif_sec_4096_md_128_prchk_7_multi_iovs_complex_splits_remap_test(void)
	}
}

static void
dix_generate_remap_and_verify(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
			      uint32_t block_size, uint32_t md_size, uint32_t num_blocks,
			      bool dif_loc, enum spdk_dif_type dif_type, uint32_t dif_flags,
			      uint32_t init_ref_tag, uint32_t remapped_init_ref_tag,
			      uint16_t apptag_mask, uint16_t app_tag)
{
	struct spdk_dif_ctx ctx;
	int rc;

	rc = ut_data_pattern_generate(iovs, iovcnt, block_size, 0, num_blocks);
	CU_ASSERT(rc == 0);

	rc = spdk_dif_ctx_init(&ctx, block_size, md_size, false, dif_loc, dif_type, dif_flags,
			       init_ref_tag, apptag_mask, app_tag, 0, GUARD_SEED);
	CU_ASSERT(rc == 0);

	rc = spdk_dix_generate(iovs, iovcnt, md_iov, num_blocks, &ctx);
	CU_ASSERT(rc == 0);

	spdk_dif_ctx_set_remapped_init_ref_tag(&ctx, remapped_init_ref_tag);

	rc = spdk_dix_remap_ref_tag(md_iov, num_blocks, &ctx, NULL);
	CU_ASSERT(rc == 0);

	rc = spdk_dif_ctx_init(&ctx, block_size, md_size, false, dif_loc, dif_type, dif_flags,
			       remapped_init_ref_tag, apptag_mask, app_tag, 0, GUARD_SEED);
	CU_ASSERT(rc == 0);

	rc = spdk_dix_verify(iovs, iovcnt, md_iov, num_blocks, &ctx, NULL);
	CU_ASSERT(rc == 0);

	rc = ut_data_pattern_verify(iovs, iovcnt, block_size, 0, num_blocks);
	CU_ASSERT(rc == 0);
}

static void
dix_sec_4096_md_128_prchk_7_multi_iovs_remap(void)
{
	struct iovec iovs[4], md_iov;
	uint32_t dif_flags;
	int i, num_blocks;

	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
		    SPDK_DIF_FLAGS_REFTAG_CHECK;

	num_blocks = 0;

	for (i = 0; i < 4; i++) {
		_iov_alloc_buf(&iovs[i], 4096 * (i + 1));
		num_blocks += i + 1;
	}
	_iov_alloc_buf(&md_iov, 128 * num_blocks);

	dix_generate_remap_and_verify(iovs, 4, &md_iov, 4096, 128, num_blocks, false, SPDK_DIF_TYPE1,
				      dif_flags, 22, 99, 0xFFFF, 0x22);
	dix_generate_remap_and_verify(iovs, 4, &md_iov, 4096, 128, num_blocks, true, SPDK_DIF_TYPE1,
				      dif_flags, 22, 99, 0xFFFF, 0x22);

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

static void
dix_sec_512_md_8_prchk_7_multi_iovs_complex_splits_remap(void)
{
	struct iovec iovs[6], md_iov;
	uint32_t dif_flags;
	int i;

	dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK |
		    SPDK_DIF_FLAGS_REFTAG_CHECK;

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

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

	/* data[1][382:256] */
	_iov_alloc_buf(&iovs[2], 128);

	/* data[1][383] */
	_iov_alloc_buf(&iovs[3], 1);

	/* data[1][510:384] */
	_iov_alloc_buf(&iovs[4], 126);

	/* data[1][511], data[2][511:0], data[3][511:0] */
	_iov_alloc_buf(&iovs[5], 1 + 512 * 2);

	_iov_alloc_buf(&md_iov, 8 * 4);

	dix_generate_remap_and_verify(iovs, 6, &md_iov, 512, 8, 4, false, SPDK_DIF_TYPE1,
				      dif_flags, 22, 99, 0xFFFF, 0x22);

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

int
main(int argc, char **argv)
{
@@ -2595,7 +2699,11 @@ main(int argc, char **argv)
		CU_add_test(suite, "dif_sec_4096_md_128_prchk_7_multi_iovs_remap_test",
			    dif_sec_4096_md_128_prchk_7_multi_iovs_remap_test) == NULL ||
		CU_add_test(suite, "dif_sec_4096_md_128_prchk_7_multi_iovs_complex_splits_remap_test",
			    dif_sec_4096_md_128_prchk_7_multi_iovs_complex_splits_remap_test) == NULL
			    dif_sec_4096_md_128_prchk_7_multi_iovs_complex_splits_remap_test) == NULL ||
		CU_add_test(suite, "dix_sec_4096_md_128_prchk_7_multi_iovs_remap",
			    dix_sec_4096_md_128_prchk_7_multi_iovs_remap) == NULL ||
		CU_add_test(suite, "dix_sec_512_md_8_prchk_7_multi_iovs_complex_splits_remap",
			    dix_sec_512_md_8_prchk_7_multi_iovs_complex_splits_remap) == NULL
	) {
		CU_cleanup_registry();
		return CU_get_error();