]> xenbits.xensource.com Git - libvirt.git/commitdiff
qemu: Add vhost-scsi string for -device parameter
authorEric Farman <farman@linux.vnet.ibm.com>
Tue, 22 Nov 2016 03:58:18 +0000 (22:58 -0500)
committerJohn Ferlan <jferlan@redhat.com>
Thu, 24 Nov 2016 17:16:19 +0000 (12:16 -0500)
Open /dev/vhost-scsi, and record the resulting file descriptor, so that
the guest has access to the host device outside of the libvirt daemon.
Pass this information, along with data parsed from the XML file, to build
a device string for the qemu command line.  That device string will be
for either a vhost-scsi-ccw device in the case of an s390 machine, or
vhost-scsi-pci for any others.

Signed-off-by: Eric Farman <farman@linux.vnet.ibm.com>
src/qemu/qemu_cgroup.c
src/qemu/qemu_command.c
src/qemu/qemu_command.h
src/qemu/qemu_domain_address.c
src/qemu/qemu_hostdev.c
src/qemu/qemu_hostdev.h

index 7a9fc536d442826169996db3e7db11e0ef8751c4..999f7a314c91abf2f21ed76ddcdc551a2a9d9346 100644 (file)
@@ -299,6 +299,25 @@ qemuSetupHostSCSIDeviceCgroup(virSCSIDevicePtr dev ATTRIBUTE_UNUSED,
     return ret;
 }
 
+static int
+qemuSetupHostSCSIVHostDeviceCgroup(virSCSIVHostDevicePtr dev ATTRIBUTE_UNUSED,
+                                   const char *path,
+                                   void *opaque)
+{
+    virDomainObjPtr vm = opaque;
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+    int ret;
+
+    VIR_DEBUG("Process path '%s' for scsi_host device", path);
+
+    ret = virCgroupAllowDevicePath(priv->cgroup, path,
+                                   VIR_CGROUP_DEVICE_RW, false);
+
+    virDomainAuditCgroupPath(vm, priv->cgroup, "allow", path, "rw", ret == 0);
+
+    return ret;
+}
+
 int
 qemuSetupHostdevCgroup(virDomainObjPtr vm,
                        virDomainHostdevDefPtr dev)
@@ -308,9 +327,11 @@ qemuSetupHostdevCgroup(virDomainObjPtr vm,
     virDomainHostdevSubsysUSBPtr usbsrc = &dev->source.subsys.u.usb;
     virDomainHostdevSubsysPCIPtr pcisrc = &dev->source.subsys.u.pci;
     virDomainHostdevSubsysSCSIPtr scsisrc = &dev->source.subsys.u.scsi;
+    virDomainHostdevSubsysSCSIVHostPtr hostsrc = &dev->source.subsys.u.scsi_host;
     virPCIDevicePtr pci = NULL;
     virUSBDevicePtr usb = NULL;
     virSCSIDevicePtr scsi = NULL;
+    virSCSIVHostDevicePtr host = NULL;
     char *path = NULL;
 
     /* currently this only does something for PCI devices using vfio
@@ -399,6 +420,16 @@ qemuSetupHostdevCgroup(virDomainObjPtr vm,
         }
 
         case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST: {
+            if (hostsrc->protocol ==
+                VIR_DOMAIN_HOSTDEV_SUBSYS_SCSI_HOST_PROTOCOL_TYPE_VHOST) {
+                if (!(host = virSCSIVHostDeviceNew(hostsrc->wwpn)))
+                    goto cleanup;
+
+                if (virSCSIVHostDeviceFileIterate(host,
+                                             qemuSetupHostSCSIVHostDeviceCgroup,
+                                             vm) < 0)
+                    goto cleanup;
+            }
             break;
         }
 
@@ -412,6 +443,7 @@ qemuSetupHostdevCgroup(virDomainObjPtr vm,
     virPCIDeviceFree(pci);
     virUSBDeviceFree(usb);
     virSCSIDeviceFree(scsi);
+    virSCSIVHostDeviceFree(host);
     VIR_FREE(path);
     return ret;
 }
index 51b5aafdd9e52a752f2db3afb96828a02735f781..6c457dd6903ca5724a049def5898720218fdc071 100644 (file)
@@ -4741,6 +4741,44 @@ qemuBuildSCSIiSCSIHostdevDrvStr(virDomainHostdevDefPtr dev)
     return source;
 }
 
+char *
+qemuBuildSCSIVHostHostdevDevStr(const virDomainDef *def,
+                           virDomainHostdevDefPtr dev,
+                           virQEMUCapsPtr qemuCaps,
+                           char *vhostfdName)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    virDomainHostdevSubsysSCSIVHostPtr hostsrc = &dev->source.subsys.u.scsi_host;
+
+    if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VHOST_SCSI)) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("This QEMU doesn't support vhost-scsi devices"));
+        goto cleanup;
+    }
+
+    if (ARCH_IS_S390(def->os.arch))
+        virBufferAddLit(&buf, "vhost-scsi-ccw");
+    else
+        virBufferAddLit(&buf, "vhost-scsi-pci");
+
+    virBufferAsprintf(&buf, ",wwpn=%s,vhostfd=%s,id=%s",
+                      hostsrc->wwpn,
+                      vhostfdName,
+                      dev->info->alias);
+
+    if (qemuBuildDeviceAddressStr(&buf, def, dev->info, qemuCaps) < 0)
+        goto cleanup;
+
+    if (virBufferCheckError(&buf) < 0)
+        goto cleanup;
+
+    return virBufferContentAndReset(&buf);
+
+ cleanup:
+    virBufferFreeAndReset(&buf);
+    return NULL;
+}
+
 char *
 qemuBuildSCSIHostdevDrvStr(virDomainHostdevDefPtr dev)
 {
@@ -5221,6 +5259,48 @@ qemuBuildHostdevCommandLine(virCommandPtr cmd,
                 return -1;
             }
         }
+
+        /* SCSI_host */
+        if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
+            subsys->type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST) {
+            if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_SCSI_GENERIC)) {
+                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                               _("SCSI passthrough is not supported by this "
+                                 "version of qemu"));
+                return -1;
+            }
+
+            if (hostdev->source.subsys.u.scsi_host.protocol ==
+                VIR_DOMAIN_HOSTDEV_SUBSYS_SCSI_HOST_PROTOCOL_TYPE_VHOST) {
+                char *vhostfdName = NULL;
+                int vhostfd = -1;
+
+                if (virSCSIVHostOpenVhostSCSI(&vhostfd) < 0)
+                    return -1;
+
+                if (virAsprintf(&vhostfdName, "%d", vhostfd) < 0) {
+                    VIR_FORCE_CLOSE(vhostfd);
+                    return -1;
+                }
+
+                virCommandPassFD(cmd, vhostfd,
+                                 VIR_COMMAND_PASS_FD_CLOSE_PARENT);
+
+                virCommandAddArg(cmd, "-device");
+                if (!(devstr = qemuBuildSCSIVHostHostdevDevStr(def,
+                                                               hostdev,
+                                                               qemuCaps,
+                                                               vhostfdName))) {
+                    VIR_FREE(vhostfdName);
+                    VIR_FORCE_CLOSE(vhostfd);
+                    return -1;
+                }
+                virCommandAddArg(cmd, devstr);
+
+                VIR_FREE(vhostfdName);
+                VIR_FREE(devstr);
+            }
+        }
     }
 
     return 0;
index e0c84dfb4902b0f71ceb3454a9ad5d7e67c1f441..3bcfdc6e4fd252b0333431a67c8c76237d18df04 100644 (file)
@@ -164,6 +164,11 @@ char *qemuBuildSCSIHostdevDrvStr(virDomainHostdevDefPtr dev);
 char *qemuBuildSCSIHostdevDevStr(const virDomainDef *def,
                                  virDomainHostdevDefPtr dev,
                                  virQEMUCapsPtr qemuCaps);
+char *
+qemuBuildSCSIVHostHostdevDevStr(const virDomainDef *def,
+                                virDomainHostdevDefPtr dev,
+                                virQEMUCapsPtr qemuCaps,
+                                char *vhostfdName);
 
 char *qemuBuildRedirdevDevStr(const virDomainDef *def,
                               virDomainRedirdevDefPtr dev,
index 30ecb4e615b47ea5d13b6137c06eae066784c4c2..13f6702b5f2ac5b31c364182a07250ae8e4f4dfb 100644 (file)
@@ -312,6 +312,14 @@ qemuDomainPrimeVirtioDeviceAddresses(virDomainDefPtr def,
         }
     }
 
+    for (i = 0; i < def->nhostdevs; i++) {
+        if (def->hostdevs[i]->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
+            def->hostdevs[i]->source.subsys.type ==
+            VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST &&
+            def->hostdevs[i]->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
+            def->hostdevs[i]->info->type = type;
+    }
+
     if (def->memballoon &&
         def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO &&
         def->memballoon->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
@@ -1594,8 +1602,10 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def,
     for (i = 0; i < def->nhostdevs; i++) {
         if (!virDeviceInfoPCIAddressWanted(def->hostdevs[i]->info))
             continue;
-        if (def->hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
-            def->hostdevs[i]->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
+        if (def->hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
+            continue;
+        if (def->hostdevs[i]->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI &&
+            def->hostdevs[i]->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST)
             continue;
 
         if (qemuDomainPCIAddressReserveNextSlot(addrs,
index dd3a3cf8faf713be40319afe5cecd9dfbfaca1bb..7cd49e4aa50a674ef4c8bcb8d16d0efecd02959f 100644 (file)
@@ -292,6 +292,17 @@ qemuHostdevPrepareSCSIDevices(virQEMUDriverPtr driver,
                                         name, hostdevs, nhostdevs);
 }
 
+int
+qemuHostdevPrepareSCSIVHostDevices(virQEMUDriverPtr driver,
+                                   const char *name,
+                                   virDomainHostdevDefPtr *hostdevs,
+                                   int nhostdevs)
+{
+    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
+
+    return virHostdevPrepareSCSIVHostDevices(hostdev_mgr, QEMU_DRIVER_NAME,
+                                             name, hostdevs, nhostdevs);
+}
 
 int
 qemuHostdevPrepareDomainDevices(virQEMUDriverPtr driver,
@@ -315,6 +326,10 @@ qemuHostdevPrepareDomainDevices(virQEMUDriverPtr driver,
                                       def->hostdevs, def->nhostdevs) < 0)
         return -1;
 
+    if (qemuHostdevPrepareSCSIVHostDevices(driver, def->name,
+                                           def->hostdevs, def->nhostdevs) < 0)
+        return -1;
+
     return 0;
 }
 
@@ -369,6 +384,18 @@ qemuHostdevReAttachSCSIDevices(virQEMUDriverPtr driver,
                                   name, hostdevs, nhostdevs);
 }
 
+void
+qemuHostdevReAttachSCSIVHostDevices(virQEMUDriverPtr driver,
+                                    const char *name,
+                                    virDomainHostdevDefPtr *hostdevs,
+                                    int nhostdevs)
+{
+    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
+
+    virHostdevReAttachSCSIVHostDevices(hostdev_mgr, QEMU_DRIVER_NAME,
+                                       name, hostdevs, nhostdevs);
+}
+
 void
 qemuHostdevReAttachDomainDevices(virQEMUDriverPtr driver,
                                  virDomainDefPtr def)
@@ -384,4 +411,7 @@ qemuHostdevReAttachDomainDevices(virQEMUDriverPtr driver,
 
     qemuHostdevReAttachSCSIDevices(driver, def->name, def->hostdevs,
                                    def->nhostdevs);
+
+    qemuHostdevReAttachSCSIVHostDevices(driver, def->name, def->hostdevs,
+                                        def->nhostdevs);
 }
index 0a3c715998e00eae341ab875df6fb7a7e555c34e..74a7d4f34e43361f4690895e159b5be4ed95c6f0 100644 (file)
@@ -55,6 +55,10 @@ int qemuHostdevPrepareSCSIDevices(virQEMUDriverPtr driver,
                                   const char *name,
                                   virDomainHostdevDefPtr *hostdevs,
                                   int nhostdevs);
+int qemuHostdevPrepareSCSIVHostDevices(virQEMUDriverPtr driver,
+                                       const char *name,
+                                       virDomainHostdevDefPtr *hostdevs,
+                                       int nhostdevs);
 int qemuHostdevPrepareDomainDevices(virQEMUDriverPtr driver,
                                     virDomainDefPtr def,
                                     virQEMUCapsPtr qemuCaps,
@@ -72,6 +76,10 @@ void qemuHostdevReAttachSCSIDevices(virQEMUDriverPtr driver,
                                     const char *name,
                                     virDomainHostdevDefPtr *hostdevs,
                                     int nhostdevs);
+void qemuHostdevReAttachSCSIVHostDevices(virQEMUDriverPtr driver,
+                                         const char *name,
+                                         virDomainHostdevDefPtr *hostdevs,
+                                         int nhostdevs);
 void qemuHostdevReAttachDomainDevices(virQEMUDriverPtr driver,
                                       virDomainDefPtr def);