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

    Status
    In progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions