From 6db126c24c202b1caf725e1a4e7f79bf15501b76 Mon Sep 17 00:00:00 2001 From: Shuhei Matsumoto Date: Mon, 17 Jun 2019 17:45:55 +0900 Subject: [PATCH] dif: Add spdk_dif_verify_stream to verify DIF by stream fashion Add spdk_dif_verify_stream to verify DIF by stream fashion. spdk_dif_verify_stream utilizes the updated _dif_verify_split. spdk_dif_verify_stream is very similar with spdk_dif_generate_stream(). UT code demonstrates how it is realized. Signed-off-by: Shuhei Matsumoto Change-Id: I1c5d197cf4c0bbc82c8e7f4fa45ddc0b94051058 Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/458330 Reviewed-by: Changpeng Liu Reviewed-by: Darek Stojaczyk Tested-by: SPDK CI Jenkins --- include/spdk/dif.h | 16 ++++++++ lib/util/dif.c | 68 +++++++++++++++++++++++++++++++ test/unit/lib/util/dif.c/dif_ut.c | 63 ++++++++++++++++++++++++++++ 3 files changed, 147 insertions(+) diff --git a/include/spdk/dif.h b/include/spdk/dif.h index aa0a6eefb..17c3ade1f 100644 --- a/include/spdk/dif.h +++ b/include/spdk/dif.h @@ -350,4 +350,20 @@ int spdk_dif_set_md_interleave_iovs(struct iovec *iovs, int iovcnt, int spdk_dif_generate_stream(struct iovec *iovs, int iovcnt, uint32_t data_offset, uint32_t data_len, struct spdk_dif_ctx *ctx); + +/** + * Verify DIF for the to-be-written block of the extended LBA payload. + * + * \param iovs iovec array describing the extended LBA payload. + * \param iovcnt Number of elements in the iovec array. + * \param data_offset Offset to the to-be-written data in the extended LBA payload. + * \param data_len Length of the to-be-written data in the extended LBA payload. + * \param ctx DIF context. + * + * \return 0 on success and negated errno otherwise. + */ +int spdk_dif_verify_stream(struct iovec *iovs, int iovcnt, + uint32_t data_offset, uint32_t data_len, + struct spdk_dif_ctx *ctx, + struct spdk_dif_error *err_blk); #endif /* SPDK_DIF_H */ diff --git a/lib/util/dif.c b/lib/util/dif.c index 0d1014849..59aecb65a 100644 --- a/lib/util/dif.c +++ b/lib/util/dif.c @@ -1575,3 +1575,71 @@ spdk_dif_generate_stream(struct iovec *iovs, int iovcnt, return 0; } + +int +spdk_dif_verify_stream(struct iovec *iovs, int iovcnt, + uint32_t data_offset, uint32_t data_len, + struct spdk_dif_ctx *ctx, + struct spdk_dif_error *err_blk) +{ + uint32_t data_block_size, data_unalign, buf_len, buf_offset; + uint32_t len, offset_in_block, offset_blocks; + uint16_t guard = 0; + struct _dif_sgl sgl; + int rc = 0; + + if (iovs == NULL || iovcnt == 0) { + return -EINVAL; + } + + data_block_size = ctx->block_size - ctx->md_size; + + if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { + guard = ctx->last_guard; + } + + data_unalign = ctx->data_offset % data_block_size; + + /* If the last data block is complete, DIF of the data block is + * verified in this function.; + */ + buf_len = ((data_unalign + data_offset + data_len) / data_block_size) * ctx->block_size + + ((data_unalign + data_offset + data_len) % data_block_size); + buf_len -= data_unalign; + + _dif_sgl_init(&sgl, iovs, iovcnt); + + if (!_dif_sgl_is_valid(&sgl, buf_len)) { + return -ERANGE; + } + + buf_offset = ((data_unalign + data_offset) / data_block_size) * ctx->block_size + + ((data_unalign + data_offset) % data_block_size); + buf_offset -= data_unalign; + + _dif_sgl_advance(&sgl, buf_offset); + buf_len -= buf_offset; + + buf_offset += data_unalign; + + while (buf_len != 0) { + len = spdk_min(buf_len, _to_next_boundary(buf_offset, ctx->block_size)); + offset_in_block = buf_offset % ctx->block_size; + offset_blocks = buf_offset / ctx->block_size; + + rc = _dif_verify_split(&sgl, offset_in_block, len, &guard, offset_blocks, + ctx, err_blk); + if (rc != 0) { + goto error; + } + + buf_len -= len; + buf_offset += len; + } + + if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { + ctx->last_guard = guard; + } +error: + return rc; +} diff --git a/test/unit/lib/util/dif.c/dif_ut.c b/test/unit/lib/util/dif.c/dif_ut.c index 2ef8d4b06..188a4e79c 100644 --- a/test/unit/lib/util/dif.c/dif_ut.c +++ b/test/unit/lib/util/dif.c/dif_ut.c @@ -2079,6 +2079,67 @@ _dif_verify_split_test(void) free(buf); } +static void +dif_verify_stream_multi_segments_test(void) +{ + struct spdk_dif_ctx ctx = {}; + struct spdk_dif_error err_blk = {}; + struct iovec iov = {}; + uint8_t *buf; + 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, 22, 0xFFFF, 0x22, 0, GUARD_SEED); + CU_ASSERT(rc == 0); + + buf = calloc(1, (4096 + 128) * 4); + SPDK_CU_ASSERT_FATAL(buf != NULL); + _iov_set_buf(&iov, buf, (4096 + 128) * 4); + + rc = ut_data_pattern_generate(&iov, 1, 4096 + 128, 128, 4); + CU_ASSERT(rc == 0); + + rc = spdk_dif_generate(&iov, 1, 4, &ctx); + CU_ASSERT(rc == 0); + + /* 1st data segment */ + _iov_set_buf(&iov, buf, 1024); + spdk_dif_ctx_set_data_offset(&ctx, 0); + + rc = spdk_dif_verify_stream(&iov, 1, 0, 1024, &ctx, &err_blk); + CU_ASSERT(rc == 0); + + /* 2nd data segment */ + _iov_set_buf(&iov, buf + 1024, (3072 + 128) + (4096 + 128) * 2 + 512); + spdk_dif_ctx_set_data_offset(&ctx, 1024); + + rc = spdk_dif_verify_stream(&iov, 1, 0, 3072 + 4096 * 2 + 512, &ctx, &err_blk); + CU_ASSERT(rc == 0); + + /* 3rd data segment */ + _iov_set_buf(&iov, buf + (4096 + 128) * 3 + 512, 3584 + 128); + spdk_dif_ctx_set_data_offset(&ctx, 4096 * 3); + + rc = spdk_dif_verify_stream(&iov, 1, 0, 3584, &ctx, &err_blk); + CU_ASSERT(rc == 0); + + /* verify all data segments once */ + _iov_set_buf(&iov, buf, (4096 + 128) * 4); + spdk_dif_ctx_set_data_offset(&ctx, 0); + + rc = spdk_dif_verify(&iov, 1, 4, &ctx, &err_blk); + CU_ASSERT(rc == 0); + + rc = ut_data_pattern_verify(&iov, 1, 4096 + 128, 128, 4); + CU_ASSERT(rc == 0); + + free(buf); +} + #define UT_CRC32C_XOR 0xffffffffUL static void @@ -2266,6 +2327,8 @@ main(int argc, char **argv) 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, "dif_verify_stream_multi_segments_test", + dif_verify_stream_multi_segments_test) == NULL || CU_add_test(suite, "update_crc32c_test", update_crc32c_test) == NULL ) { CU_cleanup_registry();