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

John Ferlan jferlan at redhat.com
Mon Mar 23 21:46:19 UTC 2015



On 03/17/2015 07:41 AM, Ján Tomko wrote:
> 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   | 348 +++++++++++++++++++++++++++++++++++++++++++++++
>  src/conf/domain_addr.h   |  56 ++++++++
>  src/libvirt_private.syms |   9 ++
>  3 files changed, 413 insertions(+)
> 

I assumed the ACK to 1/5 sticks...

> diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c
> index fb4a76f..d9d01fc 100644
> --- a/src/conf/domain_addr.c
> +++ b/src/conf/domain_addr.c
> @@ -718,3 +718,351 @@ 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)

Should the Free routine take a pointer so that when we VIR_FREE the
pointer the caller doesn't have to "worry" about setting their copy to NULL?

> +{
> +    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)
> +            return i;
> +    }

Would entries "<controller type='virtio-serial' index='1' ports='4'>"
and "<controller type='virtio-serial' index='1'"> be rejected elsewhere?
I would think "index" would be unique but this algorithm seems to be
fine and happy with it.

> +    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;
> +
> +    insertAt = virDomainVirtioSerialAddrPlaceController(addrs, cnt);
> +    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.
> + */
> +int
> +virDomainVirtioSerialAddrSetRemoveController(virDomainVirtioSerialAddrSetPtr addrs,
> +                                             virDomainControllerDefPtr cont)
> +{
> +    int ret = -1;
> +    ssize_t pos;
> +
> +    if (cont->type != VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL)
> +        return 0;
> +
> +    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) < 0)
> +        goto cleanup;
> +

If 'pos' < 0, we return 0 (and perhaps leak something). OTOH, the
controller was never added and the caller never checks status, maybe
this should just be void (wonder why Coverity didn't whine)...


> +    ret = 0;
> +
> + cleanup:
> +    return ret;
> +}
> +
> +void
> +virDomainVirtioSerialAddrSetFree(virDomainVirtioSerialAddrSetPtr addrs)
> +{

same question about having Free routine take address rather than refcopy

> +    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, start = 0;
> +    ssize_t i;
> +    unsigned int controller;
> +
> +    /* port number 0 is reserved for virtconsoles */
> +    if (allowZero)
> +        start = -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, start)) >= 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;
> +}
> +
> +/* 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;
> +
> +    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;
> +    char *str = NULL;
> +    int ret = -1;
> +    virBitmapPtr map = NULL;
> +    bool b;
> +    ssize_t i;
> +
> +    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);
> +
> +    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;
> +    }

Should we info->addr.vioserial.port = 0 here to ensure someone doesn't
end up in some loop retrying the same port?

This seems reasonable; however, results in next patch having me
scratching my head a bit...

John
> +
> +    ret = 0;
> +
> + cleanup:
> +    VIR_FREE(str);
> +    return ret;
> +}
> diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h
> index 2c3468e..846bf5c 100644
> --- a/src/conf/domain_addr.h
> +++ b/src/conf/domain_addr.h
> @@ -173,4 +173,60 @@ 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);
> +int
> +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);
> +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 1fb42ac..f600838 100644
> --- a/src/libvirt_private.syms
> +++ b/src/libvirt_private.syms
> @@ -108,6 +108,15 @@ virDomainPCIAddressSetFree;
>  virDomainPCIAddressSetGrow;
>  virDomainPCIAddressSlotInUse;
>  virDomainPCIAddressValidate;
> +virDomainVirtioSerialAddrAssign;
> +virDomainVirtioSerialAddrAutoAssign;
> +virDomainVirtioSerialAddrRelease;
> +virDomainVirtioSerialAddrReserve;
> +virDomainVirtioSerialAddrSetAddController;
> +virDomainVirtioSerialAddrSetAddControllers;
> +virDomainVirtioSerialAddrSetCreate;
> +virDomainVirtioSerialAddrSetFree;
> +virDomainVirtioSerialAddrSetRemoveController;
>  
>  
>  # conf/domain_audit.h
> 




More information about the libvir-list mailing list