They're hidden inside net/core/iovec.c. It'd be nice to just link to that but they're not too generic and come with tons of net/ specific code we don't want. So we just copy over the relevant parts. Signed-off-by: Sasha Levin <sasha.levin@xxxxxxxxxx> --- tools/kvm/Makefile | 1 + tools/kvm/include/kvm/iovec.h | 21 +++++++ tools/kvm/include/linux/kernel.h | 10 ++++ tools/kvm/util/iovec.c | 126 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 158 insertions(+) create mode 100644 tools/kvm/include/kvm/iovec.h create mode 100644 tools/kvm/util/iovec.c diff --git a/tools/kvm/Makefile b/tools/kvm/Makefile index a0a0a9b..70accaa 100644 --- a/tools/kvm/Makefile +++ b/tools/kvm/Makefile @@ -86,6 +86,7 @@ OBJS += net/uip/csum.o OBJS += net/uip/dhcp.o OBJS += kvm-cmd.o OBJS += util/init.o +OBJS += util/iovec.o OBJS += util/rbtree.o OBJS += util/threadpool.o OBJS += util/parse-options.o diff --git a/tools/kvm/include/kvm/iovec.h b/tools/kvm/include/kvm/iovec.h new file mode 100644 index 0000000..fe79dd4 --- /dev/null +++ b/tools/kvm/include/kvm/iovec.h @@ -0,0 +1,21 @@ +#ifndef KVM_UTIL_IOVEC_H_ +#define KVM_UTIL_IOVEC_H_ + +extern int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len); +extern int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov, + size_t offset, int len); +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); + +static inline size_t iov_size(const struct iovec *iovec, size_t len) +{ + size_t size = 0, i; + + for (i = 0; i < len; i++) + size += iovec[i].iov_len; + + return size; +} + +#endif diff --git a/tools/kvm/include/linux/kernel.h b/tools/kvm/include/linux/kernel.h index 1e9abe9..f2bff5f 100644 --- a/tools/kvm/include/linux/kernel.h +++ b/tools/kvm/include/linux/kernel.h @@ -36,6 +36,16 @@ (void) (&_max1 == &_max2); \ _max1 > _max2 ? _max1 : _max2; }) +#define min_t(type, x, y) ({ \ + type __min1 = (x); \ + type __min2 = (y); \ + __min1 < __min2 ? __min1: __min2; }) + +#define max_t(type, x, y) ({ \ + type __max1 = (x); \ + type __max2 = (y); \ + __max1 > __max2 ? __max1: __max2; }) + #define true 1 #endif diff --git a/tools/kvm/util/iovec.c b/tools/kvm/util/iovec.c new file mode 100644 index 0000000..0c8b9cf --- /dev/null +++ b/tools/kvm/util/iovec.c @@ -0,0 +1,126 @@ +/* + * iovec manipulation routines. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Fixes: + * Andrew Lunn : Errors in iovec copying. + * Pedro Roque : Added memcpy_fromiovecend and + * csum_..._fromiovecend. + * Andi Kleen : fixed error handling for 2.1 + * Alexey Kuznetsov: 2.1 optimisations + * Andi Kleen : Fix csum*fromiovecend for IPv6. + */ + +#include <linux/errno.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/compiler.h> +#include <sys/uio.h> +#include <kvm/iovec.h> +#include <string.h> + +/* + * Copy kernel to iovec. Returns -EFAULT on error. + * + * Note: this modifies the original iovec. + */ + +int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len) +{ + while (len > 0) { + if (iov->iov_len) { + int copy = min_t(unsigned int, iov->iov_len, len); + memcpy(iov->iov_base, kdata, copy); + kdata += copy; + len -= copy; + iov->iov_len -= copy; + iov->iov_base += copy; + } + iov++; + } + + return 0; +} +EXPORT_SYMBOL(memcpy_toiovec); + +/* + * Copy kernel to iovec. Returns -EFAULT on error. + */ + +int memcpy_toiovecend(const struct iovec *iov, unsigned char *kdata, + size_t offset, int len) +{ + int copy; + for (; len > 0; ++iov) { + /* Skip over the finished iovecs */ + if (unlikely(offset >= iov->iov_len)) { + offset -= iov->iov_len; + continue; + } + copy = min_t(unsigned int, iov->iov_len - offset, len); + memcpy(iov->iov_base + offset, kdata, copy); + offset = 0; + kdata += copy; + len -= copy; + } + + return 0; +} +EXPORT_SYMBOL(memcpy_toiovecend); + +/* + * Copy iovec to kernel. Returns -EFAULT on error. + * + * Note: this modifies the original iovec. + */ + +int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len) +{ + while (len > 0) { + if (iov->iov_len) { + int copy = min_t(unsigned int, len, iov->iov_len); + memcpy(kdata, iov->iov_base, copy); + len -= copy; + kdata += copy; + iov->iov_base += copy; + iov->iov_len -= copy; + } + iov++; + } + + return 0; +} +EXPORT_SYMBOL(memcpy_fromiovec); + +/* + * Copy iovec from kernel. Returns -EFAULT on error. + */ + +int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov, + size_t offset, int len) +{ + /* Skip over the finished iovecs */ + while (offset >= iov->iov_len) { + offset -= iov->iov_len; + iov++; + } + + while (len > 0) { + char *base = iov->iov_base + offset; + int copy = min_t(unsigned int, len, iov->iov_len - offset); + + offset = 0; + memcpy(kdata, base, copy); + len -= copy; + kdata += copy; + iov++; + } + + return 0; +} +EXPORT_SYMBOL(memcpy_fromiovecend); -- 1.8.2.1 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html