Re: [RFC] usbfs2 aio cancellation code

Alan Stern <[email protected]>
Newsgroups gmane.linux.usb.devel
Message-ID <[email protected]>
On Tue, 2 Oct 2007, Zach Brown wrote:

> > Do things really need to be this complicated?
>
> Do you think the reply I sent to Sarah safely relies on usb_unlink_urb
> ()?  I don't know if it provides the guarantees which that proposal
> would rely on.
 
The guarantees it provides aren't exactly what Sarah wrote, but
they are close.
 
> What happens if you call usb_unlink_urb() after the URB callback has  
> been called?

Then usb_unlink_urb() fails.  But it might not return -EBUSY; it might
return some other error code instead.

> I'm hoping that we can *just* call usb_unlink_urb() from ki_cancel  
> and *always* return -EBUSY.  The URB callback will either be called  
> very soon on error or will already be in flight or have been called.

Right, there's no point in having ki_cancel ever complete an aio 
operation.  The operation should complete when the URB completes, 
whether it succeeded, was unlinked, or encountered some other error.

> The trick there is to make sure that the URB callback doesn't free  
> resources that ki_cancel needs to be able to call usb_unlink_urb() to  
> find that it's already been called.  I would propose putting a struct  
> on iocb->private which is freed in the ki_dtor method.  It's called  
> once all the iocb references have been dropped.

Agreed.

> Hmm.  If usb_unlink_urb() returns 0 then operation is still in  
> flight, right?

No.  usb_unlink_urb() is weird; it returns -EINPROGRESS to indicate
success.  Don't ask me why.  Presumably that will be fixed eventually.

But even when usb_unlink_urb() succeeds, it doesn't mean that the URB
is still in flight when the function call returns.  The URB may have
already completed.  And conversely, when usb_unlink_urb() fails, it
doesn't mean the URB has completed yet.

> I got lost in the pseudo code for testing for cancelation and  
> things.  How about this:
> 
> aio_ method:
> 	/* this does not race with ki_cancel */
> 	iocb->private = alloc_urb_goo();
> 	iocb->ki_dtor = free_urb_goo();
> 	queue URB callback
> 	if (read) {
> 		iocb->ki_retry = copy_read_result();
> 		return -EIOCBRETRY:
> 	} else
> 		return -EIOCBQUEUED:
> 
> URB callback:
> 	/* usb_unlink_urb() protects the race with ki_cancel */
> 	/* this cannot race with ki_retry, it triggers it */
> 	if (read)
> 		kick_iocb();
> 	else
> 		aio_complete();
> 
> copy_read_result:
> 	if (error)
> 		return error'
> 	copy_to_user();
> 	return bytes_copied;
> 
> ki_retry:

You mean ki_cancel:

> 	some_usb_goo = iocb->private;
> 	/* usb_unlink_urb() protects us from races */
> 	/* urb goo won't be freed until ki_dtor, which we hold a reference  
> for */
> 	usb_unlink_urb(some_usb_goo);
> 	return -EBUSY;
> 
> ki_dtor:
> 	free(iocb->private);
> 
> That should work, presuming that usb_unlink_urb() has strong internal  
> serialization to have calls from ki_cancel fail if the callback is  
> pending or has been completed already.

Yes, I think this will work.

Alan Stern


-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.