Skip to content

Commit 71b0867

Browse files
isilenceSasha Levin
authored andcommitted
io_uring: fix spurious drain flushing
[ Upstream commit fde04c7 ] io_queue_deferred() is not tolerant to spurious calls not completing some requests. You can have an inflight drain-marked request and another request that came after and got queued into the drain list. Now, if io_queue_deferred() is called before the first request completes, it'll check the 2nd req with req_need_defer(), find that there is no drain flag set, and queue it for execution. To make io_queue_deferred() work, it should at least check sequences for the first request, and then we need also need to check if there is another drain request creating another bubble. Signed-off-by: Pavel Begunkov <asml.silence@gmail.com> Link: https://lore.kernel.org/r/972bde11b7d4ef25b3f5e3fd34f80e4d2aa345b8.1746788718.git.asml.silence@gmail.com Signed-off-by: Jens Axboe <axboe@kernel.dk> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 5bfa25d commit 71b0867

File tree

1 file changed

+13
-1
lines changed

1 file changed

+13
-1
lines changed

io_uring/io_uring.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -537,18 +537,30 @@ void io_req_queue_iowq(struct io_kiocb *req)
537537
io_req_task_work_add(req);
538538
}
539539

540+
static bool io_drain_defer_seq(struct io_kiocb *req, u32 seq)
541+
{
542+
struct io_ring_ctx *ctx = req->ctx;
543+
544+
return seq + READ_ONCE(ctx->cq_extra) != ctx->cached_cq_tail;
545+
}
546+
540547
static __cold noinline void io_queue_deferred(struct io_ring_ctx *ctx)
541548
{
549+
bool drain_seen = false, first = true;
550+
542551
spin_lock(&ctx->completion_lock);
543552
while (!list_empty(&ctx->defer_list)) {
544553
struct io_defer_entry *de = list_first_entry(&ctx->defer_list,
545554
struct io_defer_entry, list);
546555

547-
if (req_need_defer(de->req, de->seq))
556+
drain_seen |= de->req->flags & REQ_F_IO_DRAIN;
557+
if ((drain_seen || first) && io_drain_defer_seq(de->req, de->seq))
548558
break;
559+
549560
list_del_init(&de->list);
550561
io_req_task_queue(de->req);
551562
kfree(de);
563+
first = false;
552564
}
553565
spin_unlock(&ctx->completion_lock);
554566
}

0 commit comments

Comments
 (0)