Linux virtualization list
 help / color / mirror / Atom feed
* Re: [PATCH 3/3] vhost: fix get_user_pages_fast error handling
From: Michael S. Tsirkin @ 2010-02-23 17:32 UTC (permalink / raw)
  To: Gleb Natapov
  Cc: Rusty Russell, kvm, virtualization, netdev, linux-kernel,
	David Miller, markmc, herbert.xu, quintela, dlaor, avi
In-Reply-To: <20100223173434.GB9834@redhat.com>

On Tue, Feb 23, 2010 at 07:34:34PM +0200, Gleb Natapov wrote:
> On Tue, Feb 23, 2010 at 06:57:58PM +0200, Michael S. Tsirkin wrote:
> > get_user_pages_fast returns number of pages on success, negative value
> > on failure, but never 0. Fix vhost code to match this logic.
> > 
> > Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> > ---
> >  drivers/vhost/vhost.c |    3 ++-
> >  1 files changed, 2 insertions(+), 1 deletions(-)
> > 
> > diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
> > index d4f8fdf..d003504 100644
> > --- a/drivers/vhost/vhost.c
> > +++ b/drivers/vhost/vhost.c
> > @@ -646,8 +646,9 @@ static int set_bit_to_user(int nr, void __user *addr)
> >  	int bit = nr + (log % PAGE_SIZE) * 8;
> >  	int r;
> >  	r = get_user_pages_fast(log, 1, 1, &page);
> > -	if (r)
> > +	if (r < 0)
> >  		return r;
> > +	BUG_ON(r != 1);
> Can't this be easily triggered from user space?

I think no. get_user_pages_fast always returns number of pages
pinned (in this case always 1) or an error (< 0).
Anything else is a kernel bug.

> >  	base = kmap_atomic(page, KM_USER0);
> >  	set_bit(bit, base);
> >  	kunmap_atomic(base, KM_USER0);
> > -- 
> > 1.7.0.18.g0d53a5
> 
> --
> 			Gleb.

^ permalink raw reply

* Re: [PATCH 3/3] vhost: fix get_user_pages_fast error handling
From: Gleb Natapov @ 2010-02-23 17:34 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Rusty Russell, kvm, virtualization, netdev, linux-kernel,
	David Miller, markmc, herbert.xu, quintela, dlaor, avi
In-Reply-To: <82ba8c97ce55dd4bf9972ad755961cd14e6a0938.1266943453.git.mst@redhat.com>

On Tue, Feb 23, 2010 at 06:57:58PM +0200, Michael S. Tsirkin wrote:
> get_user_pages_fast returns number of pages on success, negative value
> on failure, but never 0. Fix vhost code to match this logic.
> 
> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> ---
>  drivers/vhost/vhost.c |    3 ++-
>  1 files changed, 2 insertions(+), 1 deletions(-)
> 
> diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
> index d4f8fdf..d003504 100644
> --- a/drivers/vhost/vhost.c
> +++ b/drivers/vhost/vhost.c
> @@ -646,8 +646,9 @@ static int set_bit_to_user(int nr, void __user *addr)
>  	int bit = nr + (log % PAGE_SIZE) * 8;
>  	int r;
>  	r = get_user_pages_fast(log, 1, 1, &page);
> -	if (r)
> +	if (r < 0)
>  		return r;
> +	BUG_ON(r != 1);
Can't this be easily triggered from user space?

>  	base = kmap_atomic(page, KM_USER0);
>  	set_bit(bit, base);
>  	kunmap_atomic(base, KM_USER0);
> -- 
> 1.7.0.18.g0d53a5

--
			Gleb.

^ permalink raw reply

* Re: [PATCH 3/3] vhost: fix get_user_pages_fast error handling
From: Michael S. Tsirkin @ 2010-02-23 17:39 UTC (permalink / raw)
  To: Gleb Natapov
  Cc: Rusty Russell, kvm, virtualization, netdev, linux-kernel,
	David Miller, markmc, herbert.xu, quintela, dlaor, avi
In-Reply-To: <20100223173952.GC9834@redhat.com>

On Tue, Feb 23, 2010 at 07:39:52PM +0200, Gleb Natapov wrote:
> On Tue, Feb 23, 2010 at 07:32:58PM +0200, Michael S. Tsirkin wrote:
> > On Tue, Feb 23, 2010 at 07:34:34PM +0200, Gleb Natapov wrote:
> > > On Tue, Feb 23, 2010 at 06:57:58PM +0200, Michael S. Tsirkin wrote:
> > > > get_user_pages_fast returns number of pages on success, negative value
> > > > on failure, but never 0. Fix vhost code to match this logic.
> > > > 
> > > > Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> > > > ---
> > > >  drivers/vhost/vhost.c |    3 ++-
> > > >  1 files changed, 2 insertions(+), 1 deletions(-)
> > > > 
> > > > diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
> > > > index d4f8fdf..d003504 100644
> > > > --- a/drivers/vhost/vhost.c
> > > > +++ b/drivers/vhost/vhost.c
> > > > @@ -646,8 +646,9 @@ static int set_bit_to_user(int nr, void __user *addr)
> > > >  	int bit = nr + (log % PAGE_SIZE) * 8;
> > > >  	int r;
> > > >  	r = get_user_pages_fast(log, 1, 1, &page);
> > > > -	if (r)
> > > > +	if (r < 0)
> > > >  		return r;
> > > > +	BUG_ON(r != 1);
> > > Can't this be easily triggered from user space?
> > 
> > I think no. get_user_pages_fast always returns number of pages
> > pinned (in this case always 1) or an error (< 0).
> > Anything else is a kernel bug.
> > 
> But what if page is unmapped from userspace?

Then we get -EFAULT

> > > >  	base = kmap_atomic(page, KM_USER0);
> > > >  	set_bit(bit, base);
> > > >  	kunmap_atomic(base, KM_USER0);
> > > > -- 
> > > > 1.7.0.18.g0d53a5
> > > 
> > > --
> > > 			Gleb.
> 
> --
> 			Gleb.

^ permalink raw reply

* Re: [PATCH 3/3] vhost: fix get_user_pages_fast error handling
From: Gleb Natapov @ 2010-02-23 17:39 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Rusty Russell, kvm, virtualization, netdev, linux-kernel,
	David Miller, markmc, herbert.xu, quintela, dlaor, avi
In-Reply-To: <20100223173258.GA25338@redhat.com>

On Tue, Feb 23, 2010 at 07:32:58PM +0200, Michael S. Tsirkin wrote:
> On Tue, Feb 23, 2010 at 07:34:34PM +0200, Gleb Natapov wrote:
> > On Tue, Feb 23, 2010 at 06:57:58PM +0200, Michael S. Tsirkin wrote:
> > > get_user_pages_fast returns number of pages on success, negative value
> > > on failure, but never 0. Fix vhost code to match this logic.
> > > 
> > > Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> > > ---
> > >  drivers/vhost/vhost.c |    3 ++-
> > >  1 files changed, 2 insertions(+), 1 deletions(-)
> > > 
> > > diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
> > > index d4f8fdf..d003504 100644
> > > --- a/drivers/vhost/vhost.c
> > > +++ b/drivers/vhost/vhost.c
> > > @@ -646,8 +646,9 @@ static int set_bit_to_user(int nr, void __user *addr)
> > >  	int bit = nr + (log % PAGE_SIZE) * 8;
> > >  	int r;
> > >  	r = get_user_pages_fast(log, 1, 1, &page);
> > > -	if (r)
> > > +	if (r < 0)
> > >  		return r;
> > > +	BUG_ON(r != 1);
> > Can't this be easily triggered from user space?
> 
> I think no. get_user_pages_fast always returns number of pages
> pinned (in this case always 1) or an error (< 0).
> Anything else is a kernel bug.
> 
But what if page is unmapped from userspace?

> > >  	base = kmap_atomic(page, KM_USER0);
> > >  	set_bit(bit, base);
> > >  	kunmap_atomic(base, KM_USER0);
> > > -- 
> > > 1.7.0.18.g0d53a5
> > 
> > --
> > 			Gleb.

--
			Gleb.

^ permalink raw reply

* Re: [PATCH 3/3] vhost: fix get_user_pages_fast error handling
From: Gleb Natapov @ 2010-02-23 17:43 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Rusty Russell, kvm, virtualization, netdev, linux-kernel,
	David Miller, markmc, herbert.xu, quintela, dlaor, avi
In-Reply-To: <20100223173908.GB25338@redhat.com>

On Tue, Feb 23, 2010 at 07:39:08PM +0200, Michael S. Tsirkin wrote:
> On Tue, Feb 23, 2010 at 07:39:52PM +0200, Gleb Natapov wrote:
> > On Tue, Feb 23, 2010 at 07:32:58PM +0200, Michael S. Tsirkin wrote:
> > > On Tue, Feb 23, 2010 at 07:34:34PM +0200, Gleb Natapov wrote:
> > > > On Tue, Feb 23, 2010 at 06:57:58PM +0200, Michael S. Tsirkin wrote:
> > > > > get_user_pages_fast returns number of pages on success, negative value
> > > > > on failure, but never 0. Fix vhost code to match this logic.
> > > > > 
> > > > > Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> > > > > ---
> > > > >  drivers/vhost/vhost.c |    3 ++-
> > > > >  1 files changed, 2 insertions(+), 1 deletions(-)
> > > > > 
> > > > > diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
> > > > > index d4f8fdf..d003504 100644
> > > > > --- a/drivers/vhost/vhost.c
> > > > > +++ b/drivers/vhost/vhost.c
> > > > > @@ -646,8 +646,9 @@ static int set_bit_to_user(int nr, void __user *addr)
> > > > >  	int bit = nr + (log % PAGE_SIZE) * 8;
> > > > >  	int r;
> > > > >  	r = get_user_pages_fast(log, 1, 1, &page);
> > > > > -	if (r)
> > > > > +	if (r < 0)
> > > > >  		return r;
> > > > > +	BUG_ON(r != 1);
> > > > Can't this be easily triggered from user space?
> > > 
> > > I think no. get_user_pages_fast always returns number of pages
> > > pinned (in this case always 1) or an error (< 0).
> > > Anything else is a kernel bug.
> > > 
> > But what if page is unmapped from userspace?
> 
> Then we get -EFAULT
> 
Ah correct.

> > > > >  	base = kmap_atomic(page, KM_USER0);
> > > > >  	set_bit(bit, base);
> > > > >  	kunmap_atomic(base, KM_USER0);
> > > > > -- 
> > > > > 1.7.0.18.g0d53a5
> > > > 
> > > > --
> > > > 			Gleb.
> > 
> > --
> > 			Gleb.

--
			Gleb.

^ permalink raw reply

* Re: [PATCH 1/3] vhost: logging math fix
From: Juan Quintela @ 2010-02-23 19:26 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Rusty Russell, kvm, virtualization, netdev, linux-kernel,
	David Miller, markmc, gleb, herbert.xu, dlaor, avi
In-Reply-To: <51e0f786b06c198ab355abab19f0bd11ac6a167b.1266943453.git.mst@redhat.com>

"Michael S. Tsirkin" <mst@redhat.com> wrote:
> vhost was dong some complex math to get
> offset to log at, and got it wrong by a couple of bytes,
> while in fact it's simple: get address where we write,
> subtract start of buffer, add log base.
>
> Do it this way.
>
> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

Reviewed-by: Juan Quintela <quintela@redhat.com>

> ---
>  drivers/vhost/vhost.c |   10 ++++++----
>  1 files changed, 6 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
> index 6eb1525..c767279 100644
> --- a/drivers/vhost/vhost.c
> +++ b/drivers/vhost/vhost.c
> @@ -1004,10 +1004,12 @@ int vhost_add_used(struct vhost_virtqueue *vq, unsigned int head, int len)
>  	if (unlikely(vq->log_used)) {
>  		/* Make sure data is seen before log. */

We explain what smp_wmb() does.

>  		smp_wmb();
> -		log_write(vq->log_base, vq->log_addr + sizeof *vq->used->ring *
> -			  (vq->last_used_idx % vq->num),
> -			  sizeof *vq->used->ring);
> -		log_write(vq->log_base, vq->log_addr, sizeof *vq->used->ring);
> +		log_write(vq->log_base,
> +			  vq->log_addr + ((void *)used - (void *)vq->used),
> +			  sizeof *used);
> +		log_write(vq->log_base,
> +			  vq->log_addr + offsetof(struct vring_used, idx),
> +			  sizeof vq->used->idx);

Once here, can we add a comment explaining _what_ are we trying to write
to the log?  michael explains that t is the used element and the index,
but nothing states that.

>  		if (vq->log_ctx)
>  			eventfd_signal(vq->log_ctx, 1);
>  	}

^ permalink raw reply

* Re: [PATCH 2/3] vhost: initialize log eventfd context pointer
From: Juan Quintela @ 2010-02-23 19:31 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Rusty Russell, kvm, virtualization, netdev, linux-kernel,
	David Miller, markmc, gleb, herbert.xu, dlaor, avi
In-Reply-To: <f383d82104a04b92fe2953a4d8a98425c1ff6cde.1266943453.git.mst@redhat.com>

"Michael S. Tsirkin" <mst@redhat.com> wrote:
> vq log eventfd context pointer needs to be initialized, otherwise
> operation may fail or oops if log is enabled but log eventfd not set by
> userspace.
>
> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

Reviewed-by: Juan Quintela <quintela@redhat.com>

When log_ctx for device is created, it is copied to the vq.  This reset
was missing.

> ---
>  drivers/vhost/vhost.c |    1 +
>  1 files changed, 1 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
> index c767279..d4f8fdf 100644
> --- a/drivers/vhost/vhost.c
> +++ b/drivers/vhost/vhost.c
> @@ -121,6 +121,7 @@ static void vhost_vq_reset(struct vhost_dev *dev,
>  	vq->kick = NULL;
>  	vq->call_ctx = NULL;
>  	vq->call = NULL;
> +	vq->log_ctx = NULL;
>  }
>  
>  long vhost_dev_init(struct vhost_dev *dev,

^ permalink raw reply

* Re: [PATCH 3/3] vhost: fix get_user_pages_fast error handling
From: Juan Quintela @ 2010-02-23 19:56 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Rusty Russell, kvm, virtualization, netdev, linux-kernel,
	David Miller, markmc, gleb, herbert.xu, dlaor, avi
In-Reply-To: <82ba8c97ce55dd4bf9972ad755961cd14e6a0938.1266943453.git.mst@redhat.com>

"Michael S. Tsirkin" <mst@redhat.com> wrote:
> get_user_pages_fast returns number of pages on success, negative value
> on failure, but never 0. Fix vhost code to match this logic.

It can return 0 if you ask for 0 pages :)
From the comment:

 * Returns number of pages pinned. This may be fewer than the number
 * requested. If nr_pages is 0 or negative, returns 0. If no pages
 * were pinned, returns -errno.
 */

I agree that code was wrong, but the BUG_ON() is not neccessary
IMHO. The important bit is the change in the comparison.

Reviewed-by: Juan Quintela <quintela@redhat.com>


> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> ---
>  drivers/vhost/vhost.c |    3 ++-
>  1 files changed, 2 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
> index d4f8fdf..d003504 100644
> --- a/drivers/vhost/vhost.c
> +++ b/drivers/vhost/vhost.c
> @@ -646,8 +646,9 @@ static int set_bit_to_user(int nr, void __user *addr)
>  	int bit = nr + (log % PAGE_SIZE) * 8;
>  	int r;
>  	r = get_user_pages_fast(log, 1, 1, &page);
> -	if (r)
> +	if (r < 0)
>  		return r;
> +	BUG_ON(r != 1);
>  	base = kmap_atomic(page, KM_USER0);
>  	set_bit(bit, base);
>  	kunmap_atomic(base, KM_USER0);

^ permalink raw reply

* Re: virtio: console: Barrier needed before dropping early_put_chars?
From: Christian Borntraeger @ 2010-02-23 22:07 UTC (permalink / raw)
  To: Amit Shah; +Cc: hch, Virtualization List
In-Reply-To: <20100223171022.GB32564@amit-x200.redhat.com>

Am Dienstag 23 Februar 2010 18:10:22 schrieb Amit Shah:
> Hey Rusty, Christian,
> 
> Christoph Hellwig asked why we don't need a barrier before this code in
> virtcons_probe():
> 
> > +     /* Start using the new console output. */
> > +     early_put_chars = NULL;
> >       return 0;
> 
> Since only s390 uses early_put_chars so far, you'd know why it's not
> needed / why we're safe.

lguest is also using early_put_chars. See arch/x86/lguest/boot.c
Anyway I had to look into linux-next to see this code. I guess that is the
version you are talking about. (I remember seeing these patches several month
ago).

So what would a barrier do? Protect against gcc moving the early_put_chars=NULL
before the virtqueue is fully initialized and ready?
In practice this should not be necessary since the last thing probe might do
is add_port which is doing send_control_msg which contains cpu_relax (which
is a barrier). So gcc should not be able to move the early_put_chars = NULL
before the add_port loop.

Anyway, an explicit barrier might be a cleaner and more future proof way of
doing it.

^ permalink raw reply

* Re: [PATCH 3/3] vhost: fix get_user_pages_fast error handling
From: David Miller @ 2010-02-23 22:42 UTC (permalink / raw)
  To: gleb
  Cc: mst, rusty, kvm, virtualization, netdev, linux-kernel, markmc,
	herbert.xu, quintela, dlaor, avi
In-Reply-To: <20100223173952.GC9834@redhat.com>


Just for the record I'm generally not interested in vhost
patches.

If it's a specific network one that will be merged via
the networking tree, yes please CC: me.

But if it's a bunch of changes to vhost.c and other pieces
of infrastructure, feel free to leave me out of it.  It just
clutters my already overflowing inbox.

Thanks.

^ permalink raw reply

* Re: virtio: console: Barrier needed before dropping early_put_chars?
From: Rusty Russell @ 2010-02-24  1:07 UTC (permalink / raw)
  To: Amit Shah; +Cc: borntraeger, hch, Virtualization List
In-Reply-To: <20100223171022.GB32564@amit-x200.redhat.com>

On Wed, 24 Feb 2010 03:40:22 am Amit Shah wrote:
> Hey Rusty, Christian,
> 
> Christoph Hellwig asked why we don't need a barrier before this code in
> virtcons_probe():
> 
> > +     /* Start using the new console output. */
> > +     early_put_chars = NULL;
> >       return 0;
> 
> Since only s390 uses early_put_chars so far, you'd know why it's not
> needed / why we're safe.

He's right, it's sloppy.

In practice the compiler checks for NULL and reuses the pointer, and we
have no problem if this is used a couple of times after the real console is
live.

The Right Way to do this is a lock in put_chars() and around this assignment.
But do we really want to bother?

Cheers,
Rusty.
-- 
Away travelling 25Feb-26Mar (6 .de + 1 .pl + 17 .lt + 2 .sg)

^ permalink raw reply

* [PULL] virtio & lguest
From: Rusty Russell @ 2010-02-24  4:05 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Michael S. Tsirkin, Shirley Ma, Jamie Lokier, linux-kernel,
	virtualization, Amit Shah, hch

(Will be away for a month from tomorrow, so this is an early pull request).

The following changes since commit 9f3a6284880ceea452903e2043c88d7226736318:
  Linus Torvalds (1):
        Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus

are available in the git repository at:

  ssh://master.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus.git master

Adam Litke (2):
      virtio: Add memory statistics reporting to the balloon driver (V4)
      virtio: Fix scheduling while atomic in virtio_balloon stats

Amit Shah (29):
      virtio: Initialize vq->data entries to NULL
      virtio: console: We support only one device at a time
      virtio: console: encapsulate buffer information in a struct
      virtio: console: ensure add_inbuf can work for multiple ports as well
      virtio: console: introduce a get_inbuf helper to fetch bufs from in_vq
      virtio: console: don't assume a single console port.
      virtio: console: struct ports for multiple ports per device.
      virtio: console: ensure console size is updated on hvc open
      virtio: console: Separate out console-specific data into a separate struct
      virtio: console: Separate out console init into a new function
      virtio: console: Separate out find_vqs operation into a different function
      virtio: console: Introduce function to hand off data from host to readers
      virtio: console: Introduce a send_buf function for a common path for sending data to host
      virtio: console: Add a new MULTIPORT feature, support for generic ports
      virtio: console: Prepare for writing to userspace buffers
      virtio: console: Associate each port with a char device
      virtio: console: Add file operations to ports for open/read/write/poll
      virtio: console: Ensure only one process can have a port open at a time
      virtio: console: Register with sysfs and create a 'name' attribute for ports
      virtio: console: Remove cached data on port close
      virtio: console: Handle port hot-plug
      virtio: console: Add ability to hot-unplug ports
      virtio: console: Add debugfs files for each port to expose debug info
      virtio: console: show error message if hvc_alloc fails for console ports
      virtio: console: Ensure no memleaks in case of unused buffers
      virtio: console: Add ability to remove module
      virtio: console: Error out if we can't allocate buffers for control queue
      virtio: console: Fill ports' entire in_vq with buffers
      Add MAINTAINERS entry for virtio_console

Christoph Hellwig (1):
      virtio_blk: add block topology support

Jamie Lokier (1):
      Add __devexit_p around reference to virtio_pci_remove

Michael S. Tsirkin (1):
      virtio: use smp_XX barriers on SMP

Rusty Russell (9):
      virtio: fix balloon without VIRTIO_BALLOON_F_STATS_VQ
      lguest: remove unneeded zlib.h include in example launcher
      virtio: remove bogus barriers from DEBUG version of virtio_ring.c
      virtio: console: comment cleanup
      virtio: console: statically initialize virtio_cons
      hvc_console: make the ops pointer const.
      virtio: console: port encapsulation
      virtio: console: use vdev->priv to avoid accessing global var.
      virtio: console: remove global var

Shirley Ma (1):
      virtio: Add ability to detach unused buffers from vrings

 Documentation/lguest/lguest.c   |    1 -
 MAINTAINERS                     |    6 +
 drivers/block/virtio_blk.c      |   61 ++-
 drivers/char/Kconfig            |    8 +
 drivers/char/hvc_beat.c         |    2 +-
 drivers/char/hvc_console.c      |    7 +-
 drivers/char/hvc_console.h      |    7 +-
 drivers/char/hvc_iseries.c      |    2 +-
 drivers/char/hvc_iucv.c         |    2 +-
 drivers/char/hvc_rtas.c         |    2 +-
 drivers/char/hvc_udbg.c         |    2 +-
 drivers/char/hvc_vio.c          |    2 +-
 drivers/char/hvc_xen.c          |    2 +-
 drivers/char/virtio_console.c   | 1578 +++++++++++++++++++++++++++++++++++----
 drivers/virtio/virtio_balloon.c |  109 +++-
 drivers/virtio/virtio_pci.c     |    2 +-
 drivers/virtio/virtio_ring.c    |   59 ++-
 include/linux/virtio.h          |    4 +
 include/linux/virtio_balloon.h  |   15 +
 include/linux/virtio_blk.h      |   13 +
 include/linux/virtio_console.h  |   30 +-
 21 files changed, 1721 insertions(+), 193 deletions(-)

-- 
Away travelling 25Feb-26Mar (6 .de + 1 .pl + 17 .lt + 2 .sg)

^ permalink raw reply

* Re: [PATCH 3/3] vhost: fix get_user_pages_fast error handling
From: Michael S. Tsirkin @ 2010-02-24  5:37 UTC (permalink / raw)
  To: David Miller
  Cc: gleb, rusty, kvm, virtualization, netdev, linux-kernel, markmc,
	herbert.xu, quintela, dlaor, avi
In-Reply-To: <20100223.144235.08984181.davem@davemloft.net>

On Tue, Feb 23, 2010 at 02:42:35PM -0800, David Miller wrote:
> 
> Just for the record I'm generally not interested in vhost
> patches.
> 
> If it's a specific network one that will be merged via
> the networking tree, yes please CC: me.
> 
> But if it's a bunch of changes to vhost.c and other pieces
> of infrastructure, feel free to leave me out of it.  It just
> clutters my already overflowing inbox.
> 
> Thanks.

Dave, so while Rusty's on vacation, what's the best way to get vhost
infrastructure fixes in? Are you ok with getting pull requests and
merging them into net-next?  That should keep the clutter in your inbox
to the minimum.

Of course network changes would still go the usual way.

-- 
MST

^ permalink raw reply

* Re: [PATCH 3/3] vhost: fix get_user_pages_fast error handling
From: David Miller @ 2010-02-24  7:04 UTC (permalink / raw)
  To: mst
  Cc: gleb, rusty, kvm, virtualization, netdev, linux-kernel, markmc,
	herbert.xu, quintela, dlaor, avi
In-Reply-To: <20100224053737.GB27806@redhat.com>

From: "Michael S. Tsirkin" <mst@redhat.com>
Date: Wed, 24 Feb 2010 07:37:37 +0200

> Dave, so while Rusty's on vacation, what's the best way to get vhost
> infrastructure fixes in? Are you ok with getting pull requests and
> merging them into net-next?  That should keep the clutter in your inbox
> to the minimum.
> 
> Of course network changes would still go the usual way.

Well, who is providing oversight of vhost work while he's
gone?  Has he, implicitly or explicitly, appointed a maintainer
while he's away?

^ permalink raw reply

* Re: [PATCH 3/3] vhost: fix get_user_pages_fast error handling
From: Michael S. Tsirkin @ 2010-02-24  7:34 UTC (permalink / raw)
  To: David Miller
  Cc: markmc, kvm, quintela, netdev, linux-kernel, virtualization, avi,
	herbert.xu
In-Reply-To: <20100223.230428.71578656.davem@davemloft.net>

On Tue, Feb 23, 2010 at 11:04:28PM -0800, David Miller wrote:
> From: "Michael S. Tsirkin" <mst@redhat.com>
> Date: Wed, 24 Feb 2010 07:37:37 +0200
> 
> > Dave, so while Rusty's on vacation, what's the best way to get vhost
> > infrastructure fixes in? Are you ok with getting pull requests and
> > merging them into net-next?  That should keep the clutter in your inbox
> > to the minimum.
> > 
> > Of course network changes would still go the usual way.
> 
> Well, who is providing oversight of vhost work while he's
> gone?

My plan was to get peer review of the patches before merging.
So far Juan Quintela and Gleb Natapov gave feedback.

> Has he, implicitly or explicitly, appointed a maintainer
> while he's away?

Implicitly, I guess. He said "if there's an issue Michael Tsirkin is the
best person to resolve it", this was wrt merging his virtio&lguest tree.
He didn't mention vhost, I wrote all of vhost though, there shouldn't be
an issue with that.

-- 
MST

^ permalink raw reply

* Re: [PATCH 3/3] vhost: fix get_user_pages_fast error handling
From: David Miller @ 2010-02-24  7:41 UTC (permalink / raw)
  To: mst
  Cc: gleb, rusty, kvm, virtualization, netdev, linux-kernel, markmc,
	herbert.xu, quintela, dlaor, avi
In-Reply-To: <20100224073424.GC27806@redhat.com>

From: "Michael S. Tsirkin" <mst@redhat.com>
Date: Wed, 24 Feb 2010 09:34:25 +0200

> Implicitly, I guess. He said "if there's an issue Michael Tsirkin is the
> best person to resolve it", this was wrt merging his virtio&lguest tree.
> He didn't mention vhost, I wrote all of vhost though, there shouldn't be
> an issue with that.

That's good enough for me.

Feel free to setup a tree for me to pull from.

^ permalink raw reply

* [PULL] virtio
From: Michael S. Tsirkin @ 2010-02-28 18:43 UTC (permalink / raw)
  To: Rusty Russell
  Cc: Shirley Ma, Jamie Lokier, linux-kernel, virtualization,
	Anthony Liguori, Amit Shah, Linus Torvalds, hch

Linus,
Rusty asked me to resolve any issues with virtio and lguest that
surface, so here comes.

Thanks!

The following changes since commit 847f9c606cad121cebf984639e3eeee1c4db82f8:
  Linus Torvalds (1):
        Merge branch 'for-linus' of git://git.kernel.org/.../geert/linux-m68k

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost.git for-linus

Michael S. Tsirkin (1):
      virtio: fix out of range array access

 drivers/virtio/virtio_pci.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

-- 
MST

^ permalink raw reply

* [GIT PULL] vhost-net fixes for 2.6.34
From: Michael S. Tsirkin @ 2010-02-28 18:44 UTC (permalink / raw)
  To: David Miller; +Cc: rusty, kvm, virtualization, netdev, linux-kernel, samudrala

David,
The following tree, based on net-next-2.6, includes
patches fixing issues with vhost-net.
Please pull them for 2.6.34.

Thanks!

The following changes since commit 655ffee284dfcf9a24ac0343f3e5ee6db85b85c5:
  Jiri Pirko (1):
        wireless: convert to use netdev_for_each_mc_addr

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost.git vhost

Michael S. Tsirkin (3):
      vhost: logging thinko fix
      vhost: initialize log eventfd context pointer
      vhost: fix get_user_pages_fast error handling

Sridhar Samudrala (1):
      vhost-net: restart tx poll on sk_sndbuf full

 drivers/vhost/net.c   |    6 +++++-
 drivers/vhost/vhost.c |   16 +++++++++++-----
 2 files changed, 16 insertions(+), 6 deletions(-)

^ permalink raw reply

* Re: [GIT PULL] vhost-net fixes for 2.6.34
From: David Miller @ 2010-03-01  2:12 UTC (permalink / raw)
  To: mst; +Cc: rusty, kvm, virtualization, netdev, linux-kernel, samudrala
In-Reply-To: <20100228184440.GA32692@redhat.com>

From: "Michael S. Tsirkin" <mst@redhat.com>
Date: Sun, 28 Feb 2010 20:44:40 +0200

> The following changes since commit 655ffee284dfcf9a24ac0343f3e5ee6db85b85c5:
>   Jiri Pirko (1):
>         wireless: convert to use netdev_for_each_mc_addr
> 
> are available in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost.git vhost

Pulled, thanks.

^ permalink raw reply

* CFP: 2nd International Conference on Cloud Computing (CloudComp2010)
From: Ming Zhao @ 2010-03-02  5:14 UTC (permalink / raw)


========================================================================
Call for Papers
The 2nd International Conference on Cloud Computing
(CloudComp2010)

Barcelona, Spain, October 25 – 28, 2010
========================================================================

Conference Scope:
-----------------

Cloud Computing is an emerging computing paradigm envisioned to change 
all IT
landscape facets including technology, business, services and human 
resources.
It is a consumer/delivery model that offers IT capabilities as services, 
billed
based on usage. Many such cloud services can be envisioned, but the main 
ones
are IaaS (Infrastructure-as-a-Service), PaaS (Platform-as-a-Service), 
and SaaS
(Software-as-a-Service). The underlying cloud architecture includes a 
pool of
virtualized compute, storage and networking resources that can be 
aggregated and
launched as platforms to run workloads and satisfy their Service-Level 
Agreement
(SLA). Cloud architectures also include provisions to best guarantee 
service
delivery for clients and at the same time optimize efficiency of 
resources of
providers. Examples of provisions include, but not limited to, elasticity
through scaling resources up/down to track workload behavior, extensive
monitoring, failure mitigation, and energy optimizations. The two main
technologies enabling clouds are: (i) Virtualization, the foundation of 
clouds;
and (ii) manageability (autonomics), the command and control of clouds.

CloudComp is intended to bring together researchers, developers, and 
industry
professionals to discuss clouds, cloud computing and related ecosystems 
support.
To that end, papers are solicited from all cloud related areas, 
including, but
not limited to:

1. Cloud architectures and provisions to optimize providers’ 
environments while
guaranteeing clients’ SLAs.
2. Programming models, applications and middleware suitable for dynamic 
cloud
environments.
3. End-to-end techniques for autonomic management of cloud resources 
including
monitoring, asset management, process automation and others.
4. New cloud delivery models, models’ optimizations and associated 
architectural
changes.
5. New cloud economic and billing models.
6. Cloud security, privacy and compliance challenges.
7. Toolkits, frameworks and processes to enable clouds and allow seamless
transitions from traditional IT environments to clouds.
8. Experiences with existing cloud infrastructure, services and uses.
9. Novel human interfaces and browsers for accessing clouds.
10.Interaction of mobile computing, mCommerce and Clouds.

Cloud Computing conference is sponsored by ICST (Institute for Computer
Sciences, Social-Informatics and Telecommunications Engineering).



Important Dates:
----------------

1. Conference Papers:
a. Paper submission: May 31, 2010
b. Authors’ notification: July 26, 2010
c. Final manuscripts: August 23, 2010

2. Workshop Proposals:
a. Workshop proposal submission: March 15, 2010
b. Workshop decision date: March 29, 2010

3. Tutorial Proposals
a. Workshop proposal submission: June 28, 2010
b. Workshop decision date: July 16, 2010

4. Conference Date: October 25 – 28, 2010



Organization:
-------------

* General Chair:

o Mazin Yousif, IBM Corporation, Canada


* Program Chairs:

o Burkhard Neidecker-Lutz, SAP Research, Germany


* Program Committee:

o Albert Zomaya, University of Sydney, Australia
o Cristiana Amza, University of Toronto, Canada
o Daniel Mosse, University of Pittsburgh, USA
o Dongyan Xu, Purdue University, USA
o Erol Gelenbe, Imperial College, UK
o Franco Zambonelli, Università di Modena e Reggio Emilia, Italy
o George Galambos, IBM Canada, Canada
o Giovanna Di Marzo Serugendo, University of London, UK
o Ivona Brandic, Vienna University of Technology, Austria
o Jose Antonio Lozano, Telefonica I+D, Spain
o Jose Bernabeu-Auban, Microsoft, USA
o Juergen Falkner, Fraunhofer, Germany
o Julie McCann, Imperial College, UK
o Karsten Schwan, Georgia Institute of Technology, USA
o Keith Jeffery, Rutherford Appleton Laboratory, UK
o Mikhail Smirnov, Fraunhofer, Germany
o Omar Rana, Cardiff University, UK
o Ozalp Babaoglu, University of Bologna, Italy
o Rajkumar Buyya, Manjrasoft, Australia
o Renato Figueiredo, University of Florida, USA
o Ricardo Bianchini, Rutgers University, USA
o Ron Brightwell, Sandia National Labs, USA
o Simon Dobson, University of St Andrews, UK
o Tamer Aboualy, IBM Corporation, Canada
o Wu Feng, Virginia Tech University, USA


* Demos/Exhibits Chair:

o Katerina Goulioutkina, IBM Corporation, Canada


* Workshop/Tutorial Chair:

o Simon Dobson, University of St Andrews, UK


* Publicity Chair:

o Ming Zhao, Florida International University, USA


* Local Arrangements Chair:

o Joan Serrat, UPC, Barcelona, Spain


* Industry Session Chair:

o Duncan Johnson-Watt, Cloudsoft Corporation, UK



Further Information:
--------------------

Web: http://www.cloudcomp.eu
Email: cloudcomp2010@icst.org





-- 
Ming Zhao, Assistant Professor
School of Computing and Information Sciences
Florida International University
Tel: (305) 348-2034, Fax: (305) 348-3549
Web: http://www.cis.fiu.edu/~zhaom

^ permalink raw reply

* [RFC][ PATCH 0/3] vhost-net: Add mergeable RX buffer support to vhost-net
From: David Stevens @ 2010-03-03  0:20 UTC (permalink / raw)
  To: mst, rusty; +Cc: netdev, kvm, virtualization

These patches add support for mergeable receive buffers to
vhost-net, allowing it to use multiple virtio buffer heads for a single
receive packet.
                                        +-DLS


Signed-off-by: David L Stevens <dlstevens@us.ibm.com>

^ permalink raw reply

* [RFC][ PATCH 1/3] vhost-net: support multiple buffer heads in receiver
From: David Stevens @ 2010-03-03  0:20 UTC (permalink / raw)
  To: mst, rusty; +Cc: netdev, kvm, virtualization

[-- Attachment #1: Type: text/plain, Size: 12556 bytes --]

This patch generalizes buffer handling functions to
support multiple buffer heads.

In-line for viewing, attached for applying.

Signed-off-by: David L Stevens <dlstevens@us.ibm.com>

diff -ruN net-next-p0/drivers/vhost/net.c net-next-p1/drivers/vhost/net.c
--- net-next-p0/drivers/vhost/net.c     2010-02-24 12:59:24.000000000 
-0800
+++ net-next-p1/drivers/vhost/net.c     2010-03-01 11:44:22.000000000 
-0800
@@ -97,7 +97,8 @@
 static void handle_tx(struct vhost_net *net)
 {
        struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_TX];
-       unsigned head, out, in, s;
+       unsigned out, in, s;
+       struct iovec head;
        struct msghdr msg = {
                .msg_name = NULL,
                .msg_namelen = 0,
@@ -126,12 +127,10 @@
        hdr_size = vq->hdr_size;
 
        for (;;) {
-               head = vhost_get_vq_desc(&net->dev, vq, vq->iov,
-                                        ARRAY_SIZE(vq->iov),
-                                        &out, &in,
-                                        NULL, NULL);
+               head.iov_base = (void *)vhost_get_vq_desc(&net->dev, vq,
+                       vq->iov, ARRAY_SIZE(vq->iov), &out, &in, NULL, 
NULL);
                /* Nothing new?  Wait for eventfd to tell us they 
refilled. */
-               if (head == vq->num) {
+               if (head.iov_base == (void *)vq->num) {
                        wmem = atomic_read(&sock->sk->sk_wmem_alloc);
                        if (wmem >= sock->sk->sk_sndbuf * 3 / 4) {
                                tx_poll_start(net, sock);
@@ -152,7 +151,7 @@
                /* Skip header. TODO: support TSO. */
                s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, out);
                msg.msg_iovlen = out;
-               len = iov_length(vq->iov, out);
+               head.iov_len = len = iov_length(vq->iov, out);
                /* Sanity check */
                if (!len) {
                        vq_err(vq, "Unexpected header len for TX: "
@@ -163,14 +162,14 @@
                /* TODO: Check specific error and bomb out unless ENOBUFS? 
*/
                err = sock->ops->sendmsg(NULL, sock, &msg, len);
                if (unlikely(err < 0)) {
-                       vhost_discard_vq_desc(vq);
+                       vhost_discard(vq, 1);
                        tx_poll_start(net, sock);
                        break;
                }
                if (err != len)
                        pr_err("Truncated TX packet: "
                               " len %d != %zd\n", err, len);
-               vhost_add_used_and_signal(&net->dev, vq, head, 0);
+               vhost_add_used_and_signal(&net->dev, vq, &head, 1);
                total_len += len;
                if (unlikely(total_len >= VHOST_NET_WEIGHT)) {
                        vhost_poll_queue(&vq->poll);
@@ -182,12 +181,22 @@
        unuse_mm(net->dev.mm);
 }
 
+static int skb_head_len(struct sk_buff_head *skq)
+{
+       struct sk_buff *head;
+
+       head = skb_peek(skq);
+       if (head)
+               return head->len;
+       return 0;
+}
+
 /* Expects to be always run from workqueue - which acts as
  * read-size critical section for our kind of RCU. */
 static void handle_rx(struct vhost_net *net)
 {
        struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX];
-       unsigned head, out, in, log, s;
+       unsigned in, log, s;
        struct vhost_log *vq_log;
        struct msghdr msg = {
                .msg_name = NULL,
@@ -204,10 +213,11 @@
        };
 
        size_t len, total_len = 0;
-       int err;
+       int err, headcount, datalen;
        size_t hdr_size;
        struct socket *sock = rcu_dereference(vq->private_data);
-       if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue))
+
+       if (!sock || !skb_head_len(&sock->sk->sk_receive_queue))
                return;
 
        use_mm(net->dev.mm);
@@ -218,13 +228,10 @@
        vq_log = unlikely(vhost_has_feature(&net->dev, VHOST_F_LOG_ALL)) ?
                vq->log : NULL;
 
-       for (;;) {
-               head = vhost_get_vq_desc(&net->dev, vq, vq->iov,
-                                        ARRAY_SIZE(vq->iov),
-                                        &out, &in,
-                                        vq_log, &log);
+       while ((datalen = skb_head_len(&sock->sk->sk_receive_queue))) {
+               headcount = vhost_get_heads(vq, datalen, &in, vq_log, 
&log);
                /* OK, now we need to know about added descriptors. */
-               if (head == vq->num) {
+               if (!headcount) {
                        if (unlikely(vhost_enable_notify(vq))) {
                                /* They have slipped one in as we were
                                 * doing that: check again. */
@@ -235,13 +242,6 @@
                         * they refilled. */
                        break;
                }
-               /* We don't need to be notified again. */
-               if (out) {
-                       vq_err(vq, "Unexpected descriptor format for RX: "
-                              "out %d, int %d\n",
-                              out, in);
-                       break;
-               }
                /* Skip header. TODO: support TSO/mergeable rx buffers. */
                s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, in);
                msg.msg_iovlen = in;
@@ -257,14 +257,14 @@
                                         len, MSG_DONTWAIT | MSG_TRUNC);
                /* TODO: Check specific error and bomb out unless EAGAIN? 
*/
                if (err < 0) {
-                       vhost_discard_vq_desc(vq);
+                       vhost_discard(vq, 1);
                        break;
                }
                /* TODO: Should check and handle checksum. */
                if (err > len) {
                        pr_err("Discarded truncated rx packet: "
                               " len %d > %zd\n", err, len);
-                       vhost_discard_vq_desc(vq);
+                       vhost_discard(vq, 1);
                        continue;
                }
                len = err;
@@ -275,7 +275,7 @@
                        break;
                }
                len += hdr_size;
-               vhost_add_used_and_signal(&net->dev, vq, head, len);
+               vhost_add_used_and_signal(&net->dev, vq, vq->heads, 
headcount);
                if (unlikely(vq_log))
                        vhost_log_write(vq, vq_log, log, len);
                total_len += len;
diff -ruN net-next-p0/drivers/vhost/vhost.c 
net-next-p1/drivers/vhost/vhost.c
--- net-next-p0/drivers/vhost/vhost.c   2010-02-15 20:08:35.000000000 
-0800
+++ net-next-p1/drivers/vhost/vhost.c   2010-03-01 11:44:06.000000000 
-0800
@@ -848,6 +848,38 @@
        return 0;
 }
 
+unsigned vhost_get_heads(struct vhost_virtqueue *vq, int datalen, int 
*iovcount,
+       struct vhost_log *log, unsigned int *log_num)
+{
+       struct iovec *heads = vq->heads;
+       int out, in;
+       int hc = 0;
+
+       while (datalen > 0) {
+               if (hc >= VHOST_NET_MAX_SG) {
+                       vhost_discard(vq, hc);
+                       return 0;
+               }
+               heads[hc].iov_base = (void *)vhost_get_vq_desc(vq->dev, 
vq,
+                       vq->iov, ARRAY_SIZE(vq->iov), &out, &in, log, 
log_num);
+               if (heads[hc].iov_base == (void *)vq->num) {
+                       vhost_discard(vq, hc);
+                       return 0;
+               }
+               if (out || in <= 0) {
+                       vq_err(vq, "unexpected descriptor format for RX: "
+                               "out %d, in %d\n", out, in);
+                       vhost_discard(vq, hc);
+                       return 0;
+               }
+               heads[hc].iov_len = iov_length(vq->iov, in);
+               hc++;
+               datalen -= heads[hc].iov_len;
+       }
+       *iovcount = in;
+       return hc;
+}
+
 /* This looks in the virtqueue and for the first available buffer, and 
converts
  * it to an iovec for convenient access.  Since descriptors consist of 
some
  * number of output then some number of input descriptors, it's actually 
two
@@ -973,31 +1005,32 @@
 }
 
 /* Reverse the effect of vhost_get_vq_desc. Useful for error handling. */
-void vhost_discard_vq_desc(struct vhost_virtqueue *vq)
+void vhost_discard(struct vhost_virtqueue *vq, int n)
 {
-       vq->last_avail_idx--;
+       vq->last_avail_idx -= n;
 }
 
 /* After we've used one of their buffers, we tell them about it.  We'll 
then
  * want to notify the guest, using eventfd. */
-int vhost_add_used(struct vhost_virtqueue *vq, unsigned int head, int 
len)
+int vhost_add_used(struct vhost_virtqueue *vq, struct iovec *heads, int 
count)
 {
        struct vring_used_elem *used;
+       int i;
 
-       /* The virtqueue contains a ring of used buffers.  Get a pointer 
to the
-        * next entry in that used ring. */
-       used = &vq->used->ring[vq->last_used_idx % vq->num];
-       if (put_user(head, &used->id)) {
-               vq_err(vq, "Failed to write used id");
-               return -EFAULT;
-       }
-       if (put_user(len, &used->len)) {
-               vq_err(vq, "Failed to write used len");
-               return -EFAULT;
+       for (i=0; i<count; i++, vq->last_used_idx++) {
+               used = &vq->used->ring[vq->last_used_idx % vq->num];
+               if (put_user((unsigned)heads[i].iov_base, &used->id)) {
+                       vq_err(vq, "Failed to write used id");
+                       return -EFAULT;
+               }
+               if (put_user(heads[i].iov_len, &used->len)) {
+                       vq_err(vq, "Failed to write used len");
+                       return -EFAULT;
+               }
        }
        /* Make sure buffer is written before we update index. */
        smp_wmb();
-       if (put_user(vq->last_used_idx + 1, &vq->used->idx)) {
+       if (put_user(vq->last_used_idx, &vq->used->idx)) {
                vq_err(vq, "Failed to increment used idx");
                return -EFAULT;
        }
@@ -1011,7 +1044,6 @@
                if (vq->log_ctx)
                        eventfd_signal(vq->log_ctx, 1);
        }
-       vq->last_used_idx++;
        return 0;
 }
 
@@ -1038,9 +1070,9 @@
 /* And here's the combo meal deal.  Supersize me! */
 void vhost_add_used_and_signal(struct vhost_dev *dev,
                               struct vhost_virtqueue *vq,
-                              unsigned int head, int len)
+                              struct iovec *heads, int count)
 {
-       vhost_add_used(vq, head, len);
+       vhost_add_used(vq, heads, count);
        vhost_signal(dev, vq);
 }
 
diff -ruN net-next-p0/drivers/vhost/vhost.h 
net-next-p1/drivers/vhost/vhost.h
--- net-next-p0/drivers/vhost/vhost.h   2010-02-15 20:08:35.000000000 
-0800
+++ net-next-p1/drivers/vhost/vhost.h   2010-03-01 11:42:18.000000000 
-0800
@@ -84,6 +84,7 @@
        struct iovec indirect[VHOST_NET_MAX_SG];
        struct iovec iov[VHOST_NET_MAX_SG];
        struct iovec hdr[VHOST_NET_MAX_SG];
+       struct iovec heads[VHOST_NET_MAX_SG];
        size_t hdr_size;
        /* We use a kind of RCU to access private pointer.
         * All readers access it from workqueue, which makes it possible 
to
@@ -120,16 +121,18 @@
 int vhost_vq_access_ok(struct vhost_virtqueue *vq);
 int vhost_log_access_ok(struct vhost_dev *);
 
+unsigned vhost_get_heads(struct vhost_virtqueue *, int datalen, int 
*iovcount,
+                       struct vhost_log *log, unsigned int *log_num);
 unsigned vhost_get_vq_desc(struct vhost_dev *, struct vhost_virtqueue *,
                           struct iovec iov[], unsigned int iov_count,
                           unsigned int *out_num, unsigned int *in_num,
                           struct vhost_log *log, unsigned int *log_num);
-void vhost_discard_vq_desc(struct vhost_virtqueue *);
+void vhost_discard(struct vhost_virtqueue *, int);
 
-int vhost_add_used(struct vhost_virtqueue *, unsigned int head, int len);
-void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *);
+int vhost_add_used(struct vhost_virtqueue *, struct iovec *heads, int 
count);
 void vhost_add_used_and_signal(struct vhost_dev *, struct vhost_virtqueue 
*,
-                              unsigned int head, int len);
+                              struct iovec *heads, int count);
+void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *);
 void vhost_disable_notify(struct vhost_virtqueue *);
 bool vhost_enable_notify(struct vhost_virtqueue *);
 

[-- Attachment #2: MRXB1.patch --]
[-- Type: application/octet-stream, Size: 9612 bytes --]

diff -ruN net-next-p0/drivers/vhost/net.c net-next-p1/drivers/vhost/net.c
--- net-next-p0/drivers/vhost/net.c	2010-02-24 12:59:24.000000000 -0800
+++ net-next-p1/drivers/vhost/net.c	2010-03-01 11:44:22.000000000 -0800
@@ -97,7 +97,8 @@
 static void handle_tx(struct vhost_net *net)
 {
 	struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_TX];
-	unsigned head, out, in, s;
+	unsigned out, in, s;
+	struct iovec head;
 	struct msghdr msg = {
 		.msg_name = NULL,
 		.msg_namelen = 0,
@@ -126,12 +127,10 @@
 	hdr_size = vq->hdr_size;
 
 	for (;;) {
-		head = vhost_get_vq_desc(&net->dev, vq, vq->iov,
-					 ARRAY_SIZE(vq->iov),
-					 &out, &in,
-					 NULL, NULL);
+		head.iov_base = (void *)vhost_get_vq_desc(&net->dev, vq,
+			vq->iov, ARRAY_SIZE(vq->iov), &out, &in, NULL, NULL);
 		/* Nothing new?  Wait for eventfd to tell us they refilled. */
-		if (head == vq->num) {
+		if (head.iov_base == (void *)vq->num) {
 			wmem = atomic_read(&sock->sk->sk_wmem_alloc);
 			if (wmem >= sock->sk->sk_sndbuf * 3 / 4) {
 				tx_poll_start(net, sock);
@@ -152,7 +151,7 @@
 		/* Skip header. TODO: support TSO. */
 		s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, out);
 		msg.msg_iovlen = out;
-		len = iov_length(vq->iov, out);
+		head.iov_len = len = iov_length(vq->iov, out);
 		/* Sanity check */
 		if (!len) {
 			vq_err(vq, "Unexpected header len for TX: "
@@ -163,14 +162,14 @@
 		/* TODO: Check specific error and bomb out unless ENOBUFS? */
 		err = sock->ops->sendmsg(NULL, sock, &msg, len);
 		if (unlikely(err < 0)) {
-			vhost_discard_vq_desc(vq);
+			vhost_discard(vq, 1);
 			tx_poll_start(net, sock);
 			break;
 		}
 		if (err != len)
 			pr_err("Truncated TX packet: "
 			       " len %d != %zd\n", err, len);
-		vhost_add_used_and_signal(&net->dev, vq, head, 0);
+		vhost_add_used_and_signal(&net->dev, vq, &head, 1);
 		total_len += len;
 		if (unlikely(total_len >= VHOST_NET_WEIGHT)) {
 			vhost_poll_queue(&vq->poll);
@@ -182,12 +181,22 @@
 	unuse_mm(net->dev.mm);
 }
 
+static int skb_head_len(struct sk_buff_head *skq)
+{
+	struct sk_buff *head;
+
+	head = skb_peek(skq);
+	if (head)
+		return head->len;
+	return 0;
+}
+
 /* Expects to be always run from workqueue - which acts as
  * read-size critical section for our kind of RCU. */
 static void handle_rx(struct vhost_net *net)
 {
 	struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX];
-	unsigned head, out, in, log, s;
+	unsigned in, log, s;
 	struct vhost_log *vq_log;
 	struct msghdr msg = {
 		.msg_name = NULL,
@@ -204,10 +213,11 @@
 	};
 
 	size_t len, total_len = 0;
-	int err;
+	int err, headcount, datalen;
 	size_t hdr_size;
 	struct socket *sock = rcu_dereference(vq->private_data);
-	if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue))
+
+	if (!sock || !skb_head_len(&sock->sk->sk_receive_queue))
 		return;
 
 	use_mm(net->dev.mm);
@@ -218,13 +228,10 @@
 	vq_log = unlikely(vhost_has_feature(&net->dev, VHOST_F_LOG_ALL)) ?
 		vq->log : NULL;
 
-	for (;;) {
-		head = vhost_get_vq_desc(&net->dev, vq, vq->iov,
-					 ARRAY_SIZE(vq->iov),
-					 &out, &in,
-					 vq_log, &log);
+	while ((datalen = skb_head_len(&sock->sk->sk_receive_queue))) {
+		headcount = vhost_get_heads(vq, datalen, &in, vq_log, &log);
 		/* OK, now we need to know about added descriptors. */
-		if (head == vq->num) {
+		if (!headcount) {
 			if (unlikely(vhost_enable_notify(vq))) {
 				/* They have slipped one in as we were
 				 * doing that: check again. */
@@ -235,13 +242,6 @@
 			 * they refilled. */
 			break;
 		}
-		/* We don't need to be notified again. */
-		if (out) {
-			vq_err(vq, "Unexpected descriptor format for RX: "
-			       "out %d, int %d\n",
-			       out, in);
-			break;
-		}
 		/* Skip header. TODO: support TSO/mergeable rx buffers. */
 		s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, in);
 		msg.msg_iovlen = in;
@@ -257,14 +257,14 @@
 					 len, MSG_DONTWAIT | MSG_TRUNC);
 		/* TODO: Check specific error and bomb out unless EAGAIN? */
 		if (err < 0) {
-			vhost_discard_vq_desc(vq);
+			vhost_discard(vq, 1);
 			break;
 		}
 		/* TODO: Should check and handle checksum. */
 		if (err > len) {
 			pr_err("Discarded truncated rx packet: "
 			       " len %d > %zd\n", err, len);
-			vhost_discard_vq_desc(vq);
+			vhost_discard(vq, 1);
 			continue;
 		}
 		len = err;
@@ -275,7 +275,7 @@
 			break;
 		}
 		len += hdr_size;
-		vhost_add_used_and_signal(&net->dev, vq, head, len);
+		vhost_add_used_and_signal(&net->dev, vq, vq->heads, headcount);
 		if (unlikely(vq_log))
 			vhost_log_write(vq, vq_log, log, len);
 		total_len += len;
diff -ruN net-next-p0/drivers/vhost/vhost.c net-next-p1/drivers/vhost/vhost.c
--- net-next-p0/drivers/vhost/vhost.c	2010-02-15 20:08:35.000000000 -0800
+++ net-next-p1/drivers/vhost/vhost.c	2010-03-01 11:44:06.000000000 -0800
@@ -848,6 +848,38 @@
 	return 0;
 }
 
+unsigned vhost_get_heads(struct vhost_virtqueue *vq, int datalen, int *iovcount,
+	struct vhost_log *log, unsigned int *log_num)
+{
+	struct iovec *heads = vq->heads;
+	int out, in;
+	int hc = 0;
+
+	while (datalen > 0) {
+		if (hc >= VHOST_NET_MAX_SG) {
+			vhost_discard(vq, hc);
+			return 0;
+		}
+		heads[hc].iov_base = (void *)vhost_get_vq_desc(vq->dev, vq,
+			vq->iov, ARRAY_SIZE(vq->iov), &out, &in, log, log_num);
+		if (heads[hc].iov_base == (void *)vq->num) {
+			vhost_discard(vq, hc);
+			return 0;
+		}
+		if (out || in <= 0) {
+			vq_err(vq, "unexpected descriptor format for RX: "
+				"out %d, in %d\n", out, in);
+			vhost_discard(vq, hc);
+			return 0;
+		}
+		heads[hc].iov_len = iov_length(vq->iov, in);
+		hc++;
+		datalen -= heads[hc].iov_len;
+	}
+	*iovcount = in;
+	return hc;
+}
+
 /* This looks in the virtqueue and for the first available buffer, and converts
  * it to an iovec for convenient access.  Since descriptors consist of some
  * number of output then some number of input descriptors, it's actually two
@@ -973,31 +1005,32 @@
 }
 
 /* Reverse the effect of vhost_get_vq_desc. Useful for error handling. */
-void vhost_discard_vq_desc(struct vhost_virtqueue *vq)
+void vhost_discard(struct vhost_virtqueue *vq, int n)
 {
-	vq->last_avail_idx--;
+	vq->last_avail_idx -= n;
 }
 
 /* After we've used one of their buffers, we tell them about it.  We'll then
  * want to notify the guest, using eventfd. */
-int vhost_add_used(struct vhost_virtqueue *vq, unsigned int head, int len)
+int vhost_add_used(struct vhost_virtqueue *vq, struct iovec *heads, int count)
 {
 	struct vring_used_elem *used;
+	int i;
 
-	/* The virtqueue contains a ring of used buffers.  Get a pointer to the
-	 * next entry in that used ring. */
-	used = &vq->used->ring[vq->last_used_idx % vq->num];
-	if (put_user(head, &used->id)) {
-		vq_err(vq, "Failed to write used id");
-		return -EFAULT;
-	}
-	if (put_user(len, &used->len)) {
-		vq_err(vq, "Failed to write used len");
-		return -EFAULT;
+	for (i=0; i<count; i++, vq->last_used_idx++) {
+		used = &vq->used->ring[vq->last_used_idx % vq->num];
+		if (put_user((unsigned)heads[i].iov_base, &used->id)) {
+			vq_err(vq, "Failed to write used id");
+			return -EFAULT;
+		}
+		if (put_user(heads[i].iov_len, &used->len)) {
+			vq_err(vq, "Failed to write used len");
+			return -EFAULT;
+		}
 	}
 	/* Make sure buffer is written before we update index. */
 	smp_wmb();
-	if (put_user(vq->last_used_idx + 1, &vq->used->idx)) {
+	if (put_user(vq->last_used_idx, &vq->used->idx)) {
 		vq_err(vq, "Failed to increment used idx");
 		return -EFAULT;
 	}
@@ -1011,7 +1044,6 @@
 		if (vq->log_ctx)
 			eventfd_signal(vq->log_ctx, 1);
 	}
-	vq->last_used_idx++;
 	return 0;
 }
 
@@ -1038,9 +1070,9 @@
 /* And here's the combo meal deal.  Supersize me! */
 void vhost_add_used_and_signal(struct vhost_dev *dev,
 			       struct vhost_virtqueue *vq,
-			       unsigned int head, int len)
+			       struct iovec *heads, int count)
 {
-	vhost_add_used(vq, head, len);
+	vhost_add_used(vq, heads, count);
 	vhost_signal(dev, vq);
 }
 
diff -ruN net-next-p0/drivers/vhost/vhost.h net-next-p1/drivers/vhost/vhost.h
--- net-next-p0/drivers/vhost/vhost.h	2010-02-15 20:08:35.000000000 -0800
+++ net-next-p1/drivers/vhost/vhost.h	2010-03-01 11:42:18.000000000 -0800
@@ -84,6 +84,7 @@
 	struct iovec indirect[VHOST_NET_MAX_SG];
 	struct iovec iov[VHOST_NET_MAX_SG];
 	struct iovec hdr[VHOST_NET_MAX_SG];
+	struct iovec heads[VHOST_NET_MAX_SG];
 	size_t hdr_size;
 	/* We use a kind of RCU to access private pointer.
 	 * All readers access it from workqueue, which makes it possible to
@@ -120,16 +121,18 @@
 int vhost_vq_access_ok(struct vhost_virtqueue *vq);
 int vhost_log_access_ok(struct vhost_dev *);
 
+unsigned vhost_get_heads(struct vhost_virtqueue *, int datalen, int *iovcount,
+			struct vhost_log *log, unsigned int *log_num);
 unsigned vhost_get_vq_desc(struct vhost_dev *, struct vhost_virtqueue *,
 			   struct iovec iov[], unsigned int iov_count,
 			   unsigned int *out_num, unsigned int *in_num,
 			   struct vhost_log *log, unsigned int *log_num);
-void vhost_discard_vq_desc(struct vhost_virtqueue *);
+void vhost_discard(struct vhost_virtqueue *, int);
 
-int vhost_add_used(struct vhost_virtqueue *, unsigned int head, int len);
-void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *);
+int vhost_add_used(struct vhost_virtqueue *, struct iovec *heads, int count);
 void vhost_add_used_and_signal(struct vhost_dev *, struct vhost_virtqueue *,
-			       unsigned int head, int len);
+			       struct iovec *heads, int count);
+void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *);
 void vhost_disable_notify(struct vhost_virtqueue *);
 bool vhost_enable_notify(struct vhost_virtqueue *);
 

^ permalink raw reply

* [RFC][ PATCH 2/3] vhost-net: handle vnet_hdr processing for MRG_RX_BUF
From: David Stevens @ 2010-03-03  0:20 UTC (permalink / raw)
  To: mst, rusty; +Cc: netdev, kvm, virtualization

[-- Attachment #1: Type: text/plain, Size: 13122 bytes --]

This patch adds vnet_hdr processing for mergeable buffer
support to vhost-net.

Signed-off-by: David L Stevens <dlstevens@us.ibm.com>

diff -ruN net-next-p1/drivers/vhost/net.c net-next-p2/drivers/vhost/net.c
--- net-next-p1/drivers/vhost/net.c     2010-03-01 11:44:22.000000000 
-0800
+++ net-next-p2/drivers/vhost/net.c     2010-03-02 13:01:34.000000000 
-0800
@@ -109,7 +109,6 @@
        };
        size_t len, total_len = 0;
        int err, wmem;
-       size_t hdr_size;
        struct socket *sock = rcu_dereference(vq->private_data);
        if (!sock)
                return;
@@ -124,7 +123,6 @@
 
        if (wmem < sock->sk->sk_sndbuf * 2)
                tx_poll_stop(net);
-       hdr_size = vq->hdr_size;
 
        for (;;) {
                head.iov_base = (void *)vhost_get_vq_desc(&net->dev, vq,
@@ -148,25 +146,45 @@
                               "out %d, int %d\n", out, in);
                        break;
                }
+               if (vq->guest_hlen > vq->sock_hlen) {
+                       if (msg.msg_iov[0].iov_len == vq->guest_hlen)
+                               msg.msg_iov[0].iov_len = vq->sock_hlen;
+                       else if (out == ARRAY_SIZE(vq->iov))
+                               vq_err(vq, "handle_tx iov overflow!");
+                       else {
+                               int i;
+
+                               /* give header its own iov */
+                               for (i=out; i>0; ++i)
+                                       msg.msg_iov[i+1] = msg.msg_iov[i];
+                               msg.msg_iov[0].iov_len = vq->sock_hlen;
+                               msg.msg_iov[1].iov_base += vq->guest_hlen;
+                               msg.msg_iov[1].iov_len -= vq->guest_hlen;
+                               out++;
+                       }
+               }
                /* Skip header. TODO: support TSO. */
-               s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, out);
                msg.msg_iovlen = out;
                head.iov_len = len = iov_length(vq->iov, out);
                /* Sanity check */
                if (!len) {
                        vq_err(vq, "Unexpected header len for TX: "
                               "%zd expected %zd\n",
-                              iov_length(vq->hdr, s), hdr_size);
+                              len, vq->guest_hlen);
                        break;
                }
                /* TODO: Check specific error and bomb out unless ENOBUFS? 
*/
                err = sock->ops->sendmsg(NULL, sock, &msg, len);
                if (unlikely(err < 0)) {
-                       vhost_discard(vq, 1);
-                       tx_poll_start(net, sock);
+                       if (err == -EAGAIN) {
+                               tx_poll_start(net, sock);
+                       } else {
+                               vq_err(vq, "sendmsg: errno %d\n", -err);
+                               /* drop packet; do not discard/resend */
+ vhost_add_used_and_signal(&net->dev,vq,&head,1);
+                       }
                        break;
-               }
-               if (err != len)
+               } else if (err != len)
                        pr_err("Truncated TX packet: "
                               " len %d != %zd\n", err, len);
                vhost_add_used_and_signal(&net->dev, vq, &head, 1);
@@ -207,14 +225,8 @@
                .msg_flags = MSG_DONTWAIT,
        };
 
-       struct virtio_net_hdr hdr = {
-               .flags = 0,
-               .gso_type = VIRTIO_NET_HDR_GSO_NONE
-       };
-
        size_t len, total_len = 0;
        int err, headcount, datalen;
-       size_t hdr_size;
        struct socket *sock = rcu_dereference(vq->private_data);
 
        if (!sock || !skb_head_len(&sock->sk->sk_receive_queue))
@@ -223,7 +235,6 @@
        use_mm(net->dev.mm);
        mutex_lock(&vq->mutex);
        vhost_disable_notify(vq);
-       hdr_size = vq->hdr_size;
 
        vq_log = unlikely(vhost_has_feature(&net->dev, VHOST_F_LOG_ALL)) ?
                vq->log : NULL;
@@ -232,25 +243,18 @@
                headcount = vhost_get_heads(vq, datalen, &in, vq_log, 
&log);
                /* OK, now we need to know about added descriptors. */
                if (!headcount) {
-                       if (unlikely(vhost_enable_notify(vq))) {
-                               /* They have slipped one in as we were
-                                * doing that: check again. */
-                               vhost_disable_notify(vq);
-                               continue;
-                       }
-                       /* Nothing new?  Wait for eventfd to tell us
-                        * they refilled. */
+                       vhost_enable_notify(vq);
                        break;
                }
                /* Skip header. TODO: support TSO/mergeable rx buffers. */
-               s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, in);
                msg.msg_iovlen = in;
                len = iov_length(vq->iov, in);
+
                /* Sanity check */
                if (!len) {
                        vq_err(vq, "Unexpected header len for RX: "
                               "%zd expected %zd\n",
-                              iov_length(vq->hdr, s), hdr_size);
+                              len, vq->guest_hlen);
                        break;
                }
                err = sock->ops->recvmsg(NULL, sock, &msg,
@@ -268,13 +272,7 @@
                        continue;
                }
                len = err;
-               err = memcpy_toiovec(vq->hdr, (unsigned char *)&hdr, 
hdr_size);
-               if (err) {
-                       vq_err(vq, "Unable to write vnet_hdr at addr %p: 
%d\n",
-                              vq->iov->iov_base, err);
-                       break;
-               }
-               len += hdr_size;
+               len += vq->guest_hlen - vq->sock_hlen;
                vhost_add_used_and_signal(&net->dev, vq, vq->heads, 
headcount);
                if (unlikely(vq_log))
                        vhost_log_write(vq, vq_log, log, len);
@@ -483,6 +481,13 @@
        return ERR_PTR(-ENOTSOCK);
 }
 
+static int vhost_sock_is_raw(struct socket *sock)
+{
+       if (!sock || !sock->sk)
+               return 0;
+       return sock->sk->sk_type == SOCK_RAW;
+}
+
 static long vhost_net_set_backend(struct vhost_net *n, unsigned index, 
int fd)
 {
        struct socket *sock, *oldsock;
@@ -519,6 +524,20 @@
 
        vhost_net_disable_vq(n, vq);
        rcu_assign_pointer(vq->private_data, sock);
+
+       if (sock && sock->sk) {
+               if (!vhost_sock_is_raw(sock) ||
+                   vhost_has_feature(&n->dev, 
VHOST_NET_F_VIRTIO_NET_HDR)) {
+                       vq->sock_hlen = sizeof(struct virtio_net_hdr);
+                       if (vhost_has_feature(&n->dev, 
VIRTIO_NET_F_MRG_RXBUF))
+                               vq->guest_hlen =
+                                       sizeof(struct 
virtio_net_hdr_mrg_rxbuf);
+                       else
+                               vq->guest_hlen = sizeof(struct 
virtio_net_hdr);
+               } else
+                       vq->guest_hlen = vq->sock_hlen = 0;
+       } else
+               vq_err(vq, "vhost_net_set_backend: sock->sk is NULL");
        vhost_net_enable_vq(n, vq);
        mutex_unlock(&vq->mutex);
 done:
@@ -566,8 +585,17 @@
        n->dev.acked_features = features;
        smp_wmb();
        for (i = 0; i < VHOST_NET_VQ_MAX; ++i) {
-               mutex_lock(&n->vqs[i].mutex);
-               n->vqs[i].hdr_size = hdr_size;
+               struct vhost_virtqueue *vq = n->vqs + i;
+               struct socket *sock = vq->private_data;
+
+               mutex_lock(&vq->mutex);
+               if (features & (1 << VIRTIO_NET_F_MRG_RXBUF))
+                       vq->sock_hlen = sizeof(struct 
virtio_net_hdr_mrg_rxbuf);
+               else if (features & (1 << VHOST_NET_F_VIRTIO_NET_HDR) ||
+                        !vhost_sock_is_raw(sock))
+                       vq->sock_hlen = sizeof(struct virtio_net_hdr);
+               else
+                       vq->sock_hlen = 0;
                mutex_unlock(&n->vqs[i].mutex);
        }
        vhost_net_flush(n);
diff -ruN net-next-p1/drivers/vhost/vhost.c 
net-next-p2/drivers/vhost/vhost.c
--- net-next-p1/drivers/vhost/vhost.c   2010-03-01 11:44:06.000000000 
-0800
+++ net-next-p2/drivers/vhost/vhost.c   2010-03-02 12:53:02.000000000 
-0800
@@ -113,7 +113,8 @@
        vq->used_flags = 0;
        vq->log_used = false;
        vq->log_addr = -1ull;
-       vq->hdr_size = 0;
+       vq->guest_hlen = 0;
+       vq->sock_hlen = 0;
        vq->private_data = NULL;
        vq->log_base = NULL;
        vq->error_ctx = NULL;
@@ -848,20 +849,85 @@
        return 0;
 }
 
+static int
+vhost_get_hdr(struct vhost_virtqueue *vq, int *in, struct vhost_log *log,
+       int *log_num)
+{
+       struct iovec *heads = vq->heads;
+       struct iovec *iov = vq->iov;
+       int out;
+
+       *in = 0;
+       iov[0].iov_len = 0;
+
+       /* get buffer, starting from iov[1] */
+       heads[0].iov_base = (void *)vhost_get_vq_desc(vq->dev, vq,
+               vq->iov+1, ARRAY_SIZE(vq->iov)-1, &out, in, log, log_num);
+       if (out || *in <= 0) {
+               vq_err(vq, "unexpected descriptor format for RX: out %d, "
+                       "in %d\n", out, *in);
+               return 0;
+       }
+       if (heads[0].iov_base == (void *)vq->num)
+               return 0;
+
+       /* make iov[0] the header */
+       if (!vq->guest_hlen) {
+               if (vq->sock_hlen) {
+                       static struct virtio_net_hdr junk; /* bit bucket 
*/
+
+                       iov[0].iov_base = &junk;
+                       iov[0].iov_len = sizeof(junk);
+               } else
+                       iov[0].iov_len = 0;
+       }
+       if (vq->sock_hlen < vq->guest_hlen) {
+               iov[0].iov_base = iov[1].iov_base;
+               iov[0].iov_len = vq->sock_hlen;
+
+               if (iov[1].iov_len < vq->sock_hlen) {
+                       vq_err(vq, "can't fit header in one buffer!");
+                       vhost_discard(vq, 1);
+                       return 0;
+               }
+               if (!vq->sock_hlen) {
+                       static const struct virtio_net_hdr_mrg_rxbuf hdr = 
{
+                               .hdr.flags = 0,
+                               .hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE
+                       };
+                       memcpy(iov[0].iov_base, &hdr, vq->guest_hlen);
+               }
+               iov[1].iov_base += vq->guest_hlen;
+               iov[1].iov_len -= vq->guest_hlen;
+       }
+       return 1;
+}
+
 unsigned vhost_get_heads(struct vhost_virtqueue *vq, int datalen, int 
*iovcount,
        struct vhost_log *log, unsigned int *log_num)
 {
        struct iovec *heads = vq->heads;
-       int out, in;
+       int out, in = 0;
+       int seg = 0;
        int hc = 0;
 
+       if (vq->guest_hlen != vq->sock_hlen) {
+               seg = vhost_get_hdr(vq, &in, log, log_num);
+               if (!seg)
+                       return 0;
+               hc++;
+               datalen -= iov_length(vq->iov+seg, in);
+               seg += in;
+       }
+
        while (datalen > 0) {
                if (hc >= VHOST_NET_MAX_SG) {
                        vhost_discard(vq, hc);
                        return 0;
                }
                heads[hc].iov_base = (void *)vhost_get_vq_desc(vq->dev, 
vq,
-                       vq->iov, ARRAY_SIZE(vq->iov), &out, &in, log, 
log_num);
+                       vq->iov+seg, ARRAY_SIZE(vq->iov)-seg, &out, &in,
+                       log, log_num);
                if (heads[hc].iov_base == (void *)vq->num) {
                        vhost_discard(vq, hc);
                        return 0;
@@ -872,11 +938,12 @@
                        vhost_discard(vq, hc);
                        return 0;
                }
-               heads[hc].iov_len = iov_length(vq->iov, in);
-               hc++;
+               heads[hc].iov_len = iov_length(vq->iov+seg, in);
                datalen -= heads[hc].iov_len;
+               hc++;
+               seg += in;
        }
-       *iovcount = in;
+       *iovcount = seg;
        return hc;
 }
 
diff -ruN net-next-p1/drivers/vhost/vhost.h 
net-next-p2/drivers/vhost/vhost.h
--- net-next-p1/drivers/vhost/vhost.h   2010-03-01 11:42:18.000000000 
-0800
+++ net-next-p2/drivers/vhost/vhost.h   2010-03-02 13:02:03.000000000 
-0800
@@ -82,10 +82,9 @@
        u64 log_addr;
 
        struct iovec indirect[VHOST_NET_MAX_SG];
-       struct iovec iov[VHOST_NET_MAX_SG];
-       struct iovec hdr[VHOST_NET_MAX_SG];
+       struct iovec iov[VHOST_NET_MAX_SG+1]; /* an extra for vnet hdr */
        struct iovec heads[VHOST_NET_MAX_SG];
-       size_t hdr_size;
+       size_t guest_hlen, sock_hlen;
        /* We use a kind of RCU to access private pointer.
         * All readers access it from workqueue, which makes it possible 
to
         * flush the workqueue instead of synchronize_rcu. Therefore 
readers do


[-- Attachment #2: MRXB2.patch --]
[-- Type: application/octet-stream, Size: 9374 bytes --]

diff -ruN net-next-p1/drivers/vhost/net.c net-next-p2/drivers/vhost/net.c
--- net-next-p1/drivers/vhost/net.c	2010-03-01 11:44:22.000000000 -0800
+++ net-next-p2/drivers/vhost/net.c	2010-03-02 13:01:34.000000000 -0800
@@ -109,7 +109,6 @@
 	};
 	size_t len, total_len = 0;
 	int err, wmem;
-	size_t hdr_size;
 	struct socket *sock = rcu_dereference(vq->private_data);
 	if (!sock)
 		return;
@@ -124,7 +123,6 @@
 
 	if (wmem < sock->sk->sk_sndbuf * 2)
 		tx_poll_stop(net);
-	hdr_size = vq->hdr_size;
 
 	for (;;) {
 		head.iov_base = (void *)vhost_get_vq_desc(&net->dev, vq,
@@ -148,25 +146,45 @@
 			       "out %d, int %d\n", out, in);
 			break;
 		}
+		if (vq->guest_hlen > vq->sock_hlen) {
+			if (msg.msg_iov[0].iov_len == vq->guest_hlen)
+				msg.msg_iov[0].iov_len = vq->sock_hlen;
+			else if (out == ARRAY_SIZE(vq->iov))
+				vq_err(vq, "handle_tx iov overflow!");
+			else {
+				int i;
+
+				/* give header its own iov */
+				for (i=out; i>0; ++i)
+					msg.msg_iov[i+1] = msg.msg_iov[i];
+				msg.msg_iov[0].iov_len = vq->sock_hlen;
+				msg.msg_iov[1].iov_base += vq->guest_hlen;
+				msg.msg_iov[1].iov_len -= vq->guest_hlen;
+				out++;
+			}
+		}
 		/* Skip header. TODO: support TSO. */
-		s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, out);
 		msg.msg_iovlen = out;
 		head.iov_len = len = iov_length(vq->iov, out);
 		/* Sanity check */
 		if (!len) {
 			vq_err(vq, "Unexpected header len for TX: "
 			       "%zd expected %zd\n",
-			       iov_length(vq->hdr, s), hdr_size);
+			       len, vq->guest_hlen);
 			break;
 		}
 		/* TODO: Check specific error and bomb out unless ENOBUFS? */
 		err = sock->ops->sendmsg(NULL, sock, &msg, len);
 		if (unlikely(err < 0)) {
-			vhost_discard(vq, 1);
-			tx_poll_start(net, sock);
+			if (err == -EAGAIN) {
+				tx_poll_start(net, sock);
+			} else {
+				vq_err(vq, "sendmsg: errno %d\n", -err);
+				/* drop packet; do not discard/resend */
+				vhost_add_used_and_signal(&net->dev,vq,&head,1);
+			}
 			break;
-		}
-		if (err != len)
+		} else if (err != len)
 			pr_err("Truncated TX packet: "
 			       " len %d != %zd\n", err, len);
 		vhost_add_used_and_signal(&net->dev, vq, &head, 1);
@@ -207,14 +225,8 @@
 		.msg_flags = MSG_DONTWAIT,
 	};
 
-	struct virtio_net_hdr hdr = {
-		.flags = 0,
-		.gso_type = VIRTIO_NET_HDR_GSO_NONE
-	};
-
 	size_t len, total_len = 0;
 	int err, headcount, datalen;
-	size_t hdr_size;
 	struct socket *sock = rcu_dereference(vq->private_data);
 
 	if (!sock || !skb_head_len(&sock->sk->sk_receive_queue))
@@ -223,7 +235,6 @@
 	use_mm(net->dev.mm);
 	mutex_lock(&vq->mutex);
 	vhost_disable_notify(vq);
-	hdr_size = vq->hdr_size;
 
 	vq_log = unlikely(vhost_has_feature(&net->dev, VHOST_F_LOG_ALL)) ?
 		vq->log : NULL;
@@ -232,25 +243,18 @@
 		headcount = vhost_get_heads(vq, datalen, &in, vq_log, &log);
 		/* OK, now we need to know about added descriptors. */
 		if (!headcount) {
-			if (unlikely(vhost_enable_notify(vq))) {
-				/* They have slipped one in as we were
-				 * doing that: check again. */
-				vhost_disable_notify(vq);
-				continue;
-			}
-			/* Nothing new?  Wait for eventfd to tell us
-			 * they refilled. */
+			vhost_enable_notify(vq);
 			break;
 		}
 		/* Skip header. TODO: support TSO/mergeable rx buffers. */
-		s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, in);
 		msg.msg_iovlen = in;
 		len = iov_length(vq->iov, in);
+
 		/* Sanity check */
 		if (!len) {
 			vq_err(vq, "Unexpected header len for RX: "
 			       "%zd expected %zd\n",
-			       iov_length(vq->hdr, s), hdr_size);
+			       len, vq->guest_hlen);
 			break;
 		}
 		err = sock->ops->recvmsg(NULL, sock, &msg,
@@ -268,13 +272,7 @@
 			continue;
 		}
 		len = err;
-		err = memcpy_toiovec(vq->hdr, (unsigned char *)&hdr, hdr_size);
-		if (err) {
-			vq_err(vq, "Unable to write vnet_hdr at addr %p: %d\n",
-			       vq->iov->iov_base, err);
-			break;
-		}
-		len += hdr_size;
+		len += vq->guest_hlen - vq->sock_hlen;
 		vhost_add_used_and_signal(&net->dev, vq, vq->heads, headcount);
 		if (unlikely(vq_log))
 			vhost_log_write(vq, vq_log, log, len);
@@ -483,6 +481,13 @@
 	return ERR_PTR(-ENOTSOCK);
 }
 
+static int vhost_sock_is_raw(struct socket *sock)
+{
+	if (!sock || !sock->sk)
+		return 0;
+	return sock->sk->sk_type == SOCK_RAW;
+}
+
 static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd)
 {
 	struct socket *sock, *oldsock;
@@ -519,6 +524,20 @@
 
 	vhost_net_disable_vq(n, vq);
 	rcu_assign_pointer(vq->private_data, sock);
+
+	if (sock && sock->sk) {
+		if (!vhost_sock_is_raw(sock) ||
+		    vhost_has_feature(&n->dev, VHOST_NET_F_VIRTIO_NET_HDR)) {
+			vq->sock_hlen = sizeof(struct virtio_net_hdr);
+			if (vhost_has_feature(&n->dev, VIRTIO_NET_F_MRG_RXBUF))
+				vq->guest_hlen =
+					sizeof(struct virtio_net_hdr_mrg_rxbuf);
+			else
+				vq->guest_hlen = sizeof(struct virtio_net_hdr);
+		} else
+			vq->guest_hlen = vq->sock_hlen = 0;
+	} else
+		vq_err(vq, "vhost_net_set_backend: sock->sk is NULL");
 	vhost_net_enable_vq(n, vq);
 	mutex_unlock(&vq->mutex);
 done:
@@ -566,8 +585,17 @@
 	n->dev.acked_features = features;
 	smp_wmb();
 	for (i = 0; i < VHOST_NET_VQ_MAX; ++i) {
-		mutex_lock(&n->vqs[i].mutex);
-		n->vqs[i].hdr_size = hdr_size;
+		struct vhost_virtqueue *vq = n->vqs + i;
+		struct socket *sock = vq->private_data;
+
+		mutex_lock(&vq->mutex);
+		if (features & (1 << VIRTIO_NET_F_MRG_RXBUF))
+			vq->sock_hlen = sizeof(struct virtio_net_hdr_mrg_rxbuf);
+		else if (features & (1 << VHOST_NET_F_VIRTIO_NET_HDR) ||
+			 !vhost_sock_is_raw(sock))
+			vq->sock_hlen = sizeof(struct virtio_net_hdr);
+		else
+			vq->sock_hlen = 0;
 		mutex_unlock(&n->vqs[i].mutex);
 	}
 	vhost_net_flush(n);
diff -ruN net-next-p1/drivers/vhost/vhost.c net-next-p2/drivers/vhost/vhost.c
--- net-next-p1/drivers/vhost/vhost.c	2010-03-01 11:44:06.000000000 -0800
+++ net-next-p2/drivers/vhost/vhost.c	2010-03-02 12:53:02.000000000 -0800
@@ -113,7 +113,8 @@
 	vq->used_flags = 0;
 	vq->log_used = false;
 	vq->log_addr = -1ull;
-	vq->hdr_size = 0;
+	vq->guest_hlen = 0;
+	vq->sock_hlen = 0;
 	vq->private_data = NULL;
 	vq->log_base = NULL;
 	vq->error_ctx = NULL;
@@ -848,20 +849,85 @@
 	return 0;
 }
 
+static int
+vhost_get_hdr(struct vhost_virtqueue *vq, int *in, struct vhost_log *log,
+	int *log_num)
+{
+	struct iovec *heads = vq->heads;
+	struct iovec *iov = vq->iov;
+	int out;
+
+	*in = 0;
+	iov[0].iov_len = 0;
+
+	/* get buffer, starting from iov[1] */
+	heads[0].iov_base = (void *)vhost_get_vq_desc(vq->dev, vq,
+		vq->iov+1, ARRAY_SIZE(vq->iov)-1, &out, in, log, log_num);
+	if (out || *in <= 0) {
+		vq_err(vq, "unexpected descriptor format for RX: out %d, "
+			"in %d\n", out, *in);
+		return 0;
+	}
+	if (heads[0].iov_base == (void *)vq->num)
+		return 0;
+
+	/* make iov[0] the header */
+	if (!vq->guest_hlen) {
+		if (vq->sock_hlen) {
+			static struct virtio_net_hdr junk; /* bit bucket */
+
+			iov[0].iov_base = &junk;
+			iov[0].iov_len = sizeof(junk);
+		} else
+			iov[0].iov_len = 0;
+	}
+	if (vq->sock_hlen < vq->guest_hlen) {
+		iov[0].iov_base = iov[1].iov_base;
+		iov[0].iov_len = vq->sock_hlen;
+
+		if (iov[1].iov_len < vq->sock_hlen) {
+			vq_err(vq, "can't fit header in one buffer!");
+			vhost_discard(vq, 1);
+			return 0;
+		}
+		if (!vq->sock_hlen) {
+			static const struct virtio_net_hdr_mrg_rxbuf hdr = {
+				.hdr.flags = 0,
+				.hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE
+			};
+			memcpy(iov[0].iov_base, &hdr, vq->guest_hlen);
+		}
+		iov[1].iov_base += vq->guest_hlen;
+		iov[1].iov_len -= vq->guest_hlen;
+	}
+	return 1;
+}
+
 unsigned vhost_get_heads(struct vhost_virtqueue *vq, int datalen, int *iovcount,
 	struct vhost_log *log, unsigned int *log_num)
 {
 	struct iovec *heads = vq->heads;
-	int out, in;
+	int out, in = 0;
+	int seg = 0;
 	int hc = 0;
 
+	if (vq->guest_hlen != vq->sock_hlen) {
+		seg = vhost_get_hdr(vq, &in, log, log_num);
+		if (!seg)
+			return 0;
+		hc++;
+		datalen -= iov_length(vq->iov+seg, in);
+		seg += in;
+	}
+
 	while (datalen > 0) {
 		if (hc >= VHOST_NET_MAX_SG) {
 			vhost_discard(vq, hc);
 			return 0;
 		}
 		heads[hc].iov_base = (void *)vhost_get_vq_desc(vq->dev, vq,
-			vq->iov, ARRAY_SIZE(vq->iov), &out, &in, log, log_num);
+			vq->iov+seg, ARRAY_SIZE(vq->iov)-seg, &out, &in,
+			log, log_num);
 		if (heads[hc].iov_base == (void *)vq->num) {
 			vhost_discard(vq, hc);
 			return 0;
@@ -872,11 +938,12 @@
 			vhost_discard(vq, hc);
 			return 0;
 		}
-		heads[hc].iov_len = iov_length(vq->iov, in);
-		hc++;
+		heads[hc].iov_len = iov_length(vq->iov+seg, in);
 		datalen -= heads[hc].iov_len;
+		hc++;
+		seg += in;
 	}
-	*iovcount = in;
+	*iovcount = seg;
 	return hc;
 }
 
diff -ruN net-next-p1/drivers/vhost/vhost.h net-next-p2/drivers/vhost/vhost.h
--- net-next-p1/drivers/vhost/vhost.h	2010-03-01 11:42:18.000000000 -0800
+++ net-next-p2/drivers/vhost/vhost.h	2010-03-02 13:02:03.000000000 -0800
@@ -82,10 +82,9 @@
 	u64 log_addr;
 
 	struct iovec indirect[VHOST_NET_MAX_SG];
-	struct iovec iov[VHOST_NET_MAX_SG];
-	struct iovec hdr[VHOST_NET_MAX_SG];
+	struct iovec iov[VHOST_NET_MAX_SG+1]; /* an extra for vnet hdr */
 	struct iovec heads[VHOST_NET_MAX_SG];
-	size_t hdr_size;
+	size_t guest_hlen, sock_hlen;
 	/* We use a kind of RCU to access private pointer.
 	 * All readers access it from workqueue, which makes it possible to
 	 * flush the workqueue instead of synchronize_rcu. Therefore readers do

^ permalink raw reply

* [RFC][ PATCH 3/3] vhost-net: Add mergeable RX buffer support to vhost-net
From: David Stevens @ 2010-03-03  0:20 UTC (permalink / raw)
  To: mst, rusty; +Cc: netdev, kvm, virtualization

[-- Attachment #1: Type: text/plain, Size: 7770 bytes --]

This patch glues them all together and makes sure we
notify whenever we don't have enough buffers to receive
a max-sized packet, and adds the feature bit.

Signed-off-by: David L Stevens <dlstevens@us.ibm.com>

diff -ruN net-next-p2/drivers/vhost/net.c net-next-p3/drivers/vhost/net.c
--- net-next-p2/drivers/vhost/net.c     2010-03-02 13:01:34.000000000 
-0800
+++ net-next-p3/drivers/vhost/net.c     2010-03-02 15:25:15.000000000 
-0800
@@ -54,26 +54,6 @@
        enum vhost_net_poll_state tx_poll_state;
 };
 
-/* Pop first len bytes from iovec. Return number of segments used. */
-static int move_iovec_hdr(struct iovec *from, struct iovec *to,
-                         size_t len, int iov_count)
-{
-       int seg = 0;
-       size_t size;
-       while (len && seg < iov_count) {
-               size = min(from->iov_len, len);
-               to->iov_base = from->iov_base;
-               to->iov_len = size;
-               from->iov_len -= size;
-               from->iov_base += size;
-               len -= size;
-               ++from;
-               ++to;
-               ++seg;
-       }
-       return seg;
-}
-
 /* Caller must have TX VQ lock */
 static void tx_poll_stop(struct vhost_net *net)
 {
@@ -97,7 +77,7 @@
 static void handle_tx(struct vhost_net *net)
 {
        struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_TX];
-       unsigned out, in, s;
+       unsigned out, in;
        struct iovec head;
        struct msghdr msg = {
                .msg_name = NULL,
@@ -110,6 +90,7 @@
        size_t len, total_len = 0;
        int err, wmem;
        struct socket *sock = rcu_dereference(vq->private_data);
+
        if (!sock)
                return;
 
@@ -166,11 +147,11 @@
                /* Skip header. TODO: support TSO. */
                msg.msg_iovlen = out;
                head.iov_len = len = iov_length(vq->iov, out);
+
                /* Sanity check */
                if (!len) {
                        vq_err(vq, "Unexpected header len for TX: "
-                              "%zd expected %zd\n",
-                              len, vq->guest_hlen);
+                              "%zd expected %zd\n", len, vq->guest_hlen);
                        break;
                }
                /* TODO: Check specific error and bomb out unless ENOBUFS? 
*/
@@ -214,7 +195,7 @@
 static void handle_rx(struct vhost_net *net)
 {
        struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX];
-       unsigned in, log, s;
+       unsigned in, log;
        struct vhost_log *vq_log;
        struct msghdr msg = {
                .msg_name = NULL,
@@ -245,30 +226,36 @@
                if (!headcount) {
                        vhost_enable_notify(vq);
                        break;
-               }
+               } else if (vq->maxheadcount < headcount)
+                       vq->maxheadcount = headcount;
                /* Skip header. TODO: support TSO/mergeable rx buffers. */
                msg.msg_iovlen = in;
                len = iov_length(vq->iov, in);
-
                /* Sanity check */
                if (!len) {
                        vq_err(vq, "Unexpected header len for RX: "
-                              "%zd expected %zd\n",
-                              len, vq->guest_hlen);
+                              "%zd expected %zd\n", len, vq->guest_hlen);
                        break;
                }
                err = sock->ops->recvmsg(NULL, sock, &msg,
                                         len, MSG_DONTWAIT | MSG_TRUNC);
-               /* TODO: Check specific error and bomb out unless EAGAIN? 
*/
                if (err < 0) {
-                       vhost_discard(vq, 1);
+                       vhost_discard(vq, headcount);
                        break;
                }
                /* TODO: Should check and handle checksum. */
+               if (vhost_has_feature(&net->dev, VIRTIO_NET_F_MRG_RXBUF)) 
{
+                       struct virtio_net_hdr_mrg_rxbuf *vhdr =
+                               (struct virtio_net_hdr_mrg_rxbuf *)
+                               vq->iov[0].iov_base;
+                       /* add num_bufs */
+                       vq->iov[0].iov_len = vq->guest_hlen;
+                       vhdr->num_buffers = headcount;
+               }
                if (err > len) {
                        pr_err("Discarded truncated rx packet: "
                               " len %d > %zd\n", err, len);
-                       vhost_discard(vq, 1);
+                       vhost_discard(vq, headcount);
                        continue;
                }
                len = err;
@@ -573,8 +560,6 @@
 
 static int vhost_net_set_features(struct vhost_net *n, u64 features)
 {
-       size_t hdr_size = features & (1 << VHOST_NET_F_VIRTIO_NET_HDR) ?
-               sizeof(struct virtio_net_hdr) : 0;
        int i;
        mutex_lock(&n->dev.mutex);
        if ((features & (1 << VHOST_F_LOG_ALL)) &&
diff -ruN net-next-p2/drivers/vhost/vhost.c 
net-next-p3/drivers/vhost/vhost.c
--- net-next-p2/drivers/vhost/vhost.c   2010-03-02 12:53:02.000000000 
-0800
+++ net-next-p3/drivers/vhost/vhost.c   2010-03-02 15:24:50.000000000 
-0800
@@ -115,6 +115,7 @@
        vq->log_addr = -1ull;
        vq->guest_hlen = 0;
        vq->sock_hlen = 0;
+       vq->maxheadcount = 0;
        vq->private_data = NULL;
        vq->log_base = NULL;
        vq->error_ctx = NULL;
@@ -410,6 +411,7 @@
                vq->last_avail_idx = s.num;
                /* Forget the cached index value. */
                vq->avail_idx = vq->last_avail_idx;
+               vq->maxheadcount = 0;
                break;
        case VHOST_GET_VRING_BASE:
                s.index = idx;
@@ -1114,10 +1116,23 @@
        return 0;
 }
 
+int vhost_available(struct vhost_virtqueue *vq)
+{
+       int avail;
+
+       if (!vq->maxheadcount)  /* haven't got any yet */
+               return 1;
+       avail = vq->avail_idx - vq->last_avail_idx;
+       if (avail < 0)
+               avail += 0x10000; /* wrapped */
+       return avail;
+}
+
 /* This actually signals the guest, using eventfd. */
 void vhost_signal(struct vhost_dev *dev, struct vhost_virtqueue *vq)
 {
        __u16 flags = 0;
+
        if (get_user(flags, &vq->avail->flags)) {
                vq_err(vq, "Failed to get flags");
                return;
@@ -1125,7 +1140,7 @@
 
        /* If they don't want an interrupt, don't signal, unless empty. */
        if ((flags & VRING_AVAIL_F_NO_INTERRUPT) &&
-           (vq->avail_idx != vq->last_avail_idx ||
+           (vhost_available(vq) > vq->maxheadcount ||
             !vhost_has_feature(dev, VIRTIO_F_NOTIFY_ON_EMPTY)))
                return;
 
diff -ruN net-next-p2/drivers/vhost/vhost.h 
net-next-p3/drivers/vhost/vhost.h
--- net-next-p2/drivers/vhost/vhost.h   2010-03-02 13:02:03.000000000 
-0800
+++ net-next-p3/drivers/vhost/vhost.h   2010-03-02 14:29:44.000000000 
-0800
@@ -85,6 +85,7 @@
        struct iovec iov[VHOST_NET_MAX_SG+1]; /* an extra for vnet hdr */
        struct iovec heads[VHOST_NET_MAX_SG];
        size_t guest_hlen, sock_hlen;
+       int maxheadcount;
        /* We use a kind of RCU to access private pointer.
         * All readers access it from workqueue, which makes it possible 
to
         * flush the workqueue instead of synchronize_rcu. Therefore 
readers do
@@ -151,7 +152,8 @@
        VHOST_FEATURES = (1 << VIRTIO_F_NOTIFY_ON_EMPTY) |
                         (1 << VIRTIO_RING_F_INDIRECT_DESC) |
                         (1 << VHOST_F_LOG_ALL) |
-                        (1 << VHOST_NET_F_VIRTIO_NET_HDR),
+                        (1 << VHOST_NET_F_VIRTIO_NET_HDR) |
+                        (1 << VIRTIO_NET_F_MRG_RXBUF),
 };
 
 static inline int vhost_has_feature(struct vhost_dev *dev, int bit)


[-- Attachment #2: MRXB3.patch --]
[-- Type: application/octet-stream, Size: 5852 bytes --]

diff -ruN net-next-p2/drivers/vhost/net.c net-next-p3/drivers/vhost/net.c
--- net-next-p2/drivers/vhost/net.c	2010-03-02 13:01:34.000000000 -0800
+++ net-next-p3/drivers/vhost/net.c	2010-03-02 15:25:15.000000000 -0800
@@ -54,26 +54,6 @@
 	enum vhost_net_poll_state tx_poll_state;
 };
 
-/* Pop first len bytes from iovec. Return number of segments used. */
-static int move_iovec_hdr(struct iovec *from, struct iovec *to,
-			  size_t len, int iov_count)
-{
-	int seg = 0;
-	size_t size;
-	while (len && seg < iov_count) {
-		size = min(from->iov_len, len);
-		to->iov_base = from->iov_base;
-		to->iov_len = size;
-		from->iov_len -= size;
-		from->iov_base += size;
-		len -= size;
-		++from;
-		++to;
-		++seg;
-	}
-	return seg;
-}
-
 /* Caller must have TX VQ lock */
 static void tx_poll_stop(struct vhost_net *net)
 {
@@ -97,7 +77,7 @@
 static void handle_tx(struct vhost_net *net)
 {
 	struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_TX];
-	unsigned out, in, s;
+	unsigned out, in;
 	struct iovec head;
 	struct msghdr msg = {
 		.msg_name = NULL,
@@ -110,6 +90,7 @@
 	size_t len, total_len = 0;
 	int err, wmem;
 	struct socket *sock = rcu_dereference(vq->private_data);
+
 	if (!sock)
 		return;
 
@@ -166,11 +147,11 @@
 		/* Skip header. TODO: support TSO. */
 		msg.msg_iovlen = out;
 		head.iov_len = len = iov_length(vq->iov, out);
+
 		/* Sanity check */
 		if (!len) {
 			vq_err(vq, "Unexpected header len for TX: "
-			       "%zd expected %zd\n",
-			       len, vq->guest_hlen);
+			       "%zd expected %zd\n", len, vq->guest_hlen);
 			break;
 		}
 		/* TODO: Check specific error and bomb out unless ENOBUFS? */
@@ -214,7 +195,7 @@
 static void handle_rx(struct vhost_net *net)
 {
 	struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX];
-	unsigned in, log, s;
+	unsigned in, log;
 	struct vhost_log *vq_log;
 	struct msghdr msg = {
 		.msg_name = NULL,
@@ -245,30 +226,36 @@
 		if (!headcount) {
 			vhost_enable_notify(vq);
 			break;
-		}
+		} else if (vq->maxheadcount < headcount)
+			vq->maxheadcount = headcount;
 		/* Skip header. TODO: support TSO/mergeable rx buffers. */
 		msg.msg_iovlen = in;
 		len = iov_length(vq->iov, in);
-
 		/* Sanity check */
 		if (!len) {
 			vq_err(vq, "Unexpected header len for RX: "
-			       "%zd expected %zd\n",
-			       len, vq->guest_hlen);
+			       "%zd expected %zd\n", len, vq->guest_hlen);
 			break;
 		}
 		err = sock->ops->recvmsg(NULL, sock, &msg,
 					 len, MSG_DONTWAIT | MSG_TRUNC);
-		/* TODO: Check specific error and bomb out unless EAGAIN? */
 		if (err < 0) {
-			vhost_discard(vq, 1);
+			vhost_discard(vq, headcount);
 			break;
 		}
 		/* TODO: Should check and handle checksum. */
+		if (vhost_has_feature(&net->dev, VIRTIO_NET_F_MRG_RXBUF)) {
+			struct virtio_net_hdr_mrg_rxbuf *vhdr =
+				(struct virtio_net_hdr_mrg_rxbuf *)
+				vq->iov[0].iov_base;
+			/* add num_bufs */
+			vq->iov[0].iov_len = vq->guest_hlen;
+			vhdr->num_buffers = headcount;
+		}
 		if (err > len) {
 			pr_err("Discarded truncated rx packet: "
 			       " len %d > %zd\n", err, len);
-			vhost_discard(vq, 1);
+			vhost_discard(vq, headcount);
 			continue;
 		}
 		len = err;
@@ -573,8 +560,6 @@
 
 static int vhost_net_set_features(struct vhost_net *n, u64 features)
 {
-	size_t hdr_size = features & (1 << VHOST_NET_F_VIRTIO_NET_HDR) ?
-		sizeof(struct virtio_net_hdr) : 0;
 	int i;
 	mutex_lock(&n->dev.mutex);
 	if ((features & (1 << VHOST_F_LOG_ALL)) &&
diff -ruN net-next-p2/drivers/vhost/vhost.c net-next-p3/drivers/vhost/vhost.c
--- net-next-p2/drivers/vhost/vhost.c	2010-03-02 12:53:02.000000000 -0800
+++ net-next-p3/drivers/vhost/vhost.c	2010-03-02 15:24:50.000000000 -0800
@@ -115,6 +115,7 @@
 	vq->log_addr = -1ull;
 	vq->guest_hlen = 0;
 	vq->sock_hlen = 0;
+	vq->maxheadcount = 0;
 	vq->private_data = NULL;
 	vq->log_base = NULL;
 	vq->error_ctx = NULL;
@@ -410,6 +411,7 @@
 		vq->last_avail_idx = s.num;
 		/* Forget the cached index value. */
 		vq->avail_idx = vq->last_avail_idx;
+		vq->maxheadcount = 0;
 		break;
 	case VHOST_GET_VRING_BASE:
 		s.index = idx;
@@ -1114,10 +1116,23 @@
 	return 0;
 }
 
+int vhost_available(struct vhost_virtqueue *vq)
+{
+	int avail;
+
+	if (!vq->maxheadcount)	/* haven't got any yet */
+		return 1;
+	avail = vq->avail_idx - vq->last_avail_idx;
+	if (avail < 0)
+		avail += 0x10000; /* wrapped */
+	return avail;
+}
+
 /* This actually signals the guest, using eventfd. */
 void vhost_signal(struct vhost_dev *dev, struct vhost_virtqueue *vq)
 {
 	__u16 flags = 0;
+
 	if (get_user(flags, &vq->avail->flags)) {
 		vq_err(vq, "Failed to get flags");
 		return;
@@ -1125,7 +1140,7 @@
 
 	/* If they don't want an interrupt, don't signal, unless empty. */
 	if ((flags & VRING_AVAIL_F_NO_INTERRUPT) &&
-	    (vq->avail_idx != vq->last_avail_idx ||
+	    (vhost_available(vq) > vq->maxheadcount ||
 	     !vhost_has_feature(dev, VIRTIO_F_NOTIFY_ON_EMPTY)))
 		return;
 
diff -ruN net-next-p2/drivers/vhost/vhost.h net-next-p3/drivers/vhost/vhost.h
--- net-next-p2/drivers/vhost/vhost.h	2010-03-02 13:02:03.000000000 -0800
+++ net-next-p3/drivers/vhost/vhost.h	2010-03-02 14:29:44.000000000 -0800
@@ -85,6 +85,7 @@
 	struct iovec iov[VHOST_NET_MAX_SG+1]; /* an extra for vnet hdr */
 	struct iovec heads[VHOST_NET_MAX_SG];
 	size_t guest_hlen, sock_hlen;
+	int maxheadcount;
 	/* We use a kind of RCU to access private pointer.
 	 * All readers access it from workqueue, which makes it possible to
 	 * flush the workqueue instead of synchronize_rcu. Therefore readers do
@@ -151,7 +152,8 @@
 	VHOST_FEATURES = (1 << VIRTIO_F_NOTIFY_ON_EMPTY) |
 			 (1 << VIRTIO_RING_F_INDIRECT_DESC) |
 			 (1 << VHOST_F_LOG_ALL) |
-			 (1 << VHOST_NET_F_VIRTIO_NET_HDR),
+			 (1 << VHOST_NET_F_VIRTIO_NET_HDR) |
+			 (1 << VIRTIO_NET_F_MRG_RXBUF),
 };
 
 static inline int vhost_has_feature(struct vhost_dev *dev, int bit)

^ permalink raw reply

* Re: [RFC][ PATCH 0/3] vhost-net: Add mergeable RX buffer support to vhost-net
From: Michael S. Tsirkin @ 2010-03-03  7:54 UTC (permalink / raw)
  To: David Stevens; +Cc: rusty, netdev, kvm, virtualization
In-Reply-To: <OF8B8E9FD7.1F227ED3-ON882576DA.008312B5-882576DB.0001D5AB@us.ibm.com>

On Tue, Mar 02, 2010 at 04:20:03PM -0800, David Stevens wrote:
> These patches add support for mergeable receive buffers to
> vhost-net, allowing it to use multiple virtio buffer heads for a single
> receive packet.
>                                         +-DLS
> 
> 
> Signed-off-by: David L Stevens <dlstevens@us.ibm.com>

Do you have performance numbers (both with and without mergeable buffers
in guest)?

-- 
MST

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox