Skip to content

Commit

Permalink
io_uring: finish waiting before flushing overflow entries
Browse files Browse the repository at this point in the history
If we have overflow entries being generated after we've done the
initial flush in io_cqring_wait(), then we could be flushing them in the
main wait loop as well. If that's done after having added ourselves
to the cq_wait waitqueue, then the task state can be != TASK_RUNNING
when we enter the overflow flush.

Check for the need to overflow flush, and finish our wait cycle first
if we have to do so.

Reported-and-tested-by: [email protected]
Link: https://lore.kernel.org/io-uring/[email protected]/
Signed-off-by: Jens Axboe <[email protected]>
  • Loading branch information
axboe committed Dec 21, 2022
1 parent 5ad70eb commit 52ea806
Showing 1 changed file with 16 additions and 9 deletions.
25 changes: 16 additions & 9 deletions io_uring/io_uring.c
Original file line number Diff line number Diff line change
Expand Up @@ -677,16 +677,20 @@ static void __io_cqring_overflow_flush(struct io_ring_ctx *ctx)
io_cq_unlock_post(ctx);
}

static void io_cqring_do_overflow_flush(struct io_ring_ctx *ctx)
{
/* iopoll syncs against uring_lock, not completion_lock */
if (ctx->flags & IORING_SETUP_IOPOLL)
mutex_lock(&ctx->uring_lock);
__io_cqring_overflow_flush(ctx);
if (ctx->flags & IORING_SETUP_IOPOLL)
mutex_unlock(&ctx->uring_lock);
}

static void io_cqring_overflow_flush(struct io_ring_ctx *ctx)
{
if (test_bit(IO_CHECK_CQ_OVERFLOW_BIT, &ctx->check_cq)) {
/* iopoll syncs against uring_lock, not completion_lock */
if (ctx->flags & IORING_SETUP_IOPOLL)
mutex_lock(&ctx->uring_lock);
__io_cqring_overflow_flush(ctx);
if (ctx->flags & IORING_SETUP_IOPOLL)
mutex_unlock(&ctx->uring_lock);
}
if (test_bit(IO_CHECK_CQ_OVERFLOW_BIT, &ctx->check_cq))
io_cqring_do_overflow_flush(ctx);
}

void __io_put_task(struct task_struct *task, int nr)
Expand Down Expand Up @@ -2549,7 +2553,10 @@ static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events,

trace_io_uring_cqring_wait(ctx, min_events);
do {
io_cqring_overflow_flush(ctx);
if (test_bit(IO_CHECK_CQ_OVERFLOW_BIT, &ctx->check_cq)) {
finish_wait(&ctx->cq_wait, &iowq.wq);
io_cqring_do_overflow_flush(ctx);
}
prepare_to_wait_exclusive(&ctx->cq_wait, &iowq.wq,
TASK_INTERRUPTIBLE);
ret = io_cqring_wait_schedule(ctx, &iowq, timeout);
Expand Down

0 comments on commit 52ea806

Please sign in to comment.