From 952cf7e4f4393fcd9cf8c16b013d8f28915c990e Mon Sep 17 00:00:00 2001 From: Xavi Hernandez Date: Fri, 31 May 2019 18:40:30 +0200 Subject: libglusterfs: cleanup iovec functions This patch cleans some iovec code and creates two additional helper functions to simplify management of iovec structures. iov_range_copy(struct iovec *dst, uint32_t dst_count, uint32_t dst_offset, struct iovec *src, uint32_t src_count, uint32_t src_offset, uint32_t size); This function copies up to 'size' bytes from 'src' at offset 'src_offset' to 'dst' at 'dst_offset'. It returns the number of bytes copied. iov_skip(struct iovec *iovec, uint32_t count, uint32_t size); This function removes the initial 'size' bytes from 'iovec' and returns the updated number of iovec vectors remaining. The signature of iov_subset() has also been modified to make it safer and easier to use. The new signature is: iov_subset(struct iovec *src, int src_count, uint32_t start, uint32_t size, struct iovec **dst, int32_t dst_count); This function creates a new iovec array containing the subset of the 'src' vector starting at 'start' with size 'size'. The resulting array is allocated if '*dst' is NULL, or copied to '*dst' if it fits (based on 'dst_count'). It returns the number of iovec vectors used. A new set of functions to iterate through an iovec array have been created. They can be used to simplify the implementation of other iovec-based helper functions. Change-Id: Ia5fe57e388e23392a8d6cdab17670e337cadd587 Updates: bz#1193929 Signed-off-by: Xavi Hernandez --- libglusterfs/src/glusterfs/common-utils.h | 228 +++++++++++++++++++++--------- 1 file changed, 164 insertions(+), 64 deletions(-) (limited to 'libglusterfs') diff --git a/libglusterfs/src/glusterfs/common-utils.h b/libglusterfs/src/glusterfs/common-utils.h index 56ea83c37d9..49ebdba2fc2 100644 --- a/libglusterfs/src/glusterfs/common-utils.h +++ b/libglusterfs/src/glusterfs/common-utils.h @@ -512,65 +512,193 @@ static inline struct iovec * iov_dup(const struct iovec *vector, int count) { int bytecount = 0; - int i; struct iovec *newvec = NULL; bytecount = (count * sizeof(struct iovec)); newvec = GF_MALLOC(bytecount, gf_common_mt_iovec); - if (!newvec) - return NULL; - - for (i = 0; i < count; i++) { - newvec[i].iov_len = vector[i].iov_len; - newvec[i].iov_base = vector[i].iov_base; + if (newvec != NULL) { + memcpy(newvec, vector, bytecount); } return newvec; } -static inline int -iov_subset(struct iovec *orig, int orig_count, off_t src_offset, - off_t dst_offset, struct iovec *new) +typedef struct _iov_iter { + const struct iovec *iovec; + void *ptr; + uint32_t len; + uint32_t count; +} iov_iter_t; + +static inline bool +iov_iter_init(iov_iter_t *iter, const struct iovec *iovec, uint32_t count, + uint32_t offset) { - int new_count = 0; - int i; - off_t offset = 0; - size_t start_offset = 0; - size_t end_offset = 0, origin_iov_len = 0; + uint32_t len; - for (i = 0; i < orig_count; i++) { - origin_iov_len = orig[i].iov_len; + while (count > 0) { + count--; + len = iovec->iov_len; + if (offset < len) { + iter->ptr = iovec->iov_base + offset; + iter->len = len - offset; + iter->iovec = iovec + 1; + iter->count = count; - if ((offset + orig[i].iov_len < src_offset) || (offset > dst_offset)) { - goto not_subset; + return true; } + offset -= len; + } - if (!new) { - goto count_only; - } + memset(iter, 0, sizeof(*iter)); + + return false; +} + +static inline bool +iov_iter_end(iov_iter_t *iter) +{ + return iter->count == 0; +} + +static inline bool +iov_iter_next(iov_iter_t *iter, uint32_t size) +{ + GF_ASSERT(size <= iter->len); + + if (iter->len > size) { + iter->len -= size; + iter->ptr += size; + + return true; + } + if (iter->count > 0) { + iter->count--; + iter->ptr = iter->iovec->iov_base; + iter->len = iter->iovec->iov_len; + iter->iovec++; + + return true; + } + + memset(iter, 0, sizeof(*iter)); + + return false; +} + +static inline uint32_t +iov_iter_copy(iov_iter_t *dst, iov_iter_t *src, uint32_t size) +{ + uint32_t len; + + len = src->len; + if (len > dst->len) { + len = dst->len; + } + if (len > size) { + len = size; + } + memcpy(dst->ptr, src->ptr, len); - start_offset = 0; - end_offset = orig[i].iov_len; + return len; +} - if (src_offset >= offset) { - start_offset = (src_offset - offset); +static inline uint32_t +iov_iter_to_iovec(iov_iter_t *iter, struct iovec *iovec, int32_t idx, + uint32_t size) +{ + uint32_t len; + + len = iter->len; + if (len > size) { + len = size; + } + iovec[idx].iov_base = iter->ptr; + iovec[idx].iov_len = len; + + return len; +} + +static inline int +iov_subset(struct iovec *src, int src_count, uint32_t start, uint32_t size, + struct iovec **dst, int32_t dst_count) +{ + struct iovec iovec[src_count]; + iov_iter_t iter; + uint32_t len; + int32_t idx; + + if ((size == 0) || !iov_iter_init(&iter, src, src_count, start)) { + return 0; + } + + idx = 0; + do { + len = iov_iter_to_iovec(&iter, iovec, idx, size); + idx++; + size -= len; + } while ((size > 0) && iov_iter_next(&iter, len)); + + if (*dst == NULL) { + *dst = iov_dup(iovec, idx); + if (*dst == NULL) { + return -1; } + } else if (idx > dst_count) { + return -1; + } else { + memcpy(*dst, iovec, idx * sizeof(struct iovec)); + } - if (dst_offset <= (offset + orig[i].iov_len)) { - end_offset = (dst_offset - offset); + return idx; +} + +static inline int +iov_skip(struct iovec *iovec, uint32_t count, uint32_t size) +{ + uint32_t len, idx; + + idx = 0; + while ((size > 0) && (idx < count)) { + len = iovec[idx].iov_len; + if (len > size) { + iovec[idx].iov_len -= size; + iovec[idx].iov_base += size; + break; } + idx++; + size -= len; + } + + if (idx > 0) { + memmove(iovec, iovec + idx, (count - idx) * sizeof(struct iovec)); + } - new[new_count].iov_base = orig[i].iov_base + start_offset; - new[new_count].iov_len = end_offset - start_offset; + return count - idx; +} - count_only: - new_count++; +static inline size_t +iov_range_copy(const struct iovec *dst, uint32_t dst_count, uint32_t dst_offset, + const struct iovec *src, uint32_t src_count, uint32_t src_offset, + uint32_t size) +{ + iov_iter_t src_iter, dst_iter; + uint32_t len, total; - not_subset: - offset += origin_iov_len; + if ((size == 0) || !iov_iter_init(&src_iter, src, src_count, src_offset) || + !iov_iter_init(&dst_iter, dst, dst_count, dst_offset)) { + return 0; } - return new_count; + total = 0; + do { + len = iov_iter_copy(&dst_iter, &src_iter, size); + total += len; + size -= len; + } while ((size > 0) && iov_iter_next(&src_iter, len) && + iov_iter_next(&dst_iter, len)); + + return total; } static inline void @@ -609,35 +737,7 @@ iov_load(const struct iovec *vector, int count, char *buf, int size) static inline size_t iov_copy(const struct iovec *dst, int dcnt, const struct iovec *src, int scnt) { - size_t ret = 0; - size_t left = 0; - size_t min_i = 0; - int s_i = 0, s_ii = 0; - int d_i = 0, d_ii = 0; - - ret = min(iov_length(dst, dcnt), iov_length(src, scnt)); - left = ret; - - while (left) { - min_i = min(dst[d_i].iov_len - d_ii, src[s_i].iov_len - s_ii); - memcpy(dst[d_i].iov_base + d_ii, src[s_i].iov_base + s_ii, min_i); - - d_ii += min_i; - if (d_ii == dst[d_i].iov_len) { - d_ii = 0; - d_i++; - } - - s_ii += min_i; - if (s_ii == src[s_i].iov_len) { - s_ii = 0; - s_i++; - } - - left -= min_i; - } - - return ret; + return iov_range_copy(dst, dcnt, 0, src, scnt, 0, UINT32_MAX); } /* based on the amusing discussion @ https://rusty.ozlabs.org/?p=560 */ -- cgit