[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH v4 1/2] libxl: Introduce functions to add and remove USB devices to an HVM guest



On 11/04/13 20:51, George Dunlap wrote:
> This patch exposes a generic interface which can be expanded in the
> future to implement USB for PVUSB, qemu, and stubdoms.  It can also be
> extended to include other types of USB other than host USB (for example,
> tablets, mice, or keyboards).
> 
> For each device removed or added, one of two protocols is available:
> * PVUSB
> * qemu (DEVICEMODEL)
> 
> The caller can additionally specify "AUTO", in which case the library will
> try to determine the best protocol automatically.
> 
> At the moment, the only protocol implemented is DEVICEMODEL, and the only
> device type impelmented is HOSTDEV.
> 
> This uses the qmp functionality, and is thus only available for
> qemu-xen, not qemu-traditional.
> 
> Signed-off-by: George Dunlap <george.dunlap@xxxxxxxxxxxxx>
> CC: Ian Jackson <ian.jackson@xxxxxxxxxx>
> CC: Roger Pau Monne <roger.pau@xxxxxxxxxx>
> CC: sstanisi@xxxxxxxxx

I'm not familiar with the QMP interface, so I just commented the general
libxl parts of the patch.

> ---
>  tools/libxl/Makefile           |    2 +-
>  tools/libxl/libxl.h            |   35 +++
>  tools/libxl/libxl_create.c     |   12 +-
>  tools/libxl/libxl_internal.h   |   18 ++
>  tools/libxl/libxl_qmp.c        |   66 +++++
>  tools/libxl/libxl_types.idl    |   22 ++
>  tools/libxl/libxl_usb.c        |  531 
> ++++++++++++++++++++++++++++++++++++++++
>  tools/ocaml/libs/xl/genwrap.py |    1 +
>  8 files changed, 685 insertions(+), 2 deletions(-)
>  create mode 100644 tools/libxl/libxl_usb.c
> 
> diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
> index 2984051..866960a 100644
> --- a/tools/libxl/Makefile
> +++ b/tools/libxl/Makefile
> @@ -74,7 +74,7 @@ LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o 
> libxl_pci.o \
>                         libxl_internal.o libxl_utils.o libxl_uuid.o \
>                         libxl_json.o libxl_aoutils.o libxl_numa.o \
>                         libxl_save_callout.o _libxl_save_msgs_callout.o \
> -                       libxl_qmp.o libxl_event.o libxl_fork.o $(LIBXL_OBJS-y)
> +                       libxl_qmp.o libxl_event.o libxl_fork.o libxl_usb.o 
> $(LIBXL_OBJS-y)
>  LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o
> 
>  $(LIBXL_OBJS): CFLAGS += $(CFLAGS_LIBXL) -include $(XEN_ROOT)/tools/config.h
> diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
> index d18d22c..2c60cc2 100644
> --- a/tools/libxl/libxl.h
> +++ b/tools/libxl/libxl.h
> @@ -75,6 +75,11 @@
>  #define LIBXL_HAVE_FIRMWARE_PASSTHROUGH 1
> 
>  /*
> + * FIXME: Update comment
> + */
> +#define LIBXL_HAVE_USB 1
> +
> +/*
>   * libxl ABI compatibility
>   *
>   * The only guarantee which libxl makes regarding ABI compatibility
> @@ -735,6 +740,36 @@ int libxl_cdrom_insert(libxl_ctx *ctx, uint32_t domid, 
> libxl_device_disk *disk,
>                         const libxl_asyncop_how *ao_how)
>                         LIBXL_EXTERNAL_CALLERS_ONLY;
> 
> +/*
> + * USB
> + *
> + * For each device removed or added, one of three protocols is available:
> + * - PVUSB
> + * - qemu (DEVICEMODEL)
> + *
> + * The caller can additionally specify "AUTO", in which case the library will
> + * try to determine the best protocol automatically.
> + *
> + * At the moment, the only protocol implemented is DEVICEMODEL, and the only
> + * device type impelmented is HOSTDEV.
> + *
> + * This uses the qmp functionality, and is thus only available for
> + * qemu-xen, not qemu-traditional.
> + *
> + */
> +#define LIBXL_DEVICE_USB_BACKEND_DEFAULT (-1)
> +int libxl_device_usb_add(libxl_ctx *ctx, uint32_t domid,
> +                         libxl_device_usb *dev,
> +                         const libxl_asyncop_how *ao_how)
> +                         LIBXL_EXTERNAL_CALLERS_ONLY;
> +int libxl_device_usb_remove(libxl_ctx *ctx, uint32_t domid,
> +                            libxl_device_usb *dev,
> +                            const libxl_asyncop_how *ao_how)
> +                            LIBXL_EXTERNAL_CALLERS_ONLY;
> +libxl_device_usb *libxl_device_usb_list(libxl_ctx *ctx, uint32_t domid,
> +                                        int *num)
> +                          LIBXL_EXTERNAL_CALLERS_ONLY;
> +
>  /* Network Interfaces */
>  int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic 
> *nic,
>                           const libxl_asyncop_how *ao_how)
> diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
> index 30a4507..c620d6d 100644
> --- a/tools/libxl/libxl_create.c
> +++ b/tools/libxl/libxl_create.c
> @@ -391,7 +391,7 @@ int libxl__domain_make(libxl__gc *gc, 
> libxl_domain_create_info *info,
>      libxl_ctx *ctx = libxl__gc_owner(gc);
>      int flags, ret, rc, nb_vm;
>      char *uuid_string;
> -    char *dom_path, *vm_path, *libxl_path;
> +    char *dom_path, *vm_path, *libxl_path, *libxl_usb_path;
>      struct xs_permissions roperm[2];
>      struct xs_permissions rwperm[1];
>      struct xs_permissions noperm[1];
> @@ -452,6 +452,13 @@ int libxl__domain_make(libxl__gc *gc, 
> libxl_domain_create_info *info,
>          goto out;
>      }
> 
> +    libxl_usb_path = libxl__sprintf(gc, "%s/usb", libxl_path);

I would recommend to use GCSPRINTF instead, it already checks for errors
and allows for smaller lines (altought you don't have to split the line
here)

> +    if (!libxl_usb_path) {
> +        LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "cannot allocate create paths");
> +        rc = ERROR_FAIL;
> +        goto out;
> +    }
> +
>      noperm[0].id = 0;
>      noperm[0].perms = XS_PERM_NONE;
> 
> @@ -475,6 +482,9 @@ retry_transaction:
>      xs_rm(ctx->xsh, t, libxl_path);
>      libxl__xs_mkdir(gc, t, libxl_path, noperm, ARRAY_SIZE(noperm));
> 
> +    xs_rm(ctx->xsh, t, libxl_usb_path);

You are missing the error check, there's also a helper for xs_rm,
libxl__xs_rm_checked.

> +    libxl__xs_mkdir(gc, t, libxl_usb_path, noperm, ARRAY_SIZE(noperm));

Error checking

> +
>      xs_write(ctx->xsh, t, libxl__sprintf(gc, "%s/vm", dom_path), vm_path, 
> strlen(vm_path));
>      rc = libxl__domain_rename(gc, *domid, 0, info->name, t);
>      if (rc)
> diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
> index 3ba3a21..d2e00fa 100644
> --- a/tools/libxl/libxl_internal.h
> +++ b/tools/libxl/libxl_internal.h
> @@ -1412,6 +1412,24 @@ _hidden int libxl__qmp_save(libxl__gc *gc, int domid, 
> const char *filename);
>  /* Set dirty bitmap logging status */
>  _hidden int libxl__qmp_set_global_dirty_log(libxl__gc *gc, int domid, bool 
> enable);
>  _hidden int libxl__qmp_insert_cdrom(libxl__gc *gc, int domid, const 
> libxl_device_disk *disk);
> +/* Same as normal, but "translated" */
> +typedef struct libxl__device_usb {
> +    libxl_usb_protocol protocol;
> +    libxl_domid target_domid;
> +    libxl_domid backend_domid;
> +    libxl_domid dm_domid;
> +    libxl_device_usb_type type;
> +    union {
> +        struct {
> +            int hostbus;
> +            int hostaddr;
> +        } hostdev;
> +    } u;
> +} libxl__device_usb;
> +_hidden int libxl__qmp_usb_add(libxl__gc *gc, int domid,
> +                               libxl__device_usb *dev);
> +_hidden int libxl__qmp_usb_remove(libxl__gc *gc, int domid,
> +                                  libxl__device_usb *dev);
>  /* close and free the QMP handler */
>  _hidden void libxl__qmp_close(libxl__qmp_handler *qmp);
>  /* remove the socket file, if the file has already been removed,
> diff --git a/tools/libxl/libxl_qmp.c b/tools/libxl/libxl_qmp.c
> index 644d2c0..ae55695 100644
> --- a/tools/libxl/libxl_qmp.c
> +++ b/tools/libxl/libxl_qmp.c
> @@ -42,6 +42,7 @@
> 
>  #define QMP_RECEIVE_BUFFER_SIZE 4096
>  #define PCI_PT_QDEV_ID "pci-pt-%02x_%02x.%01x"
> +#define HOST_USB_QDEV_ID "usb-hostdev-%04x.%04x"
> 
>  typedef int (*qmp_callback_t)(libxl__qmp_handler *qmp,
>                                const libxl__json_object *tree,
> @@ -929,6 +930,71 @@ int libxl__qmp_insert_cdrom(libxl__gc *gc, int domid,
>      }
>  }
> 
> +static int libxl__qmp_usb_hostdev_add(libxl__gc *gc, int domid,
> +                                   libxl__device_usb *dev)
> +{
> +    libxl__json_object *args = NULL;
> +    char *id;
> +
> +    id = libxl__sprintf(NOGC, HOST_USB_QDEV_ID,
> +                        (uint16_t) dev->u.hostdev.hostbus,
> +                        (uint16_t) dev->u.hostdev.hostaddr);

Are you sure you need to use NOGC here? id is only used to generate the
"args" string, which in turn is using the GC.

> +
> +    qmp_parameters_add_string(gc, &args, "driver", "usb-host");
> +    QMP_PARAMETERS_SPRINTF(&args, "hostbus", "0x%x", dev->u.hostdev.hostbus);
> +    QMP_PARAMETERS_SPRINTF(&args, "hostaddr", "0x%x", 
> dev->u.hostdev.hostaddr);
> +
> +    qmp_parameters_add_string(gc, &args, "id", id);
> +
> +    return qmp_run_command(gc, domid, "device_add", args, NULL, NULL);
> +}
> +
> +int libxl__qmp_usb_add(libxl__gc *gc, int domid,
> +                            libxl__device_usb *usbdev)
> +{
> +    int rc;
> +    switch(usbdev->type) {
> +    case LIBXL_DEVICE_USB_TYPE_HOSTDEV:
> +        rc = libxl__qmp_usb_hostdev_add(gc, domid, usbdev);
> +        break;
> +    default:
> +        return ERROR_INVAL;
> +    }
> +    return rc;
> +}
> +
> +
> +static int libxl__qmp_usb_hostdev_remove(libxl__gc *gc, int domid,
> +                               libxl__device_usb *dev)
> +{
> +    libxl__json_object *args = NULL;
> +    char *id;
> +
> +    id = libxl__sprintf(NOGC, HOST_USB_QDEV_ID,
> +                        (uint16_t) dev->u.hostdev.hostbus,
> +                        (uint16_t) dev->u.hostdev.hostaddr);

The same here, I think you can safely use the GC (GCSPRINTF).

> +
> +    qmp_parameters_add_string(gc, &args, "id", id);
> +
> +    return qmp_run_command(gc, domid, "device_del", args, NULL, NULL);
> +}
> +
> +int libxl__qmp_usb_remove(libxl__gc *gc, int domid,
> +                          libxl__device_usb *usbdev)
> +{
> +    int rc;
> +    switch(usbdev->type) {
> +    case LIBXL_DEVICE_USB_TYPE_HOSTDEV:
> +        rc = libxl__qmp_usb_hostdev_remove(gc, domid, usbdev);
> +        break;
> +    default:
> +        return ERROR_INVAL;
> +    }
> +    return rc;
> +}
> +
> +
> +
>  int libxl__qmp_initializations(libxl__gc *gc, uint32_t domid,
>                                 const libxl_domain_config *guest_config)
>  {
> diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
> index 6cb6de6..9e0a435 100644
> --- a/tools/libxl/libxl_types.idl
> +++ b/tools/libxl/libxl_types.idl
> @@ -407,6 +407,28 @@ libxl_device_vtpm = Struct("device_vtpm", [
>      ("uuid",             libxl_uuid),
>  ])
> 
> +libxl_device_usb_protocol = Enumeration("usb_protocol", [
> +    (0, "AUTO"),
> +    (1, "PV"),
> +    (2, "DEVICEMODEL"),
> +    ])
> +
> +libxl_device_usb_type = Enumeration("device_usb_type", [
> +    (1, "HOSTDEV"),
> +    ])
> +
> +libxl_device_usb = Struct("device_usb", [
> +        ("protocol", libxl_device_usb_protocol,
> +         {'init_val': 'LIBXL_USB_PROTOCOL_AUTO'}),
> +        ("backend_domid", libxl_domid,
> +         {'init_val': 'LIBXL_DEVICE_USB_BACKEND_DEFAULT'}),
> +        ("u", KeyedUnion(None, libxl_device_usb_type, "type",
> +                         [("hostdev", Struct(None, [
> +                                ("hostbus",   integer),
> +                                ("hostaddr",  integer) ]))
> +                          ]))
> +    ])
> +
>  libxl_domain_config = Struct("domain_config", [
>      ("c_info", libxl_domain_create_info),
>      ("b_info", libxl_domain_build_info),
> diff --git a/tools/libxl/libxl_usb.c b/tools/libxl/libxl_usb.c
> new file mode 100644
> index 0000000..50e1571
> --- /dev/null
> +++ b/tools/libxl/libxl_usb.c
> @@ -0,0 +1,531 @@
> +/*
> + * Copyright (C) 2009      Citrix Ltd.
> + * Author Vincent Hanquez <vincent.hanquez@xxxxxxxxxxxxx>
> + * Author Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU Lesser General Public License as published
> + * by the Free Software Foundation; version 2.1 only. with the special
> + * exception on linking described in file LICENSE.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU Lesser General Public License for more details.
> + */
> +
> +#include "libxl_osdeps.h" /* must come before any other headers */
> +
> +#include "libxl_internal.h"
> +
> +/*
> + * /libxl/<domid>/usb/<devid>/{type, protocol, backend, [typeinfo]}
> + */
> +#define USB_INFO_PATH "%s/usb"
> +#define USB_HOSTDEV_ID "hostdev-%04x-%04x"
> +
> +/*
> + * Just use plain numbers for now.  Replace these with strings at some point.
> + */
> +#define protocol_to_str(gc, t) libxl__sprintf((gc), "%d", (t))
> +#define str_to_protocol(s) atoi((s))
> +#define type_to_str(gc, t) libxl__sprintf((gc), "%d", (t))

GCSPRINTF, although this macros are so simple that you might also
replace them entirely with GCSPRINTF (altough it might make the code
harder to understand).

> +#define str_to_typeprotocol(s) atoi((s))
> +
> +static char * hostdev_xs_path(libxl__gc *gc, uint32_t domid,
> +                                    libxl__device_usb *usbdev)
> +{
> +    return libxl__sprintf(gc, USB_INFO_PATH "/%s",
> +                   libxl__xs_libxl_path(gc, domid),
> +                   libxl__sprintf(gc, USB_HOSTDEV_ID,
> +                                  (uint16_t)usbdev->u.hostdev.hostbus,
> +                                  (uint16_t)usbdev->u.hostdev.hostaddr));

I will stop repeating every time I see libxl__sprintf to replace it with
GCSPRINTF.

> +}
> +
> +static void hostdev_xs_append_params(libxl__gc *gc, libxl__device_usb 
> *usbdev,
> +                                  flexarray_t *a)
> +{
> +    flexarray_append_pair(a, "hostbus",
> +                          libxl__sprintf(gc, "%d",
> +                                         usbdev->u.hostdev.hostbus));
> +    flexarray_append_pair(a, "hostaddr",
> +                          libxl__sprintf(gc, "%d",
> +                                         usbdev->u.hostdev.hostaddr));
> +}
> +
> +static int read_hostdev_xenstore_entry(libxl__gc *gc, const char * path,
> +                                       libxl__device_usb *usbdev)
> +{
> +    int rc = 0;
> +    char * val;
> +
> +    val = libxl__xs_read(gc, XBT_NULL,
> +                         libxl__sprintf(gc, "%s/hostbus", path));

libxl__xs_read_checked will also print an error message if the read fails.

> +    if(!val) {
> +        LOG(ERROR, "Internal error (missing hostbus)");
> +        rc = ERROR_FAIL;
> +        goto out;
> +    }
> +    usbdev->u.hostdev.hostbus = atoi(val);
> +
> +    val = libxl__xs_read(gc, XBT_NULL,
> +                         libxl__sprintf(gc, "%s/hostaddr", path));

Same

> +    if(!val) {
> +        LOG(ERROR, "Internal error (missing hostaddr)");
> +        rc = ERROR_FAIL;
> +        goto out;
> +    }
> +    usbdev->u.hostdev.hostaddr = atoi(val);
> +
> +out:
> +    return rc;
> +}
> +
> +static int usb_read_xenstore(libxl__gc *gc, const char * path,
> +                                           libxl__device_usb *usbdev)
> +{
> +    char *val;
> +    int rc = 0;
> +
> +    val = libxl__xs_read(gc, XBT_NULL,
> +                         libxl__sprintf(gc, "%s/protocol", path));
> +    if(!val) {
> +        LOG(ERROR, "Internal error (missing protocol)");
> +        rc = ERROR_FAIL;
> +        goto out;
> +    }
> +    usbdev->protocol = atoi(val);
> +
> +    val = libxl__xs_read(gc, XBT_NULL,
> +                         libxl__sprintf(gc, "%s/backend_domid", path));
> +    if(!val) {
> +        LOG(ERROR, "Internal error (missing backend_domid)");
> +        rc = ERROR_FAIL;
> +        goto out;
> +    }
> +    usbdev->backend_domid = atoi(val);
> +
> +    val = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/type", path));
> +    if(!val) {
> +        LOG(ERROR, "Internal error (missing type)");
> +        rc = ERROR_FAIL;
> +        goto out;
> +    }
> +    usbdev->type = atoi(val);
> +
> +    switch(usbdev->type) {
> +    case LIBXL_DEVICE_USB_TYPE_HOSTDEV:
> +        if ((rc = read_hostdev_xenstore_entry(gc, path, usbdev)) < 0)
> +            goto out;
> +        break;
> +    default:
> +        LOG(ERROR, "Internal error (unimplemented type)");
> +        rc = ERROR_FAIL;
> +        goto out;
> +    }
> +
> +out:
> +    return rc;
> +}
> +
> +static int usb_add_xenstore(libxl__gc *gc, uint32_t domid,
> +                            libxl__device_usb *usbdev)
> +{
> +    libxl_ctx *ctx = libxl__gc_owner(gc);
> +    flexarray_t *dev;
> +    char *dev_path;
> +    xs_transaction_t t;
> +    struct xs_permissions noperm[1];
> +
> +    noperm[0].id = 0;
> +    noperm[0].perms = XS_PERM_NONE;
> +
> +    dev = flexarray_make(gc, 16, 1);
> +
> +    flexarray_append_pair(dev, "protocol",
> +                          libxl__sprintf(gc, "%d", usbdev->protocol));
> +
> +    flexarray_append_pair(dev, "backend_domid",
> +                          libxl__sprintf(gc, "%d", usbdev->backend_domid));
> +
> +    flexarray_append_pair(dev, "type",
> +                          libxl__sprintf(gc, "%d", usbdev->type));
> +
> +    switch(usbdev->type) {
> +    case LIBXL_DEVICE_USB_TYPE_HOSTDEV:
> +        dev_path = hostdev_xs_path(gc, domid, usbdev);
> +        hostdev_xs_append_params(gc, usbdev, dev);
> +        break;
> +    default:
> +        LOG(ERROR, "Invalid device type: %d", usbdev->type);
> +        return ERROR_FAIL;
> +    }
> +
> +    LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Adding new usb device to xenstore");
> +
> +retry_transaction:
> +    t = xs_transaction_start(ctx->xsh);
> +    libxl__xs_mkdir(gc, t, dev_path, noperm, ARRAY_SIZE(noperm));

Error checking

> +    libxl__xs_writev(gc, t, dev_path,
> +                    libxl__xs_kvs_of_flexarray(gc, dev, dev->count));
> +    if (!xs_transaction_end(ctx->xsh, t, 0))
> +        if (errno == EAGAIN)
> +            goto retry_transaction;

Ian Jackson (if I remember correctly) added some helpers for
transactions, that make the logic a little bit easier (take a look at
libxl__device_destroy for example in libxl_device.c):

for (;;) {
    rc = libxl__xs_transaction_start(gc, &t);
    if (rc) goto out;

    /* Do stuff */

    rc = libxl__xs_transaction_commit(gc, &t);
    if (!rc) break;
    if (rc < 0) goto out;
}

out:
libxl__xs_transaction_abort(gc, &t);

> +
> +    return 0;
> +}
> +
> +static int usb_remove_xenstore(libxl__gc *gc, uint32_t domid,
> +                               libxl__device_usb *usbdev)
> +{
> +    libxl_ctx *ctx = libxl__gc_owner(gc);
> +    char *dev_path;
> +
> +    LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Removing device from xenstore");
> +
> +    switch(usbdev->type) {
> +    case LIBXL_DEVICE_USB_TYPE_HOSTDEV:
> +        dev_path = hostdev_xs_path(gc, domid, usbdev);
> +        break;
> +    default:
> +        LOG(ERROR, "Invalid device type: %d", usbdev->type);
> +        return ERROR_FAIL;
> +    }
> +
> +    xs_rm(ctx->xsh, XBT_NULL, dev_path);
> +
> +    return 0;
> +}
> +
> +static int get_assigned_devices(libxl__gc *gc, uint32_t domid,
> +                                libxl__device_usb **list, int *num)
> +{
> +    char **devlist, *dompath;
> +    unsigned int nd = 0;
> +    int i, rc = 0;
> +
> +    *list = NULL;
> +    *num = 0;
> +
> +    dompath = libxl__sprintf(gc, USB_INFO_PATH,
> +                             libxl__xs_libxl_path(gc, domid));
> +
> +    devlist = libxl__xs_directory(gc, XBT_NULL, dompath, &nd);
> +    if ( !devlist )
> +        goto out;
> +
> +    *list = calloc(nd, sizeof(libxl__device_usb));

libxl__calloc

> +
> +    for(i = 0; i < nd; i++) {
> +        char *path;
> +
> +        path = libxl__sprintf(gc, "%s/%s", dompath, devlist[i]);
> +        if ( usb_read_xenstore(gc, path, (*list) + i) ) {
> +            rc = ERROR_INVAL;
> +            free(*list);
> +            *list = NULL;
> +            *num = 0;
> +            goto out;
> +        }
> +    }
> +
> +    *num = nd;
> +
> +    libxl__ptr_add(gc, *list);
> +
> +out:
> +    return rc;
> +}
> +
> +static int is_usbdev_type_hostdev_equal(libxl__device_usb *a,
> +                                        libxl__device_usb *b)
> +{
> +    if ( !memcmp(&a->u.hostdev, &b->u.hostdev, sizeof(a->u.hostdev) ) )
> +        return 1;
> +    else
> +        return 0;
> +}
> +
> +static int is_usbdev_in_array(libxl__device_usb *assigned, int num_assigned,
> +                              libxl__device_usb *dev)
> +{
> +    int i;
> +
> +    /* Devices are the same if:
> +     * - They have the same backend_domid
> +     * - They are of the same type
> +     * - Their types match
> +     * In theory, someone could try to pass the same device through
> +     * via both PVUSB and qemu; not comparing protocol will prevent that.
> +     */
> +    for(i = 0; i < num_assigned; i++) {
> +        if( assigned[i].type != dev->type
> +            || assigned[i].backend_domid != dev->backend_domid )

No spaces between "(" and the condition.

> +            continue;
> +
> +        switch(dev->type) {
> +        case LIBXL_DEVICE_USB_TYPE_HOSTDEV:
> +            if (!is_usbdev_type_hostdev_equal(dev, assigned+i))
> +                continue;
> +        }
> +
> +        return 1;
> +    }
> +
> +    return 0;
> +}
> +
> +static void usbdev_ext_to_int(libxl__device_usb *dev_int,
> +                              libxl_device_usb *dev_ext)
> +{
> +    dev_int->protocol = dev_ext->protocol;
> +
> +    if (dev_ext->backend_domid == LIBXL_DEVICE_USB_BACKEND_DEFAULT)
> +        dev_int->backend_domid = 0;
> +    else
> +        dev_int->backend_domid = dev_ext->backend_domid;
> +
> +    dev_int->type = dev_ext->type;
> +    memcpy(&dev_int->u, &dev_ext->u, sizeof(dev_ext->u));
> +}
> +
> +static void usbdev_int_to_ext(libxl_device_usb *dev_ext,
> +                              libxl__device_usb *dev_int)
> +{
> +    dev_ext->protocol = dev_int->protocol;
> +
> +    dev_ext->backend_domid = dev_int->backend_domid;
> +
> +    dev_ext->type = dev_int->type;
> +    memcpy(&dev_ext->u, &dev_int->u, sizeof(dev_ext->u));
> +}
> +
> +/*
> + * USB add
> + */
> +static int do_usb_add(libxl__gc *gc, uint32_t domid,
> +                      libxl__device_usb *usbdev)
> +{
> +    int rc;
> +
> +    switch (usbdev->protocol) {
> +    case LIBXL_USB_PROTOCOL_DEVICEMODEL:
> +        switch (libxl__device_model_version_running(gc, domid)) {
> +        case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL:
> +            LOG(ERROR, "usb-add not yet implemented for qemu-traditional");
> +            return ERROR_INVAL;
> +        case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN:
> +            if ( (rc = libxl__qmp_usb_add(gc, domid, usbdev)) < 0 )
> +                goto out;
> +            break;
> +        default:
> +            return ERROR_INVAL;
> +        }
> +        break;
> +    default:
> +        return ERROR_FAIL;
> +    }
> +
> +    rc = usb_add_xenstore(gc, domid, usbdev);
> +out:
> +    return rc;
> +}
> +
> +
> +
> +static int libxl__device_usb_add(libxl__gc *gc, uint32_t domid,
> +                                 libxl_device_usb *dev_ext)
> +{
> +    libxl_ctx *ctx = libxl__gc_owner(gc);
> +    libxl__device_usb *assigned, _usbdev, *usbdev;
> +    int rc = ERROR_FAIL, num_assigned;
> +    libxl_domain_type domtype = libxl__domain_type(gc, domid);
> +
> +    /* Interpret incoming */
> +    usbdev = &_usbdev;
> +
> +    usbdev->target_domid = domid;
> +    usbdev->dm_domid = libxl_get_stubdom_id(ctx, domid);
> +
> +    usbdev_ext_to_int(usbdev, dev_ext);
> +
> +    if ( usbdev->protocol == LIBXL_USB_PROTOCOL_AUTO ) {
> +        if ( domtype == LIBXL_DOMAIN_TYPE_PV ) {
> +            usbdev->protocol = LIBXL_USB_PROTOCOL_PV;
> +        } else if (domtype == LIBXL_DOMAIN_TYPE_HVM) {
> +            /* FIXME: See if we can detect PV frontend */
> +            usbdev->protocol = LIBXL_USB_PROTOCOL_DEVICEMODEL;
> +        }
> +    }
> +
> +    /* Check to make sure we're doing something that's impemented */
> +    if ( usbdev->protocol != LIBXL_USB_PROTOCOL_DEVICEMODEL ) {
> +        rc = ERROR_FAIL;
> +        LOG(ERROR, "Protocol not implemented");
> +        goto out;
> +    }
> +
> +    if ( usbdev->dm_domid != 0 ) {
> +        rc = ERROR_FAIL;
> +        LOG(ERROR, "Stubdoms not yet supported");
> +        goto out;
> +    }
> +
> +    /* Double-check to make sure it's not already assigned */
> +    rc = get_assigned_devices(gc, domid, &assigned, &num_assigned);
> +    if ( rc ) {
> +        LOG(ERROR, "cannot determine if device is assigned, refusing to 
> continue");
> +        goto out;
> +    }
> +    if ( is_usbdev_in_array(assigned, num_assigned, usbdev) ) {
> +        LOG(ERROR, "USB device already attached to a domain");
> +        rc = ERROR_FAIL;
> +        goto out;
> +    }
> +
> +    /* Do the add */
> +    if ( do_usb_add(gc, domid, usbdev) )
> +        rc = ERROR_FAIL;

Spaces between "(" and conditions in this function.

> +
> +out:
> +    return rc;
> +}
> +
> +int libxl_device_usb_add(libxl_ctx *ctx, uint32_t domid,
> +                         libxl_device_usb *usbdev,
> +                         const libxl_asyncop_how *ao_how)
> +{
> +    AO_CREATE(ctx, domid, ao_how);
> +    int rc;
> +    rc = libxl__device_usb_add(gc, domid, usbdev);
> +    libxl__ao_complete(egc, ao, rc);
> +    return AO_INPROGRESS;
> +}
> +
> +/*
> + * USB remove
> + */
> +static int do_usb_remove(libxl__gc *gc, uint32_t domid,
> +                         libxl__device_usb *usbdev)
> +{
> +    int rc;
> +
> +    switch (usbdev->protocol) {
> +    case LIBXL_USB_PROTOCOL_DEVICEMODEL:
> +        switch (libxl__device_model_version_running(gc, domid)) {
> +        case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL:
> +            LOG(ERROR, "usb-remove not yet implemented for 
> qemu-traditional");
> +            return ERROR_INVAL;
> +        case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN:
> +            if ( (rc = libxl__qmp_usb_remove(gc, domid, usbdev)) < 0 )

Spaces

> +                goto out;
> +            break;
> +        default:
> +            return ERROR_INVAL;
> +        }
> +        break;
> +    default:
> +        return ERROR_FAIL;
> +    }
> +
> +    rc = usb_remove_xenstore(gc, domid, usbdev);
> +out:
> +    return rc;
> +}
> +static int libxl__device_usb_remove(libxl__gc *gc, uint32_t domid,
> +                                    libxl_device_usb *dev_ext)
> +{
> +    libxl_ctx *ctx = libxl__gc_owner(gc);
> +    libxl__device_usb *assigned, _usbdev, *usbdev;
> +    int rc = ERROR_FAIL, num_assigned;
> +    libxl_domain_type domtype = libxl__domain_type(gc, domid);
> +
> +    /* Interpret incoming */
> +    usbdev = &_usbdev;
> +
> +    usbdev->target_domid = domid;
> +    usbdev->dm_domid = libxl_get_stubdom_id(ctx, domid);
> +
> +    usbdev_ext_to_int(usbdev, dev_ext);
> +
> +    if ( usbdev->protocol == LIBXL_USB_PROTOCOL_AUTO ) {
> +        if ( domtype == LIBXL_DOMAIN_TYPE_PV ) {
> +            usbdev->protocol = LIBXL_USB_PROTOCOL_PV;
> +        } else if (domtype == LIBXL_DOMAIN_TYPE_HVM) {
> +            /* FIXME: See if we can detect PV frontend */
> +            usbdev->protocol = LIBXL_USB_PROTOCOL_DEVICEMODEL;
> +        }
> +    }
> +
> +    /* Check to make sure we're doing something that's impemented */
> +    if ( usbdev->protocol != LIBXL_USB_PROTOCOL_DEVICEMODEL ) {
> +        rc = ERROR_FAIL;
> +        LOG(ERROR, "Protocol not implemented");
> +        goto out;
> +    }
> +
> +    if ( usbdev->dm_domid != 0 ) {
> +        rc = ERROR_FAIL;
> +        LOG(ERROR, "Stubdoms not yet supported");
> +        goto out;
> +    }
> +
> +    /* Double-check to make sure it's not already assigned */
> +    rc = get_assigned_devices(gc, domid, &assigned, &num_assigned);
> +    if ( rc ) {
> +        LOG(ERROR, "cannot determine if device is assigned, refusing to 
> continue");
> +        goto out;
> +    }
> +    if ( !is_usbdev_in_array(assigned, num_assigned, usbdev) ) {
> +        LOG(ERROR, "USB device doesn't seem to be attached to the domain");
> +        rc = ERROR_FAIL;
> +        goto out;
> +    }
> +
> +    /* Do the remove */
> +    if ( do_usb_remove(gc, domid, usbdev) )
> +        rc = ERROR_FAIL;
> +

Again spaces in almost the whole function

> +out:
> +    return rc;
> +}
> +
> +int libxl_device_usb_remove(libxl_ctx *ctx, uint32_t domid,
> +                            libxl_device_usb *usbdev,
> +                            const libxl_asyncop_how *ao_how)
> +{
> +    AO_CREATE(ctx, domid, ao_how);
> +    int rc;
> +    rc = libxl__device_usb_remove(gc, domid, usbdev);
> +    libxl__ao_complete(egc, ao, rc);
> +    return AO_INPROGRESS;
> +}
> +
> +
> +libxl_device_usb *libxl_device_usb_list(libxl_ctx *ctx,
> +                                        uint32_t domid, int *num)
> +{
> +    GC_INIT(ctx);
> +    libxl__device_usb *devint;
> +    libxl_device_usb *devext = NULL;
> +    int n = 0, i, rc;
> +
> +    rc = get_assigned_devices(gc, domid, &devint, &n);
> +    if ( rc ) {
> +        LOG(ERROR, "Could not get assigned devices");
> +        goto out;
> +    }
> +
> +    if(n == 0)
> +        goto out;
> +
> +    devext = calloc(n, sizeof(libxl_device_usb));

libxl__calloc, also you seem to leak this allocation, which will be
solved by the use of libxl__calloc.

> +
> +    for (i = 0; i < n; i++)
> +        usbdev_int_to_ext(devext + i, devint + i);
> +
> +    *num = n;
> +out:
> +    GC_FREE;
> +    return devext;
> +}
> diff --git a/tools/ocaml/libs/xl/genwrap.py b/tools/ocaml/libs/xl/genwrap.py
> index ea978bf..aab65f3 100644
> --- a/tools/ocaml/libs/xl/genwrap.py
> +++ b/tools/ocaml/libs/xl/genwrap.py
> @@ -286,6 +286,7 @@ if __name__ == '__main__':
>          "domain_config",
>          "vcpuinfo",
>          "event",
> +        "device_usb"
>          ]
> 
>      for t in blacklist:
> --
> 1.7.9.5
> 


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.