Re: usb: core: URB completer callback possibly called after usb_kill_anchored_urbs() returns

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

 



On Sat, Jul 25, 2020 at 07:44:02PM +0300, Eli Billauer wrote:
> Hello Alan & all,
> 
> Thanks for your response.
> 
> The thing is that I'm not alone assuming that it's fine to free resources
> after usb_kill_anchored_urbs() returns. Most notable is usb-skeleton.c,
> which does exactly that in skel_disconnect():
> 
>     usb_kill_anchored_urbs(&dev->submitted);
> 
>     /* decrement our usage count */
>     kref_put(&dev->kref, skel_delete);
> 
> Needless to say, skel_delete() frees the struct that the URBs' contexts
> point at.
> 
> Keeping track of the number of uncompleted URBs, as you suggested, is indeed
> a solution. But as it seems that the only problem is the race condition
> between usb_kill_anchored_urbs() and __usb_hcd_giveback_urb(), I suppose
> it's enough to ensure that the resources are not freed while
> __usb_hcd_giveback_urb() is doing its unanchor-before-complete thing.
> 
> After taking a second look, I discovered that there's already a function
> that takes the race condition into consideration:
> usb_wait_anchor_empty_timeout().
> 
> Looking again at commit 6ec4147, which I mentioned before, it turns out that
> it added a counter to each anchor struct (atomic_t suspend_wakeups). It's
> incremented in __usb_hcd_giveback_urb() just before unanchoring a URB, and
> decremented after the completion has been called. This is made with calls to
> usb_anchor_suspend_wakeups() and usb_anchor_resume_wakeups(), but that's the
> essence of these calls.
> 
> And there's a wait queue in place, which gets a wakeup call by
> usb_anchor_resume_wakeups(), if the anchor's list is empty and the counter
> is zero after decrementing it. In the said commit,
> usb_wait_anchor_empty_timeout() was modified to check the counter as well,
> so when it returns, the anchor is genuinely idle.
> 
> So I would say that the safe way to go is
> 
>   usb_kill_anchored_urbs(&ep->anchor);
>   if (!usb_wait_anchor_empty_timeout(&ep->anchor, 1000)) {
>      /* This is really bad */
>   }
>   /* Release memory */
> 
> And if indeed so, I'm thinking about submitting a patch, which adds a
> usb_wait_anchor_empty_timeout() at the bottom of usb_kill_anchored_urbs().
> So that the function does what people out there think it does.
> 
> Have I missed something?

That sounds like a good proposal to me.  The 1-second timeout is 
somewhat arbitrary, but I guess it's okay since we expect unlink 
operations to be pretty quick.

Alan Stern



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux