Skip to content

Fix ublk stop races - #2

Open
bsbernd wants to merge 6 commits into
niova-ublk-7.1from
ublk-stop-races
Open

Fix ublk stop races#2
bsbernd wants to merge 6 commits into
niova-ublk-7.1from
ublk-stop-races

Conversation

@bsbernd

@bsbernd bsbernd commented Aug 14, 2026

Copy link
Copy Markdown

No description provided.

del_gendisk() blocks in blk_mq_freeze_queue_wait() until every
in-flight request has ended. ublk_stop_dev() cancelled the server's
parked commands and aborted its own in-flight requests only after
del_gendisk() had already returned, so neither side could ever make
progress: the ublk server sits in io_uring_enter() waiting for CQEs
that only ublk_cancel_dev() posts, while the control task sits inside
del_gendisk() waiting for requests only ublk_abort_queue() can end.

Move cancel-then-abort into ublk_stop_dev_unlocked(), before
del_gendisk(), matching the sequence ublk_ch_release_work_fn()
already uses. cancel_mutex is released before the abort loop runs
(not held across it) so it doesn't needlessly block the server's own
exit path for the loop's duration.

Fixes: 71f28f3 ("ublk_drv: add io_uring based userspace block driver")
Cc: stable@vger.kernel.org
Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
ublk_abort_queue() reads and disposes of a tag's OWNED_BY_SRV state
without any lock, racing a live server on the same tag three ways:
the io->cmd/io->req union is published in two separate, unlocked
writes, so a concurrent reader can observe the flag set and the old
io->cmd value still in the union; a request already handed back to
the server via UBLK_IO_COMMIT_AND_FETCH_REQ or NEED_GET_DATA can be
disposed of a second time by abort; and abort never clears the flag,
so a retried abort pass reprocesses an already-ended request.

Give each tag one lock-protected claim, the same io->lock the
batch-IO commit path already uses for this: publish (auto buffer
registration and the classic completion path) sets OWNED_BY_SRV and
stores io->req as one locked step, and every place that hands a tag
back to driver ownership (COMMIT_AND_FETCH_REQ, NEED_GET_DATA,
ublk_abort_queue()) rechecks the flag and clears it under the same
lock before touching the request. Whichever side loses the race
backs off cleanly instead of running twice.

Fixes: 64d1dc5 ("ublk: store request pointer in ublk_io")
Cc: stable@vger.kernel.org
Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
ublk_queue_rq() hands a started request to the server via a task-work
hop: ublk_queue_cmd() schedules the dispatch, ublk_dispatch_req()
runs it and publishes OWNED_BY_SRV later. A single ublk_abort_queue()
pass during that window sees a request that is started but not yet
owned by the server, leaves it alone, and del_gendisk() then waits
for a request nobody will ever end.

ublk_abort_queue() now reports how many tags it had to leave alone
using the same started-but-not-owned predicate ublk_cancel_cmd()
already relies on. ublk_stop_dev_unlocked() quiesces the queue around
the whole cancel/set_canceling/retry sequence, the same bracket
ublk_force_abort_dev() already uses, and repeats the abort pass until
nothing is pending before calling del_gendisk(). Quiescing blocks new
submissions only, not the task-work completions the retry loop is
waiting on, and keeps a fresh request from appearing after the loop's
last zero-pending scan. A stuck loop warns once and doubles its warn
interval on each further repeat, so it stays diagnosable instead of
turning into a silent hang inside STOP_DEV.

Fixes: 71f28f3 ("ublk_drv: add io_uring based userspace block driver")
Cc: stable@vger.kernel.org
Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
__ublk_prep_compl_io_cmd(), ublk_auto_buf_io_setup() and
ublk_batch_commit_io_check() all require the caller to already hold
io->lock before touching UBLK_IO_FLAG_OWNED_BY_SRV/io->req, but only
one of the three documented that in a comment and none enforced it.
Add lockdep_assert_held() to each, matching how __ublk_acquire_fcmd()
already asserts ubq->evts_lock, so a future caller that forgets to
lock is caught at runtime instead of racing silently.

Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant