mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
io_uring/timeout: no ABS update of multishot timeouts
IORING_TIMEOUT_MULTISHOT can't be combined with IORING_TIMEOUT_ABS, prep
rejects that, as the request is armed again with the same value each time
it fires. IORING_TIMEOUT_UPDATE doesn't check and takes an absolute time
for a multishot timeout. The first expiry is as asked for, but
io_timeout_complete() then arms the timer with ->mode of the original
request, i.e. it uses the absolute time as the interval. With
CLOCK_MONOTONIC the next expiry is an uptime away, with CLOCK_REALTIME
more than fifty years.
Fail such an update with -EINVAL, and do so before the timeout is
touched.
Fixes: ea97f6c855 ("io_uring: add support for multishot timeouts")
Assisted-by: LLM
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-41-c1556f5d7bf5@toxicpanda.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
parent
8444de681a
commit
b088ae34d4
|
|
@ -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 */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user