Skip to content

Commit 85faa7b

Browse files
committed
io_uring: punt final io_ring_ctx wait-and-free to workqueue
We can't reliably wait in io_ring_ctx_wait_and_kill(), since the task_works list isn't ordered (in fact it's LIFO ordered). We could either fix this with a separate task_works list for io_uring work, or just punt the wait-and-free to async context. This ensures that task_work that comes in while we're shutting down is processed correctly. If we don't go async, we could have work past the fput() work for the ring that depends on work that won't be executed until after we're done with the wait-and-free. But as this operation is blocking, it'll never get a chance to run. This was reproduced with hundreds of thousands of sockets running memcached, haven't been able to reproduce this synthetically. Reported-by: Dan Melnic <[email protected]> Signed-off-by: Jens Axboe <[email protected]>
1 parent c398ecb commit 85faa7b

File tree

1 file changed

+16
-2
lines changed

1 file changed

+16
-2
lines changed

fs/io_uring.c

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,8 @@ struct io_ring_ctx {
326326
spinlock_t inflight_lock;
327327
struct list_head inflight_list;
328328
} ____cacheline_aligned_in_smp;
329+
330+
struct work_struct exit_work;
329331
};
330332

331333
/*
@@ -7271,6 +7273,18 @@ static int io_remove_personalities(int id, void *p, void *data)
72717273
return 0;
72727274
}
72737275

7276+
static void io_ring_exit_work(struct work_struct *work)
7277+
{
7278+
struct io_ring_ctx *ctx;
7279+
7280+
ctx = container_of(work, struct io_ring_ctx, exit_work);
7281+
if (ctx->rings)
7282+
io_cqring_overflow_flush(ctx, true);
7283+
7284+
wait_for_completion(&ctx->completions[0]);
7285+
io_ring_ctx_free(ctx);
7286+
}
7287+
72747288
static void io_ring_ctx_wait_and_kill(struct io_ring_ctx *ctx)
72757289
{
72767290
mutex_lock(&ctx->uring_lock);
@@ -7298,8 +7312,8 @@ static void io_ring_ctx_wait_and_kill(struct io_ring_ctx *ctx)
72987312
if (ctx->rings)
72997313
io_cqring_overflow_flush(ctx, true);
73007314
idr_for_each(&ctx->personality_idr, io_remove_personalities, ctx);
7301-
wait_for_completion(&ctx->completions[0]);
7302-
io_ring_ctx_free(ctx);
7315+
INIT_WORK(&ctx->exit_work, io_ring_exit_work);
7316+
queue_work(system_wq, &ctx->exit_work);
73037317
}
73047318

73057319
static int io_uring_release(struct inode *inode, struct file *file)

0 commit comments

Comments
 (0)