Instead of replicating the information (domain, bus, slot, function)
inside the virPCIDevice structure, use the already-existing
virPCIDeviceAddress structure.
You use virPCIDeviceAddressPtr rather than virPCIDeviceAddress,
resulting in an extra bit of memory to malloc, and an extra indirection
when the members are accessed. Was there a particular reason for that? I
had figured the domain/bus/slot/function would just be replaced by a
plain virPCIDeviceAddress rather than a pointer to one...
Outside of the module, the only visible change is that the return
value
of virPCIDeviceGetAddress() must no longer be freed by the caller.
---
Suggested by Laine[1] in the context of a patch series; since the idea
is not really tied to the series, sending as a stand-alone cleanup.
[1]
https://www.redhat.com/archives/libvir-list/2015-December/msg00125.html
src/util/virhostdev.c | 4 --
src/util/virpci.c | 182 ++++++++++++++++++++++++++++++++++----------------
src/util/virpci.h | 7 ++
3 files changed, 133 insertions(+), 60 deletions(-)
diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c
index de029a0..173ac58 100644
--- a/src/util/virhostdev.c
+++ b/src/util/virhostdev.c
@@ -585,7 +585,6 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
goto cleanup;
}
- VIR_FREE(devAddr);
if (!(devAddr = virPCIDeviceGetAddress(dev)))
goto cleanup;
@@ -728,7 +727,6 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
virObjectUnlock(hostdev_mgr->activePCIHostdevs);
virObjectUnlock(hostdev_mgr->inactivePCIHostdevs);
virObjectUnref(pcidevs);
- VIR_FREE(devAddr);
return ret;
}
@@ -1581,7 +1579,6 @@ virHostdevPCINodeDeviceDetach(virHostdevManagerPtr hostdev_mgr,
out:
virObjectUnlock(hostdev_mgr->inactivePCIHostdevs);
virObjectUnlock(hostdev_mgr->activePCIHostdevs);
- VIR_FREE(devAddr);
return ret;
}
@@ -1613,7 +1610,6 @@ virHostdevPCINodeDeviceReAttach(virHostdevManagerPtr hostdev_mgr,
out:
virObjectUnlock(hostdev_mgr->inactivePCIHostdevs);
virObjectUnlock(hostdev_mgr->activePCIHostdevs);
- VIR_FREE(devAddr);
return ret;
}
diff --git a/src/util/virpci.c b/src/util/virpci.c
index bececb5..2818bf7 100644
--- a/src/util/virpci.c
+++ b/src/util/virpci.c
@@ -56,10 +56,7 @@ VIR_ENUM_IMPL(virPCIELinkSpeed, VIR_PCIE_LINK_SPEED_LAST,
"", "2.5", "5", "8")
struct _virPCIDevice {
- unsigned int domain;
- unsigned int bus;
- unsigned int slot;
- unsigned int function;
+ virPCIDeviceAddressPtr address;
char name[PCI_ADDR_LEN]; /* domain:bus:slot.function */
char id[PCI_ID_LEN]; /* product vendor */
@@ -653,12 +650,14 @@ static int
virPCIDeviceSharesBusWithActive(virPCIDevicePtr dev, virPCIDevicePtr check, void
*data)
{
virPCIDeviceList *inactiveDevs = data;
+ virPCIDeviceAddressPtr devAddr = dev->address;
+ virPCIDeviceAddressPtr checkAddr = check->address;
/* Different domain, different bus, or simply identical device */
- if (dev->domain != check->domain ||
- dev->bus != check->bus ||
- (dev->slot == check->slot &&
- dev->function == check->function))
+ if (devAddr->domain != checkAddr->domain ||
+ devAddr->bus != checkAddr->bus ||
+ (devAddr->slot == checkAddr->slot &&
+ devAddr->function == checkAddr->function))
return 0;
/* same bus, but inactive, i.e. about to be assigned to guest */
@@ -686,10 +685,12 @@ virPCIDeviceIsParent(virPCIDevicePtr dev, virPCIDevicePtr check,
void *data)
uint16_t device_class;
uint8_t header_type, secondary, subordinate;
virPCIDevicePtr *best = data;
+ virPCIDeviceAddressPtr devAddr = dev->address;
+ virPCIDeviceAddressPtr checkAddr = check->address;
int ret = 0;
int fd;
- if (dev->domain != check->domain)
+ if (devAddr->domain != checkAddr->domain)
return 0;
if ((fd = virPCIDeviceConfigOpen(check, false)) < 0)
@@ -713,7 +714,7 @@ virPCIDeviceIsParent(virPCIDevicePtr dev, virPCIDevicePtr check, void
*data)
/* if the secondary bus exactly equals the device's bus, then we found
* the direct parent. No further work is necessary
*/
- if (dev->bus == secondary) {
+ if (devAddr->bus == secondary) {
ret = 1;
goto cleanup;
}
@@ -722,10 +723,10 @@ virPCIDeviceIsParent(virPCIDevicePtr dev, virPCIDevicePtr check,
void *data)
* In this case, what we need to do is look for the "best" match; i.e.
* the most restrictive match that still satisfies all of the conditions.
*/
- if (dev->bus > secondary && dev->bus <= subordinate) {
+ if (devAddr->bus > secondary && devAddr->bus <= subordinate) {
if (*best == NULL) {
- *best = virPCIDeviceNew(check->domain, check->bus, check->slot,
- check->function);
+ *best = virPCIDeviceNew(checkAddr->domain, checkAddr->bus,
+ checkAddr->slot, checkAddr->function);
if (*best == NULL) {
ret = -1;
goto cleanup;
@@ -745,8 +746,8 @@ virPCIDeviceIsParent(virPCIDevicePtr dev, virPCIDevicePtr check, void
*data)
if (secondary > best_secondary) {
virPCIDeviceFree(*best);
- *best = virPCIDeviceNew(check->domain, check->bus,
check->slot,
- check->function);
+ *best = virPCIDeviceNew(checkAddr->domain, checkAddr->bus,
+ checkAddr->slot, checkAddr->function);
if (*best == NULL) {
ret = -1;
goto cleanup;
@@ -925,6 +926,7 @@ virPCIDeviceReset(virPCIDevicePtr dev,
char *drvName = NULL;
int ret = -1;
int fd = -1;
+ virPCIDeviceAddressPtr devAddr = dev->address;
if (activeDevs && virPCIDeviceListFind(activeDevs, dev)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -970,7 +972,7 @@ virPCIDeviceReset(virPCIDevicePtr dev,
ret = virPCIDeviceTryPowerManagementReset(dev, fd);
/* Bus reset is not an option with the root bus */
- if (ret < 0 && dev->bus != 0)
+ if (ret < 0 && devAddr->bus != 0)
ret = virPCIDeviceTrySecondaryBusReset(dev, fd, inactiveDevs);
if (ret < 0) {
@@ -1428,6 +1430,7 @@ virPCIDeviceWaitForCleanup(virPCIDevicePtr dev, const char
*matcher)
bool in_matching_device;
int ret;
size_t match_depth;
+ virPCIDeviceAddressPtr devAddr = dev->address;
fp = fopen("/proc/iomem", "r");
if (!fp) {
@@ -1483,8 +1486,8 @@ virPCIDeviceWaitForCleanup(virPCIDevicePtr dev, const char
*matcher)
virStrToLong_ui(tmp + 1, &tmp, 16, &function) < 0 || *tmp !=
'\n')
continue;
- if (domain != dev->domain || bus != dev->bus || slot != dev->slot
||
- function != dev->function)
+ if (domain != devAddr->domain || bus != devAddr->bus ||
+ slot != devAddr->slot || function != devAddr->function)
continue;
in_matching_device = true;
match_depth = strspn(line, " ");
@@ -1547,6 +1550,72 @@ virPCIGetAddrString(unsigned int domain,
return ret;
}
+/**
+ * virPCIDeviceAddressNew:
+ * @domain: PCI domain
+ * @bus: PCI bus
+ * @slot: PCI slot
+ * @function: PCI function
+ *
+ * Create a new virPCIDeviceAddress object.
+ *
+ * Returns: a new address, or NULL on failure.
+ */
+virPCIDeviceAddressPtr
+virPCIDeviceAddressNew(unsigned int domain,
+ unsigned int bus,
+ unsigned int slot,
+ unsigned int function)
+{
+ virPCIDeviceAddressPtr addr;
+
+ if (VIR_ALLOC(addr) < 0)
+ return NULL;
+
+ addr->domain = domain;
+ addr->bus = bus;
+ addr->slot = slot;
+ addr->function = function;
+
+ return addr;
+}
+
+/**
+ * virPCIDeviceAddressCopy:
+ * @addr: PCI address
+ *
+ * Create a copy of a PCI address.
+ *
+ * Returns: a copy of @addr, or NULL on failure.
+ */
+virPCIDeviceAddressPtr
+virPCIDeviceAddressCopy(virPCIDeviceAddressPtr addr)
+{
+ virPCIDeviceAddressPtr copy;
+
+ if (!addr)
+ return NULL;
+
+ if (VIR_ALLOC(copy) < 0)
+ return NULL;
+
+ *copy = *addr;
+
+ return copy;
+}
+
+/**
+ * virPCIDeviceAddressFree:
+ * @addr: PCI address
+ *
+ * Release all resources associated with a PCI address.
+ */
+void
+virPCIDeviceAddressFree(virPCIDeviceAddressPtr addr)
+{
+ VIR_FREE(addr);
+}
+
virPCIDevicePtr
virPCIDeviceNew(unsigned int domain,
unsigned int bus,
@@ -1560,17 +1629,14 @@ virPCIDeviceNew(unsigned int domain,
if (VIR_ALLOC(dev) < 0)
return NULL;
- dev->domain = domain;
- dev->bus = bus;
- dev->slot = slot;
- dev->function = function;
+ if (!(dev->address = virPCIDeviceAddressNew(domain, bus, slot, function)))
+ goto error;
if (snprintf(dev->name, sizeof(dev->name), "%.4x:%.2x:%.2x.%.1x",
- dev->domain, dev->bus, dev->slot,
- dev->function) >= sizeof(dev->name)) {
+ domain, bus, slot, function) >= sizeof(dev->name)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("dev->name buffer overflow:
%.4x:%.2x:%.2x.%.1x"),
- dev->domain, dev->bus, dev->slot, dev->function);
+ domain, bus, slot, function);
goto error;
}
if (virAsprintf(&dev->path, PCI_SYSFS "devices/%s/config",
@@ -1627,9 +1693,13 @@ virPCIDeviceCopy(virPCIDevicePtr dev)
/* shallow copy to take care of most attributes */
*copy = *dev;
+
+ /* deep copy for the rest */
+ copy->address = NULL;
copy->path = copy->stubDriver = NULL;
copy->used_by_drvname = copy->used_by_domname = NULL;
- if (VIR_STRDUP(copy->path, dev->path) < 0 ||
+ if (!(copy->address = virPCIDeviceAddressCopy(dev->address)) ||
+ VIR_STRDUP(copy->path, dev->path) < 0 ||
VIR_STRDUP(copy->stubDriver, dev->stubDriver) < 0 ||
VIR_STRDUP(copy->used_by_drvname, dev->used_by_drvname) < 0 ||
VIR_STRDUP(copy->used_by_domname, dev->used_by_domname) < 0) {
@@ -1649,6 +1719,7 @@ virPCIDeviceFree(virPCIDevicePtr dev)
if (!dev)
return;
VIR_DEBUG("%s %s: freeing", dev->id, dev->name);
+ virPCIDeviceAddressFree(dev->address);
VIR_FREE(dev->path);
VIR_FREE(dev->stubDriver);
VIR_FREE(dev->used_by_drvname);
@@ -1661,25 +1732,14 @@ virPCIDeviceFree(virPCIDevicePtr dev)
* @dev: device to get address from
*
* Take a PCI device on input and return its PCI address. The
- * caller must free the returned value when no longer needed.
+ * returned object is owned by the device and must not be freed.
*
* Returns NULL on failure, the device address on success.
*/
virPCIDeviceAddressPtr
virPCIDeviceGetAddress(virPCIDevicePtr dev)
{
-
- virPCIDeviceAddressPtr pciAddrPtr;
-
- if (!dev || (VIR_ALLOC(pciAddrPtr) < 0))
- return NULL;
-
- pciAddrPtr->domain = dev->domain;
- pciAddrPtr->bus = dev->bus;
- pciAddrPtr->slot = dev->slot;
- pciAddrPtr->function = dev->function;
-
- return pciAddrPtr;
+ return dev->address;
}
const char *
@@ -1888,14 +1948,18 @@ virPCIDeviceListDel(virPCIDeviceListPtr list,
int
virPCIDeviceListFindIndex(virPCIDeviceListPtr list, virPCIDevicePtr dev)
{
+ virPCIDeviceAddressPtr devAddr = dev->address;
+ virPCIDeviceAddressPtr tmpAddr;
size_t i;
- for (i = 0; i < list->count; i++)
- if (list->devs[i]->domain == dev->domain &&
- list->devs[i]->bus == dev->bus &&
- list->devs[i]->slot == dev->slot &&
- list->devs[i]->function == dev->function)
+ for (i = 0; i < list->count; i++) {
+ tmpAddr = list->devs[i]->address;
+ if (tmpAddr->domain == devAddr->domain &&
+ tmpAddr->bus == devAddr->bus &&
+ tmpAddr->slot == devAddr->slot &&
+ tmpAddr->function == devAddr->function)
return i;
+ }
return -1;
}
@@ -1907,13 +1971,16 @@ virPCIDeviceListFindByIDs(virPCIDeviceListPtr list,
unsigned int slot,
unsigned int function)
{
+ virPCIDeviceAddressPtr tmpAddr;
size_t 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)
+ tmpAddr = list->devs[i]->address;
+ if (tmpAddr &&
+ tmpAddr->domain == domain &&
+ tmpAddr->bus == bus &&
+ tmpAddr->slot == slot &&
+ tmpAddr->function == function)
return list->devs[i];
}
return NULL;
@@ -1942,9 +2009,11 @@ int virPCIDeviceFileIterate(virPCIDevicePtr dev,
int ret = -1;
struct dirent *ent;
int direrr;
+ virPCIDeviceAddressPtr devAddr = dev->address;
if (virAsprintf(&pcidir, "/sys/bus/pci/devices/%04x:%02x:%02x.%x",
- dev->domain, dev->bus, dev->slot, dev->function) <
0)
+ devAddr->domain, devAddr->bus,
+ devAddr->slot, devAddr->function) < 0)
goto cleanup;
if (!(dir = opendir(pcidir))) {
@@ -2074,13 +2143,12 @@ virPCIDeviceListPtr
virPCIDeviceGetIOMMUGroupList(virPCIDevicePtr dev)
{
virPCIDeviceListPtr groupList = virPCIDeviceListNew();
- virPCIDeviceAddress devAddr = { dev->domain, dev->bus,
- dev->slot, dev->function };
+ virPCIDeviceAddressPtr devAddr = dev->address;
if (!groupList)
goto error;
- if (virPCIDeviceAddressIOMMUGroupIterate(&devAddr,
+ if (virPCIDeviceAddressIOMMUGroupIterate(devAddr,
virPCIDeviceGetIOMMUGroupAddOne,
groupList) < 0)
goto error;
@@ -2286,6 +2354,7 @@ static int
virPCIDeviceIsBehindSwitchLackingACS(virPCIDevicePtr dev)
{
virPCIDevicePtr parent;
+ virPCIDeviceAddressPtr devAddr = dev->address;
if (virPCIDeviceGetParent(dev, &parent) < 0)
return -1;
@@ -2294,7 +2363,7 @@ virPCIDeviceIsBehindSwitchLackingACS(virPCIDevicePtr dev)
* into play since devices on the root bus can't P2P without going
* through the root IOMMU.
*/
- if (dev->bus == 0) {
+ if (devAddr->bus == 0) {
return 0;
} else {
virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -2664,12 +2733,13 @@ virPCIGetSysfsFile(char *virPCIDeviceName, char
**pci_sysfs_device_link)
}
int
-virPCIDeviceAddressGetSysfsFile(virPCIDeviceAddressPtr dev,
+virPCIDeviceAddressGetSysfsFile(virPCIDeviceAddressPtr addr,
char **pci_sysfs_device_link)
{
if (virAsprintf(pci_sysfs_device_link,
- PCI_SYSFS "devices/%04x:%02x:%02x.%x", dev->domain,
- dev->bus, dev->slot, dev->function) < 0)
+ PCI_SYSFS "devices/%04x:%02x:%02x.%x",
+ addr->domain, addr->bus,
+ addr->slot, addr->function) < 0)
return -1;
return 0;
}
diff --git a/src/util/virpci.h b/src/util/virpci.h
index 6516f05..a137a9a 100644
--- a/src/util/virpci.h
+++ b/src/util/virpci.h
@@ -69,6 +69,13 @@ struct _virPCIEDeviceInfo {
virPCIELink *link_sta; /* Actually negotiated capabilities */
};
+virPCIDeviceAddressPtr virPCIDeviceAddressNew(unsigned int domain,
+ unsigned int bus,
+ unsigned int slot,
+ unsigned int function);
+virPCIDeviceAddressPtr virPCIDeviceAddressCopy(virPCIDeviceAddressPtr addr);
+void virPCIDeviceAddressFree(virPCIDeviceAddressPtr addr);
+
virPCIDevicePtr virPCIDeviceNew(unsigned int domain,
unsigned int bus,
unsigned int slot,