[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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |