dif: Process unaligned end of data buffer in spdk_dif_generate_stream()

NVMe/TCP target may split a whole data payload into multiple H2C
or C2H PDUs with any alignment. Hence to insert or strip DIF correctly
to the split H2C or C2H PDUs, we have to bring the interim guard
value of the last partial data block of the current H2C or C2H
PDU to the first partial data block of the next H2C or C2H PDU.

So we add last_guard to struct spdk_dif_ctx and use it in
spdk_dif_generate_stream().

API spdk_dif_generate_stream() is not changed and UT code should
pass without any change.

Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Change-Id: I12636c5ac7f619483402538faff4339a16c0e6b0
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/457545
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Darek Stojaczyk <dariusz.stojaczyk@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
This commit is contained in:
Shuhei Matsumoto 2019-06-13 09:48:58 +09:00 committed by Changpeng Liu
parent f6a91b3b40
commit 1750a0859b
2 changed files with 45 additions and 15 deletions

View File

@ -98,6 +98,13 @@ struct spdk_dif_ctx {
/* Offset to initial reference tag */
uint32_t ref_tag_offset;
/** Guard value of the last data block.
*
* Interim guard value is set if the last data block is partial, or
* seed value is set otherwise.
*/
uint16_t last_guard;
/* Seed value for guard computation */
uint16_t guard_seed;
};
@ -315,15 +322,21 @@ int spdk_dif_set_md_interleave_iovs(struct iovec *iovs, int iovcnt,
/**
* Generate and insert DIF into metadata space for newly read data block.
*
* When the extended LBA payload is splitted into multiple data segments,
* start of each data segment is passed through the DIF context. data_offset
* and data_len is within a data segment.
*
* \param iovs iovec array describing the extended LBA payload.
* \param iovcnt Number of elements in the iovec array.
* \param data_offset Offset to the newly read data in the extended LBA payload.
* \param data_len Length of the newly read data in the extended LBA payload.
* \param data_offset Offset to the newly read data in the current data segment of
* the extended LBA payload.
* \param data_len Length of the newly read data in the current data segment of
* the extended LBA payload.
* \param ctx DIF context.
*
* \return 0 on success and negated errno otherwise.
*/
int spdk_dif_generate_stream(struct iovec *iovs, int iovcnt,
uint32_t data_offset, uint32_t data_len,
const struct spdk_dif_ctx *ctx);
struct spdk_dif_ctx *ctx);
#endif /* SPDK_DIF_H */

View File

@ -258,6 +258,7 @@ spdk_dif_ctx_init(struct spdk_dif_ctx *ctx, uint32_t block_size, uint32_t md_siz
ctx->app_tag = app_tag;
ctx->data_offset = data_offset;
ctx->ref_tag_offset = data_offset / data_block_size;
ctx->last_guard = guard_seed;
ctx->guard_seed = guard_seed;
return 0;
@ -1465,9 +1466,10 @@ spdk_dif_set_md_interleave_iovs(struct iovec *iovs, int iovcnt,
int
spdk_dif_generate_stream(struct iovec *iovs, int iovcnt,
uint32_t data_offset, uint32_t data_len,
const struct spdk_dif_ctx *ctx)
struct spdk_dif_ctx *ctx)
{
uint32_t data_block_size, offset_blocks, num_blocks, i;
uint32_t data_block_size, buf_len, buf_offset;
uint32_t len, offset_in_block, offset_blocks;
uint16_t guard = 0;
struct _dif_sgl sgl;
@ -1478,25 +1480,40 @@ spdk_dif_generate_stream(struct iovec *iovs, int iovcnt,
data_block_size = ctx->block_size - ctx->md_size;
if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
guard = ctx->guard_seed;
guard = ctx->last_guard;
}
offset_blocks = data_offset / data_block_size;
data_len += data_offset % data_block_size;
data_offset = offset_blocks * ctx->block_size;
num_blocks = data_len / data_block_size;
/* If the last data block is complete, DIF of the data block is
* inserted in this function.
*/
buf_len = ((data_offset + data_len) / data_block_size) * ctx->block_size +
((data_offset + data_len) % data_block_size);
_dif_sgl_init(&sgl, iovs, iovcnt);
if (!_dif_sgl_is_valid(&sgl, data_offset + num_blocks * ctx->block_size)) {
if (!_dif_sgl_is_valid(&sgl, buf_len)) {
return -ERANGE;
}
_dif_sgl_advance(&sgl, data_offset);
buf_offset = (data_offset / data_block_size) * ctx->block_size +
(data_offset % data_block_size);
for (i = 0; i < num_blocks; i++) {
_dif_generate_split(&sgl, 0, ctx->block_size, guard, offset_blocks + i, ctx);
_dif_sgl_advance(&sgl, buf_offset);
buf_len -= buf_offset;
while (buf_len != 0) {
len = spdk_min(buf_len, _to_next_boundary(buf_offset, ctx->block_size));
offset_in_block = buf_offset % ctx->block_size;
offset_blocks = buf_offset / ctx->block_size;
guard = _dif_generate_split(&sgl, offset_in_block, len, guard, offset_blocks, ctx);
buf_len -= len;
buf_offset += len;
}
if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
ctx->last_guard = guard;
}
return 0;