diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 9401d93c66..7c38c58077 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1688,6 +1688,7 @@ virObjectUnref; # util/virpci.h virPCIDeviceAddressGetSysfsFile; +virPCIDeviceCopy; virPCIDeviceDetach; virPCIDeviceFileIterate; virPCIDeviceFree; @@ -1704,6 +1705,7 @@ virPCIDeviceListAdd; virPCIDeviceListCount; virPCIDeviceListDel; virPCIDeviceListFind; +virPCIDeviceListFindByIDs; virPCIDeviceListFindIndex; virPCIDeviceListGet; virPCIDeviceListNew; diff --git a/src/util/virpci.c b/src/util/virpci.c index d00c3ee822..10e95bd8b0 100644 --- a/src/util/virpci.c +++ b/src/util/virpci.c @@ -880,6 +880,54 @@ virPCIFile(char **buffer, const char *device, const char *file) return 0; } + +/* virPCIDeviceGetDriverPathAndName - put the path to the driver + * directory of the driver in use for this device in @path and the + * name of the driver in @name. Both could be NULL if it's not bound + * to any driver. + * + * Return 0 for success, -1 for error. + */ +static int +virPCIDeviceGetDriverPathAndName(virPCIDevicePtr dev, char **path, char **name) +{ + int ret = -1; + char *drvlink = NULL; + + *path = *name = NULL; + /* drvlink = "/sys/bus/pci/dddd:bb:ss.ff/driver" */ + if (virPCIFile(&drvlink, dev->name, "driver") < 0) + goto cleanup; + + if (virFileIsLink(drvlink) != 1) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Invalid device %s driver file %s is not a symlink"), + dev->name, drvlink); + goto cleanup; + } + if (virFileResolveLink(drvlink, path) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to resolve device %s driver symlink %s"), + dev->name, drvlink); + goto cleanup; + } + /* path = "/sys/bus/pci/drivers/${drivername}" */ + + if (VIR_STRDUP(*name, last_component(*path)) < 0) + goto cleanup; + /* name = "${drivername}" */ + + ret = 0; +cleanup: + VIR_FREE(drvlink); + if (ret < 0) { + VIR_FREE(*path); + VIR_FREE(*name); + } + return ret; +} + + static int virPCIProbeStubDriver(const char *driver) { @@ -931,23 +979,7 @@ virPCIDeviceUnbindFromStub(virPCIDevicePtr dev) /* If the device is currently bound to one of the "well known" * stub drivers, then unbind it, otherwise ignore it. */ - if (virPCIFile(&path, dev->name, "driver") < 0) - goto cleanup; - /* path = "/sys/bus/pci/dddd:bb:ss.ff/driver" */ - if (virFileIsLink(path) != 1) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Invalid device %s driver file %s is not a symlink"), - dev->name, path); - goto cleanup; - } - if (virFileResolveLink(path, &drvdir) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unable to resolve device %s driver symlink %s"), - dev->name, path); - goto cleanup; - } - /* drvdir = "/sys/bus/pci/drivers/${drivername}" */ - if (VIR_STRDUP(driver, last_component(drvdir)) < 0) + if (virPCIDeviceGetDriverPathAndName(dev, &drvdir, &driver) < 0) goto cleanup; if (!dev->unbind_from_stub) @@ -1473,6 +1505,32 @@ error: goto cleanup; } + +virPCIDevicePtr +virPCIDeviceCopy(virPCIDevicePtr dev) +{ + virPCIDevicePtr copy; + + if (VIR_ALLOC(copy) < 0) { + virReportOOMError(); + return NULL; + } + + /* shallow copy to take care of most attributes */ + *copy = *dev; + copy->path = copy->stubDriver = NULL; + if (VIR_STRDUP(copy->path, dev->path) < 0 || + VIR_STRDUP(copy->stubDriver, dev->stubDriver) < 0) { + goto error; + } + return copy; + +error: + virPCIDeviceFree(copy); + return NULL; +} + + void virPCIDeviceFree(virPCIDevicePtr dev) { @@ -1690,6 +1748,27 @@ virPCIDeviceListFindIndex(virPCIDeviceListPtr list, virPCIDevicePtr dev) return -1; } + +virPCIDevicePtr +virPCIDeviceListFindByIDs(virPCIDeviceListPtr list, + unsigned int domain, + unsigned int bus, + unsigned int slot, + unsigned int function) +{ + int i; + + for (i = 0; i < list->count; i++) { + if (list->devs[i]->domain == domain && + list->devs[i]->bus == bus && + list->devs[i]->slot == slot && + list->devs[i]->function == function) + return list->devs[i]; + } + return NULL; +} + + virPCIDevicePtr virPCIDeviceListFind(virPCIDeviceListPtr list, virPCIDevicePtr dev) { diff --git a/src/util/virpci.h b/src/util/virpci.h index 17b15fef06..d069adba0d 100644 --- a/src/util/virpci.h +++ b/src/util/virpci.h @@ -45,6 +45,7 @@ virPCIDevicePtr virPCIDeviceNew(unsigned int domain, unsigned int bus, unsigned int slot, unsigned int function); +virPCIDevicePtr virPCIDeviceCopy(virPCIDevicePtr dev); void virPCIDeviceFree(virPCIDevicePtr dev); const char *virPCIDeviceGetName(virPCIDevicePtr dev); @@ -94,6 +95,12 @@ void virPCIDeviceListDel(virPCIDeviceListPtr list, virPCIDevicePtr dev); virPCIDevicePtr virPCIDeviceListFind(virPCIDeviceListPtr list, virPCIDevicePtr dev); +virPCIDevicePtr +virPCIDeviceListFindByIDs(virPCIDeviceListPtr list, + unsigned int domain, + unsigned int bus, + unsigned int slot, + unsigned int function); int virPCIDeviceListFindIndex(virPCIDeviceListPtr list, virPCIDevicePtr dev);