Commit f30bd4d0 authored by Breno Leitao's avatar Breno Leitao Committed by Jens Axboe

io_uring: Split io_issue_def struct

This patch removes some "cold" fields from `struct io_issue_def`.

The plan is to keep only highly used fields into `struct io_issue_def`, so,
it may be hot in the cache. The hot fields are basically all the bitfields
and the callback functions for .issue and .prep.

The other less frequently used fields are now located in a secondary and
cold struct, called `io_cold_def`.

This is the size for the structs:

Before: io_issue_def = 56 bytes
After: io_issue_def = 24 bytes; io_cold_def = 40 bytes
Signed-off-by: default avatarBreno Leitao <leitao@debian.org>
Reviewed-by: default avatarPavel Begunkov <asml.silence@gmail.com>
Link: https://lore.kernel.org/r/20230112144411.2624698-2-leitao@debian.orgSigned-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent a7dd2782
...@@ -1009,7 +1009,7 @@ void io_req_complete_post(struct io_kiocb *req, unsigned issue_flags) ...@@ -1009,7 +1009,7 @@ void io_req_complete_post(struct io_kiocb *req, unsigned issue_flags)
void io_req_defer_failed(struct io_kiocb *req, s32 res) void io_req_defer_failed(struct io_kiocb *req, s32 res)
__must_hold(&ctx->uring_lock) __must_hold(&ctx->uring_lock)
{ {
const struct io_issue_def *def = &io_issue_defs[req->opcode]; const struct io_cold_def *def = &io_cold_defs[req->opcode];
lockdep_assert_held(&req->ctx->uring_lock); lockdep_assert_held(&req->ctx->uring_lock);
...@@ -1741,8 +1741,8 @@ unsigned int io_file_get_flags(struct file *file) ...@@ -1741,8 +1741,8 @@ unsigned int io_file_get_flags(struct file *file)
bool io_alloc_async_data(struct io_kiocb *req) bool io_alloc_async_data(struct io_kiocb *req)
{ {
WARN_ON_ONCE(!io_issue_defs[req->opcode].async_size); WARN_ON_ONCE(!io_cold_defs[req->opcode].async_size);
req->async_data = kmalloc(io_issue_defs[req->opcode].async_size, GFP_KERNEL); req->async_data = kmalloc(io_cold_defs[req->opcode].async_size, GFP_KERNEL);
if (req->async_data) { if (req->async_data) {
req->flags |= REQ_F_ASYNC_DATA; req->flags |= REQ_F_ASYNC_DATA;
return false; return false;
...@@ -1752,20 +1752,21 @@ bool io_alloc_async_data(struct io_kiocb *req) ...@@ -1752,20 +1752,21 @@ bool io_alloc_async_data(struct io_kiocb *req)
int io_req_prep_async(struct io_kiocb *req) int io_req_prep_async(struct io_kiocb *req)
{ {
const struct io_cold_def *cdef = &io_cold_defs[req->opcode];
const struct io_issue_def *def = &io_issue_defs[req->opcode]; const struct io_issue_def *def = &io_issue_defs[req->opcode];
/* assign early for deferred execution for non-fixed file */ /* assign early for deferred execution for non-fixed file */
if (def->needs_file && !(req->flags & REQ_F_FIXED_FILE)) if (def->needs_file && !(req->flags & REQ_F_FIXED_FILE))
req->file = io_file_get_normal(req, req->cqe.fd); req->file = io_file_get_normal(req, req->cqe.fd);
if (!def->prep_async) if (!cdef->prep_async)
return 0; return 0;
if (WARN_ON_ONCE(req_has_async_data(req))) if (WARN_ON_ONCE(req_has_async_data(req)))
return -EFAULT; return -EFAULT;
if (!io_issue_defs[req->opcode].manual_alloc) { if (!def->manual_alloc) {
if (io_alloc_async_data(req)) if (io_alloc_async_data(req))
return -EAGAIN; return -EAGAIN;
} }
return def->prep_async(req); return cdef->prep_async(req);
} }
static u32 io_get_sequence(struct io_kiocb *req) static u32 io_get_sequence(struct io_kiocb *req)
...@@ -1829,7 +1830,7 @@ static void io_clean_op(struct io_kiocb *req) ...@@ -1829,7 +1830,7 @@ static void io_clean_op(struct io_kiocb *req)
} }
if (req->flags & REQ_F_NEED_CLEANUP) { if (req->flags & REQ_F_NEED_CLEANUP) {
const struct io_issue_def *def = &io_issue_defs[req->opcode]; const struct io_cold_def *def = &io_cold_defs[req->opcode];
if (def->cleanup) if (def->cleanup)
def->cleanup(req); def->cleanup(req);
......
This diff is collapsed.
...@@ -29,19 +29,24 @@ struct io_issue_def { ...@@ -29,19 +29,24 @@ struct io_issue_def {
unsigned iopoll_queue : 1; unsigned iopoll_queue : 1;
/* opcode specific path will handle ->async_data allocation if needed */ /* opcode specific path will handle ->async_data allocation if needed */
unsigned manual_alloc : 1; unsigned manual_alloc : 1;
int (*issue)(struct io_kiocb *, unsigned int);
int (*prep)(struct io_kiocb *, const struct io_uring_sqe *);
};
struct io_cold_def {
/* size of async data needed, if any */ /* size of async data needed, if any */
unsigned short async_size; unsigned short async_size;
const char *name; const char *name;
int (*prep)(struct io_kiocb *, const struct io_uring_sqe *);
int (*issue)(struct io_kiocb *, unsigned int);
int (*prep_async)(struct io_kiocb *); int (*prep_async)(struct io_kiocb *);
void (*cleanup)(struct io_kiocb *); void (*cleanup)(struct io_kiocb *);
void (*fail)(struct io_kiocb *); void (*fail)(struct io_kiocb *);
}; };
extern const struct io_issue_def io_issue_defs[]; extern const struct io_issue_def io_issue_defs[];
extern const struct io_cold_def io_cold_defs[];
void io_uring_optable_init(void); void io_uring_optable_init(void);
#endif #endif
...@@ -516,7 +516,7 @@ static void io_req_map_rw(struct io_kiocb *req, const struct iovec *iovec, ...@@ -516,7 +516,7 @@ static void io_req_map_rw(struct io_kiocb *req, const struct iovec *iovec,
static int io_setup_async_rw(struct io_kiocb *req, const struct iovec *iovec, static int io_setup_async_rw(struct io_kiocb *req, const struct iovec *iovec,
struct io_rw_state *s, bool force) struct io_rw_state *s, bool force)
{ {
if (!force && !io_issue_defs[req->opcode].prep_async) if (!force && !io_cold_defs[req->opcode].prep_async)
return 0; return 0;
if (!req_has_async_data(req)) { if (!req_has_async_data(req)) {
struct io_async_rw *iorw; struct io_async_rw *iorw;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment