[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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.