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:
parent
85e6f154b8
commit
4fa7987047
@ -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.
|
||||
*
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user