diff mbox

[1/8] lib/iovec: Add memcpy_fromiovec_out library function

Message ID 1422605552-24797-2-git-send-email-nab@daterainc.com (mailing list archive)
State New, archived
Headers show

Commit Message

Nicholas A. Bellinger Jan. 30, 2015, 8:12 a.m. UTC
From: Nicholas Bellinger <nab@linux-iscsi.org>

This patch adds a new memcpy_fromiovec_out() library function which modifies
the passed *iov following memcpy_fromiovec(), but also returns the next current
iovec pointer via **iov_out.

This is useful for vhost ANY_LAYOUT support when guests are allowed to generate
incoming virtio request headers combined with subsequent SGL payloads into a
single iovec.

Cc: Michael S. Tsirkin <mst@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
---
 include/linux/uio.h |  2 ++
 lib/iovec.c         | 27 +++++++++++++++++++++++++++
 2 files changed, 29 insertions(+)

Comments

Paolo Bonzini Jan. 30, 2015, 9:33 a.m. UTC | #1
On 30/01/2015 09:12, Nicholas A. Bellinger wrote:
> From: Nicholas Bellinger <nab@linux-iscsi.org>
> 
> This patch adds a new memcpy_fromiovec_out() library function which modifies
> the passed *iov following memcpy_fromiovec(), but also returns the next current
> iovec pointer via **iov_out.
> 
> This is useful for vhost ANY_LAYOUT support when guests are allowed to generate
> incoming virtio request headers combined with subsequent SGL payloads into a
> single iovec.
> 
> Cc: Michael S. Tsirkin <mst@redhat.com>
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
> ---
>  include/linux/uio.h |  2 ++
>  lib/iovec.c         | 27 +++++++++++++++++++++++++++
>  2 files changed, 29 insertions(+)
> 
> diff --git a/include/linux/uio.h b/include/linux/uio.h
> index 1c5e453..3e4473d 100644
> --- a/include/linux/uio.h
> +++ b/include/linux/uio.h
> @@ -136,6 +136,8 @@ size_t csum_and_copy_to_iter(void *addr, size_t bytes, __wsum *csum, struct iov_
>  size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum, struct iov_iter *i);
>  
>  int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len);
> +int memcpy_fromiovec_out(unsigned char *kdata, struct iovec *iov,
> +			 struct iovec **iov_out, int len);
>  int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov,
>  			int offset, int len);
>  int memcpy_toiovecend(const struct iovec *v, unsigned char *kdata,
> diff --git a/lib/iovec.c b/lib/iovec.c
> index 2d99cb4..6a813dd 100644
> --- a/lib/iovec.c
> +++ b/lib/iovec.c
> @@ -28,6 +28,33 @@ int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len)
>  EXPORT_SYMBOL(memcpy_fromiovec);
>  
>  /*
> + *	Copy iovec to kernel, saving the current iov to *iov_out.
> + *	Returns -EFAULT on error.

Perhaps document that iov is modified, zeroing everything in [iov,
*iov_out) and possibly removing the front of *iov_out?

Paolo

> + */
> +
> +int memcpy_fromiovec_out(unsigned char *kdata, struct iovec *iov,
> +			 struct iovec **iov_out, int len)
> +{
> +	while (len > 0) {
> +		if (iov->iov_len) {
> +			int copy = min_t(unsigned int, len, iov->iov_len);
> +			if (copy_from_user(kdata, iov->iov_base, copy))
> +				return -EFAULT;
> +			len -= copy;
> +			kdata += copy;
> +			iov->iov_base += copy;
> +			iov->iov_len -= copy;
> +		}
> +		if (!iov->iov_len)
> +			iov++;
> +	}
> +	*iov_out = iov;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(memcpy_fromiovec_out);
> +
> +/*
>   *	Copy kernel to iovec. Returns -EFAULT on error.
>   */
>  
> 
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Nicholas A. Bellinger Feb. 1, 2015, 7:15 a.m. UTC | #2
On Fri, 2015-01-30 at 10:33 +0100, Paolo Bonzini wrote:
> 
> On 30/01/2015 09:12, Nicholas A. Bellinger wrote:
> > From: Nicholas Bellinger <nab@linux-iscsi.org>
> > 
> > This patch adds a new memcpy_fromiovec_out() library function which modifies
> > the passed *iov following memcpy_fromiovec(), but also returns the next current
> > iovec pointer via **iov_out.
> > 
> > This is useful for vhost ANY_LAYOUT support when guests are allowed to generate
> > incoming virtio request headers combined with subsequent SGL payloads into a
> > single iovec.
> > 
> > Cc: Michael S. Tsirkin <mst@redhat.com>
> > Cc: Paolo Bonzini <pbonzini@redhat.com>
> > Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
> > ---
> >  include/linux/uio.h |  2 ++
> >  lib/iovec.c         | 27 +++++++++++++++++++++++++++
> >  2 files changed, 29 insertions(+)
> > 

<SNIP>

> > --- a/lib/iovec.c
> > +++ b/lib/iovec.c
> > @@ -28,6 +28,33 @@ int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len)
> >  EXPORT_SYMBOL(memcpy_fromiovec);
> >  
> >  /*
> > + *	Copy iovec to kernel, saving the current iov to *iov_out.
> > + *	Returns -EFAULT on error.
> 
> Perhaps document that iov is modified, zeroing everything in [iov,
> *iov_out) and possibly removing the front of *iov_out?
> 

Sure, updated the read the following:

 *      Copy iovec to kernel, modifying the passed *iov entries.
 *
 *      Save **iov_out for the caller to use upon return, that may either
 *      contain the current entry with a re-calculated iov_base + iov_len
 *      or next unmodified entry.
 *
 *      Also note that any iovec entries preceding the final *iov_out are
 *      zeroed by copy_from_user().

Thank you,

--nab

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/include/linux/uio.h b/include/linux/uio.h
index 1c5e453..3e4473d 100644
--- a/include/linux/uio.h
+++ b/include/linux/uio.h
@@ -136,6 +136,8 @@  size_t csum_and_copy_to_iter(void *addr, size_t bytes, __wsum *csum, struct iov_
 size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum, struct iov_iter *i);
 
 int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len);
+int memcpy_fromiovec_out(unsigned char *kdata, struct iovec *iov,
+			 struct iovec **iov_out, int len);
 int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov,
 			int offset, int len);
 int memcpy_toiovecend(const struct iovec *v, unsigned char *kdata,
diff --git a/lib/iovec.c b/lib/iovec.c
index 2d99cb4..6a813dd 100644
--- a/lib/iovec.c
+++ b/lib/iovec.c
@@ -28,6 +28,33 @@  int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len)
 EXPORT_SYMBOL(memcpy_fromiovec);
 
 /*
+ *	Copy iovec to kernel, saving the current iov to *iov_out.
+ *	Returns -EFAULT on error.
+ */
+
+int memcpy_fromiovec_out(unsigned char *kdata, struct iovec *iov,
+			 struct iovec **iov_out, int len)
+{
+	while (len > 0) {
+		if (iov->iov_len) {
+			int copy = min_t(unsigned int, len, iov->iov_len);
+			if (copy_from_user(kdata, iov->iov_base, copy))
+				return -EFAULT;
+			len -= copy;
+			kdata += copy;
+			iov->iov_base += copy;
+			iov->iov_len -= copy;
+		}
+		if (!iov->iov_len)
+			iov++;
+	}
+	*iov_out = iov;
+
+	return 0;
+}
+EXPORT_SYMBOL(memcpy_fromiovec_out);
+
+/*
  *	Copy kernel to iovec. Returns -EFAULT on error.
  */