[libvirt] [PATCH 2/2] Implement node device assignment in QEMU driver

Mark McLoughlin markmc at redhat.com
Tue Feb 24 22:35:39 UTC 2009


Handle a hostdev source specified as a node device name
by looking up the node device, parsing its XML for
PCI/USB address details, using those as the hostdev
source and, finally, dettaching and resetting the
device.

Signed-off-by: Mark McLoughlin <markmc at redhat.com>
---
 src/qemu_conf.c |  115 ++++++++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 102 insertions(+), 13 deletions(-)

diff --git a/src/qemu_conf.c b/src/qemu_conf.c
index 6f58ee8..dd35f9a 100644
--- a/src/qemu_conf.c
+++ b/src/qemu_conf.c
@@ -47,6 +47,7 @@
 #include "datatypes.h"
 #include "xml.h"
 #include "nodeinfo.h"
+#include "node_device_conf.h"
 
 #define VIR_FROM_THIS VIR_FROM_QEMU
 
@@ -629,6 +630,69 @@ qemudNetworkIfaceConnect(virConnectPtr conn,
 }
 
 
+static int qemudResolveHostdev(virConnectPtr conn, virDomainHostdevDefPtr hostdev)
+{
+    virNodeDevicePtr dev = NULL;
+    virNodeDeviceDefPtr def = NULL;
+    virNodeDevCapsDefPtr cap;
+    char *xml = NULL;
+    int ret = 0;
+
+    if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
+        hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_NODEDEV)
+        goto out;
+
+    ret = -1;
+
+    dev = virNodeDeviceLookupByName(conn, hostdev->source.subsys.u.nodedev_name);
+    if (!dev)
+        goto out;
+
+    xml = virNodeDeviceGetXMLDesc(dev, 0);
+    if (!xml)
+        goto out;
+
+    def = virNodeDeviceDefParseString(dev->conn, xml);
+    if (!def)
+        goto out;
+
+    cap = def->caps;
+    while (cap) {
+        if (cap->type == VIR_NODE_DEV_CAP_USB_DEV) {
+            hostdev->source.subsys.type          = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB;
+            hostdev->source.subsys.u.usb.bus     = cap->data.usb_dev.bus;
+            hostdev->source.subsys.u.usb.device  = cap->data.usb_dev.device;
+            hostdev->source.subsys.u.usb.vendor  = cap->data.usb_dev.vendor;
+            hostdev->source.subsys.u.usb.product = cap->data.usb_dev.product;
+            break;
+        } else if (cap->type == VIR_NODE_DEV_CAP_PCI_DEV) {
+            hostdev->source.subsys.type           = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI;
+            hostdev->source.subsys.u.pci.domain   = cap->data.pci_dev.domain;
+            hostdev->source.subsys.u.pci.bus      = cap->data.pci_dev.bus;
+            hostdev->source.subsys.u.pci.slot     = cap->data.pci_dev.slot;
+            hostdev->source.subsys.u.pci.function = cap->data.pci_dev.function;
+            break;
+        }
+        cap = cap->next;
+    }
+
+    if (!cap) {
+        qemudReportError(dev->conn, NULL, NULL, VIR_ERR_INVALID_ARG,
+                         _("device %s is not a PCI or USB device"), dev->name);
+        goto out;
+    }
+
+    if (virNodeDeviceDettach(dev) < 0)
+        goto out;
+
+    ret = 0;
+out:
+    virNodeDeviceDefFree(def);
+    VIR_FREE(xml);
+    virNodeDeviceFree(dev);
+    return ret;
+}
+
 static int qemudBuildCommandLineChrDevStr(virDomainChrDefPtr dev,
                                           char *buf,
                                           int buflen)
@@ -1357,20 +1421,23 @@ int qemudBuildCommandLine(virConnectPtr conn,
         int ret;
         char* usbdev;
         char* pcidev;
-        virDomainHostdevDefPtr hostdev = vm->def->hostdevs[i];
+        virDomainHostdevDef hostdev = *vm->def->hostdevs[i];
+
+        if (qemudResolveHostdev(conn, &hostdev) < 0)
+            goto error;
 
         /* USB */
-        if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
-            hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
-            if(hostdev->source.subsys.u.usb.vendor) {
+        if (hostdev.mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
+            hostdev.source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
+            if(hostdev.source.subsys.u.usb.vendor) {
                     ret = virAsprintf(&usbdev, "host:%.4x:%.4x",
-                               hostdev->source.subsys.u.usb.vendor,
-                               hostdev->source.subsys.u.usb.product);
+                               hostdev.source.subsys.u.usb.vendor,
+                               hostdev.source.subsys.u.usb.product);
 
             } else {
                     ret = virAsprintf(&usbdev, "host:%.3d.%.3d",
-                               hostdev->source.subsys.u.usb.bus,
-                               hostdev->source.subsys.u.usb.device);
+                               hostdev.source.subsys.u.usb.bus,
+                               hostdev.source.subsys.u.usb.device);
             }
             if (ret < 0)
                 goto error;
@@ -1381,12 +1448,12 @@ int qemudBuildCommandLine(virConnectPtr conn,
         }
 
         /* PCI */
-        if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
-            hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
+        if (hostdev.mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
+            hostdev.source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
             ret = virAsprintf(&pcidev, "host=%.2x:%.2x.%.1x",
-                           hostdev->source.subsys.u.pci.bus,
-                           hostdev->source.subsys.u.pci.slot,
-                           hostdev->source.subsys.u.pci.function);
+                              hostdev.source.subsys.u.pci.bus,
+                              hostdev.source.subsys.u.pci.slot,
+                              hostdev.source.subsys.u.pci.function);
             if (ret < 0) {
                 pcidev = NULL;
                 goto error;
@@ -1395,7 +1462,29 @@ int qemudBuildCommandLine(virConnectPtr conn,
             ADD_ARG_LIT(pcidev);
             VIR_FREE(pcidev);
         }
+    }
+
+    /* Now try and reset passthrough node devices; we do this
+     * because we want to have dettached *all* devices before
+     * resetting *any* devices. */
+    for (i = 0 ; i < vm->def->nhostdevs ; i++) {
+        virDomainHostdevDefPtr hostdev = vm->def->hostdevs[i];
+        virNodeDevicePtr dev;
+
+        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
+            hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_NODEDEV)
+            continue;
+
+        dev = virNodeDeviceLookupByName(conn, hostdev->source.subsys.u.nodedev_name);
+        if (!dev)
+            goto error;
+
+        if (virNodeDeviceReset(dev) < 0) {
+            virNodeDeviceFree(dev);
+            goto error;
+        }
 
+        virNodeDeviceFree(dev);
     }
 
     if (migrateFrom) {
-- 
1.6.0.6




More information about the libvir-list mailing list