Right now io_flush_timeouts() checks if the current number of events is equal to ->timeout.target_seq, but this will miss some timeouts if there have been more than 1 event added since the last time they were flushed (possible in io_submit_flush_completions(), for example). The test below hangs before this change (unless you run with $ ./a.out ~/somefile 1) int main(int argc, char **argv) { if (argc < 2) return 1; int fd = open(argv[1], O_RDONLY); if (fd < 0) { perror("open"); return 1; } struct io_uring ring; io_uring_queue_init(4, &ring, 0); struct io_uring_sqe *sqe = io_uring_get_sqe(&ring); struct __kernel_timespec ts = { .tv_sec = 9999999 }; io_uring_prep_timeout(sqe, &ts, 1, 0); sqe->user_data = 123; int ret = io_uring_submit(&ring); if (ret < 0) { fprintf(stderr, "submit(timeout_sqe): %d\n", ret); return 1; } int n = 2; if (argc > 2) n = atoi(argv[2]); char buf; for (int i = 0; i < n; i++) { sqe = io_uring_get_sqe(&ring); if (!sqe) { fprintf(stderr, "too many\n"); exit(1); } io_uring_prep_read(sqe, fd, &buf, 1, 0); } ret = io_uring_submit(&ring); if (ret < 0) { fprintf(stderr, "submit(read_sqe): %d\n", ret); exit(1); } struct io_uring_cqe *cqe; for (int i = 0; i < n+1; i++) { struct io_uring_cqe *cqe; int ret = io_uring_wait_cqe(&ring, &cqe); if (ret < 0) { fprintf(stderr, "wait_cqe(): %d\n", ret); return 1; } if (cqe->user_data == 123) printf("timeout found\n"); io_uring_cqe_seen(&ring, cqe); } } Signed-off-by: Marcelo Diop-Gonzalez <marcelo827@xxxxxxxxx> --- fs/io_uring.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/io_uring.c b/fs/io_uring.c index b74957856e68..ae7244f8e842 100644 --- a/fs/io_uring.c +++ b/fs/io_uring.c @@ -1639,7 +1639,7 @@ static void io_flush_timeouts(struct io_ring_ctx *ctx) if (io_is_timeout_noseq(req)) break; - if (req->timeout.target_seq != ctx->cached_cq_tail + if (req->timeout.target_seq > ctx->cached_cq_tail - atomic_read(&ctx->cq_timeouts)) break; -- 2.20.1