From: Stefan Hajnoczi <stefa...@linux.vnet.ibm.com>

This patch starts and stops vhost as the virtio device transitions
through its status phases.  Vhost can only be started once the guest
reports its driver has successfully initialized, which means the
virtqueues have been set up by the guest.

Signed-off-by: Stefan Hajnoczi <stefa...@linux.vnet.ibm.com>
Signed-off-by: Zhi Yong Wu <wu...@linux.vnet.ibm.com>
---
 hw/virtio-scsi.c |   44 +++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 43 insertions(+), 1 deletions(-)

diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c
index 5c74523..85170d3 100644
--- a/hw/virtio-scsi.c
+++ b/hw/virtio-scsi.c
@@ -138,7 +138,6 @@ typedef struct {
     uint32_t sense_size;
     uint32_t cdb_size;
     int resetting;
-    struct vhost_virtqueue vhost_vqs[1];
     bool vhost_started;
     VHostSCSI *vhost_scsi;
 } VirtIOSCSI;
@@ -586,6 +585,42 @@ static struct SCSIBusInfo virtio_scsi_scsi_info = {
     .load_request = virtio_scsi_load_request,
 };
 
+static bool virtio_scsi_started(VirtIOSCSI *s, uint8_t val)
+{
+    return (val & VIRTIO_CONFIG_S_DRIVER_OK) && s->vdev.vm_running;
+}
+
+static void virtio_scsi_set_status(VirtIODevice *vdev, uint8_t val)
+{
+    VirtIOSCSI *s = to_virtio_scsi(vdev);
+    bool start = virtio_scsi_started(s, val);
+
+    if (s->vhost_started == start) {
+        return;
+    }
+
+    if (start) {
+        int ret;
+
+        if (!vhost_dev_query(&s->vhost_scsi, vdev)) {
+            return;
+        }
+
+        ret = virtio_scsi_vhost_start(s);
+        if (ret < 0) {
+            error_report("virtio-scsi: unable to start vhost: %s\n",
+                         strerror(-ret));
+
+            /* There is no userspace virtio-scsi fallback so exit */
+            exit(1);
+        }
+    } else {
+        virtio_scsi_vhost_stop(s);
+    }
+
+    s->vhost_started = start;
+}
+
 VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *proxyconf)
 {
     VirtIOSCSI *s;
@@ -605,6 +640,9 @@ VirtIODevice *virtio_scsi_init(DeviceState *dev, 
VirtIOSCSIConf *proxyconf)
     s->vdev.set_config = virtio_scsi_set_config;
     s->vdev.get_features = virtio_scsi_get_features;
     s->vdev.reset = virtio_scsi_reset;
+    if (s->vhost_scsi) {
+        s->vdev.set_status = virtio_scsi_set_status;
+    }
 
     s->ctrl_vq = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE,
                                    virtio_scsi_handle_ctrl);
@@ -628,6 +666,10 @@ void virtio_scsi_exit(VirtIODevice *vdev)
 {
     VirtIOSCSI *s = (VirtIOSCSI *)vdev;
     unregister_savevm(s->qdev, "virtio-scsi", s);
+
+    /* This will stop vhost backend if appropriate. */
+    virtio_scsi_set_status(vdev, 0);
+
     vhost_dev_cleanup(&s->vhost_scsi);
     virtio_cleanup(vdev);
 }
-- 
1.7.6


Reply via email to