Re: [PATCH V2] ublk: setup ublk_io correctly in case of ublk_get_data() failure

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

 



On Tue, Jun 24, 2025 at 8:16 AM Caleb Sander Mateos
<csander@xxxxxxxxxxxxxxx> wrote:
>
> On Tue, Jun 24, 2025 at 3:41 AM Ming Lei <ming.lei@xxxxxxxxxx> wrote:
> >
> > If ublk_get_data() fails, -EIOCBQUEUED is returned and the current command
> > becomes ASYNC. And the only reason is that mapping data can't move on,
> > because of no enough pages or pending signal, then the current ublk request
> > has to be requeued.
> >
> > Once the request need to be requeued, we have to setup `ublk_io` correctly,
> > including io->cmd and flags, otherwise the request may not be forwarded to
> > ublk server successfully.
> >
> > Fixes: 9810362a57cb ("ublk: don't call ublk_dispatch_req() for NEED_GET_DATA")
>
> Don't think this is the right Fixes tag; the issue predates this
> refactoring. I pointed out this existing issue when we discussed that
> patch: https://lore.kernel.org/linux-block/CADUfDZroQ4zHanPjytcEUhn4tQc3BYMPZD2uLOik7jAXvOCjGg@xxxxxxxxxxxxxx/
>
> Looks like the correct commit would be c86019ff75c1 ("ublk_drv: add
> support for UBLK_IO_NEED_GET_DATA").

Ah never mind, I see my commit removed the call to ublk_fill_io_cmd().
I see that's necessary for the -EIOCBQUEUED return to work correctly.

>
> > Reported-by: Changhui Zhong <czhong@xxxxxxxxxx>
> > Closes: https://lore.kernel.org/linux-block/CAGVVp+VN9QcpHUz_0nasFf5q9i1gi8H8j-G-6mkBoqa3TyjRHA@xxxxxxxxxxxxxx/
> > Signed-off-by: Ming Lei <ming.lei@xxxxxxxxxx>
> > ---
> > V2:
> >         - move io->addr assignment into ublk_fill_io_cmd()
> >
> >  drivers/block/ublk_drv.c | 35 +++++++++++++++++++++++++----------
> >  1 file changed, 25 insertions(+), 10 deletions(-)
> >
> > diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
> > index d36f44f5ee80..3566d7c36b8d 100644
> > --- a/drivers/block/ublk_drv.c
> > +++ b/drivers/block/ublk_drv.c
> > @@ -1148,8 +1148,8 @@ static inline void __ublk_complete_rq(struct request *req)
> >         blk_mq_end_request(req, res);
> >  }
> >
> > -static void ublk_complete_io_cmd(struct ublk_io *io, struct request *req,
> > -                                int res, unsigned issue_flags)
> > +static struct io_uring_cmd *__ublk_prep_compl_io_cmd(struct ublk_io *io,
> > +                                                    struct request *req)
>
> nit: don't think the underscores are necessary
>
> >  {
> >         /* read cmd first because req will overwrite it */
> >         struct io_uring_cmd *cmd = io->cmd;
> > @@ -1164,6 +1164,13 @@ static void ublk_complete_io_cmd(struct ublk_io *io, struct request *req,
> >         io->flags &= ~UBLK_IO_FLAG_ACTIVE;
> >
> >         io->req = req;
> > +       return cmd;
> > +}
> > +
> > +static void ublk_complete_io_cmd(struct ublk_io *io, struct request *req,
> > +                                int res, unsigned issue_flags)
> > +{
> > +       struct io_uring_cmd *cmd = __ublk_prep_compl_io_cmd(io, req);
> >
> >         /* tell ublksrv one io request is coming */
> >         io_uring_cmd_done(cmd, res, 0, issue_flags);
> > @@ -2148,10 +2155,9 @@ static int ublk_commit_and_fetch(const struct ublk_queue *ubq,
> >         return 0;
> >  }
> >
> > -static bool ublk_get_data(const struct ublk_queue *ubq, struct ublk_io *io)
> > +static bool ublk_get_data(const struct ublk_queue *ubq, struct ublk_io *io,
> > +                         struct request *req)
> >  {
> > -       struct request *req = io->req;
> > -
> >         /*
> >          * We have handled UBLK_IO_NEED_GET_DATA command,
> >          * so clear UBLK_IO_FLAG_NEED_GET_DATA now and just
> > @@ -2178,6 +2184,7 @@ static int __ublk_ch_uring_cmd(struct io_uring_cmd *cmd,
> >         u32 cmd_op = cmd->cmd_op;
> >         unsigned tag = ub_cmd->tag;
> >         int ret = -EINVAL;
> > +       struct request *req;
> >
> >         pr_devel("%s: received: cmd op %d queue %d tag %d result %d\n",
> >                         __func__, cmd->cmd_op, ub_cmd->q_id, tag,
> > @@ -2236,11 +2243,19 @@ static int __ublk_ch_uring_cmd(struct io_uring_cmd *cmd,
> >                         goto out;
> >                 break;
> >         case UBLK_IO_NEED_GET_DATA:
> > -               io->addr = ub_cmd->addr;
> > -               if (!ublk_get_data(ubq, io))
> > -                       return -EIOCBQUEUED;
> > -
> > -               return UBLK_IO_RES_OK;
> > +               /*
> > +                * ublk_get_data() may fail and fallback to requeue, so keep
> > +                * uring_cmd active first and prepare for handling new requeued
> > +                * request
> > +                */
> > +               req = io->req;
> > +               ublk_fill_io_cmd(io, cmd, ub_cmd->addr);
> > +               io->flags &= ~UBLK_IO_FLAG_OWNED_BY_SRV;
> > +               if (likely(ublk_get_data(ubq, io, req))) {
> > +                       __ublk_prep_compl_io_cmd(io, req);
>
> Isn't __ublk_prep_compl_io_cmd() basically undoing the
> ublk_fill_io_cmd() and io->flags &= ~UBLK_IO_FLAG_OWNED_BY_SRV? How
> about something like this instead?
>
> io->addr = ub_cmd->addr;
> if (likely(ublk_get_data(ubq, io)))
>         return UBLK_IO_RES_OK;
>
> ublk_fill_io_cmd(io, cmd, ub_cmd->addr);
> io->flags &= ~UBLK_IO_FLAG_OWNED_BY_SRV;
> break;
>
> Best,
> Caleb
>
> > +                       return UBLK_IO_RES_OK;
> > +               }
> > +               break;
> >         default:
> >                 goto out;
> >         }
> > --
> > 2.49.0
> >





[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