xref: /openbmc/linux/io_uring/uring_cmd.c (revision 9566ef57)
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>
10*9566ef57SAl Viro #include <asm/ioctls.h>
1199f15d8dSJens Axboe 
1299f15d8dSJens Axboe #include "io_uring.h"
13a9216facSAnuj Gupta #include "rsrc.h"
1499f15d8dSJens Axboe #include "uring_cmd.h"
1599f15d8dSJens Axboe 
io_uring_cmd_work(struct io_kiocb * req,struct io_tw_state * ts)16a282967cSPavel Begunkov static void io_uring_cmd_work(struct io_kiocb *req, struct io_tw_state *ts)
1799f15d8dSJens Axboe {
18f2ccb5aeSStefan Metzmacher 	struct io_uring_cmd *ioucmd = io_kiocb_to_cmd(req, struct io_uring_cmd);
19a282967cSPavel Begunkov 	unsigned issue_flags = ts->locked ? 0 : IO_URING_F_UNLOCKED;
2099f15d8dSJens Axboe 
219d2789acSJens Axboe 	ioucmd->task_work_cb(ioucmd, issue_flags);
2299f15d8dSJens Axboe }
2399f15d8dSJens Axboe 
__io_uring_cmd_do_in_task(struct io_uring_cmd * ioucmd,void (* task_work_cb)(struct io_uring_cmd *,unsigned),unsigned flags)245f3139fcSPavel Begunkov void __io_uring_cmd_do_in_task(struct io_uring_cmd *ioucmd,
255f3139fcSPavel Begunkov 			void (*task_work_cb)(struct io_uring_cmd *, unsigned),
265f3139fcSPavel Begunkov 			unsigned flags)
2799f15d8dSJens Axboe {
2899f15d8dSJens Axboe 	struct io_kiocb *req = cmd_to_io_kiocb(ioucmd);
2999f15d8dSJens Axboe 
3099f15d8dSJens Axboe 	ioucmd->task_work_cb = task_work_cb;
3199f15d8dSJens Axboe 	req->io_task_work.func = io_uring_cmd_work;
325f3139fcSPavel Begunkov 	__io_req_task_work_add(req, flags);
3399f15d8dSJens Axboe }
345f3139fcSPavel Begunkov EXPORT_SYMBOL_GPL(__io_uring_cmd_do_in_task);
355f3139fcSPavel Begunkov 
io_uring_cmd_do_in_task_lazy(struct io_uring_cmd * ioucmd,void (* task_work_cb)(struct io_uring_cmd *,unsigned))365f3139fcSPavel Begunkov void io_uring_cmd_do_in_task_lazy(struct io_uring_cmd *ioucmd,
375f3139fcSPavel Begunkov 			void (*task_work_cb)(struct io_uring_cmd *, unsigned))
385f3139fcSPavel Begunkov {
395f3139fcSPavel Begunkov 	__io_uring_cmd_do_in_task(ioucmd, task_work_cb, IOU_F_TWQ_LAZY_WAKE);
405f3139fcSPavel Begunkov }
415f3139fcSPavel Begunkov EXPORT_SYMBOL_GPL(io_uring_cmd_do_in_task_lazy);
4299f15d8dSJens Axboe 
io_req_set_cqe32_extra(struct io_kiocb * req,u64 extra1,u64 extra2)4399f15d8dSJens Axboe static inline void io_req_set_cqe32_extra(struct io_kiocb *req,
4499f15d8dSJens Axboe 					  u64 extra1, u64 extra2)
4599f15d8dSJens Axboe {
46b24c5d75SPavel Begunkov 	req->big_cqe.extra1 = extra1;
47b24c5d75SPavel Begunkov 	req->big_cqe.extra2 = extra2;
4899f15d8dSJens Axboe }
4999f15d8dSJens Axboe 
5099f15d8dSJens Axboe /*
5199f15d8dSJens Axboe  * Called by consumers of io_uring_cmd, if they originally returned
5299f15d8dSJens Axboe  * -EIOCBQUEUED upon receiving the command.
5399f15d8dSJens Axboe  */
io_uring_cmd_done(struct io_uring_cmd * ioucmd,ssize_t ret,ssize_t res2,unsigned issue_flags)549d2789acSJens Axboe void io_uring_cmd_done(struct io_uring_cmd *ioucmd, ssize_t ret, ssize_t res2,
559d2789acSJens Axboe 		       unsigned issue_flags)
5699f15d8dSJens Axboe {
5799f15d8dSJens Axboe 	struct io_kiocb *req = cmd_to_io_kiocb(ioucmd);
5899f15d8dSJens Axboe 
5999f15d8dSJens Axboe 	if (ret < 0)
6099f15d8dSJens Axboe 		req_set_fail(req);
6199f15d8dSJens Axboe 
62ff2557b7SMing Lei 	io_req_set_res(req, ret, 0);
6399f15d8dSJens Axboe 	if (req->ctx->flags & IORING_SETUP_CQE32)
6499f15d8dSJens Axboe 		io_req_set_cqe32_extra(req, res2, 0);
6527a67079SJens Axboe 	if (req->ctx->flags & IORING_SETUP_IOPOLL) {
665756a3a7SKanchan Joshi 		/* order with io_iopoll_req_issued() checking ->iopoll_complete */
675756a3a7SKanchan Joshi 		smp_store_release(&req->iopoll_completed, 1);
6827a67079SJens Axboe 	} else {
6927a67079SJens Axboe 		struct io_tw_state ts = {
7027a67079SJens Axboe 			.locked = !(issue_flags & IO_URING_F_UNLOCKED),
7127a67079SJens Axboe 		};
7227a67079SJens Axboe 		io_req_task_complete(req, &ts);
7327a67079SJens Axboe 	}
7499f15d8dSJens Axboe }
7599f15d8dSJens Axboe EXPORT_SYMBOL_GPL(io_uring_cmd_done);
7699f15d8dSJens Axboe 
io_uring_cmd_prep_async(struct io_kiocb * req)7799f15d8dSJens Axboe int io_uring_cmd_prep_async(struct io_kiocb *req)
7899f15d8dSJens Axboe {
79f2ccb5aeSStefan Metzmacher 	struct io_uring_cmd *ioucmd = io_kiocb_to_cmd(req, struct io_uring_cmd);
8099f15d8dSJens Axboe 
81fd9b8547SBreno Leitao 	memcpy(req->async_data, ioucmd->sqe, uring_sqe_size(req->ctx));
82fd9b8547SBreno Leitao 	ioucmd->sqe = req->async_data;
8399f15d8dSJens Axboe 	return 0;
8499f15d8dSJens Axboe }
8599f15d8dSJens Axboe 
io_uring_cmd_prep(struct io_kiocb * req,const struct io_uring_sqe * sqe)8699f15d8dSJens Axboe int io_uring_cmd_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
8799f15d8dSJens Axboe {
88f2ccb5aeSStefan Metzmacher 	struct io_uring_cmd *ioucmd = io_kiocb_to_cmd(req, struct io_uring_cmd);
8999f15d8dSJens Axboe 
909cda70f6SAnuj Gupta 	if (sqe->__pad1)
9199f15d8dSJens Axboe 		return -EINVAL;
929cda70f6SAnuj Gupta 
939cda70f6SAnuj Gupta 	ioucmd->flags = READ_ONCE(sqe->uring_cmd_flags);
949cda70f6SAnuj Gupta 	if (ioucmd->flags & ~IORING_URING_CMD_FIXED)
959cda70f6SAnuj Gupta 		return -EINVAL;
969cda70f6SAnuj Gupta 
979cda70f6SAnuj Gupta 	if (ioucmd->flags & IORING_URING_CMD_FIXED) {
989cda70f6SAnuj Gupta 		struct io_ring_ctx *ctx = req->ctx;
999cda70f6SAnuj Gupta 		u16 index;
1009cda70f6SAnuj Gupta 
1019cda70f6SAnuj Gupta 		req->buf_index = READ_ONCE(sqe->buf_index);
1029cda70f6SAnuj Gupta 		if (unlikely(req->buf_index >= ctx->nr_user_bufs))
1039cda70f6SAnuj Gupta 			return -EFAULT;
1049cda70f6SAnuj Gupta 		index = array_index_nospec(req->buf_index, ctx->nr_user_bufs);
1059cda70f6SAnuj Gupta 		req->imu = ctx->user_bufs[index];
1069cda70f6SAnuj Gupta 		io_req_set_rsrc_node(req, ctx, 0);
1079cda70f6SAnuj Gupta 	}
108fd9b8547SBreno Leitao 	ioucmd->sqe = sqe;
10999f15d8dSJens Axboe 	ioucmd->cmd_op = READ_ONCE(sqe->cmd_op);
11099f15d8dSJens Axboe 	return 0;
11199f15d8dSJens Axboe }
11299f15d8dSJens Axboe 
io_uring_cmd(struct io_kiocb * req,unsigned int issue_flags)11399f15d8dSJens Axboe int io_uring_cmd(struct io_kiocb *req, unsigned int issue_flags)
11499f15d8dSJens Axboe {
115f2ccb5aeSStefan Metzmacher 	struct io_uring_cmd *ioucmd = io_kiocb_to_cmd(req, struct io_uring_cmd);
11699f15d8dSJens Axboe 	struct io_ring_ctx *ctx = req->ctx;
11799f15d8dSJens Axboe 	struct file *file = req->file;
11899f15d8dSJens Axboe 	int ret;
11999f15d8dSJens Axboe 
12003b3d6beSJens Axboe 	if (!file->f_op->uring_cmd)
12199f15d8dSJens Axboe 		return -EOPNOTSUPP;
12299f15d8dSJens Axboe 
1232a584012SLuis Chamberlain 	ret = security_uring_cmd(ioucmd);
1242a584012SLuis Chamberlain 	if (ret)
1252a584012SLuis Chamberlain 		return ret;
1262a584012SLuis Chamberlain 
12799f15d8dSJens Axboe 	if (ctx->flags & IORING_SETUP_SQE128)
12899f15d8dSJens Axboe 		issue_flags |= IO_URING_F_SQE128;
12999f15d8dSJens Axboe 	if (ctx->flags & IORING_SETUP_CQE32)
13099f15d8dSJens Axboe 		issue_flags |= IO_URING_F_CQE32;
1315756a3a7SKanchan Joshi 	if (ctx->flags & IORING_SETUP_IOPOLL) {
13203b3d6beSJens Axboe 		if (!file->f_op->uring_cmd_iopoll)
13303b3d6beSJens Axboe 			return -EOPNOTSUPP;
13499f15d8dSJens Axboe 		issue_flags |= IO_URING_F_IOPOLL;
1355756a3a7SKanchan Joshi 		req->iopoll_completed = 0;
1365756a3a7SKanchan Joshi 		WRITE_ONCE(ioucmd->cookie, NULL);
1375756a3a7SKanchan Joshi 	}
13899f15d8dSJens Axboe 
13999f15d8dSJens Axboe 	ret = file->f_op->uring_cmd(ioucmd, issue_flags);
14099f15d8dSJens Axboe 	if (ret == -EAGAIN) {
14199f15d8dSJens Axboe 		if (!req_has_async_data(req)) {
14299f15d8dSJens Axboe 			if (io_alloc_async_data(req))
14399f15d8dSJens Axboe 				return -ENOMEM;
14499f15d8dSJens Axboe 			io_uring_cmd_prep_async(req);
14599f15d8dSJens Axboe 		}
14699f15d8dSJens Axboe 		return -EAGAIN;
14799f15d8dSJens Axboe 	}
14899f15d8dSJens Axboe 
14999f15d8dSJens Axboe 	if (ret != -EIOCBQUEUED) {
1503ed159c9SAnuj Gupta 		if (ret < 0)
1513ed159c9SAnuj Gupta 			req_set_fail(req);
1523ed159c9SAnuj Gupta 		io_req_set_res(req, ret, 0);
153a9c3eda7SKanchan Joshi 		return ret;
15499f15d8dSJens Axboe 	}
15599f15d8dSJens Axboe 
15699f15d8dSJens Axboe 	return IOU_ISSUE_SKIP_COMPLETE;
15799f15d8dSJens Axboe }
158a9216facSAnuj Gupta 
io_uring_cmd_import_fixed(u64 ubuf,unsigned long len,int rw,struct iov_iter * iter,void * ioucmd)159a9216facSAnuj Gupta int io_uring_cmd_import_fixed(u64 ubuf, unsigned long len, int rw,
160a9216facSAnuj Gupta 			      struct iov_iter *iter, void *ioucmd)
161a9216facSAnuj Gupta {
162a9216facSAnuj Gupta 	struct io_kiocb *req = cmd_to_io_kiocb(ioucmd);
163a9216facSAnuj Gupta 
164a9216facSAnuj Gupta 	return io_import_fixed(rw, iter, req->imu, ubuf, len);
165a9216facSAnuj Gupta }
166a9216facSAnuj Gupta EXPORT_SYMBOL_GPL(io_uring_cmd_import_fixed);
1678e9fad0eSBreno Leitao 
io_uring_cmd_sock(struct io_uring_cmd * cmd,unsigned int issue_flags)1688e9fad0eSBreno Leitao int io_uring_cmd_sock(struct io_uring_cmd *cmd, unsigned int issue_flags)
1698e9fad0eSBreno Leitao {
1708e9fad0eSBreno Leitao 	struct socket *sock = cmd->file->private_data;
1718e9fad0eSBreno Leitao 	struct sock *sk = sock->sk;
1728e9fad0eSBreno Leitao 	struct proto *prot = READ_ONCE(sk->sk_prot);
1738e9fad0eSBreno Leitao 	int ret, arg = 0;
1748e9fad0eSBreno Leitao 
1758e9fad0eSBreno Leitao 	if (!prot || !prot->ioctl)
1768e9fad0eSBreno Leitao 		return -EOPNOTSUPP;
1778e9fad0eSBreno Leitao 
1788e9fad0eSBreno Leitao 	switch (cmd->sqe->cmd_op) {
1798e9fad0eSBreno Leitao 	case SOCKET_URING_OP_SIOCINQ:
1808e9fad0eSBreno Leitao 		ret = prot->ioctl(sk, SIOCINQ, &arg);
1818e9fad0eSBreno Leitao 		if (ret)
1828e9fad0eSBreno Leitao 			return ret;
1838e9fad0eSBreno Leitao 		return arg;
1848e9fad0eSBreno Leitao 	case SOCKET_URING_OP_SIOCOUTQ:
1858e9fad0eSBreno Leitao 		ret = prot->ioctl(sk, SIOCOUTQ, &arg);
1868e9fad0eSBreno Leitao 		if (ret)
1878e9fad0eSBreno Leitao 			return ret;
1888e9fad0eSBreno Leitao 		return arg;
1898e9fad0eSBreno Leitao 	default:
1908e9fad0eSBreno Leitao 		return -EOPNOTSUPP;
1918e9fad0eSBreno Leitao 	}
1928e9fad0eSBreno Leitao }
1938e9fad0eSBreno Leitao EXPORT_SYMBOL_GPL(io_uring_cmd_sock);
194