[libvirt] [PATCH 2/5] Add functions to track virtio-serial addresses

Ján Tomko jtomko at redhat.com
Tue Mar 3 14:44:27 UTC 2015


Store the available ports of a virtio-serial controller in a virBitmap.
The bitmaps are stored in a hash table - the controller index
formatted as a string.

Buses are not tracked, because they aren't supported by QEMU.
---
 src/conf/domain_addr.c   | 382 +++++++++++++++++++++++++++++++++++++++++++++++
 src/conf/domain_addr.h   |  45 ++++++
 src/libvirt_private.syms |   8 +
 3 files changed, 435 insertions(+)

diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c
index fb4a76f..654c95a 100644
--- a/src/conf/domain_addr.c
+++ b/src/conf/domain_addr.c
@@ -718,3 +718,385 @@ virDomainCCWAddressSetCreate(void)
     virDomainCCWAddressSetFree(addrs);
     return NULL;
 }
+
+
+#define VIR_DOMAIN_DEFAULT_VIRTIO_SERIAL_PORTS 31
+
+
+static void
+virDomainVirtioSerialAddrHashValueFree(void *value,
+                                       const void *name ATTRIBUTE_UNUSED)
+{
+    virBitmapPtr map = value;
+
+    virBitmapFree(map);
+}
+
+/* virDomainVirtioSerialAddrSetCreate
+ *
+ * Allocates an address set for virtio serial addresses
+ */
+virDomainVirtioSerialAddrSetPtr
+virDomainVirtioSerialAddrSetCreate(void)
+{
+    virDomainVirtioSerialAddrSetPtr ret = NULL;
+
+    if (VIR_ALLOC(ret) < 0)
+        goto error;
+
+    if (!(ret->used = virHashCreate(9, virDomainVirtioSerialAddrHashValueFree)))
+        goto error;
+
+    return ret;
+
+ error:
+    virDomainVirtioSerialAddrSetFree(ret);
+    return NULL;
+}
+
+/* virDomainVirtioSerialAddrSetAddController
+ *
+ * Adds virtio serial ports of the existing controller
+ * to the address set.
+ */
+int
+virDomainVirtioSerialAddrSetAddController(virDomainVirtioSerialAddrSetPtr addrs,
+                                          virDomainControllerDefPtr cont)
+{
+    virBitmapPtr map = NULL;
+    char *str = NULL;
+    int ret = -1;
+    int ports;
+
+    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 (!(map = virBitmapNew(ports)))
+        goto cleanup;
+
+    if (virAsprintf(&str, "%u", cont->idx) < 0)
+        goto cleanup;
+
+    if (virHashLookup(addrs->used, str)) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("virtio serial controller with index %u "
+                         " is already in the address set"), cont->idx);
+        goto cleanup;
+    }
+    if (virHashAddEntry(addrs->used, str, map) < 0)
+        goto cleanup;
+    map = NULL;
+
+    if (!addrs->nextInit) {
+        addrs->next.controller = cont->idx;
+        addrs->nextInit = true;
+    }
+
+    ret = 0;
+
+ cleanup:
+    VIR_FREE(str);
+    virBitmapFree(map);
+    return ret;
+}
+
+/* virDomainVirtioSerialAddrSetAddControllers
+ *
+ * Adds virtio serial ports of the existing controllers
+ * 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;
+}
+
+void
+virDomainVirtioSerialAddrSetFree(virDomainVirtioSerialAddrSetPtr addrs)
+{
+    if (addrs) {
+        virHashFree(addrs->used);
+        VIR_FREE(addrs);
+    }
+}
+
+/*
+ * Eww, this function compares two unsigned integers stored as a string
+ */
+static int
+virDomainVirtioSerialAddrCompare(const virHashKeyValuePair *a,
+                                 const virHashKeyValuePair *b)
+{
+    const char *key_a = a->key;
+    const char *key_b = b->key;
+
+    size_t len_a = strlen(key_a);
+    size_t len_b = strlen(key_b);
+
+    /* with no padding/negative numbers allowed, the longer string
+     * contains a larger number */
+    if (len_a < len_b)
+        return -1;
+    else if (len_a > len_b)
+        return 1;
+    else
+        return strncmp(key_a, key_b, len_a);
+}
+
+static int
+virDomainVirtioSerialAddrNext(virDomainVirtioSerialAddrSetPtr addrs,
+                              virDomainDeviceVirtioSerialAddress *addr,
+                              bool allowZero)
+{
+    virBitmapPtr cur = NULL;
+    char *str = NULL;
+    int ret = -1;
+    virHashKeyValuePairPtr arr = NULL;
+    size_t i, ncontrollers;
+    size_t curidx;
+    ssize_t port, start = 0;
+    unsigned int controller;
+
+    /* port number 0 is reserved for virtconsoles */
+    if (allowZero)
+        start = -1;
+
+    /* What controller was the last assigned address on? */
+    if (virAsprintf(&str, "%u", addrs->next.controller) < 0)
+        goto cleanup;
+
+    if (!(cur = virHashLookup(addrs->used, str))) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("The last used virtio serial controller is missing "
+                         "from the address set hash table"));
+        goto cleanup;
+    }
+
+    /* Look for a free port on the current controller */
+    if ((port = virBitmapNextClearBit(cur, start + addrs->next.port)) >= 0) {
+        controller = addrs->next.controller;
+        goto success;
+    }
+
+    ncontrollers = virHashSize(addrs->used);
+    arr = virHashGetItems(addrs->used, virDomainVirtioSerialAddrCompare);
+    if (!arr) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Unable to get the hash table as an array"));
+        goto cleanup;
+    }
+
+    /* Find its position in the hash "array" */
+    for (i = 0; i < ncontrollers; i++) {
+        if (arr[i].value == cur) {
+            curidx = i;
+            break;
+        }
+    }
+    if (i == ncontrollers) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("The last used virtio serial controller is missing from the set"));
+        goto cleanup;
+    }
+
+    /* Search for a free port after the current controller */
+    for (i = curidx; i < ncontrollers; i++) {
+        cur = (virBitmapPtr) arr[i].value;
+        if ((port = virBitmapNextClearBit(cur, start)) >= 0) {
+            if (virStrToLong_ui(arr[i].key, NULL, 10, &controller) < 0)
+                goto cleanup;
+            goto success;
+        }
+    }
+
+    for (i = 0; i < curidx; i++) {
+        cur = (virBitmapPtr) arr[i].value;
+        if ((port = virBitmapNextClearBit(cur, start)) >= 0) {
+            if (virStrToLong_ui(arr[i].key, NULL, 10, &controller) < 0)
+                goto cleanup;
+            goto success;
+        }
+    }
+
+    virReportError(VIR_ERR_XML_ERROR, "%s",
+                   _("Unable to find a free virtio-serial port"));
+
+ cleanup:
+    VIR_FREE(arr);
+    VIR_FREE(str);
+    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;
+}
+
+/* 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)
+{
+    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);
+}
+
+
+int
+virDomainVirtioSerialAddrAssign(virDomainVirtioSerialAddrSetPtr addrs,
+                                virDomainDeviceInfoPtr info,
+                                bool allowZero)
+{
+    int ret = -1;
+    virDomainDeviceInfo nfo = { NULL };
+    virDomainDeviceInfoPtr ptr = allowZero ? &nfo : info;
+
+    ptr->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL;
+
+    if (virDomainVirtioSerialAddrNext(addrs, &ptr->addr.vioserial,
+                                      allowZero) < 0)
+        goto cleanup;
+
+    addrs->next = info->addr.vioserial;
+
+    if (virDomainVirtioSerialAddrReserve(NULL, NULL, ptr, addrs) < 0)
+        goto cleanup;
+
+    ret = 0;
+
+ cleanup:
+    return ret;
+}
+
+/* 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;
+    virBitmapPtr map;
+    char *str = NULL;
+    int ret = -1;
+    bool b;
+
+    if (info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL ||
+        info->addr.vioserial.port == 0)
+        return 0;
+
+    VIR_DEBUG("Reserving virtio serial %u %u", info->addr.vioserial.controller,
+              info->addr.vioserial.port);
+
+    if (virAsprintf(&str, "%u", info->addr.vioserial.controller) < 0)
+        goto cleanup;
+
+    if ((map = virHashLookup(addrs->used, str)) == NULL) {
+        virReportError(VIR_ERR_XML_ERROR,
+                       _("virtio serial controller %u is missing"),
+                       info->addr.vioserial.controller);
+        goto cleanup;
+    }
+
+    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;
+
+    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);
+
+    if (virAsprintf(&str, "%u", info->addr.vioserial.controller) < 0)
+        goto cleanup;
+
+    if ((map = virHashLookup(addrs->used, str)) == NULL) {
+        virReportError(VIR_ERR_XML_ERROR,
+                       _("virtio serial controller %u is missing"),
+                       info->addr.vioserial.controller);
+        goto cleanup;
+    }
+
+    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..5c65a98 100644
--- a/src/conf/domain_addr.h
+++ b/src/conf/domain_addr.h
@@ -173,4 +173,49 @@ int virDomainCCWAddressReleaseAddr(virDomainCCWAddressSetPtr addrs,
                                    virDomainDeviceInfoPtr dev)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
 virDomainCCWAddressSetPtr virDomainCCWAddressSetCreate(void);
+
+struct _virDomainVirtioSerialAddrSet {
+    virHashTablePtr used;
+    virDomainDeviceVirtioSerialAddress next;
+    bool nextInit;
+};
+typedef struct _virDomainVirtioSerialAddrSet virDomainVirtioSerialAddrSet;
+typedef virDomainVirtioSerialAddrSet *virDomainVirtioSerialAddrSetPtr;
+
+virDomainVirtioSerialAddrSetPtr
+virDomainVirtioSerialAddrSetCreate(void);
+int
+virDomainVirtioSerialAddrSetAddController(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);
+int
+virDomainVirtioSerialAddrAutoAssign(virDomainVirtioSerialAddrSetPtr addrs,
+                                    virDomainDeviceInfoPtr info,
+                                    bool allowZero)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+
+int
+virDomainVirtioSerialAddrAssign(virDomainVirtioSerialAddrSetPtr addrs,
+                                virDomainDeviceInfoPtr info,
+                                bool allowZero)
+    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 6028002..9f2996a 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -108,6 +108,14 @@ virDomainPCIAddressSetFree;
 virDomainPCIAddressSetGrow;
 virDomainPCIAddressSlotInUse;
 virDomainPCIAddressValidate;
+virDomainVirtioSerialAddrAssign;
+virDomainVirtioSerialAddrAutoAssign;
+virDomainVirtioSerialAddrRelease;
+virDomainVirtioSerialAddrReserve;
+virDomainVirtioSerialAddrSetAddController;
+virDomainVirtioSerialAddrSetAddControllers;
+virDomainVirtioSerialAddrSetCreate;
+virDomainVirtioSerialAddrSetFree;
 
 
 # conf/domain_audit.h
-- 
2.0.5




More information about the libvir-list mailing list