Commit 1750a085 authored by Shuhei Matsumoto's avatar Shuhei Matsumoto Committed by Changpeng Liu
Browse files

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: default avatarShuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Change-Id: I12636c5ac7f619483402538faff4339a16c0e6b0
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/457545


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarDarek Stojaczyk <dariusz.stojaczyk@intel.com>
Reviewed-by: default avatarChangpeng Liu <changpeng.liu@intel.com>
parent f6a91b3b
Loading
Loading
Loading
Loading
+16 −3
Original line number Diff line number Diff line
@@ -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 */
+29 −12
Original line number Diff line number Diff line
@@ -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);

	_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);

	for (i = 0; i < num_blocks; i++) {
		_dif_generate_split(&sgl, 0, ctx->block_size, guard, offset_blocks + i, ctx);
		buf_len -= len;
		buf_offset += len;
	}

	if (ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK) {
		ctx->last_guard = guard;
	}

	return 0;