This patch provides a caching mechanism for the device address
extensions uid and fid on S390. For efficient sparse address allocation,
we introduce two hash tables for uid/fid which hold the address set
information per domain. Also in order to improve performance of
searching available value, we introduce our own callbacks for the two
hashtables. In this way, uid/fid is saved in hash key and hash value
could be any non-NULL pointer due to no operation on hash value. That is
also the reason why we don't introduce hash value free callback.
Signed-off-by: Yi Min Zhao <zyimin(a)linux.ibm.com>
Reviewed-by: Boris Fiuczynski <fiuczy(a)linux.vnet.ibm.com>
Reviewed-by: Bjoern Walk <bwalk(a)linux.vnet.ibm.com>
---
src/conf/domain_addr.c | 79 ++++++++++++++++++++++++++++++++++++++++++
src/conf/domain_addr.h | 9 +++++
src/libvirt_private.syms | 1 +
src/qemu/qemu_domain_address.c | 5 +++
4 files changed, 94 insertions(+)
diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c
index 8964973e03..e2e799930f 100644
--- a/src/conf/domain_addr.c
+++ b/src/conf/domain_addr.c
@@ -27,11 +27,23 @@
#include "virlog.h"
#include "virstring.h"
#include "domain_addr.h"
+#include "virhashcode.h"
#define VIR_FROM_THIS VIR_FROM_DOMAIN
VIR_LOG_INIT("conf.domain_addr");
+static void
+virDomainPCIAddressSetExtensionFree(virDomainPCIAddressSetPtr addrs)
+{
+ if (!addrs || !addrs->zpciIds)
+ return;
+
+ virHashFree(addrs->zpciIds->uids);
+ virHashFree(addrs->zpciIds->fids);
+ VIR_FREE(addrs->zpciIds);
+}
+
virDomainPCIConnectFlags
virDomainPCIControllerModelToConnectType(virDomainControllerModelPCI model)
{
@@ -741,6 +753,72 @@ virDomainPCIAddressReleaseAddr(virDomainPCIAddressSetPtr addrs,
addrs->buses[addr->bus].slot[addr->slot].functions &= ~(1 <<
addr->function);
}
+
+static uint32_t virZPCIAddrCode(const void *name, uint32_t seed)
+{
+ unsigned int value = *((unsigned int *)name);
+ return virHashCodeGen(&value, sizeof(value), seed);
+}
+
+
+static bool virZPCIAddrEqual(const void *namea, const void *nameb)
+{
+ return *((unsigned int *)namea) == *((unsigned int *)nameb);
+}
+
+
+static void *virZPCIAddrCopy(const void *name)
+{
+ unsigned int *copy;
+
+ if (VIR_ALLOC(copy) < 0)
+ return NULL;
+
+ *copy = *((unsigned int *)name);
+ return (void *)copy;
+}
+
+
+static void virZPCIAddrKeyFree(void *name)
+{
+ VIR_FREE(name);
+}
+
+
+int
+virDomainPCIAddressSetExtensionAlloc(virDomainPCIAddressSetPtr addrs,
+ virDomainPCIAddressExtensionFlags extFlags)
+{
+ if (extFlags == VIR_PCI_ADDRESS_EXTENSION_ZPCI) {
+ if (addrs->zpciIds)
+ return 0;
+
+ if (VIR_ALLOC(addrs->zpciIds) < 0)
+ return -1;
+
+ if (!(addrs->zpciIds->uids = virHashCreateFull(10, NULL,
+ virZPCIAddrCode,
+ virZPCIAddrEqual,
+ virZPCIAddrCopy,
+ virZPCIAddrKeyFree)))
+ goto error;
+
+ if (!(addrs->zpciIds->fids = virHashCreateFull(10, NULL,
+ virZPCIAddrCode,
+ virZPCIAddrEqual,
+ virZPCIAddrCopy,
+ virZPCIAddrKeyFree)))
+ goto error;
+ }
+
+ return 0;
+
+ error:
+ virDomainPCIAddressSetExtensionFree(addrs);
+ return -1;
+}
+
+
virDomainPCIAddressSetPtr
virDomainPCIAddressSetAlloc(unsigned int nbuses)
{
@@ -767,6 +845,7 @@ virDomainPCIAddressSetFree(virDomainPCIAddressSetPtr addrs)
if (!addrs)
return;
+ virDomainPCIAddressSetExtensionFree(addrs);
VIR_FREE(addrs->buses);
VIR_FREE(addrs);
}
diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h
index 1d1837bd23..f95d56c0a0 100644
--- a/src/conf/domain_addr.h
+++ b/src/conf/domain_addr.h
@@ -116,6 +116,11 @@ typedef struct {
} virDomainPCIAddressBus;
typedef virDomainPCIAddressBus *virDomainPCIAddressBusPtr;
+typedef struct {
+ virHashTablePtr uids, fids;
+} virDomainZPCIAddressIds;
+typedef virDomainZPCIAddressIds *virDomainZPCIAddressIdsPtr;
+
struct _virDomainPCIAddressSet {
virDomainPCIAddressBus *buses;
size_t nbuses;
@@ -125,6 +130,7 @@ struct _virDomainPCIAddressSet {
bool areMultipleRootsSupported;
/* If true, the guest can use the pcie-to-pci-bridge controller */
bool isPCIeToPCIBridgeSupported;
+ virDomainZPCIAddressIdsPtr zpciIds;
};
typedef struct _virDomainPCIAddressSet virDomainPCIAddressSet;
typedef virDomainPCIAddressSet *virDomainPCIAddressSetPtr;
@@ -132,6 +138,9 @@ typedef virDomainPCIAddressSet *virDomainPCIAddressSetPtr;
char *virDomainPCIAddressAsString(virPCIDeviceAddressPtr addr)
ATTRIBUTE_NONNULL(1);
+int virDomainPCIAddressSetExtensionAlloc(virDomainPCIAddressSetPtr addrs,
+ virDomainPCIAddressExtensionFlags extFlags);
+
virDomainPCIAddressSetPtr virDomainPCIAddressSetAlloc(unsigned int nbuses);
void virDomainPCIAddressSetFree(virDomainPCIAddressSetPtr addrs);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 98913a577a..7a808331ef 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -120,6 +120,7 @@ virDomainPCIAddressReserveAddr;
virDomainPCIAddressReserveNextAddr;
virDomainPCIAddressSetAllMulti;
virDomainPCIAddressSetAlloc;
+virDomainPCIAddressSetExtensionAlloc;
virDomainPCIAddressSetFree;
virDomainPCIAddressSlotInUse;
virDomainPCIAddressValidate;
diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c
index f5cd485e3f..db23b4ef40 100644
--- a/src/qemu/qemu_domain_address.c
+++ b/src/qemu/qemu_domain_address.c
@@ -1499,6 +1499,11 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
addrs->dryRun = dryRun;
+ /* create zpci address set for s390 domain */
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_ZPCI) &&
+ virDomainPCIAddressSetExtensionAlloc(addrs, VIR_PCI_ADDRESS_EXTENSION_ZPCI))
+ goto error;
+
/* pSeries domains support multiple pci-root controllers */
if (qemuDomainIsPSeries(def))
addrs->areMultipleRootsSupported = true;
--
Yi Min