On Mon, 16 Jan 2017, Felipe Balbi wrote: > >>>> Another point here is that the really robust way of fixing this is to > >>>> get rid of USB_GADGET_DELAYED_STATUS altogether and just make sure > >>>> gadget drivers know how to queue requests for all three phases of a > >>>> Control Transfer. > >>>> > >>>> A lot of code will be removed from all gadget drivers and UDC drivers > >>>> while combining all of it in a single place in composite.c. Don't forget the legacy drivers. > >>>> > >>>> The reason I'm saying this is that other UDC drivers might have similar > >>>> races already but they just haven't triggered. > >> Alright, it's important enough to fix this bug. Can you also have a look > >> into dropping USB_GADGET_DELAYED_STATUS altogether? If you're too busy, > >> no issues. It'll stay in my queue. > > > > Okay, I will have a look at f_mass_storage driver to see if we can > > drop USB_GADGET_DELAYED_STATUS. Thanks. > > not only mass storage. It needs to be done for all drivers. The way to > do that is to teach functions that control transfers are composed of two > or three phases. If you look at UDC drivers today, they all have > peculiarities about control transfers to handle stuff that *maybe* > gadget drivers won't handle. > > What we should do here is make sure that *all* 3 phases always have a > matching usb_ep_queue() coming from the upper layers. Whether > composite.c or f_*.c handles it, that's an implementation detail. But > just to illustrate the problem, we should be able to get rid of > dwc3_ep0_out_start() and assume that the upper layer will call > usb_ep_queue() when it wants to receive a new SETUP packet. > > Likewise, we should be able to assume that STATUS phase will only start > based on a usb_ep_queue() call. That way we can remove > USB_GADGET_DELAYED_STATUS altogether, because that will *always* be the > case. There will be no races to handle apart from the normal case where > XferNotReady can come before or after usb_ep_queue(), but we already > have proper handling for that too. It sounds like you're talking about a major change in the way the gadget subsystem handles control requests. We can distinguish three cases. In the existing implementation, they work like this: (1) Control-OUT with no data stage. The gadget driver's setup routine either queues a request on ep0, which the UDC driver uses for the status stage transfer (so it should be a length-0 IN transfer) and returns 0, or else returns an error, in which case the UDC driver sends a protocol STALL for the status stage. (What the UDC driver should do if the setup routine queues a request on ep0 and then returns an error is undefined.) (2) Control-OUT with a data stage. The gadget driver's setup routine either queues an OUT request on ep0, which the UDC driver uses for the data stage transfer, or else returns an error, in which case the UDC driver sends a protocol STALL for the data stage. In the first case, the UDC driver automatically queues a 0-length IN request for the status stage; the gadget driver does not get any chance to fail the transfer after the host's data has been successfully received. (IMO this is a bug in the design of the gadget subsystem.) (3) Control-IN with a data stage. The gadget driver's setup routine either queues an IN request on ep0, which the UDC driver uses for the data stage transfer, or else returns an error, in which case the UDC driver sends a protocol STALL for the data stage. In the first case, the UDC driver automatically queues a 0-length OUT request for the status stage; the gadget driver does not get any chance to fail the transfer after its data has been successfully sent (and I can't think of any reason for doing this). In the delayed-status or delayed-data case, the setup routine does not queue a request on ep0 before returning 0; instead the gadget driver queues this request at a later time in a separate thread. The gadget driver never calls usb_ep_queue in order to receive the next SETUP packet; the UDC driver takes care of SETUP handling automatically. You are suggesting that status stage requests should not be queued automatically by UDC drivers but instead queued explicitly by gadget drivers. This would mean changing every UDC driver and every gadget driver. Also, it won't fix the race that Baolin Wang found. The setup routine is always called in interrupt context, so it can't sleep. Doing anything non-trivial will require a separate task, and it's possible that this task will try to enqueue the data-stage or status-stage request before the UDC driver is ready to handle it (for example, before or shortly after the setup routine returns). To work properly, the UDC driver must be able to accept a request for ep0 any time after it invokes the setup callback -- either before the callback returns or after. It seems that this was the real problem Baolin wanted to fix. Alan Stern -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html