[PATCH 2/2] io_uring/timeout: cancel pending link timeouts from ltimeout_list
Yang Xiuwei <[email protected]>
| Newsgroups | org.kernel.vger.io-uring |
|---|---|
| Message-ID | <[email protected]> |
TIMEOUT_REMOVE and IORING_OP_ASYNC_CANCEL look up pending timeouts via io_timeout_cancel(), but that path only scans timeout_list. Pending link timeouts live on ltimeout_list instead, so cancel/remove by user_data returns -ENOENT. Fall back to ltimeout_list when the initial lookup fails, reusing __io_disarm_linked_timeout(). Complete the disarmed link timeout via io_req_queue_tw_complete() rather than io_req_task_queue_fail(), and clean up the link timeout state on the head request. Signed-off-by: Yang Xiuwei <[email protected]> --- io_uring/timeout.c | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/io_uring/timeout.c b/io_uring/timeout.c index c4dd26cf342d..8ecc9a7f1597 100644 --- a/io_uring/timeout.c +++ b/io_uring/timeout.c @@ -348,18 +348,52 @@ static struct io_kiocb *io_timeout_extract(struct io_ring_ctx *ctx, return req; } +static struct io_kiocb *io_linked_timeout_cancel(struct io_ring_ctx *ctx, + struct io_cancel_data *cd) + __must_hold(&ctx->completion_lock) + __must_hold(&ctx->timeout_lock) +{ + struct io_timeout *timeout; + + list_for_each_entry(timeout, &ctx->ltimeout_list, list) { + struct io_kiocb *link = cmd_to_io_kiocb(timeout); + struct io_kiocb *head; + + if (!io_cancel_req_match(link, cd)) + continue; + head = timeout->head; + if (!head) + return ERR_PTR(-EALREADY); + link = __io_disarm_linked_timeout(head, link); + if (!link) + return ERR_PTR(-EALREADY); + head->flags &= ~REQ_F_LINK_TIMEOUT; + return link; + } + return ERR_PTR(-ENOENT); +} + int io_timeout_cancel(struct io_ring_ctx *ctx, struct io_cancel_data *cd) __must_hold(&ctx->completion_lock) { struct io_kiocb *req; + bool linked = false; raw_spin_lock_irq(&ctx->timeout_lock); req = io_timeout_extract(ctx, cd); + if (req == ERR_PTR(-ENOENT)) { + req = io_linked_timeout_cancel(ctx, cd); + if (!IS_ERR(req)) + linked = true; + } raw_spin_unlock_irq(&ctx->timeout_lock); if (IS_ERR(req)) return PTR_ERR(req); - io_req_task_queue_fail(req, -ECANCELED); + if (linked) + io_req_queue_tw_complete(req, -ECANCELED); + else + io_req_task_queue_fail(req, -ECANCELED); return 0; } -- 2.25.1