io_uring/uring_cmd: implement ->sqe_copy() to avoid unnecessary copies uring_cmd.2
authorJens Axboe <axboe@kernel.dk>
Thu, 5 Jun 2025 17:39:17 +0000 (11:39 -0600)
committerJens Axboe <axboe@kernel.dk>
Tue, 10 Jun 2025 13:36:26 +0000 (07:36 -0600)
uring_cmd currently copies the full SQE at prep time, just in case it
needs it to be stable. However, for inline completions or requests that
get queued up on the device side, there's no need to ever copy the SQE.
This is particularly important, as various use cases of uring_cmd will
be using 128b sized SQEs.

Opt in to using ->sqe_copy() to let the core of io_uring decide when to
copy SQEs. This callback will only be called if it is safe to do so.

Reviewed-by: Caleb Sander Mateos <csander@purestorage.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
io_uring/opdef.c
io_uring/uring_cmd.c
io_uring/uring_cmd.h

index 6e0882b051f93bae2974cc623678b199b39262e5..287f9a23b8164b74226d22cbc8f45cb99ae285d6 100644 (file)
@@ -759,6 +759,7 @@ const struct io_cold_def io_cold_defs[] = {
        },
        [IORING_OP_URING_CMD] = {
                .name                   = "URING_CMD",
+               .sqe_copy               = io_uring_cmd_sqe_copy,
                .cleanup                = io_uring_cmd_cleanup,
        },
        [IORING_OP_SEND_ZC] = {
index e204f4941d72301de869ca7d41cf4554b738095a..9ad0ea5398c2e9234af996907c1cb9cd059e728b 100644 (file)
@@ -205,17 +205,20 @@ int io_uring_cmd_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
        if (!ac)
                return -ENOMEM;
        ac->data.op_data = NULL;
+       ioucmd->sqe = sqe;
+       return 0;
+}
+
+void io_uring_cmd_sqe_copy(struct io_kiocb *req)
+{
+       struct io_uring_cmd *ioucmd = io_kiocb_to_cmd(req, struct io_uring_cmd);
+       struct io_async_cmd *ac = req->async_data;
 
-       /*
-        * Unconditionally cache the SQE for now - this is only needed for
-        * requests that go async, but prep handlers must ensure that any
-        * sqe data is stable beyond prep. Since uring_cmd is special in
-        * that it doesn't read in per-op data, play it safe and ensure that
-        * any SQE data is stable beyond prep. This can later get relaxed.
-        */
-       memcpy(ac->sqes, sqe, uring_sqe_size(req->ctx));
+       /* Should not happen, as REQ_F_SQE_COPIED covers this */
+       if (WARN_ON_ONCE(ioucmd->sqe == ac->sqes))
+               return;
+       memcpy(ac->sqes, ioucmd->sqe, uring_sqe_size(req->ctx));
        ioucmd->sqe = ac->sqes;
-       return 0;
 }
 
 int io_uring_cmd(struct io_kiocb *req, unsigned int issue_flags)
index e6a5142c890ea6420e89e8aaf0285f045041db87..a6dad47afc6bfecc9613835c9441bf1fd642c460 100644 (file)
@@ -11,6 +11,7 @@ struct io_async_cmd {
 
 int io_uring_cmd(struct io_kiocb *req, unsigned int issue_flags);
 int io_uring_cmd_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
+void io_uring_cmd_sqe_copy(struct io_kiocb *req);
 void io_uring_cmd_cleanup(struct io_kiocb *req);
 
 bool io_uring_try_cancel_uring_cmd(struct io_ring_ctx *ctx,