Skip to content

Commit b6f58a3

Browse files
committed
io_uring: move struct io_kiocb from task_struct to io_uring_task
Rather than store the task_struct itself in struct io_kiocb, store the io_uring specific task_struct. The life times are the same in terms of io_uring, and this avoids doing some dereferences through the task_struct. For the hot path of putting local task references, we can deref req->tctx instead, which we'll need anyway in that function regardless of whether it's local or remote references. This is mostly straight forward, except the original task PF_EXITING check needs a bit of tweaking. task_work is _always_ run from the originating task, except in the fallback case, where it's run from a kernel thread. Replace the potentially racy (in case of fallback work) checks for req->task->flags with current->flags. It's either the still the original task, in which case PF_EXITING will be sane, or it has PF_KTHREAD set, in which case it's fallback work. Both cases should prevent moving forward with the given request. Signed-off-by: Jens Axboe <[email protected]>
1 parent 6ed368c commit b6f58a3

File tree

14 files changed

+48
-36
lines changed

14 files changed

+48
-36
lines changed

include/linux/io_uring/cmd.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ static inline void io_uring_cmd_complete_in_task(struct io_uring_cmd *ioucmd,
110110

111111
static inline struct task_struct *io_uring_cmd_get_task(struct io_uring_cmd *cmd)
112112
{
113-
return cmd_to_io_kiocb(cmd)->task;
113+
return cmd_to_io_kiocb(cmd)->tctx->task;
114114
}
115115

116116
#endif /* _LINUX_IO_URING_CMD_H */

include/linux/io_uring_types.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ struct io_uring_task {
8484
/* submission side */
8585
int cached_refs;
8686
const struct io_ring_ctx *last;
87+
struct task_struct *task;
8788
struct io_wq *io_wq;
8889
struct file *registered_rings[IO_RINGFD_REG_MAX];
8990

@@ -625,7 +626,7 @@ struct io_kiocb {
625626
struct io_cqe cqe;
626627

627628
struct io_ring_ctx *ctx;
628-
struct task_struct *task;
629+
struct io_uring_task *tctx;
629630

630631
union {
631632
/* stores selected buf, valid IFF REQ_F_BUFFER_SELECTED is set */

io_uring/cancel.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ int io_async_cancel(struct io_kiocb *req, unsigned int issue_flags)
205205
.opcode = cancel->opcode,
206206
.seq = atomic_inc_return(&req->ctx->cancel_seq),
207207
};
208-
struct io_uring_task *tctx = req->task->io_uring;
208+
struct io_uring_task *tctx = req->tctx;
209209
int ret;
210210

211211
if (cd.flags & IORING_ASYNC_CANCEL_FD) {

io_uring/fdinfo.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ __cold void io_uring_show_fdinfo(struct seq_file *m, struct file *file)
203203

204204
hlist_for_each_entry(req, &hb->list, hash_node)
205205
seq_printf(m, " op=%d, task_works=%d\n", req->opcode,
206-
task_work_pending(req->task));
206+
task_work_pending(req->tctx->task));
207207
}
208208

209209
if (has_lock)

io_uring/io_uring.c

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ bool io_match_task_safe(struct io_kiocb *head, struct io_uring_task *tctx,
206206
{
207207
bool matched;
208208

209-
if (tctx && head->task->io_uring != tctx)
209+
if (tctx && head->tctx != tctx)
210210
return false;
211211
if (cancel_all)
212212
return true;
@@ -407,11 +407,8 @@ static void io_clean_op(struct io_kiocb *req)
407407
kfree(req->apoll);
408408
req->apoll = NULL;
409409
}
410-
if (req->flags & REQ_F_INFLIGHT) {
411-
struct io_uring_task *tctx = req->task->io_uring;
412-
413-
atomic_dec(&tctx->inflight_tracked);
414-
}
410+
if (req->flags & REQ_F_INFLIGHT)
411+
atomic_dec(&req->tctx->inflight_tracked);
415412
if (req->flags & REQ_F_CREDS)
416413
put_cred(req->creds);
417414
if (req->flags & REQ_F_ASYNC_DATA) {
@@ -425,7 +422,7 @@ static inline void io_req_track_inflight(struct io_kiocb *req)
425422
{
426423
if (!(req->flags & REQ_F_INFLIGHT)) {
427424
req->flags |= REQ_F_INFLIGHT;
428-
atomic_inc(&req->task->io_uring->inflight_tracked);
425+
atomic_inc(&req->tctx->inflight_tracked);
429426
}
430427
}
431428

@@ -514,7 +511,7 @@ static void io_prep_async_link(struct io_kiocb *req)
514511
static void io_queue_iowq(struct io_kiocb *req)
515512
{
516513
struct io_kiocb *link = io_prep_linked_timeout(req);
517-
struct io_uring_task *tctx = req->task->io_uring;
514+
struct io_uring_task *tctx = req->tctx;
518515

519516
BUG_ON(!tctx);
520517
BUG_ON(!tctx->io_wq);
@@ -529,7 +526,7 @@ static void io_queue_iowq(struct io_kiocb *req)
529526
* procedure rather than attempt to run this request (or create a new
530527
* worker for it).
531528
*/
532-
if (WARN_ON_ONCE(!same_thread_group(req->task, current)))
529+
if (WARN_ON_ONCE(!same_thread_group(tctx->task, current)))
533530
atomic_or(IO_WQ_WORK_CANCEL, &req->work.flags);
534531

535532
trace_io_uring_queue_async_work(req, io_wq_is_hashed(&req->work));
@@ -678,17 +675,17 @@ static void io_cqring_do_overflow_flush(struct io_ring_ctx *ctx)
678675
}
679676

680677
/* must to be called somewhat shortly after putting a request */
681-
static inline void io_put_task(struct task_struct *task)
678+
static inline void io_put_task(struct io_kiocb *req)
682679
{
683-
struct io_uring_task *tctx = task->io_uring;
680+
struct io_uring_task *tctx = req->tctx;
684681

685-
if (likely(task == current)) {
682+
if (likely(tctx->task == current)) {
686683
tctx->cached_refs++;
687684
} else {
688685
percpu_counter_sub(&tctx->inflight, 1);
689686
if (unlikely(atomic_read(&tctx->in_cancel)))
690687
wake_up(&tctx->wait);
691-
put_task_struct(task);
688+
put_task_struct(tctx->task);
692689
}
693690
}
694691

@@ -1207,7 +1204,7 @@ static inline void io_req_local_work_add(struct io_kiocb *req,
12071204

12081205
static void io_req_normal_work_add(struct io_kiocb *req)
12091206
{
1210-
struct io_uring_task *tctx = req->task->io_uring;
1207+
struct io_uring_task *tctx = req->tctx;
12111208
struct io_ring_ctx *ctx = req->ctx;
12121209

12131210
/* task_work already pending, we're done */
@@ -1226,7 +1223,7 @@ static void io_req_normal_work_add(struct io_kiocb *req)
12261223
return;
12271224
}
12281225

1229-
if (likely(!task_work_add(req->task, &tctx->task_work, ctx->notify_method)))
1226+
if (likely(!task_work_add(tctx->task, &tctx->task_work, ctx->notify_method)))
12301227
return;
12311228

12321229
io_fallback_tw(tctx, false);
@@ -1343,8 +1340,7 @@ static void io_req_task_cancel(struct io_kiocb *req, struct io_tw_state *ts)
13431340
void io_req_task_submit(struct io_kiocb *req, struct io_tw_state *ts)
13441341
{
13451342
io_tw_lock(req->ctx, ts);
1346-
/* req->task == current here, checking PF_EXITING is safe */
1347-
if (unlikely(req->task->flags & PF_EXITING))
1343+
if (unlikely(io_should_terminate_tw()))
13481344
io_req_defer_failed(req, -EFAULT);
13491345
else if (req->flags & REQ_F_FORCE_ASYNC)
13501346
io_queue_iowq(req);
@@ -1403,7 +1399,7 @@ static void io_free_batch_list(struct io_ring_ctx *ctx,
14031399
}
14041400
io_put_file(req);
14051401
io_req_put_rsrc_nodes(req);
1406-
io_put_task(req->task);
1402+
io_put_task(req);
14071403

14081404
node = req->comp_list.next;
14091405
io_req_add_to_cache(req, ctx);
@@ -2019,7 +2015,7 @@ static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req,
20192015
req->flags = (__force io_req_flags_t) sqe_flags;
20202016
req->cqe.user_data = READ_ONCE(sqe->user_data);
20212017
req->file = NULL;
2022-
req->task = current;
2018+
req->tctx = current->io_uring;
20232019
req->cancel_seq_set = false;
20242020

20252021
if (unlikely(opcode >= IORING_OP_LAST)) {

io_uring/io_uring.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,19 @@ static inline bool io_allowed_run_tw(struct io_ring_ctx *ctx)
426426
ctx->submitter_task == current);
427427
}
428428

429+
/*
430+
* Terminate the request if either of these conditions are true:
431+
*
432+
* 1) It's being executed by the original task, but that task is marked
433+
* with PF_EXITING as it's exiting.
434+
* 2) PF_KTHREAD is set, in which case the invoker of the task_work is
435+
* our fallback task_work.
436+
*/
437+
static inline bool io_should_terminate_tw(void)
438+
{
439+
return current->flags & (PF_KTHREAD | PF_EXITING);
440+
}
441+
429442
static inline void io_req_queue_tw_complete(struct io_kiocb *req, s32 res)
430443
{
431444
io_req_set_res(req, res, 0);

io_uring/msg_ring.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ static void io_msg_tw_complete(struct io_kiocb *req, struct io_tw_state *ts)
8989
static int io_msg_remote_post(struct io_ring_ctx *ctx, struct io_kiocb *req,
9090
int res, u32 cflags, u64 user_data)
9191
{
92-
req->task = READ_ONCE(ctx->submitter_task);
93-
if (!req->task) {
92+
req->tctx = READ_ONCE(ctx->submitter_task->io_uring);
93+
if (!req->tctx) {
9494
kmem_cache_free(req_cachep, req);
9595
return -EOWNERDEAD;
9696
}

io_uring/notif.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ static int io_link_skb(struct sk_buff *skb, struct ubuf_info *uarg)
8989

9090
/* make sure all noifications can be finished in the same task_work */
9191
if (unlikely(notif->ctx != prev_notif->ctx ||
92-
notif->task != prev_notif->task))
92+
notif->tctx != prev_notif->tctx))
9393
return -EEXIST;
9494

9595
nd->head = prev_nd->head;
@@ -115,7 +115,7 @@ struct io_kiocb *io_alloc_notif(struct io_ring_ctx *ctx)
115115
notif->opcode = IORING_OP_NOP;
116116
notif->flags = 0;
117117
notif->file = NULL;
118-
notif->task = current;
118+
notif->tctx = current->io_uring;
119119
io_get_task_refs(1);
120120
notif->file_node = NULL;
121121
notif->buf_node = NULL;

io_uring/poll.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,8 +224,7 @@ static int io_poll_check_events(struct io_kiocb *req, struct io_tw_state *ts)
224224
{
225225
int v;
226226

227-
/* req->task == current here, checking PF_EXITING is safe */
228-
if (unlikely(req->task->flags & PF_EXITING))
227+
if (unlikely(io_should_terminate_tw()))
229228
return -ECANCELED;
230229

231230
do {

io_uring/rw.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ static bool io_rw_should_reissue(struct io_kiocb *req)
435435
* Play it safe and assume not safe to re-import and reissue if we're
436436
* not in the original thread group (or in task context).
437437
*/
438-
if (!same_thread_group(req->task, current) || !in_task())
438+
if (!same_thread_group(req->tctx->task, current) || !in_task())
439439
return false;
440440
return true;
441441
}

0 commit comments

Comments
 (0)