This function iterates through all the devices in a domain to determine if the address it has been given is part of a "multifunction device" (i.e. multiple devices connected to different functions of the same slot).
This implementation may seem a bit inefficient because it has to iterate through all the devices for each device that needs checking, but this really is our only option since the address allocation set isn't always available (and maybe not even exist at the time it's needed). --- src/conf/domain_addr.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++ src/conf/domain_addr.h | 5 ++++ src/libvirt_private.syms | 1 + 3 files changed, 66 insertions(+) diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index 2ac740f..dcd384a 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -809,6 +809,66 @@ virDomainPCIAddressReserveNextSlot(virDomainPCIAddressSetPtr addrs, } +typedef struct { + virPCIDeviceAddressPtr addr; + bool isMulti; +} virDomainPCIAddressIsMultiIterData; + + +static int +virDomainPCIAddressIsMultiIter(virDomainDefPtr def ATTRIBUTE_UNUSED, + virDomainDeviceDefPtr dev ATTRIBUTE_UNUSED, + virDomainDeviceInfoPtr info, + void *data) +{ + virDomainPCIAddressIsMultiIterData *context = data; + virPCIDeviceAddressPtr testAddr = context->addr; + virPCIDeviceAddressPtr thisAddr; + + if (!info || info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) + return 0; + + thisAddr = &info->addr.pci; + + if (thisAddr->domain == testAddr->domain && + thisAddr->bus == testAddr->bus && + thisAddr->slot == testAddr->slot && + thisAddr->function != testAddr->function) { + context->isMulti = true; + return -1; /* finish early, *NOT* an error */ + } + + return 0; +} + + +/** + * virDomainPCIAddressIsMulti(): + * + * @def: the domain definition whose devices need adjusting + * @addr: the address to check + * + * See if there is any PCI device in the domain with the same + * domain/bus/slot but different function. If so, then this address is + * used by a multifunction device. + * + * Returns true if the address is being used by multiple devices, else + * false. + */ +bool +virDomainPCIAddressIsMulti(const virDomainDef *def, + virPCIDeviceAddressPtr addr) +{ + virDomainPCIAddressIsMultiIterData data = { .addr = addr, + .isMulti = false }; + + ignore_value(virDomainDeviceInfoIterate((virDomainDefPtr)def, + virDomainPCIAddressIsMultiIter, + &data)); + return data.isMulti; +} + + static char* virDomainCCWAddressAsString(virDomainDeviceCCWAddressPtr addr) { diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h index 0a571ca..1b36877 100644 --- a/src/conf/domain_addr.h +++ b/src/conf/domain_addr.h @@ -173,6 +173,11 @@ int virDomainPCIAddressReserveNextSlot(virDomainPCIAddressSetPtr addrs, virDomainPCIConnectFlags flags) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); +bool +virDomainPCIAddressIsMulti(const virDomainDef *def, + virPCIDeviceAddressPtr addr) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + struct _virDomainCCWAddressSet { virHashTablePtr defined; virDomainDeviceCCWAddress next; diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index b4210f4..104d43e 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -99,6 +99,7 @@ virDomainPCIAddressAsString; virDomainPCIAddressBusSetModel; virDomainPCIAddressEnsureAddr; virDomainPCIAddressFlagsCompatible; +virDomainPCIAddressIsMulti; virDomainPCIAddressReleaseSlot; virDomainPCIAddressReserveAddr; virDomainPCIAddressReserveNextAddr; -- 2.7.4 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list