diff --git a/include/spdk/dif.h b/include/spdk/dif.h index 17c3ade1f..e68d77654 100644 --- a/include/spdk/dif.h +++ b/include/spdk/dif.h @@ -366,4 +366,20 @@ 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); + +/** + * Calculate CRC-32C checksum of the specified range in 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 range + * \param data_len Length of the range + * \param crc32c Initial and updated CRC-32C value. + * \param ctx DIF context. + * + * \return 0 on success and negated errno otherwise. + */ +int spdk_dif_update_crc32c_stream(struct iovec *iovs, int iovcnt, + uint32_t data_offset, uint32_t data_len, + uint32_t *crc32c, const struct spdk_dif_ctx *ctx); #endif /* SPDK_DIF_H */ diff --git a/lib/util/dif.c b/lib/util/dif.c index cfc13524c..a176ce021 100644 --- a/lib/util/dif.c +++ b/lib/util/dif.c @@ -1644,3 +1644,40 @@ spdk_dif_verify_stream(struct iovec *iovs, int iovcnt, error: return rc; } + +int +spdk_dif_update_crc32c_stream(struct iovec *iovs, int iovcnt, + uint32_t data_offset, uint32_t data_len, + uint32_t *_crc32c, const struct spdk_dif_ctx *ctx) +{ + uint32_t buf_len = 0, buf_offset = 0, len, offset_in_block; + uint32_t crc32c; + struct _dif_sgl sgl; + int rc; + + if (iovs == NULL || iovcnt == 0) { + return -EINVAL; + } + + crc32c = *_crc32c; + _dif_sgl_init(&sgl, iovs, iovcnt); + + rc = _dif_sgl_setup_stream(&sgl, &buf_offset, &buf_len, data_offset, data_len, ctx); + if (rc != 0) { + return rc; + } + + 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; + + crc32c = _dif_update_crc32c_split(&sgl, offset_in_block, len, crc32c, ctx); + + buf_len -= len; + buf_offset += len; + } + + *_crc32c = crc32c; + + 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 9f066417b..ac7a7f624 100644 --- a/test/unit/lib/util/dif.c/dif_ut.c +++ b/test/unit/lib/util/dif.c/dif_ut.c @@ -2171,7 +2171,7 @@ update_crc32c_test(void) _iov_alloc_buf(&iovs[3], 3 + 123); /* data[1][511:123], md[1][5:0] */ - _iov_alloc_buf(&iovs[4], 399 + 6); + _iov_alloc_buf(&iovs[4], 389 + 6); /* md[1][7:6], data[2][511:0], md[2][7:0], data[3][431:0] */ _iov_alloc_buf(&iovs[5], 2 + 512 + 8 + 432); @@ -2281,6 +2281,68 @@ _dif_update_crc32c_split_test(void) free(buf); } +static void +dif_update_crc32c_stream_multi_segments_test(void) +{ + struct spdk_dif_ctx ctx = {}; + struct iovec iov = {}; + uint8_t *buf; + uint32_t dif_flags, crc32c1, crc32c2; + 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); + + crc32c1 = UT_CRC32C_XOR; + crc32c2 = UT_CRC32C_XOR; + + /* 1st data segment */ + _iov_set_buf(&iov, buf, 1024); + spdk_dif_ctx_set_data_offset(&ctx, 0); + + rc = spdk_dif_update_crc32c_stream(&iov, 1, 0, 1024, &crc32c1, &ctx); + 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_update_crc32c_stream(&iov, 1, 0, 3072 + 4096 * 2 + 512, &crc32c1, &ctx); + 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_update_crc32c_stream(&iov, 1, 0, 3584, &crc32c1, &ctx); + CU_ASSERT(rc == 0); + + /* Update CRC32C for all data segments once */ + _iov_set_buf(&iov, buf, (4096 + 128) * 4); + spdk_dif_ctx_set_data_offset(&ctx, 0); + + rc = spdk_dif_update_crc32c(&iov, 1, 4, &crc32c2, &ctx); + CU_ASSERT(rc == 0); + + CU_ASSERT(crc32c1 == crc32c2); + + free(buf); +} + int main(int argc, char **argv) { @@ -2379,7 +2441,9 @@ main(int argc, char **argv) dif_verify_stream_multi_segments_test) == NULL || CU_add_test(suite, "update_crc32c_test", update_crc32c_test) == NULL || CU_add_test(suite, "_dif_update_crc32c_split_test", - _dif_update_crc32c_split_test) == NULL + _dif_update_crc32c_split_test) == NULL || + CU_add_test(suite, "dif_update_crc32c_stream_multi_segments_test", + dif_update_crc32c_stream_multi_segments_test) == NULL ) { CU_cleanup_registry(); return CU_get_error();