render / rpms / libvirt

Forked from rpms/libvirt 7 months ago
Clone
43fe83
From 3155b1327ffc178fea9ef96987dfbeb296862d58 Mon Sep 17 00:00:00 2001
43fe83
Message-Id: <3155b1327ffc178fea9ef96987dfbeb296862d58.1377873636.git.jdenemar@redhat.com>
43fe83
From: Laine Stump <laine@laine.org>
43fe83
Date: Tue, 6 Aug 2013 13:23:20 -0600
43fe83
Subject: [PATCH] qemu: eliminate almost-duplicate code in qemu_command.c
43fe83
43fe83
This patch is part of the resolution to:
43fe83
43fe83
   https://bugzilla.redhat.com/show_bug.cgi?id=819968
43fe83
43fe83
* The functions qemuDomainPCIAddressReserveAddr and
43fe83
qemuDomainPCIAddressReserveSlot were very similar (and should have
43fe83
been more similar) and were about to get more code added to them which
43fe83
would create even more duplicated code, so this patch gives
43fe83
qemuDomainPCIAddressReserveAddr a "reserveEntireSlot" arg, then
43fe83
replaces the body of qemuDomainPCIAddressReserveSlot with a call to
43fe83
qemuDomainPCIAddressReserveAddr.
43fe83
43fe83
You will notice that addrs->lastaddr was previously set in
43fe83
qemuDomainPCIAddressReserveAddr (but *not* set in
43fe83
qemuDomainPCIAddressReserveSlot). For consistency and cleanliness of
43fe83
code, that bit was removed and put into the one caller of
43fe83
qemuDomainPCIAddressReserveAddr (there is a similar place where the
43fe83
caller of qemuDomainPCIAddressReserveSlot sets lastaddr). This does
43fe83
guarantee identical functionality to pre-patch code, but in practice
43fe83
isn't really critical, because lastaddr is just keeping track of where
43fe83
to start when looking for a free slot - if it isn't updated, we will
43fe83
just start looking on a slot that's already occupied, then skip up to
43fe83
one that isn't.
43fe83
43fe83
* qemuCollectPCIAddress was essentially doing the same thing as
43fe83
qemuDomainPCIAddressReserveAddr, but with some extra special case
43fe83
checking at the beginning. The duplicate code has been replaced with
43fe83
a call to qemuDomainPCIAddressReserveAddr. This required adding a
43fe83
"fromConfig" boolean, which is only used to change the log error
43fe83
code from VIR_ERR_INTERNAL_ERROR (when the address was
43fe83
auto-generated by libvirt) to VIR_ERR_XML_ERROR (when the address is
43fe83
coming from the config); without this differentiation, it would be
43fe83
difficult to tell if an error was caused by something wrong in
43fe83
libvirt's auto-allocate code or just bad config.
43fe83
43fe83
* the bit of code in qemuDomainPCIAddressValidate that checks the
43fe83
connect type flags is going to be used in a couple more places where
43fe83
we don't need to also check the slot limits (because we're generating
43fe83
the slot number ourselves), so that has been pulled out into a
43fe83
separate qemuDomainPCIAddressFlagsCompatible function.
43fe83
(cherry picked from commit 3bb0125766a301a9d99884e7cdb002ba5fa5df01)
43fe83
---
43fe83
 src/qemu/qemu_command.c | 232 ++++++++++++++++++++++++------------------------
43fe83
 src/qemu/qemu_command.h |   4 +-
43fe83
 2 files changed, 119 insertions(+), 117 deletions(-)
43fe83
43fe83
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
43fe83
index 4345456..abc973a 100644
43fe83
--- a/src/qemu/qemu_command.c
43fe83
+++ b/src/qemu/qemu_command.c
43fe83
@@ -1434,9 +1434,53 @@ struct _qemuDomainPCIAddressSet {
43fe83
 };
43fe83
 
43fe83
 
43fe83
-/*
43fe83
- * Check that the PCI address is valid for use
43fe83
- * with the specified PCI address set.
43fe83
+static bool
43fe83
+qemuDomainPCIAddressFlagsCompatible(virDevicePCIAddressPtr addr,
43fe83
+                                    qemuDomainPCIConnectFlags busFlags,
43fe83
+                                    qemuDomainPCIConnectFlags devFlags,
43fe83
+                                    bool reportError)
43fe83
+{
43fe83
+    /* If this bus doesn't allow the type of connection (PCI
43fe83
+     * vs. PCIe) required by the device, or if the device requires
43fe83
+     * hot-plug and this bus doesn't have it, return false.
43fe83
+     */
43fe83
+    if (!(devFlags & busFlags & QEMU_PCI_CONNECT_TYPES_MASK)) {
43fe83
+        if (reportError) {
43fe83
+            if (devFlags & QEMU_PCI_CONNECT_TYPE_PCI) {
43fe83
+                virReportError(VIR_ERR_INTERNAL_ERROR,
43fe83
+                               _("PCI bus %.4x:%.2x is not compatible with the "
43fe83
+                                 "device. Device requires a standard PCI slot, "
43fe83
+                                 "which is not provided by this bus"),
43fe83
+                               addr->domain, addr->bus);
43fe83
+            } else {
43fe83
+                /* this should never happen. If it does, there is a
43fe83
+                 * bug in the code that sets the flag bits for devices.
43fe83
+                 */
43fe83
+                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
43fe83
+                           _("The device information has no PCI "
43fe83
+                             "connection types listed"));
43fe83
+            }
43fe83
+        }
43fe83
+        return false;
43fe83
+    }
43fe83
+    if ((devFlags & QEMU_PCI_CONNECT_HOTPLUGGABLE) &&
43fe83
+        !(busFlags & QEMU_PCI_CONNECT_HOTPLUGGABLE)) {
43fe83
+        if (reportError) {
43fe83
+            virReportError(VIR_ERR_INTERNAL_ERROR,
43fe83
+                           _("PCI bus %.4x:%.2x is not compatible with the "
43fe83
+                             "device. Device requires hot-plug capability, "
43fe83
+                             "which is not provided by the bus"),
43fe83
+                           addr->domain, addr->bus);
43fe83
+        }
43fe83
+        return false;
43fe83
+    }
43fe83
+    return true;
43fe83
+}
43fe83
+
43fe83
+
43fe83
+/* Verify that the address is in bounds for the chosen bus, and
43fe83
+ * that the bus is of the correct type for the device (via
43fe83
+ * comparing the flags).
43fe83
  */
43fe83
 static bool
43fe83
 qemuDomainPCIAddressValidate(qemuDomainPCIAddressSetPtr addrs,
43fe83
@@ -1466,24 +1510,9 @@ qemuDomainPCIAddressValidate(qemuDomainPCIAddressSetPtr addrs,
43fe83
     /* assure that at least one of the requested connection types is
43fe83
      * provided by this bus
43fe83
      */
43fe83
-    if (!(flags & bus->flags & QEMU_PCI_CONNECT_TYPES_MASK)) {
43fe83
-        virReportError(VIR_ERR_XML_ERROR,
43fe83
-                       _("Invalid PCI address: The PCI controller "
43fe83
-                         "providing bus %04x doesn't support "
43fe83
-                         "connections appropriate for the device "
43fe83
-                         "(%x required vs. %x provided by bus)"),
43fe83
-                       addr->bus, flags & QEMU_PCI_CONNECT_TYPES_MASK,
43fe83
-                       bus->flags & QEMU_PCI_CONNECT_TYPES_MASK);
43fe83
-        return false;
43fe83
-    }
43fe83
-    /* make sure this bus allows hot-plug if the caller demands it */
43fe83
-    if ((flags & QEMU_PCI_CONNECT_HOTPLUGGABLE) &&
43fe83
-        !(bus->flags &  QEMU_PCI_CONNECT_HOTPLUGGABLE)) {
43fe83
-        virReportError(VIR_ERR_XML_ERROR,
43fe83
-                       _("Invalid PCI address: hot-pluggable slot requested, "
43fe83
-                         "but bus %04x doesn't support hot-plug"), addr->bus);
43fe83
+    if (!qemuDomainPCIAddressFlagsCompatible(addr, bus->flags, flags, true))
43fe83
         return false;
43fe83
-    }
43fe83
+
43fe83
     /* some "buses" are really just a single port */
43fe83
     if (bus->minSlot && addr->slot < bus->minSlot) {
43fe83
         virReportError(VIR_ERR_XML_ERROR,
43fe83
@@ -1597,10 +1626,10 @@ qemuCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
43fe83
                       virDomainDeviceInfoPtr info,
43fe83
                       void *opaque)
43fe83
 {
43fe83
+    qemuDomainPCIAddressSetPtr addrs = opaque;
43fe83
     int ret = -1;
43fe83
-    char *str = NULL;
43fe83
     virDevicePCIAddressPtr addr = &info->addr.pci;
43fe83
-    qemuDomainPCIAddressSetPtr addrs = opaque;
43fe83
+    bool entireSlot;
43fe83
     /* FIXME: flags should be set according to the requirements of @device */
43fe83
     qemuDomainPCIConnectFlags flags = (QEMU_PCI_CONNECT_HOTPLUGGABLE |
43fe83
                                        QEMU_PCI_CONNECT_TYPE_PCI);
43fe83
@@ -1639,56 +1668,15 @@ qemuCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
43fe83
             return 0;
43fe83
     }
43fe83
 
43fe83
-    /* add an additional bus of the correct type if needed */
43fe83
-    if (addrs->dryRun &&
43fe83
-        qemuDomainPCIAddressSetGrow(addrs, addr, flags) < 0)
43fe83
-        return -1;
43fe83
-
43fe83
-    /* verify that the address is in bounds for the chosen bus, and
43fe83
-     * that the bus is of the correct type for the device (via
43fe83
-     * comparing the flags).
43fe83
-     */
43fe83
-    if (!qemuDomainPCIAddressValidate(addrs, addr, flags))
43fe83
-        return -1;
43fe83
-
43fe83
-    if (!(str = qemuDomainPCIAddressAsString(addr)))
43fe83
-        goto cleanup;
43fe83
+    entireSlot = (addr->function == 0 &&
43fe83
+                  addr->multi != VIR_DEVICE_ADDRESS_PCI_MULTI_ON);
43fe83
 
43fe83
-    /* check if already in use */
43fe83
-    if (addrs->buses[addr->bus].slots[addr->slot] & (1 << addr->function)) {
43fe83
-        if (info->addr.pci.function != 0) {
43fe83
-            virReportError(VIR_ERR_XML_ERROR,
43fe83
-                           _("Attempted double use of PCI Address '%s' "
43fe83
-                             "(may need \"multifunction='on'\" for device on function 0)"),
43fe83
-                           str);
43fe83
-        } else {
43fe83
-            virReportError(VIR_ERR_XML_ERROR,
43fe83
-                           _("Attempted double use of PCI Address '%s'"), str);
43fe83
-        }
43fe83
+    if (qemuDomainPCIAddressReserveAddr(addrs, addr, flags,
43fe83
+                                        entireSlot, true) < 0)
43fe83
         goto cleanup;
43fe83
-    }
43fe83
 
43fe83
-    /* mark as in use */
43fe83
-    if ((info->addr.pci.function == 0) &&
43fe83
-        (info->addr.pci.multi != VIR_DEVICE_ADDRESS_PCI_MULTI_ON)) {
43fe83
-        /* a function 0 w/o multifunction=on must reserve the entire slot */
43fe83
-        if (addrs->buses[addr->bus].slots[addr->slot]) {
43fe83
-            virReportError(VIR_ERR_XML_ERROR,
43fe83
-                           _("Attempted double use of PCI Address on slot '%s' "
43fe83
-                             "(need \"multifunction='off'\" for device "
43fe83
-                             "on function 0)"),
43fe83
-                           str);
43fe83
-            goto cleanup;
43fe83
-        }
43fe83
-        addrs->buses[addr->bus].slots[addr->slot] = 0xFF;
43fe83
-        VIR_DEBUG("Remembering PCI slot: %s (multifunction=off)", str);
43fe83
-    } else {
43fe83
-        VIR_DEBUG("Remembering PCI addr: %s", str);
43fe83
-        addrs->buses[addr->bus].slots[addr->slot] |= 1 << addr->function;
43fe83
-    }
43fe83
     ret = 0;
43fe83
 cleanup:
43fe83
-    VIR_FREE(str);
43fe83
     return ret;
43fe83
 }
43fe83
 
43fe83
@@ -1871,46 +1859,73 @@ static bool qemuDomainPCIAddressSlotInUse(qemuDomainPCIAddressSetPtr addrs,
43fe83
 }
43fe83
 
43fe83
 
43fe83
+/*
43fe83
+ * Reserve a slot (or just one function) for a device. If
43fe83
+ * reserveEntireSlot is true, all functions for the slot are reserved,
43fe83
+ * otherwise only one. If fromConfig is true, the address being
43fe83
+ * requested came directly from the config and errors should be worded
43fe83
+ * appropriately. If fromConfig is false, the address was
43fe83
+ * automatically created by libvirt, so it is an internal error (not
43fe83
+ * XML).
43fe83
+ */
43fe83
 int
43fe83
 qemuDomainPCIAddressReserveAddr(qemuDomainPCIAddressSetPtr addrs,
43fe83
                                 virDevicePCIAddressPtr addr,
43fe83
-                                qemuDomainPCIConnectFlags flags)
43fe83
+                                qemuDomainPCIConnectFlags flags,
43fe83
+                                bool reserveEntireSlot,
43fe83
+                                bool fromConfig)
43fe83
 {
43fe83
-    char *str;
43fe83
+    int ret = -1;
43fe83
+    char *str = NULL;
43fe83
     qemuDomainPCIAddressBusPtr bus;
43fe83
-
43fe83
-    if (addrs->dryRun && qemuDomainPCIAddressSetGrow(addrs, addr, flags) < 0)
43fe83
-        return -1;
43fe83
+    virErrorNumber errType = (fromConfig
43fe83
+                              ? VIR_ERR_XML_ERROR : VIR_ERR_INTERNAL_ERROR);
43fe83
 
43fe83
     if (!(str = qemuDomainPCIAddressAsString(addr)))
43fe83
-        return -1;
43fe83
+        goto cleanup;
43fe83
 
43fe83
-    VIR_DEBUG("Reserving PCI addr %s", str);
43fe83
+    /* Add an extra bus if necessary */
43fe83
+    if (addrs->dryRun && qemuDomainPCIAddressSetGrow(addrs, addr, flags) < 0)
43fe83
+        goto cleanup;
43fe83
+    /* Check that the requested bus exists, is the correct type, and we
43fe83
+     * are asking for a valid slot
43fe83
+     */
43fe83
+    if (!qemuDomainPCIAddressValidate(addrs, addr, flags))
43fe83
+        goto cleanup;
43fe83
 
43fe83
     bus = &addrs->buses[addr->bus];
43fe83
-    if ((bus->minSlot && addr->slot < bus->minSlot) ||
43fe83
-        addr->slot > bus->maxSlot) {
43fe83
-        virReportError(VIR_ERR_INTERNAL_ERROR,
43fe83
-                       _("Unable to reserve PCI address %s. "
43fe83
-                         "Slot %02x can't be used on bus %04x, "
43fe83
-                         "only slots %02zx - %02zx are permitted on this bus."),
43fe83
-                       str, addr->slot, addr->bus, bus->minSlot, bus->maxSlot);
43fe83
-    }
43fe83
 
43fe83
-    if (bus->slots[addr->slot] & (1 << addr->function)) {
43fe83
-        virReportError(VIR_ERR_INTERNAL_ERROR,
43fe83
-                       _("unable to reserve PCI address %s already in use"), str);
43fe83
-        VIR_FREE(str);
43fe83
-        return -1;
43fe83
+    if (reserveEntireSlot) {
43fe83
+        if (bus->slots[addr->slot]) {
43fe83
+            virReportError(errType,
43fe83
+                           _("Attempted double use of PCI slot %s "
43fe83
+                             "(may need \"multifunction='on'\" for "
43fe83
+                             "device on function 0)"), str);
43fe83
+            goto cleanup;
43fe83
+        }
43fe83
+        bus->slots[addr->slot] = 0xFF; /* reserve all functions of slot */
43fe83
+        VIR_DEBUG("Reserving PCI slot %s (multifunction='off')", str);
43fe83
+    } else {
43fe83
+        if (bus->slots[addr->slot] & (1 << addr->function)) {
43fe83
+            if (addr->function == 0) {
43fe83
+                virReportError(errType,
43fe83
+                               _("Attempted double use of PCI Address %s"), str);
43fe83
+            } else {
43fe83
+                virReportError(errType,
43fe83
+                               _("Attempted double use of PCI Address %s "
43fe83
+                                 "(may need \"multifunction='on'\" "
43fe83
+                                 "for device on function 0)"), str);
43fe83
+            }
43fe83
+            goto cleanup;
43fe83
+        }
43fe83
+        bus->slots[addr->slot] |= (1 << addr->function);
43fe83
+        VIR_DEBUG("Reserving PCI address %s", str);
43fe83
     }
43fe83
 
43fe83
+    ret = 0;
43fe83
+cleanup:
43fe83
     VIR_FREE(str);
43fe83
-
43fe83
-    addrs->lastaddr = *addr;
43fe83
-    addrs->lastaddr.function = 0;
43fe83
-    addrs->lastaddr.multi = 0;
43fe83
-    bus->slots[addr->slot] |= 1 << addr->function;
43fe83
-    return 0;
43fe83
+    return ret;
43fe83
 }
43fe83
 
43fe83
 
43fe83
@@ -1919,26 +1934,7 @@ qemuDomainPCIAddressReserveSlot(qemuDomainPCIAddressSetPtr addrs,
43fe83
                                 virDevicePCIAddressPtr addr,
43fe83
                                 qemuDomainPCIConnectFlags flags)
43fe83
 {
43fe83
-    char *str;
43fe83
-
43fe83
-    if (addrs->dryRun && qemuDomainPCIAddressSetGrow(addrs, addr, flags) < 0)
43fe83
-        return -1;
43fe83
-
43fe83
-    if (!(str = qemuDomainPCIAddressAsString(addr)))
43fe83
-        return -1;
43fe83
-
43fe83
-    VIR_DEBUG("Reserving PCI slot %s", str);
43fe83
-
43fe83
-    if (addrs->buses[addr->bus].slots[addr->slot]) {
43fe83
-        virReportError(VIR_ERR_INTERNAL_ERROR,
43fe83
-                       _("unable to reserve PCI slot %s"), str);
43fe83
-        VIR_FREE(str);
43fe83
-        return -1;
43fe83
-    }
43fe83
-
43fe83
-    VIR_FREE(str);
43fe83
-    addrs->buses[addr->bus].slots[addr->slot] = 0xFF;
43fe83
-    return 0;
43fe83
+    return qemuDomainPCIAddressReserveAddr(addrs, addr, flags, true, false);
43fe83
 }
43fe83
 
43fe83
 int qemuDomainPCIAddressEnsureAddr(qemuDomainPCIAddressSetPtr addrs,
43fe83
@@ -2044,12 +2040,11 @@ qemuDomainPCIAddressGetNextSlot(qemuDomainPCIAddressSetPtr addrs,
43fe83
                 VIR_DEBUG("PCI slot %.4x:%.2x:%.2x already in use",
43fe83
                           a.domain, a.bus, a.slot);
43fe83
             }
43fe83
-
43fe83
         }
43fe83
     }
43fe83
 
43fe83
     virReportError(VIR_ERR_INTERNAL_ERROR,
43fe83
-                   "%s", _("No more available PCI addresses"));
43fe83
+                   "%s", _("No more available PCI slots"));
43fe83
     return -1;
43fe83
 
43fe83
 success:
43fe83
@@ -2409,9 +2404,14 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
43fe83
 
43fe83
                 addr.bus = tmp_addr.bus;
43fe83
                 addr.slot = tmp_addr.slot;
43fe83
+
43fe83
+                addrs->lastaddr = addr;
43fe83
+                addrs->lastaddr.function = 0;
43fe83
+                addrs->lastaddr.multi = 0;
43fe83
             }
43fe83
             /* Finally we can reserve the slot+function */
43fe83
-            if (qemuDomainPCIAddressReserveAddr(addrs, &addr, flags) < 0)
43fe83
+            if (qemuDomainPCIAddressReserveAddr(addrs, &addr, flags,
43fe83
+                                                false, false) < 0)
43fe83
                 goto error;
43fe83
 
43fe83
             def->controllers[i]->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
43fe83
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
43fe83
index c9f1600..bf4953a 100644
43fe83
--- a/src/qemu/qemu_command.h
43fe83
+++ b/src/qemu/qemu_command.h
43fe83
@@ -253,7 +253,9 @@ int qemuDomainPCIAddressReserveSlot(qemuDomainPCIAddressSetPtr addrs,
43fe83
                                     qemuDomainPCIConnectFlags flags);
43fe83
 int qemuDomainPCIAddressReserveAddr(qemuDomainPCIAddressSetPtr addrs,
43fe83
                                     virDevicePCIAddressPtr addr,
43fe83
-                                    qemuDomainPCIConnectFlags flags);
43fe83
+                                    qemuDomainPCIConnectFlags flags,
43fe83
+                                    bool reserveEntireSlot,
43fe83
+                                    bool fromConfig);
43fe83
 int qemuDomainPCIAddressReserveNextSlot(qemuDomainPCIAddressSetPtr addrs,
43fe83
                                         virDomainDeviceInfoPtr dev,
43fe83
                                         qemuDomainPCIConnectFlags flags);
43fe83
-- 
43fe83
1.8.3.2
43fe83