diff --git a/include/spdk/util.h b/include/spdk/util.h index e052bcf41..d4c2880b5 100644 --- a/include/spdk/util.h +++ b/include/spdk/util.h @@ -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 diff --git a/lib/util/Makefile b/lib/util/Makefile index 5acca39c3..b282ed562 100644 --- a/lib/util/Makefile +++ b/lib/util/Makefile @@ -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 \ diff --git a/lib/util/iov.c b/lib/util/iov.c index e89ef9d21..cd911728f 100644 --- a/lib/util/iov.c +++ b/lib/util/iov.c @@ -33,78 +33,100 @@ #include "spdk/util.h" +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) +{ + iter->siov = siov; + iter->siovcnt = siovcnt; + + iter->diov = diov; + iter->diovcnt = diovcnt; + + 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; + + return spdk_ioviter_next(iter, src, dst); +} + +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; + } + + *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; + } + + 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 */ + iter->sidx++; + if (iter->sidx == iter->siovcnt) { + return len; + } + + 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 { + /* Advance only the destination to the next element */ + 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; + } + + return len; +} + size_t spdk_iovcpy(struct iovec *siov, size_t siovcnt, struct iovec *diov, size_t diovcnt) { - size_t total_sz; - size_t sidx; - size_t didx; - int siov_len; - uint8_t *siov_base; - int diov_len; - uint8_t *diov_base; - - /* d prefix = destination. s prefix = source. */ - - assert(diovcnt > 0); - assert(siovcnt > 0); + struct spdk_ioviter iter; + size_t len, total_sz; + void *src, *dst; 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; - - /* Advance both iovs to the next element */ - sidx++; - if (sidx == siovcnt) { - break; - } - - didx++; - if (didx == diovcnt) { - break; - } - - 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; - - /* Advance only the source to the next element */ - sidx++; - if (sidx == siovcnt) { - break; - } - - diov_base += siov_len; - diov_len -= siov_len; - siov_len = siov[sidx].iov_len; - siov_base = siov[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; - } - - siov_base += diov_len; - siov_len -= diov_len; - diov_len = diov[didx].iov_len; - diov_base = diov[didx].iov_base; - } + 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; diff --git a/lib/util/spdk_util.map b/lib/util/spdk_util.map index 88705e416..e72a2e254 100644 --- a/lib/util/spdk_util.map +++ b/lib/util/spdk_util.map @@ -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;