diff --git a/lib/util/dif.c b/lib/util/dif.c index d3a08285e..023ce58d3 100644 --- a/lib/util/dif.c +++ b/lib/util/dif.c @@ -1333,6 +1333,64 @@ dif_set_md_interleave_iovs(struct iovec *iovs, int iovcnt, return iovcnt - sgl.iovcnt; } +static int +dif_set_md_interleave_iovs_split(struct iovec *iovs, int iovcnt, + struct iovec *buf_iovs, int buf_iovcnt, + uint32_t data_offset, uint32_t data_len, + uint32_t *_mapped_len, + const struct spdk_dif_ctx *ctx) +{ + uint32_t data_block_size, head_unalign; + uint32_t num_blocks, offset_blocks; + struct _dif_sgl dif_sgl; + struct _dif_sgl buf_sgl; + uint8_t *buf; + uint32_t buf_len, remaining; + + data_block_size = ctx->block_size - ctx->md_size; + num_blocks = data_len / data_block_size; + + _dif_sgl_init(&dif_sgl, iovs, iovcnt); + _dif_sgl_init(&buf_sgl, buf_iovs, buf_iovcnt); + + if (!_dif_sgl_is_valid(&buf_sgl, num_blocks * ctx->block_size)) { + SPDK_ERRLOG("Buffer overflow will occur.\n"); + return -ERANGE; + } + + offset_blocks = data_offset / data_block_size; + head_unalign = data_offset % data_block_size; + + _dif_sgl_fast_forward(&buf_sgl, offset_blocks * ctx->block_size); + + while (offset_blocks < num_blocks) { + _dif_sgl_fast_forward(&buf_sgl, head_unalign); + + remaining = data_block_size - head_unalign; + while (remaining != 0) { + _dif_sgl_get_buf(&buf_sgl, (void *)&buf, &buf_len); + buf_len = spdk_min(buf_len, remaining); + + if (!_dif_sgl_append(&dif_sgl, buf, buf_len)) { + goto end; + } + _dif_sgl_advance(&buf_sgl, buf_len); + remaining -= buf_len; + } + _dif_sgl_fast_forward(&buf_sgl, ctx->md_size); + offset_blocks++; + + head_unalign = 0; + } + +end: + if (_mapped_len != NULL) { + *_mapped_len = dif_sgl.total_size; + } + + return iovcnt - dif_sgl.iovcnt; +} + int spdk_dif_set_md_interleave_iovs(struct iovec *iovs, int iovcnt, struct iovec *buf_iovs, int buf_iovcnt, @@ -1363,7 +1421,8 @@ spdk_dif_set_md_interleave_iovs(struct iovec *iovs, int iovcnt, buf_iovs[0].iov_base, buf_iovs[0].iov_len, data_offset, data_len, _mapped_len, ctx); } else { - return -EINVAL; + return dif_set_md_interleave_iovs_split(iovs, iovcnt, buf_iovs, buf_iovcnt, + data_offset, data_len, _mapped_len, ctx); } } diff --git a/test/unit/lib/util/dif.c/dif_ut.c b/test/unit/lib/util/dif.c/dif_ut.c index 304460d9c..0c43561f3 100644 --- a/test/unit/lib/util/dif.c/dif_ut.c +++ b/test/unit/lib/util/dif.c/dif_ut.c @@ -1493,6 +1493,96 @@ set_md_interleave_iovs_test(void) free(buf2); } +static void +set_md_interleave_iovs_split_test(void) +{ + struct spdk_dif_ctx ctx = {}; + struct iovec iovs1[7], dif_iovs[8]; + uint32_t dif_check_flags, mapped_len = 0, read_base = 0; + int rc, i; + + dif_check_flags = SPDK_DIF_FLAGS_GUARD_CHECK | SPDK_DIF_FLAGS_APPTAG_CHECK | + SPDK_DIF_FLAGS_REFTAG_CHECK; + + rc = spdk_dif_ctx_init(&ctx, 512 + 8, 8, true, false, SPDK_DIF_TYPE1, + dif_check_flags, 22, 0xFFFF, 0x22, GUARD_SEED); + CU_ASSERT(rc == 0); + + /* The first SGL data buffer: + * - Create iovec array to leave a space for metadata for each block + * - Split vectored read and so creating iovec array is done before every vectored read. + */ + _iov_alloc_buf(&iovs1[0], 512 + 8 + 128); + _iov_alloc_buf(&iovs1[1], 128); + _iov_alloc_buf(&iovs1[2], 256 + 8); + _iov_alloc_buf(&iovs1[3], 100); + _iov_alloc_buf(&iovs1[4], 412 + 5); + _iov_alloc_buf(&iovs1[5], 3 + 300); + _iov_alloc_buf(&iovs1[6], 212 + 8); + + rc = spdk_dif_set_md_interleave_iovs(dif_iovs, 8, iovs1, 7, + 0, 512 * 4, &mapped_len, &ctx); + CU_ASSERT(rc == 8); + CU_ASSERT(mapped_len == 512 * 4); + CU_ASSERT(_iov_check(&dif_iovs[0], iovs1[0].iov_base, 512) == true); + CU_ASSERT(_iov_check(&dif_iovs[1], iovs1[0].iov_base + 512 + 8, 128) == true); + CU_ASSERT(_iov_check(&dif_iovs[2], iovs1[1].iov_base, 128) == true); + CU_ASSERT(_iov_check(&dif_iovs[3], iovs1[2].iov_base, 256) == true); + CU_ASSERT(_iov_check(&dif_iovs[4], iovs1[3].iov_base, 100) == true); + CU_ASSERT(_iov_check(&dif_iovs[5], iovs1[4].iov_base, 412) == true); + CU_ASSERT(_iov_check(&dif_iovs[6], iovs1[5].iov_base + 3, 300) == true); + CU_ASSERT(_iov_check(&dif_iovs[7], iovs1[6].iov_base, 212) == true); + + read_base = ut_readv(0, 128, dif_iovs, 8); + CU_ASSERT(read_base == 128); + + rc = spdk_dif_set_md_interleave_iovs(dif_iovs, 8, iovs1, 7, + read_base, 512 * 4, &mapped_len, &ctx); + CU_ASSERT(rc == 8); + CU_ASSERT(mapped_len == 384 + 512 * 3); + CU_ASSERT(_iov_check(&dif_iovs[0], iovs1[0].iov_base + 128, 384) == true); + CU_ASSERT(_iov_check(&dif_iovs[1], iovs1[0].iov_base + 512 + 8, 128) == true); + CU_ASSERT(_iov_check(&dif_iovs[2], iovs1[1].iov_base, 128) == true); + CU_ASSERT(_iov_check(&dif_iovs[3], iovs1[2].iov_base, 256) == true); + CU_ASSERT(_iov_check(&dif_iovs[4], iovs1[3].iov_base, 100) == true); + CU_ASSERT(_iov_check(&dif_iovs[5], iovs1[4].iov_base, 412) == true); + CU_ASSERT(_iov_check(&dif_iovs[6], iovs1[5].iov_base + 3, 300) == true); + CU_ASSERT(_iov_check(&dif_iovs[7], iovs1[6].iov_base, 212) == true); + + read_base += ut_readv(read_base, 383, dif_iovs, 8); + CU_ASSERT(read_base == 511); + + rc = spdk_dif_set_md_interleave_iovs(dif_iovs, 8, iovs1, 7, + read_base, 512 * 4, &mapped_len, &ctx); + CU_ASSERT(rc == 8); + CU_ASSERT(mapped_len == 1 + 512 * 3); + CU_ASSERT(_iov_check(&dif_iovs[0], iovs1[0].iov_base + 511, 1) == true); + CU_ASSERT(_iov_check(&dif_iovs[1], iovs1[0].iov_base + 512 + 8, 128) == true); + CU_ASSERT(_iov_check(&dif_iovs[2], iovs1[1].iov_base, 128) == true); + CU_ASSERT(_iov_check(&dif_iovs[3], iovs1[2].iov_base, 256) == true); + CU_ASSERT(_iov_check(&dif_iovs[4], iovs1[3].iov_base, 100) == true); + CU_ASSERT(_iov_check(&dif_iovs[5], iovs1[4].iov_base, 412) == true); + CU_ASSERT(_iov_check(&dif_iovs[6], iovs1[5].iov_base + 3, 300) == true); + CU_ASSERT(_iov_check(&dif_iovs[7], iovs1[6].iov_base, 212) == true); + + read_base += ut_readv(read_base, 1 + 512 * 2 + 128, dif_iovs, 8); + CU_ASSERT(read_base == 512 * 3 + 128); + + rc = spdk_dif_set_md_interleave_iovs(dif_iovs, 8, iovs1, 7, + read_base, 512 * 4, &mapped_len, &ctx); + CU_ASSERT(rc == 2); + CU_ASSERT(mapped_len == 384); + CU_ASSERT(_iov_check(&dif_iovs[0], iovs1[5].iov_base + 3 + 128, 172) == true); + CU_ASSERT(_iov_check(&dif_iovs[1], iovs1[6].iov_base, 212) == true); + + read_base += ut_readv(read_base, 384, dif_iovs, 8); + CU_ASSERT(read_base == 512 * 4); + + for (i = 0; i < 7; i++) { + _iov_free_buf(&iovs1[i]); + } +} + static void dif_generate_stream_test(void) { @@ -1629,6 +1719,8 @@ main(int argc, char **argv) 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_split_test", + set_md_interleave_iovs_split_test) == NULL || CU_add_test(suite, "dif_generate_stream_test", dif_generate_stream_test) == NULL ) { CU_cleanup_registry();