ublk: make sure io cmd handled in submitter task context
authorMing Lei <ming.lei@redhat.com>
Mon, 9 Oct 2023 09:33:17 +0000 (17:33 +0800)
committerJens Axboe <axboe@kernel.dk>
Tue, 17 Oct 2023 14:27:55 +0000 (08:27 -0600)
In well-done ublk server implementation, ublk io command won't be
linked into any link chain. Meantime they are always handled in no-wait
style, so basically io cmd is always handled in submitter task context.

However, the server may set IOSQE_ASYNC, or io command is linked to one
chain mistakenly, then we may still run into io-wq context and
ctx->uring_lock isn't held.

So in case of IO_URING_F_UNLOCKED, schedule this command by
io_uring_cmd_complete_in_task to force running it in submitter task. Then
ublk_ch_uring_cmd_local() is guaranteed to run with context uring_lock held,
and we needn't to worry about sync among submission code path any more.

Signed-off-by: Ming Lei <ming.lei@redhat.com>
Link: https://lore.kernel.org/r/20231009093324.957829-3-ming.lei@redhat.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
drivers/block/ublk_drv.c

index 59d3652699f596f9461c1fac03fa34d90f4444cb..2e2efae62c7798c29ea967cb427d029bdcfc6420 100644 (file)
@@ -1811,7 +1811,8 @@ fail_put:
        return NULL;
 }
 
-static int ublk_ch_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
+static inline int ublk_ch_uring_cmd_local(struct io_uring_cmd *cmd,
+               unsigned int issue_flags)
 {
        /*
         * Not necessary for async retry, but let's keep it simple and always
@@ -1825,9 +1826,28 @@ static int ublk_ch_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
                .addr = READ_ONCE(ub_src->addr)
        };
 
+       WARN_ON_ONCE(issue_flags & IO_URING_F_UNLOCKED);
+
        return __ublk_ch_uring_cmd(cmd, issue_flags, &ub_cmd);
 }
 
+static void ublk_ch_uring_cmd_cb(struct io_uring_cmd *cmd,
+               unsigned int issue_flags)
+{
+       ublk_ch_uring_cmd_local(cmd, issue_flags);
+}
+
+static int ublk_ch_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
+{
+       /* well-implemented server won't run into unlocked */
+       if (unlikely(issue_flags & IO_URING_F_UNLOCKED)) {
+               io_uring_cmd_complete_in_task(cmd, ublk_ch_uring_cmd_cb);
+               return -EIOCBQUEUED;
+       }
+
+       return ublk_ch_uring_cmd_local(cmd, issue_flags);
+}
+
 static inline bool ublk_check_ubuf_dir(const struct request *req,
                int ubuf_dir)
 {