提交 037118ad 编写于 作者: J Jens Axboe 提交者: Joseph Qi

io_uring: add lookup table for various opcode needs

to #26323588

commit d3656344fea0339fb0365c8df4d2beba4e0089cd upstream.

We currently have various switch statements that check if an opcode needs
a file, mm, etc. These are hard to keep in sync as opcodes are added. Add
a struct io_op_def that holds all of this information, so we have just
one spot to update when opcodes are added.

This also enables us to NOT allocate req->io if a deferred command
doesn't need it, and corrects some mistakes we had in terms of what
commands need mm context.
Signed-off-by: NJens Axboe <axboe@kernel.dk>
Signed-off-by: NJoseph Qi <joseph.qi@linux.alibaba.com>
Acked-by: NXiaoguang Wang <xiaoguang.wang@linux.alibaba.com>
上级 99071bc2
...@@ -516,6 +516,135 @@ struct io_submit_state { ...@@ -516,6 +516,135 @@ struct io_submit_state {
unsigned int ios_left; unsigned int ios_left;
}; };
struct io_op_def {
/* needs req->io allocated for deferral/async */
unsigned async_ctx : 1;
/* needs current->mm setup, does mm access */
unsigned needs_mm : 1;
/* needs req->file assigned */
unsigned needs_file : 1;
/* needs req->file assigned IFF fd is >= 0 */
unsigned fd_non_neg : 1;
/* hash wq insertion if file is a regular file */
unsigned hash_reg_file : 1;
/* unbound wq insertion if file is a non-regular file */
unsigned unbound_nonreg_file : 1;
};
static const struct io_op_def io_op_defs[] = {
{
/* IORING_OP_NOP */
},
{
/* IORING_OP_READV */
.async_ctx = 1,
.needs_mm = 1,
.needs_file = 1,
.unbound_nonreg_file = 1,
},
{
/* IORING_OP_WRITEV */
.async_ctx = 1,
.needs_mm = 1,
.needs_file = 1,
.hash_reg_file = 1,
.unbound_nonreg_file = 1,
},
{
/* IORING_OP_FSYNC */
.needs_file = 1,
},
{
/* IORING_OP_READ_FIXED */
.needs_file = 1,
.unbound_nonreg_file = 1,
},
{
/* IORING_OP_WRITE_FIXED */
.needs_file = 1,
.hash_reg_file = 1,
.unbound_nonreg_file = 1,
},
{
/* IORING_OP_POLL_ADD */
.needs_file = 1,
.unbound_nonreg_file = 1,
},
{
/* IORING_OP_POLL_REMOVE */
},
{
/* IORING_OP_SYNC_FILE_RANGE */
.needs_file = 1,
},
{
/* IORING_OP_SENDMSG */
.async_ctx = 1,
.needs_mm = 1,
.needs_file = 1,
.unbound_nonreg_file = 1,
},
{
/* IORING_OP_RECVMSG */
.async_ctx = 1,
.needs_mm = 1,
.needs_file = 1,
.unbound_nonreg_file = 1,
},
{
/* IORING_OP_TIMEOUT */
.async_ctx = 1,
.needs_mm = 1,
},
{
/* IORING_OP_TIMEOUT_REMOVE */
},
{
/* IORING_OP_ACCEPT */
.needs_mm = 1,
.needs_file = 1,
.unbound_nonreg_file = 1,
},
{
/* IORING_OP_ASYNC_CANCEL */
},
{
/* IORING_OP_LINK_TIMEOUT */
.async_ctx = 1,
.needs_mm = 1,
},
{
/* IORING_OP_CONNECT */
.async_ctx = 1,
.needs_mm = 1,
.needs_file = 1,
.unbound_nonreg_file = 1,
},
{
/* IORING_OP_FALLOCATE */
.needs_file = 1,
},
{
/* IORING_OP_OPENAT */
.needs_file = 1,
.fd_non_neg = 1,
},
{
/* IORING_OP_CLOSE */
.needs_file = 1,
},
{
/* IORING_OP_FILES_UPDATE */
.needs_mm = 1,
},
{
/* IORING_OP_STATX */
.needs_mm = 1,
.needs_file = 1,
.fd_non_neg = 1,
},
};
static void io_wq_submit_work(struct io_wq_work **workptr); static void io_wq_submit_work(struct io_wq_work **workptr);
static void io_cqring_fill_event(struct io_kiocb *req, long res); static void io_cqring_fill_event(struct io_kiocb *req, long res);
static void io_put_req(struct io_kiocb *req); static void io_put_req(struct io_kiocb *req);
...@@ -671,41 +800,20 @@ static void __io_commit_cqring(struct io_ring_ctx *ctx) ...@@ -671,41 +800,20 @@ static void __io_commit_cqring(struct io_ring_ctx *ctx)
} }
} }
static inline bool io_req_needs_user(struct io_kiocb *req)
{
return !(req->opcode == IORING_OP_READ_FIXED ||
req->opcode == IORING_OP_WRITE_FIXED);
}
static inline bool io_prep_async_work(struct io_kiocb *req, static inline bool io_prep_async_work(struct io_kiocb *req,
struct io_kiocb **link) struct io_kiocb **link)
{ {
const struct io_op_def *def = &io_op_defs[req->opcode];
bool do_hashed = false; bool do_hashed = false;
switch (req->opcode) { if (req->flags & REQ_F_ISREG) {
case IORING_OP_WRITEV: if (def->hash_reg_file)
case IORING_OP_WRITE_FIXED:
/* only regular files should be hashed for writes */
if (req->flags & REQ_F_ISREG)
do_hashed = true; do_hashed = true;
/* fall-through */ } else {
case IORING_OP_READV: if (def->unbound_nonreg_file)
case IORING_OP_READ_FIXED:
case IORING_OP_SENDMSG:
case IORING_OP_RECVMSG:
case IORING_OP_ACCEPT:
case IORING_OP_POLL_ADD:
case IORING_OP_CONNECT:
/*
* We know REQ_F_ISREG is not set on some of these
* opcodes, but this enables us to keep the check in
* just one place.
*/
if (!(req->flags & REQ_F_ISREG))
req->work.flags |= IO_WQ_WORK_UNBOUND; req->work.flags |= IO_WQ_WORK_UNBOUND;
break;
} }
if (io_req_needs_user(req)) if (def->needs_mm)
req->work.flags |= IO_WQ_WORK_NEEDS_USER; req->work.flags |= IO_WQ_WORK_NEEDS_USER;
*link = io_prep_linked_timeout(req); *link = io_prep_linked_timeout(req);
...@@ -1823,6 +1931,8 @@ static void io_req_map_rw(struct io_kiocb *req, ssize_t io_size, ...@@ -1823,6 +1931,8 @@ static void io_req_map_rw(struct io_kiocb *req, ssize_t io_size,
static int io_alloc_async_ctx(struct io_kiocb *req) static int io_alloc_async_ctx(struct io_kiocb *req)
{ {
if (!io_op_defs[req->opcode].async_ctx)
return 0;
req->io = kmalloc(sizeof(*req->io), GFP_KERNEL); req->io = kmalloc(sizeof(*req->io), GFP_KERNEL);
return req->io == NULL; return req->io == NULL;
} }
...@@ -3762,29 +3872,13 @@ static void io_wq_submit_work(struct io_wq_work **workptr) ...@@ -3762,29 +3872,13 @@ static void io_wq_submit_work(struct io_wq_work **workptr)
io_wq_assign_next(workptr, nxt); io_wq_assign_next(workptr, nxt);
} }
static bool io_req_op_valid(int op)
{
return op >= IORING_OP_NOP && op < IORING_OP_LAST;
}
static int io_req_needs_file(struct io_kiocb *req, int fd) static int io_req_needs_file(struct io_kiocb *req, int fd)
{ {
switch (req->opcode) { if (!io_op_defs[req->opcode].needs_file)
case IORING_OP_NOP:
case IORING_OP_POLL_REMOVE:
case IORING_OP_TIMEOUT:
case IORING_OP_TIMEOUT_REMOVE:
case IORING_OP_ASYNC_CANCEL:
case IORING_OP_LINK_TIMEOUT:
return 0; return 0;
case IORING_OP_OPENAT: if (fd == -1 && io_op_defs[req->opcode].fd_non_neg)
case IORING_OP_STATX: return 0;
return fd != -1; return 1;
default:
if (io_req_op_valid(req->opcode))
return 1;
return -EINVAL;
}
} }
static inline struct file *io_file_from_index(struct io_ring_ctx *ctx, static inline struct file *io_file_from_index(struct io_ring_ctx *ctx,
...@@ -3801,7 +3895,7 @@ static int io_req_set_file(struct io_submit_state *state, struct io_kiocb *req, ...@@ -3801,7 +3895,7 @@ static int io_req_set_file(struct io_submit_state *state, struct io_kiocb *req,
{ {
struct io_ring_ctx *ctx = req->ctx; struct io_ring_ctx *ctx = req->ctx;
unsigned flags; unsigned flags;
int fd, ret; int fd;
flags = READ_ONCE(sqe->flags); flags = READ_ONCE(sqe->flags);
fd = READ_ONCE(sqe->fd); fd = READ_ONCE(sqe->fd);
...@@ -3809,9 +3903,8 @@ static int io_req_set_file(struct io_submit_state *state, struct io_kiocb *req, ...@@ -3809,9 +3903,8 @@ static int io_req_set_file(struct io_submit_state *state, struct io_kiocb *req,
if (flags & IOSQE_IO_DRAIN) if (flags & IOSQE_IO_DRAIN)
req->flags |= REQ_F_IO_DRAIN; req->flags |= REQ_F_IO_DRAIN;
ret = io_req_needs_file(req, fd); if (!io_req_needs_file(req, fd))
if (ret <= 0) return 0;
return ret;
if (flags & IOSQE_FIXED_FILE) { if (flags & IOSQE_FIXED_FILE) {
if (unlikely(!ctx->file_data || if (unlikely(!ctx->file_data ||
...@@ -4237,7 +4330,16 @@ static int io_submit_sqes(struct io_ring_ctx *ctx, unsigned int nr, ...@@ -4237,7 +4330,16 @@ static int io_submit_sqes(struct io_ring_ctx *ctx, unsigned int nr,
break; break;
} }
if (io_req_needs_user(req) && !*mm) { /* will complete beyond this point, count as submitted */
submitted++;
if (unlikely(req->opcode >= IORING_OP_LAST)) {
io_cqring_add_event(req, -EINVAL);
io_double_put_req(req);
break;
}
if (io_op_defs[req->opcode].needs_mm && !*mm) {
mm_fault = mm_fault || !mmget_not_zero(ctx->sqo_mm); mm_fault = mm_fault || !mmget_not_zero(ctx->sqo_mm);
if (!mm_fault) { if (!mm_fault) {
use_mm(ctx->sqo_mm); use_mm(ctx->sqo_mm);
...@@ -4245,7 +4347,6 @@ static int io_submit_sqes(struct io_ring_ctx *ctx, unsigned int nr, ...@@ -4245,7 +4347,6 @@ static int io_submit_sqes(struct io_ring_ctx *ctx, unsigned int nr,
} }
} }
submitted++;
req->ring_file = ring_file; req->ring_file = ring_file;
req->ring_fd = ring_fd; req->ring_fd = ring_fd;
req->has_user = *mm != NULL; req->has_user = *mm != NULL;
...@@ -6089,6 +6190,7 @@ SYSCALL_DEFINE4(io_uring_register, unsigned int, fd, unsigned int, opcode, ...@@ -6089,6 +6190,7 @@ SYSCALL_DEFINE4(io_uring_register, unsigned int, fd, unsigned int, opcode,
static int __init io_uring_init(void) static int __init io_uring_init(void)
{ {
BUILD_BUG_ON(ARRAY_SIZE(io_op_defs) != IORING_OP_LAST);
req_cachep = KMEM_CACHE(io_kiocb, SLAB_HWCACHE_ALIGN | SLAB_PANIC); req_cachep = KMEM_CACHE(io_kiocb, SLAB_HWCACHE_ALIGN | SLAB_PANIC);
return 0; return 0;
}; };
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册