From: Ming Lei <ming.lei@redhat.com>
To: Caleb Sander Mateos <csander@purestorage.com>
Cc: Jens Axboe <axboe@kernel.dk>,
linux-block@vger.kernel.org,
Uday Shankar <ushankar@purestorage.com>
Subject: Re: [PATCH V5 08/21] ublk: add UBLK_U_IO_FETCH_IO_CMDS for batch I/O processing
Date: Sun, 7 Dec 2025 21:56:47 +0800 [thread overview]
Message-ID: <aTWHn9Jw2RuXdD8A@fedora> (raw)
In-Reply-To: <CADUfDZpJu+wQWWq2-GJm+ZN-wX3dcb_AYQhJ9ikwGjMEPCqh+w@mail.gmail.com>
On Sat, Dec 06, 2025 at 11:38:39PM -0800, Caleb Sander Mateos wrote:
> On Tue, Dec 2, 2025 at 4:21 AM Ming Lei <ming.lei@redhat.com> wrote:
> >
> > Add UBLK_U_IO_FETCH_IO_CMDS command to enable efficient batch processing
> > of I/O requests. This multishot uring_cmd allows the ublk server to fetch
> > multiple I/O commands in a single operation, significantly reducing
> > submission overhead compared to individual FETCH_REQ* commands.
> >
> > Key Design Features:
> >
> > 1. Multishot Operation: One UBLK_U_IO_FETCH_IO_CMDS can fetch many I/O
> > commands, with the batch size limited by the provided buffer length.
> >
> > 2. Dynamic Load Balancing: Multiple fetch commands can be submitted
> > simultaneously, but only one is active at any time. This enables
> > efficient load distribution across multiple server task contexts.
> >
> > 3. Implicit State Management: The implementation uses three key variables
> > to track state:
> > - evts_fifo: Queue of request tags awaiting processing
> > - fcmd_head: List of available fetch commands
> > - active_fcmd: Currently active fetch command (NULL = none active)
> >
> > States are derived implicitly:
> > - IDLE: No fetch commands available
> > - READY: Fetch commands available, none active
> > - ACTIVE: One fetch command processing events
> >
> > 4. Lockless Reader Optimization: The active fetch command can read from
> > evts_fifo without locking (single reader guarantee), while writers
> > (ublk_queue_rq/ublk_queue_rqs) use evts_lock protection. The memory
> > barrier pairing plays key role for the single lockless reader
> > optimization.
> >
> > Implementation Details:
> >
> > - ublk_queue_rq() and ublk_queue_rqs() save request tags to evts_fifo
> > - __ublk_acquire_fcmd() selects an available fetch command when
> > events arrive and no command is currently active
> > - ublk_batch_dispatch() moves tags from evts_fifo to the fetch command's
> > buffer and posts completion via io_uring_mshot_cmd_post_cqe()
> > - State transitions are coordinated via evts_lock to maintain consistency
> >
> > Signed-off-by: Ming Lei <ming.lei@redhat.com>
> > ---
> > drivers/block/ublk_drv.c | 392 +++++++++++++++++++++++++++++++++-
> > include/uapi/linux/ublk_cmd.h | 7 +
> > 2 files changed, 391 insertions(+), 8 deletions(-)
> >
> > diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
> > index 05bf9786751f..de6ce0e17b1b 100644
> > --- a/drivers/block/ublk_drv.c
> > +++ b/drivers/block/ublk_drv.c
> > @@ -93,6 +93,7 @@
> >
> > /* ublk batch fetch uring_cmd */
> > struct ublk_batch_fetch_cmd {
> > + struct list_head node;
> > struct io_uring_cmd *cmd;
> > unsigned short buf_group;
> > };
> > @@ -117,7 +118,10 @@ struct ublk_uring_cmd_pdu {
> > */
> > struct ublk_queue *ubq;
> >
> > - u16 tag;
> > + union {
> > + u16 tag;
> > + struct ublk_batch_fetch_cmd *fcmd; /* batch io only */
> > + };
> > };
> >
> > struct ublk_batch_io_data {
> > @@ -239,10 +243,37 @@ struct ublk_queue {
> > * Make sure just one reader for fetching request from task work
> > * function to ublk server, so no need to grab the lock in reader
> > * side.
> > + *
> > + * Batch I/O State Management:
> > + *
> > + * The batch I/O system uses implicit state management based on the
> > + * combination of three key variables below.
> > + *
> > + * - IDLE: list_empty(&fcmd_head) && !active_fcmd
> > + * No fetch commands available, events queue in evts_fifo
> > + *
> > + * - READY: !list_empty(&fcmd_head) && !active_fcmd
> > + * Fetch commands available but none processing events
> > + *
> > + * - ACTIVE: active_fcmd
> > + * One fetch command actively processing events from evts_fifo
> > + *
> > + * Key Invariants:
> > + * - At most one active_fcmd at any time (single reader)
> > + * - active_fcmd is always from fcmd_head list when non-NULL
> > + * - evts_fifo can be read locklessly by the single active reader
> > + * - All state transitions require evts_lock protection
> > + * - Multiple writers to evts_fifo require lock protection
> > */
> > struct {
> > DECLARE_KFIFO_PTR(evts_fifo, unsigned short);
> > spinlock_t evts_lock;
> > +
> > + /* List of fetch commands available to process events */
> > + struct list_head fcmd_head;
> > +
> > + /* Currently active fetch command (NULL = none active) */
> > + struct ublk_batch_fetch_cmd *active_fcmd;
> > }____cacheline_aligned_in_smp;
> >
> > struct ublk_io ios[] __counted_by(q_depth);
> > @@ -294,12 +325,20 @@ static void ublk_abort_queue(struct ublk_device *ub, struct ublk_queue *ubq);
> > static inline struct request *__ublk_check_and_get_req(struct ublk_device *ub,
> > u16 q_id, u16 tag, struct ublk_io *io, size_t offset);
> > static inline unsigned int ublk_req_build_flags(struct request *req);
> > +static void ublk_batch_dispatch(struct ublk_queue *ubq,
> > + const struct ublk_batch_io_data *data,
> > + struct ublk_batch_fetch_cmd *fcmd);
> >
> > static inline bool ublk_dev_support_batch_io(const struct ublk_device *ub)
> > {
> > return false;
> > }
> >
> > +static inline bool ublk_support_batch_io(const struct ublk_queue *ubq)
> > +{
> > + return false;
> > +}
> > +
> > static inline void ublk_io_lock(struct ublk_io *io)
> > {
> > spin_lock(&io->lock);
> > @@ -620,13 +659,45 @@ static wait_queue_head_t ublk_idr_wq; /* wait until one idr is freed */
> >
> > static DEFINE_MUTEX(ublk_ctl_mutex);
> >
> > +static struct ublk_batch_fetch_cmd *
> > +ublk_batch_alloc_fcmd(struct io_uring_cmd *cmd)
> > +{
> > + struct ublk_batch_fetch_cmd *fcmd = kzalloc(sizeof(*fcmd), GFP_NOIO);
> >
> > -static void ublk_batch_deinit_fetch_buf(const struct ublk_batch_io_data *data,
> > + if (fcmd) {
> > + fcmd->cmd = cmd;
> > + fcmd->buf_group = READ_ONCE(cmd->sqe->buf_index);
> > + }
> > + return fcmd;
> > +}
> > +
> > +static void ublk_batch_free_fcmd(struct ublk_batch_fetch_cmd *fcmd)
> > +{
> > + kfree(fcmd);
> > +}
> > +
> > +static void __ublk_release_fcmd(struct ublk_queue *ubq)
> > +{
> > + WRITE_ONCE(ubq->active_fcmd, NULL);
> > +}
> > +
> > +/*
> > + * Nothing can move on, so clear ->active_fcmd, and the caller should stop
> > + * dispatching
> > + */
> > +static void ublk_batch_deinit_fetch_buf(struct ublk_queue *ubq,
> > + const struct ublk_batch_io_data *data,
> > struct ublk_batch_fetch_cmd *fcmd,
> > int res)
> > {
> > + spin_lock(&ubq->evts_lock);
> > + list_del(&fcmd->node);
> > + WARN_ON_ONCE(fcmd != ubq->active_fcmd);
> > + __ublk_release_fcmd(ubq);
> > + spin_unlock(&ubq->evts_lock);
> > +
> > io_uring_cmd_done(fcmd->cmd, res, data->issue_flags);
> > - fcmd->cmd = NULL;
> > + ublk_batch_free_fcmd(fcmd);
> > }
> >
> > static int ublk_batch_fetch_post_cqe(struct ublk_batch_fetch_cmd *fcmd,
> > @@ -1489,6 +1560,8 @@ static int __ublk_batch_dispatch(struct ublk_queue *ubq,
> > bool needs_filter;
> > int ret;
> >
> > + WARN_ON_ONCE(data->cmd != fcmd->cmd);
> > +
> > sel = io_uring_cmd_buffer_select(fcmd->cmd, fcmd->buf_group, &len,
> > data->issue_flags);
> > if (sel.val < 0)
> > @@ -1552,21 +1625,92 @@ static int __ublk_batch_dispatch(struct ublk_queue *ubq,
> > return ret;
> > }
> >
> > -static __maybe_unused void
>
> Drop the __maybe_unused in the previous commit that introduced it?
Yes, it can't be avoided, because the previous commit just adds this
helpers without caller. Otherwise putting the two into one can become too big.
Thanks,
Ming
next prev parent reply other threads:[~2025-12-07 13:57 UTC|newest]
Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-12-02 12:18 [PATCH V5 00/21] ublk: add UBLK_F_BATCH_IO Ming Lei
2025-12-02 12:18 ` [PATCH V5 01/21] ublk: define ublk_ch_batch_io_fops for the coming feature F_BATCH_IO Ming Lei
2025-12-02 12:18 ` [PATCH V5 02/21] ublk: prepare for not tracking task context for command batch Ming Lei
2025-12-02 12:18 ` [PATCH V5 03/21] ublk: add new batch command UBLK_U_IO_PREP_IO_CMDS & UBLK_U_IO_COMMIT_IO_CMDS Ming Lei
2025-12-02 12:18 ` [PATCH V5 04/21] ublk: handle UBLK_U_IO_PREP_IO_CMDS Ming Lei
2025-12-02 12:18 ` [PATCH V5 05/21] ublk: handle UBLK_U_IO_COMMIT_IO_CMDS Ming Lei
2025-12-04 3:11 ` Caleb Sander Mateos
2025-12-02 12:19 ` [PATCH V5 06/21] ublk: add io events fifo structure Ming Lei
2025-12-04 3:16 ` Caleb Sander Mateos
2025-12-02 12:19 ` [PATCH V5 07/21] ublk: add batch I/O dispatch infrastructure Ming Lei
2025-12-04 3:38 ` Caleb Sander Mateos
2025-12-02 12:19 ` [PATCH V5 08/21] ublk: add UBLK_U_IO_FETCH_IO_CMDS for batch I/O processing Ming Lei
2025-12-07 7:38 ` Caleb Sander Mateos
2025-12-07 13:54 ` Ming Lei
2025-12-08 17:03 ` Caleb Sander Mateos
2025-12-07 13:56 ` Ming Lei [this message]
2025-12-08 17:04 ` Caleb Sander Mateos
2025-12-02 12:19 ` [PATCH V5 09/21] ublk: abort requests filled in event kfifo Ming Lei
2025-12-07 7:44 ` Caleb Sander Mateos
2025-12-02 12:19 ` [PATCH V5 10/21] ublk: add new feature UBLK_F_BATCH_IO Ming Lei
2025-12-07 8:16 ` Caleb Sander Mateos
2025-12-07 13:58 ` Ming Lei
2025-12-02 12:19 ` [PATCH V5 11/21] ublk: document " Ming Lei
2025-12-07 8:22 ` Caleb Sander Mateos
2025-12-07 15:03 ` Ming Lei
2025-12-08 21:10 ` Caleb Sander Mateos
2025-12-02 12:19 ` [PATCH V5 12/21] ublk: implement batch request completion via blk_mq_end_request_batch() Ming Lei
2025-12-02 12:19 ` [PATCH V5 13/21] selftests: ublk: fix user_data truncation for tgt_data >= 256 Ming Lei
2025-12-02 12:19 ` [PATCH V5 14/21] selftests: ublk: replace assert() with ublk_assert() Ming Lei
2025-12-02 12:19 ` [PATCH V5 15/21] selftests: ublk: add ublk_io_buf_idx() for returning io buffer index Ming Lei
2025-12-02 12:19 ` [PATCH V5 16/21] selftests: ublk: add batch buffer management infrastructure Ming Lei
2025-12-02 12:19 ` [PATCH V5 17/21] selftests: ublk: handle UBLK_U_IO_PREP_IO_CMDS Ming Lei
2025-12-02 12:19 ` [PATCH V5 18/21] selftests: ublk: handle UBLK_U_IO_COMMIT_IO_CMDS Ming Lei
2025-12-02 12:19 ` [PATCH V5 19/21] selftests: ublk: handle UBLK_U_IO_FETCH_IO_CMDS Ming Lei
2025-12-02 12:19 ` [PATCH V5 20/21] selftests: ublk: add --batch/-b for enabling F_BATCH_IO Ming Lei
2025-12-02 12:19 ` [PATCH V5 21/21] selftests: ublk: support arbitrary threads/queues combination Ming Lei
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=aTWHn9Jw2RuXdD8A@fedora \
--to=ming.lei@redhat.com \
--cc=axboe@kernel.dk \
--cc=csander@purestorage.com \
--cc=linux-block@vger.kernel.org \
--cc=ushankar@purestorage.com \
/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