199f15d8dSJens Axboe // SPDX-License-Identifier: GPL-2.0 299f15d8dSJens Axboe #include <linux/kernel.h> 399f15d8dSJens Axboe #include <linux/errno.h> 499f15d8dSJens Axboe #include <linux/file.h> 599f15d8dSJens Axboe #include <linux/io_uring.h> 62a584012SLuis Chamberlain #include <linux/security.h> 79cda70f6SAnuj Gupta #include <linux/nospec.h> 899f15d8dSJens Axboe 999f15d8dSJens Axboe #include <uapi/linux/io_uring.h> 1099f15d8dSJens Axboe 1199f15d8dSJens Axboe #include "io_uring.h" 12a9216facSAnuj Gupta #include "rsrc.h" 1399f15d8dSJens Axboe #include "uring_cmd.h" 1499f15d8dSJens Axboe 1599f15d8dSJens Axboe static void io_uring_cmd_work(struct io_kiocb *req, bool *locked) 1699f15d8dSJens Axboe { 17f2ccb5aeSStefan Metzmacher struct io_uring_cmd *ioucmd = io_kiocb_to_cmd(req, struct io_uring_cmd); 1899f15d8dSJens Axboe 1999f15d8dSJens Axboe ioucmd->task_work_cb(ioucmd); 2099f15d8dSJens Axboe } 2199f15d8dSJens Axboe 2299f15d8dSJens Axboe void io_uring_cmd_complete_in_task(struct io_uring_cmd *ioucmd, 2399f15d8dSJens Axboe void (*task_work_cb)(struct io_uring_cmd *)) 2499f15d8dSJens Axboe { 2599f15d8dSJens Axboe struct io_kiocb *req = cmd_to_io_kiocb(ioucmd); 2699f15d8dSJens Axboe 2799f15d8dSJens Axboe ioucmd->task_work_cb = task_work_cb; 2899f15d8dSJens Axboe req->io_task_work.func = io_uring_cmd_work; 2999f15d8dSJens Axboe io_req_task_work_add(req); 3099f15d8dSJens Axboe } 3199f15d8dSJens Axboe EXPORT_SYMBOL_GPL(io_uring_cmd_complete_in_task); 3299f15d8dSJens Axboe 3399f15d8dSJens Axboe static inline void io_req_set_cqe32_extra(struct io_kiocb *req, 3499f15d8dSJens Axboe u64 extra1, u64 extra2) 3599f15d8dSJens Axboe { 3699f15d8dSJens Axboe req->extra1 = extra1; 3799f15d8dSJens Axboe req->extra2 = extra2; 3899f15d8dSJens Axboe req->flags |= REQ_F_CQE32_INIT; 3999f15d8dSJens Axboe } 4099f15d8dSJens Axboe 4199f15d8dSJens Axboe /* 4299f15d8dSJens Axboe * Called by consumers of io_uring_cmd, if they originally returned 4399f15d8dSJens Axboe * -EIOCBQUEUED upon receiving the command. 4499f15d8dSJens Axboe */ 4599f15d8dSJens Axboe void io_uring_cmd_done(struct io_uring_cmd *ioucmd, ssize_t ret, ssize_t res2) 4699f15d8dSJens Axboe { 4799f15d8dSJens Axboe struct io_kiocb *req = cmd_to_io_kiocb(ioucmd); 4899f15d8dSJens Axboe 4999f15d8dSJens Axboe if (ret < 0) 5099f15d8dSJens Axboe req_set_fail(req); 5199f15d8dSJens Axboe 52ff2557b7SMing Lei io_req_set_res(req, ret, 0); 5399f15d8dSJens Axboe if (req->ctx->flags & IORING_SETUP_CQE32) 5499f15d8dSJens Axboe io_req_set_cqe32_extra(req, res2, 0); 555756a3a7SKanchan Joshi if (req->ctx->flags & IORING_SETUP_IOPOLL) 565756a3a7SKanchan Joshi /* order with io_iopoll_req_issued() checking ->iopoll_complete */ 575756a3a7SKanchan Joshi smp_store_release(&req->iopoll_completed, 1); 585756a3a7SKanchan Joshi else 59*1bec951cSPavel Begunkov io_req_complete_post(req, 0); 6099f15d8dSJens Axboe } 6199f15d8dSJens Axboe EXPORT_SYMBOL_GPL(io_uring_cmd_done); 6299f15d8dSJens Axboe 6399f15d8dSJens Axboe int io_uring_cmd_prep_async(struct io_kiocb *req) 6499f15d8dSJens Axboe { 65f2ccb5aeSStefan Metzmacher struct io_uring_cmd *ioucmd = io_kiocb_to_cmd(req, struct io_uring_cmd); 6699f15d8dSJens Axboe size_t cmd_size; 6799f15d8dSJens Axboe 689c71d39aSStefan Metzmacher BUILD_BUG_ON(uring_cmd_pdu_size(0) != 16); 699c71d39aSStefan Metzmacher BUILD_BUG_ON(uring_cmd_pdu_size(1) != 80); 709c71d39aSStefan Metzmacher 7199f15d8dSJens Axboe cmd_size = uring_cmd_pdu_size(req->ctx->flags & IORING_SETUP_SQE128); 7299f15d8dSJens Axboe 7399f15d8dSJens Axboe memcpy(req->async_data, ioucmd->cmd, cmd_size); 7499f15d8dSJens Axboe return 0; 7599f15d8dSJens Axboe } 7699f15d8dSJens Axboe 7799f15d8dSJens Axboe int io_uring_cmd_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) 7899f15d8dSJens Axboe { 79f2ccb5aeSStefan Metzmacher struct io_uring_cmd *ioucmd = io_kiocb_to_cmd(req, struct io_uring_cmd); 8099f15d8dSJens Axboe 819cda70f6SAnuj Gupta if (sqe->__pad1) 8299f15d8dSJens Axboe return -EINVAL; 839cda70f6SAnuj Gupta 849cda70f6SAnuj Gupta ioucmd->flags = READ_ONCE(sqe->uring_cmd_flags); 859cda70f6SAnuj Gupta if (ioucmd->flags & ~IORING_URING_CMD_FIXED) 869cda70f6SAnuj Gupta return -EINVAL; 879cda70f6SAnuj Gupta 889cda70f6SAnuj Gupta if (ioucmd->flags & IORING_URING_CMD_FIXED) { 899cda70f6SAnuj Gupta struct io_ring_ctx *ctx = req->ctx; 909cda70f6SAnuj Gupta u16 index; 919cda70f6SAnuj Gupta 929cda70f6SAnuj Gupta req->buf_index = READ_ONCE(sqe->buf_index); 939cda70f6SAnuj Gupta if (unlikely(req->buf_index >= ctx->nr_user_bufs)) 949cda70f6SAnuj Gupta return -EFAULT; 959cda70f6SAnuj Gupta index = array_index_nospec(req->buf_index, ctx->nr_user_bufs); 969cda70f6SAnuj Gupta req->imu = ctx->user_bufs[index]; 979cda70f6SAnuj Gupta io_req_set_rsrc_node(req, ctx, 0); 989cda70f6SAnuj Gupta } 9999f15d8dSJens Axboe ioucmd->cmd = sqe->cmd; 10099f15d8dSJens Axboe ioucmd->cmd_op = READ_ONCE(sqe->cmd_op); 10199f15d8dSJens Axboe return 0; 10299f15d8dSJens Axboe } 10399f15d8dSJens Axboe 10499f15d8dSJens Axboe int io_uring_cmd(struct io_kiocb *req, unsigned int issue_flags) 10599f15d8dSJens Axboe { 106f2ccb5aeSStefan Metzmacher struct io_uring_cmd *ioucmd = io_kiocb_to_cmd(req, struct io_uring_cmd); 10799f15d8dSJens Axboe struct io_ring_ctx *ctx = req->ctx; 10899f15d8dSJens Axboe struct file *file = req->file; 10999f15d8dSJens Axboe int ret; 11099f15d8dSJens Axboe 11199f15d8dSJens Axboe if (!req->file->f_op->uring_cmd) 11299f15d8dSJens Axboe return -EOPNOTSUPP; 11399f15d8dSJens Axboe 1142a584012SLuis Chamberlain ret = security_uring_cmd(ioucmd); 1152a584012SLuis Chamberlain if (ret) 1162a584012SLuis Chamberlain return ret; 1172a584012SLuis Chamberlain 11899f15d8dSJens Axboe if (ctx->flags & IORING_SETUP_SQE128) 11999f15d8dSJens Axboe issue_flags |= IO_URING_F_SQE128; 12099f15d8dSJens Axboe if (ctx->flags & IORING_SETUP_CQE32) 12199f15d8dSJens Axboe issue_flags |= IO_URING_F_CQE32; 1225756a3a7SKanchan Joshi if (ctx->flags & IORING_SETUP_IOPOLL) { 12399f15d8dSJens Axboe issue_flags |= IO_URING_F_IOPOLL; 1245756a3a7SKanchan Joshi req->iopoll_completed = 0; 1255756a3a7SKanchan Joshi WRITE_ONCE(ioucmd->cookie, NULL); 1265756a3a7SKanchan Joshi } 12799f15d8dSJens Axboe 12899f15d8dSJens Axboe if (req_has_async_data(req)) 12999f15d8dSJens Axboe ioucmd->cmd = req->async_data; 13099f15d8dSJens Axboe 13199f15d8dSJens Axboe ret = file->f_op->uring_cmd(ioucmd, issue_flags); 13299f15d8dSJens Axboe if (ret == -EAGAIN) { 13399f15d8dSJens Axboe if (!req_has_async_data(req)) { 13499f15d8dSJens Axboe if (io_alloc_async_data(req)) 13599f15d8dSJens Axboe return -ENOMEM; 13699f15d8dSJens Axboe io_uring_cmd_prep_async(req); 13799f15d8dSJens Axboe } 13899f15d8dSJens Axboe return -EAGAIN; 13999f15d8dSJens Axboe } 14099f15d8dSJens Axboe 14199f15d8dSJens Axboe if (ret != -EIOCBQUEUED) { 1423ed159c9SAnuj Gupta if (ret < 0) 1433ed159c9SAnuj Gupta req_set_fail(req); 1443ed159c9SAnuj Gupta io_req_set_res(req, ret, 0); 145a9c3eda7SKanchan Joshi return ret; 14699f15d8dSJens Axboe } 14799f15d8dSJens Axboe 14899f15d8dSJens Axboe return IOU_ISSUE_SKIP_COMPLETE; 14999f15d8dSJens Axboe } 150a9216facSAnuj Gupta 151a9216facSAnuj Gupta int io_uring_cmd_import_fixed(u64 ubuf, unsigned long len, int rw, 152a9216facSAnuj Gupta struct iov_iter *iter, void *ioucmd) 153a9216facSAnuj Gupta { 154a9216facSAnuj Gupta struct io_kiocb *req = cmd_to_io_kiocb(ioucmd); 155a9216facSAnuj Gupta 156a9216facSAnuj Gupta return io_import_fixed(rw, iter, req->imu, ubuf, len); 157a9216facSAnuj Gupta } 158a9216facSAnuj Gupta EXPORT_SYMBOL_GPL(io_uring_cmd_import_fixed); 159