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:
parent
f6a91b3b40
commit
1750a0859b
@ -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 */
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user