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@xxxxxxxxxx> --- 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 -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list