In the CAMIOQUEUE ioctl, a queued CCB completes through passdone(),
which moves it to the done queue and calls selwakeuppri() and
KNOTE_LOCKED() so that a consumer blocked in select(2), poll(2) or
kevent(2) wakes up and collects the CCB with CAMIOGET. An immediate
CCB (e.g. XPT_DEV_ADVINFO or XPT_DEV_MATCH) is instead executed
synchronously in the ioctl and moved to the done queue directly,
with no notification, so a consumer sleeping while waiting for its
completion never wakes up until some other queued I/O completes.
Send the same notification that passdone() sends. The peripheral
lock is held at this point and backs the knlist, so KNOTE_LOCKED()
is the correct variant.
A version of this fix has been in production use at Spectra Logic
since 2024.
Co-authored-by: Dave Baukus <daveb@spectralogic.com>
MFC after: 1 week
Sponsored by: Spectra Logic
Assisted-by: Claude Fable 5 <noreply@anthropic.com>