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;
};
/** 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.
*
@ -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 num_blocks Number of blocks of the 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_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.
@ -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 num_blocks Number of blocks of the payload.
* \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.
*/
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 */

View File

@ -348,9 +348,21 @@ spdk_dif_generate(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
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
_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;
uint16_t _guard;
@ -395,6 +407,8 @@ _dif_verify(void *_dif, uint16_t guard, uint32_t offset_blocks,
*/
_guard = from_be16(&dif->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 "," \
" Expected=%x, Actual=%x\n",
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);
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 "," \
" Expected=%x, Actual=%x\n",
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);
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 "," \
" Expected=%x, Actual=%x\n",
ref_tag, ref_tag, _ref_tag);
@ -447,7 +465,7 @@ _dif_verify(void *_dif, uint16_t guard, uint32_t offset_blocks,
static int
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;
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);
}
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) {
return rc;
}
@ -479,7 +497,7 @@ dif_verify(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
static int
_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;
void *buf;
@ -514,12 +532,12 @@ _dif_verify_split(struct _iov_iter *iter, uint32_t offset_blocks,
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
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;
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);
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) {
return rc;
}
@ -541,7 +559,7 @@ dif_verify_split(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)
{
if (!_are_iovs_valid(iovs, iovcnt, ctx->block_size * num_blocks)) {
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)) {
return dif_verify(iovs, iovcnt, num_blocks, ctx);
return dif_verify(iovs, iovcnt, num_blocks, ctx, err_blk);
} 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
dif_inject_error(struct iovec *iovs, int iovcnt,
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 offset_blocks;
int rc;
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++) {
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_bytes,
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
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;
@ -646,7 +671,8 @@ spdk_dif_inject_error(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
if (inject_flags & SPDK_DIF_REFTAG_ERROR) {
rc = dif_inject_error(iovs, iovcnt, ctx->block_size, num_blocks,
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) {
SPDK_ERRLOG("Failed to inject error to Reference Tag.\n");
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) {
rc = dif_inject_error(iovs, iovcnt, ctx->block_size, num_blocks,
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) {
SPDK_ERRLOG("Failed to inject error to Application Tag.\n");
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) {
rc = dif_inject_error(iovs, iovcnt, ctx->block_size, num_blocks,
ctx->guard_interval,
_member_size(struct spdk_dif, guard));
_member_size(struct spdk_dif, guard),
inject_offset);
if (rc != 0) {
SPDK_ERRLOG("Failed to inject error to Guard.\n");
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
* the last 8 bytes. But error injection does not cover these metadata
* 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,
0,
ctx->block_size - ctx->md_size);
ctx->block_size - ctx->md_size,
inject_offset);
if (rc != 0) {
SPDK_ERRLOG("Failed to inject error to data block.\n");
return rc;

View File

@ -162,7 +162,7 @@ _dif_generate_and_verify(struct iovec *iov,
ctx.apptag_mask = apptag_mask;
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));
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);
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);
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)
{
struct spdk_dif_ctx ctx = {};
uint32_t dif_flags;
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;
@ -588,15 +589,21 @@ _dif_inject_error_and_verify(struct iovec *iovs, int iovcnt,
rc = spdk_dif_generate(iovs, iovcnt, num_blocks, &ctx);
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);
rc = spdk_dif_verify(iovs, iovcnt, num_blocks, &ctx);
rc = spdk_dif_verify(iovs, iovcnt, 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);
rc = ut_data_pattern_verify(iovs, iovcnt, block_size, md_size, num_blocks);
CU_ASSERT((rc == 0 && !(inject_flags & SPDK_DIF_DATA_ERROR)) ||
(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)));
}
static void