From: Ming Lei <ming.lei@redhat.com>
To: huang-jl <huang-jl@deepseek.com>
Cc: linux-block@vger.kernel.org
Subject: Re: [BUG] ublk: ublk server hangs in D state during STOP_DEV
Date: Sun, 18 Jan 2026 19:50:09 +0800 [thread overview]
Message-ID: <aWzI8XXbN7z2JcNh@fedora> (raw)
In-Reply-To: <20260117170319.51050-1-huang-jl@deepseek.com>
On Sun, Jan 18, 2026 at 01:03:19AM +0800, huang-jl wrote:
> > > - Upon receiving SIGINT, our ublk server will sends UBLK_U_CMD_STOP_DEV to the
> > > driver.
> >
> > Can you share how your server sends STOP_DEV when receiving SIGINT?
> >
> > If it prevents normal IO command handling, ublk_stop_dev() will cause deadlock.
> >
> > For example, follows the preferred IO handling in ublk server:
> >
> > prepare UBLK_IO_FETCH_REQ uring_cmds;
> > while (1) {
> > io_uring_enter(submission & wait event);
> > }
> >
> > If you send STOP_DEV command inside the above loop, you will get the
> > deadlock, because inflight and new IOs can't be handled any more.
>
> My ublk server has two threads:
>
> - The main thread: opens /dev/ublk-control and create an io uring. It handles
> all control uring cmd (e.g., ADD_DEV, START_DEV, STOP_DEV).
>
> - A worker thread: also creates an io uring. It will send UBLK_U_IO_FETCH_REQ
> and UBLK_U_IO_COMMIT_AND_FETCH_REQ uring cmd, and handle IO request.
>
> Main thread will first ADD and START device, then listens for SIGINT signal.
> Upon receiving SIGINT, main thread issues a STOP_DEV cmd.
> The worker thread continues running independently and is not directly affected
> by this signal.
>
> (Implementation detail: I am using Rust and the Tokio async runtime. The SIGINT
> is handled within the userspace rather than directly inside the signal handler.)
>
> > If that is the case, you may remove the sending of STOP_DEV simply in your
> > implementation, and let ublk server exit. Then delete the ublk device before
> > ublk server is exiting to kernel, or let your monitor process remove the
> > ublk device, which becomes DEAD state after ublk server exits.
> >
> > Otherwise, you may have to investigate why ublk server can't handle IO
> > command after sending STOP_DEV command.
>
> Based on my previous post [1], **the ublk server gets SIGKILL after sending
> STOP_DEV command**, so it cannot handle IO request.
>
> In detail:
>
> 1. Flush Kernel Thread: A kworker/flush thread attempts to write dirty pages
> to the ublk device. It acquires a folio lock but then enters a sleep state
> in wbt_wait() due to Writeback Throttling (WBT).
>
> 2. STOP_DEV Command: The ublk server issues a STOP_DEV command. This uring cmd
> is processed by an uring kernel thread.
>
> 3. Resource Conflict: When handle STOP_DEV, the uring kernel thread also tries
> to flush dirty pages. It needs to acquire the same folio lock held by the flush
> kworker to submit the I/O.
>
> 4. Termination Signal: At this point, the ublk server receives a SIGKILL.
It is _not_ related with WBT or write cache.
When your monitor sends SIGKILL, do_exit() is actually called, but
io_uring_cancel_generic() blocks on io_wq_put_and_exit() because STOP_DEV
can't be completed, then do_exit() can't move on, and finally the ublk cancel
function can't be called, then ublk char device can't be closed.
Looks something which might be improved in future, but it highly depends on
(complicated) io_uring's cancel code path, and I believe there isn't
any way for ublk to get notified when do_exit() happens from `kill -9`.
>
> Conclusion:
> This creates a circular dependency: the flush kworker cannot be woken from WBT
> because the ublk server is no longer processing I/O requests.
> Simultaneously, the ublk server cannot exit because it is waiting for the
> STOP_DEV command to complete. However, the uring kernel thread remains stuck
> waiting for the folio lock held by the flush kworker.
>
> Should we avoid having the ublk server issue STOP_DEV command by it self? As it
> is highly prone to deadlocks if a SIGKILL occurs during the shutdown sequence.
So far there are at least two ways:
1) don't provide signal handler for SIGINT, or simply call exit() in the
signal handler, and ublk block device is removed automatically when ublk
server is done in case of !USER_RECOVERY.
OR
2) provide signal SIGINT handler to stop device, meantime not send SIGKILL
in your monitor process. This way works just fine if your ublk server is
well implemented, which often requires you to handle timeout in the server
implementation.
Thanks,
Ming
next prev parent reply other threads:[~2026-01-18 11:50 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-16 14:15 [BUG] ublk: ublk server hangs in D state during STOP_DEV huang-jl
2026-01-16 14:58 ` Ming Lei
2026-01-17 5:18 ` huang-jl
[not found] ` <20260116171613.46312-1-huang-jl@deepseek.com>
2026-01-17 7:44 ` Ming Lei
2026-01-17 11:16 ` Ming Lei
2026-01-17 17:03 ` huang-jl
2026-01-18 11:50 ` Ming Lei [this message]
2026-01-18 13:14 ` huang-jl
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=aWzI8XXbN7z2JcNh@fedora \
--to=ming.lei@redhat.com \
--cc=huang-jl@deepseek.com \
--cc=linux-block@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox