Skip to content

Commit 1d6d088

Browse files
author
Xiaoguang Wang
committed
io_uring: avoid whole io_wq_work copy for requests completed inline
to #28736503 commit 7cdaf58 upstream If requests can be submitted and completed inline, we don't need to initialize whole io_wq_work in io_init_req(), which is an expensive operation, add a new 'REQ_F_WORK_INITIALIZED' to determine whether io_wq_work is initialized and add a helper io_req_init_async(), users must call io_req_init_async() for the first time touching any members of io_wq_work. I use /dev/nullb0 to evaluate performance improvement in my physical machine: modprobe null_blk nr_devices=1 completion_nsec=0 sudo taskset -c 60 fio -name=fiotest -filename=/dev/nullb0 -iodepth=128 -thread -rw=read -ioengine=io_uring -direct=1 -bs=4k -size=100G -numjobs=1 -time_based -runtime=120 before this patch: Run status group 0 (all jobs): READ: bw=724MiB/s (759MB/s), 724MiB/s-724MiB/s (759MB/s-759MB/s), io=84.8GiB (91.1GB), run=120001-120001msec With this patch: Run status group 0 (all jobs): READ: bw=761MiB/s (798MB/s), 761MiB/s-761MiB/s (798MB/s-798MB/s), io=89.2GiB (95.8GB), run=120001-120001msec About 5% improvement. Signed-off-by: Xiaoguang Wang <xiaoguang.wang@linux.alibaba.com> Acked-by: Joseph Qi <joseph.qi@linux.alibaba.com> Signed-off-by: Jens Axboe <axboe@kernel.dk> Signed-off-by: Xiaoguang Wang <xiaoguang.wang@linux.alibaba.com> Acked-by: Joseph Qi <joseph.qi@linux.alibaba.com>
1 parent c081099 commit 1d6d088

File tree

2 files changed

+36
-9
lines changed

2 files changed

+36
-9
lines changed

fs/io-wq.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,6 @@ struct io_wq_work {
9393
pid_t task_pid;
9494
};
9595

96-
#define INIT_IO_WORK(work) \
97-
do { \
98-
*(work) = (struct io_wq_work){}; \
99-
} while (0) \
100-
10196
static inline struct io_wq_work *wq_next_work(struct io_wq_work *work)
10297
{
10398
if (!work->list.next)

fs/io_uring.c

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,7 @@ enum {
532532
REQ_F_BUFFER_SELECTED_BIT,
533533
REQ_F_NO_FILE_TABLE_BIT,
534534
REQ_F_QUEUE_TIMEOUT_BIT,
535+
REQ_F_WORK_INITIALIZED_BIT,
535536

536537
/* not a real bit, just to check we're not overflowing the space */
537538
__REQ_F_LAST_BIT,
@@ -589,6 +590,8 @@ enum {
589590
REQ_F_NO_FILE_TABLE = BIT(REQ_F_NO_FILE_TABLE_BIT),
590591
/* needs to queue linked timeout */
591592
REQ_F_QUEUE_TIMEOUT = BIT(REQ_F_QUEUE_TIMEOUT_BIT),
593+
/* io_wq_work is initialized */
594+
REQ_F_WORK_INITIALIZED = BIT(REQ_F_WORK_INITIALIZED_BIT),
592595
};
593596

594597
struct async_poll {
@@ -901,6 +904,19 @@ EXPORT_SYMBOL(io_uring_get_socket);
901904

902905
static void io_file_put_work(struct work_struct *work);
903906

907+
/*
908+
* Note: must call io_req_init_async() for the first time you
909+
* touch any members of io_wq_work.
910+
*/
911+
static inline void io_req_init_async(struct io_kiocb *req)
912+
{
913+
if (req->flags & REQ_F_WORK_INITIALIZED)
914+
return;
915+
916+
memset(&req->work, 0, sizeof(req->work));
917+
req->flags |= REQ_F_WORK_INITIALIZED;
918+
}
919+
904920
static inline bool io_async_submit(struct io_ring_ctx *ctx)
905921
{
906922
return ctx->flags & IORING_SETUP_SQPOLL;
@@ -1030,6 +1046,9 @@ static inline void io_req_work_grab_env(struct io_kiocb *req,
10301046

10311047
static inline void io_req_work_drop_env(struct io_kiocb *req)
10321048
{
1049+
if (!(req->flags & REQ_F_WORK_INITIALIZED))
1050+
return;
1051+
10331052
if (req->work.mm) {
10341053
mmdrop(req->work.mm);
10351054
req->work.mm = NULL;
@@ -2776,8 +2795,14 @@ static int __io_splice_prep(struct io_kiocb *req,
27762795
return ret;
27772796
req->flags |= REQ_F_NEED_CLEANUP;
27782797

2779-
if (!S_ISREG(file_inode(sp->file_in)->i_mode))
2798+
if (!S_ISREG(file_inode(sp->file_in)->i_mode)) {
2799+
/*
2800+
* Splice operation will be punted aync, and here need to
2801+
* modify io_wq_work.flags, so initialize io_wq_work firstly.
2802+
*/
2803+
io_req_init_async(req);
27802804
req->work.flags |= IO_WQ_WORK_UNBOUND;
2805+
}
27812806

27822807
return 0;
27832808
}
@@ -3364,8 +3389,10 @@ static int io_close_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
33643389
{
33653390
/*
33663391
* If we queue this for async, it must not be cancellable. That would
3367-
* leave the 'file' in an undeterminate state.
3392+
* leave the 'file' in an undeterminate state, and here need to modify
3393+
* io_wq_work.flags, so initialize io_wq_work firstly.
33683394
*/
3395+
io_req_init_async(req);
33693396
req->work.flags |= IO_WQ_WORK_NO_CANCEL;
33703397

33713398
if (unlikely(req->ctx->flags & (IORING_SETUP_IOPOLL|IORING_SETUP_SQPOLL)))
@@ -4770,6 +4797,8 @@ static int io_req_defer_prep(struct io_kiocb *req,
47704797
if (!sqe)
47714798
return 0;
47724799

4800+
io_req_init_async(req);
4801+
47734802
if (io_op_defs[req->opcode].file_table) {
47744803
ret = io_grab_files(req);
47754804
if (unlikely(ret))
@@ -5424,7 +5453,8 @@ static void __io_queue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe)
54245453
again:
54255454
linked_timeout = io_prep_linked_timeout(req);
54265455

5427-
if (req->work.creds && req->work.creds != current_cred()) {
5456+
if ((req->flags & REQ_F_WORK_INITIALIZED) && req->work.creds &&
5457+
req->work.creds != current_cred()) {
54285458
if (old_creds)
54295459
revert_creds(old_creds);
54305460
if (old_creds == req->work.creds)
@@ -5447,6 +5477,8 @@ static void __io_queue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe)
54475477
goto exit;
54485478
}
54495479
punt:
5480+
io_req_init_async(req);
5481+
54505482
if (io_op_defs[req->opcode].file_table) {
54515483
ret = io_grab_files(req);
54525484
if (ret)
@@ -5699,7 +5731,6 @@ static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req,
56995731
refcount_set(&req->refs, 2);
57005732
req->task = NULL;
57015733
req->result = 0;
5702-
INIT_IO_WORK(&req->work);
57035734

57045735
if (unlikely(req->opcode >= IORING_OP_LAST))
57055736
return -EINVAL;
@@ -5721,6 +5752,7 @@ static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req,
57215752

57225753
id = READ_ONCE(sqe->personality);
57235754
if (id) {
5755+
io_req_init_async(req);
57245756
req->work.creds = idr_find(&ctx->personality_idr, id);
57255757
if (unlikely(!req->work.creds))
57265758
return -EINVAL;

0 commit comments

Comments
 (0)