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 8cc30ee..b8a91d2 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -867,6 +867,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 9c08274..50c4675 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 4c0170c..0dd0af5 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@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list