c480ed
From 87e3a5f2f797c79516a560ddc224074c834ef528 Mon Sep 17 00:00:00 2001
c480ed
Message-Id: <87e3a5f2f797c79516a560ddc224074c834ef528@dist-git>
c480ed
From: Yi Min Zhao <zyimin@linux.ibm.com>
c480ed
Date: Mon, 8 Apr 2019 10:57:27 +0200
c480ed
Subject: [PATCH] conf: Allocate/release 'uid' and 'fid' in PCI address
c480ed
MIME-Version: 1.0
c480ed
Content-Type: text/plain; charset=UTF-8
c480ed
Content-Transfer-Encoding: 8bit
c480ed
c480ed
This patch adds new functions for reservation, assignment and release
c480ed
to handle the uid/fid. If the uid/fid is defined in the domain XML,
c480ed
they will be reserved directly in the collecting phase. If any of them
c480ed
is not defined, we will find out an available value for them from the
c480ed
zPCI address hashtable, and reserve them. For the hotplug case there
c480ed
might not be a zPCI definition. So allocate and reserve uid/fid the
c480ed
case. Assign if needed and reserve uid/fid for the defined case.
c480ed
c480ed
Signed-off-by: Yi Min Zhao <zyimin@linux.ibm.com>
c480ed
Reviewed-by: Bjoern Walk <bwalk@linux.ibm.com>
c480ed
Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
c480ed
Reviewed-by: Andrea Bolognani <abologna@redhat.com>
c480ed
c480ed
(cherry picked from commit f183b87fc1dbcc6446ac3c1cef9cdd345b9725fb)
c480ed
c480ed
https://bugzilla.redhat.com/show_bug.cgi?id=1508149
c480ed
c480ed
Conflicts:
c480ed
c480ed
  * src/libvirt_private.syms
c480ed
    + several symbols are not present in the list
c480ed
      - missing 9ad119f4db5, ab3f781a10c, edeef779585, b899726faa5
c480ed
c480ed
  * src/qemu/qemu_domain_address.c
c480ed
    + the old name for virDeviceInfoPCIAddressIsPresent() is used
c480ed
      - missing 76151a53a100
c480ed
c480ed
Signed-off-by: Andrea Bolognani <abologna@redhat.com>
c480ed
Message-Id: <20190408085732.28684-11-abologna@redhat.com>
c480ed
Reviewed-by: Laine Stump <laine@redhat.com>
c480ed
Reviewed-by: Ján Tomko <jtomko@redhat.com>
c480ed
---
c480ed
 src/conf/device_conf.c         |  16 +++
c480ed
 src/conf/device_conf.h         |   3 +
c480ed
 src/conf/domain_addr.c         | 244 +++++++++++++++++++++++++++++++++
c480ed
 src/conf/domain_addr.h         |  12 ++
c480ed
 src/libvirt_private.syms       |   5 +
c480ed
 src/qemu/qemu_domain_address.c |  59 +++++++-
c480ed
 6 files changed, 338 insertions(+), 1 deletion(-)
c480ed
c480ed
diff --git a/src/conf/device_conf.c b/src/conf/device_conf.c
c480ed
index cadac32603..76370d30a2 100644
c480ed
--- a/src/conf/device_conf.c
c480ed
+++ b/src/conf/device_conf.c
c480ed
@@ -28,6 +28,7 @@
c480ed
 #include "viruuid.h"
c480ed
 #include "virbuffer.h"
c480ed
 #include "device_conf.h"
c480ed
+#include "domain_addr.h"
c480ed
 #include "virstring.h"
c480ed
 
c480ed
 #define VIR_FROM_THIS VIR_FROM_DEVICE
c480ed
@@ -230,6 +231,21 @@ int virPCIDeviceAddressIsValid(virPCIDeviceAddressPtr addr,
c480ed
 }
c480ed
 
c480ed
 
c480ed
+bool
c480ed
+virDeviceInfoPCIAddressExtensionIsWanted(const virDomainDeviceInfo *info)
c480ed
+{
c480ed
+    return (info->addr.pci.extFlags & VIR_PCI_ADDRESS_EXTENSION_ZPCI) &&
c480ed
+           virZPCIDeviceAddressIsEmpty(&info->addr.pci.zpci);
c480ed
+}
c480ed
+
c480ed
+bool
c480ed
+virDeviceInfoPCIAddressExtensionIsPresent(const virDomainDeviceInfo *info)
c480ed
+{
c480ed
+    return (info->addr.pci.extFlags & VIR_PCI_ADDRESS_EXTENSION_ZPCI) &&
c480ed
+           !virZPCIDeviceAddressIsEmpty(&info->addr.pci.zpci);
c480ed
+}
c480ed
+
c480ed
+
c480ed
 int
c480ed
 virPCIDeviceAddressParseXML(xmlNodePtr node,
c480ed
                             virPCIDeviceAddressPtr addr)
c480ed
diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h
c480ed
index c79066ec02..6bef2f093a 100644
c480ed
--- a/src/conf/device_conf.h
c480ed
+++ b/src/conf/device_conf.h
c480ed
@@ -214,6 +214,9 @@ virDeviceInfoPCIAddressPresent(const virDomainDeviceInfo *info)
c480ed
        !virPCIDeviceAddressIsEmpty(&info->addr.pci);
c480ed
 }
c480ed
 
c480ed
+bool virDeviceInfoPCIAddressExtensionIsWanted(const virDomainDeviceInfo *info);
c480ed
+bool virDeviceInfoPCIAddressExtensionIsPresent(const virDomainDeviceInfo *info);
c480ed
+
c480ed
 int virPCIDeviceAddressParseXML(xmlNodePtr node,
c480ed
                                 virPCIDeviceAddressPtr addr);
c480ed
 
c480ed
diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c
c480ed
index 9e0a0fdf95..a58910c394 100644
c480ed
--- a/src/conf/domain_addr.c
c480ed
+++ b/src/conf/domain_addr.c
c480ed
@@ -33,6 +33,238 @@
c480ed
 
c480ed
 VIR_LOG_INIT("conf.domain_addr");
c480ed
 
c480ed
+static int
c480ed
+virDomainZPCIAddressReserveId(virHashTablePtr set,
c480ed
+                              unsigned int id,
c480ed
+                              const char *name)
c480ed
+{
c480ed
+    if (virHashLookup(set, &id)) {
c480ed
+        virReportError(VIR_ERR_INTERNAL_ERROR,
c480ed
+                       _("zPCI %s %o is already reserved"),
c480ed
+                       name, id);
c480ed
+        return -1;
c480ed
+    }
c480ed
+
c480ed
+    if (virHashAddEntry(set, &id, (void*)1) < 0) {
c480ed
+        virReportError(VIR_ERR_INTERNAL_ERROR,
c480ed
+                       _("Failed to reserve %s %o"),
c480ed
+                       name, id);
c480ed
+        return -1;
c480ed
+    }
c480ed
+
c480ed
+    return 0;
c480ed
+}
c480ed
+
c480ed
+
c480ed
+static int
c480ed
+virDomainZPCIAddressReserveUid(virHashTablePtr set,
c480ed
+                               virZPCIDeviceAddressPtr addr)
c480ed
+{
c480ed
+    return virDomainZPCIAddressReserveId(set, addr->uid, "uid");
c480ed
+}
c480ed
+
c480ed
+
c480ed
+static int
c480ed
+virDomainZPCIAddressReserveFid(virHashTablePtr set,
c480ed
+                               virZPCIDeviceAddressPtr addr)
c480ed
+{
c480ed
+    return virDomainZPCIAddressReserveId(set, addr->fid, "fid");
c480ed
+}
c480ed
+
c480ed
+
c480ed
+static int
c480ed
+virDomainZPCIAddressAssignId(virHashTablePtr set,
c480ed
+                             unsigned int *id,
c480ed
+                             unsigned int min,
c480ed
+                             unsigned int max,
c480ed
+                             const char *name)
c480ed
+{
c480ed
+    while (virHashLookup(set, &min)) {
c480ed
+        if (min == max) {
c480ed
+            virReportError(VIR_ERR_INTERNAL_ERROR,
c480ed
+                           _("There is no more free %s."),
c480ed
+                           name);
c480ed
+            return -1;
c480ed
+        }
c480ed
+        ++min;
c480ed
+    }
c480ed
+    *id = min;
c480ed
+
c480ed
+    return 0;
c480ed
+}
c480ed
+
c480ed
+
c480ed
+static int
c480ed
+virDomainZPCIAddressAssignUid(virHashTablePtr set,
c480ed
+                              virZPCIDeviceAddressPtr addr)
c480ed
+{
c480ed
+    return virDomainZPCIAddressAssignId(set, &addr->uid, 1,
c480ed
+                                        VIR_DOMAIN_DEVICE_ZPCI_MAX_UID, "uid");
c480ed
+}
c480ed
+
c480ed
+
c480ed
+static int
c480ed
+virDomainZPCIAddressAssignFid(virHashTablePtr set,
c480ed
+                              virZPCIDeviceAddressPtr addr)
c480ed
+{
c480ed
+    return virDomainZPCIAddressAssignId(set, &addr->fid, 0,
c480ed
+                                        VIR_DOMAIN_DEVICE_ZPCI_MAX_FID, "fid");
c480ed
+}
c480ed
+
c480ed
+
c480ed
+static void
c480ed
+virDomainZPCIAddressReleaseId(virHashTablePtr set,
c480ed
+                              unsigned int *id,
c480ed
+                              const char *name)
c480ed
+{
c480ed
+    if (virHashRemoveEntry(set, id) < 0) {
c480ed
+        virReportError(VIR_ERR_INTERNAL_ERROR,
c480ed
+                       _("Release %s %o failed"),
c480ed
+                       name, *id);
c480ed
+    }
c480ed
+
c480ed
+    *id = 0;
c480ed
+}
c480ed
+
c480ed
+
c480ed
+static void
c480ed
+virDomainZPCIAddressReleaseUid(virHashTablePtr set,
c480ed
+                               virZPCIDeviceAddressPtr addr)
c480ed
+{
c480ed
+    virDomainZPCIAddressReleaseId(set, &addr->uid, "uid");
c480ed
+}
c480ed
+
c480ed
+
c480ed
+static void
c480ed
+virDomainZPCIAddressReleaseFid(virHashTablePtr set,
c480ed
+                               virZPCIDeviceAddressPtr addr)
c480ed
+{
c480ed
+    virDomainZPCIAddressReleaseId(set, &addr->fid, "fid");
c480ed
+}
c480ed
+
c480ed
+
c480ed
+static void
c480ed
+virDomainZPCIAddressReleaseIds(virDomainZPCIAddressIdsPtr zpciIds,
c480ed
+                               virZPCIDeviceAddressPtr addr)
c480ed
+{
c480ed
+    if (!zpciIds || virZPCIDeviceAddressIsEmpty(addr))
c480ed
+        return;
c480ed
+
c480ed
+    virDomainZPCIAddressReleaseUid(zpciIds->uids, addr);
c480ed
+
c480ed
+    virDomainZPCIAddressReleaseFid(zpciIds->fids, addr);
c480ed
+}
c480ed
+
c480ed
+
c480ed
+static int
c480ed
+virDomainZPCIAddressReserveNextUid(virHashTablePtr uids,
c480ed
+                                   virZPCIDeviceAddressPtr zpci)
c480ed
+{
c480ed
+    if (virDomainZPCIAddressAssignUid(uids, zpci) < 0)
c480ed
+        return -1;
c480ed
+
c480ed
+    if (virDomainZPCIAddressReserveUid(uids, zpci) < 0)
c480ed
+        return -1;
c480ed
+
c480ed
+    return 0;
c480ed
+}
c480ed
+
c480ed
+
c480ed
+static int
c480ed
+virDomainZPCIAddressReserveNextFid(virHashTablePtr fids,
c480ed
+                                   virZPCIDeviceAddressPtr zpci)
c480ed
+{
c480ed
+    if (virDomainZPCIAddressAssignFid(fids, zpci) < 0)
c480ed
+        return -1;
c480ed
+
c480ed
+    if (virDomainZPCIAddressReserveFid(fids, zpci) < 0)
c480ed
+        return -1;
c480ed
+
c480ed
+    return 0;
c480ed
+}
c480ed
+
c480ed
+
c480ed
+static int
c480ed
+virDomainZPCIAddressReserveAddr(virDomainZPCIAddressIdsPtr zpciIds,
c480ed
+                                virZPCIDeviceAddressPtr addr)
c480ed
+{
c480ed
+    if (virDomainZPCIAddressReserveUid(zpciIds->uids, addr) < 0)
c480ed
+        return -1;
c480ed
+
c480ed
+    if (virDomainZPCIAddressReserveFid(zpciIds->fids, addr) < 0) {
c480ed
+        virDomainZPCIAddressReleaseUid(zpciIds->uids, addr);
c480ed
+        return -1;
c480ed
+    }
c480ed
+
c480ed
+    return 0;
c480ed
+}
c480ed
+
c480ed
+
c480ed
+static int
c480ed
+virDomainZPCIAddressReserveNextAddr(virDomainZPCIAddressIdsPtr zpciIds,
c480ed
+                                    virZPCIDeviceAddressPtr addr)
c480ed
+{
c480ed
+    if (virDomainZPCIAddressReserveNextUid(zpciIds->uids, addr) < 0)
c480ed
+        return -1;
c480ed
+
c480ed
+    if (virDomainZPCIAddressReserveNextFid(zpciIds->fids, addr) < 0) {
c480ed
+        virDomainZPCIAddressReleaseUid(zpciIds->uids, addr);
c480ed
+        return -1;
c480ed
+    }
c480ed
+
c480ed
+    return 0;
c480ed
+}
c480ed
+
c480ed
+
c480ed
+int
c480ed
+virDomainPCIAddressExtensionReserveAddr(virDomainPCIAddressSetPtr addrs,
c480ed
+                                        virPCIDeviceAddressPtr addr)
c480ed
+{
c480ed
+    if (addr->extFlags & VIR_PCI_ADDRESS_EXTENSION_ZPCI) {
c480ed
+        /* Reserve uid/fid to ZPCI device which has defined uid/fid
c480ed
+         * in the domain.
c480ed
+         */
c480ed
+        return virDomainZPCIAddressReserveAddr(addrs->zpciIds, &addr->zpci);
c480ed
+    }
c480ed
+
c480ed
+    return 0;
c480ed
+}
c480ed
+
c480ed
+
c480ed
+int
c480ed
+virDomainPCIAddressExtensionReserveNextAddr(virDomainPCIAddressSetPtr addrs,
c480ed
+                                            virPCIDeviceAddressPtr addr)
c480ed
+{
c480ed
+    if (addr->extFlags & VIR_PCI_ADDRESS_EXTENSION_ZPCI) {
c480ed
+        virZPCIDeviceAddress zpci = { 0 };
c480ed
+
c480ed
+        if (virDomainZPCIAddressReserveNextAddr(addrs->zpciIds, &zpci) < 0)
c480ed
+            return -1;
c480ed
+
c480ed
+        if (!addrs->dryRun)
c480ed
+            addr->zpci = zpci;
c480ed
+    }
c480ed
+
c480ed
+    return 0;
c480ed
+}
c480ed
+
c480ed
+static int
c480ed
+virDomainPCIAddressExtensionEnsureAddr(virDomainPCIAddressSetPtr addrs,
c480ed
+                                       virPCIDeviceAddressPtr addr)
c480ed
+{
c480ed
+    if (addr->extFlags & VIR_PCI_ADDRESS_EXTENSION_ZPCI) {
c480ed
+        virZPCIDeviceAddressPtr zpci = &addr->zpci;
c480ed
+
c480ed
+        if (virZPCIDeviceAddressIsEmpty(zpci))
c480ed
+            return virDomainZPCIAddressReserveNextAddr(addrs->zpciIds, zpci);
c480ed
+        else
c480ed
+            return virDomainZPCIAddressReserveAddr(addrs->zpciIds, zpci);
c480ed
+    }
c480ed
+
c480ed
+    return 0;
c480ed
+}
c480ed
+
c480ed
+
c480ed
 virDomainPCIConnectFlags
c480ed
 virDomainPCIControllerModelToConnectType(virDomainControllerModelPCI model)
c480ed
 {
c480ed
@@ -729,12 +961,24 @@ virDomainPCIAddressEnsureAddr(virDomainPCIAddressSetPtr addrs,
c480ed
         ret = virDomainPCIAddressReserveNextAddr(addrs, dev, flags, -1);
c480ed
     }
c480ed
 
c480ed
+    dev->addr.pci.extFlags = dev->pciAddrExtFlags;
c480ed
+    ret = virDomainPCIAddressExtensionEnsureAddr(addrs, &dev->addr.pci);
c480ed
+
c480ed
  cleanup:
c480ed
     VIR_FREE(addrStr);
c480ed
     return ret;
c480ed
 }
c480ed
 
c480ed
 
c480ed
+void
c480ed
+virDomainPCIAddressExtensionReleaseAddr(virDomainPCIAddressSetPtr addrs,
c480ed
+                                        virPCIDeviceAddressPtr addr)
c480ed
+{
c480ed
+    if (addr->extFlags & VIR_PCI_ADDRESS_EXTENSION_ZPCI)
c480ed
+        virDomainZPCIAddressReleaseIds(addrs->zpciIds, &addr->zpci);
c480ed
+}
c480ed
+
c480ed
+
c480ed
 void
c480ed
 virDomainPCIAddressReleaseAddr(virDomainPCIAddressSetPtr addrs,
c480ed
                                virPCIDeviceAddressPtr addr)
c480ed
diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h
c480ed
index b01e6b9d20..e5ce4868d5 100644
c480ed
--- a/src/conf/domain_addr.h
c480ed
+++ b/src/conf/domain_addr.h
c480ed
@@ -166,6 +166,14 @@ bool virDomainPCIAddressSlotInUse(virDomainPCIAddressSetPtr addrs,
c480ed
                                   virPCIDeviceAddressPtr addr)
c480ed
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
c480ed
 
c480ed
+int virDomainPCIAddressExtensionReserveAddr(virDomainPCIAddressSetPtr addrs,
c480ed
+                                            virPCIDeviceAddressPtr addr)
c480ed
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
c480ed
+
c480ed
+int virDomainPCIAddressExtensionReserveNextAddr(virDomainPCIAddressSetPtr addrs,
c480ed
+                                                virPCIDeviceAddressPtr addr)
c480ed
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
c480ed
+
c480ed
 int virDomainPCIAddressReserveAddr(virDomainPCIAddressSetPtr addrs,
c480ed
                                    virPCIDeviceAddressPtr addr,
c480ed
                                    virDomainPCIConnectFlags flags,
c480ed
@@ -187,6 +195,10 @@ void virDomainPCIAddressReleaseAddr(virDomainPCIAddressSetPtr addrs,
c480ed
                                     virPCIDeviceAddressPtr addr)
c480ed
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
c480ed
 
c480ed
+void virDomainPCIAddressExtensionReleaseAddr(virDomainPCIAddressSetPtr addrs,
c480ed
+                                             virPCIDeviceAddressPtr addr)
c480ed
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
c480ed
+
c480ed
 void virDomainPCIAddressSetAllMulti(virDomainDefPtr def)
c480ed
     ATTRIBUTE_NONNULL(1);
c480ed
 
c480ed
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
c480ed
index b2a2a1f265..ee7625b0f3 100644
c480ed
--- a/src/libvirt_private.syms
c480ed
+++ b/src/libvirt_private.syms
c480ed
@@ -93,6 +93,8 @@ virCPUModeTypeToString;
c480ed
 
c480ed
 
c480ed
 # conf/device_conf.h
c480ed
+virDeviceInfoPCIAddressExtensionIsPresent;
c480ed
+virDeviceInfoPCIAddressExtensionIsWanted;
c480ed
 virDomainDeviceInfoAddressIsEqual;
c480ed
 virDomainDeviceInfoCopy;
c480ed
 virInterfaceLinkFormat;
c480ed
@@ -114,6 +116,9 @@ virDomainPCIAddressAsString;
c480ed
 virDomainPCIAddressBusIsFullyReserved;
c480ed
 virDomainPCIAddressBusSetModel;
c480ed
 virDomainPCIAddressEnsureAddr;
c480ed
+virDomainPCIAddressExtensionReleaseAddr;
c480ed
+virDomainPCIAddressExtensionReserveAddr;
c480ed
+virDomainPCIAddressExtensionReserveNextAddr;
c480ed
 virDomainPCIAddressReleaseAddr;
c480ed
 virDomainPCIAddressReserveAddr;
c480ed
 virDomainPCIAddressReserveNextAddr;
c480ed
diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c
c480ed
index ba870d56b1..8338241cba 100644
c480ed
--- a/src/qemu/qemu_domain_address.c
c480ed
+++ b/src/qemu/qemu_domain_address.c
c480ed
@@ -1405,6 +1405,24 @@ qemuDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs,
c480ed
 }
c480ed
 
c480ed
 
c480ed
+static int
c480ed
+qemuDomainAssignPCIAddressExtension(virDomainDefPtr def ATTRIBUTE_UNUSED,
c480ed
+                                    virDomainDeviceDefPtr device ATTRIBUTE_UNUSED,
c480ed
+                                    virDomainDeviceInfoPtr info,
c480ed
+                                    void *opaque)
c480ed
+{
c480ed
+    virDomainPCIAddressSetPtr addrs = opaque;
c480ed
+    virPCIDeviceAddressPtr addr = &info->addr.pci;
c480ed
+
c480ed
+    if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)
c480ed
+        addr->extFlags = info->pciAddrExtFlags;
c480ed
+
c480ed
+    if (virDeviceInfoPCIAddressExtensionIsWanted(info))
c480ed
+        return virDomainPCIAddressExtensionReserveNextAddr(addrs, addr);
c480ed
+
c480ed
+    return 0;
c480ed
+}
c480ed
+
c480ed
 static int
c480ed
 qemuDomainCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
c480ed
                             virDomainDeviceDefPtr device,
c480ed
@@ -1498,6 +1516,31 @@ qemuDomainCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
c480ed
     return ret;
c480ed
 }
c480ed
 
c480ed
+static int
c480ed
+qemuDomainCollectPCIAddressExtension(virDomainDefPtr def ATTRIBUTE_UNUSED,
c480ed
+                                     virDomainDeviceDefPtr device,
c480ed
+                                     virDomainDeviceInfoPtr info,
c480ed
+                                     void *opaque)
c480ed
+{
c480ed
+    virDomainPCIAddressSetPtr addrs = opaque;
c480ed
+    virPCIDeviceAddressPtr addr = &info->addr.pci;
c480ed
+
c480ed
+    if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)
c480ed
+        addr->extFlags = info->pciAddrExtFlags;
c480ed
+
c480ed
+    if (!virDeviceInfoPCIAddressExtensionIsPresent(info) ||
c480ed
+        ((device->type == VIR_DOMAIN_DEVICE_HOSTDEV) &&
c480ed
+         (device->data.hostdev->parent.type != VIR_DOMAIN_DEVICE_NONE))) {
c480ed
+        /* If a hostdev has a parent, its info will be a part of the
c480ed
+         * parent, and will have its address collected during the scan
c480ed
+         * of the parent's device type.
c480ed
+        */
c480ed
+        return 0;
c480ed
+    }
c480ed
+
c480ed
+    return virDomainPCIAddressExtensionReserveAddr(addrs, addr);
c480ed
+}
c480ed
+
c480ed
 static virDomainPCIAddressSetPtr
c480ed
 qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
c480ed
                               virQEMUCapsPtr qemuCaps,
c480ed
@@ -1589,6 +1632,12 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
c480ed
     if (virDomainDeviceInfoIterate(def, qemuDomainCollectPCIAddress, addrs) < 0)
c480ed
         goto error;
c480ed
 
c480ed
+    if (virDomainDeviceInfoIterate(def,
c480ed
+                                   qemuDomainCollectPCIAddressExtension,
c480ed
+                                   addrs) < 0) {
c480ed
+        goto error;
c480ed
+    }
c480ed
+
c480ed
     return addrs;
c480ed
 
c480ed
  error:
c480ed
@@ -2590,6 +2639,9 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
c480ed
         if (qemuDomainAssignDevicePCISlots(def, qemuCaps, addrs) < 0)
c480ed
             goto cleanup;
c480ed
 
c480ed
+        if (virDomainDeviceInfoIterate(def, qemuDomainAssignPCIAddressExtension, addrs) < 0)
c480ed
+            goto cleanup;
c480ed
+
c480ed
         /* Only for *new* domains with pcie-root (and no other
c480ed
          * manually specified PCI controllers in the definition): If,
c480ed
          * after assigning addresses/reserving slots for all devices,
c480ed
@@ -2684,6 +2736,9 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
c480ed
         if (qemuDomainAssignDevicePCISlots(def, qemuCaps, addrs) < 0)
c480ed
             goto cleanup;
c480ed
 
c480ed
+        if (virDomainDeviceInfoIterate(def, qemuDomainAssignPCIAddressExtension, addrs) < 0)
c480ed
+            goto cleanup;
c480ed
+
c480ed
         /* set multi attribute for devices at function 0 of
c480ed
          * any slot that has multiple functions in use
c480ed
          */
c480ed
@@ -3143,8 +3198,10 @@ qemuDomainReleaseDeviceAddress(virDomainObjPtr vm,
c480ed
     if (!devstr)
c480ed
         devstr = info->alias;
c480ed
 
c480ed
-    if (virDeviceInfoPCIAddressPresent(info))
c480ed
+    if (virDeviceInfoPCIAddressPresent(info)) {
c480ed
         virDomainPCIAddressReleaseAddr(priv->pciaddrs, &info->addr.pci);
c480ed
+        virDomainPCIAddressExtensionReleaseAddr(priv->pciaddrs, &info->addr.pci);
c480ed
+    }
c480ed
 
c480ed
     if (virDomainUSBAddressRelease(priv->usbaddrs, info) < 0)
c480ed
         VIR_WARN("Unable to release USB address on %s", NULLSTR(devstr));
c480ed
-- 
c480ed
2.22.0
c480ed