Blob Blame History Raw
From 87e3a5f2f797c79516a560ddc224074c834ef528 Mon Sep 17 00:00:00 2001
Message-Id: <87e3a5f2f797c79516a560ddc224074c834ef528@dist-git>
From: Yi Min Zhao <zyimin@linux.ibm.com>
Date: Mon, 8 Apr 2019 10:57:27 +0200
Subject: [PATCH] conf: Allocate/release 'uid' and 'fid' in PCI address
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This patch adds new functions for reservation, assignment and release
to handle the uid/fid. If the uid/fid is defined in the domain XML,
they will be reserved directly in the collecting phase. If any of them
is not defined, we will find out an available value for them from the
zPCI address hashtable, and reserve them. For the hotplug case there
might not be a zPCI definition. So allocate and reserve uid/fid the
case. Assign if needed and reserve uid/fid for the defined case.

Signed-off-by: Yi Min Zhao <zyimin@linux.ibm.com>
Reviewed-by: Bjoern Walk <bwalk@linux.ibm.com>
Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Reviewed-by: Andrea Bolognani <abologna@redhat.com>

(cherry picked from commit f183b87fc1dbcc6446ac3c1cef9cdd345b9725fb)

https://bugzilla.redhat.com/show_bug.cgi?id=1508149

Conflicts:

  * src/libvirt_private.syms
    + several symbols are not present in the list
      - missing 9ad119f4db5, ab3f781a10c, edeef779585, b899726faa5

  * src/qemu/qemu_domain_address.c
    + the old name for virDeviceInfoPCIAddressIsPresent() is used
      - missing 76151a53a100

Signed-off-by: Andrea Bolognani <abologna@redhat.com>
Message-Id: <20190408085732.28684-11-abologna@redhat.com>
Reviewed-by: Laine Stump <laine@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
---
 src/conf/device_conf.c         |  16 +++
 src/conf/device_conf.h         |   3 +
 src/conf/domain_addr.c         | 244 +++++++++++++++++++++++++++++++++
 src/conf/domain_addr.h         |  12 ++
 src/libvirt_private.syms       |   5 +
 src/qemu/qemu_domain_address.c |  59 +++++++-
 6 files changed, 338 insertions(+), 1 deletion(-)

diff --git a/src/conf/device_conf.c b/src/conf/device_conf.c
index cadac32603..76370d30a2 100644
--- a/src/conf/device_conf.c
+++ b/src/conf/device_conf.c
@@ -28,6 +28,7 @@
 #include "viruuid.h"
 #include "virbuffer.h"
 #include "device_conf.h"
+#include "domain_addr.h"
 #include "virstring.h"
 
 #define VIR_FROM_THIS VIR_FROM_DEVICE
@@ -230,6 +231,21 @@ int virPCIDeviceAddressIsValid(virPCIDeviceAddressPtr addr,
 }
 
 
+bool
+virDeviceInfoPCIAddressExtensionIsWanted(const virDomainDeviceInfo *info)
+{
+    return (info->addr.pci.extFlags & VIR_PCI_ADDRESS_EXTENSION_ZPCI) &&
+           virZPCIDeviceAddressIsEmpty(&info->addr.pci.zpci);
+}
+
+bool
+virDeviceInfoPCIAddressExtensionIsPresent(const virDomainDeviceInfo *info)
+{
+    return (info->addr.pci.extFlags & VIR_PCI_ADDRESS_EXTENSION_ZPCI) &&
+           !virZPCIDeviceAddressIsEmpty(&info->addr.pci.zpci);
+}
+
+
 int
 virPCIDeviceAddressParseXML(xmlNodePtr node,
                             virPCIDeviceAddressPtr addr)
diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h
index c79066ec02..6bef2f093a 100644
--- a/src/conf/device_conf.h
+++ b/src/conf/device_conf.h
@@ -214,6 +214,9 @@ virDeviceInfoPCIAddressPresent(const virDomainDeviceInfo *info)
        !virPCIDeviceAddressIsEmpty(&info->addr.pci);
 }
 
+bool virDeviceInfoPCIAddressExtensionIsWanted(const virDomainDeviceInfo *info);
+bool virDeviceInfoPCIAddressExtensionIsPresent(const virDomainDeviceInfo *info);
+
 int virPCIDeviceAddressParseXML(xmlNodePtr node,
                                 virPCIDeviceAddressPtr addr);
 
diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c
index 9e0a0fdf95..a58910c394 100644
--- a/src/conf/domain_addr.c
+++ b/src/conf/domain_addr.c
@@ -33,6 +33,238 @@
 
 VIR_LOG_INIT("conf.domain_addr");
 
+static int
+virDomainZPCIAddressReserveId(virHashTablePtr set,
+                              unsigned int id,
+                              const char *name)
+{
+    if (virHashLookup(set, &id)) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("zPCI %s %o is already reserved"),
+                       name, id);
+        return -1;
+    }
+
+    if (virHashAddEntry(set, &id, (void*)1) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Failed to reserve %s %o"),
+                       name, id);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+static int
+virDomainZPCIAddressReserveUid(virHashTablePtr set,
+                               virZPCIDeviceAddressPtr addr)
+{
+    return virDomainZPCIAddressReserveId(set, addr->uid, "uid");
+}
+
+
+static int
+virDomainZPCIAddressReserveFid(virHashTablePtr set,
+                               virZPCIDeviceAddressPtr addr)
+{
+    return virDomainZPCIAddressReserveId(set, addr->fid, "fid");
+}
+
+
+static int
+virDomainZPCIAddressAssignId(virHashTablePtr set,
+                             unsigned int *id,
+                             unsigned int min,
+                             unsigned int max,
+                             const char *name)
+{
+    while (virHashLookup(set, &min)) {
+        if (min == max) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("There is no more free %s."),
+                           name);
+            return -1;
+        }
+        ++min;
+    }
+    *id = min;
+
+    return 0;
+}
+
+
+static int
+virDomainZPCIAddressAssignUid(virHashTablePtr set,
+                              virZPCIDeviceAddressPtr addr)
+{
+    return virDomainZPCIAddressAssignId(set, &addr->uid, 1,
+                                        VIR_DOMAIN_DEVICE_ZPCI_MAX_UID, "uid");
+}
+
+
+static int
+virDomainZPCIAddressAssignFid(virHashTablePtr set,
+                              virZPCIDeviceAddressPtr addr)
+{
+    return virDomainZPCIAddressAssignId(set, &addr->fid, 0,
+                                        VIR_DOMAIN_DEVICE_ZPCI_MAX_FID, "fid");
+}
+
+
+static void
+virDomainZPCIAddressReleaseId(virHashTablePtr set,
+                              unsigned int *id,
+                              const char *name)
+{
+    if (virHashRemoveEntry(set, id) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Release %s %o failed"),
+                       name, *id);
+    }
+
+    *id = 0;
+}
+
+
+static void
+virDomainZPCIAddressReleaseUid(virHashTablePtr set,
+                               virZPCIDeviceAddressPtr addr)
+{
+    virDomainZPCIAddressReleaseId(set, &addr->uid, "uid");
+}
+
+
+static void
+virDomainZPCIAddressReleaseFid(virHashTablePtr set,
+                               virZPCIDeviceAddressPtr addr)
+{
+    virDomainZPCIAddressReleaseId(set, &addr->fid, "fid");
+}
+
+
+static void
+virDomainZPCIAddressReleaseIds(virDomainZPCIAddressIdsPtr zpciIds,
+                               virZPCIDeviceAddressPtr addr)
+{
+    if (!zpciIds || virZPCIDeviceAddressIsEmpty(addr))
+        return;
+
+    virDomainZPCIAddressReleaseUid(zpciIds->uids, addr);
+
+    virDomainZPCIAddressReleaseFid(zpciIds->fids, addr);
+}
+
+
+static int
+virDomainZPCIAddressReserveNextUid(virHashTablePtr uids,
+                                   virZPCIDeviceAddressPtr zpci)
+{
+    if (virDomainZPCIAddressAssignUid(uids, zpci) < 0)
+        return -1;
+
+    if (virDomainZPCIAddressReserveUid(uids, zpci) < 0)
+        return -1;
+
+    return 0;
+}
+
+
+static int
+virDomainZPCIAddressReserveNextFid(virHashTablePtr fids,
+                                   virZPCIDeviceAddressPtr zpci)
+{
+    if (virDomainZPCIAddressAssignFid(fids, zpci) < 0)
+        return -1;
+
+    if (virDomainZPCIAddressReserveFid(fids, zpci) < 0)
+        return -1;
+
+    return 0;
+}
+
+
+static int
+virDomainZPCIAddressReserveAddr(virDomainZPCIAddressIdsPtr zpciIds,
+                                virZPCIDeviceAddressPtr addr)
+{
+    if (virDomainZPCIAddressReserveUid(zpciIds->uids, addr) < 0)
+        return -1;
+
+    if (virDomainZPCIAddressReserveFid(zpciIds->fids, addr) < 0) {
+        virDomainZPCIAddressReleaseUid(zpciIds->uids, addr);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+static int
+virDomainZPCIAddressReserveNextAddr(virDomainZPCIAddressIdsPtr zpciIds,
+                                    virZPCIDeviceAddressPtr addr)
+{
+    if (virDomainZPCIAddressReserveNextUid(zpciIds->uids, addr) < 0)
+        return -1;
+
+    if (virDomainZPCIAddressReserveNextFid(zpciIds->fids, addr) < 0) {
+        virDomainZPCIAddressReleaseUid(zpciIds->uids, addr);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+int
+virDomainPCIAddressExtensionReserveAddr(virDomainPCIAddressSetPtr addrs,
+                                        virPCIDeviceAddressPtr addr)
+{
+    if (addr->extFlags & VIR_PCI_ADDRESS_EXTENSION_ZPCI) {
+        /* Reserve uid/fid to ZPCI device which has defined uid/fid
+         * in the domain.
+         */
+        return virDomainZPCIAddressReserveAddr(addrs->zpciIds, &addr->zpci);
+    }
+
+    return 0;
+}
+
+
+int
+virDomainPCIAddressExtensionReserveNextAddr(virDomainPCIAddressSetPtr addrs,
+                                            virPCIDeviceAddressPtr addr)
+{
+    if (addr->extFlags & VIR_PCI_ADDRESS_EXTENSION_ZPCI) {
+        virZPCIDeviceAddress zpci = { 0 };
+
+        if (virDomainZPCIAddressReserveNextAddr(addrs->zpciIds, &zpci) < 0)
+            return -1;
+
+        if (!addrs->dryRun)
+            addr->zpci = zpci;
+    }
+
+    return 0;
+}
+
+static int
+virDomainPCIAddressExtensionEnsureAddr(virDomainPCIAddressSetPtr addrs,
+                                       virPCIDeviceAddressPtr addr)
+{
+    if (addr->extFlags & VIR_PCI_ADDRESS_EXTENSION_ZPCI) {
+        virZPCIDeviceAddressPtr zpci = &addr->zpci;
+
+        if (virZPCIDeviceAddressIsEmpty(zpci))
+            return virDomainZPCIAddressReserveNextAddr(addrs->zpciIds, zpci);
+        else
+            return virDomainZPCIAddressReserveAddr(addrs->zpciIds, zpci);
+    }
+
+    return 0;
+}
+
+
 virDomainPCIConnectFlags
 virDomainPCIControllerModelToConnectType(virDomainControllerModelPCI model)
 {
@@ -729,12 +961,24 @@ virDomainPCIAddressEnsureAddr(virDomainPCIAddressSetPtr addrs,
         ret = virDomainPCIAddressReserveNextAddr(addrs, dev, flags, -1);
     }
 
+    dev->addr.pci.extFlags = dev->pciAddrExtFlags;
+    ret = virDomainPCIAddressExtensionEnsureAddr(addrs, &dev->addr.pci);
+
  cleanup:
     VIR_FREE(addrStr);
     return ret;
 }
 
 
+void
+virDomainPCIAddressExtensionReleaseAddr(virDomainPCIAddressSetPtr addrs,
+                                        virPCIDeviceAddressPtr addr)
+{
+    if (addr->extFlags & VIR_PCI_ADDRESS_EXTENSION_ZPCI)
+        virDomainZPCIAddressReleaseIds(addrs->zpciIds, &addr->zpci);
+}
+
+
 void
 virDomainPCIAddressReleaseAddr(virDomainPCIAddressSetPtr addrs,
                                virPCIDeviceAddressPtr addr)
diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h
index b01e6b9d20..e5ce4868d5 100644
--- a/src/conf/domain_addr.h
+++ b/src/conf/domain_addr.h
@@ -166,6 +166,14 @@ bool virDomainPCIAddressSlotInUse(virDomainPCIAddressSetPtr addrs,
                                   virPCIDeviceAddressPtr addr)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
 
+int virDomainPCIAddressExtensionReserveAddr(virDomainPCIAddressSetPtr addrs,
+                                            virPCIDeviceAddressPtr addr)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+
+int virDomainPCIAddressExtensionReserveNextAddr(virDomainPCIAddressSetPtr addrs,
+                                                virPCIDeviceAddressPtr addr)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+
 int virDomainPCIAddressReserveAddr(virDomainPCIAddressSetPtr addrs,
                                    virPCIDeviceAddressPtr addr,
                                    virDomainPCIConnectFlags flags,
@@ -187,6 +195,10 @@ void virDomainPCIAddressReleaseAddr(virDomainPCIAddressSetPtr addrs,
                                     virPCIDeviceAddressPtr addr)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
 
+void virDomainPCIAddressExtensionReleaseAddr(virDomainPCIAddressSetPtr addrs,
+                                             virPCIDeviceAddressPtr addr)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+
 void virDomainPCIAddressSetAllMulti(virDomainDefPtr def)
     ATTRIBUTE_NONNULL(1);
 
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index b2a2a1f265..ee7625b0f3 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -93,6 +93,8 @@ virCPUModeTypeToString;
 
 
 # conf/device_conf.h
+virDeviceInfoPCIAddressExtensionIsPresent;
+virDeviceInfoPCIAddressExtensionIsWanted;
 virDomainDeviceInfoAddressIsEqual;
 virDomainDeviceInfoCopy;
 virInterfaceLinkFormat;
@@ -114,6 +116,9 @@ virDomainPCIAddressAsString;
 virDomainPCIAddressBusIsFullyReserved;
 virDomainPCIAddressBusSetModel;
 virDomainPCIAddressEnsureAddr;
+virDomainPCIAddressExtensionReleaseAddr;
+virDomainPCIAddressExtensionReserveAddr;
+virDomainPCIAddressExtensionReserveNextAddr;
 virDomainPCIAddressReleaseAddr;
 virDomainPCIAddressReserveAddr;
 virDomainPCIAddressReserveNextAddr;
diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c
index ba870d56b1..8338241cba 100644
--- a/src/qemu/qemu_domain_address.c
+++ b/src/qemu/qemu_domain_address.c
@@ -1405,6 +1405,24 @@ qemuDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs,
 }
 
 
+static int
+qemuDomainAssignPCIAddressExtension(virDomainDefPtr def ATTRIBUTE_UNUSED,
+                                    virDomainDeviceDefPtr device ATTRIBUTE_UNUSED,
+                                    virDomainDeviceInfoPtr info,
+                                    void *opaque)
+{
+    virDomainPCIAddressSetPtr addrs = opaque;
+    virPCIDeviceAddressPtr addr = &info->addr.pci;
+
+    if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)
+        addr->extFlags = info->pciAddrExtFlags;
+
+    if (virDeviceInfoPCIAddressExtensionIsWanted(info))
+        return virDomainPCIAddressExtensionReserveNextAddr(addrs, addr);
+
+    return 0;
+}
+
 static int
 qemuDomainCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
                             virDomainDeviceDefPtr device,
@@ -1498,6 +1516,31 @@ qemuDomainCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
     return ret;
 }
 
+static int
+qemuDomainCollectPCIAddressExtension(virDomainDefPtr def ATTRIBUTE_UNUSED,
+                                     virDomainDeviceDefPtr device,
+                                     virDomainDeviceInfoPtr info,
+                                     void *opaque)
+{
+    virDomainPCIAddressSetPtr addrs = opaque;
+    virPCIDeviceAddressPtr addr = &info->addr.pci;
+
+    if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)
+        addr->extFlags = info->pciAddrExtFlags;
+
+    if (!virDeviceInfoPCIAddressExtensionIsPresent(info) ||
+        ((device->type == VIR_DOMAIN_DEVICE_HOSTDEV) &&
+         (device->data.hostdev->parent.type != VIR_DOMAIN_DEVICE_NONE))) {
+        /* If a hostdev has a parent, its info will be a part of the
+         * parent, and will have its address collected during the scan
+         * of the parent's device type.
+        */
+        return 0;
+    }
+
+    return virDomainPCIAddressExtensionReserveAddr(addrs, addr);
+}
+
 static virDomainPCIAddressSetPtr
 qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
                               virQEMUCapsPtr qemuCaps,
@@ -1589,6 +1632,12 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
     if (virDomainDeviceInfoIterate(def, qemuDomainCollectPCIAddress, addrs) < 0)
         goto error;
 
+    if (virDomainDeviceInfoIterate(def,
+                                   qemuDomainCollectPCIAddressExtension,
+                                   addrs) < 0) {
+        goto error;
+    }
+
     return addrs;
 
  error:
@@ -2590,6 +2639,9 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
         if (qemuDomainAssignDevicePCISlots(def, qemuCaps, addrs) < 0)
             goto cleanup;
 
+        if (virDomainDeviceInfoIterate(def, qemuDomainAssignPCIAddressExtension, addrs) < 0)
+            goto cleanup;
+
         /* Only for *new* domains with pcie-root (and no other
          * manually specified PCI controllers in the definition): If,
          * after assigning addresses/reserving slots for all devices,
@@ -2684,6 +2736,9 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
         if (qemuDomainAssignDevicePCISlots(def, qemuCaps, addrs) < 0)
             goto cleanup;
 
+        if (virDomainDeviceInfoIterate(def, qemuDomainAssignPCIAddressExtension, addrs) < 0)
+            goto cleanup;
+
         /* set multi attribute for devices at function 0 of
          * any slot that has multiple functions in use
          */
@@ -3143,8 +3198,10 @@ qemuDomainReleaseDeviceAddress(virDomainObjPtr vm,
     if (!devstr)
         devstr = info->alias;
 
-    if (virDeviceInfoPCIAddressPresent(info))
+    if (virDeviceInfoPCIAddressPresent(info)) {
         virDomainPCIAddressReleaseAddr(priv->pciaddrs, &info->addr.pci);
+        virDomainPCIAddressExtensionReleaseAddr(priv->pciaddrs, &info->addr.pci);
+    }
 
     if (virDomainUSBAddressRelease(priv->usbaddrs, info) < 0)
         VIR_WARN("Unable to release USB address on %s", NULLSTR(devstr));
-- 
2.22.0