Commit cd8c36f2 authored by Ben Walker's avatar Ben Walker Committed by Tomasz Zawadzki
Browse files

util: Add spdk_ioviter for iterating iovecs



spdk_ioviter_next will walk through two iovecs and yield pointers
to common length segments. For example, given a source iovec (siov) with
4 1KiB elements and a destination iovec (diov) with 1 4KiB element, the
following will happen:

first spdk_ioviter_next:

src = siov[0].iov_base
dst = diov[0].iov_base
len = 1KiB

second spdk_ioviter_next:

src = siov[1].iov_base
dst = diov[0].iov_base + 1KiB
len = 1KiB

third spdk_ioviter_next:

src = siov[2].iov_base
dst = diov[0].iov_base + 2KiB
len = 1KiB

fourth spdk_ioviter_next:

src = siov[3].iov_base
dst = diov[0].iov_base + 3KiB
len = 1KiB

fifth spdk_ioviter_next:

len = 0

This is a useful utility for performing operations where both the source
and destination are scattered memory. As an example and a test vehicle,
spdk_iovcpy has been updated to use this internally.

Change-Id: I7e35e76d38e78d07ea1caf6282d0dfc02182aa83
Signed-off-by: default avatarBen Walker <benjamin.walker@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/10284


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Mellanox Build Bot
Reviewed-by: default avatarChangpeng Liu <changpeng.liu@intel.com>
Reviewed-by: default avatarKonrad Sztyber <konrad.sztyber@intel.com>
Reviewed-by: default avatarPaul Luse <paul.e.luse@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
parent b33e68a7
Loading
Loading
Loading
Loading
+38 −0
Original line number Diff line number Diff line
@@ -136,6 +136,44 @@ spdk_divide_round_up(uint64_t num, uint64_t divisor)
 */
size_t spdk_iovcpy(struct iovec *siov, size_t siovcnt, struct iovec *diov, size_t diovcnt);

/**
 * An iovec iterator. Can be allocated on the stack.
 */
struct spdk_ioviter {
	struct iovec	*siov;
	size_t		siovcnt;

	struct iovec	*diov;
	size_t		diovcnt;

	size_t		sidx;
	size_t		didx;
	int		siov_len;
	uint8_t		*siov_base;
	int		diov_len;
	uint8_t		*diov_base;
};

/**
 * Initialize and move to the first common segment of the two given
 * iovecs. See spdk_ioviter_next().
 */
size_t spdk_ioviter_first(struct spdk_ioviter *iter,
			  struct iovec *siov, size_t siovcnt,
			  struct iovec *diov, size_t diovcnt,
			  void **src, void **dst);

/**
 * Move to the next segment in the iterator.
 *
 * This will iterate through the segments of the source and destination
 * and return the individual segments, one by one. For example, if the
 * source consists of one element of length 4k and the destination
 * consists of 4 elements each of length 1k, this function will return
 * 4 1k src+dst pairs of buffers, and then return 0 bytes to indicate
 * the iteration is complete on the fifth call.
 */
size_t spdk_ioviter_next(struct spdk_ioviter *iter, void **src, void **dst);

/**
 * Scan build is really pessimistic and assumes that mempool functions can
+1 −1
Original line number Diff line number Diff line
@@ -35,7 +35,7 @@ SPDK_ROOT_DIR := $(abspath $(CURDIR)/../..)
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk

SO_VER := 4
SO_MINOR := 0
SO_MINOR := 1

C_SRCS = base64.c bit_array.c cpuset.c crc16.c crc32.c crc32c.c crc32_ieee.c \
	 dif.c fd.c file.c iov.c math.c pipe.c strerror_tls.c string.c uuid.c \
+88 −66
Original line number Diff line number Diff line
@@ -34,77 +34,99 @@
#include "spdk/util.h"

size_t
spdk_iovcpy(struct iovec *siov, size_t siovcnt, struct iovec *diov, size_t diovcnt)
spdk_ioviter_first(struct spdk_ioviter *iter,
		   struct iovec *siov, size_t siovcnt,
		   struct iovec *diov, size_t diovcnt,
		   void **src, void **dst)
{
	size_t total_sz;
	size_t sidx;
	size_t didx;
	int siov_len;
	uint8_t *siov_base;
	int diov_len;
	uint8_t *diov_base;
	iter->siov = siov;
	iter->siovcnt = siovcnt;

	/* d prefix = destination. s prefix = source. */
	iter->diov = diov;
	iter->diovcnt = diovcnt;

	assert(diovcnt > 0);
	assert(siovcnt > 0);
	iter->sidx = 0;
	iter->didx = 0;
	iter->siov_len = siov[0].iov_len;
	iter->siov_base = siov[0].iov_base;
	iter->diov_len = diov[0].iov_len;
	iter->diov_base = diov[0].iov_base;

	total_sz = 0;
	sidx = 0;
	didx = 0;
	siov_len = siov[0].iov_len;
	siov_base = siov[0].iov_base;
	diov_len = diov[0].iov_len;
	diov_base = diov[0].iov_base;
	while (siov_len > 0 && diov_len > 0) {
		if (siov_len == diov_len) {
			memcpy(diov_base, siov_base, siov_len);
			total_sz += siov_len;
	return spdk_ioviter_next(iter, src, dst);
}

			/* Advance both iovs to the next element */
			sidx++;
			if (sidx == siovcnt) {
				break;
size_t
spdk_ioviter_next(struct spdk_ioviter *iter, void **src, void **dst)
{
	size_t len = 0;

	if (iter->sidx == iter->siovcnt ||
	    iter->didx == iter->diovcnt ||
	    iter->siov_len == 0 ||
	    iter->diov_len == 0) {
		return 0;
	}

			didx++;
			if (didx == diovcnt) {
				break;
	*src = iter->siov_base;
	*dst = iter->diov_base;
	len = spdk_min(iter->siov_len, iter->diov_len);

	if (iter->siov_len == iter->diov_len) {
		/* Advance both iovs to the next element */
		iter->sidx++;
		if (iter->sidx == iter->siovcnt) {
			return len;
		}

			siov_len = siov[sidx].iov_len;
			siov_base = siov[sidx].iov_base;
			diov_len = diov[didx].iov_len;
			diov_base = diov[didx].iov_base;
		} else if (siov_len < diov_len) {
			memcpy(diov_base, siov_base, siov_len);
			total_sz += siov_len;
		iter->didx++;
		if (iter->didx == iter->diovcnt) {
			return len;
		}

		iter->siov_len = iter->siov[iter->sidx].iov_len;
		iter->siov_base = iter->siov[iter->sidx].iov_base;
		iter->diov_len = iter->diov[iter->didx].iov_len;
		iter->diov_base = iter->diov[iter->didx].iov_base;
	} else if (iter->siov_len < iter->diov_len) {
		/* Advance only the source to the next element */
			sidx++;
			if (sidx == siovcnt) {
				break;
		iter->sidx++;
		if (iter->sidx == iter->siovcnt) {
			return len;
		}

			diov_base += siov_len;
			diov_len -= siov_len;
			siov_len = siov[sidx].iov_len;
			siov_base = siov[sidx].iov_base;
		iter->diov_base += iter->siov_len;
		iter->diov_len -= iter->siov_len;
		iter->siov_len = iter->siov[iter->sidx].iov_len;
		iter->siov_base = iter->siov[iter->sidx].iov_base;
	} else {
			memcpy(diov_base, siov_base, diov_len);
			total_sz += diov_len;

		/* Advance only the destination to the next element */
			didx++;
			if (didx == diovcnt) {
				break;
		iter->didx++;
		if (iter->didx == iter->diovcnt) {
			return len;
		}

		iter->siov_base += iter->diov_len;
		iter->siov_len -= iter->diov_len;
		iter->diov_len = iter->diov[iter->didx].iov_len;
		iter->diov_base = iter->diov[iter->didx].iov_base;
	}

			siov_base += diov_len;
			siov_len -= diov_len;
			diov_len = diov[didx].iov_len;
			diov_base = diov[didx].iov_base;
	return len;
}

size_t
spdk_iovcpy(struct iovec *siov, size_t siovcnt, struct iovec *diov, size_t diovcnt)
{
	struct spdk_ioviter iter;
	size_t len, total_sz;
	void *src, *dst;

	total_sz = 0;
	for (len = spdk_ioviter_first(&iter, siov, siovcnt, diov, diovcnt, &src, &dst);
	     len != 0;
	     len = spdk_ioviter_next(&iter, &src, &dst)) {
		memcpy(dst, src, len);
		total_sz += len;
	}

	return total_sz;
+2 −0
Original line number Diff line number Diff line
@@ -124,6 +124,8 @@
	spdk_u32log2;
	spdk_u64log2;
	spdk_iovcpy;
	spdk_ioviter_first;
	spdk_ioviter_next;

	# resolvers for functions in util.h
	spdk_u32log2.resolver;