diff --git a/io_uring/io_uring.h b/io_uring/io_uring.h index 203bf019e931..32247529076c 100644 --- a/io_uring/io_uring.h +++ b/io_uring/io_uring.h @@ -404,16 +404,22 @@ static inline void io_ring_submit_lock(struct io_ring_ctx *ctx, * cancellations find it, rather than completing it. Whoever tried to cancel * the request before that found it running. It has flagged the work item, * has searched the list in vain, and won't come back. To be called with - * ->uring_lock held, which the search needs as well, once the request is on - * the list: if the search came first, the flag is visible. + * the lock the search takes held: if the search came first, the flag is + * visible. For most lists that is ->uring_lock, timeouts use ->timeout_lock. */ +static inline bool __io_wq_cancel_seen(struct io_kiocb *req, + unsigned int issue_flags) +{ + return (issue_flags & IO_URING_F_IOWQ) && + (atomic_read(&req->work.flags) & IO_WQ_WORK_CANCEL); +} + static inline bool io_wq_cancel_seen(struct io_kiocb *req, unsigned int issue_flags) { lockdep_assert_held(&req->ctx->uring_lock); - return (issue_flags & IO_URING_F_IOWQ) && - (atomic_read(&req->work.flags) & IO_WQ_WORK_CANCEL); + return __io_wq_cancel_seen(req, issue_flags); } static inline void io_commit_cqring(struct io_ring_ctx *ctx) diff --git a/io_uring/timeout.c b/io_uring/timeout.c index c92d1363df81..8a2108aa14ae 100644 --- a/io_uring/timeout.c +++ b/io_uring/timeout.c @@ -687,6 +687,13 @@ int io_timeout(struct io_kiocb *req, unsigned int issue_flags) raw_spin_lock_irq(&ctx->timeout_lock); + /* the list is searched under ->timeout_lock, see io_wq_cancel_seen() */ + if (__io_wq_cancel_seen(req, issue_flags)) { + raw_spin_unlock_irq(&ctx->timeout_lock); + io_req_task_queue_fail(req, -ECANCELED); + return IOU_ISSUE_SKIP_COMPLETE; + } + /* * sqe->off holds how many events that need to occur for this * timeout event to be satisfied. If it isn't set, then this is