dif: Compute CRC-32C for extended LBA payload

Data digest computation should take extended LBA payload but
could not do yet.

This patch adds an new API spdk_dif_update_crc32c() to compute
CRC-32C value for extended LBA payload.

In the next patch, spdk_dif_update_crc32c will be used in iSCSI
target first.

Change-Id: I327f384bb7dfd8b68279b0acec0ee78a40264a26
Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/456171
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Ziye Yang <ziye.yang@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
Shuhei Matsumoto 2019-05-29 16:01:39 +09:00 committed by Changpeng Liu
parent 85e6f154b8
commit 4fa7987047
3 changed files with 194 additions and 1 deletions

View File

@ -163,6 +163,20 @@ int spdk_dif_generate(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
int spdk_dif_verify(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk);
/**
* Calculate CRC-32C checksum for extended LBA payload.
*
* \param iovs iovec array describing the extended LBA payload.
* \param iovcnt Number of elements in the iovec array.
* \param num_blocks Number of blocks of the payload.
* \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(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
uint32_t *crc32c, const struct spdk_dif_ctx *ctx);
/**
* Copy data and generate DIF for extended LBA payload.
*

View File

@ -33,6 +33,7 @@
#include "spdk/dif.h"
#include "spdk/crc16.h"
#include "spdk/crc32.h"
#include "spdk/endian.h"
#include "spdk/log.h"
#include "spdk/util.h"
@ -597,6 +598,90 @@ spdk_dif_verify(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
}
}
static uint32_t
dif_update_crc32c(struct _dif_sgl *sgl, uint32_t num_blocks,
uint32_t crc32c, const struct spdk_dif_ctx *ctx)
{
uint32_t offset_blocks;
void *buf;
for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
_dif_sgl_get_buf(sgl, &buf, NULL);
crc32c = spdk_crc32c_update(buf, ctx->block_size - ctx->md_size, crc32c);
_dif_sgl_advance(sgl, ctx->block_size);
}
return crc32c;
}
static uint32_t
_dif_update_crc32c_split(struct _dif_sgl *sgl, uint32_t crc32c,
const struct spdk_dif_ctx *ctx)
{
uint32_t data_block_size, offset_in_block, buf_len;
void *buf;
data_block_size = ctx->block_size - ctx->md_size;
offset_in_block = 0;
while (offset_in_block < ctx->block_size) {
_dif_sgl_get_buf(sgl, &buf, &buf_len);
if (offset_in_block < data_block_size) {
buf_len = spdk_min(buf_len, data_block_size - offset_in_block);
crc32c = spdk_crc32c_update(buf, buf_len, crc32c);
} else {
buf_len = spdk_min(buf_len, ctx->block_size - offset_in_block);
}
_dif_sgl_advance(sgl, buf_len);
offset_in_block += buf_len;
}
return crc32c;
}
static uint32_t
dif_update_crc32c_split(struct _dif_sgl *sgl, uint32_t num_blocks,
uint32_t crc32c, const struct spdk_dif_ctx *ctx)
{
uint32_t offset_blocks;
for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
crc32c = _dif_update_crc32c_split(sgl, crc32c, ctx);
}
return crc32c;
}
int
spdk_dif_update_crc32c(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
uint32_t *_crc32c, const struct spdk_dif_ctx *ctx)
{
struct _dif_sgl sgl;
if (_crc32c == NULL) {
return -EINVAL;
}
_dif_sgl_init(&sgl, iovs, iovcnt);
if (!_dif_sgl_is_valid(&sgl, ctx->block_size * num_blocks)) {
SPDK_ERRLOG("Size of iovec array is not valid.\n");
return -EINVAL;
}
if (_dif_sgl_is_bytes_multiple(&sgl, ctx->block_size)) {
*_crc32c = dif_update_crc32c(&sgl, num_blocks, *_crc32c, ctx);
} else {
*_crc32c = dif_update_crc32c_split(&sgl, num_blocks, *_crc32c, ctx);
}
return 0;
}
static void
dif_generate_copy(struct _dif_sgl *src_sgl, struct _dif_sgl *dst_sgl,
uint32_t num_blocks, const struct spdk_dif_ctx *ctx)

View File

@ -1677,6 +1677,99 @@ dif_generate_stream_test(void)
_iov_free_buf(&iov);
}
#define UT_CRC32C_XOR 0xffffffffUL
static void
update_crc32c_test(void)
{
struct spdk_dif_ctx ctx = {};
struct iovec iovs[7];
uint32_t crc32c1, crc32c2, crc32c3, crc32c4;
uint32_t dif_flags;
int i, rc;
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, 8, true, false, SPDK_DIF_TYPE1,
dif_flags, 0, 0, 0, 0);
CU_ASSERT(rc == 0);
/* data[0][255:0] */
_iov_alloc_buf(&iovs[0], 256);
/* data[0][511:256], md[0][0] */
_iov_alloc_buf(&iovs[1], 256 + 1);
/* md[0][4:1] */
_iov_alloc_buf(&iovs[2], 4);
/* md[0][7:5], data[1][122:0] */
_iov_alloc_buf(&iovs[3], 3 + 123);
/* data[1][511:123], md[1][5:0] */
_iov_alloc_buf(&iovs[4], 399 + 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);
/* data[3][511:432], md[3][7:0] */
_iov_alloc_buf(&iovs[6], 80 + 8);
rc = ut_data_pattern_generate(iovs, 7, 512 + 8, 8, 4);
CU_ASSERT(rc == 0);
crc32c1 = UT_CRC32C_XOR;
rc = spdk_dif_update_crc32c(iovs, 7, 4, &crc32c1, &ctx);
CU_ASSERT(rc == 0);
/* Test if DIF doesn't affect CRC for split case. */
rc = spdk_dif_generate(iovs, 7, 4, &ctx);
CU_ASSERT(rc == 0);
crc32c2 = UT_CRC32C_XOR;
rc = spdk_dif_update_crc32c(iovs, 7, 4, &crc32c2, &ctx);
CU_ASSERT(rc == 0);
CU_ASSERT(crc32c1 == crc32c2);
for (i = 0; i < 7; i++) {
_iov_free_buf(&iovs[i]);
}
/* Test if CRC is same regardless of splitting. */
for (i = 0; i < 4; i++) {
_iov_alloc_buf(&iovs[i], 512 + 8);
}
rc = ut_data_pattern_generate(iovs, 4, 512 + 8, 8, 4);
CU_ASSERT(rc == 0);
crc32c3 = UT_CRC32C_XOR;
rc = spdk_dif_update_crc32c(iovs, 4, 4, &crc32c3, &ctx);
CU_ASSERT(rc == 0);
CU_ASSERT(crc32c1 == crc32c3);
/* Test if DIF doesn't affect CRC for non-split case. */
rc = spdk_dif_generate(iovs, 4, 4, &ctx);
CU_ASSERT(rc == 0);
crc32c4 = UT_CRC32C_XOR;
rc = spdk_dif_update_crc32c(iovs, 4, 4, &crc32c4, &ctx);
CU_ASSERT(rc == 0);
CU_ASSERT(crc32c1 == crc32c4);
for (i = 0; i < 4; i++) {
_iov_free_buf(&iovs[i]);
}
}
int
main(int argc, char **argv)
{
@ -1764,7 +1857,8 @@ main(int argc, char **argv)
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_add_test(suite, "dif_generate_stream_test", dif_generate_stream_test) == NULL ||
CU_add_test(suite, "update_crc32c_test", update_crc32c_test) == NULL
) {
CU_cleanup_registry();
return CU_get_error();