aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJean-Philippe Brucker <jean-philippe.brucker@arm.com>2022-06-07 18:02:25 +0100
committerWill Deacon <will@kernel.org>2022-06-09 13:44:14 +0100
commitc492534f3ac930107a628c0fadd4c152e8972b35 (patch)
tree78c60a513d61b4727ae22ea6172efb5b64226596
parent902a8ecb3877d383cc601571611690050fed9e48 (diff)
downloadkvmtool-c492534f3ac930107a628c0fadd4c152e8972b35.tar.gz
Add memcpy_fromiovec_safe
Existing IOV functions don't take the iovec size as parameter. This is unfortunate because when parsing buffers split into header and body, callers may want to know where the body starts in the iovec, after copying the header. Add a function that does the same as memcpy_fromiovec, but also allows to iterate over the iovec. Signed-off-by: Jean-Philippe Brucker <jean-philippe.brucker@arm.com> Link: https://lore.kernel.org/r/20220607170239.120084-11-jean-philippe.brucker@arm.com Signed-off-by: Will Deacon <will@kernel.org>
-rw-r--r--include/kvm/iovec.h2
-rw-r--r--util/iovec.c31
2 files changed, 33 insertions, 0 deletions
diff --git a/include/kvm/iovec.h b/include/kvm/iovec.h
index fe79dd48..55a03913 100644
--- a/include/kvm/iovec.h
+++ b/include/kvm/iovec.h
@@ -7,6 +7,8 @@ extern int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov,
extern int memcpy_toiovec(struct iovec *v, unsigned char *kdata, int len);
extern int memcpy_toiovecend(const struct iovec *v, unsigned char *kdata,
size_t offset, int len);
+ssize_t memcpy_fromiovec_safe(void *buf, struct iovec **iov, size_t len,
+ size_t *iovcount);
static inline size_t iov_size(const struct iovec *iovec, size_t len)
{
diff --git a/util/iovec.c b/util/iovec.c
index 089f1051..c0159011 100644
--- a/util/iovec.c
+++ b/util/iovec.c
@@ -94,6 +94,37 @@ int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len)
}
/*
+ * Copy at most @len bytes from iovec to buffer.
+ * Returns the remaining len.
+ *
+ * Note: this modifies the original iovec, the iov pointer, and the
+ * iovcount to describe the remaining buffer.
+ */
+ssize_t memcpy_fromiovec_safe(void *buf, struct iovec **iov, size_t len,
+ size_t *iovcount)
+{
+ size_t copy;
+
+ while (len && *iovcount) {
+ copy = min(len, (*iov)->iov_len);
+ memcpy(buf, (*iov)->iov_base, copy);
+ buf += copy;
+ len -= copy;
+
+ /* Move iov cursor */
+ (*iov)->iov_base += copy;
+ (*iov)->iov_len -= copy;
+
+ if (!(*iov)->iov_len) {
+ (*iov)++;
+ (*iovcount)--;
+ }
+ }
+
+ return len;
+}
+
+/*
* Copy iovec from kernel. Returns -EFAULT on error.
*/