[libvirt] [PATCHv3 2/6] Add functions to track virtio-serial addresses

Ján Tomko jtomko at redhat.com
Tue Mar 24 17:15:16 UTC 2015


Create a sorted array of virtio-serial controllers.
Each of the elements contains the controller index
and a bitmap of available ports.

Buses are not tracked, because they aren't supported by QEMU.
---
 src/conf/domain_addr.c   | 398 +++++++++++++++++++++++++++++++++++++++++++++++
 src/conf/domain_addr.h   |  59 +++++++
 src/libvirt_private.syms |  10 ++
 3 files changed, 467 insertions(+)

diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c
index fb4a76f..49d28be 100644
--- a/src/conf/domain_addr.c
+++ b/src/conf/domain_addr.c
@@ -718,3 +718,401 @@ virDomainCCWAddressSetCreate(void)
     virDomainCCWAddressSetFree(addrs);
     return NULL;
 }
+
+
+#define VIR_DOMAIN_DEFAULT_VIRTIO_SERIAL_PORTS 31
+
+
+/* virDomainVirtioSerialAddrSetCreate
+ *
+ * Allocates an address set for virtio serial addresses
+ */
+virDomainVirtioSerialAddrSetPtr
+virDomainVirtioSerialAddrSetCreate(void)
+{
+    virDomainVirtioSerialAddrSetPtr ret = NULL;
+
+    if (VIR_ALLOC(ret) < 0)
+        return NULL;
+
+    return ret;
+}
+
+static void
+virDomainVirtioSerialControllerFree(virDomainVirtioSerialControllerPtr cont)
+{
+    if (cont) {
+        virBitmapFree(cont->ports);
+        VIR_FREE(cont);
+    }
+}
+
+static ssize_t
+virDomainVirtioSerialAddrPlaceController(virDomainVirtioSerialAddrSetPtr addrs,
+                                         virDomainVirtioSerialControllerPtr cont)
+{
+    size_t i;
+
+    for (i = 0; i < addrs->ncontrollers; i++) {
+        if (addrs->controllers[i]->idx == cont->idx) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("virtio serial controller with index %u already exists"
+                             " in the address set"),
+                           cont->idx);
+            return -2;
+        }
+        if (addrs->controllers[i]->idx > cont->idx)
+            return i;
+    }
+    return -1;
+}
+
+static ssize_t
+virDomainVirtioSerialAddrFindController(virDomainVirtioSerialAddrSetPtr addrs,
+                                        unsigned int idx)
+{
+    size_t i;
+
+    for (i = 0; i < addrs->ncontrollers; i++) {
+        if (addrs->controllers[i]->idx == idx)
+            return i;
+    }
+    return -1;
+}
+
+/* virDomainVirtioSerialAddrSetAddController
+ *
+ * Adds virtio serial ports of the existing controller
+ * to the address set.
+ */
+int
+virDomainVirtioSerialAddrSetAddController(virDomainVirtioSerialAddrSetPtr addrs,
+                                          virDomainControllerDefPtr cont)
+{
+    int ret = -1;
+    int ports;
+    virDomainVirtioSerialControllerPtr cnt = NULL;
+    ssize_t insertAt;
+
+    if (cont->type != VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL)
+        return 0;
+
+    ports = cont->opts.vioserial.ports;
+    if (ports == -1)
+        ports = VIR_DOMAIN_DEFAULT_VIRTIO_SERIAL_PORTS;
+
+    VIR_DEBUG("Adding virtio serial controller index %u with %d"
+              " ports to the address set", cont->idx, ports);
+
+    if (VIR_ALLOC(cnt) < 0)
+        goto cleanup;
+
+    if (!(cnt->ports = virBitmapNew(ports)))
+        goto cleanup;
+    cnt->idx = cont->idx;
+
+    if ((insertAt = virDomainVirtioSerialAddrPlaceController(addrs, cnt)) < -1)
+        goto cleanup;
+    if (VIR_INSERT_ELEMENT(addrs->controllers, insertAt,
+                           addrs->ncontrollers, cnt) < 0)
+        goto cleanup;
+
+    ret = 0;
+
+ cleanup:
+    virDomainVirtioSerialControllerFree(cnt);
+    return ret;
+}
+
+/* virDomainVirtioSerialAddrSetAddControllers
+ *
+ * Adds virtio serial ports of controllers present in the domain definition
+ * to the address set.
+ */
+int
+virDomainVirtioSerialAddrSetAddControllers(virDomainVirtioSerialAddrSetPtr addrs,
+                                           virDomainDefPtr def)
+{
+    size_t i;
+
+    for (i = 0; i < def->ncontrollers; i++) {
+        if (virDomainVirtioSerialAddrSetAddController(addrs,
+                                                      def->controllers[i]) < 0)
+            return -1;
+    }
+
+    return 0;
+}
+
+/* virDomainVirtioSerialAddrSetRemoveController
+ *
+ * Removes a virtio serial controller from the address set.
+ */
+void
+virDomainVirtioSerialAddrSetRemoveController(virDomainVirtioSerialAddrSetPtr addrs,
+                                             virDomainControllerDefPtr cont)
+{
+    ssize_t pos;
+
+    if (cont->type != VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL)
+        return;
+
+    VIR_DEBUG("Removing virtio serial controller index %u "
+              "from the address set", cont->idx);
+
+    pos = virDomainVirtioSerialAddrFindController(addrs, cont->idx);
+
+    if (pos >= 0)
+        VIR_DELETE_ELEMENT(addrs->controllers, pos, addrs->ncontrollers);
+}
+
+void
+virDomainVirtioSerialAddrSetFree(virDomainVirtioSerialAddrSetPtr addrs)
+{
+    size_t i;
+    if (addrs) {
+        for (i = 0; i < addrs->ncontrollers; i++)
+            virDomainVirtioSerialControllerFree(addrs->controllers[i]);
+        VIR_FREE(addrs);
+    }
+}
+
+static int
+virDomainVirtioSerialAddrNext(virDomainVirtioSerialAddrSetPtr addrs,
+                              virDomainDeviceVirtioSerialAddress *addr,
+                              bool allowZero)
+{
+    int ret = -1;
+    ssize_t port, startPort = 0;
+    ssize_t i;
+    unsigned int controller;
+
+    /* port number 0 is reserved for virtconsoles */
+    if (allowZero)
+        startPort = -1;
+
+    if (addrs->ncontrollers == 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("no virtio-serial controllers are available"));
+        goto cleanup;
+    }
+
+    for (i = 0; i < addrs->ncontrollers; i++) {
+        virBitmapPtr map = addrs->controllers[i]->ports;
+        if ((port = virBitmapNextClearBit(map, startPort)) >= 0) {
+            controller = addrs->controllers[i]->idx;
+            goto success;
+        }
+    }
+
+    virReportError(VIR_ERR_XML_ERROR, "%s",
+                   _("Unable to find a free virtio-serial port"));
+
+ cleanup:
+    return ret;
+
+ success:
+    addr->bus = 0;
+    addr->port = port;
+    addr->controller = controller;
+    VIR_DEBUG("Found free virtio serial controller %u port %u", addr->controller,
+              addr->port);
+    ret = 0;
+    goto cleanup;
+}
+
+static int
+virDomainVirtioSerialAddrNextFromController(virDomainVirtioSerialAddrSetPtr addrs,
+                                            virDomainDeviceVirtioSerialAddress *addr)
+{
+    ssize_t port;
+    ssize_t i;
+    virBitmapPtr map;
+
+    i = virDomainVirtioSerialAddrFindController(addrs, addr->controller);
+    if (i < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("virtio-serial controller %u not available"),
+                       addr->controller);
+        return -1;
+    }
+
+    map = addrs->controllers[i]->ports;
+    if ((port = virBitmapNextClearBit(map, 0)) <= 0) {
+        virReportError(VIR_ERR_XML_ERROR,
+                       _("Unable to find a free port on virtio-serial controller %u"),
+                       addr->controller);
+        return -1;
+    }
+
+    addr->bus = 0;
+    addr->port = port;
+    VIR_DEBUG("Found free virtio serial controller %u port %u", addr->controller,
+              addr->port);
+    return 0;
+}
+
+/* virDomainVirtioSerialAddrAutoAssign
+ *
+ * reserve a virtio serial address of the device (if it has one)
+ * or assign a virtio serial address to the device
+ */
+int
+virDomainVirtioSerialAddrAutoAssign(virDomainVirtioSerialAddrSetPtr addrs,
+                                    virDomainDeviceInfoPtr info,
+                                    bool allowZero)
+{
+    bool portOnly = info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL;
+    if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL &&
+        info->addr.vioserial.port)
+        return virDomainVirtioSerialAddrReserve(NULL, NULL, info, addrs);
+    else
+        return virDomainVirtioSerialAddrAssign(addrs, info, allowZero, portOnly);
+}
+
+
+int
+virDomainVirtioSerialAddrAssign(virDomainVirtioSerialAddrSetPtr addrs,
+                                virDomainDeviceInfoPtr info,
+                                bool allowZero,
+                                bool portOnly)
+{
+    int ret = -1;
+    virDomainDeviceInfo nfo = { NULL };
+    virDomainDeviceInfoPtr ptr = allowZero ? &nfo : info;
+
+    ptr->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL;
+
+    if (portOnly) {
+        if (virDomainVirtioSerialAddrNextFromController(addrs,
+                                                        &ptr->addr.vioserial) < 0)
+            goto cleanup;
+    } else {
+        if (virDomainVirtioSerialAddrNext(addrs, &ptr->addr.vioserial,
+                                          allowZero) < 0)
+            goto cleanup;
+    }
+
+    if (virDomainVirtioSerialAddrReserve(NULL, NULL, ptr, addrs) < 0)
+        goto cleanup;
+
+    ret = 0;
+
+ cleanup:
+    return ret;
+}
+
+/* virDomainVirtioSerialAddrIsComplete
+ *
+ * Check if the address is complete, or it needs auto-assignment
+ */
+bool
+virDomainVirtioSerialAddrIsComplete(virDomainDeviceInfoPtr info)
+{
+    return info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL &&
+        info->addr.vioserial.port != 0;
+}
+
+/* virDomainVirtioSerialAddrReserve
+ *
+ * Reserve the virtio serial address of the device
+ *
+ * For use with virDomainDeviceInfoIterate,
+ * opaque should be the address set
+ */
+int
+virDomainVirtioSerialAddrReserve(virDomainDefPtr def ATTRIBUTE_UNUSED,
+                                 virDomainDeviceDefPtr dev ATTRIBUTE_UNUSED,
+                                 virDomainDeviceInfoPtr info,
+                                 void *data)
+{
+    virDomainVirtioSerialAddrSetPtr addrs = data;
+    char *str = NULL;
+    int ret = -1;
+    virBitmapPtr map = NULL;
+    bool b;
+    ssize_t i;
+
+    if (!virDomainVirtioSerialAddrIsComplete(info))
+        return 0;
+
+    VIR_DEBUG("Reserving virtio serial %u %u", info->addr.vioserial.controller,
+              info->addr.vioserial.port);
+
+    i = virDomainVirtioSerialAddrFindController(addrs, info->addr.vioserial.controller);
+    if (i < 0) {
+        virReportError(VIR_ERR_XML_ERROR,
+                       _("virtio serial controller %u is missing"),
+                       info->addr.vioserial.controller);
+        goto cleanup;
+    }
+
+    map = addrs->controllers[i]->ports;
+    if (virBitmapGetBit(map, info->addr.vioserial.port, &b) < 0) {
+        virReportError(VIR_ERR_XML_ERROR,
+                       _("virtio serial controller %u does not have port %u"),
+                       info->addr.vioserial.controller,
+                       info->addr.vioserial.port);
+        goto cleanup;
+    }
+
+    if (b) {
+        virReportError(VIR_ERR_XML_ERROR,
+                       _("virtio serial port %u on controller %u is already occupied"),
+                       info->addr.vioserial.port,
+                       info->addr.vioserial.controller);
+        goto cleanup;
+    }
+
+    ignore_value(virBitmapSetBit(map, info->addr.vioserial.port));
+
+    ret = 0;
+
+ cleanup:
+    VIR_FREE(str);
+    return ret;
+}
+
+/* virDomainVirtioSerialAddrRelease
+ *
+ * Release the virtio serial address of the device
+ */
+int
+virDomainVirtioSerialAddrRelease(virDomainVirtioSerialAddrSetPtr addrs,
+                                 virDomainDeviceInfoPtr info)
+{
+    virBitmapPtr map;
+    char *str = NULL;
+    int ret = -1;
+    ssize_t i;
+
+    if (info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL ||
+        info->addr.vioserial.port == 0)
+        return 0;
+
+    VIR_DEBUG("Releasing virtio serial %u %u", info->addr.vioserial.controller,
+              info->addr.vioserial.port);
+
+    i = virDomainVirtioSerialAddrFindController(addrs, info->addr.vioserial.controller);
+    if (i < 0) {
+        virReportError(VIR_ERR_XML_ERROR,
+                       _("virtio serial controller %u is missing"),
+                       info->addr.vioserial.controller);
+        goto cleanup;
+    }
+
+    map = addrs->controllers[i]->ports;
+    if (virBitmapClearBit(map, info->addr.vioserial.port) < 0) {
+        virReportError(VIR_ERR_XML_ERROR,
+                       _("virtio serial controller %u does not have port %u"),
+                       info->addr.vioserial.controller,
+                       info->addr.vioserial.port);
+        goto cleanup;
+    }
+
+    ret = 0;
+
+ cleanup:
+    VIR_FREE(str);
+    return ret;
+}
diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h
index 2c3468e..14ffd17 100644
--- a/src/conf/domain_addr.h
+++ b/src/conf/domain_addr.h
@@ -173,4 +173,63 @@ int virDomainCCWAddressReleaseAddr(virDomainCCWAddressSetPtr addrs,
                                    virDomainDeviceInfoPtr dev)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
 virDomainCCWAddressSetPtr virDomainCCWAddressSetCreate(void);
+
+struct _virDomainVirtioSerialController {
+    unsigned int idx;
+    virBitmapPtr ports;
+};
+
+typedef struct _virDomainVirtioSerialController virDomainVirtioSerialController;
+typedef virDomainVirtioSerialController *virDomainVirtioSerialControllerPtr;
+
+struct _virDomainVirtioSerialAddrSet {
+    virDomainVirtioSerialControllerPtr *controllers;
+    size_t ncontrollers;
+};
+typedef struct _virDomainVirtioSerialAddrSet virDomainVirtioSerialAddrSet;
+typedef virDomainVirtioSerialAddrSet *virDomainVirtioSerialAddrSetPtr;
+
+virDomainVirtioSerialAddrSetPtr
+virDomainVirtioSerialAddrSetCreate(void);
+int
+virDomainVirtioSerialAddrSetAddController(virDomainVirtioSerialAddrSetPtr addrs,
+                                          virDomainControllerDefPtr cont)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+void
+virDomainVirtioSerialAddrSetRemoveController(virDomainVirtioSerialAddrSetPtr addrs,
+                                             virDomainControllerDefPtr cont)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+int
+virDomainVirtioSerialAddrSetAddControllers(virDomainVirtioSerialAddrSetPtr addrs,
+                                           virDomainDefPtr def)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+void
+virDomainVirtioSerialAddrSetFree(virDomainVirtioSerialAddrSetPtr addrs);
+bool
+virDomainVirtioSerialAddrIsComplete(virDomainDeviceInfoPtr info);
+int
+virDomainVirtioSerialAddrAutoAssign(virDomainVirtioSerialAddrSetPtr addrs,
+                                    virDomainDeviceInfoPtr info,
+                                    bool allowZero)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+
+int
+virDomainVirtioSerialAddrAssign(virDomainVirtioSerialAddrSetPtr addrs,
+                                virDomainDeviceInfoPtr info,
+                                bool allowZero,
+                                bool portOnly)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+
+int
+virDomainVirtioSerialAddrReserve(virDomainDefPtr def,
+                                 virDomainDeviceDefPtr dev,
+                                 virDomainDeviceInfoPtr info,
+                                 void *data)
+    ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4);
+
+int
+virDomainVirtioSerialAddrRelease(virDomainVirtioSerialAddrSetPtr addrs,
+                                 virDomainDeviceInfoPtr info)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+
 #endif /* __DOMAIN_ADDR_H__ */
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 33222f0..fe8aee3 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -108,6 +108,16 @@ virDomainPCIAddressSetFree;
 virDomainPCIAddressSetGrow;
 virDomainPCIAddressSlotInUse;
 virDomainPCIAddressValidate;
+virDomainVirtioSerialAddrAssign;
+virDomainVirtioSerialAddrAutoAssign;
+virDomainVirtioSerialAddrIsComplete;
+virDomainVirtioSerialAddrRelease;
+virDomainVirtioSerialAddrReserve;
+virDomainVirtioSerialAddrSetAddController;
+virDomainVirtioSerialAddrSetAddControllers;
+virDomainVirtioSerialAddrSetCreate;
+virDomainVirtioSerialAddrSetFree;
+virDomainVirtioSerialAddrSetRemoveController;
 
 
 # conf/domain_audit.h
-- 
2.0.5




More information about the libvir-list mailing list