diff --git a/include/spdk/dif.h b/include/spdk/dif.h index f78e88fc3..45605f4e4 100644 --- a/include/spdk/dif.h +++ b/include/spdk/dif.h @@ -285,4 +285,19 @@ int spdk_dif_set_md_interleave_iovs(struct iovec *iovs, int num_iovs, uint32_t data_offset, uint32_t data_len, uint32_t *mapped_len, const struct spdk_dif_ctx *ctx); + +/** + * Generate and insert DIF into metadata space for newly read data block. + * + * \param buf Buffer to create extended LBA payload. + * \param buf_len Length of the buffer to create extended LBA payload. + * \param offset Offset to the newly read data. + * \param read_len Length of the newly read data. + * \param ctx DIF context. + * + * \return 0 on success and negated errno otherwise. + */ +int spdk_dif_generate_stream(uint8_t *buf, uint32_t buf_len, + uint32_t offset, uint32_t read_len, + const struct spdk_dif_ctx *ctx); #endif /* SPDK_DIF_H */ diff --git a/lib/util/dif.c b/lib/util/dif.c index 9291daa7a..51ce8d057 100644 --- a/lib/util/dif.c +++ b/lib/util/dif.c @@ -1370,3 +1370,42 @@ spdk_dif_set_md_interleave_iovs(struct iovec *iovs, int num_iovs, return iovcnt; } + +int +spdk_dif_generate_stream(uint8_t *buf, uint32_t buf_len, + uint32_t offset, uint32_t read_len, + const struct spdk_dif_ctx *ctx) +{ + uint32_t data_block_size, offset_blocks, num_blocks, i; + uint16_t guard = 0; + + if (buf == NULL) { + return -EINVAL; + } + + data_block_size = ctx->block_size - ctx->md_size; + + offset_blocks = offset / data_block_size; + read_len += offset % data_block_size; + + offset = offset_blocks * ctx->block_size; + num_blocks = read_len / data_block_size; + + if (offset + num_blocks * ctx->block_size > buf_len) { + return -ERANGE; + } + + buf += offset; + + for (i = 0; i < num_blocks; i++) { + if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) { + guard = spdk_crc16_t10dif(ctx->guard_seed, buf, ctx->guard_interval); + } + + _dif_generate(buf + ctx->guard_interval, guard, offset_blocks + i, ctx); + + buf += ctx->block_size; + } + + 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 761e8855c..0ec3c78b2 100644 --- a/test/unit/lib/util/dif.c/dif_ut.c +++ b/test/unit/lib/util/dif.c/dif_ut.c @@ -1420,6 +1420,9 @@ set_md_interleave_iovs_test(void) read_base = ut_readv(0, 1024, dif_iovs, 4); CU_ASSERT(read_base == 1024); + rc = spdk_dif_generate_stream(buf1, (4096 + 128) * 4, 0, 1024, &ctx); + CU_ASSERT(rc == 0); + rc = spdk_dif_set_md_interleave_iovs(dif_iovs, 4, buf1, (4096 + 128) * 4, read_base, 4096 * 4, &mapped_len, &ctx); CU_ASSERT(rc == 4); @@ -1432,6 +1435,9 @@ set_md_interleave_iovs_test(void) read_base += ut_readv(read_base, 3071, dif_iovs, 4); CU_ASSERT(read_base == 4095); + rc = spdk_dif_generate_stream(buf1, (4096 + 128) * 4, 1024, 3071, &ctx); + CU_ASSERT(rc == 0); + rc = spdk_dif_set_md_interleave_iovs(dif_iovs, 4, buf1, (4096 + 128) * 4, read_base, 4096 * 4, &mapped_len, &ctx); CU_ASSERT(rc == 4); @@ -1444,6 +1450,9 @@ set_md_interleave_iovs_test(void) read_base += ut_readv(read_base, 1 + 4096 * 2 + 512, dif_iovs, 4); CU_ASSERT(read_base == 4096 * 3 + 512); + rc = spdk_dif_generate_stream(buf1, (4096 + 128) * 4, 4095, 1 + 4096 * 2 + 512, &ctx); + CU_ASSERT(rc == 0); + rc = spdk_dif_set_md_interleave_iovs(dif_iovs, 4, buf1, (4096 + 128) * 4, read_base, 4096 * 4, &mapped_len, &ctx); CU_ASSERT(rc == 1); @@ -1453,7 +1462,7 @@ set_md_interleave_iovs_test(void) read_base += ut_readv(read_base, 3584, dif_iovs, 1); CU_ASSERT(read_base == 4096 * 4); - rc = spdk_dif_generate(&iov1, 1, 4, &ctx); + rc = spdk_dif_generate_stream(buf1, (4096 + 128) * 4, 4096 * 3 + 512, 3584, &ctx); CU_ASSERT(rc == 0); /* The second data buffer: @@ -1482,6 +1491,57 @@ set_md_interleave_iovs_test(void) free(buf2); } +static void +dif_generate_stream_test(void) +{ + struct iovec iov; + struct spdk_dif_ctx ctx; + struct spdk_dif_error err_blk; + uint32_t dif_flags; + int rc; + + _iov_alloc_buf(&iov, (512 + 8) * 5); + + rc = ut_data_pattern_generate(&iov, 1, 512, 8, 5); + CU_ASSERT(rc == 0); + + dif_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK | + SPDK_DIF_FLAGS_REFTAG_CHECK; + + rc = spdk_dif_ctx_init(&ctx, 512, 8, true, false, SPDK_DIF_TYPE1, dif_flags, + 22, 0xFFFF, 0x22, GUARD_SEED); + CU_ASSERT(rc == 0); + + rc = spdk_dif_generate_stream(iov.iov_base, (512 + 8) * 5, 0, 511, &ctx); + CU_ASSERT(rc == 0); + + rc = spdk_dif_generate_stream(iov.iov_base, (512 + 8) * 5, 511, 1, &ctx); + CU_ASSERT(rc == 0); + + rc = spdk_dif_generate_stream(iov.iov_base, (512 + 8) * 5, 512, 256, &ctx); + CU_ASSERT(rc == 0); + + rc = spdk_dif_generate_stream(iov.iov_base, (512 + 8) * 5, 768, 512, &ctx); + CU_ASSERT(rc == 0); + + rc = spdk_dif_generate_stream(iov.iov_base, (512 + 8) * 5, 1280, 1024, &ctx); + CU_ASSERT(rc == 0); + + rc = spdk_dif_generate_stream(iov.iov_base, (512 + 8) * 5, 2304, 256, &ctx); + CU_ASSERT(rc == 0); + + rc = spdk_dif_generate_stream(iov.iov_base, (512 + 8) * 5, 2560, 512, &ctx); + CU_ASSERT(rc == -ERANGE); + + rc = spdk_dif_verify(&iov, 1, 5, &ctx, &err_blk); + CU_ASSERT(rc == 0); + + rc = ut_data_pattern_verify(&iov, 1, 512, 8, 5); + CU_ASSERT(rc == 0); + + _iov_free_buf(&iov); +} + int main(int argc, char **argv) { @@ -1566,7 +1626,8 @@ main(int argc, char **argv) dix_sec_4096_md_128_inject_1_2_4_8_multi_iovs_test) == NULL || CU_add_test(suite, "dix_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_test", dix_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_test) == NULL || - CU_add_test(suite, "set_md_interleave_iovs_test", set_md_interleave_iovs_test) == NULL + CU_add_test(suite, "set_md_interleave_iovs_test", set_md_interleave_iovs_test) == NULL || + CU_add_test(suite, "dif_generate_stream_test", dif_generate_stream_test) == NULL ) { CU_cleanup_registry(); return CU_get_error();