Patchwork [13/15] virtio-pci: reset all qbuses too when writing to the status field

login
register
mail settings
Submitter Paolo Bonzini
Date Dec. 17, 2012, 4:24 p.m.
Message ID <1355761490-10073-14-git-send-email-pbonzini@redhat.com>
Download mbox | patch
Permalink /patch/206944/
State New
Headers show

Comments

Paolo Bonzini - Dec. 17, 2012, 4:24 p.m.
virtio-pci devices do not perform a full reset when zero is written
to the status byte.  While PCI-specific status is initialized, the
reset does not propagate down the qdev bus hierarchy.  Because of
this, a virtio reset does not cancel in-flight I/O for virtio-scsi
(where the cancellation is handled automatically by the SCSI
devices underneath virtio-scsi-pci).

Reported-by: Bryan Venteicher <bryanv@daemoninthecloset.org>
Cc: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/virtio-pci.c | 28 ++++++++++------------------
 1 file changed, 10 insertions(+), 18 deletions(-)

Patch

diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index a7c75fe..2cf5282 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -268,12 +268,10 @@  static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
     case VIRTIO_PCI_QUEUE_PFN:
         pa = (hwaddr)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT;
         if (pa == 0) {
-            virtio_reset(proxy->vdev);
-            virtio_pci_stop_ioeventfd(proxy);
-            msix_unuse_all_vectors(&proxy->pci_dev);
-        }
-        else
+            qdev_reset_all(&proxy->pci_dev.qdev);
+        } else {
             virtio_queue_set_addr(vdev, vdev->queue_sel, pa);
+        }
         break;
     case VIRTIO_PCI_QUEUE_SEL:
         if (val < VIRTIO_PCI_QUEUE_MAX)
@@ -285,22 +283,16 @@  static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
         }
         break;
     case VIRTIO_PCI_STATUS:
-        if (vdev->status == 0) {
-            virtio_reset(proxy->vdev);
-        }
-
-        if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) {
-            virtio_pci_stop_ioeventfd(proxy);
-        }
-
         virtio_set_status(vdev, val & 0xFF);
 
-        if (val & VIRTIO_CONFIG_S_DRIVER_OK) {
-            virtio_pci_start_ioeventfd(proxy);
-        }
-
         if (vdev->status == 0) {
-            msix_unuse_all_vectors(&proxy->pci_dev);
+            qdev_reset_all(&proxy->pci_dev.qdev);
+        } else {
+            if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) {
+                virtio_pci_stop_ioeventfd(proxy);
+            } else {
+                virtio_pci_start_ioeventfd(proxy);
+            }
         }
 
         /* Linux before 2.6.34 sets the device as OK without enabling