dif: Return DIF error information by struct at verification

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.

Change-Id: I43941f1a7f4b0ad1e8ff324f2ac8fad9e195a100
Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-on: https://review.gerrithub.io/c/438023
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>
Reviewed-by: wuzhouhui <wuzhouhui@kingsoft.com>
Chandler-Test-Pool: SPDK Automated Test System <sys_sgsw@intel.com>
This commit is contained in:
Shuhei Matsumoto 2018-12-28 10:18:21 +09:00 committed by Jim Harris
parent b810dda24a
commit 65e491a8de
3 changed files with 88 additions and 29 deletions

View File

@ -87,6 +87,21 @@ struct spdk_dif_ctx {
uint16_t apptag_mask; uint16_t apptag_mask;
}; };
/** DIF error information */
struct spdk_dif_error {
/** Error type */
uint8_t err_type;
/** Expected value */
uint32_t expected;
/** Actual value */
uint32_t actual;
/** Offset the error occurred at, block based */
uint32_t err_offset;
};
/** /**
* Initialize DIF context. * Initialize DIF context.
* *
@ -128,11 +143,12 @@ int spdk_dif_generate(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
* \param iovcnt Number of elements in the iovec array. * \param iovcnt Number of elements in the iovec array.
* \param num_blocks Number of blocks of the payload. * \param num_blocks Number of blocks of the payload.
* \param ctx DIF context. * \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. * \return 0 on success and negated errno otherwise.
*/ */
int spdk_dif_verify(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); const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk);
/** /**
* Inject bit flip error to extended LBA payload. * Inject bit flip error to extended LBA payload.
@ -141,9 +157,13 @@ int spdk_dif_verify(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
* \param iovcnt Number of elements in the iovec array. * \param iovcnt Number of elements in the iovec array.
* \param num_blocks Number of blocks of the payload. * \param num_blocks Number of blocks of the payload.
* \param ctx DIF context. * \param ctx DIF context.
* \param inject_flags Flags 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. * \return 0 on success and negated errno otherwise including no metadata.
*/ */
int spdk_dif_inject_error(struct iovec *iovs, int iovcnt, uint32_t num_blocks, int spdk_dif_inject_error(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
const struct spdk_dif_ctx *ctx, uint32_t inject_flags); const struct spdk_dif_ctx *ctx, uint32_t inject_flags,
uint32_t *inject_offset);
#endif /* SPDK_DIF_H */ #endif /* SPDK_DIF_H */

View File

@ -348,9 +348,21 @@ spdk_dif_generate(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
return 0; return 0;
} }
static void
_dif_error_set(struct spdk_dif_error *err_blk, uint8_t err_type,
uint32_t expected, uint32_t actual, uint32_t err_offset)
{
if (err_blk) {
err_blk->err_type = err_type;
err_blk->expected = expected;
err_blk->actual = actual;
err_blk->err_offset = err_offset;
}
}
static int static int
_dif_verify(void *_dif, uint16_t guard, uint32_t offset_blocks, _dif_verify(void *_dif, uint16_t guard, uint32_t offset_blocks,
const struct spdk_dif_ctx *ctx) const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk)
{ {
struct spdk_dif *dif = _dif; struct spdk_dif *dif = _dif;
uint16_t _guard; uint16_t _guard;
@ -395,6 +407,8 @@ _dif_verify(void *_dif, uint16_t guard, uint32_t offset_blocks,
*/ */
_guard = from_be16(&dif->guard); _guard = from_be16(&dif->guard);
if (_guard != guard) { if (_guard != guard) {
_dif_error_set(err_blk, SPDK_DIF_GUARD_ERROR, _guard, guard,
offset_blocks);
SPDK_ERRLOG("Failed to compare Guard: LBA=%" PRIu32 "," \ SPDK_ERRLOG("Failed to compare Guard: LBA=%" PRIu32 "," \
" Expected=%x, Actual=%x\n", " Expected=%x, Actual=%x\n",
ref_tag, _guard, guard); ref_tag, _guard, guard);
@ -408,6 +422,8 @@ _dif_verify(void *_dif, uint16_t guard, uint32_t offset_blocks,
*/ */
_app_tag = from_be16(&dif->app_tag); _app_tag = from_be16(&dif->app_tag);
if ((_app_tag & ctx->apptag_mask) != ctx->app_tag) { if ((_app_tag & ctx->apptag_mask) != ctx->app_tag) {
_dif_error_set(err_blk, SPDK_DIF_APPTAG_ERROR, ctx->app_tag,
(_app_tag & ctx->apptag_mask), offset_blocks);
SPDK_ERRLOG("Failed to compare App Tag: LBA=%" PRIu32 "," \ SPDK_ERRLOG("Failed to compare App Tag: LBA=%" PRIu32 "," \
" Expected=%x, Actual=%x\n", " Expected=%x, Actual=%x\n",
ref_tag, ctx->app_tag, (_app_tag & ctx->apptag_mask)); ref_tag, ctx->app_tag, (_app_tag & ctx->apptag_mask));
@ -426,6 +442,8 @@ _dif_verify(void *_dif, uint16_t guard, uint32_t offset_blocks,
*/ */
_ref_tag = from_be32(&dif->ref_tag); _ref_tag = from_be32(&dif->ref_tag);
if (_ref_tag != ref_tag) { if (_ref_tag != ref_tag) {
_dif_error_set(err_blk, SPDK_DIF_REFTAG_ERROR, ref_tag,
_ref_tag, offset_blocks);
SPDK_ERRLOG("Failed to compare Ref Tag: LBA=%" PRIu32 "," \ SPDK_ERRLOG("Failed to compare Ref Tag: LBA=%" PRIu32 "," \
" Expected=%x, Actual=%x\n", " Expected=%x, Actual=%x\n",
ref_tag, ref_tag, _ref_tag); ref_tag, ref_tag, _ref_tag);
@ -447,7 +465,7 @@ _dif_verify(void *_dif, uint16_t guard, uint32_t offset_blocks,
static int static int
dif_verify(struct iovec *iovs, int iovcnt, uint32_t num_blocks, dif_verify(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
const struct spdk_dif_ctx *ctx) const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk)
{ {
struct _iov_iter iter; struct _iov_iter iter;
uint32_t offset_blocks; uint32_t offset_blocks;
@ -465,7 +483,7 @@ dif_verify(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
guard = spdk_crc16_t10dif(0, buf, ctx->guard_interval); guard = spdk_crc16_t10dif(0, buf, ctx->guard_interval);
} }
rc = _dif_verify(buf + ctx->guard_interval, guard, offset_blocks, ctx); rc = _dif_verify(buf + ctx->guard_interval, guard, offset_blocks, ctx, err_blk);
if (rc != 0) { if (rc != 0) {
return rc; return rc;
} }
@ -479,7 +497,7 @@ dif_verify(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
static int static int
_dif_verify_split(struct _iov_iter *iter, uint32_t offset_blocks, _dif_verify_split(struct _iov_iter *iter, uint32_t offset_blocks,
const struct spdk_dif_ctx *ctx) const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk)
{ {
uint32_t offset_in_block, offset_in_dif, buf_len; uint32_t offset_in_block, offset_in_dif, buf_len;
void *buf; void *buf;
@ -514,12 +532,12 @@ _dif_verify_split(struct _iov_iter *iter, uint32_t offset_blocks,
offset_in_block += buf_len; offset_in_block += buf_len;
} }
return _dif_verify(&dif, guard, offset_blocks, ctx); return _dif_verify(&dif, guard, offset_blocks, ctx, err_blk);
} }
static int static int
dif_verify_split(struct iovec *iovs, int iovcnt, uint32_t num_blocks, dif_verify_split(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
const struct spdk_dif_ctx *ctx) const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk)
{ {
struct _iov_iter iter; struct _iov_iter iter;
uint32_t offset_blocks; uint32_t offset_blocks;
@ -529,7 +547,7 @@ dif_verify_split(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
_iov_iter_init(&iter, iovs, iovcnt); _iov_iter_init(&iter, iovs, iovcnt);
while (offset_blocks < num_blocks && _iov_iter_cont(&iter)) { while (offset_blocks < num_blocks && _iov_iter_cont(&iter)) {
rc = _dif_verify_split(&iter, offset_blocks, ctx); rc = _dif_verify_split(&iter, offset_blocks, ctx, err_blk);
if (rc != 0) { if (rc != 0) {
return rc; return rc;
} }
@ -541,7 +559,7 @@ dif_verify_split(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
int int
spdk_dif_verify(struct iovec *iovs, int iovcnt, uint32_t num_blocks, spdk_dif_verify(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
const struct spdk_dif_ctx *ctx) const struct spdk_dif_ctx *ctx, struct spdk_dif_error *err_blk)
{ {
if (!_are_iovs_valid(iovs, iovcnt, ctx->block_size * num_blocks)) { if (!_are_iovs_valid(iovs, iovcnt, ctx->block_size * num_blocks)) {
SPDK_ERRLOG("Size of iovec array is not valid.\n"); SPDK_ERRLOG("Size of iovec array is not valid.\n");
@ -553,9 +571,9 @@ spdk_dif_verify(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
} }
if (_are_iovs_bytes_multiple(iovs, iovcnt, ctx->block_size)) { if (_are_iovs_bytes_multiple(iovs, iovcnt, ctx->block_size)) {
return dif_verify(iovs, iovcnt, num_blocks, ctx); return dif_verify(iovs, iovcnt, num_blocks, ctx, err_blk);
} else { } else {
return dif_verify_split(iovs, iovcnt, num_blocks, ctx); return dif_verify_split(iovs, iovcnt, num_blocks, ctx, err_blk);
} }
} }
@ -607,10 +625,12 @@ _dif_inject_error(struct iovec *iovs, int iovcnt,
static int static int
dif_inject_error(struct iovec *iovs, int iovcnt, dif_inject_error(struct iovec *iovs, int iovcnt,
uint32_t block_size, uint32_t num_blocks, uint32_t block_size, uint32_t num_blocks,
uint32_t start_inject_bytes, uint32_t inject_range_bytes) uint32_t start_inject_bytes, uint32_t inject_range_bytes,
uint32_t *inject_offset)
{ {
uint32_t inject_offset_blocks, inject_offset_bytes, inject_offset_bits; uint32_t inject_offset_blocks, inject_offset_bytes, inject_offset_bits;
uint32_t offset_blocks; uint32_t offset_blocks;
int rc;
srand(time(0)); srand(time(0));
@ -620,10 +640,14 @@ dif_inject_error(struct iovec *iovs, int iovcnt,
for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) { for (offset_blocks = 0; offset_blocks < num_blocks; offset_blocks++) {
if (offset_blocks == inject_offset_blocks) { if (offset_blocks == inject_offset_blocks) {
return _dif_inject_error(iovs, iovcnt, block_size, num_blocks, rc = _dif_inject_error(iovs, iovcnt, block_size, num_blocks,
inject_offset_blocks, inject_offset_blocks,
inject_offset_bytes, inject_offset_bytes,
inject_offset_bits); inject_offset_bits);
if (rc == 0) {
*inject_offset = inject_offset_blocks;
}
return rc;
} }
} }
@ -634,7 +658,8 @@ dif_inject_error(struct iovec *iovs, int iovcnt,
int int
spdk_dif_inject_error(struct iovec *iovs, int iovcnt, uint32_t num_blocks, spdk_dif_inject_error(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
const struct spdk_dif_ctx *ctx, uint32_t inject_flags) const struct spdk_dif_ctx *ctx, uint32_t inject_flags,
uint32_t *inject_offset)
{ {
int rc; int rc;
@ -646,7 +671,8 @@ spdk_dif_inject_error(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
if (inject_flags & SPDK_DIF_REFTAG_ERROR) { if (inject_flags & SPDK_DIF_REFTAG_ERROR) {
rc = dif_inject_error(iovs, iovcnt, ctx->block_size, num_blocks, rc = dif_inject_error(iovs, iovcnt, ctx->block_size, num_blocks,
ctx->guard_interval + offsetof(struct spdk_dif, ref_tag), ctx->guard_interval + offsetof(struct spdk_dif, ref_tag),
_member_size(struct spdk_dif, ref_tag)); _member_size(struct spdk_dif, ref_tag),
inject_offset);
if (rc != 0) { if (rc != 0) {
SPDK_ERRLOG("Failed to inject error to Reference Tag.\n"); SPDK_ERRLOG("Failed to inject error to Reference Tag.\n");
return rc; return rc;
@ -656,7 +682,8 @@ spdk_dif_inject_error(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
if (inject_flags & SPDK_DIF_APPTAG_ERROR) { if (inject_flags & SPDK_DIF_APPTAG_ERROR) {
rc = dif_inject_error(iovs, iovcnt, ctx->block_size, num_blocks, rc = dif_inject_error(iovs, iovcnt, ctx->block_size, num_blocks,
ctx->guard_interval + offsetof(struct spdk_dif, app_tag), ctx->guard_interval + offsetof(struct spdk_dif, app_tag),
_member_size(struct spdk_dif, app_tag)); _member_size(struct spdk_dif, app_tag),
inject_offset);
if (rc != 0) { if (rc != 0) {
SPDK_ERRLOG("Failed to inject error to Application Tag.\n"); SPDK_ERRLOG("Failed to inject error to Application Tag.\n");
return rc; return rc;
@ -665,7 +692,8 @@ spdk_dif_inject_error(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
if (inject_flags & SPDK_DIF_GUARD_ERROR) { if (inject_flags & SPDK_DIF_GUARD_ERROR) {
rc = dif_inject_error(iovs, iovcnt, ctx->block_size, num_blocks, rc = dif_inject_error(iovs, iovcnt, ctx->block_size, num_blocks,
ctx->guard_interval, ctx->guard_interval,
_member_size(struct spdk_dif, guard)); _member_size(struct spdk_dif, guard),
inject_offset);
if (rc != 0) { if (rc != 0) {
SPDK_ERRLOG("Failed to inject error to Guard.\n"); SPDK_ERRLOG("Failed to inject error to Guard.\n");
return rc; return rc;
@ -677,10 +705,14 @@ spdk_dif_inject_error(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
* metadata, then the CRC covers all metadata bytes up to but excluding * metadata, then the CRC covers all metadata bytes up to but excluding
* the last 8 bytes. But error injection does not cover these metadata * the last 8 bytes. But error injection does not cover these metadata
* because classification is not determined yet. * because classification is not determined yet.
*
* 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, rc = dif_inject_error(iovs, iovcnt, ctx->block_size, num_blocks,
0, 0,
ctx->block_size - ctx->md_size); ctx->block_size - ctx->md_size,
inject_offset);
if (rc != 0) { if (rc != 0) {
SPDK_ERRLOG("Failed to inject error to data block.\n"); SPDK_ERRLOG("Failed to inject error to data block.\n");
return rc; return rc;

View File

@ -162,7 +162,7 @@ _dif_generate_and_verify(struct iovec *iov,
ctx.apptag_mask = apptag_mask; ctx.apptag_mask = apptag_mask;
ctx.app_tag = e_app_tag; ctx.app_tag = e_app_tag;
rc = _dif_verify(iov->iov_base + guard_interval, guard, 0, &ctx); rc = _dif_verify(iov->iov_base + guard_interval, guard, 0, &ctx, NULL);
CU_ASSERT((expect_pass && rc == 0) || (!expect_pass && rc != 0)); CU_ASSERT((expect_pass && rc == 0) || (!expect_pass && rc != 0));
rc = ut_data_pattern_verify(iov, 1, block_size, md_size, 1); rc = ut_data_pattern_verify(iov, 1, block_size, md_size, 1);
@ -293,7 +293,7 @@ dif_generate_and_verify(struct iovec *iovs, int iovcnt,
rc = spdk_dif_generate(iovs, iovcnt, num_blocks, &ctx); rc = spdk_dif_generate(iovs, iovcnt, num_blocks, &ctx);
CU_ASSERT(rc == 0); CU_ASSERT(rc == 0);
rc = spdk_dif_verify(iovs, iovcnt, num_blocks, &ctx); rc = spdk_dif_verify(iovs, iovcnt, num_blocks, &ctx, NULL);
CU_ASSERT(rc == 0); CU_ASSERT(rc == 0);
rc = ut_data_pattern_verify(iovs, iovcnt, block_size, md_size, num_blocks); rc = ut_data_pattern_verify(iovs, iovcnt, block_size, md_size, num_blocks);
@ -573,7 +573,8 @@ _dif_inject_error_and_verify(struct iovec *iovs, int iovcnt,
uint32_t inject_flags, bool dif_loc) uint32_t inject_flags, bool dif_loc)
{ {
struct spdk_dif_ctx ctx = {}; struct spdk_dif_ctx ctx = {};
uint32_t dif_flags; struct spdk_dif_error err_blk = {};
uint32_t inject_offset = 0, dif_flags;
int rc; int rc;
dif_flags = SPDK_DIF_GUARD_CHECK | SPDK_DIF_APPTAG_CHECK | SPDK_DIF_REFTAG_CHECK; dif_flags = SPDK_DIF_GUARD_CHECK | SPDK_DIF_APPTAG_CHECK | SPDK_DIF_REFTAG_CHECK;
@ -588,15 +589,21 @@ _dif_inject_error_and_verify(struct iovec *iovs, int iovcnt,
rc = spdk_dif_generate(iovs, iovcnt, num_blocks, &ctx); rc = spdk_dif_generate(iovs, iovcnt, num_blocks, &ctx);
CU_ASSERT(rc == 0); CU_ASSERT(rc == 0);
rc = spdk_dif_inject_error(iovs, iovcnt, num_blocks, &ctx, inject_flags); rc = spdk_dif_inject_error(iovs, iovcnt, num_blocks, &ctx, inject_flags, &inject_offset);
CU_ASSERT(rc == 0); CU_ASSERT(rc == 0);
rc = spdk_dif_verify(iovs, iovcnt, num_blocks, &ctx); rc = spdk_dif_verify(iovs, iovcnt, num_blocks, &ctx, &err_blk);
CU_ASSERT(rc != 0); 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);
rc = ut_data_pattern_verify(iovs, iovcnt, block_size, md_size, num_blocks); rc = ut_data_pattern_verify(iovs, iovcnt, block_size, md_size, num_blocks);
CU_ASSERT((rc == 0 && !(inject_flags & SPDK_DIF_DATA_ERROR)) || CU_ASSERT((rc == 0 && (inject_flags != SPDK_DIF_DATA_ERROR)) ||
(rc != 0 && (inject_flags & SPDK_DIF_DATA_ERROR))); (rc != 0 && (inject_flags == SPDK_DIF_DATA_ERROR)));
} }
static void static void