Skip to content

Commit 576cce9

Browse files
committed
io_uring: remove the per-ctx fallback task_work machinery
With the tctx fallback running its entries directly, the per-ctx fallback work has a single user left: moving local (DEFER_TASKRUN) task_work entries out of a ring that is going away. Both of its call sites are process context and don't hold ->uring_lock, the same conditions the deferred fallback work itself ran under - so run the entries in cancel mode right there instead, and rename the helper to io_cancel_local_task_work() to match what it now does. With that, ->fallback_llist, ->fallback_work, io_fallback_req_func() and __io_fallback_tw() can all go away, along with the fallback work flushing in the ring exit and cancel paths. Requests that get orphaned by an exiting task now run via the tctx fallback work, which the ring exit side implicitly waits on through the ctx refs those requests hold. Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent df58c21 commit 576cce9

5 files changed

Lines changed: 16 additions & 65 deletions

File tree

include/linux/io_uring_types.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -498,8 +498,6 @@ struct io_ring_ctx {
498498
struct mutex tctx_lock;
499499

500500
/* ctx exit and cancelation */
501-
struct llist_head fallback_llist;
502-
struct delayed_work fallback_work;
503501
struct work_struct exit_work;
504502
struct completion ref_comp;
505503

io_uring/cancel.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -565,8 +565,6 @@ __cold bool io_uring_try_cancel_requests(struct io_ring_ctx *ctx,
565565
ret |= io_kill_timeouts(ctx, tctx, cancel_all);
566566
if (tctx)
567567
ret |= io_run_task_work() > 0;
568-
else
569-
ret |= flush_delayed_work(&ctx->fallback_work);
570568
return ret;
571569
}
572570

io_uring/io_uring.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,6 @@ static __cold struct io_ring_ctx *io_ring_ctx_alloc(struct io_uring_params *p)
289289
#ifdef CONFIG_FUTEX
290290
INIT_HLIST_HEAD(&ctx->futex_list);
291291
#endif
292-
INIT_DELAYED_WORK(&ctx->fallback_work, io_fallback_req_func);
293292
INIT_WQ_LIST(&ctx->submit_state.compl_reqs);
294293
INIT_HLIST_HEAD(&ctx->cancelable_uring_cmd);
295294
io_napi_init(ctx);
@@ -1192,7 +1191,7 @@ __cold void io_iopoll_try_reap_events(struct io_ring_ctx *ctx)
11921191
mutex_unlock(&ctx->uring_lock);
11931192

11941193
if (ctx->flags & IORING_SETUP_DEFER_TASKRUN)
1195-
io_move_task_work_from_local(ctx);
1194+
io_cancel_local_task_work(ctx);
11961195
}
11971196

11981197
static int io_iopoll_check(struct io_ring_ctx *ctx, unsigned int min_events)
@@ -2334,7 +2333,7 @@ static __cold void io_ring_exit_work(struct work_struct *work)
23342333
/* The SQPOLL thread never reaches this path */
23352334
do {
23362335
if (ctx->flags & IORING_SETUP_DEFER_TASKRUN)
2337-
io_move_task_work_from_local(ctx);
2336+
io_cancel_local_task_work(ctx);
23382337
cond_resched();
23392338
} while (io_uring_try_cancel_requests(ctx, NULL, true, false));
23402339

@@ -2420,8 +2419,6 @@ static __cold void io_ring_ctx_wait_and_kill(struct io_ring_ctx *ctx)
24202419
io_unregister_personality(ctx, index);
24212420
mutex_unlock(&ctx->uring_lock);
24222421

2423-
flush_delayed_work(&ctx->fallback_work);
2424-
24252422
INIT_WORK(&ctx->exit_work, io_ring_exit_work);
24262423
/*
24272424
* Use system_dfl_wq to avoid spawning tons of event kworkers

io_uring/tw.c

Lines changed: 13 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,6 @@
1616
#include "wait.h"
1717
#include "mpscq.h"
1818

19-
void io_fallback_req_func(struct work_struct *work)
20-
{
21-
struct io_ring_ctx *ctx = container_of(work, struct io_ring_ctx,
22-
fallback_work.work);
23-
struct llist_node *node = llist_del_all(&ctx->fallback_llist);
24-
struct io_kiocb *req, *tmp;
25-
struct io_tw_state ts = {};
26-
27-
percpu_ref_get(&ctx->refs);
28-
mutex_lock(&ctx->uring_lock);
29-
ts.cancel = io_should_terminate_tw(ctx);
30-
llist_for_each_entry_safe(req, tmp, node, io_task_work.node)
31-
req->io_task_work.func((struct io_tw_req){req}, ts);
32-
io_submit_flush_completions(ctx);
33-
mutex_unlock(&ctx->uring_lock);
34-
percpu_ref_put(&ctx->refs);
35-
}
36-
3719
static void ctx_flush_and_put(struct io_ring_ctx *ctx, io_tw_token_t tw)
3820
{
3921
if (!ctx)
@@ -46,34 +28,6 @@ static void ctx_flush_and_put(struct io_ring_ctx *ctx, io_tw_token_t tw)
4628
percpu_ref_put(&ctx->refs);
4729
}
4830

49-
static __cold void __io_fallback_tw(struct llist_node *node, bool sync)
50-
{
51-
struct io_ring_ctx *last_ctx = NULL;
52-
struct io_kiocb *req;
53-
54-
while (node) {
55-
req = container_of(node, struct io_kiocb, io_task_work.node);
56-
node = node->next;
57-
if (last_ctx != req->ctx) {
58-
if (last_ctx) {
59-
if (sync)
60-
flush_delayed_work(&last_ctx->fallback_work);
61-
percpu_ref_put(&last_ctx->refs);
62-
}
63-
last_ctx = req->ctx;
64-
percpu_ref_get(&last_ctx->refs);
65-
}
66-
if (llist_add(&req->io_task_work.node, &last_ctx->fallback_llist))
67-
schedule_delayed_work(&last_ctx->fallback_work, 1);
68-
}
69-
70-
if (last_ctx) {
71-
if (sync)
72-
flush_delayed_work(&last_ctx->fallback_work);
73-
percpu_ref_put(&last_ctx->refs);
74-
}
75-
}
76-
7731
void io_tctx_fallback_work(struct work_struct *work)
7832
{
7933
struct io_uring_task *tctx = container_of(work, struct io_uring_task,
@@ -286,29 +240,34 @@ void io_req_task_work_add_remote(struct io_kiocb *req, unsigned flags)
286240
__io_req_task_work_add(req, flags);
287241
}
288242

289-
void __cold io_move_task_work_from_local(struct io_ring_ctx *ctx)
243+
void __cold io_cancel_local_task_work(struct io_ring_ctx *ctx)
290244
{
291-
struct llist_node *node, *first = NULL, **tail = &first;
245+
struct io_tw_state ts = { .cancel = true };
246+
struct llist_node *node;
292247

293248
/*
294249
* The work list consumer side is serialized by ->uring_lock, see
295250
* __io_run_local_work(). Grab it to guard against racing with normal
296-
* task_work running, as the task may be exiting.
251+
* task_work running, as the task may be exiting. The ring is going
252+
* away, run the entries in cancel mode right here - the callers
253+
* provide the same process context the per-ctx fallback work that
254+
* they were previously punted to ran in.
297255
*/
298256
guard(mutex)(&ctx->uring_lock);
299257

300258
while (!mpscq_empty(&ctx->work_list)) {
259+
struct io_kiocb *req;
260+
301261
node = mpscq_pop(&ctx->work_list, &ctx->work_head);
302262
if (!node) {
303263
/* a producer is mid-push, wait for it to link */
304-
cpu_relax();
264+
cond_resched();
305265
continue;
306266
}
307-
*tail = node;
308-
tail = &node->next;
267+
req = container_of(node, struct io_kiocb, io_task_work.node);
268+
req->io_task_work.func((struct io_tw_req){req}, ts);
309269
}
310-
*tail = NULL;
311-
__io_fallback_tw(first, false);
270+
io_submit_flush_completions(ctx);
312271
}
313272

314273
static bool io_run_local_work_continue(struct io_ring_ctx *ctx, int events,

io_uring/tw.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,7 @@ void io_tctx_fallback_work(struct work_struct *work);
3030
int io_run_local_work(struct io_ring_ctx *ctx, int min_events, int max_events);
3131
int io_run_task_work_sig(struct io_ring_ctx *ctx);
3232

33-
__cold void io_fallback_req_func(struct work_struct *work);
34-
__cold void io_move_task_work_from_local(struct io_ring_ctx *ctx);
33+
__cold void io_cancel_local_task_work(struct io_ring_ctx *ctx);
3534
int io_run_local_work_locked(struct io_ring_ctx *ctx, int min_events);
3635

3736
void io_req_local_work_add(struct io_kiocb *req, unsigned flags);

0 commit comments

Comments
 (0)