Skip to content

dwc3: "request ... was not queued to ep0out" on every FunctionFS gadget teardown #20

Description

@Yury-MonZon

Every teardown of a gadget that includes a FunctionFS function logs an error:

[  188.808339] dwc3 23000000.usb: request 00000000ad92f1c4 was not queued to ep0out

Reproduced on Flipper One (rk3576, USB-C gadget port usb@23000000) with the
ncmmscmtp composite (ffs.mtp + mass_storage.0 + ncm.usb0), kernel 7.2.0-rc3.
It also appears at boot when the gadget setup retries, in which case it is followed by
failed to start ncmmscmtp: -19 / couldn't find an available UDC or it's busy.

Cause

Two correct-in-isolation behaviours collide:

  1. functionfs_unbind() dequeues ep0req unconditionally before freeing it. That is
    deliberate: usb_ep_free_request() requires the request no longer be queued, which
    commit ce405d5 ("usb: gadget: f_fs: Ensure ep0req is dequeued before
    free_request", 2022-12-15) made explicit to close a use-after-free.
  2. By that point the request has long completed, so dwc3_gadget_ep_dequeue() finds it on
    none of its lists (cancelled_list, pending_list, started_list) and falls through to
    the dev_err() at drivers/usb/dwc3/gadget.c:2184, returning -EINVAL.

Impact

Cosmetic. Both callers ignore the return value and free the request immediately; nothing
leaks and no transfer is affected. It is noise in every gadget teardown, which makes real
USB errors harder to spot in logs.

Evidence

ftrace stack on dwc3_gadget_ep_dequeue, triggered by stopping the composite
(usb-gadget-setup.sh stop, i.e. a write to the gadget's UDC attribute):

>> [  188.808339] dwc3 23000000.usb: request 00000000ad92f1c4 was not queued to ep0out

 usb-gadget-setu-7074  [005]  188.808328: dwc3_gadget_ep_dequeue <-usb_ep_dequeue
 usb-gadget-setu-7074  [005]  188.808333: <stack trace>
 => dwc3_gadget_ep_dequeue
 => usb_ep_dequeue
 => functionfs_unbind
 => ffs_func_unbind
 => purge_configs_funcs
 => configfs_composite_unbind
 => gadget_unbind_driver
 => device_remove
 => device_release_driver_internal
 => driver_detach
 => bus_remove_driver
 => gadget_dev_desc_UDC_store
 => configfs_write_iter
 => vfs_write
 => ksys_write
 => __arm64_sys_write
 => invoke_syscall
 => el0_svc_common.constprop.0
 => do_el0_svc
 => el0_svc
 => el0t_64_sync_handler
 => el0t_64_sync

Upstream state: unfixed, and previously contested

  • The same class of bug was fixed in the UDC driver for cdnsp: commit 34f08eb
    ("usb: cdnsp: Fixes issue with dequeuing not queued requests", 2023-07-13, cc stable)
    added three lines, if (request->status != -EINPROGRESS) return 0;, for a gadget
    dequeuing a not-queued request during module unload.

  • A dwc3-side fix was posted and stalled:
    usb: dwc3: ep0: Add implementation of ep0_dequeue separately
    (Nov 2022), still state=new. Maintainer Thinh Nguyen questioned the premise:

    Just curious, how do you hit/test this scenario? For other endpoint types, I can see
    possible scenarios where a dequeue may be needed, but I don't see one for control
    transfer. [...] So, where does ep0_dequeue come into play here?

    and asked for the opposite of a silent no-op: "Need to check if the control transfer is
    active and the input request is the valid request to dequeue. Return error code if it's
    not.
    "

That thread is answerable now: the f_fs commit that creates this caller landed after that
discussion, so the stack trace above is exactly the caller he asked for.

Possible fixes

  1. Mirror cdnsp in dwc3 - return 0 early when request->status != -EINPROGRESS. dwc3
    sets -EINPROGRESS on queue for both normal endpoints (gadget.c:2002) and ep0
    (ep0.c:95), and overwrites it on completion, so the check is reliable. Downside: it is
    the silent no-op the dwc3 maintainer explicitly did not want, so it would likely be
    rejected upstream as-is.
  2. Follow the maintainer's preference - validate that the control transfer is active and
    return an error otherwise, reviving the 2022 thread with this reproducer attached.
  3. Carry a local patch only to silence the log, and leave upstream alone.

Preference welcome before anything is sent to linux-usb.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinghelp wantedExtra attention is needed

    Type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions