[libvirt] [PATCH 2/2] qemu: add support vhost-scsi-pci for device_add hotplug

Nicholas A. Bellinger nab at linux-iscsi.org
Thu Jul 24 03:24:14 UTC 2014


From: Nicholas Bellinger <nab at linux-iscsi.org>

This patch adds support for device_add hotplug for vhost-scsi-pci
against QEMU >= v1.5.x code.

This includes:

  - Add qemuOpenVhostSCSI() to open fds to /dev/vhost-scsi character
    device.
  - Changes to qemuBuildControllerDevStr() for adding 'vhostfd='
    parameters to device_add.
  - Add qemuMonitorAddControllerVhost() that is specific to
    VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VHOST_SCSI
  - Update qemuDomainAttachControllerDevice() to setup vhostfd
    fd + name arrays, and invoke qemuOpenVhostSCSI().
  - Update qemuDomainAttachControllerDevice() to invoke
    qemuMonitorAddControllerVhost() -> qemuMonitorSendFileHandle() ->
    qemuMonitorAddDevice() in order to pass the pre-opened vhostfd.

This code has been tested using openstack nova volume-attach, using
a Juno v2 development head from 07192014.

Signed-off-by: Nicholas Bellinger <nab at linux-iscsi.org>
Signed-off-by: Mike Perez <thingee at gmail.com>
---
 src/qemu/qemu_command.c |   56 ++++++++++++++++++++++++++++++++++++++++++++---
 src/qemu/qemu_command.h |    8 ++++++-
 src/qemu/qemu_hotplug.c |   47 +++++++++++++++++++++++++++++++++++++--
 src/qemu/qemu_monitor.c |   24 ++++++++++++++++++++
 src/qemu/qemu_monitor.h |    4 ++++
 5 files changed, 133 insertions(+), 6 deletions(-)

diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 43c0e1c..1e987f9 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -678,6 +678,38 @@ static int qemuAssignDeviceDiskAliasFixed(virDomainDiskDefPtr disk)
     return 0;
 }
 
+int
+qemuOpenVhostSCSI(virDomainControllerDefPtr controller,
+                  int *vhostfd,
+                  int *vhostfdSize)
+{
+    size_t i;
+
+    if (controller->model != VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VHOST_SCSI) {
+        *vhostfdSize = 0;
+        return 0;
+    }
+
+    for (i = 0; i < *vhostfdSize; i++) {
+        vhostfd[i] = open("/dev/vhost-scsi", O_RDWR);
+
+        if (vhostfd[i] < 0) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                           "%s", _("vhost-scsi was requested for an interface, "
+                                   "but is unavailable"));
+            goto error;
+        }
+    }
+
+    return 0;
+
+ error:
+    while (i--)
+        VIR_FORCE_CLOSE(vhostfd[i]);
+
+    return -1;
+}
+
 static int
 qemuSetSCSIControllerModel(virDomainDefPtr def,
                            virQEMUCapsPtr qemuCaps,
@@ -4153,10 +4185,13 @@ char *
 qemuBuildControllerDevStr(virDomainDefPtr domainDef,
                           virDomainControllerDefPtr def,
                           virQEMUCapsPtr qemuCaps,
-                          int *nusbcontroller)
+                          int *nusbcontroller,
+                          char **vhostfd,
+                          int vhostfdSize)
 {
     virBuffer buf = VIR_BUFFER_INITIALIZER;
     int model;
+    size_t i;
 
     if (!(def->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI &&
           (def->model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI ||
@@ -4328,6 +4363,19 @@ qemuBuildControllerDevStr(virDomainDefPtr domainDef,
     if (def->wwpn)
         virBufferAsprintf(&buf, ",wwpn=%s", def->wwpn);
 
+    if (vhostfdSize) {
+        if (vhostfdSize == 1) {
+            virBufferAsprintf(&buf, ",vhostfd=%s", vhostfd[0]);
+        } else {
+            virBufferAddLit(&buf, ",vhostfds=");
+            for (i = 0; i < vhostfdSize; i++) {
+                if (i)
+                    virBufferAddChar(&buf, ':');
+                virBufferAdd(&buf, vhostfd[i], -1);
+            }
+        }
+    }
+
     if (qemuBuildDeviceAddressStr(&buf, domainDef, &def->info, qemuCaps) < 0)
         goto error;
 
@@ -7843,7 +7891,8 @@ qemuBuildCommandLine(virConnectPtr conn,
 
                         virCommandAddArg(cmd, "-device");
                         if (!(devstr = qemuBuildControllerDevStr(def, cont,
-                                                                 qemuCaps, NULL)))
+                                                                 qemuCaps, NULL,
+                                                                 NULL, 0)))
                             goto error;
 
                         virCommandAddArg(cmd, devstr);
@@ -7867,7 +7916,8 @@ qemuBuildCommandLine(virConnectPtr conn,
 
                     char *devstr;
                     if (!(devstr = qemuBuildControllerDevStr(def, cont, qemuCaps,
-                                                             &usbcontroller)))
+                                                             &usbcontroller, NULL,
+                                                             0)))
                         goto error;
 
                     virCommandAddArg(cmd, devstr);
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index cf51056..b0651ff 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -114,6 +114,10 @@ char * qemuBuildNicDevStr(virDomainDefPtr def,
 char *qemuDeviceDriveHostAlias(virDomainDiskDefPtr disk,
                                virQEMUCapsPtr qemuCaps);
 
+int qemuOpenVhostSCSI(virDomainControllerDefPtr controller,
+                      int *vhostfd,
+                      int *vhostfdSize);
+
 /* Both legacy & current support */
 char *qemuBuildDriveStr(virConnectPtr conn,
                         virDomainDiskDefPtr disk,
@@ -134,7 +138,9 @@ char * qemuBuildFSDevStr(virDomainDefPtr domainDef,
 char * qemuBuildControllerDevStr(virDomainDefPtr domainDef,
                                  virDomainControllerDefPtr def,
                                  virQEMUCapsPtr qemuCaps,
-                                 int *nusbcontroller);
+                                 int *nusbcontroller,
+                                 char **vhostfd,
+                                 int vhostfdSize);
 
 char * qemuBuildWatchdogDevStr(virDomainDefPtr domainDef,
                                virDomainWatchdogDefPtr dev,
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 1fc28b8..4cdac56 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -360,9 +360,13 @@ int qemuDomainAttachControllerDevice(virQEMUDriverPtr driver,
                                      virDomainObjPtr vm,
                                      virDomainControllerDefPtr controller)
 {
+    size_t i;
     int ret = -1;
     const char* type = virDomainControllerTypeToString(controller->type);
     char *devstr = NULL;
+    char **vhostfdName = NULL;
+    int *vhostfd = NULL;
+    int vhostfdSize = 0;
     qemuDomainObjPrivatePtr priv = vm->privateData;
     bool releaseaddr = false;
 
@@ -403,7 +407,30 @@ int qemuDomainAttachControllerDevice(virQEMUDriverPtr driver,
             goto cleanup;
         }
 
-        if (!(devstr = qemuBuildControllerDevStr(vm->def, controller, priv->qemuCaps, NULL))) {
+        if (controller->model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VHOST_SCSI) {
+            /* FIXME: Get total number of virtio-scsi queues */
+            vhostfdSize = 1;
+
+            if (VIR_ALLOC_N(vhostfd, vhostfdSize) < 0)
+                goto cleanup;
+
+            memset(vhostfd, -1, sizeof(*vhostfd) * vhostfdSize);
+
+            if (VIR_ALLOC_N(vhostfdName, vhostfdSize) < 0)
+                goto cleanup;
+
+            if (qemuOpenVhostSCSI(controller, vhostfd, &vhostfdSize) < 0)
+                goto cleanup;
+
+            for (i = 0; i < vhostfdSize; i++) {
+                if (virAsprintf(&vhostfdName[i], "vhostfd-%s%zu",
+                                controller->info.alias, i) < 0)
+                    goto cleanup;
+            }
+        }
+
+        if (!(devstr = qemuBuildControllerDevStr(vm->def, controller, priv->qemuCaps,
+                                                 NULL, vhostfdName, vhostfdSize))) {
             goto cleanup;
         }
     }
@@ -413,7 +440,12 @@ int qemuDomainAttachControllerDevice(virQEMUDriverPtr driver,
 
     qemuDomainObjEnterMonitor(driver, vm);
     if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
-        ret = qemuMonitorAddDevice(priv->mon, devstr);
+        if (controller->model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VHOST_SCSI) {
+            ret = qemuMonitorAddControllerVhost(priv->mon, devstr,
+                                                vhostfd, vhostfdName, vhostfdSize);
+        } else {
+            ret = qemuMonitorAddDevice(priv->mon, devstr);
+        }
     } else {
         ret = qemuMonitorAttachPCIDiskController(priv->mon,
                                                  type,
@@ -421,6 +453,9 @@ int qemuDomainAttachControllerDevice(virQEMUDriverPtr driver,
     }
     qemuDomainObjExitMonitor(driver, vm);
 
+    for (i = 0; i < vhostfdSize; i++)
+        VIR_FORCE_CLOSE(vhostfd[i]);
+
     if (ret == 0) {
         if (controller->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
             controller->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
@@ -431,6 +466,14 @@ int qemuDomainAttachControllerDevice(virQEMUDriverPtr driver,
     if (ret != 0 && releaseaddr)
         qemuDomainReleaseDeviceAddress(vm, &controller->info, NULL);
 
+    for (i = 0; vhostfd && i < vhostfdSize; i++) {
+        VIR_FORCE_CLOSE(vhostfd[i]);
+        if (vhostfdName)
+            VIR_FREE(vhostfdName[i]);
+    }
+    VIR_FREE(vhostfd);
+    VIR_FREE(vhostfdName);
+
     VIR_FREE(devstr);
     return ret;
 }
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index db3dd73..3e67c85 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -3052,6 +3052,30 @@ int qemuMonitorAddDevice(qemuMonitorPtr mon,
     return qemuMonitorAddDeviceWithFd(mon, devicestr, -1, NULL);
 }
 
+int qemuMonitorAddControllerVhost(qemuMonitorPtr mon,
+                                  const char *devicestr,
+                                  int *vhostfd, char **vhostfdName, int vhostfdSize)
+{
+    size_t i = 0;
+
+    for (i = 0; i < vhostfdSize; i++) {
+        if (qemuMonitorSendFileHandle(mon, vhostfdName[i], vhostfd[i]) < 0)
+            goto cleanup;
+    }
+
+    if (qemuMonitorAddDevice(mon, devicestr) < 0)
+        goto cleanup;
+
+    return 0;
+
+ cleanup:
+    while (i--) {
+        if (qemuMonitorCloseFileHandle(mon, vhostfdName[i]) < 0)
+            VIR_WARN("failed to close device handle '%s'", vhostfdName[i]);
+    }
+    return -1;
+}
+
 int qemuMonitorAddDrive(qemuMonitorPtr mon,
                         const char *drivestr)
 {
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 8a23267..8fe21a0 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -620,6 +620,10 @@ int qemuMonitorAddDeviceWithFd(qemuMonitorPtr mon,
                                int fd,
                                const char *fdname);
 
+int qemuMonitorAddControllerVhost(qemuMonitorPtr mon,
+                                  const char *devicestr,
+                                  int *vhostfd, char **vhostfdName, int vhostfdSize);
+
 int qemuMonitorDelDevice(qemuMonitorPtr mon,
                          const char *devalias);
 
-- 
1.7.9.5




More information about the libvir-list mailing list