Commit 65e491a8 authored by Shuhei Matsumoto's avatar Shuhei Matsumoto Committed by Jim Harris
Browse files

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: default avatarShuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-on: https://review.gerrithub.io/c/438023


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarChangpeng Liu <changpeng.liu@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarwuzhouhui <wuzhouhui@kingsoft.com>
Chandler-Test-Pool: SPDK Automated Test System <sys_sgsw@intel.com>
parent b810dda2
Loading
Loading
Loading
Loading
+22 −2
Original line number Diff line number Diff line
@@ -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 */
+52 −20
Original line number Diff line number Diff line
@@ -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;
+14 −7
Original line number Diff line number Diff line
@@ -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