qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/2] virtio: migration fixes for memory region cache
@ 2017-02-21 18:58 Stefan Hajnoczi
  2017-02-21 18:59 ` [Qemu-devel] [PATCH 1/2] virtio: invalidate memory in vring_set_avail_event() Stefan Hajnoczi
  2017-02-21 18:59 ` [Qemu-devel] [PATCH 2/2] virtio: add missing region cache init in virtio_load() Stefan Hajnoczi
  0 siblings, 2 replies; 7+ messages in thread
From: Stefan Hajnoczi @ 2017-02-21 18:58 UTC (permalink / raw)
  To: qemu-devel; +Cc: Michael S. Tsirkin, Stefan Hajnoczi

Bug fixes for the recently added memory region cache in virtio.  This series
fixes live migration, see patches for details.

Stefan Hajnoczi (2):
  virtio: invalidate memory in vring_set_avail_event()
  virtio: add missing region cache init in virtio_load()

 hw/virtio/virtio.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

-- 
2.9.3

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [Qemu-devel] [PATCH 1/2] virtio: invalidate memory in vring_set_avail_event()
  2017-02-21 18:58 [Qemu-devel] [PATCH 0/2] virtio: migration fixes for memory region cache Stefan Hajnoczi
@ 2017-02-21 18:59 ` Stefan Hajnoczi
  2017-02-21 18:59 ` [Qemu-devel] [PATCH 2/2] virtio: add missing region cache init in virtio_load() Stefan Hajnoczi
  1 sibling, 0 replies; 7+ messages in thread
From: Stefan Hajnoczi @ 2017-02-21 18:59 UTC (permalink / raw)
  To: qemu-devel; +Cc: Michael S. Tsirkin, Stefan Hajnoczi, Paolo Bonzini

Remember to invalidate the avail event field so the memory pages are
marked dirty.

Cc: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 hw/virtio/virtio.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 23483c7..da5c6fe 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -282,6 +282,7 @@ static inline void vring_set_avail_event(VirtQueue *vq, uint16_t val)
     caches = atomic_rcu_read(&vq->vring.caches);
     pa = offsetof(VRingUsed, ring[vq->vring.num]);
     virtio_stw_phys_cached(vq->vdev, &caches->used, pa, val);
+    address_space_cache_invalidate(&caches->used, pa, sizeof(val));
 }
 
 void virtio_queue_set_notification(VirtQueue *vq, int enable)
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [Qemu-devel] [PATCH 2/2] virtio: add missing region cache init in virtio_load()
  2017-02-21 18:58 [Qemu-devel] [PATCH 0/2] virtio: migration fixes for memory region cache Stefan Hajnoczi
  2017-02-21 18:59 ` [Qemu-devel] [PATCH 1/2] virtio: invalidate memory in vring_set_avail_event() Stefan Hajnoczi
@ 2017-02-21 18:59 ` Stefan Hajnoczi
  2017-02-22  9:16   ` Cornelia Huck
  1 sibling, 1 reply; 7+ messages in thread
From: Stefan Hajnoczi @ 2017-02-21 18:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Michael S. Tsirkin, Stefan Hajnoczi, Dr . David Alan Gilbert,
	Paolo Bonzini

Commit 97cd965c070152bc626c7507df9fb356bbe1cd81 ("virtio: use
VRingMemoryRegionCaches for avail and used rings") switched to a memory
region cache to avoid repeated map/unmap operations.

The virtio_load() process is a little tricky because vring addresses are
serialized in two separate places.  VIRTIO 1.0 devices serialize desc
and then a subsection with used and avail.  Legacy devices only
serialize desc.

Live migration of VIRTIO 1.0 devices fails on the destination host with:

  VQ 0 size 0x80 < last_avail_idx 0x12f8 - used_idx 0x0
  Failed to load virtio-blk:virtio
  error while loading state for instance 0x0 of device '0000:00:04.0/virtio-blk'

This happens because the memory region cache is only initialized after
desc is loaded and not after the used and avail subsection is loaded.
If the guest chose memory addresses that don't match the legacy ring
layout then the wrong guest memory location is accessed.

Clarify comments about VIRTIO 1.0 and force memory region cache
initialization at the point where all ring addresses are known.

Cc: Dr. David Alan Gilbert <dgilbert@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 hw/virtio/virtio.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index da5c6fe..5bbc34b 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -1853,7 +1853,10 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f)
         if (k->has_variable_vring_alignment) {
             qemu_put_be32(f, vdev->vq[i].vring.align);
         }
-        /* XXX virtio-1 devices */
+        /*
+         * Save desc now, the rest of the ring addresses are saved in
+         * subsections for VIRTIO-1 devices.
+         */
         qemu_put_be64(f, vdev->vq[i].vring.desc);
         qemu_put_be16s(f, &vdev->vq[i].last_avail_idx);
         if (k->save_queue) {
@@ -1995,7 +1998,10 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
         vdev->vq[i].notification = true;
 
         if (vdev->vq[i].vring.desc) {
-            /* XXX virtio-1 devices */
+            /*
+             * VIRTIO-1 devices may not have final ring addresses here.  The
+             * used and avail ring addresses are loaded in subsections later.
+             */
             virtio_queue_update_rings(vdev, i);
         } else if (vdev->vq[i].last_avail_idx) {
             error_report("VQ %d address 0x0 "
@@ -2062,6 +2068,10 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
     for (i = 0; i < num; i++) {
         if (vdev->vq[i].vring.desc) {
             uint16_t nheads;
+
+            /* All ring addresses have been loaded now... */
+            virtio_init_region_cache(vdev, i);
+
             nheads = vring_avail_idx(&vdev->vq[i]) - vdev->vq[i].last_avail_idx;
             /* Check it isn't doing strange things with descriptor numbers. */
             if (nheads > vdev->vq[i].vring.num) {
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [Qemu-devel] [PATCH 2/2] virtio: add missing region cache init in virtio_load()
  2017-02-21 18:59 ` [Qemu-devel] [PATCH 2/2] virtio: add missing region cache init in virtio_load() Stefan Hajnoczi
@ 2017-02-22  9:16   ` Cornelia Huck
  2017-02-22 10:19     ` Paolo Bonzini
  2017-02-22 11:33     ` Stefan Hajnoczi
  0 siblings, 2 replies; 7+ messages in thread
From: Cornelia Huck @ 2017-02-22  9:16 UTC (permalink / raw)
  To: Stefan Hajnoczi
  Cc: qemu-devel, Paolo Bonzini, Dr . David Alan Gilbert,
	Michael S. Tsirkin

On Tue, 21 Feb 2017 18:59:01 +0000
Stefan Hajnoczi <stefanha@redhat.com> wrote:

> Commit 97cd965c070152bc626c7507df9fb356bbe1cd81 ("virtio: use
> VRingMemoryRegionCaches for avail and used rings") switched to a memory
> region cache to avoid repeated map/unmap operations.
> 
> The virtio_load() process is a little tricky because vring addresses are
> serialized in two separate places.  VIRTIO 1.0 devices serialize desc
> and then a subsection with used and avail.  Legacy devices only
> serialize desc.
> 
> Live migration of VIRTIO 1.0 devices fails on the destination host with:
> 
>   VQ 0 size 0x80 < last_avail_idx 0x12f8 - used_idx 0x0
>   Failed to load virtio-blk:virtio
>   error while loading state for instance 0x0 of device '0000:00:04.0/virtio-blk'
> 
> This happens because the memory region cache is only initialized after
> desc is loaded and not after the used and avail subsection is loaded.
> If the guest chose memory addresses that don't match the legacy ring
> layout then the wrong guest memory location is accessed.
> 
> Clarify comments about VIRTIO 1.0 and force memory region cache
> initialization at the point where all ring addresses are known.

Yes, the XXX comments should have been changed when the subsection for
used/avail had been introduced.

> 
> Cc: Dr. David Alan Gilbert <dgilbert@redhat.com>
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>  hw/virtio/virtio.c | 14 ++++++++++++--
>  1 file changed, 12 insertions(+), 2 deletions(-)
> 
> diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
> index da5c6fe..5bbc34b 100644
> --- a/hw/virtio/virtio.c
> +++ b/hw/virtio/virtio.c
> @@ -1853,7 +1853,10 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f)
>          if (k->has_variable_vring_alignment) {
>              qemu_put_be32(f, vdev->vq[i].vring.align);
>          }
> -        /* XXX virtio-1 devices */
> +        /*
> +         * Save desc now, the rest of the ring addresses are saved in
> +         * subsections for VIRTIO-1 devices.
> +         */
>          qemu_put_be64(f, vdev->vq[i].vring.desc);
>          qemu_put_be16s(f, &vdev->vq[i].last_avail_idx);
>          if (k->save_queue) {
> @@ -1995,7 +1998,10 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
>          vdev->vq[i].notification = true;
> 
>          if (vdev->vq[i].vring.desc) {
> -            /* XXX virtio-1 devices */
> +            /*
> +             * VIRTIO-1 devices may not have final ring addresses here.  The
> +             * used and avail ring addresses are loaded in subsections later.
> +             */
>              virtio_queue_update_rings(vdev, i);
>          } else if (vdev->vq[i].last_avail_idx) {
>              error_report("VQ %d address 0x0 "
> @@ -2062,6 +2068,10 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
>      for (i = 0; i < num; i++) {
>          if (vdev->vq[i].vring.desc) {
>              uint16_t nheads;
> +
> +            /* All ring addresses have been loaded now... */
> +            virtio_init_region_cache(vdev, i);

It feels a bit weird that the region cache was already initialized when
update rings was called. Should the call to init_region_cache be moved
from update_rings() to virtio_queue_set_addr()?

> +
>              nheads = vring_avail_idx(&vdev->vq[i]) - vdev->vq[i].last_avail_idx;
>              /* Check it isn't doing strange things with descriptor numbers. */
>              if (nheads > vdev->vq[i].vring.num) {

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Qemu-devel] [PATCH 2/2] virtio: add missing region cache init in virtio_load()
  2017-02-22  9:16   ` Cornelia Huck
@ 2017-02-22 10:19     ` Paolo Bonzini
  2017-02-22 11:12       ` Cornelia Huck
  2017-02-22 11:33     ` Stefan Hajnoczi
  1 sibling, 1 reply; 7+ messages in thread
From: Paolo Bonzini @ 2017-02-22 10:19 UTC (permalink / raw)
  To: Cornelia Huck, Stefan Hajnoczi
  Cc: Michael S. Tsirkin, qemu-devel, Dr . David Alan Gilbert



On 22/02/2017 10:16, Cornelia Huck wrote:
>> +
>> +            /* All ring addresses have been loaded now... */
>> +            virtio_init_region_cache(vdev, i);
> It feels a bit weird that the region cache was already initialized when
> update rings was called. Should the call to init_region_cache be moved
> from update_rings() to virtio_queue_set_addr()?

virtio_queue_set_addr isn't called at all, is it?

The alternative would be to call virtio_init_region_cache from a
postload callback of vmstate_virtqueue, but Stefan's patch is fine too IMHO.

Paolo

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Qemu-devel] [PATCH 2/2] virtio: add missing region cache init in virtio_load()
  2017-02-22 10:19     ` Paolo Bonzini
@ 2017-02-22 11:12       ` Cornelia Huck
  0 siblings, 0 replies; 7+ messages in thread
From: Cornelia Huck @ 2017-02-22 11:12 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Stefan Hajnoczi, Michael S. Tsirkin, qemu-devel,
	Dr . David Alan Gilbert

On Wed, 22 Feb 2017 11:19:45 +0100
Paolo Bonzini <pbonzini@redhat.com> wrote:

> On 22/02/2017 10:16, Cornelia Huck wrote:
> >> +
> >> +            /* All ring addresses have been loaded now... */
> >> +            virtio_init_region_cache(vdev, i);
> > It feels a bit weird that the region cache was already initialized when
> > update rings was called. Should the call to init_region_cache be moved
> > from update_rings() to virtio_queue_set_addr()?
> 
> virtio_queue_set_addr isn't called at all, is it?
> 
> The alternative would be to call virtio_init_region_cache from a
> postload callback of vmstate_virtqueue, but Stefan's patch is fine too IMHO.

What I meant was:

We currently have

set_addr -> update_rings -> init_region_cache

and for virtio-1

set_rings -> init_region_cache

The code with Stefan's fix now sets up a region cache via update_rings
and replaces it later via the call introduced above - which is fine,
but adds an extra iteration.

If we move to

set_addr -> update_rings
            init_region_cache

we get the same call pattern for both legacy and virtio-1 layouts and
save the extra iteration. But we can do that in an additional cleanup
patch, and I think the patch is fine as-is, so

Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Qemu-devel] [PATCH 2/2] virtio: add missing region cache init in virtio_load()
  2017-02-22  9:16   ` Cornelia Huck
  2017-02-22 10:19     ` Paolo Bonzini
@ 2017-02-22 11:33     ` Stefan Hajnoczi
  1 sibling, 0 replies; 7+ messages in thread
From: Stefan Hajnoczi @ 2017-02-22 11:33 UTC (permalink / raw)
  To: Cornelia Huck
  Cc: qemu-devel, Paolo Bonzini, Dr . David Alan Gilbert,
	Michael S. Tsirkin

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

On Wed, Feb 22, 2017 at 10:16:53AM +0100, Cornelia Huck wrote:
> > @@ -2062,6 +2068,10 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
> >      for (i = 0; i < num; i++) {
> >          if (vdev->vq[i].vring.desc) {
> >              uint16_t nheads;
> > +
> > +            /* All ring addresses have been loaded now... */
> > +            virtio_init_region_cache(vdev, i);
> 
> It feels a bit weird that the region cache was already initialized when
> update rings was called. Should the call to init_region_cache be moved
> from update_rings() to virtio_queue_set_addr()?

Will fix in v2.

Stefan

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 455 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2017-02-22 12:34 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-02-21 18:58 [Qemu-devel] [PATCH 0/2] virtio: migration fixes for memory region cache Stefan Hajnoczi
2017-02-21 18:59 ` [Qemu-devel] [PATCH 1/2] virtio: invalidate memory in vring_set_avail_event() Stefan Hajnoczi
2017-02-21 18:59 ` [Qemu-devel] [PATCH 2/2] virtio: add missing region cache init in virtio_load() Stefan Hajnoczi
2017-02-22  9:16   ` Cornelia Huck
2017-02-22 10:19     ` Paolo Bonzini
2017-02-22 11:12       ` Cornelia Huck
2017-02-22 11:33     ` Stefan Hajnoczi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).