Skip to content

Commit d120fcb

Browse files
isilencemehmetb0
authored andcommitted
io_uring: fix spurious drain flushing
BugLink: https://bugs.launchpad.net/bugs/2119603 [ Upstream commit fde04c7e2775feb0746301e0ef86a04d3598c3fe ] 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 <[email protected]> Link: https://lore.kernel.org/r/972bde11b7d4ef25b3f5e3fd34f80e4d2aa345b8.1746788718.git.asml.silence@gmail.com Signed-off-by: Jens Axboe <[email protected]> Signed-off-by: Sasha Levin <[email protected]> Signed-off-by: Manuel Diewald <[email protected]> Signed-off-by: Mehmet Basaran <[email protected]>
1 parent c647ee2 commit d120fcb

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
@@ -533,18 +533,30 @@ void io_req_queue_iowq(struct io_kiocb *req)
533533
io_req_task_work_add(req);
534534
}
535535

536+
static bool io_drain_defer_seq(struct io_kiocb *req, u32 seq)
537+
{
538+
struct io_ring_ctx *ctx = req->ctx;
539+
540+
return seq + READ_ONCE(ctx->cq_extra) != ctx->cached_cq_tail;
541+
}
542+
536543
static __cold noinline void io_queue_deferred(struct io_ring_ctx *ctx)
537544
{
545+
bool drain_seen = false, first = true;
546+
538547
spin_lock(&ctx->completion_lock);
539548
while (!list_empty(&ctx->defer_list)) {
540549
struct io_defer_entry *de = list_first_entry(&ctx->defer_list,
541550
struct io_defer_entry, list);
542551

543-
if (req_need_defer(de->req, de->seq))
552+
drain_seen |= de->req->flags & REQ_F_IO_DRAIN;
553+
if ((drain_seen || first) && io_drain_defer_seq(de->req, de->seq))
544554
break;
555+
545556
list_del_init(&de->list);
546557
io_req_task_queue(de->req);
547558
kfree(de);
559+
first = false;
548560
}
549561
spin_unlock(&ctx->completion_lock);
550562
}

0 commit comments

Comments
 (0)