dix: Return DIF error information at verification for separate metadata payload

For separate metadata payload, Introduce a struct to collect DIF error
information and pass the reference to the struct to bit-flip error injection
and verification.

This change will make logging of DIF error and comparison between
injection and verification possible for separate metadata payload.

Merging this patch to the previous is possible but add this as a separate patch
to reduce the patch size.

Change-Id: Ifce2130e902bc090cbe205fa8df12559739ced57
Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-on: https://review.gerrithub.io/c/435097
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Chandler-Test-Pool: SPDK Automated Test System <sys_sgsw@intel.com>
This commit is contained in:
Shuhei Matsumoto 2019-01-08 18:08:08 +09:00 committed by Jim Harris
parent 65624bd5e4
commit ed45352564
3 changed files with 203 additions and 12 deletions

View File

@ -221,9 +221,29 @@ int spdk_dix_generate(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
* \param md_iov A contiguous buffer for metadata.
* \param num_blocks Number of blocks of the separate metadata payload.
* \param ctx DIF context.
* \param err_blk Error information of the block in which DIF error is found.
*
* \return 0 on success and negated errno otherwise.
*/
int spdk_dix_verify(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
uint32_t num_blocks, const struct spdk_dif_ctx *ctx);
uint32_t num_blocks, const struct spdk_dif_ctx *ctx,
struct spdk_dif_error *err_blk);
/**
* Inject bit flip error to separate metadata payload.
*
* \param iovs iovec array describing the extended LBA payload.
* \param iovcnt Number of elements in the iovec array.
* \param md_iov A contiguous buffer for metadata.
* \param num_blocks Number of blocks of the payload.
* \param ctx DIF context.
* \param inject_flags Flag to specify the action of error injection.
* \param inject_offset Offset, in blocks, to which error is injected.
* If multiple error is injected, only the last injection is stored.
*
* \return 0 on success and negated errno otherwise including no metadata.
*/
int spdk_dix_inject_error(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
uint32_t num_blocks, const struct spdk_dif_ctx *ctx,
uint32_t inject_flags, uint32_t *inject_offset);
#endif /* SPDK_DIF_H */

View File

@ -1114,7 +1114,8 @@ spdk_dix_generate(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
static int
dix_verify(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
uint32_t num_blocks, const struct spdk_dif_ctx *ctx,
struct spdk_dif_error *err_blk)
{
struct _iov_iter data_iter, md_iter;
uint32_t offset_blocks;
@ -1138,7 +1139,7 @@ dix_verify(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
guard = spdk_crc16_t10dif(guard, md_buf, ctx->guard_interval);
}
rc = _dif_verify(md_buf + ctx->guard_interval, guard, offset_blocks, ctx, NULL);
rc = _dif_verify(md_buf + ctx->guard_interval, guard, offset_blocks, ctx, err_blk);
if (rc != 0) {
return rc;
}
@ -1153,7 +1154,8 @@ dix_verify(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
static int
_dix_verify_split(struct _iov_iter *data_iter, struct _iov_iter *md_iter,
uint32_t offset_blocks, const struct spdk_dif_ctx *ctx)
uint32_t offset_blocks, const struct spdk_dif_ctx *ctx,
struct spdk_dif_error *err_blk)
{
uint32_t offset_in_block, data_buf_len;
uint16_t guard;
@ -1182,12 +1184,13 @@ _dix_verify_split(struct _iov_iter *data_iter, struct _iov_iter *md_iter,
_iov_iter_advance(md_iter, ctx->md_size);
return _dif_verify(md_buf + ctx->guard_interval, guard, offset_blocks, ctx, NULL);
return _dif_verify(md_buf + ctx->guard_interval, guard, offset_blocks, ctx, err_blk);
}
static int
dix_verify_split(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
uint32_t num_blocks, const struct spdk_dif_ctx *ctx,
struct spdk_dif_error *err_blk)
{
struct _iov_iter data_iter, md_iter;
uint32_t offset_blocks;
@ -1199,7 +1202,7 @@ dix_verify_split(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
while (offset_blocks < num_blocks &&
_iov_iter_cont(&data_iter) && _iov_iter_cont(&md_iter)) {
rc = _dix_verify_split(&data_iter, &md_iter, offset_blocks, ctx);
rc = _dix_verify_split(&data_iter, &md_iter, offset_blocks, ctx, err_blk);
if (rc != 0) {
return rc;
}
@ -1211,7 +1214,8 @@ dix_verify_split(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
int
spdk_dix_verify(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
uint32_t num_blocks, const struct spdk_dif_ctx *ctx,
struct spdk_dif_error *err_blk)
{
if (!_are_iovs_valid(iovs, iovcnt, ctx->block_size * num_blocks) ||
!_are_iovs_valid(md_iov, 1, ctx->md_size * num_blocks)) {
@ -1224,8 +1228,71 @@ spdk_dix_verify(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
}
if (_are_iovs_bytes_multiple(iovs, iovcnt, ctx->block_size)) {
return dix_verify(iovs, iovcnt, md_iov, num_blocks, ctx);
return dix_verify(iovs, iovcnt, md_iov, num_blocks, ctx, err_blk);
} else {
return dix_verify_split(iovs, iovcnt, md_iov, num_blocks, ctx);
return dix_verify_split(iovs, iovcnt, md_iov, num_blocks, ctx, err_blk);
}
}
int
spdk_dix_inject_error(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
uint32_t num_blocks, const struct spdk_dif_ctx *ctx,
uint32_t inject_flags, uint32_t *inject_offset)
{
int rc;
if (!_are_iovs_valid(iovs, iovcnt, ctx->block_size * num_blocks) ||
!_are_iovs_valid(md_iov, 1, ctx->md_size * num_blocks)) {
SPDK_ERRLOG("Size of iovec array is not valid.\n");
return -EINVAL;
}
if (inject_flags & SPDK_DIF_REFTAG_ERROR) {
rc = dif_inject_error(md_iov, 1, ctx->md_size, num_blocks,
ctx->guard_interval + offsetof(struct spdk_dif, ref_tag),
_member_size(struct spdk_dif, ref_tag),
inject_offset);
if (rc != 0) {
SPDK_ERRLOG("Failed to inject error to Reference Tag.\n");
return rc;
}
}
if (inject_flags & SPDK_DIF_APPTAG_ERROR) {
rc = dif_inject_error(md_iov, 1, ctx->md_size, num_blocks,
ctx->guard_interval + offsetof(struct spdk_dif, app_tag),
_member_size(struct spdk_dif, app_tag),
inject_offset);
if (rc != 0) {
SPDK_ERRLOG("Failed to inject error to Application Tag.\n");
return rc;
}
}
if (inject_flags & SPDK_DIF_GUARD_ERROR) {
rc = dif_inject_error(md_iov, 1, ctx->md_size, num_blocks,
ctx->guard_interval,
_member_size(struct spdk_dif, guard),
inject_offset);
if (rc != 0) {
SPDK_ERRLOG("Failed to inject error to Guard.\n");
return rc;
}
}
if (inject_flags & SPDK_DIF_DATA_ERROR) {
/* Note: Error injection to data block is expected to be detected
* as guard error.
*/
rc = dif_inject_error(iovs, iovcnt, ctx->block_size, num_blocks,
0,
ctx->block_size,
inject_offset);
if (rc != 0) {
SPDK_ERRLOG("Failed to inject error to Guard.\n");
return rc;
}
}
return 0;
}

View File

@ -1036,7 +1036,7 @@ dix_generate_and_verify(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
rc = spdk_dix_generate(iovs, iovcnt, md_iov, num_blocks, &ctx);
CU_ASSERT(rc == 0);
rc = spdk_dix_verify(iovs, iovcnt, md_iov, num_blocks, &ctx);
rc = spdk_dix_verify(iovs, iovcnt, md_iov, num_blocks, &ctx, NULL);
CU_ASSERT(rc == 0);
rc = ut_data_pattern_verify(iovs, iovcnt, block_size, 0, num_blocks);
@ -1176,6 +1176,106 @@ dix_sec_512_md_8_prchk_7_multi_iovs_complex_splits(void)
_iov_free_buf(&md_iov);
}
static void
_dix_inject_error_and_verify(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
uint32_t block_size, uint32_t md_size, uint32_t num_blocks,
uint32_t inject_flags, bool dif_loc)
{
struct spdk_dif_ctx ctx = {};
struct spdk_dif_error err_blk = {};
uint32_t inject_offset = 0, dif_flags;
int rc;
dif_flags = SPDK_DIF_GUARD_CHECK | SPDK_DIF_APPTAG_CHECK | SPDK_DIF_REFTAG_CHECK;
rc = ut_data_pattern_generate(iovs, iovcnt, block_size, 0, num_blocks);
CU_ASSERT(rc == 0);
rc = spdk_dif_ctx_init(&ctx, block_size, md_size, false, dif_loc, SPDK_DIF_TYPE1, dif_flags,
88, 0xFFFF, 0x88);
CU_ASSERT(rc == 0);
rc = spdk_dix_generate(iovs, iovcnt, md_iov, num_blocks, &ctx);
CU_ASSERT(rc == 0);
rc = spdk_dix_inject_error(iovs, iovcnt, md_iov, num_blocks, &ctx, inject_flags, &inject_offset);
CU_ASSERT(rc == 0);
rc = spdk_dix_verify(iovs, iovcnt, md_iov, num_blocks, &ctx, &err_blk);
CU_ASSERT(rc != 0);
if (inject_flags == SPDK_DIF_DATA_ERROR) {
CU_ASSERT(SPDK_DIF_GUARD_ERROR == err_blk.err_type);
} else {
CU_ASSERT(inject_flags == err_blk.err_type);
}
CU_ASSERT(inject_offset == err_blk.err_offset);
}
static void
dix_inject_error_and_verify(struct iovec *iovs, int iovcnt, struct iovec *md_iov,
uint32_t block_size, uint32_t md_size, uint32_t num_blocks,
uint32_t inject_flags)
{
/* The case that DIF is contained in the first 8 bytes of metadata. */
_dix_inject_error_and_verify(iovs, iovcnt, md_iov, block_size, md_size, num_blocks,
inject_flags, false);
/* The case that DIF is contained in the last 8 bytes of metadata. */
_dix_inject_error_and_verify(iovs, iovcnt, md_iov, block_size, md_size, num_blocks,
inject_flags, true);
}
static void
dix_sec_4096_md_128_inject_1_2_4_8_multi_iovs_test(void)
{
struct iovec iovs[4], md_iov;
int i, num_blocks;
num_blocks = 0;
for (i = 0; i < 4; i++) {
_iov_alloc_buf(&iovs[i], 4096 * (i + 1));
num_blocks += i + 1;
}
_iov_alloc_buf(&md_iov, 128 * num_blocks);
dix_inject_error_and_verify(iovs, 4, &md_iov, 4096, 128, num_blocks, SPDK_DIF_GUARD_ERROR);
dix_inject_error_and_verify(iovs, 4, &md_iov, 4096, 128, num_blocks, SPDK_DIF_APPTAG_ERROR);
dix_inject_error_and_verify(iovs, 4, &md_iov, 4096, 128, num_blocks, SPDK_DIF_REFTAG_ERROR);
dix_inject_error_and_verify(iovs, 4, &md_iov, 4096, 128, num_blocks, SPDK_DIF_DATA_ERROR);
for (i = 0; i < 4; i++) {
_iov_free_buf(&iovs[i]);
}
_iov_free_buf(&md_iov);
}
static void
dix_sec_4096_md_128_inject_1_2_4_8_multi_iovs_split_test(void)
{
struct iovec iovs[4], md_iov;
int i;
_iov_alloc_buf(&iovs[0], 2048);
_iov_alloc_buf(&iovs[1], 2048);
_iov_alloc_buf(&iovs[2], 1);
_iov_alloc_buf(&iovs[3], 4095);
_iov_alloc_buf(&md_iov, 128 * 2);
dix_inject_error_and_verify(iovs, 4, &md_iov, 4096, 128, 2, SPDK_DIF_GUARD_ERROR);
dix_inject_error_and_verify(iovs, 4, &md_iov, 4096, 128, 2, SPDK_DIF_APPTAG_ERROR);
dix_inject_error_and_verify(iovs, 4, &md_iov, 4096, 128, 2, SPDK_DIF_REFTAG_ERROR);
dix_inject_error_and_verify(iovs, 4, &md_iov, 4096, 128, 2, SPDK_DIF_DATA_ERROR);
for (i = 0; i < 4; i++) {
_iov_free_buf(&iovs[i]);
}
_iov_free_buf(&md_iov);
}
int
main(int argc, char **argv)
{
@ -1254,7 +1354,11 @@ main(int argc, char **argv)
CU_add_test(suite, "dix_sec_512_md_8_prchk_7_multi_iovs_split_data",
dix_sec_512_md_8_prchk_7_multi_iovs_split_data) == NULL ||
CU_add_test(suite, "dix_sec_512_md_8_prchk_7_multi_iovs_complex_splits",
dix_sec_512_md_8_prchk_7_multi_iovs_complex_splits) == NULL
dix_sec_512_md_8_prchk_7_multi_iovs_complex_splits) == NULL ||
CU_add_test(suite, "dix_sec_4096_md_128_inject_1_2_4_8_multi_iovs_test",
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_cleanup_registry();
return CU_get_error();