dif: Clean-up APIs by introducing context data

This patch reduces the number of parameters of APIs by setting
necessary information to context struct and pass it to APIs.

This will simplify the code and will clarify the core logic.
Besides, by introducing context data, update of reference tag
is further consolidated.

Change-Id: I1b3eec596847eb4ef1cf43441035df21f746192a
Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-on: https://review.gerrithub.io/c/438021
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Chandler-Test-Pool: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-by: wuzhouhui <wuzhouhui@kingsoft.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
Shuhei Matsumoto 2019-01-07 09:20:35 +09:00 committed by Jim Harris
parent c0839cc0c9
commit 18461cba7c
3 changed files with 234 additions and 250 deletions

View File

@ -60,68 +60,90 @@ struct spdk_dif {
}; };
SPDK_STATIC_ASSERT(sizeof(struct spdk_dif) == 8, "Incorrect size"); SPDK_STATIC_ASSERT(sizeof(struct spdk_dif) == 8, "Incorrect size");
/** DIF context information */
struct spdk_dif_ctx {
/** Block size */
uint32_t block_size;
/** Metadata size */
uint32_t md_size;
/** Interval for guard computation */
uint32_t guard_interval;
/** DIF type */
enum spdk_dif_type dif_type;
/* Flags to specify the DIF action */
uint32_t dif_flags;
/* Initial reference tag */
uint32_t init_ref_tag;
/** Application tag */
uint16_t app_tag;
/* Application tag mask */
uint16_t apptag_mask;
};
/**
* Initialize DIF context.
*
* \param ctx DIF context.
* \param block_size Block size in a block.
* \param md_size Metadata size in a block.
* \param dif_loc DIF location. If true, DIF is set in the last 8 bytes of metadata.
* If false, DIF is in the first 8 bytes of metadata.
* \param dif_type Type of DIF.
* \param dif_flags Flag to specify the DIF action.
* \param init_ref_tag Initial reference tag. For type 1, this is the
* starting block address.
* \param apptag_mask Application tag mask.
* \param app_tag Application tag.
*
* \return 0 on success and negated errno otherwise.
*/
int spdk_dif_ctx_init(struct spdk_dif_ctx *ctx, uint32_t block_size, uint32_t md_size,
bool dif_loc, enum spdk_dif_type dif_type, uint32_t dif_flags,
uint32_t init_ref_tag, uint16_t apptag_mask, uint16_t app_tag);
/** /**
* Generate DIF for extended LBA payload. * Generate DIF for extended LBA payload.
* *
* \param iovs iovec array describing the extended LBA payload. * \param iovs iovec array describing the extended LBA payload.
* \param iovcnt Number of elements in the iovec array. * \param iovcnt Number of elements in the iovec array.
* \param block_size Block size in a block.
* \param md_size Metadata size in a block.
* \param num_blocks Number of blocks of the payload. * \param num_blocks Number of blocks of the payload.
* \param dif_loc DIF location. If true, DIF is set in the last 8 bytes of metadata. * \param ctx DIF context.
* If false, DIF is in the first 8 bytes of metadata.
* \param dif_type Type of DIF.
* \param dif_flags Flag to specify the DIF action.
* \param init_ref_tag Initial Reference Tag. For type 1, this is the
* starting block address.
* \param app_tag Application Tag.
* *
* \return 0 on success and negated errno otherwise. * \return 0 on success and negated errno otherwise.
*/ */
int spdk_dif_generate(struct iovec *iovs, int iovcnt, int spdk_dif_generate(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
uint32_t block_size, uint32_t md_size, uint32_t num_blocks, const struct spdk_dif_ctx *ctx);
bool dif_loc, enum spdk_dif_type dif_type, uint32_t dif_flags,
uint32_t init_ref_tag, uint16_t app_tag);
/** /**
* Verify DIF for extended LBA payload. * Verify DIF for extended LBA payload.
* *
* \param iovs iovec array describing the extended LBA payload. * \param iovs iovec array describing the extended LBA payload.
* \param iovcnt Number of elements in the iovec array. * \param iovcnt Number of elements in the iovec array.
* \param block_size Block size in a block.
* \param md_size Metadata size in a block.
* \param num_blocks Number of blocks of the payload. * \param num_blocks Number of blocks of the payload.
* \param dif_loc DIF location. If true, DIF is set in the last 8 bytes of metadata. * \param ctx DIF context.
* If false, DIF is set in the first 8 bytes of metadata.
* \param dif_type Type of DIF.
* \param dif_flags Flag to specify the DIF action.
* \param init_ref_tag Initial Reference Tag. For type 1, this is the
* starting block address.
* \param apptag_mask Application Tag Mask.
* \param app_tag Application Tag.
* *
* \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, int spdk_dif_verify(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
uint32_t block_size, uint32_t md_size, uint32_t num_blocks, const struct spdk_dif_ctx *ctx);
bool dif_loc, enum spdk_dif_type dif_type, uint32_t dif_flags,
uint32_t init_ref_tag, uint16_t apptag_mask, uint16_t app_tag);
/** /**
* Inject bit flip error to extended LBA payload. * Inject bit flip error to extended LBA payload.
* *
* \param iovs iovec array describing the extended LBA payload. * \param iovs iovec array describing the extended LBA payload.
* \param iovcnt Number of elements in the iovec array. * \param iovcnt Number of elements in the iovec array.
* \param block_size Block size in a block.
* \param md_size Metadata size in a block.
* \param num_blocks Number of blocks of the payload. * \param num_blocks Number of blocks of the payload.
* \param dif_loc DIF location. If true, DIF is set in the last 8 bytes of metadata. * \param ctx DIF context.
* If false, DIF is set in the first 8 bytes of metadata.
* \param inject_flags Flag to specify the action of error injection.
* *
* \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, int spdk_dif_inject_error(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
uint32_t block_size, uint32_t md_size, uint32_t num_blocks, const struct spdk_dif_ctx *ctx, uint32_t inject_flags);
bool dif_loc, uint32_t inject_flags);
#endif /* SPDK_DIF_H */ #endif /* SPDK_DIF_H */

View File

@ -177,33 +177,74 @@ _get_dif_guard_interval(uint32_t block_size, uint32_t md_size, bool dif_loc)
} }
} }
int
spdk_dif_ctx_init(struct spdk_dif_ctx *ctx, uint32_t block_size, uint32_t md_size,
bool dif_loc, enum spdk_dif_type dif_type, uint32_t dif_flags,
uint32_t init_ref_tag, uint16_t apptag_mask, uint16_t app_tag)
{
if (md_size < sizeof(struct spdk_dif)) {
SPDK_ERRLOG("Metadata size is smaller than DIF size.\n");
return -EINVAL;
}
if (block_size < md_size) {
SPDK_ERRLOG("Block size is smaller than DIF size.\n");
return -EINVAL;
}
if (!_dif_type_is_valid(dif_type, dif_flags)) {
SPDK_ERRLOG("DIF type is invalid.\n");
return -EINVAL;
}
ctx->block_size = block_size;
ctx->md_size = md_size;
ctx->guard_interval = _get_dif_guard_interval(block_size, md_size, dif_loc);
ctx->dif_type = dif_type;
ctx->dif_flags = dif_flags;
ctx->init_ref_tag = init_ref_tag;
ctx->apptag_mask = apptag_mask;
ctx->app_tag = app_tag;
return 0;
}
static void static void
_dif_generate(void *_dif, uint32_t dif_flags, _dif_generate(void *_dif, uint16_t guard, uint32_t offset_blocks,
uint16_t guard, uint32_t ref_tag, uint16_t app_tag) const struct spdk_dif_ctx *ctx)
{ {
struct spdk_dif *dif = _dif; struct spdk_dif *dif = _dif;
uint32_t ref_tag;
if (dif_flags & SPDK_DIF_GUARD_CHECK) { if (ctx->dif_flags & SPDK_DIF_GUARD_CHECK) {
to_be16(&dif->guard, guard); to_be16(&dif->guard, guard);
} }
if (dif_flags & SPDK_DIF_APPTAG_CHECK) { if (ctx->dif_flags & SPDK_DIF_APPTAG_CHECK) {
to_be16(&dif->app_tag, app_tag); to_be16(&dif->app_tag, ctx->app_tag);
} }
if (dif_flags & SPDK_DIF_REFTAG_CHECK) { if (ctx->dif_flags & SPDK_DIF_REFTAG_CHECK) {
/* For type 1 and 2, the reference tag is incremented for each
* subsequent logical block. For type 3, the reference tag
* remains the same as the initial reference tag.
*/
if (ctx->dif_type != SPDK_DIF_TYPE3) {
ref_tag = ctx->init_ref_tag + offset_blocks;
} else {
ref_tag = ctx->init_ref_tag;
}
to_be32(&dif->ref_tag, ref_tag); to_be32(&dif->ref_tag, ref_tag);
} }
} }
static void static void
dif_generate(struct iovec *iovs, int iovcnt, dif_generate(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
uint32_t block_size, uint32_t guard_interval, uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
enum spdk_dif_type dif_type, uint32_t dif_flags,
uint32_t init_ref_tag, uint16_t app_tag)
{ {
struct _iov_iter iter; struct _iov_iter iter;
uint32_t offset_blocks, ref_tag; uint32_t offset_blocks;
void *buf; void *buf;
uint16_t guard = 0; uint16_t guard = 0;
@ -211,35 +252,22 @@ dif_generate(struct iovec *iovs, int iovcnt,
_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)) {
/* For type 1 and 2, the reference tag is incremented for each
* subsequent logical block. For type 3, the reference tag
* remains the same as the initial reference tag.
*/
if (dif_type != SPDK_DIF_TYPE3) {
ref_tag = init_ref_tag + offset_blocks;
} else {
ref_tag = init_ref_tag;
}
_iov_iter_get_buf(&iter, &buf, NULL); _iov_iter_get_buf(&iter, &buf, NULL);
if (dif_flags & SPDK_DIF_GUARD_CHECK) { if (ctx->dif_flags & SPDK_DIF_GUARD_CHECK) {
guard = spdk_crc16_t10dif(0, buf, guard_interval); guard = spdk_crc16_t10dif(0, buf, ctx->guard_interval);
} }
_dif_generate(buf + guard_interval, dif_flags, guard, ref_tag, _dif_generate(buf + ctx->guard_interval, guard, offset_blocks, ctx);
app_tag);
_iov_iter_advance(&iter, block_size); _iov_iter_advance(&iter, ctx->block_size);
offset_blocks++; offset_blocks++;
} }
} }
static void static void
_dif_generate_split(struct _iov_iter *iter, _dif_generate_split(struct _iov_iter *iter, uint32_t offset_blocks,
uint32_t block_size, uint32_t guard_interval, const struct spdk_dif_ctx *ctx)
enum spdk_dif_type dif_type, uint32_t dif_flags,
uint32_t ref_tag, uint16_t app_tag)
{ {
uint32_t offset_in_block, offset_in_dif, buf_len; uint32_t offset_in_block, offset_in_dif, buf_len;
void *buf; void *buf;
@ -249,32 +277,32 @@ _dif_generate_split(struct _iov_iter *iter,
guard = 0; guard = 0;
offset_in_block = 0; offset_in_block = 0;
while (offset_in_block < block_size && _iov_iter_cont(iter)) { while (offset_in_block < ctx->block_size && _iov_iter_cont(iter)) {
_iov_iter_get_buf(iter, &buf, &buf_len); _iov_iter_get_buf(iter, &buf, &buf_len);
if (offset_in_block < guard_interval) { if (offset_in_block < ctx->guard_interval) {
buf_len = spdk_min(buf_len, guard_interval - offset_in_block); buf_len = spdk_min(buf_len, ctx->guard_interval - offset_in_block);
if (dif_flags & SPDK_DIF_GUARD_CHECK) { if (ctx->dif_flags & SPDK_DIF_GUARD_CHECK) {
/* Compute CRC over split logical block data. */ /* Compute CRC over split logical block data. */
guard = spdk_crc16_t10dif(guard, buf, buf_len); guard = spdk_crc16_t10dif(guard, buf, buf_len);
} }
if (offset_in_block + buf_len == guard_interval) { if (offset_in_block + buf_len == ctx->guard_interval) {
/* If a whole logical block data is parsed, generate DIF /* If a whole logical block data is parsed, generate DIF
* and save it to the temporary DIF area. * and save it to the temporary DIF area.
*/ */
_dif_generate(&dif, dif_flags, guard, ref_tag, app_tag); _dif_generate(&dif, guard, offset_blocks, ctx);
} }
} else if (offset_in_block < guard_interval + sizeof(struct spdk_dif)) { } else if (offset_in_block < ctx->guard_interval + sizeof(struct spdk_dif)) {
/* Copy generated DIF to the split DIF field. */ /* Copy generated DIF to the split DIF field. */
offset_in_dif = offset_in_block - guard_interval; offset_in_dif = offset_in_block - ctx->guard_interval;
buf_len = spdk_min(buf_len, sizeof(struct spdk_dif) - offset_in_dif); buf_len = spdk_min(buf_len, sizeof(struct spdk_dif) - offset_in_dif);
memcpy(buf, ((uint8_t *)&dif) + offset_in_dif, buf_len); memcpy(buf, ((uint8_t *)&dif) + offset_in_dif, buf_len);
} else { } else {
/* Skip metadata field after DIF field. */ /* Skip metadata field after DIF field. */
buf_len = spdk_min(buf_len, block_size - offset_in_block); buf_len = spdk_min(buf_len, ctx->block_size - offset_in_block);
} }
_iov_iter_advance(iter, buf_len); _iov_iter_advance(iter, buf_len);
@ -283,85 +311,53 @@ _dif_generate_split(struct _iov_iter *iter,
} }
static void static void
dif_generate_split(struct iovec *iovs, int iovcnt, dif_generate_split(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
uint32_t block_size, uint32_t guard_interval, uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
enum spdk_dif_type dif_type, uint32_t dif_flags,
uint32_t init_ref_tag, uint16_t app_tag)
{ {
struct _iov_iter iter; struct _iov_iter iter;
uint32_t offset_blocks, ref_tag; uint32_t offset_blocks;
offset_blocks = 0; offset_blocks = 0;
_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)) {
/* For type 1 and 2, the reference tag is incremented for each _dif_generate_split(&iter, offset_blocks, ctx);
* subsequent logical block. For type 3, the reference tag
* remains the same as the initial reference tag.
*/
if (dif_type != SPDK_DIF_TYPE3) {
ref_tag = init_ref_tag + offset_blocks;
} else {
ref_tag = init_ref_tag;
}
_dif_generate_split(&iter, block_size, guard_interval,
dif_type, dif_flags, ref_tag, app_tag);
offset_blocks++; offset_blocks++;
} }
} }
int int
spdk_dif_generate(struct iovec *iovs, int iovcnt, spdk_dif_generate(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
uint32_t block_size, uint32_t md_size, uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
bool dif_loc, enum spdk_dif_type dif_type, uint32_t dif_flags,
uint32_t init_ref_tag, uint16_t app_tag)
{ {
uint32_t guard_interval; if (!_are_iovs_valid(iovs, iovcnt, ctx->block_size * num_blocks)) {
if (!_are_iovs_valid(iovs, iovcnt, block_size * num_blocks)) {
SPDK_ERRLOG("Size of iovec array is not valid.\n"); SPDK_ERRLOG("Size of iovec array is not valid.\n");
return -EINVAL; return -EINVAL;
} }
if (md_size < sizeof(struct spdk_dif)) { if (_dif_is_disabled(ctx->dif_type)) {
SPDK_ERRLOG("Metadata size is smaller than DIF size.\n");
return -EINVAL;
}
if (!_dif_type_is_valid(dif_type, dif_flags)) {
SPDK_ERRLOG("DIF type is invalid.\n");
return -EINVAL;
}
if (_dif_is_disabled(dif_type)) {
return 0; return 0;
} }
guard_interval = _get_dif_guard_interval(block_size, md_size, dif_loc); if (_are_iovs_bytes_multiple(iovs, iovcnt, ctx->block_size)) {
dif_generate(iovs, iovcnt, num_blocks, ctx);
if (_are_iovs_bytes_multiple(iovs, iovcnt, block_size)) {
dif_generate(iovs, iovcnt, block_size, guard_interval, num_blocks,
dif_type, dif_flags, init_ref_tag, app_tag);
} else { } else {
dif_generate_split(iovs, iovcnt, block_size, guard_interval, num_blocks, dif_generate_split(iovs, iovcnt, num_blocks, ctx);
dif_type, dif_flags, init_ref_tag, app_tag);
} }
return 0; return 0;
} }
static int static int
_dif_verify(void *_dif, enum spdk_dif_type dif_type, uint32_t dif_flags, _dif_verify(void *_dif, uint16_t guard, uint32_t offset_blocks,
uint16_t guard, uint32_t ref_tag, uint16_t apptag_mask, uint16_t app_tag) const struct spdk_dif_ctx *ctx)
{ {
struct spdk_dif *dif = _dif; struct spdk_dif *dif = _dif;
uint16_t _guard; uint16_t _guard;
uint16_t _app_tag; uint16_t _app_tag;
uint32_t _ref_tag; uint32_t ref_tag, _ref_tag;
switch (dif_type) { switch (ctx->dif_type) {
case SPDK_DIF_TYPE1: case SPDK_DIF_TYPE1:
case SPDK_DIF_TYPE2: case SPDK_DIF_TYPE2:
/* If Type 1 or 2 is used, then all DIF checks are disabled when /* If Type 1 or 2 is used, then all DIF checks are disabled when
@ -383,7 +379,17 @@ _dif_verify(void *_dif, enum spdk_dif_type dif_type, uint32_t dif_flags,
break; break;
} }
if (dif_flags & SPDK_DIF_GUARD_CHECK) { /* For type 1 and 2, the reference tag is incremented for each
* subsequent logical block. For type 3, the reference tag
* remains the same as the initial reference tag.
*/
if (ctx->dif_type != SPDK_DIF_TYPE3) {
ref_tag = ctx->init_ref_tag + offset_blocks;
} else {
ref_tag = ctx->init_ref_tag;
}
if (ctx->dif_flags & SPDK_DIF_GUARD_CHECK) {
/* Compare the DIF Guard field to the CRC computed over the logical /* Compare the DIF Guard field to the CRC computed over the logical
* block data. * block data.
*/ */
@ -396,21 +402,21 @@ _dif_verify(void *_dif, enum spdk_dif_type dif_type, uint32_t dif_flags,
} }
} }
if (dif_flags & SPDK_DIF_APPTAG_CHECK) { if (ctx->dif_flags & SPDK_DIF_APPTAG_CHECK) {
/* Compare unmasked bits in the DIF Application Tag field to the /* Compare unmasked bits in the DIF Application Tag field to the
* passed Application Tag. * passed Application Tag.
*/ */
_app_tag = from_be16(&dif->app_tag); _app_tag = from_be16(&dif->app_tag);
if ((_app_tag & apptag_mask) != app_tag) { if ((_app_tag & ctx->apptag_mask) != ctx->app_tag) {
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, app_tag, (_app_tag & apptag_mask)); ref_tag, ctx->app_tag, (_app_tag & ctx->apptag_mask));
return -1; return -1;
} }
} }
if (dif_flags & SPDK_DIF_REFTAG_CHECK) { if (ctx->dif_flags & SPDK_DIF_REFTAG_CHECK) {
switch (dif_type) { switch (ctx->dif_type) {
case SPDK_DIF_TYPE1: case SPDK_DIF_TYPE1:
case SPDK_DIF_TYPE2: case SPDK_DIF_TYPE2:
/* Compare the DIF Reference Tag field to the passed Reference Tag. /* Compare the DIF Reference Tag field to the passed Reference Tag.
@ -440,13 +446,11 @@ _dif_verify(void *_dif, enum spdk_dif_type dif_type, uint32_t dif_flags,
} }
static int static int
dif_verify(struct iovec *iovs, int iovcnt, dif_verify(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
uint32_t block_size, uint32_t guard_interval, uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
enum spdk_dif_type dif_type, uint32_t dif_flags, uint32_t init_ref_tag,
uint16_t apptag_mask, uint16_t app_tag)
{ {
struct _iov_iter iter; struct _iov_iter iter;
uint32_t offset_blocks, ref_tag; uint32_t offset_blocks;
int rc; int rc;
void *buf; void *buf;
uint16_t guard = 0; uint16_t guard = 0;
@ -455,29 +459,18 @@ dif_verify(struct iovec *iovs, int iovcnt,
_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)) {
/* For type 1 and 2, the reference tag is incremented for each
* subsequent logical block. For type 3, the reference tag
* remains the same as the initial reference tag.
*/
if (dif_type != SPDK_DIF_TYPE3) {
ref_tag = init_ref_tag + offset_blocks;
} else {
ref_tag = init_ref_tag;
}
_iov_iter_get_buf(&iter, &buf, NULL); _iov_iter_get_buf(&iter, &buf, NULL);
if (dif_flags & SPDK_DIF_GUARD_CHECK) { if (ctx->dif_flags & SPDK_DIF_GUARD_CHECK) {
guard = spdk_crc16_t10dif(0, buf, guard_interval); guard = spdk_crc16_t10dif(0, buf, ctx->guard_interval);
} }
rc = _dif_verify(buf + guard_interval, dif_type, dif_flags, rc = _dif_verify(buf + ctx->guard_interval, guard, offset_blocks, ctx);
guard, ref_tag, apptag_mask, app_tag);
if (rc != 0) { if (rc != 0) {
return rc; return rc;
} }
_iov_iter_advance(&iter, block_size); _iov_iter_advance(&iter, ctx->block_size);
offset_blocks++; offset_blocks++;
} }
@ -485,10 +478,8 @@ dif_verify(struct iovec *iovs, int iovcnt,
} }
static int static int
_dif_verify_split(struct _iov_iter *iter, _dif_verify_split(struct _iov_iter *iter, uint32_t offset_blocks,
uint32_t block_size, uint32_t guard_interval, const struct spdk_dif_ctx *ctx)
enum spdk_dif_type dif_type, uint32_t dif_flags,
uint32_t ref_tag, uint16_t apptag_mask, uint16_t app_tag)
{ {
uint32_t offset_in_block, offset_in_dif, buf_len; uint32_t offset_in_block, offset_in_dif, buf_len;
void *buf; void *buf;
@ -498,65 +489,50 @@ _dif_verify_split(struct _iov_iter *iter,
guard = 0; guard = 0;
offset_in_block = 0; offset_in_block = 0;
while (offset_in_block < block_size && _iov_iter_cont(iter)) { while (offset_in_block < ctx->block_size && _iov_iter_cont(iter)) {
_iov_iter_get_buf(iter, &buf, &buf_len); _iov_iter_get_buf(iter, &buf, &buf_len);
if (offset_in_block < guard_interval) { if (offset_in_block < ctx->guard_interval) {
buf_len = spdk_min(buf_len, guard_interval - offset_in_block); buf_len = spdk_min(buf_len, ctx->guard_interval - offset_in_block);
if (dif_flags & SPDK_DIF_GUARD_CHECK) { if (ctx->dif_flags & SPDK_DIF_GUARD_CHECK) {
/* Compute CRC over split logical block data. */ /* Compute CRC over split logical block data. */
guard = spdk_crc16_t10dif(guard, buf, buf_len); guard = spdk_crc16_t10dif(guard, buf, buf_len);
} }
} else if (offset_in_block < guard_interval + sizeof(struct spdk_dif)) { } else if (offset_in_block < ctx->guard_interval + sizeof(struct spdk_dif)) {
/* Copy the split DIF field to the temporary DIF buffer. */ /* Copy the split DIF field to the temporary DIF buffer. */
offset_in_dif = offset_in_block - guard_interval; offset_in_dif = offset_in_block - ctx->guard_interval;
buf_len = spdk_min(buf_len, sizeof(struct spdk_dif) - offset_in_dif); buf_len = spdk_min(buf_len, sizeof(struct spdk_dif) - offset_in_dif);
memcpy((uint8_t *)&dif + offset_in_dif, buf, buf_len); memcpy((uint8_t *)&dif + offset_in_dif, buf, buf_len);
} else { } else {
/* Skip metadata field after DIF field. */ /* Skip metadata field after DIF field. */
buf_len = spdk_min(buf_len, block_size - offset_in_block); buf_len = spdk_min(buf_len, ctx->block_size - offset_in_block);
} }
_iov_iter_advance(iter, buf_len); _iov_iter_advance(iter, buf_len);
offset_in_block += buf_len; offset_in_block += buf_len;
} }
return _dif_verify(&dif, dif_type, dif_flags, guard, ref_tag, apptag_mask, app_tag); return _dif_verify(&dif, guard, offset_blocks, ctx);
} }
static int static int
dif_verify_split(struct iovec *iovs, int iovcnt, dif_verify_split(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
uint32_t block_size, uint32_t guard_interval, uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
enum spdk_dif_type dif_type, uint32_t dif_flags,
uint32_t init_ref_tag, uint16_t apptag_mask, uint16_t app_tag)
{ {
struct _iov_iter iter; struct _iov_iter iter;
uint32_t offset_blocks; uint32_t offset_blocks;
uint32_t ref_tag;
int rc; int rc;
offset_blocks = 0; offset_blocks = 0;
_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)) {
/* For type 1 and 2, the reference tag is incremented for each rc = _dif_verify_split(&iter, offset_blocks, ctx);
* subsequent logical block. For type 3, the reference tag
* remains the same as the initial reference tag.
*/
if (dif_type != SPDK_DIF_TYPE3) {
ref_tag = init_ref_tag + offset_blocks;
} else {
ref_tag = init_ref_tag;
}
rc = _dif_verify_split(&iter, block_size, guard_interval, dif_type, dif_flags,
ref_tag, apptag_mask, app_tag);
if (rc != 0) { if (rc != 0) {
return rc; return rc;
} }
offset_blocks++; offset_blocks++;
} }
@ -564,40 +540,22 @@ dif_verify_split(struct iovec *iovs, int iovcnt,
} }
int int
spdk_dif_verify(struct iovec *iovs, int iovcnt, spdk_dif_verify(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
uint32_t block_size, uint32_t md_size, uint32_t num_blocks, const struct spdk_dif_ctx *ctx)
bool dif_loc, enum spdk_dif_type dif_type, uint32_t dif_flags,
uint32_t init_ref_tag, uint16_t apptag_mask, uint16_t app_tag)
{ {
uint32_t guard_interval; if (!_are_iovs_valid(iovs, iovcnt, ctx->block_size * num_blocks)) {
if (!_are_iovs_valid(iovs, iovcnt, block_size * num_blocks)) {
SPDK_ERRLOG("Size of iovec array is not valid.\n"); SPDK_ERRLOG("Size of iovec array is not valid.\n");
return -EINVAL; return -EINVAL;
} }
if (md_size < sizeof(struct spdk_dif)) { if (_dif_is_disabled(ctx->dif_type)) {
SPDK_ERRLOG("Metadata size is smaller than DIF size\n");
return -EINVAL;
}
if (!_dif_type_is_valid(dif_type, dif_flags)) {
SPDK_ERRLOG("DIF type is invalid.\n");
return -EINVAL;
}
if (_dif_is_disabled(dif_type)) {
return 0; return 0;
} }
guard_interval = _get_dif_guard_interval(block_size, md_size, dif_loc); if (_are_iovs_bytes_multiple(iovs, iovcnt, ctx->block_size)) {
return dif_verify(iovs, iovcnt, num_blocks, ctx);
if (_are_iovs_bytes_multiple(iovs, iovcnt, block_size)) {
return dif_verify(iovs, iovcnt, block_size, guard_interval, num_blocks,
dif_type, dif_flags, init_ref_tag, apptag_mask, app_tag);
} else { } else {
return dif_verify_split(iovs, iovcnt, block_size, guard_interval, num_blocks, return dif_verify_split(iovs, iovcnt, num_blocks, ctx);
dif_type, dif_flags, init_ref_tag, apptag_mask, app_tag);
} }
} }
@ -675,27 +633,19 @@ dif_inject_error(struct iovec *iovs, int iovcnt,
#define _member_size(type, member) sizeof(((type *)0)->member) #define _member_size(type, member) sizeof(((type *)0)->member)
int int
spdk_dif_inject_error(struct iovec *iovs, int iovcnt, spdk_dif_inject_error(struct iovec *iovs, int iovcnt, uint32_t num_blocks,
uint32_t block_size, uint32_t md_size, uint32_t num_blocks, const struct spdk_dif_ctx *ctx, uint32_t inject_flags)
bool dif_loc, uint32_t inject_flags)
{ {
uint32_t guard_interval;
int rc; int rc;
if (md_size < sizeof(struct spdk_dif)) { if (!_are_iovs_valid(iovs, iovcnt, ctx->block_size * num_blocks)) {
return -EINVAL;
}
if (!_are_iovs_valid(iovs, iovcnt, block_size * num_blocks)) {
SPDK_ERRLOG("Size of iovec array is not valid.\n"); SPDK_ERRLOG("Size of iovec array is not valid.\n");
return -EINVAL; return -EINVAL;
} }
guard_interval = _get_dif_guard_interval(block_size, md_size, dif_loc);
if (inject_flags & SPDK_DIF_REFTAG_ERROR) { if (inject_flags & SPDK_DIF_REFTAG_ERROR) {
rc = dif_inject_error(iovs, iovcnt, block_size, num_blocks, rc = dif_inject_error(iovs, iovcnt, ctx->block_size, num_blocks,
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));
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");
@ -704,8 +654,8 @@ spdk_dif_inject_error(struct iovec *iovs, int iovcnt,
} }
if (inject_flags & SPDK_DIF_APPTAG_ERROR) { if (inject_flags & SPDK_DIF_APPTAG_ERROR) {
rc = dif_inject_error(iovs, iovcnt, block_size, num_blocks, rc = dif_inject_error(iovs, iovcnt, ctx->block_size, num_blocks,
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));
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");
@ -713,8 +663,8 @@ spdk_dif_inject_error(struct iovec *iovs, int iovcnt,
} }
} }
if (inject_flags & SPDK_DIF_GUARD_ERROR) { if (inject_flags & SPDK_DIF_GUARD_ERROR) {
rc = dif_inject_error(iovs, iovcnt, block_size, num_blocks, rc = dif_inject_error(iovs, iovcnt, ctx->block_size, num_blocks,
guard_interval, ctx->guard_interval,
_member_size(struct spdk_dif, guard)); _member_size(struct spdk_dif, guard));
if (rc != 0) { if (rc != 0) {
SPDK_ERRLOG("Failed to inject error to Guard.\n"); SPDK_ERRLOG("Failed to inject error to Guard.\n");
@ -728,9 +678,9 @@ spdk_dif_inject_error(struct iovec *iovs, int iovcnt,
* 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.
*/ */
rc = dif_inject_error(iovs, iovcnt, block_size, num_blocks, rc = dif_inject_error(iovs, iovcnt, ctx->block_size, num_blocks,
0, 0,
block_size - md_size); ctx->block_size - ctx->md_size);
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

@ -131,26 +131,38 @@ _iov_free_buf(struct iovec *iov)
static void static void
_dif_generate_and_verify(struct iovec *iov, _dif_generate_and_verify(struct iovec *iov,
uint32_t block_size, uint32_t md_size, uint32_t guard_interval, uint32_t block_size, uint32_t md_size, bool dif_loc,
enum spdk_dif_type dif_type, uint32_t dif_flags, enum spdk_dif_type dif_type, uint32_t dif_flags,
uint32_t ref_tag, uint32_t e_ref_tag, uint32_t ref_tag, uint32_t e_ref_tag,
uint16_t app_tag, uint16_t apptag_mask, uint16_t e_app_tag, uint16_t app_tag, uint16_t apptag_mask, uint16_t e_app_tag,
bool expect_pass) bool expect_pass)
{ {
int rc; struct spdk_dif_ctx ctx = {};
uint32_t guard_interval;
uint16_t guard = 0; uint16_t guard = 0;
int rc;
rc = ut_data_pattern_generate(iov, 1, block_size, md_size, 1); rc = ut_data_pattern_generate(iov, 1, block_size, md_size, 1);
CU_ASSERT(rc == 0); CU_ASSERT(rc == 0);
guard_interval = _get_dif_guard_interval(block_size, md_size, dif_loc);
ctx.dif_type = dif_type;
ctx.dif_flags = dif_flags;
ctx.init_ref_tag = ref_tag;
ctx.app_tag = app_tag;
if (dif_flags & SPDK_DIF_GUARD_CHECK) { if (dif_flags & SPDK_DIF_GUARD_CHECK) {
guard = spdk_crc16_t10dif(0, iov->iov_base, guard_interval); guard = spdk_crc16_t10dif(0, iov->iov_base, guard_interval);
} }
_dif_generate(iov->iov_base + guard_interval, dif_flags, guard, ref_tag, app_tag); _dif_generate(iov->iov_base + guard_interval, guard, 0, &ctx);
rc = _dif_verify(iov->iov_base + guard_interval, dif_type, dif_flags, ctx.init_ref_tag = e_ref_tag;
guard, e_ref_tag, apptag_mask, e_app_tag); ctx.apptag_mask = apptag_mask;
ctx.app_tag = e_app_tag;
rc = _dif_verify(iov->iov_base + guard_interval, guard, 0, &ctx);
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);
@ -171,7 +183,7 @@ dif_generate_and_verify_test(void)
/* The case that DIF is contained in the first 8 bytes of metadata. */ /* The case that DIF is contained in the first 8 bytes of metadata. */
_dif_generate_and_verify(&iov, _dif_generate_and_verify(&iov,
4096 + 128, 128, 4096, 4096 + 128, 128, false,
SPDK_DIF_TYPE1, dif_flags, SPDK_DIF_TYPE1, dif_flags,
22, 22, 22, 22,
0x22, 0xFFFF, 0x22, 0x22, 0xFFFF, 0x22,
@ -179,7 +191,7 @@ dif_generate_and_verify_test(void)
/* The case that DIF is contained in the last 8 bytes of metadata. */ /* The case that DIF is contained in the last 8 bytes of metadata. */
_dif_generate_and_verify(&iov, _dif_generate_and_verify(&iov,
4096 + 128, 128, 4096 + 128 - 8, 4096 + 128, 128, true,
SPDK_DIF_TYPE1, dif_flags, SPDK_DIF_TYPE1, dif_flags,
22, 22, 22, 22,
0x22, 0xFFFF, 0x22, 0x22, 0xFFFF, 0x22,
@ -189,7 +201,7 @@ dif_generate_and_verify_test(void)
/* Reference tag doesn't match. */ /* Reference tag doesn't match. */
_dif_generate_and_verify(&iov, _dif_generate_and_verify(&iov,
4096 + 128, 128, 4096, 4096 + 128, 128, false,
SPDK_DIF_TYPE1, dif_flags, SPDK_DIF_TYPE1, dif_flags,
22, 23, 22, 23,
0x22, 0xFFFF, 0x22, 0x22, 0xFFFF, 0x22,
@ -197,7 +209,7 @@ dif_generate_and_verify_test(void)
/* Application tag doesn't match. */ /* Application tag doesn't match. */
_dif_generate_and_verify(&iov, _dif_generate_and_verify(&iov,
4096 + 128, 128, 4096, 4096 + 128, 128, false,
SPDK_DIF_TYPE1, dif_flags, SPDK_DIF_TYPE1, dif_flags,
22, 22, 22, 22,
0x22, 0xFFFF, 0x23, 0x22, 0xFFFF, 0x23,
@ -220,7 +232,7 @@ dif_disable_check_test(void)
* Type 1. DIF check is disabled and pass is expected. * Type 1. DIF check is disabled and pass is expected.
*/ */
_dif_generate_and_verify(&iov, _dif_generate_and_verify(&iov,
4096 + 128, 128, 4096, 4096 + 128, 128, false,
SPDK_DIF_TYPE1, dif_flags, SPDK_DIF_TYPE1, dif_flags,
22, 22, 22, 22,
0xFFFF, 0xFFFF, 0x22, 0xFFFF, 0xFFFF, 0x22,
@ -231,7 +243,7 @@ dif_disable_check_test(void)
* fail is expected. * fail is expected.
*/ */
_dif_generate_and_verify(&iov, _dif_generate_and_verify(&iov,
4096 + 128, 128, 4096, 4096 + 128, 128, false,
SPDK_DIF_TYPE3, dif_flags, SPDK_DIF_TYPE3, dif_flags,
22, 22, 22, 22,
0xFFFF, 0xFFFF, 0x22, 0xFFFF, 0xFFFF, 0x22,
@ -242,7 +254,7 @@ dif_disable_check_test(void)
* pass is expected. * pass is expected.
*/ */
_dif_generate_and_verify(&iov, _dif_generate_and_verify(&iov,
4096 + 128, 128, 4096, 4096 + 128, 128, false,
SPDK_DIF_TYPE3, dif_flags, SPDK_DIF_TYPE3, dif_flags,
0xFFFFFFFF, 22, 0xFFFFFFFF, 22,
0xFFFF, 0xFFFF, 0x22, 0xFFFF, 0xFFFF, 0x22,
@ -254,14 +266,11 @@ dif_disable_check_test(void)
static void static void
dif_sec_512_md_0_error_test(void) dif_sec_512_md_0_error_test(void)
{ {
struct iovec iov = {}; struct spdk_dif_ctx ctx = {};
int rc; int rc;
/* Metadata size is 0. */ /* Metadata size is 0. */
rc = spdk_dif_generate(&iov, 1, 512, 0, 1, false, SPDK_DIF_TYPE1, 0, 0, 0); rc = spdk_dif_ctx_init(&ctx, 512, 0, false, SPDK_DIF_TYPE1, 0, 0, 0, 0);
CU_ASSERT(rc != 0);
rc = spdk_dif_verify(&iov, 1, 512, 0, 1, false, SPDK_DIF_TYPE1, 0, 0, 0, 0);
CU_ASSERT(rc != 0); CU_ASSERT(rc != 0);
} }
@ -271,19 +280,20 @@ dif_generate_and_verify(struct iovec *iovs, int iovcnt,
bool dif_loc, enum spdk_dif_type dif_type, uint32_t dif_flags, bool dif_loc, enum spdk_dif_type dif_type, uint32_t dif_flags,
uint32_t init_ref_tag, uint16_t apptag_mask, uint16_t app_tag) uint32_t init_ref_tag, uint16_t apptag_mask, uint16_t app_tag)
{ {
struct spdk_dif_ctx ctx = {};
int rc; int rc;
rc = ut_data_pattern_generate(iovs, iovcnt, block_size, md_size, num_blocks); rc = ut_data_pattern_generate(iovs, iovcnt, block_size, md_size, num_blocks);
CU_ASSERT(rc == 0); CU_ASSERT(rc == 0);
rc = spdk_dif_generate(iovs, iovcnt, block_size, md_size, num_blocks, rc = spdk_dif_ctx_init(&ctx, block_size, md_size, dif_loc, dif_type, dif_flags,
dif_loc, dif_type, dif_flags, init_ref_tag, apptag_mask, app_tag);
init_ref_tag, app_tag);
CU_ASSERT(rc == 0); CU_ASSERT(rc == 0);
rc = spdk_dif_verify(iovs, iovcnt, block_size, md_size, num_blocks, rc = spdk_dif_generate(iovs, iovcnt, num_blocks, &ctx);
dif_loc, dif_type, dif_flags, CU_ASSERT(rc == 0);
init_ref_tag, apptag_mask, app_tag);
rc = spdk_dif_verify(iovs, iovcnt, num_blocks, &ctx);
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);
@ -562,6 +572,7 @@ _dif_inject_error_and_verify(struct iovec *iovs, int iovcnt,
uint32_t block_size, uint32_t md_size, uint32_t num_blocks, uint32_t block_size, uint32_t md_size, uint32_t num_blocks,
uint32_t inject_flags, bool dif_loc) uint32_t inject_flags, bool dif_loc)
{ {
struct spdk_dif_ctx ctx = {};
uint32_t dif_flags; uint32_t dif_flags;
int rc; int rc;
@ -570,16 +581,17 @@ _dif_inject_error_and_verify(struct iovec *iovs, int iovcnt,
rc = ut_data_pattern_generate(iovs, iovcnt, block_size, md_size, num_blocks); rc = ut_data_pattern_generate(iovs, iovcnt, block_size, md_size, num_blocks);
CU_ASSERT(rc == 0); CU_ASSERT(rc == 0);
rc = spdk_dif_generate(iovs, iovcnt, block_size, md_size, num_blocks, rc = spdk_dif_ctx_init(&ctx, block_size, md_size, dif_loc,
dif_loc, SPDK_DIF_TYPE1, dif_flags, 88, 0x88); SPDK_DIF_TYPE1, dif_flags, 88, 0xFFFF, 0x88);
CU_ASSERT(rc == 0); CU_ASSERT(rc == 0);
rc = spdk_dif_inject_error(iovs, iovcnt, block_size, md_size, num_blocks, rc = spdk_dif_generate(iovs, iovcnt, num_blocks, &ctx);
dif_loc, inject_flags);
CU_ASSERT(rc == 0); CU_ASSERT(rc == 0);
rc = spdk_dif_verify(iovs, iovcnt, block_size, md_size, num_blocks, rc = spdk_dif_inject_error(iovs, iovcnt, num_blocks, &ctx, inject_flags);
dif_loc, SPDK_DIF_TYPE1, dif_flags, 88, 0xFFFF, 0x88); CU_ASSERT(rc == 0);
rc = spdk_dif_verify(iovs, iovcnt, num_blocks, &ctx);
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);