diff --git a/io_uring/timeout.c b/io_uring/timeout.c index 90d440a75f28..1cf59c494769 100644 --- a/io_uring/timeout.c +++ b/io_uring/timeout.c @@ -321,22 +321,29 @@ static enum hrtimer_restart io_timeout_fn(struct hrtimer *timer) return HRTIMER_NORESTART; } +static struct io_kiocb *io_timeout_find(struct io_ring_ctx *ctx, + struct io_cancel_data *cd) + __must_hold(&ctx->timeout_lock) +{ + struct io_timeout *timeout; + + list_for_each_entry(timeout, &ctx->timeout_list, list) { + struct io_kiocb *req = cmd_to_io_kiocb(timeout); + + if (io_cancel_req_match(req, cd)) + return req; + } + return NULL; +} + static struct io_kiocb *io_timeout_extract(struct io_ring_ctx *ctx, struct io_cancel_data *cd) __must_hold(&ctx->timeout_lock) { + struct io_kiocb *req = io_timeout_find(ctx, cd); struct io_timeout *timeout; struct io_timeout_data *io; - struct io_kiocb *req = NULL; - list_for_each_entry(timeout, &ctx->timeout_list, list) { - struct io_kiocb *tmp = cmd_to_io_kiocb(timeout); - - if (io_cancel_req_match(tmp, cd)) { - req = tmp; - break; - } - } if (!req) return ERR_PTR(-ENOENT); @@ -470,14 +477,21 @@ static int io_timeout_update(struct io_ring_ctx *ctx, __u64 user_data, __must_hold(&ctx->timeout_lock) { struct io_cancel_data cd = { .ctx = ctx, .data = user_data, }; - struct io_kiocb *req = io_timeout_extract(ctx, &cd); + struct io_kiocb *req = io_timeout_find(ctx, &cd); struct io_timeout *timeout = io_kiocb_to_cmd(req, struct io_timeout); struct io_timeout_data *data; - if (IS_ERR(req)) - return PTR_ERR(req); + if (!req) + return -ENOENT; data = req->async_data; + /* multishot requests only make sense with rel values */ + if ((data->flags & IORING_TIMEOUT_MULTISHOT) && mode == HRTIMER_MODE_ABS) + return -EINVAL; + + req = io_timeout_extract(ctx, &cd); + if (IS_ERR(req)) + return PTR_ERR(req); /* for a multishot request this isn't a sequence, keep the repeats */ if (!(data->flags & IORING_TIMEOUT_MULTISHOT)) timeout->off = 0; /* noseq */