1// SPDX-License-Identifier: GPL-2.0
2#include <linux/kernel.h>
3#include <linux/errno.h>
4#include <linux/fs.h>
5#include <linux/file.h>
6#include <linux/io_uring.h>
7
8#include <uapi/linux/io_uring.h>
9
10#include "io_uring.h"
11#include "rsrc.h"
12#include "nop.h"
13
14struct io_nop {
15 /* NOTE: kiocb has the file as the first member, so don't do it here */
16 struct file *file;
17 int result;
18 int fd;
19 unsigned int flags;
20 __u64 extra1;
21 __u64 extra2;
22};
23
24#define NOP_FLAGS (IORING_NOP_INJECT_RESULT | IORING_NOP_FIXED_FILE | \
25 IORING_NOP_FIXED_BUFFER | IORING_NOP_FILE | \
26 IORING_NOP_TW | IORING_NOP_CQE32)
27
28int io_nop_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
29{
30 struct io_nop *nop = io_kiocb_to_cmd(req, struct io_nop);
31
32 nop->flags = READ_ONCE(sqe->nop_flags);
33 if (nop->flags & ~NOP_FLAGS)
34 return -EINVAL;
35
36 if (nop->flags & IORING_NOP_INJECT_RESULT)
37 nop->result = READ_ONCE(sqe->len);
38 else
39 nop->result = 0;
40 if (nop->flags & IORING_NOP_FILE)
41 nop->fd = READ_ONCE(sqe->fd);
42 else
43 nop->fd = -1;
44 if (nop->flags & IORING_NOP_FIXED_BUFFER)
45 req->buf_index = READ_ONCE(sqe->buf_index);
46 if (nop->flags & IORING_NOP_CQE32) {
47 struct io_ring_ctx *ctx = req->ctx;
48
49 if (!(ctx->flags & (IORING_SETUP_CQE32|IORING_SETUP_CQE_MIXED)))
50 return -EINVAL;
51 nop->extra1 = READ_ONCE(sqe->off);
52 nop->extra2 = READ_ONCE(sqe->addr);
53 }
54 return 0;
55}
56
57int io_nop(struct io_kiocb *req, unsigned int issue_flags)
58{
59 struct io_nop *nop = io_kiocb_to_cmd(req, struct io_nop);
60 int ret = nop->result;
61
62 if (nop->flags & IORING_NOP_FILE) {
63 if (nop->flags & IORING_NOP_FIXED_FILE) {
64 req->file = io_file_get_fixed(req, fd: nop->fd, issue_flags);
65 req->flags |= REQ_F_FIXED_FILE;
66 } else {
67 req->file = io_file_get_normal(req, fd: nop->fd);
68 }
69 if (!req->file) {
70 ret = -EBADF;
71 goto done;
72 }
73 }
74 if (nop->flags & IORING_NOP_FIXED_BUFFER) {
75 if (!io_find_buf_node(req, issue_flags))
76 ret = -EFAULT;
77 }
78done:
79 if (ret < 0)
80 req_set_fail(req);
81 if (nop->flags & IORING_NOP_CQE32)
82 io_req_set_res32(req, res: nop->result, cflags: 0, extra1: nop->extra1, extra2: nop->extra2);
83 else
84 io_req_set_res(req, res: nop->result, cflags: 0);
85 if (nop->flags & IORING_NOP_TW) {
86 req->io_task_work.func = io_req_task_complete;
87 io_req_task_work_add(req);
88 return IOU_ISSUE_SKIP_COMPLETE;
89 }
90 return IOU_COMPLETE;
91}
92