]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ublk: setup ublk_io correctly in case of ublk_get_data() failure
authorMing Lei <ming.lei@redhat.com>
Tue, 24 Jun 2025 10:41:21 +0000 (18:41 +0800)
committerJens Axboe <axboe@kernel.dk>
Wed, 25 Jun 2025 02:45:31 +0000 (20:45 -0600)
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")
Reported-by: Changhui Zhong <czhong@redhat.com>
Closes: https://lore.kernel.org/linux-block/CAGVVp+VN9QcpHUz_0nasFf5q9i1gi8H8j-G-6mkBoqa3TyjRHA@mail.gmail.com/
Signed-off-by: Ming Lei <ming.lei@redhat.com>
Tested-by: Changhui Zhong <czhong@redhat.com>
Link: https://lore.kernel.org/r/20250624104121.859519-1-ming.lei@redhat.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
drivers/block/ublk_drv.c

index 90c02ced392a2289760168a63d6cabc324cb3335..d441d3259edb3fe9314077dae1c07e4d981b5ec4 100644 (file)
@@ -1148,8 +1148,8 @@ exit:
        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)
 {
        /* 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);
@@ -2157,10 +2164,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
@@ -2187,6 +2193,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,
@@ -2245,11 +2252,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);
+                       return UBLK_IO_RES_OK;
+               }
+               break;
        default:
                goto out;
        }