diff --git a/include/spdk/dif.h b/include/spdk/dif.h index 20242d8b5..255e643af 100644 --- a/include/spdk/dif.h +++ b/include/spdk/dif.h @@ -172,11 +172,13 @@ int spdk_dif_generate_copy(struct iovec *iovs, int iovcnt, struct iovec *bounce_ * \param bounce_iov A contiguous buffer forming extended LBA payload. * \param num_blocks Number of blocks of the LBA 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_dif_verify_copy(struct iovec *iovs, int iovcnt, struct iovec *bounce_iov, - uint32_t num_blocks, const struct spdk_dif_ctx *ctx); + uint32_t num_blocks, const struct spdk_dif_ctx *ctx, + struct spdk_dif_error *err_blk); /** * Inject bit flip error to extended LBA payload. diff --git a/lib/util/dif.c b/lib/util/dif.c index a8b671706..e8d5424f0 100644 --- a/lib/util/dif.c +++ b/lib/util/dif.c @@ -705,7 +705,8 @@ spdk_dif_generate_copy(struct iovec *iovs, int iovcnt, struct iovec *bounce_iov, static int dif_verify_copy(struct iovec *iovs, int iovcnt, struct iovec *bounce_iov, - uint32_t num_blocks, const struct spdk_dif_ctx *ctx) + uint32_t num_blocks, const struct spdk_dif_ctx *ctx, + struct spdk_dif_error *err_blk) { struct _iov_iter src_iter, dst_iter; uint32_t offset_blocks, data_block_size; @@ -734,7 +735,7 @@ dif_verify_copy(struct iovec *iovs, int iovcnt, struct iovec *bounce_iov, memcpy(dst, src, data_block_size); } - rc = _dif_verify(src + ctx->guard_interval, guard, offset_blocks, ctx, NULL); + rc = _dif_verify(src + ctx->guard_interval, guard, offset_blocks, ctx, err_blk); if (rc != 0) { return rc; } @@ -749,7 +750,8 @@ dif_verify_copy(struct iovec *iovs, int iovcnt, struct iovec *bounce_iov, static int _dif_verify_copy_split(struct _iov_iter *src_iter, struct _iov_iter *dst_iter, - uint32_t offset_blocks, const struct spdk_dif_ctx *ctx) + uint32_t offset_blocks, const struct spdk_dif_ctx *ctx, + struct spdk_dif_error *err_blk) { uint32_t offset_in_block, dst_len, data_block_size; uint16_t guard; @@ -787,12 +789,13 @@ _dif_verify_copy_split(struct _iov_iter *src_iter, struct _iov_iter *dst_iter, _iov_iter_advance(src_iter, ctx->block_size); - return _dif_verify(src + ctx->guard_interval, guard, offset_blocks, ctx, NULL); + return _dif_verify(src + ctx->guard_interval, guard, offset_blocks, ctx, err_blk); } static int dif_verify_copy_split(struct iovec *iovs, int iovcnt, struct iovec *bounce_iov, - uint32_t num_blocks, const struct spdk_dif_ctx *ctx) + uint32_t num_blocks, const struct spdk_dif_ctx *ctx, + struct spdk_dif_error *err_blk) { struct _iov_iter src_iter, dst_iter; uint32_t offset_blocks; @@ -804,7 +807,7 @@ dif_verify_copy_split(struct iovec *iovs, int iovcnt, struct iovec *bounce_iov, while (offset_blocks < num_blocks && _iov_iter_cont(&src_iter) && _iov_iter_cont(&dst_iter)) { - rc = _dif_verify_copy_split(&src_iter, &dst_iter, offset_blocks, ctx); + rc = _dif_verify_copy_split(&src_iter, &dst_iter, offset_blocks, ctx, err_blk); if (rc != 0) { return rc; } @@ -816,7 +819,8 @@ dif_verify_copy_split(struct iovec *iovs, int iovcnt, struct iovec *bounce_iov, int spdk_dif_verify_copy(struct iovec *iovs, int iovcnt, struct iovec *bounce_iov, - uint32_t num_blocks, const struct spdk_dif_ctx *ctx) + uint32_t num_blocks, const struct spdk_dif_ctx *ctx, + struct spdk_dif_error *err_blk) { uint32_t data_block_size; @@ -833,9 +837,9 @@ spdk_dif_verify_copy(struct iovec *iovs, int iovcnt, struct iovec *bounce_iov, } if (_are_iovs_bytes_multiple(iovs, iovcnt, data_block_size)) { - return dif_verify_copy(iovs, iovcnt, bounce_iov, num_blocks, ctx); + return dif_verify_copy(iovs, iovcnt, bounce_iov, num_blocks, ctx, err_blk); } else { - return dif_verify_copy_split(iovs, iovcnt, bounce_iov, num_blocks, ctx); + return dif_verify_copy_split(iovs, iovcnt, bounce_iov, num_blocks, ctx, err_blk); } } diff --git a/test/unit/lib/util/dif.c/dif_ut.c b/test/unit/lib/util/dif.c/dif_ut.c index 236abf211..20985ddab 100644 --- a/test/unit/lib/util/dif.c/dif_ut.c +++ b/test/unit/lib/util/dif.c/dif_ut.c @@ -747,7 +747,7 @@ dif_copy_gen_and_verify(struct iovec *iovs, int iovcnt, struct iovec *bounce_iov rc = spdk_dif_generate_copy(iovs, iovcnt, bounce_iov, num_blocks, &ctx); CU_ASSERT(rc == 0); - rc = spdk_dif_verify_copy(iovs, iovcnt, bounce_iov, num_blocks, &ctx); + rc = spdk_dif_verify_copy(iovs, iovcnt, bounce_iov, num_blocks, &ctx, NULL); CU_ASSERT(rc == 0); rc = ut_data_pattern_verify(iovs, iovcnt, block_size - md_size, 0, num_blocks); @@ -892,6 +892,121 @@ dif_copy_sec_512_md_8_prchk_7_multi_iovs_complex_splits(void) _iov_free_buf(&bounce_iov); } +static void +_dif_copy_inject_error_and_verify(struct iovec *iovs, int iovcnt, struct iovec *bounce_iov, + uint32_t block_size, uint32_t md_size, uint32_t num_blocks, + uint32_t inject_flags, bool dif_loc) +{ + struct spdk_dif_ctx ctx = {}; + struct spdk_dif_error err_blk = {}; + uint32_t inject_offset = 0, dif_flags; + int rc; + + dif_flags = SPDK_DIF_GUARD_CHECK | SPDK_DIF_APPTAG_CHECK | SPDK_DIF_REFTAG_CHECK; + + rc = ut_data_pattern_generate(iovs, iovcnt, block_size - md_size, 0, num_blocks); + CU_ASSERT(rc == 0); + + rc = spdk_dif_ctx_init(&ctx, block_size, md_size, dif_loc, SPDK_DIF_TYPE1, dif_flags, + 88, 0xFFFF, 0x88); + SPDK_CU_ASSERT_FATAL(rc == 0); + + rc = spdk_dif_generate_copy(iovs, iovcnt, bounce_iov, num_blocks, &ctx); + CU_ASSERT(rc == 0); + + rc = spdk_dif_inject_error(bounce_iov, 1, num_blocks, &ctx, inject_flags, &inject_offset); + CU_ASSERT(rc == 0); + + rc = spdk_dif_verify_copy(iovs, iovcnt, bounce_iov, num_blocks, &ctx, &err_blk); + CU_ASSERT(rc != 0); + if (inject_flags == SPDK_DIF_DATA_ERROR) { + CU_ASSERT(SPDK_DIF_GUARD_ERROR == err_blk.err_type); + } else { + CU_ASSERT(inject_flags == err_blk.err_type); + } + CU_ASSERT(inject_offset == err_blk.err_offset); +} + +static void +dif_copy_inject_error_and_verify(struct iovec *iovs, int iovcnt, struct iovec *bounce_iov, + uint32_t block_size, uint32_t md_size, uint32_t num_blocks, + uint32_t inject_flags) +{ + /* The case that DIF is contained in the first 8 bytes of metadata. */ + _dif_copy_inject_error_and_verify(iovs, iovcnt, bounce_iov, + block_size, md_size, num_blocks, + inject_flags, false); + + /* The case that DIF is contained in the last 8 bytes of metadata. */ + _dif_copy_inject_error_and_verify(iovs, iovcnt, bounce_iov, + block_size, md_size, num_blocks, + inject_flags, true); +} + +static void +dif_copy_sec_4096_md_128_inject_1_2_4_8_multi_iovs_test(void) +{ + struct iovec iovs[4], bounce_iov; + int i, num_blocks; + + num_blocks = 0; + + for (i = 0; i < 4; i++) { + _iov_alloc_buf(&iovs[i], 4096 * (i + 1)); + num_blocks += i + 1; + } + + _iov_alloc_buf(&bounce_iov, (4096 + 128) * num_blocks); + + dif_copy_inject_error_and_verify(iovs, 4, &bounce_iov, 4096 + 128, 128, + num_blocks, SPDK_DIF_GUARD_ERROR); + + dif_copy_inject_error_and_verify(iovs, 4, &bounce_iov, 4096 + 128, 128, + num_blocks, SPDK_DIF_APPTAG_ERROR); + + dif_copy_inject_error_and_verify(iovs, 4, &bounce_iov, 4096 + 128, 128, + num_blocks, SPDK_DIF_REFTAG_ERROR); + + dif_copy_inject_error_and_verify(iovs, 4, &bounce_iov, 4096 + 128, 128, + num_blocks, SPDK_DIF_DATA_ERROR); + + for (i = 0; i < 4; i++) { + _iov_free_buf(&iovs[i]); + } + _iov_free_buf(&bounce_iov); +} + +static void +dif_copy_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_test(void) +{ + struct iovec iovs[4], bounce_iov; + int i; + + _iov_alloc_buf(&iovs[0], 2048); + _iov_alloc_buf(&iovs[1], 2048); + _iov_alloc_buf(&iovs[2], 1); + _iov_alloc_buf(&iovs[3], 4095); + + _iov_alloc_buf(&bounce_iov, (4096 + 128) * 2); + + dif_copy_inject_error_and_verify(iovs, 4, &bounce_iov, 4096 + 128, 128, + 2, SPDK_DIF_GUARD_ERROR); + + dif_copy_inject_error_and_verify(iovs, 4, &bounce_iov, 4096 + 128, 128, + 2, SPDK_DIF_APPTAG_ERROR); + + dif_copy_inject_error_and_verify(iovs, 4, &bounce_iov, 4096 + 128, 128, + 2, SPDK_DIF_REFTAG_ERROR); + + dif_copy_inject_error_and_verify(iovs, 4, &bounce_iov, 4096 + 128, 128, + 2, SPDK_DIF_DATA_ERROR); + + for (i = 0; i < 4; i++) { + _iov_free_buf(&iovs[i]); + } + _iov_free_buf(&bounce_iov); +} + int main(int argc, char **argv) { @@ -955,7 +1070,11 @@ main(int argc, char **argv) CU_add_test(suite, "dif_copy_sec_512_md_8_prchk_7_multi_iovs_split_data", dif_copy_sec_512_md_8_prchk_7_multi_iovs_split_data) == NULL || CU_add_test(suite, "dif_copy_sec_512_md_8_prchk_7_multi_iovs_complex_splits", - dif_copy_sec_512_md_8_prchk_7_multi_iovs_complex_splits) == NULL + dif_copy_sec_512_md_8_prchk_7_multi_iovs_complex_splits) == NULL || + CU_add_test(suite, "dif_copy_sec_4096_md_128_inject_1_2_4_8_multi_iovs_test", + dif_copy_sec_4096_md_128_inject_1_2_4_8_multi_iovs_test) == NULL || + CU_add_test(suite, "dif_copy_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_test", + dif_copy_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_test) == NULL ) { CU_cleanup_registry(); return CU_get_error();