Re: [PATCH 2/2] ublk: run auto buf unregisgering in same io_ring_ctx with register

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, May 21, 2025 at 5:42 PM Ming Lei <ming.lei@xxxxxxxxxx> wrote:
>
> On Wed, May 21, 2025 at 08:58:20AM -0700, Caleb Sander Mateos wrote:
> > On Tue, May 20, 2025 at 7:55 PM Ming Lei <ming.lei@xxxxxxxxxx> wrote:
> > >
> > > UBLK_F_AUTO_BUF_REG requires that the buffer registered automatically
> > > is unregistered in same `io_ring_ctx`, so check it explicitly.
> > >
> > > Meantime return the failure code if io_buffer_unregister_bvec() fails,
> > > then ublk server can handle the failure in consistent way.
> > >
> > > Also force to clear UBLK_IO_FLAG_AUTO_BUF_REG in ublk_io_release()
> > > because ublk_io_release() may be triggered not from handling
> > > UBLK_IO_COMMIT_AND_FETCH_REQ, and from releasing the `io_ring_ctx`
> > > for registering the buffer.
> > >
> > > Fixes: 99c1e4eb6a3f ("ublk: register buffer to local io_uring with provided buf index via UBLK_F_AUTO_BUF_REG")
> > > Reported-by: Caleb Sander Mateos <csander@xxxxxxxxxxxxxxx>
> > > Signed-off-by: Ming Lei <ming.lei@xxxxxxxxxx>
> > > ---
> > >  drivers/block/ublk_drv.c      | 35 +++++++++++++++++++++++++++++++----
> > >  include/uapi/linux/ublk_cmd.h |  3 ++-
> > >  2 files changed, 33 insertions(+), 5 deletions(-)
> > >
> > > diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
> > > index fcf568b89370..2af6422d6a89 100644
> > > --- a/drivers/block/ublk_drv.c
> > > +++ b/drivers/block/ublk_drv.c
> > > @@ -84,6 +84,7 @@ struct ublk_rq_data {
> > >
> > >         /* for auto-unregister buffer in case of UBLK_F_AUTO_BUF_REG */
> > >         u16 buf_index;
> > > +       unsigned long buf_ctx_id;
> > >  };
> > >
> > >  struct ublk_uring_cmd_pdu {
> > > @@ -1192,6 +1193,11 @@ static void ublk_auto_buf_reg_fallback(struct request *req, struct ublk_io *io)
> > >         refcount_set(&data->ref, 1);
> > >  }
> > >
> > > +static unsigned long ublk_uring_cmd_ctx_id(struct io_uring_cmd *cmd)
> > > +{
> > > +       return (unsigned long)(cmd_to_io_kiocb(cmd)->ctx);
> >
> > Is the fact that a struct io_uring_cmd * can be passed to
> > cmd_to_io_kiocb() an io_uring internal implementation detail? Maybe it
> > would be good to add a helper in include/linux/io_uring/cmd.h so ublk
> > isn't depending on io_uring internals.
>
> All this definition is defined in kernel public header, not sure if it is
> big deal to add the helper, especially there is just single user.
>
> But I will do it.
>
> >
> > Also, storing buf_ctx_id as a void * instead would allow this cast to
> > be avoided, but not a big deal.
> >
> > > +}
> > > +
> > >  static bool ublk_auto_buf_reg(struct request *req, struct ublk_io *io,
> > >                               unsigned int issue_flags)
> > >  {
> > > @@ -1211,6 +1217,8 @@ static bool ublk_auto_buf_reg(struct request *req, struct ublk_io *io,
> > >         }
> > >         /* one extra reference is dropped by ublk_io_release */
> > >         refcount_set(&data->ref, 2);
> > > +
> > > +       data->buf_ctx_id = ublk_uring_cmd_ctx_id(io->cmd);
> > >         /* store buffer index in request payload */
> > >         data->buf_index = pdu->buf.index;
> > >         io->flags |= UBLK_IO_FLAG_AUTO_BUF_REG;
> > > @@ -1994,6 +2002,21 @@ static void ublk_io_release(void *priv)
> > >  {
> > >         struct request *rq = priv;
> > >         struct ublk_queue *ubq = rq->mq_hctx->driver_data;
> > > +       struct ublk_io *io = &ubq->ios[rq->tag];
> > > +
> > > +       /*
> > > +        * In case of UBLK_F_AUTO_BUF_REG, the `io_uring_ctx` for registering
> > > +        * this buffer may be released, so we reach here not from handling
> > > +        * `UBLK_IO_COMMIT_AND_FETCH_REQ`.
> >
> > What do you mean by this? That the io_uring was closed while a ublk
> > I/O owned by the server still had a registered buffer?
>
> The buffer is registered to `io_ring_ctx A`, which is closed and the buffer
> is used up and un-registered on `io_ring_ctx A`, so this callback is
> triggered, but the io command isn't completed yet, which can be run from
> `io_ring_ctx B`
>
> >
> > > +        *
> > > +        * Force to clear UBLK_IO_FLAG_AUTO_BUF_REG, so that ublk server
> > > +        * still may complete this IO request by issuing uring_cmd from
> > > +        * another `io_uring_ctx` in case that the `io_ring_ctx` for
> > > +        * registering the buffer is gone
> > > +        */
> > > +       if (ublk_support_auto_buf_reg(ubq) &&
> > > +                       (io->flags & UBLK_IO_FLAG_AUTO_BUF_REG))
> > > +               io->flags &= ~UBLK_IO_FLAG_AUTO_BUF_REG;
> >
> > This is racy, since ublk_io_release() can be called on a thread other
> > than the ubq_daemon.
>
> Yeah, it can be true.
>
> > Could we avoid touching io->flags here and
> > instead have ublk_commit_and_fetch() check whether the reference count
> > is already 1?
>
> It is still a little racy because the buffer unregister from another thread
> can happen just after the check immediately.

True. I think it might be better to just skip the unregister if the
contexts don't match rather than returning -EINVAL. Then there is no
race. If userspace has already closed the old io_uring context,
skipping the unregister is the desired behavior. If userspace hasn't
closed the old io_uring, then that's a userspace bug and they get what
they deserve (a buffer stuck registered). If userspace wants to submit
the UBLK_IO_COMMIT_AND_FETCH_REQ on a different io_uring for some
reason, they can always issue an explicit UBLK_IO_UNREGISTER_IO_BUF on
the old io_uring to unregister the buffer.

>
> Adding one spinlock should cover it.

I would really prefer not to add a spinlock in the I/O path.

>
> And it shouldn't be one big thing, because anyway the buffer can only be
> released once.
>
> >
> > Also, the ublk_support_auto_buf_reg(ubq) check seems redundant, since
> > UBLK_IO_FLAG_AUTO_BUF_REG is set in ublk_auto_buf_reg(), which is only
> > called if ublk_support_auto_buf_reg(ubq).
>
> It has document benefit at least, so I'd suggest to keep it.

Doesn't checking for UBLK_IO_FLAG_AUTO_BUF_REG already document that
this only applies to auto buffer registration?

Best,
Caleb





[Index of Archives]     [Linux RAID]     [Linux SCSI]     [Linux ATA RAID]     [IDE]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Device Mapper]

  Powered by Linux