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

Re: [Xen-devel] [PATCH V8 3/7] libxl: add pvusb API




>>> On 11/13/2015 at 01:00 AM, in message
<22084.50631.506663.212889@xxxxxxxxxxxxxxxxxxxxxxxx>, Ian Jackson
<Ian.Jackson@xxxxxxxxxxxxx> wrote: 
> Chun Yan Liu writes ("Re: [PATCH V8 3/7] libxl: add pvusb API"): 
> > On 11/10/2015 at 02:11 AM, in message 
> > <22080.57829.461049.37192@xxxxxxxxxxxxxxxxxxxxxxxx>, Ian Jackson 
> > <Ian.Jackson@xxxxxxxxxxxxx> wrote:  
> > > Chunyan Liu writes ("[PATCH V8 3/7] libxl: add pvusb API"):  
> > > > +void libxl__device_usbctrl_add(libxl__egc *egc, uint32_t domid,  
> > > > +                               libxl_device_usbctrl *usbctrl,  
> > > > +                               libxl__ao_device *aodev)  
> > > > +{  
> > >   
> > > Thanks for adjusting the error-handling patterns in these functions.  
> > > The new way is good, except that:  
> > >   
> > > > +out:  
> > > > +    aodev->rc = rc;  
> > > > +    if (rc) aodev->callback(egc, aodev);  
> > >   
> > > Here, rc is always set, and indeed the code would be wrong if it were  
> > > not.  So can you remove the conditional please ?  Ie:  
> >  
> > Reading the codes, libxl__wait_device_connection will call 
> > aodev->callback properly. 
>  
> Indeed.  So you need to call aodev->callback() iff you don't call 
> libxl__wait_device_connection.  But libxl__wait_device_connection is 
> called only on the success exit path which ends in `return', not in 
> `goto out'.  So: 
>  
> > So here, only if (rc != 0), that means 
> > error happens, then we need to call aodev->callback to end the 
> > process. (Refer to current libxl__device_disk_add, all current code 
> > does similar work.) So I think the code is not wrong (?) 
>  
> In the `goto out' path, rc is always set.  Writing `if (rc)' implies 
> that it might not be (or is allowed not to be), which is misleading.

I'm convinced your suggestion is better :-). I'll adjust codes.
 
>  
>  
> > > > +static int usb_busaddr_from_busid(libxl__gc *gc, const char *busid,  
> > > > +                                  uint8_t *bus, uint8_t *addr)  
> > > > +{  
> > > > +    char *filename;  
> > > > +    void *buf;  
> > > > +  
> > > > +    filename = GCSPRINTF(SYSFS_USB_DEV"/%s/busnum", busid);  
> > > > +    if (!libxl__read_sysfs_file_contents(gc, filename, &buf, NULL))  
> > > > +        *bus = atoi((char *)buf);  
> > >   
> > > I don't think this cast (and the one for addr) are necessary ?  
> >  
> > Which cast? Here, we want to get a uint_8 value, but buf is a string, 
> > we need to do atoi. 
>  
> I mean that I think 
>  
>      +        *bus = atoi(buf);  
>  
> would compile and be correct.  buf would be automatically converted 
> from void* to const char*.  It's better to avoid casts where they are 
> not needed, because casts will suppress compiler warnings. 

Yes, you're right. Thanks very much!

>  
> For example if someone wanted to have the buffer be an updated 
> parameter they might do this: 
>  
>   static int usb_busaddr_from_busid(libxl__gc *gc, const char *busid,  
> +                                   void **buf, 
>                                     uint8_t *bus, uint8_t *addr) 
> -    void *buf;  
>  
> and hope or expect the compiler to notice places where they had failed 
> to update the usage of buf.  With void **buf, 
>   atoi((char*)buf) 
> would compile and do a wrong thing whereas 
>   atoi(buf) 
> would produce a fatal warning. 
>  
> > > > +/* bind/unbind usb device interface */  
> > > > +static int unbind_usb_intf(libxl__gc *gc, char *intf, char **drvpath)  
> > > > +{  
> ... 
> > > > +        dp = libxl__zalloc(gc, PATH_MAX);  
> > > > +        dp = realpath(spath, dp);  
> > >   
> > > Why is this call to realpath needed ? 
> >  
> > In sysfs, /driver sometimes is a link, since we need to save the original 
> > driver to xenstore, so need to get the realpath of the driver. 
>  
> I mean, why is the path with all the symlinks in it not suitable for 
> storage and later use ? 

The symlink might be "../../../../../../bus/usb/drivers/btusb", we couldn't save
that to xenstore for later usage.

>  
>  
> > > > +static int usbback_dev_unassign(libxl__gc *gc, libxl_device_usb *usb)  
> > > > +{  
> > > ...  
> > > > +        /* 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_xenstore_encode(intf)));  
> > > > +        if (drvpath && bind_usb_intf(gc, intf, drvpath))  
> > > > +            LOGE(WARN, "Couldn't bind %s to %s", intf, drvpath);  
> > >   
> > > This error message could be clearer.  
> > >   
> > > Also it would be worth a comment in the code to explain why this is a  
> > > warning (merely logged), rather than an error (logged and reported  
> > > with nonzero status to caller). 
> >  
> > Will update. When doing USB remove, it's the ideal result we can rebound 
> > the USB to its original driver, in case the USB interface failed to be 
> > rebound to its original driver, we will export warning but won't stop the 
> > removing process. 
>  
> Right.  Please put that in a comment :-). 
>  
>  
> > > > +static int usbback_dev_assign(libxl__gc *gc, libxl_device_usb *usb)  
> > > > +{  
> > > ...  
> > > > +            if (libxl__xs_write_checked(gc, XBT_NULL, path, drvpath) < 
> > > > 0)  
> {  
> > > > +                LOG(WARN, "Write of %s to node %s failed", drvpath,  
> path);  
> > > > +            }  
> > >   
> > > One of the advantages of libxl__xs_write_checked is that it logs  
> > > errors.  So you can leave that log message out.  
> > >   
> > > However, if the xs write fails, you should presumably stop, rather  
> > > than carrying on.  
> > >  
> > > I think you probably do things in the wrong order here.  You should  
> > > write the old driver info to xenstore first, so that if the bind to  
> > > usbback fails, you have the old driver info.  
> >  
> > Perhaps not. Once we finished adding entries to xenstore, pvusb 
> > frontend/backend drivers will detect the change and do probe work, if 
> > USB device is still not bound to USBBACK, there might be error. 
>  
> What I mean is this: 
>  
> Is it not possible to write the original path to xenstore before doing 
> the unbind ?  Otherwise it seems like there could be error paths where 
> the original path is not recorded, the xenstore write fails, and then 
> the information about how to rebind to the original driver has been 
> lost. 

I see. 

>  
> Does writing USBBACK_INFO_PATH"/%s/%s/driver_path" really trigger 
> usbback ? 

No, writing driver_path info to xenstore won't trigger usbback. Writing
frontend/backend info will.

>  
> > > > +    free(usb_encode);  
> > >   
> > > This came from the gc, I think.  
> ... 
> > > > +    switch (usbctrlinfo.type) {  
> > > > +    case LIBXL_USBCTRL_TYPE_DEVICEMODEL:  
> > > > +        LOG(ERROR, "Not supported");  
> > > > +        break;  
> > >   
> > > Needs to set rc.  
>  
> (Did you spot these comments ?  Normally I wouldn't even expect you to 
> quote the comments that you are just going to fix, but since you have 
> replied to the others, I thought I would check.)

No, it's definitely right, so I'll fix surely.
 
>  
>  
> > > > +void libxl__device_usb_add(libxl__egc *egc, uint32_t domid,  
> > > > +                           libxl_device_usb *usb,  
> > > > +                           libxl__ao_device *aodev)  
> > > > +{  
> > > ...  
> > > > +        if (usbctrlinfo.backend_id != 0) {  
> > >   
> > > LIBXL_TOOLSTACK_DOMID please.  (And in remove, too.)  
> > >   
> > > Why is this check done in libxl__device_usb_add and do_usb_remove,  
> > > rather than in a symmetrical way? 
> >   
> > In libxl__device_usb_add, the set_default function implementation won't 
> > work if backend domain is USB driver domain in future, so we must add 
> > a check before set_default, so in libxl__device_usb_add. To check backend 
> > domain, we need to get usbctrl info. And in do_usb_add, to check usbctrl 
> > type, again we need to get usbctrl info. It's disgusting to do the same  
> thing 
> > twice. 
> >  
> > In usb remove, nothing in libxl__device_usb_remove is Dom0 specific, so 
> > I do all check in do_usb_remove, then only one time to get usbctrl info. 
>  
> Right. 
>  
> > If we merge libxl__device_usb_add and do_usb_add, then it's cleaner. 
>  
> See my comment below.  You've explained the distinction to my 
> satisfaction. 
>  
> But, to solve the duplication of the controller info acquisition, 
> perhaps you could have do_usb_add take the controller info as a 
> paramaeter ?

Yes, could be. Only do_usb_add and do_usb_remove parameters are not
symmetrical. 

>  
>  
> > > > +    /* Do the add */  
> > > > +    if (do_usb_add(gc, domid, usb, aodev)) {  
> > > > +        rc = ERROR_FAIL;  
> > > > +        goto out;  
> > > > +    }  
> > > > +  
> > > > +    libxl__ao_complete(egc, ao, 0);  
> > > > +    rc = 0;  
> > > > +  
> > > > +out:  
> > > > +    libxl_device_usbctrl_dispose(&usbctrl);  
> > > > +    libxl_usbctrlinfo_dispose(&usbctrlinfo);  
> > > > +    aodev->rc = rc;  
> > > > +    if (rc) aodev->callback(egc, aodev);  
> > > > +    return;  
> > >   
> > > Calling libxl__ao_complete here is quite wrong.  I think you should  
> > > call aodev->callback in both success and failure cases.  And it must  
> > > be the last thing you do.  
> >  
> > As mentioned in libxl__device_usbctrl_add, libxl__ao_complete will 
> > call callback, so in 'out' section, only if (rc !=0), which means 
> > error happens, then we need to call aodev->callback explicitly to 
> > end the process. 
> >  
> > Here, since we don't have actual async work needs to do, so call 
> > libxl__ao_complete(egc, ao, 0) directly to end the process. 
>  
> I'm afraid this is definiitely wrong.  There are a number of things 
> wrong with it, or a number of ways of looking at it: 
>  
> Most obviously, a single entrypoint should always complete its 
> execution the same way.  In this case the entrypoint takes an aodev 
> and in the error path calls aodev->callback().  So it should do the 
> same on the success path. 
>  
> Secondly (and relatedly), it is generally wrong for anything inside a 
> particular piece of machinery to terminate an ao. 
>  
> In this particular case I think it leads to a use-after-free bug: 
> completing the ao will (maybe) free the ao, and aodev was allocated 
> from the ao's gc.  So the write to aodev->rc is improper. 

Reasonable, I'll adjust codes. Thanks!

- Chunyan

>  
>  
> > > I might ask the same question about do_usb_add and  
> > > libxl__device_usb_add ?  
> >  
> > Using libxl__device_usb_add and within it extracting do_usb_add is to: 
> > * doing some initialization work and necessary check work in 
> >   libxl__device_usb_add (this part are common to PVUSB and QEMU USB) 
> > * doing actual adding usb operations in do_usb_add (this part will diverge 
> >   for PVUSB and QEMU USB) . 
>  
> This is a good reason for keeping them split.  Thanks for the 
> explanation. 
>  
>  
> Thanks for your other replies. 
>  
> Regards, 
> Ian. 
>  
>  


_______________________________________________
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®.