From 7e70c3d18f623f5245f4c80591cf2ca7e609a070 Mon Sep 17 00:00:00 2001 From: Shuhei Matsumoto Date: Tue, 9 Jul 2019 11:58:45 +0900 Subject: [PATCH] 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: Shuhei Matsumoto Change-Id: I55cc45c475d4e86e736f5712baf02fcabfde3c82 Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/461104 Reviewed-by: Changpeng Liu Reviewed-by: Ben Walker Tested-by: SPDK CI Jenkins --- include/spdk/dif.h | 18 +++++ lib/util/dif.c | 116 ++++++++++++++++++++++++++++++ test/unit/lib/util/dif.c/dif_ut.c | 110 +++++++++++++++++++++++++++- 3 files changed, 243 insertions(+), 1 deletion(-) diff --git a/include/spdk/dif.h b/include/spdk/dif.h index ab8d43ef0..7d4006dab 100644 --- a/include/spdk/dif.h +++ b/include/spdk/dif.h @@ -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 */ diff --git a/lib/util/dif.c b/lib/util/dif.c index ba7236986..64bce1487 100644 --- a/lib/util/dif.c +++ b/lib/util/dif.c @@ -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; +} diff --git a/test/unit/lib/util/dif.c/dif_ut.c b/test/unit/lib/util/dif.c/dif_ut.c index 535ef7698..163a05e07 100644 --- a/test/unit/lib/util/dif.c/dif_ut.c +++ b/test/unit/lib/util/dif.c/dif_ut.c @@ -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();