[libvirt] [PATCH 10/13] conf: Allocate/release 'uid' and 'fid' in PCI address

Xiao Feng Ren renxiaof at linux.vnet.ibm.com
Thu May 24 12:24:35 UTC 2018


From: Yi Min Zhao <zyimin at linux.ibm.com>

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 collecting phase. If any of them is
not defined, we will find out an available value for it from zPCI
address hashtable, and reserve it. For hotplug case, there might be or
not zPCI definition. So allocate and reserve uid/fid for undefined
case. Assign if needed and reserve uid/fid for defined case. If the user
define zPCI extension address but zPCI capability doesn't exist, an
error will be reported.

Signed-off-by: Yi Min Zhao <zyimin at linux.ibm.com>
Reviewed-by: Boris Fiuczynski <fiuczy at linux.vnet.ibm.com>
---
 src/conf/domain_addr.c         | 264 +++++++++++++++++++++++++++++++++++++++++
 src/conf/domain_addr.h         |  15 +++
 src/libvirt_private.syms       |   3 +
 src/qemu/qemu_domain_address.c |  41 ++++++-
 4 files changed, 321 insertions(+), 2 deletions(-)

diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c
index 37a3645c5d..e8b7d06609 100644
--- a/src/conf/domain_addr.c
+++ b/src/conf/domain_addr.c
@@ -33,6 +33,147 @@
 
 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 %u is already reserved"), name, id);
+        return -1;
+    }
+
+    if (virHashAddEntry(set, &id, (void*)1) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Failed to reserve %s %u"), name, id);
+        return -1;
+    }
+
+    return 0;
+}
+
+static int
+virDomainZPCIAddressReserveUid(virHashTablePtr set, virZPCIDeviceAddressPtr addr)
+{
+    return virDomainZPCIAddressReserveId(set, addr->zpciuid, "uid");
+}
+
+static int
+virDomainZPCIAddressReserveFid(virHashTablePtr set, virZPCIDeviceAddressPtr addr)
+{
+    return virDomainZPCIAddressReserveId(set, addr->zpcifid, "fid");
+}
+
+
+static bool
+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 false;
+        }
+        ++min;
+    }
+    *id = min;
+
+    return true;
+}
+
+static int
+virDomainZPCIAddressAssignUid(virHashTablePtr set, virZPCIDeviceAddressPtr addr)
+{
+    if (addr->uid_assigned)
+        return 0;
+
+    addr->uid_assigned = virDomainZPCIAddressAssignId(set, &addr->zpciuid, 1,
+                                     VIR_DOMAIN_DEVICE_ZPCI_MAX_UID, "uid");
+    return addr->uid_assigned ? 0 : -1;
+}
+
+static int
+virDomainZPCIAddressAssignFid(virHashTablePtr set, virZPCIDeviceAddressPtr addr)
+{
+    if (addr->fid_assigned)
+        return 0;
+
+    addr->fid_assigned = virDomainZPCIAddressAssignId(set, &addr->zpcifid, 0,
+                                     VIR_DOMAIN_DEVICE_ZPCI_MAX_FID, "fid");
+    return addr->fid_assigned ? 0 : -1;
+}
+
+
+static void
+virDomainZPCIAddressReleaseUid(virHashTablePtr set, virZPCIDeviceAddressPtr addr)
+{
+    if (!addr->uid_assigned)
+        return;
+
+    if (virHashRemoveEntry(set, &addr->zpciuid))
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Release uid %u failed"), addr->zpciuid);
+
+    addr->uid_assigned = false;
+}
+
+static void
+virDomainZPCIAddressReleaseFid(virHashTablePtr set, virZPCIDeviceAddressPtr addr)
+{
+    if (!addr->fid_assigned)
+        return;
+
+    if (virHashRemoveEntry(set, &addr->zpcifid))
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Release fid %u failed"), addr->zpcifid);
+
+    addr->fid_assigned = false;
+}
+
+
+static void
+virDomainZPCIAddressReleaseIds(virDomainZPCIAddressIdsPtr zpciIds,
+                               virPCIDeviceAddressPtr addr)
+{
+    if (!zpciIds || !addr->zpci)
+        return;
+
+    virDomainZPCIAddressReleaseUid(zpciIds->uids, addr->zpci);
+
+    virDomainZPCIAddressReleaseFid(zpciIds->fids, addr->zpci);
+
+    VIR_FREE(addr->zpci);
+}
+
+
+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 void
 virDomainPCIAddressSetExtensionFree(virDomainPCIAddressSetPtr addrs)
 {
@@ -44,6 +185,116 @@ virDomainPCIAddressSetExtensionFree(virDomainPCIAddressSetPtr addrs)
     VIR_FREE(addrs->zpciIds);
 }
 
+static int
+virDomainZPCIAddressReserveAddr(virDomainPCIAddressSetPtr addrs,
+                                virPCIDeviceAddressPtr addr)
+{
+    if (!addr->zpci)
+        return 0;
+
+    if (addr->zpci->uid_assigned &&
+        virDomainZPCIAddressReserveUid(addrs->zpciIds->uids, addr->zpci))
+            return -1;
+
+    if (addr->zpci->fid_assigned &&
+        virDomainZPCIAddressReserveFid(addrs->zpciIds->fids, addr->zpci)) {
+        virDomainZPCIAddressReleaseUid(addrs->zpciIds->uids, addr->zpci);
+        return -1;
+    }
+
+    return 0;
+}
+
+static int
+virDomainZPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs,
+                                    virZPCIDeviceAddressPtr zpci)
+{
+    if (!zpci->uid_assigned &&
+        virDomainZPCIAddressReserveNextUid(addrs->zpciIds->uids, zpci))
+            return -1;
+
+    if (!zpci->fid_assigned &&
+        virDomainZPCIAddressReserveNextFid(addrs->zpciIds->fids, zpci)) {
+        virDomainZPCIAddressReleaseUid(addrs->zpciIds->uids, zpci);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+int
+virDomainPCIAddressExtensionReserveAddr(virDomainPCIAddressSetPtr addrs,
+                                        virPCIDeviceAddressPtr addr,
+                                        virDomainPCIAddressExtensionFlags extFlags)
+{
+    if (extFlags & VIR_PCI_ADDRESS_EXTENSION_ZPCI) {
+    /* Reserve uid/fid to ZPCI device which has defined uid/fid
+     * in the domain.
+     */
+        if (virDomainZPCIAddressReserveAddr(addrs, addr) < 0)
+            return -1;
+    }
+
+    return 0;
+}
+
+
+int
+virDomainPCIAddressExtensionReserveNextAddr(virDomainPCIAddressSetPtr addrs,
+                                            virPCIDeviceAddressPtr dev,
+                                            virDomainPCIAddressExtensionFlags extFlags)
+{
+    if (extFlags & VIR_PCI_ADDRESS_EXTENSION_ZPCI) {
+    /* Assign and reserve uid/fid to ZPCI device which has not defined uid/fid
+     * in the domain.
+     */
+        virZPCIDeviceAddress zpci = { 0 };
+
+        if (dev->zpci)
+            zpci = *dev->zpci;
+
+        if (virDomainZPCIAddressReserveNextAddr(addrs, &zpci) < 0)
+            return -1;
+
+        if (!addrs->dryRun) {
+            if (!dev->zpci && VIR_ALLOC(dev->zpci) < 0)
+                return -1;
+            *dev->zpci = zpci;
+        }
+    }
+
+    return 0;
+}
+
+static int
+virDomainPCIAddressEnsureExtensionAddr(virDomainPCIAddressSetPtr addrs,
+                                       virDomainDeviceInfoPtr dev)
+{
+    virZPCIDeviceAddressPtr zpci = dev->addr.pci.zpci;
+
+    if (zpci && !dev->pciAddressExtFlags) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("zPCI is not supported."));
+        return -1;
+    }
+
+    if (!zpci) {
+        return virDomainPCIAddressExtensionReserveNextAddr(addrs, &dev->addr.pci,
+                                                           dev->pciAddressExtFlags);
+    } else {
+        if (virDomainZPCIAddressAssignUid(addrs->zpciIds->uids, zpci))
+            return -1;
+
+        if (virDomainZPCIAddressAssignFid(addrs->zpciIds->fids, zpci))
+            return -1;
+
+        if (virDomainZPCIAddressReserveAddr(addrs, &dev->addr.pci))
+            return -1;
+    }
+
+    return 0;
+}
+
 virDomainPCIConnectFlags
 virDomainPCIControllerModelToConnectType(virDomainControllerModelPCI model)
 {
@@ -740,12 +991,25 @@ virDomainPCIAddressEnsureAddr(virDomainPCIAddressSetPtr addrs,
         ret = virDomainPCIAddressReserveNextAddr(addrs, dev, flags, -1);
     }
 
+    if (virDomainPCIAddressEnsureExtensionAddr(addrs, dev) < 0)
+        goto cleanup;
+
  cleanup:
     VIR_FREE(addrStr);
     return ret;
 }
 
 
+void
+virDomainPCIAddressExtensionReleaseAddr(virDomainPCIAddressSetPtr addrs,
+                                        virPCIDeviceAddressPtr addr,
+                                        int extFlags)
+{
+    if ((extFlags & VIR_PCI_ADDRESS_EXTENSION_ZPCI))
+        virDomainZPCIAddressReleaseIds(addrs->zpciIds, addr);
+}
+
+
 void
 virDomainPCIAddressReleaseAddr(virDomainPCIAddressSetPtr addrs,
                                virPCIDeviceAddressPtr addr)
diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h
index f95d56c0a0..86d54e38f2 100644
--- a/src/conf/domain_addr.h
+++ b/src/conf/domain_addr.h
@@ -167,6 +167,16 @@ bool virDomainPCIAddressSlotInUse(virDomainPCIAddressSetPtr addrs,
                                   virPCIDeviceAddressPtr addr)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
 
+int virDomainPCIAddressExtensionReserveAddr(virDomainPCIAddressSetPtr addrs,
+                                            virPCIDeviceAddressPtr addr,
+                                            virDomainPCIAddressExtensionFlags extFlags)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+
+int virDomainPCIAddressExtensionReserveNextAddr(virDomainPCIAddressSetPtr addrs,
+                                            virPCIDeviceAddressPtr addr,
+                                            virDomainPCIAddressExtensionFlags extFlags)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+
 int virDomainPCIAddressReserveAddr(virDomainPCIAddressSetPtr addrs,
                                    virPCIDeviceAddressPtr addr,
                                    virDomainPCIConnectFlags flags,
@@ -188,6 +198,11 @@ void virDomainPCIAddressReleaseAddr(virDomainPCIAddressSetPtr addrs,
                                     virPCIDeviceAddressPtr addr)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
 
+void virDomainPCIAddressExtensionReleaseAddr(virDomainPCIAddressSetPtr addrs,
+                                             virPCIDeviceAddressPtr addr,
+                                             int extFlags)
+    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 2be1f8788a..372f43c6d3 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -114,6 +114,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 392723d616..f186691949 100644
--- a/src/qemu/qemu_domain_address.c
+++ b/src/qemu/qemu_domain_address.c
@@ -1389,6 +1389,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;
+    virDomainPCIAddressExtensionFlags extFlags = info->pciAddressExtFlags;
+
+    if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
+        if (virDomainPCIAddressExtensionReserveNextAddr(addrs, addr, extFlags) < 0)
+            return -1;
+    }
+
+    return 0;
+}
+
 static int
 qemuDomainCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
                             virDomainDeviceDefPtr device,
@@ -1406,7 +1424,12 @@ qemuDomainCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
          * parent, and will have its address collected during the scan
          * of the parent's device type.
         */
-        return 0;
+        if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI ||
+            info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
+            return virDomainPCIAddressExtensionReserveAddr(addrs, addr,
+                                                           info->pciAddressExtFlags);
+        else
+            return 0;
     }
 
     /* If we get to here, the device has a PCI address assigned in the
@@ -1477,6 +1500,11 @@ qemuDomainCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
         goto cleanup;
     }
 
+    if (virDomainPCIAddressExtensionReserveAddr(addrs, addr,
+                                                info->pciAddressExtFlags) < 0) {
+        goto cleanup;
+    }
+
     ret = 0;
  cleanup:
     return ret;
@@ -2568,6 +2596,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,
@@ -2662,6 +2693,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
          */
@@ -3121,8 +3155,11 @@ 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,
+                                                info->pciAddressExtFlags);
+    }
 
     if (virDomainUSBAddressRelease(priv->usbaddrs, info) < 0)
         VIR_WARN("Unable to release USB address on %s", NULLSTR(devstr));
-- 
2.16.3




More information about the libvir-list mailing list