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 29d06f1..986d90e 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 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 74dd527..60fb760 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