|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] çåï Re: [PATCH V3 3/6] libxl: add pvusb API
>>> å 2:06 ç 2015/5/20 äïåèæ
<CAFLBxZZHFFWo6Tm7602y3+x5kX65-w4obFS1VdVb8KqnzdAmDg@xxxxxxxxxxxxxx> äïGeorge
Dunlap <George.Dunlap@xxxxxxxxxxxxx> ååï
> On Sun, Apr 19, 2015 at 4:50 AM, Chunyan Liu <cyliu@xxxxxxxx> wrote:
> > Add pvusb APIs, including:
> > - attach/detach (create/destroy) virtual usb controller.
> > - attach/detach usb device
> > - list usb controller and usb devices
> > - some other helper functions
> >
> > Signed-off-by: Chunyan Liu <cyliu@xxxxxxxx>
> > Signed-off-by: Simon Cao <caobosimon@xxxxxxxxx>
>
> OK, getting closer. :-)
>
> A number of comments:
Hi, George, thanks very much!
I'm so sorry for missing the message and not reply immediately.
Before sending new version, I'm answering some of your questions here.
And there are a couple of comments, I still have some hesitation to follow.
All others, I agree and will update as you suggested.
>
> > diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
> > index 6bc75c5..cbe3519 100644
> > --- a/tools/libxl/libxl.h
> > +++ b/tools/libxl/libxl.h
> > @@ -114,6 +114,12 @@
> > #define LIBXL_HAVE_DOMAIN_NODEAFFINITY 1
> >
> > /*
> > + * LIBXL_HAVE_PVUSB indicates the functions for doing hot-plug of
> > + * USB devices through pvusb.
> > + */
> > +#define LIBXL_HAVE_PVUSB 1
>
> It seems like we should document somewhere how we expect these to be
> used -- namely the connection between usbctrl and usb devices. In
> particular, that you can either add a usbctrl, and then add a usb
> device to it specifically; or if you don't specify a usbctrl when
> calling usb_add, it will find the most reasonable one to add it to,
> even creating one for you if you didn't have one.
>
>
> > diff --git a/tools/libxl/libxl_pvusb.c b/tools/libxl/libxl_pvusb.c
> > new file mode 100644
> > index 0000000..4e4975a
> > --- /dev/null
> > +++ b/tools/libxl/libxl_pvusb.c
>
> > +int libxl__device_usbctrl_add(libxl__gc *gc, uint32_t domid,
> > + libxl_device_usbctrl *usbctrl)
> > +{
> > + int rc = 0;
> > +
> > + rc = libxl__device_usbctrl_setdefault(gc, domid, usbctrl);
> > + if (rc < 0) goto out;
> > +
> > + if (usbctrl->devid == -1) {
>
> Hmm, I was doing to say that this shouldn't be a magic constant, but
> it looks like that's what all the other devices do :-/
>
> > +static bool is_usb_in_array(libxl_device_usb *usbs, int num,
> > + libxl_device_usb *usb)
> > +{
> > + int i;
> > +
> > + for (i = 0; i < num; i++) {
> > + if (!strcmp(usbs[i].busid, usb->busid) )
>
> Here (and elsewhere) you should probably use the COMPARE_USB() macro
> you define in this patch.
>
> > +/* check if USB device type is assignable */
> > +static bool is_usb_assignable(libxl__gc *gc, libxl_device_usb *usb)
> > +{
> > + libxl_ctx *ctx = libxl__gc_owner(gc);
> > + int classcode;
> > + char *filename;
> > + void *buf;
> > +
> > + assert(usb->busid);
> > +
> > + filename = GCSPRINTF(SYSFS_USB_DEV"/%s/bDeviceClass", usb->busid);
> > + if (libxl_read_file_contents(ctx, filename, &buf, NULL) < 0)
> > + return false;
> > +
> > + sscanf(buf, "%x", &classcode);
> > + if (classcode == USBHUB_CLASS_CODE)
> > + return false;
> > +
> > + return true;
>
> Just checking, is it really the case that *all* USB classes are
> assignable, *except* for hubs?
Referring to xm pvusb implementation, only HUB is excluded, so I
just keep the same.
>
> This is a minor thing, but this might be simper to do this:
>
> return classcode != USBHUB_CLASS_CODE;
>
> > +/* get usb devices under certain usb controller */
> > +static int libxl__device_usb_list(libxl__gc *gc, uint32_t domid, int
> usbctrl,
> > + libxl_device_usb **usbs, int *num)
> > +{
> > + char *be_path, *num_devs;
> > + int n, i;
> > +
> > + *usbs = NULL;
> > + *num = 0;
> > +
> > + be_path = GCSPRINTF("%s/backend/vusb/%d/%d",
> > + libxl__xs_get_dompath(gc, 0), domid, usbctrl);
> > + num_devs = libxl__xs_read(gc, XBT_NULL,
> > + GCSPRINTF("%s/num-ports", be_path));
> > + if (!num_devs)
> > + return 0;
> > +
> > + n = atoi(num_devs);
> > + *usbs = calloc(n, sizeof(libxl_device_usb));
> > +
> > + for (i = 0; i < n; i++) {
> > + char *busid;
> > + libxl_device_usb *usb = NULL;
> > +
> > + busid = libxl__xs_read(gc, XBT_NULL,
> > + GCSPRINTF("%s/port/%d", be_path, i + 1));
> > + if (busid && strcmp(busid, "")) {
> > + usb = *usbs + *num;
> > + usb->ctrl = usbctrl;
> > + usb->port = i + 1;
> > + usb->busid = strdup(busid);
>
> This needs to populate the hostbus / hostaddr as well; busid is pretty
> useless to users / external callers.
I thought about that when implementing, but finally not added to codes
considering:
* for all libxl pvusb internal usage, busid is enough.
* for toolstack usage, if we want to expose users useful information about
bus:addr,
vendorID:devieID, we have libxl_device_usb_getinfo API, with this API callers
can get
all information including hostbus, hostaddr.
If that couldn't satisfy qemu usage, I can add a translating to fill in hostbus
and
hostaddr too.
>
> > +/* get all usb devices of the domain */
> > +static libxl_device_usb *
> > +libxl_device_usb_list_all(libxl__gc *gc, uint32_t domid, int *num)
> > +{
> > + char **usbctrls;
> > + unsigned int nd, i, j;
> > + char *be_path;
> > + int rc;
> > + libxl_device_usb *usbs = NULL;
> > +
> > + *num = 0;
> > +
> > + be_path = GCSPRINTF("/local/domain/%d/backend/vusb/%d",
> > + LIBXL_TOOLSTACK_DOMID, domid);
> > + usbctrls = libxl__xs_directory(gc, XBT_NULL, be_path, &nd);
> > +
> > + for (i = 0; i < nd; i++) {
> > + int nc = 0;
> > + libxl_device_usb *tmp = NULL;
> > + rc = libxl__device_usb_list(gc, domid, atoi(usbctrls[i]), &tmp,
> &nc);
> > + if (!nc) continue;
> > +
> > + usbs = realloc(usbs, sizeof(libxl_device_usb)*((*num) + nc));
> > + for(j = 0; j < nc; j++) {
> > + usbs[*num].ctrl = tmp[j].ctrl;
> > + usbs[*num].port = tmp[j].port;
> > + usbs[*num].busid = strdup(tmp[j].busid);
>
> This needs to copy the hostaddr and busaddr as well, as these are
> primarily what an external caller will want.
Same to above.
>
> > +/* find first unused controller:port and give that to usb device */
> > +static int
> > +libxl__device_usb_set_default_usbctrl(libxl__gc *gc, uint32_t domid,
> > + libxl_device_usb *usb)
> > +{
> > + libxl_ctx *ctx = CTX;
> > + libxl_device_usbctrl *usbctrls;
> > + libxl_device_usb *usbs = NULL;
> > + int numctrl, numusb, i, j, rc = -1;
> > + char *be_path, *tmp;
> > +
> > + usbctrls = libxl_device_usbctrl_list(ctx, domid, &numctrl);
> > + if ( !numctrl)
> > + goto out;
> > +
> > + for (i = 0; i < numctrl; i++) {
> > + rc = libxl__device_usb_list(gc, domid, usbctrls[i].devid,
> > + &usbs, &numusb);
> > + if (rc) continue;
> > +
> > + if (!usbctrls[i].ports || numusb == usbctrls[i].ports)
> > + continue;
> > +
> > + for (j = 1; i <= numusb; j++) {
>
> Port numbers start at 1, do they? Interesting...
Keep same as xm implementation. I think that should be proved right.
>
> Er, but isn't the middle thing just plain wrong? For one, you want to
> be comparing j not i. I can't see that i is updated inside the loop,
> so ATM this will loop forever.
>
> For two, you want to compare to usbctrls[i].ports (the total number of
> ports), not to numusb (the number of currently assigned devices).
>
> > +static int libxl__device_usb_setdefault(libxl__gc *gc, uint32_t domid,
> > + libxl_device_usb *usb)
> > +{
> > + char *be_path, *tmp;
> > +
> > + if (usb->ctrl == -1) {
>
> Oh, right -- libxl_devid's default to -1, don't they? I'll save the
> grumbling about the lack of a #define here then. (Or rather, I'll
> grumble at the library rather than you.)
>
> > + int ret = libxl__device_usb_set_default_usbctrl(gc, domid, usb);
> > + /* If no existing ctrl to host this usb device, setup a new one */
> > + if (ret) {
> > + libxl_device_usbctrl usbctrl;
> > + libxl_device_usbctrl_init(&usbctrl);
> > + libxl__device_usbctrl_add(gc, domid, &usbctrl);
>
> I think in the previous round I asked what would happen if this
> failed, and you said you would fail later, but that you'd change it to
> check for an error here and bail out earlier.
>
> > +/* Cann't write '.' or ':' into Xenstore as key. So, change '.' to '_',
> > + * change ':' to '-'.
> > + */
> > +static char *usb_interface_encode(char *busid)
>
> Maybe usb_interface_xenstore_encode, to make it clear that you're just
> encoding it to store in xenstore?
>
> > +static int usbback_dev_unassign(libxl__gc *gc, libxl_device_usb *usb)
> > +{
> > + char **intfs = NULL;
> > + char *path;
> > + int num = 0, i;
> > + int rc = 0;
> > + char *usb_encode = NULL;
> > +
> > + if (usb_get_all_interfaces(gc, usb, &intfs, &num) < 0)
> > + return ERROR_FAIL;
> > +
> > + usb_encode = usb_interface_encode(usb->busid);
> > +
> > + for (i = 0; i < num; i++){
> > + char *intf = intfs[i];
> > + char *drvpath = NULL;
> > +
> > + if (usb_intf_is_assigned(gc, intf) > 0) {
> > + /* unbind interface from usbback driver */
> > + if (unbind_usb_intf(gc, intf, NULL) < 0) {
> > + rc = ERROR_FAIL;
> > + goto out;
> > + }
> > + }
> > +
> > + /* bind interface to its originial driver */
> > + drvpath = libxl__xs_read(gc, XBT_NULL,
> > + GCSPRINTF(USBBACK_INFO_PATH"/%s/%s/driver_path",
> > + usb_encode, usb_interface_encode(intf)));
> > + if (drvpath) {
> > + if (bind_usb_intf(gc, intf, drvpath) < 0) {
> > + LOGE(ERROR, "Couldn't bind %s to %s", intf, drvpath);
> > + rc = ERROR_FAIL;
> > + goto out;
>
> I think this function probably shouldn't fail if it can't re-bind to
> the original driver. If nothing else, this will be bad because now
> the USB device has at least one of its interfaces unbound from
> usbback, but the other ones still bound to it. All interfaces should
> be unbound from usbback regardless.
>
> I also think that while a warning should be logged, that the function
> as a whole should return success if it managed to unbind, even if it
> didn't manage to rebind. (But feel free to argue otherwise.)
>
> > diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
> > index 0866433..a6db614 100644
> > --- a/tools/libxl/libxl_types.idl
> > +++ b/tools/libxl/libxl_types.idl
> > @@ -533,6 +533,22 @@ libxl_device_pci = Struct("device_pci", [
> > ("seize", bool),
> > ])
> >
> > +libxl_device_usbctrl = Struct("device_usbctrl", [
> > + ("devid", libxl_devid),
> > + ("version", integer),
> > + ("ports", integer),
> > + ("backend_domid", libxl_domid),
> > + ("backend_domname", string),
> > + ])
> > +
> > +libxl_device_usb = Struct("device_usb", [
> > + ("ctrl", libxl_devid),
> > + ("port", integer),
> > + ("busid", string),
>
> So it looks like "busid" is purely an internal string that you're
> putting in the device struct for convenience, so that you don't have
> to either keep translating bus:addr into the sysfs node, or pass
> around the second string as well. Is that right?
Yes, right. Actually in libxl pvusb, internally it uses busid, hostbus:hostaddr
is only a toolstack interface.
It is 'busid' saved in xenstore for pvusb driver's usage, and everywhere
comparing
work (e.g. check usb device existence before removing a usb device) it uses
'busid' to compare. So having a struct element is very convenient, otherwise,
there
are many places that need to translate from busid to/from bus:addr.
Personally I still prefer to keep 'busid', but if that's really unacceptable,
I can also update.
- Chunyan
>
> I think libxl does something similar to this with "backend_domname"
> and "backend_domid"; but in that case I believe you *can* specify the
> backend_domid if you want to. In this case, you're exposing a struct
> element which is clobbered immediately, at least by usb_add and
> usb_remove.
>
> Maintainers, what do you think?
>
> Other than that, I think this patch as-is looks in pretty good shape
> (haven't taken a close look at the rest in the series yet); the
> primary things are making the "hostbus:hostaddr" actually the primary
> interface; at a minimum filling in that information when doing
> queries. I'd ideally getting rid of "busid" from the external
> interface altogether.
>
> -George
>
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@xxxxxxxxxxxxx
> http://lists.xen.org/xen-devel
>
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |