aboutgitcodebugslistschat
path: root/iov.c
diff options
context:
space:
mode:
Diffstat (limited to 'iov.c')
-rw-r--r--iov.c129
1 files changed, 91 insertions, 38 deletions
diff --git a/iov.c b/iov.c
index 52a7c01..91e87a7 100644
--- a/iov.c
+++ b/iov.c
@@ -26,7 +26,8 @@
#include "iov.h"
-/* iov_skip_bytes() - Skip leading bytes of an IO vector
+/**
+ * iov_skip_bytes() - Skip leading bytes of an IO vector
* @iov: IO vector
* @n: Number of entries in @iov
* @skip: Number of leading bytes of @iov to skip
@@ -56,8 +57,8 @@ size_t iov_skip_bytes(const struct iovec *iov, size_t n,
}
/**
- * iov_from_buf - Copy data from a buffer to an I/O vector (struct iovec)
- * efficiently.
+ * iov_from_buf() - Copy data from a buffer to an I/O vector (struct iovec)
+ * efficiently.
*
* @iov: Pointer to the array of struct iovec describing the
* scatter/gather I/O vector.
@@ -68,7 +69,6 @@ size_t iov_skip_bytes(const struct iovec *iov, size_t n,
*
* Returns: The number of bytes successfully copied.
*/
-/* cppcheck-suppress unusedFunction */
size_t iov_from_buf(const struct iovec *iov, size_t iov_cnt,
size_t offset, const void *buf, size_t bytes)
{
@@ -97,8 +97,8 @@ size_t iov_from_buf(const struct iovec *iov, size_t iov_cnt,
}
/**
- * iov_to_buf - Copy data from a scatter/gather I/O vector (struct iovec) to
- * a buffer efficiently.
+ * iov_to_buf() - Copy data from a scatter/gather I/O vector (struct iovec) to
+ * a buffer efficiently.
*
* @iov: Pointer to the array of struct iovec describing the scatter/gather
* I/O vector.
@@ -137,8 +137,8 @@ size_t iov_to_buf(const struct iovec *iov, size_t iov_cnt,
}
/**
- * iov_size - Calculate the total size of a scatter/gather I/O vector
- * (struct iovec).
+ * iov_size() - Calculate the total size of a scatter/gather I/O vector
+ * (struct iovec).
*
* @iov: Pointer to the array of struct iovec describing the
* scatter/gather I/O vector.
@@ -158,40 +158,93 @@ size_t iov_size(const struct iovec *iov, size_t iov_cnt)
}
/**
- * iov_copy - Copy data from one scatter/gather I/O vector (struct iovec) to
- * another.
- *
- * @dst_iov: Pointer to the destination array of struct iovec describing
- * the scatter/gather I/O vector to copy to.
- * @dst_iov_cnt: Number of elements in the destination iov array.
- * @iov: Pointer to the source array of struct iovec describing
- * the scatter/gather I/O vector to copy from.
- * @iov_cnt: Number of elements in the source iov array.
- * @offset: Offset within the source iov from where copying should start.
- * @bytes: Total number of bytes to copy from iov to dst_iov.
- *
- * Returns: The number of elements successfully copied to the destination
- * iov array.
+ * iov_tail_prune() - Remove any unneeded buffers from an IOV tail
+ * @tail: IO vector tail (modified)
+ *
+ * If an IOV tail's offset is large enough, it may not include any bytes from
+ * the first (or first several) buffers in the underlying IO vector. Modify the
+ * tail's representation so it contains the same logical bytes, but only
+ * includes buffers that are actually needed. This will avoid stepping through
+ * unnecessary elements of the underlying IO vector on future operations.
+ *
+ * Return: true if the tail still contains any bytes, otherwise false
*/
-/* cppcheck-suppress unusedFunction */
-unsigned iov_copy(struct iovec *dst_iov, size_t dst_iov_cnt,
- const struct iovec *iov, size_t iov_cnt,
- size_t offset, size_t bytes)
+bool iov_tail_prune(struct iov_tail *tail)
{
- unsigned int i, j;
+ size_t i;
- i = iov_skip_bytes(iov, iov_cnt, offset, &offset);
+ i = iov_skip_bytes(tail->iov, tail->cnt, tail->off, &tail->off);
+ tail->iov += i;
+ tail->cnt -= i;
- /* copying data */
- for (j = 0; i < iov_cnt && j < dst_iov_cnt && bytes; i++) {
- size_t len = MIN(bytes, iov[i].iov_len - offset);
+ return !!tail->cnt;
+}
- dst_iov[j].iov_base = (char *)iov[i].iov_base + offset;
- dst_iov[j].iov_len = len;
- j++;
- bytes -= len;
- offset = 0;
- }
+/**
+ * iov_tail_size - Calculate the total size of an IO vector tail
+ * @tail: IO vector tail
+ *
+ * Returns: The total size in bytes.
+ */
+size_t iov_tail_size(struct iov_tail *tail)
+{
+ iov_tail_prune(tail);
+ return iov_size(tail->iov, tail->cnt) - tail->off;
+}
+
+/**
+ * iov_peek_header_() - Get pointer to a header from an IOV tail
+ * @tail: IOV tail to get header from
+ * @len: Length of header to get, in bytes
+ * @align: Required alignment of header, in bytes
+ *
+ * @tail may be pruned, but will represent the same bytes as before.
+ *
+ * Returns: Pointer to the first @len logical bytes of the tail, NULL if that
+ * overruns the IO vector, is not contiguous or doesn't have the
+ * requested alignment.
+ */
+/* cppcheck-suppress [staticFunction,unmatchedSuppression] */
+void *iov_peek_header_(struct iov_tail *tail, size_t len, size_t align)
+{
+ char *p;
+
+ if (!iov_tail_prune(tail))
+ return NULL; /* Nothing left */
+
+ if (tail->off + len < tail->off)
+ return NULL; /* Overflow */
+
+ if (tail->off + len > tail->iov[0].iov_len)
+ return NULL; /* Not contiguous */
+
+ p = (char *)tail->iov[0].iov_base + tail->off;
+ if ((uintptr_t)p % align)
+ return NULL; /* not aligned */
+
+ return p;
+}
+
+/**
+ * iov_remove_header_() - Remove a header from an IOV tail
+ * @tail: IOV tail to remove header from (modified)
+ * @len: Length of header to remove, in bytes
+ * @align: Required alignment of header, in bytes
+ *
+ * On success, @tail is updated so that it longer includes the bytes of the
+ * returned header.
+ *
+ * Returns: Pointer to the first @len logical bytes of the tail, NULL if that
+ * overruns the IO vector, is not contiguous or doesn't have the
+ * requested alignment.
+ */
+void *iov_remove_header_(struct iov_tail *tail, size_t len, size_t align)
+{
+ char *p = iov_peek_header_(tail, len, align);
+
+ if (!p)
+ return NULL;
- return j;
+ tail->off = tail->off + len;
+ return p;
}