Add IORING_OP_NOP_FAIL so that it is easy to inject failure from userspace. Like IORING_OP_NOP, the main use case is test, and it is very helpful for covering failure handling code in io_uring core change. Signed-off-by: Ming Lei <ming.lei@xxxxxxxxxx> --- include/uapi/linux/io_uring.h | 2 ++ io_uring/nop.c | 27 +++++++++++++++++++++++++++ io_uring/nop.h | 3 +++ io_uring/opdef.c | 9 +++++++++ 4 files changed, 41 insertions(+) diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h index 922f29b07ccc..18e58477e0f0 100644 --- a/include/uapi/linux/io_uring.h +++ b/include/uapi/linux/io_uring.h @@ -72,6 +72,7 @@ struct io_uring_sqe { __u32 waitid_flags; __u32 futex_flags; __u32 install_fd_flags; + __s32 nop_fail_res; }; __u64 user_data; /* data to be passed back at completion time */ /* pack this to avoid bogus arm OABI complaints */ @@ -259,6 +260,7 @@ enum io_uring_op { IORING_OP_FUTEX_WAITV, IORING_OP_FIXED_FD_INSTALL, IORING_OP_FTRUNCATE, + IORING_OP_NOP_FAIL, /* this goes last, obviously */ IORING_OP_LAST, diff --git a/io_uring/nop.c b/io_uring/nop.c index d956599a3c1b..c30547e53b5c 100644 --- a/io_uring/nop.c +++ b/io_uring/nop.c @@ -10,6 +10,12 @@ #include "io_uring.h" #include "nop.h" +struct io_nop_fail { + /* NOTE: kiocb has the file as the first member, so don't do it here */ + struct file *file; + int res; +}; + int io_nop_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) { return 0; @@ -23,3 +29,24 @@ int io_nop(struct io_kiocb *req, unsigned int issue_flags) io_req_set_res(req, 0, 0); return IOU_OK; } + +int io_nop_fail_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) +{ + struct io_nop_fail *nf = io_kiocb_to_cmd(req, struct io_nop_fail); + + nf->res = READ_ONCE(sqe->nop_fail_res); + return 0; +} + +/* + * IORING_OP_NOP just posts a completion event, nothing else. + */ +int io_nop_fail(struct io_kiocb *req, unsigned int issue_flags) +{ + struct io_nop_fail *nf = io_kiocb_to_cmd(req, struct io_nop_fail); + + if (nf->res < 0) + req_set_fail(req); + io_req_set_res(req, nf->res, 0); + return IOU_OK; +} diff --git a/io_uring/nop.h b/io_uring/nop.h index 97f1535c9dec..ef40d3b15899 100644 --- a/io_uring/nop.h +++ b/io_uring/nop.h @@ -2,3 +2,6 @@ int io_nop_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe); int io_nop(struct io_kiocb *req, unsigned int issue_flags); + +int io_nop_fail_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe); +int io_nop_fail(struct io_kiocb *req, unsigned int issue_flags); diff --git a/io_uring/opdef.c b/io_uring/opdef.c index 92b657a063a0..eadc5a12ee06 100644 --- a/io_uring/opdef.c +++ b/io_uring/opdef.c @@ -56,6 +56,12 @@ const struct io_issue_def io_issue_defs[] = { .prep = io_nop_prep, .issue = io_nop, }, + [IORING_OP_NOP_FAIL] = { + .audit_skip = 1, + .iopoll = 1, + .prep = io_nop_fail_prep, + .issue = io_nop_fail, + }, [IORING_OP_READV] = { .needs_file = 1, .unbound_nonreg_file = 1, @@ -506,6 +512,9 @@ const struct io_cold_def io_cold_defs[] = { [IORING_OP_NOP] = { .name = "NOP", }, + [IORING_OP_NOP_FAIL] = { + .name = "NOP_FAIL", + }, [IORING_OP_READV] = { .name = "READV", .cleanup = io_readv_writev_cleanup, -- 2.44.0