summaryrefslogtreecommitdiff
path: root/io_uring
AgeCommit message (Collapse)Author
25 hoursMerge branch 'master' of ↵Mark Brown
https://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git # Conflicts: # Documentation/scheduler/index.rst # arch/arm64/configs/defconfig
25 hoursMerge branch 'for-next' of ↵Mark Brown
https://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux.git # Conflicts: # drivers/nvme/host/pci.c
27 hoursMerge branch into tip/master: 'timers/core'Ingo Molnar
# New commits in timers/core: 348f54c435bf ("selftests/timers: clocksource-switch: Fix unchecked open()/read()") b03638013add ("selftests: timers: Measure the CPU timers on the clock they count") a252cb93e156 ("selftests: timers: Count what tick is worth in the drift estimate") 3945c4a3ea15 ("time/kunit: Add time64_to_tm() case beyond 32-bit day count") 2927f7ca7844 ("time: Prevent time64_to_tm() day truncation on 32-bit") bc5b66c300b8 ("timekeeping: Use READ_ONCE/WRITE_ONCE() for ktime_sec to prevent tearing") bb41ece16463 ("timers/migration: Mark racy updates to tmigr_event::ignore field") 1159ad0a6aaa ("timers: Mark racy updates to hlist_node::pprev field") 5dffe33bfdaf ("hrtimer: Apply READ_ONCE() to lockless base->running loads") ad80926d7803 ("hrtimer: Mark the hrtimer_sleeper structure's ->task field __private") 15f84398330c ("hrtimer: Update hrtimer_resolution only if value changes") 7eed1771a6e8 ("futex: Use accessor for hrtimer_sleeper ->task field in requeue") 9cd2f4e304d9 ("rtmutex: Use accessor for hrtimer_sleeper ->task field") 3990d196954a ("net: pktgen: Use accessor for hrtimer_sleeper ->task field") 9b7bcd671e9c ("timers: Use accessor for hrtimer_sleeper ->task field in sleep_timeout.c") fa3d486086d6 ("futex: Use accessor for hrtimer_sleeper ->task field in waitwake.c") 851c30277918 ("io-uring/rw: Use accessor for hrtimer_sleeper ->task field") 66b29025b676 ("wait: Use accessor for hrtimer_sleeper ->task field") cefc1a24ace5 ("aio: Use accessor for hrtimer_sleeper ->task field") d166a1cd9016 ("hrtimer: Mark data-racy accesses to hrtimer_sleeper ->task field") 7b07d15ed1d7 ("posix-timers: Handle exit in do_exit() completely") 54ad1e0ea42c ("posix-cpu-timers: Prevent enqueueing when PF_EXITING is set") 760ad335d600 ("posix-cpu-timers: Use PF_EXITING to indicate exit") 8e9ed3b66f40 ("posix-cpu-timers: Move inlines out of public header") 24adce0b86c9 ("posix-timers: Move POSIX timer group exit related code out of do_exit()") 7117334f022b ("posix-timers: Move posixtimer_exec_cleanup() out of exec.c") Signed-off-by: Ingo Molnar <mingo@kernel.org>
28 hoursMerge branch 'vfs-7.4.file' into vfs.allChristian Brauner
28 hoursMerge branch 'kernel-7.4.signal' into vfs.allChristian Brauner
Signed-off-by: Christian Brauner <brauner@kernel.org>
37 hoursMerge branch 'for-7.4/io_uring' into for-nextJens Axboe
* for-7.4/io_uring: io_uring/timeout: don't lose a cancel as io-wq arms a timeout
37 hoursio_uring/timeout: don't lose a cancel as io-wq arms a timeoutJens Axboe
An IORING_OP_TIMEOUT run by io-wq, because of IOSQE_ASYNC, has the same problem as poll, futex and waitid. io_wq_submit_work() looks at IO_WQ_WORK_CANCEL once, before it issues the request. A cancel in between flags the work, gets -EALREADY, and searches ->timeout_list in vain, while the worker then adds the request and starts the timer: io-wq worker io_try_cancel() io_wq_submit_work() IO_WQ_WORK_CANCEL isn't set io_async_cancel_one() sets IO_WQ_WORK_CANCEL = -EALREADY io_timeout_cancel() = -ENOENT io_timeout() adds the request to ->timeout_list hrtimer_start() = IOU_ISSUE_SKIP_COMPLETE Nobody looks at the flag again, and the timeout runs its course. At ring exit, io_uring_try_cancel_requests() cancels io-wq work and then kills the timeouts the same way, so an exiting task can get stuck for the full duration of such a timeout. Look at the flag under ->timeout_lock, which the search takes as well, and fail the request if it is set. If the search came first, the flag is visible. If it comes later, it finds the request on the list. Fixes: ce35a47a3a02 ("io_uring: add IOSQE_ASYNC") Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursMerge branch 'for-7.4/io_uring' into for-nextJens Axboe
* for-7.4/io_uring: (46 commits) io_uring/timeout: don't flush with the sequence behind the last flush io_uring/timeout: don't put a sequence target behind the last flush io_uring/poll: avoid retry wakeup loss when dropping ownership io_uring: look up the file before queueing to io-wq io_uring/timeout: don't end a linked timeout with 1 io_uring/timeout: no ABS update of multishot timeouts io_uring/net: don't retry recv on uncommitted buffers io_uring: don't pass restart error codes to userspace io_uring/openclose: keep the lock in io_pipe_fixed() io_uring/sqpoll: let the thread sleep on disabled rings io_uring/kbuf: handle index wrap in last buffer check io_uring/zcrx: fix buffer offsets in areas above 4GB io_uring/napi: don't busy poll past an expired timeout io_uring/napi: make stale entries time out after 60s io_uring/wait: no early -ETIME if min_wait finds work io_uring/timeout: use the right clock for ABS updates io_uring/timeout: keep repeat count on multishot update io_uring/timeout: don't skip over reached sequences io_uring/fdinfo: fix CQE dump of CQE32 rings io_uring/register: keep 128b SQEs intact on resize ...
41 hoursio_uring/timeout: don't flush with the sequence behind the last flushJens Axboe
io_flush_timeouts() measures the events since the last flush as the distance of the current sequence from ->cq_last_tm_flush. A fired timeout bumps ->cq_timeouts before its CQE is posted, so until it is the sequence can be behind the last flush, and the distance wraps: last flush: seq 100, cq_last_tm_flush = 100 Y: IORING_OP_TIMEOUT, off 50, target_seq 150 pure timeout A fires, cq_timeouts = 1 task_work posts A's CQE, cached_cq_tail = 101 pure timeout B fires before the flush, cq_timeouts = 2 io_flush_timeouts(): seq = 99, events_got = 0xffffffff Y, and every sequence timeout behind it, is ended with -ETIME although no event happened. Two timeouts expiring close together is all it takes, a completion with IOSQE_CQE_SKIP_SUCCESS after a single one does it too. Nothing but those in flight CQEs separates the two, so count from the last flush when the sequence is behind it, as io_timeout() does. Fixes: f010505b78a4 ("io_uring: flush timeouts that should already have expired") Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring/timeout: don't put a sequence target behind the last flushJens Axboe
io_timeout_fn() and io_kill_timeout() bump ->cq_timeouts when a timeout fires, but its CQE is only posted later from task_work. Until then the sequence io_timeout() computes is one below the last flush per fired timeout. Now that ->cq_last_tm_flush is kept while sequence timeouts are pending, a timeout armed in that window with a small offset gets a target behind the base. Its distance from the base wraps, and it's never completed by events, only by its timer. With DEFER_TASKRUN that window is as wide as the application makes it, as submission runs before the local task_work. Nothing but those in flight CQEs separates the two, so use the last flush as the base for the target when the sequence is behind it. Fixes: c6c0b3eba88c ("io_uring/timeout: don't skip over reached sequences") Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring/poll: avoid retry wakeup loss when dropping ownershipJuanlu Herrero
If a wakeup sets IO_POLL_RETRY_FLAG between the owning task consuming the existing instance of IO_POLL_RETRY_FLAG and the loop check of io_poll_check_events(), then we stall on processing the request until an unrelated wakeup comes along. Using atomic_cmpxchg instead of atomic_sub_return to guarantee both the count v and poll_refs are 0 and no wake-ups are missed. Cc: stable@vger.kernel.org Fixes: a26a35e9019f ("io_uring: make poll refs more robust") Signed-off-by: Juanlu Herrero <juanlu@fastmail.com> Assisted-by: LLM Suggested-by: Anand Natarajan <anand@meta.com> Link: https://patch.msgid.link/20261013-pu-cmpxchg-v1-1-4ddc10fd8a03@fastmail.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring: look up the file before queueing to io-wqJosef Bacik
io_prep_async_work() decides by the file of a request what kind of work it is for io-wq. I/O on regular files and block devices is bounded work, limited to min(SQ entries, 4 * CPUs) workers, for anything else that may block indefinitely the limit is RLIMIT_NPROC. Writes to a regular file are hashed by the inode, so that they are run one after the other instead of having a bunch of workers fight for the inode lock. Since the file is only assigned when a request is issued, a request that is queued without an attempt to issue it, REQ_F_FORCE_ASYNC, doesn't have one at that point. io_prep_async_work() takes that for "not a regular file or block device": - Reads and writes end up as unbound work. 32 reads with IOSQE_ASYNC from a slow block device on a ring with 4 SQ entries get 32 workers, not 4. - Writes aren't hashed. Four buffered writes to one file get four workers, three of which do nothing but wait for the lock. The late assignment is for the benefit of links, where a request may use a fixed file that one of its predecessors installs. By the time a request gets to io_queue_iowq() these are done, it is as good as issued. Assign the file there. io_assign_file() moves up and is forced inline. With a third caller the compiler may stop inlining it, and every request that is issued would pay for a call. IORING_OP_SPLICE is left as it is, unbound and not hashed. The file of the request is where it writes to, which says nothing about how long it takes: a splice from an empty pipe or a socket into a regular file waits for its input. As bounded work, four of these on a ring with 4 SQ entries keep all other bounded work of the task from running, and as hashed work one of them blocks all writes to that file. REQ_F_FORCE_ASYNC is not only set for IOSQE_ASYNC. What changes, and brings back what was the case before the file assignment was deferred: - Requests with IOSQE_ASYNC or IOSQE_IO_DRAIN, and all requests that are submitted while a drain is active: reads and writes on regular files and block devices count against the limit for bounded workers, including the one set with IORING_REGISTER_IOWQ_MAX_WORKERS, so fewer of them run at the same time. - Of these, writes to one regular file are run one at a time, unless they are O_DIRECT and the filesystem has FOP_DIO_PARALLEL_WRITE. - IORING_OP_FALLOCATE and IORING_OP_FTRUNCATE, which always go to io-wq, are run one at a time per file, and in turn with these writes. - The descriptor or the fixed file slot is looked up when the request is queued, not when a worker gets around to it, so closing or replacing it in between no longer has an effect on the request. Fixes: 6bf9c47a3989 ("io_uring: defer file assignment") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-43-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring/timeout: don't end a linked timeout with 1Josef Bacik
A linked timeout that fires cancels the request it is linked to, and completes with -ETIME if that worked out: ret = io_try_cancel(req->tctx, &cd, 0); ... io_req_set_res(req, ret ?: -ETIME, 0); io_try_cancel() returns 0 or an error, except for requests that are parked on ->futex_list or ->waitid_list. io_futex_cancel() and io_waitid_cancel() return the number of requests that they have cancelled, and io_try_cancel() hands it on. So the linked timeout of an IORING_OP_FUTEX_WAIT, IORING_OP_FUTEX_WAITV or IORING_OP_WAITID that it has cancelled completes with 1, each time. The waitid test of liburing checks for that 1, and has to be changed to expect -ETIME, which is what the linked timeout of any other request completes with. Fixes: f31ecf671ddc ("io_uring: add IORING_OP_WAITID support") Fixes: 194bb58c6090 ("io_uring: add support for futex wake and wait") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-42-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring/timeout: no ABS update of multishot timeoutsJosef Bacik
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: ea97f6c8558e ("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>
41 hoursio_uring/net: don't retry recv on uncommitted buffersJosef Bacik
Commit 41b70df5b38b ("io_uring/net: commit partial buffers on retry") commits ring provided buffers when a receive is going to be retried after a partial transfer, so that another request using the same buffer group can't be handed the memory the first one keeps receiving into. It commits the number of bytes received so far. That does the job for a single buffer which is consumed as a whole, but the request hangs on to all it has mapped: - For a buffer ring with IOU_PBUF_RING_INC only these bytes are consumed. The rest of the buffer stays at the head of the ring. - For a bundle only the buffers which hold these bytes are consumed, the others that were peeked stay in the ring. In both cases the next receive with that buffer group gets memory that the retried request is still going to write to, and whoever comes last overwrites the data of the other. What the retry fills isn't committed at all, as the buffer list isn't known any more at that point. So the kernel hands it out again later on, while the CQE tells the application that it was used, and for an incremental buffer that it is done with. The remainder can't be committed in advance: if the request ends up receiving less, there is no way to tell the application that more was consumed than the CQE accounts for. Complete the request with what it has got instead of retrying it. MSG_WAITALL is no longer honoured for receives into incremental buffers or multi buffer bundles, they can return a short count, with the request marked as failed like for other short MSG_WAITALL transfers. Fixes: 41b70df5b38b ("io_uring/net: commit partial buffers on retry") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-40-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring: don't pass restart error codes to userspaceJosef Bacik
-ERESTARTSYS and friends are instructions for the system call exit code, which either restarts the call or turns them into -EINTR. They are not supposed to be seen by applications. A request isn't a system call, nobody looks at what it returns before that is put into a CQE. The read/write and the networking opcodes convert these codes to -EINTR by hand. The others don't. An io-wq worker that is blocked in the open of a FIFO, a tty or some other device, or in a splice from an empty pipe, and that gets interrupted because the request is cancelled, completes it with -512: IORING_OP_OPENAT, IOSQE_ASYNC // FIFO without a writer IORING_OP_ASYNC_CANCEL // -EALREADY, worker is signalled CQE of the open: res == -512 There are more candidates, like whatever a file system or driver returns from ->flush(), ->fsync(), ->fallocate() or ->uring_cmd(), or breaking a lease or delegation. Take care of it in io_issue_sqe(), which all of them go through. The helper is moved from rw.c as is. The cost is a compare and a branch that is not taken per request. Fixes: 15b71abe7b52 ("io_uring: add support for IORING_OP_OPENAT") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-39-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring/openclose: keep the lock in io_pipe_fixed()Josef Bacik
io_pipe_fixed() installs both ends of the pipe in the fixed file table, drops ->uring_lock, and copies the slot numbers to the application. If that faults, it takes the lock again and removes whatever is in these slots. If the request is run by io-wq the lock really is dropped in between, and the slots are visible to everybody else. By the time the error path gets to them, they may have been closed and reused, by IORING_OP_CLOSE and a direct open or accept, or by IORING_REGISTER_FILES_UPDATE. Then a file is removed from the table that has nothing to do with the failed request. Do the copy with the lock held. Faulting in user memory under ->uring_lock is fine, the registration paths do it all the time. Fixes: 53db8a71ecb4 ("io_uring: add support for IORING_OP_PIPE") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-38-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring/sqpoll: let the thread sleep on disabled ringsJosef Bacik
__io_sq_thread() doesn't submit anything as long as the ring has IORING_SETUP_R_DISABLED set. The check that keeps the SQPOLL thread from going to sleep while the SQ ring holds entries doesn't know about that. If an application fills in SQEs first and enables the ring later, the thread finds that there is work each time it is about to sleep, goes around, doesn't submit it, and so on. It uses up a CPU until the ring gets enabled. Entries in the SQ ring of a disabled ring are no reason to stay awake. io_register_enable_rings() clears the flag and then wakes the thread, and the flag is looked at after prepare_to_wait(), so the thread can't miss that. Fixes: 0298ef969a11 ("io_uring: clean R_DISABLED startup mess") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-37-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring/kbuf: handle index wrap in last buffer checkJosef Bacik
io_ring_buffer_select() flags the request with REQ_F_BL_EMPTY if it takes the last buffer of the ring. Head and tail are 16-bit counters, but "head + 1" is computed as an int. If head is 65535 and tail has wrapped to 0, that compares 65536 to 0 and the flag isn't set. A bundle receive relies on the flag to tell that there is no point in trying to get more data. Without it, it goes for another round, finds no buffer, and the request, which has received data, is marked as failed on account of the -ENOBUFS. That severs a link, and ends a multishot. Fixes: c3f9109dbc9e ("io_uring/kbuf: flag request if buffer pool is empty after buffer pick") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-36-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring/zcrx: fix buffer offsets in areas above 4GBJosef Bacik
io_zcrx_queue_cqe() computes the offset of the buffer in its area from net_iov_idx(), which is an unsigned int, so the shift is done in 32 bits and only the result is widened to the u64 that goes into the CQE. An area can be up to 1TB in size. For every niov beyond the first 4GB the CQE points the application at a buffer 4GB, or a multiple of that, below the one which has the data. It reads the wrong data, and then returns a buffer it doesn't own via the refill queue while the real one is never given back. Fixes: 11ed914bbf94 ("io_uring/zcrx: add io_recvzc request") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-35-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring/napi: don't busy poll past an expired timeoutJosef Bacik
__io_napi_busy_loop() caps the busy poll time to what is left until the timeout of the wait. The difference is negative if the timeout has passed already, which is what an application gets if it uses IORING_ENTER_ABS_TIMER with a time that isn't in the future any more. The min_t(u64, ...) turns that into a huge value, so the cap has no effect and the wait, which should return right away, spins for the full busy poll time first. Fixes: d5cce407e4f5 ("io_uring/napi: postpone napi timeout adjustment") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-34-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring/napi: make stale entries time out after 60sJosef Bacik
With dynamic tracking a NAPI id that hasn't been seen for a minute is meant to be dropped from the list the ring busy polls. The timeout is added to jiffies, but it is defined as 60 * SEC_CONVERSION, and SEC_CONVERSION isn't the number of jiffies in a second. It is the internal factor of __timespec64_to_jiffies(), HZ scaled up by SEC_JIFFIE_SC bits. For HZ=1000 that is 1000 << 22, which puts the timeout at about eight years. On 32-bit the multiplication overflows. So entries are never removed, and every id that a socket of the ring ever had keeps being polled on each wait. Fixes: 8d0c12a80cde ("io-uring: add napi busy poll support") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-33-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring/wait: no early -ETIME if min_wait finds workJosef Bacik
When the min wait time is over and there is work to run, which for DEFER_TASKRUN includes task_work that was queued lazily and didn't wake the waiter, io_cqring_min_timer_wakeup() ends the wait via io_cqring_timer_wakeup(). That flags it as timed out. io_cqring_wait() runs the work, leaves the loop, and returns 0 if the CQ ring holds something. Running task_work doesn't have to result in a CQE, though. A poll wake up can turn out to be spurious, for instance if somebody else has read the data by the time the request is retried. The application then gets -ETIME once the min wait time has passed, no matter how far away the timeout it asked for is. Wake the task without declaring a timeout. From now on a single CQE satisfies the wait, like in the case where the timer is switched over to the normal timeout. If running the work doesn't post one, the loop in io_cqring_wait() goes back to sleep with the normal timeout. Fixes: 1100c4a2656d ("io_uring: add support for batch wait timeout") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-32-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring/timeout: use the right clock for ABS updatesJosef Bacik
io_parse_user_time() converts an absolute time from the time namespace of the caller to the host's view, for the clock given by the flags. The flags of IORING_TIMEOUT_UPDATE and IORING_LINK_TIMEOUT_UPDATE can't name a clock, the updated timer keeps running on the clock the timeout was set up with. So the time is always converted as if it was CLOCK_MONOTONIC. In a time namespace with a monotonic offset, that moves the new expiry of a CLOCK_REALTIME timeout by that offset, although the clock isn't affected by time namespaces at all, and the one of a CLOCK_BOOTTIME timeout by the difference between the two offsets. Do the conversion when the timeout has been looked up and its clock is known. The update is run by the submitter, its SQPOLL thread or one of its io-wq workers, all of which share the time namespace. Fixes: 9cc6bac1bebf ("io_uring/timeout: honour caller's time namespace for IORING_TIMEOUT_ABS") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-31-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring/timeout: keep repeat count on multishot updateJosef Bacik
IORING_TIMEOUT_UPDATE clears ->off of the timeout it updates, to turn a timeout that waits for a number of completions into a pure one. For a multishot timeout ->off isn't a sequence though, it tells whether the number of repeats is limited: io_timeout_finish() only looks at ->repeats if ->off is set. A multishot timeout that was set up to fire N times hence fires forever once its interval has been updated. Leave ->off alone for those, they are never treated as sequence timeouts anyway. Fixes: ea97f6c8558e ("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-30-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring/timeout: don't skip over reached sequencesJosef Bacik
io_flush_timeouts() copes with the wrap of the CQ sequence by looking at the distance from ->cq_last_tm_flush. That relies on the target of each pending timeout being at or ahead of the last flush. io_timeout() breaks that. It sets ->cq_last_tm_flush to the current sequence, on the assumption that nothing has been posted since the last flush. That isn't true. A multishot request posts its CQEs right when it is issued or retried, but they are committed, and the timeouts flushed, at the end of the submission or task_work run: X: IORING_OP_TIMEOUT, off == 1 target_seq == N + 1 io_submit_sqes() multishot recv, posts two CQEs sequence == N + 2 Y: IORING_OP_TIMEOUT, off == 100 ->cq_last_tm_flush = N + 2 io_flush_timeouts() X: events_needed = N + 1 - (N + 2) // 0xffffffff events_got = 0 // not yet X isn't completed although the completions it was waiting for have happened, only its timer can end it now. And as the list is sorted and the walk ends at the first timeout that isn't due, it gets in the way of the ones behind it. The insertion sort has the same problem, it measures the distance of the pending targets from the current sequence. ->cq_last_tm_flush only needs to be brought up to date if no timeout is waiting for a sequence, as io_flush_timeouts() isn't called before the first one is set up. Otherwise it is current enough. Timeouts with a sequence come first in the list, so looking at the first entry will do. Use the last flush as the base for the insertion sort as well. Fixes: f010505b78a4 ("io_uring: flush timeouts that should already have expired") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-29-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring/fdinfo: fix CQE dump of CQE32 ringsJosef Bacik
Since the CQ ring dump was changed to deal with IORING_SETUP_CQE_MIXED, a 32b CQE is taken to occupy two entries of the ring. That is how it works for mixed rings. With IORING_SETUP_CQE32 each entry has twice the size: head and tail count 32b CQEs, and entry n is found at cqes[n << 1]. For such rings the dump reads cqes[n], and skips every other entry. It shows half of the pending CQEs at best, and what it shows is taken from the wrong place unless the head happens to be at the start of the ring. The extra data of the last entry isn't shown at all, as the check that keeps the dump of a mixed ring from reading beyond the array is applied to these rings as well. Fixes: 82ceb7fcc5ff ("io_uring/fdinfo: handle mixed sized CQEs") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-28-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring/register: keep 128b SQEs intact on resizeJosef Bacik
On a ring with IORING_SETUP_SQE_MIXED a 128b SQE takes two entries that have to be contiguous in memory, io_init_req() fails it with -EINVAL if it starts on the last entry of the SQ ring. The entry a pending SQE ends up in after IORING_REGISTER_RESIZE_RINGS depends on the size of the new ring, and nothing takes care of that. With four entries instead of eight, a 128b SQE which was fine in entries 3 and 4 is split up between entry 3 and entry 0. The resize succeeds, and the request fails later on. If the ring has an SQ array, the second half is also taken from the wrong place unless the array happens to map the following index to the following entry. The submission side doesn't look at the array for the second half. Do what is done for 32b CQEs on IORING_SETUP_CQE_MIXED rings: fail the resize with -EOVERFLOW if a 128b SQE would wrap. And copy the second half from where it is. Fixes: 1cba30bf9fdd ("io_uring: add support for IORING_SETUP_SQE_MIXED") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-27-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring/register: handle index wrap when resizingJosef Bacik
The ring heads and tails are free running 32-bit counters. io_register_resize_rings() takes that into account when it checks whether the pending entries fit into the new rings, but then copies them with for (i = old_head; i < tail; i++) If the tail has wrapped and the head hasn't, that copies nothing. The new rings get the old head and tail, so the application finds whatever is in the freshly allocated memory, zeroes, in place of the CQEs it hasn't reaped yet, or the kernel in place of the SQEs that have not been submitted yet. A ring that completes a million requests per second gets there after little more than an hour. Loop until the tail is reached, the number of iterations has been bounded by the size of the new ring at that point. Fixes: 79cfe9e59c2a ("io_uring/register: add IORING_REGISTER_RESIZE_RINGS") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-26-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring/register: don't wrap 32b CQEs when resizingJosef Bacik
On an IORING_SETUP_CQE_MIXED ring, a 32b CQE uses two contiguous CQ entries and is never allowed to wrap the end of the ring. When posting, io_cqe_cache_refill() inserts a dummy IORING_CQE_F_SKIP entry if only one entry is left before the ring wraps, and the application relies on that to read a 32b CQE as one contiguous 32 byte slot. io_register_resize_rings() copies pending CQEs to the new ring one 16b entry at a time, placing entry i at i & (new_entries - 1). When the CQ ring is shrunk, a pending 32b CQE that was contiguous in the old ring can land with its first half on the last entry of the new ring and its second half on entry 0. For example, with 8 old entries, 4 new entries and a 32b CQE at index 3, the halves end up at entries 3 and 0. The application then reads the extra data of that CQE from past the end of the CQ array, and the CQE content it sees is wrong. This was found by code inspection and has not been reproduced. Fix by failing the resize with -EOVERFLOW if a pending 32b CQE would wrap the new ring, the same way the resize fails when the pending CQEs don't fit. Fixes: e26dca67fde1 ("io_uring: add support for IORING_SETUP_CQE_MIXED") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-25-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring: don't split 128b SQEs at the SQPOLL capJosef Bacik
If an SQPOLL thread serves more than one ring, __io_sq_thread() submits no more than IORING_SQPOLL_CAP_ENTRIES_VALUE entries per ring and round, for fairness. On a ring with IORING_SETUP_SQE_MIXED the cap may fall between the two entries of a 128b SQE. io_init_req() finds that just one entry is left of what it was asked to submit and fails the request with -EINVAL, although the second entry is sitting in the SQ ring. In the next round the second entry is taken for an SQE of its own, so on top of the failed request the application gets whatever its payload amounts to when it is read as an SQE. The application has done nothing wrong, and it can't know where the cap is going to be applied. For SQPOLL, let the request have its second entry if the SQ ring holds it, in excess of the number of entries that were to be submitted. Fixes: 1cba30bf9fdd ("io_uring: add support for IORING_SETUP_SQE_MIXED") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-24-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring: drop the CQE cache if a refill failsJosef Bacik
->cqe_cached and ->cqe_sentinel delimit the CQ entries which can be handed out without looking at the ring. io_get_cqe_overflow() only calls io_cqe_cache_refill() if that range is too small. Without IORING_SETUP_CQE_MIXED too small means empty. With it, a 32b CQE needs two entries, and one may be left. If the refill then fails, the entry stays in the cache, and the next 16b CQE gets it without any checks. That CQE overtakes the 32b one, which went to the overflow list. The test for IO_CHECK_CQ_OVERFLOW_BIT, which is there to prevent that, is part of the refill: CQ ring with 4 entries, head == 0 16b CQE, 32b CQE tail == 3, one entry cached 32b CQE no room, the CQE overflows 16b CQE written to entry 3, ahead of the 32b CQE Forget about the rest of the cache when it is refilled. Fixes: e26dca67fde1 ("io_uring: add support for IORING_SETUP_CQE_MIXED") Reported-by: Leonid Ovchinnikov <teiny.work@gmail.com> Closes: https://lore.kernel.org/io-uring/CAECZYD5OMD9vMTzjteFMMP40Dn+SWKj9SFj=43U6uO3XMnxJbw@mail.gmail.com/ Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-23-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring/futex: allocate private hash before waitingJosef Bacik
The futex code relies on there being no private futex waiters by the time the first private hash of a mm is installed: __futex_pivot_hash() moves the waiters from the previous private hash to the new one, but it does not look for them in the global hash which is used as long as there is no private hash. That is why every clone(CLONE_VM) allocates it up front: a task which is alone in its mm cannot block in futex_wait() and create a thread or invoke prctl(PR_FUTEX_HASH) at the same time. IORING_OP_FUTEX_WAIT and IORING_OP_FUTEX_WAITV do not block the submitter though: io_uring_enter() io_futex_wait() futex_wait_setup() // no private hash: queued in the global hash pthread_create() futex_hash_allocate_default() __futex_pivot_hash() // first private hash, nothing is moved futex(FUTEX_WAKE_PRIVATE) futex_hash() // private hash: no waiter The wakeup is lost and the request only completes when it is cancelled. prctl(PR_FUTEX_HASH, PR_FUTEX_HASH_SET_SLOTS, n) instead of pthread_create() has the same effect. Allocate the default private hash when a wait request on a private futex is prepared, which happens in the context of the submitter. This is a RCU protected pointer check once the hash exists. A failure to allocate it fails the request with -ENOMEM. Fixes: 80367ad01d93 ("futex: Add basic infrastructure for local task local hash") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-22-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring/poll: drop stale double poll entry on rearmJosef Bacik
A file that uses two wait queues for poll, e.g. a tty, gets a second io_poll entry, which IORING_OP_POLL_ADD keeps in ->async_data until the request is freed. io_poll_add() can run more than once for a request though: IORING_OP_POLL_REMOVE with one of the update flags disarms and rearms it, and io_poll_task_func() reissues it if a wake up turns out to be spurious. The second poll_wait() of the new round then finds *poll_ptr set, with ->head cleared by the disarm, and __io_queue_proc() fails what it takes for a third wait queue with -EINVAL. For an update that means that the poll request is completed with -ECANCELED, while the update itself reports success. For a spurious wake up, e.g. tcsetattr() on the polled tty, the poll request fails with -EINVAL. Free the old entry and clear the poll flags before arming, which is what io_arm_apoll() does for internal polling. All entries have been removed from their wait queues at that point. Fixes: b69de288e913 ("io_uring: allow events and user_data update of running poll requests") Fixes: 6e5aedb9324a ("io_uring/poll: attempt request issue after racy poll wakeup") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-21-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring/wait: look at all CQ waiters on wake upJosef Bacik
io_wake_function() returns -1 if the waiter it is called for doesn't have enough events yet, which makes __wake_up_common() stop walking the wait queue. That assumes that the waiters behind it can't be satisfied either. Each waiter has its own target though, computed from the min_complete it passed in: thread A: io_uring_enter(GETEVENTS, min_complete = 10) // queued first thread B: io_uring_enter(GETEVENTS, min_complete = 1) one CQE is posted: A isn't woken, and B isn't even considered B keeps sleeping with the event it asked for sitting in the CQ ring, until A's demand is met or a timeout or signal ends the wait. Return 0 to carry on with the next waiter. Only waiters whose condition is met are woken, like before. Fixes: bda521624e75 ("io_uring: make CQ ring wakeups be more efficient") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-20-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring: wake ring pollers for local task_workJosef Bacik
With IORING_SETUP_DEFER_TASKRUN completions are queued as local work, and only become CQEs when the submitter enters the kernel to wait for events. For an application that finds out via poll() or epoll on the ring fd when it is time to do that, io_uring_poll() reports EPOLLIN if local work is pending. That only helps if the work is there at the time of the call. When DEFER_TASKRUN was added, io_req_local_work_add() did io_cqring_wake(), which took care of tasks sleeping in poll() as well. Then polling got a wait queue of its own, ->poll_wq, and the wake up in io_req_local_work_add() was replaced by waking the submitter directly. Since then ->poll_wq is only woken when CQEs are committed, which for such a ring is done by the very task that is waiting to be told to: submitter completion poll(ring_fd) io_uring_poll() // nothing yet schedule() io_req_local_work_add() // ->cq_wait_nr: nobody waits // sleeps on Wake ->poll_wq when the first entry is put on the work list. Like for the eventfd, that must not be done right away if the work is queued from a wake up handler, as the chain of wake ups could get back to the wait queue whose lock is held. Use an RCU callback in that case, with a reference to the ring. Fixes: 130bd686d9be ("io_uring: waitqueue-less cq waiting") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-19-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring/cancel: let CANCEL_ALL find parked requestsJosef Bacik
A cancellation with IORING_ASYNC_CANCEL_ALL or _ANY goes on until it finds nothing more. A request may stay where it was found for a while after it has been cancelled, so each one that matches is stamped with the sequence number of the cancellation, and is skipped from then on. io_cancel_cb() does so for io-wq work as well. There is no need to: pending work is taken off the list, and the workers are looked at once per call. And it does harm. A request that is run by io-wq may be parked while it still is the current work of the worker: poll gets armed for it, or it is put on ->futex_list or ->waitid_list. io-wq worker io_try_cancel() io_wq_submit_work() io_arm_poll_handler() io_poll_add_hash() io_async_cancel_one() io_cancel_cb() stamps the request sets IO_WQ_WORK_CANCEL = -EALREADY io_poll_cancel() skips the request = -ENOENT io_assign_current_work(NULL) The flag comes too late for the worker to see it, and the search that would have found the request takes it for done. The cancellation returns, and the request stays. With a multishot poll, IOSQE_ASYNC, and IORING_OP_ASYNC_CANCEL with IORING_ASYNC_CANCEL_ALL up to 63us later, that happens to 4 of 1,000 requests (4 CPUs, KVM). Take the stamp off again if the work matches. If the request is found on one of the lists it gets a new one, and io_cancel_cb() doesn't match it a second time. __io_async_cancel() tries the io-wq of the caller twice. So far the stamp has kept it from counting work that is running there the second time. Skip it instead, so that the number that is returned stays the same. Fixes: 8e29da69fead ("io_uring: add support for IORING_ASYNC_CANCEL_ALL") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-18-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring/cancel: recognize "no timeout" on 32-bitJosef Bacik
IORING_REGISTER_SYNC_CANCEL waits without a limit if both fields of io_uring_sync_cancel_reg::timeout are -1. io_sync_cancel() compares them with -1UL. They are of type long long. With a long of 32 bits -1UL is 4294967295, which is what it stays when it is converted for the comparison, and the fields are never equal to it. So { -1, -1 } is taken for a timeout. ktime_set() takes the nanoseconds as an unsigned long, so what becomes of it is -1s + 4294967295ns = 3.29s. If the request is being run by io-wq and can't be interrupted, the call returns -ETIME after that time, rather than waiting for the request to be gone. On i386, with a buffered read from a null_blk device that takes 4s to complete a request, IOSQE_ASYNC, that is what each call does. Fixes: 78a861b94959 ("io_uring: add sync cancelation API through io_uring_register()") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-17-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring/cancel: don't forget that the work was runningJosef Bacik
If the request to be cancelled is being run by io-wq, io_async_cancel_one() flags the work, signals the worker and returns -EALREADY. Since commit ccbf726171b7 ("io_uring: perform poll removal even if async work removal is successful") io_try_cancel() goes on regardless, as poll may be armed for the request. If it isn't, and nothing else turns up, the result is the -ENOENT of the last search. __io_async_cancel() makes up for that. On -ENOENT it tries the io-wq of every task that uses the ring, and that of the caller is one of them. So the work is found a second time, and the result is -EALREADY after all. Unless the worker is done with it by then. If the work is flagged before io_wq_submit_work() looks at IO_WQ_WORK_CANCEL, all the worker does is to queue the request to be failed by task work. Then it isn't anywhere to be found until the task work has run, and - IORING_REGISTER_SYNC_CANCEL returns -ENOENT, - IORING_OP_ASYNC_CANCEL completes with -ENOENT, for a request that they have just cancelled, and that completes with -ECANCELED. With a read of an empty pipe, IOSQE_ASYNC, and a sync cancel right behind it, 1 to 3 of 1,000,000 calls return -ENOENT, and 50 to 110 with IORING_SETUP_DEFER_TASKRUN (4 CPUs, KVM). Nothing is written to the pipe, and all of these reads end with -ECANCELED. Remember that the work was found. IORING_OP_ASYNC_CANCEL completes with -EALREADY, as it does if the worker is a bit slower. For IORING_REGISTER_SYNC_CANCEL it means to try again, which ends with 0. The result of a linked timeout, which calls io_try_cancel() by itself, and the number that is returned for IORING_ASYNC_CANCEL_ALL and _ANY don't change. Fixes: ccbf726171b7 ("io_uring: perform poll removal even if async work removal is successful") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-16-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring: don't lose a cancel as io-wq parks a requestJosef Bacik
IORING_OP_FUTEX_WAIT, IORING_OP_FUTEX_WAITV and IORING_OP_WAITID don't block. They put the request on a list of the ring, where a wake up or a cancellation finds it, and return IOU_ISSUE_SKIP_COMPLETE. They do so as well if they are run by io-wq, e.g. because of IOSQE_ASYNC. io_wq_submit_work() looks at IO_WQ_WORK_CANCEL once, before it issues the request. Somebody who wants to cancel the request after that, and before it is on the list, finds it running: io-wq worker io_try_cancel() io_wq_submit_work() IO_WQ_WORK_CANCEL isn't set io_async_cancel_one() sets IO_WQ_WORK_CANCEL signals the worker = -EALREADY ... io_futex_cancel() = -ENOENT ... io_futex_wait() adds the request to ->futex_list = IOU_ISSUE_SKIP_COMPLETE Nobody looks at the flag again. IORING_OP_ASYNC_CANCEL returns -EALREADY and the request stays. It is the problem that "io_uring/poll: don't lose a cancel as io-wq arms poll" deals with for poll. Look at the flag once the request is on the list, and cancel it if it is set. The lists are searched and the requests are added with ->uring_lock held, and the flag is set before the search. So either the search finds the request, or it came first and the flag is seen. What the canceller is told doesn't change, see the other patch, also for IORING_ASYNC_CANCEL_ALL and _ANY. Fixes: 194bb58c6090 ("io_uring: add support for futex wake and wait") Fixes: 8f350194d5cf ("io_uring: add support for vectored futex waits") Fixes: f31ecf671ddc ("io_uring: add IORING_OP_WAITID support") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-15-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring/poll: don't lose a cancel as io-wq arms pollJosef Bacik
A request on a pollable file that was forced to io-wq is issued without blocking there. If that ends in -EAGAIN, io_wq_submit_work() arms poll for it and returns. It looks at IO_WQ_WORK_CANCEL once, before it issues the request. Somebody who wants to cancel the request in between finds it running: io-wq worker io_try_cancel() io_wq_submit_work() IO_WQ_WORK_CANCEL isn't set io_issue_sqe() = -EAGAIN io_async_cancel_one() sets IO_WQ_WORK_CANCEL signals the worker = -EALREADY io_poll_cancel() = -ENOENT ... = -ENOENT io_arm_poll_handler() = IO_APOLL_OK return Nobody looks at the flag again, and the signal doesn't matter to a worker that doesn't sleep. The request is armed as if nothing had happened: - a linked timeout completes with -ENOENT, and the request it was meant to limit waits for as long as it takes. - IORING_OP_ASYNC_CANCEL returns -EALREADY, and the request stays. - IORING_REGISTER_SYNC_CANCEL waits for the request to complete if it gets -EALREADY. Since commit 5623eb1ed035 ("io_uring/tctx: add separate lock for list of tctx's in ctx") it doesn't sleep but spins, so its next attempt finds the armed poll. The same goes for a multishot poll, recv or accept that is armed from io-wq. With a read of an empty pipe, IOSQE_ASYNC, and a linked timeout of 5ms or a cancel in the same submission, in a guest that is slow enough (TCG, KASAN), the request is lost in 21 of 24 rounds of 40 or 100 attempts. While it arms poll from io-wq, __io_arm_poll_handler() owns the request. Look at the flag once the request is in the hash table. The table is searched and the request is added with ->uring_lock held, and the flag is set before the search. So either the search finds the request, or it came first and the flag is seen. With the request marked as cancelled, the task work that is queued, right away or because ownership can't be released, fails it with -ECANCELED. What the canceller is told doesn't change. In this window a linked timeout still completes with -ENOENT rather than -ETIME, a cancel request with -EALREADY, and one with IORING_ASYNC_CANCEL_ALL or _ANY with a count that doesn't include the request. But the request is cancelled, so what is new is a request that completes with -ECANCELED after such a result. This doesn't help in two cases: - IORING_ASYNC_CANCEL_ALL and _ANY, if the work is flagged after the test added here, while io-wq still has it as the current work of the worker. io_cancel_cb() stamps it with the sequence of the cancel, so the search of the hash table on behalf of the same cancel takes it for done and skips it. - requests that are parked elsewhere by io-wq, like IORING_OP_FUTEX_WAIT and IORING_OP_WAITID. They have the same problem. Fixes: 90fa02883f06 ("io_uring: implement async hybrid mode for pollable requests") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-14-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring/io-wq: let cancel find picked up hashed workJosef Bacik
io_get_next_work() takes all the work items that share a hash off the work list in one go, and the worker runs them one after the other. Only the one it is working on is visible as ->cur_work. The others are neither on the list nor current, so io_wq_cancel_cb() can't find them. IORING_OP_ASYNC_CANCEL and IORING_REGISTER_SYNC_CANCEL return -ENOENT for a request that has not even been started, e.g. a buffered write queued behind another write to the same file that is blocked, and the request is carried out. The cancellation done for a task or ring that goes away gets there in the end, as it keeps trying, but it has to wait for each item to become current. Keep a pointer to the remainder of the chain next to ->cur_work, and have io_wq_worker_cancel() look at it. The items on it belong to the worker, which needs ->lock to move on to the next one. Matching work is flagged with IO_WQ_WORK_CANCEL and fails with -ECANCELED when its turn comes. The worker isn't signalled for it, that would interrupt the unrelated work it is busy with. As the request isn't gone yet, it is reported like running work, with -EALREADY. Fixes: 86f3cd1b589a ("io-wq: handle hashed writes in chains") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-13-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring/io-wq: don't exit with a creation pendingJosef Bacik
A worker that is the last one to go to sleep while work is pending asks for another worker. io_wq_dec_running() bumps ->nr_running on behalf of the new worker and queues create_worker_cb() as task_work for the owner of the io-wq. Until that has run, everybody else takes it that a worker is running which is going to look after the work list: io_wq_enqueue() doesn't create one, and other workers that go to sleep don't find themselves to be the last. If the worker that made the request exits, io_worker_exit() cancels the task_work, and io_worker_cancel_cb() drops ->nr_running without a look at the work list: worker A worker B io_wq_enqueue() blocks, work is pending nr_running++ queues create_worker_cb() wakes, handles the work idle timeout, decides to exit picks up work 1 queues work 2 B is on the free list still: wakes B work 1 blocks nr_running 2 -> 1 io_worker_exit() io_worker_cancel_cb() nr_running 1 -> 0 Work 2 has to wait for work 1, although there is room for more workers. It takes an owner that doesn't get around to run its task_work for the time of the idle timeout, less if the worker exits because its affinity was changed or the io-wq is marked exit-on-idle. Let the worker stay around until its request has been dealt with. Only the worker itself sets ->create_state, so it can't be set behind its back once it has decided to leave. Fixes: 1d5f5ea7cb7d ("io-wq: remove worker to owner tw dependency") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-12-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring/io-wq: don't strand work when a worker exitsJosef Bacik
A worker exits if its idle timeout fired and it isn't the last one, if its affinity was changed, or if the wq is marked exit-on-idle. It decides so after it found the work list empty, and until io_worker_exit() is through it stays on the free list and in ->nr_running: worker io_wq_enqueue() io_acct_run_queue() == false queues work io_acct_activate_free_worker() wake_up_process(worker) // found one, nothing to create acct->nr_workers-- break io_worker_exit() Nobody is going to look at the work. If other workers exist, it has to wait until one of them finishes what it is blocked on or hits its idle timeout. If not, which is possible for the affinity and the exit-on-idle case, it sits there until something else is queued. For exit-on-idle it takes a task that closes its last ring and sets up a new one while the workers are on their way out. Make the worker take itself off the free list when it gives up its ->nr_workers slot, then leave ->nr_running, and only then take the final look at the work list. That look and queueing work are both done under acct->lock, so either the worker sees the work and stays, or the enqueue side sees that the worker is gone and wakes or creates another one. If it wants to stay and finds that its slot has been taken, a worker has been created in its place, which is going to look at the work list, and it can leave after all. Fixes: 38aa434ab933 ("io_uring/io-wq: add exit-on-idle state") Fixes: 05c5f4ee4da7 ("io-wq: get rid of FIXED worker flag") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-11-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
41 hoursio_uring/io-wq: don't go to sleep on pending workJosef Bacik
io_wq_enqueue() wakes a worker off the free list. If there is none it creates one, unless ->nr_running says that a worker is running. That relies on whoever takes ->nr_running to zero to check for pending work, which io_wq_dec_running() no longer does for a worker without ->cur_work, on the grounds that an idle worker is either woken right away or someone else has created a worker. Neither has to be the case: worker A (idle) worker B (idle) io_wq_enqueue() woken for work 1 woken (e.g. timeout) takes work 1 work list is empty queues work 2 B is first on the free list: wake_up_process(B) leaves the free list work 1 blocks nr_running 2 -> 1 schedule_timeout() nr_running 1 -> 0 ->cur_work == NULL Work 2 isn't looked at until work 1 is done or A's idle timeout fires, five seconds later. ->cur_work is also NULL while a worker blocks on ->uring_lock in io_wq_put_work(), with the same result if it was the only one running. Let the idle worker leave ->nr_running by itself before it takes its last look at the work list. Both that and queueing work are done under acct->lock, so either the worker sees the work, or the enqueue side sees that it can't count on this worker. This doesn't bring back the request for a new worker which the check was meant to avoid, and as idle workers don't get to io_wq_dec_running() any more, the check can go. Fixes: 8343cae362e1 ("io_uring/io-wq: ignore non-busy worker going to sleep") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-10-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
42 hoursio_uring/mpscq: disable preemption while pushingJosef Bacik
A push makes the node the new tail, and then links it to its predecessor. In between the queue isn't empty, but mpscq_pop() can't get at the node. The consumers deal with that by trying again, with a cond_resched() in the loop to give a preempted producer the chance to finish. cond_resched() doesn't do that if the consumer has a higher priority than the producer and both have to use the same CPU: producer (SCHED_OTHER) consumer (SCHED_FIFO), same CPU io_req_local_work_add() mpscq_push() prev = xchg(&q->tail, node) <preempted> io_cqring_wait() __io_run_local_work() again: cond_resched() // nothing to do mpscq_pop() // NULL // work pending, no events yet goto again The producer can be any task that is able to queue task_work for the ring: an io-wq worker, or somebody who sends a message with IORING_OP_MSG_RING. The consumer spins, holding ->uring_lock, until the scheduler takes pity on the fair class, which takes about a second with the default settings of the fair server, and forever without it. The loops in tctx_task_work_run() and io_cancel_local_task_work() have the same problem. Don't allow preemption between the two steps. That bounds the time the window is open on the CPU of the producer by what interrupts take, and a consumer that waits for that is on another CPU. The cost is a preempt_disable()/preempt_enable() pair per push. Fixes: 50cb44bd0d5f ("io_uring/mpscq: add lockless multi-producer, single-consumer FIFO queue") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-9-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
42 hoursio_uring/cancel: rearm local work wake up before sleepJosef Bacik
io_uring_try_cancel_requests() sets ->cq_wait_nr to 1 so that the next io_req_local_work_add() wakes the cancelling task. The add that takes the count to zero is the only one that wakes, later ones see a count <= 0 and return. io_uring_cancel_generic() however only becomes TASK_INTERRUPTIBLE much later, so the one wake up can be spent on a running task. That is fine as long as the entry of that add is still queued, as the io_local_work_pending() check then skips the sleep. It is not if the add was delayed after queueing its entry: CPU0 (submitter in exec or exit) CPU1 (io_req_local_work_add) mpscq_push(req A) io_uring_try_cancel_requests() io_run_local_work() // runs req A io_uring_try_cancel_requests() atomic_set(&ctx->cq_wait_nr, 1) atomic_read(&ctx->cq_wait_nr) == 1 count taken, wake_up_state() // task is running, no-op prepare_to_wait(TASK_INTERRUPTIBLE) io_local_work_pending() == false schedule() mpscq_push(req B) cq_wait_nr <= 0, return Only the sleeping task can run req B, so it is stuck in execve() until a signal happens to wake it. An exiting task doesn't even get that. Arm the count again once the task state is set and before the work list is checked, for the rings whose local work this task is the one to run. Fixes: d46ab2c98aba ("io_uring: switch local task_work to a mpscq") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-8-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
42 hoursio_uring: don't lose the DEFER_TASKRUN wake upJosef Bacik
Since local task_work moved to the mpscq, ->cq_wait_nr is a credit: the add that counts it down to zero, or exchanges it for IO_CQ_WAKE_INIT, issues the only wake up of the wait cycle, and every later add returns early as the count is <= 0. An add looks at the count after it has queued its entry, so an add that gets delayed in between can take the credit of a later cycle. That was assumed to cause an early wake up at worst, but the waiter publishes the count before it changes its task state: CPU0 (submitter, io_cqring_wait) CPU1 (io_req_local_work_add) mpscq_push(req A) io_run_local_work() // runs req A atomic_set(&ctx->cq_wait_nr, 1) atomic_read(&ctx->cq_wait_nr) == 1 atomic_xchg(.., IO_CQ_WAKE_INIT) wake_up_state(.., TASK_INTERRUPTIBLE) // still TASK_RUNNING, no-op set_current_state(TASK_INTERRUPTIBLE) io_local_work_pending() == false schedule() mpscq_push(req B) cq_wait_nr <= 0, return The task now sleeps with req B queued, until a signal or a timeout ends the wait. Set the task state first and only then make the count visible, so that whoever takes the credit finds a task it can wake. The full barrier that orders the count against the check of the work list is kept. Do the same for the wait of the BPF driven loop, which copied the sequence. Fixes: d46ab2c98aba ("io_uring: switch local task_work to a mpscq") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-7-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
42 hoursio_uring: don't flood a cancelling task with task_workJosef Bacik
io_ring_exit_work() asks each task which has used the ring to remove its tctx node, by task_work, and repeats that until the list is empty. io_tctx_exit_cb() doesn't touch the node while the task is in io_uring_cancel_generic(), which removes all the nodes at its end. So the work item queues the callback again as soon as it has completed, for nothing. That is more than a waste of time. task_work_run() only returns when it finds the list empty. If the rings are released from inside the cancellation, because requests of other rings held the last references to their files, up to 64 work items keep sending callbacks to the one task which is running them. It never finds the list empty, never gets back to the cancellation, the nodes stay, and so it goes on: a task with 60 pairs of rings which poll each other ran 280000 callbacks in 5 seconds, 20 seconds after exit_group(). It ends when all the senders happen to be late at the same time. Until then the task keeps a CPU and the work items busy. An exiting task can't be killed meanwhile. execve() cancels the requests in the same way, so a live task can get stuck there as well, for minutes. If it takes more than five, the work items run into the WARN_ON_ONCE(time_after(jiffies, timeout)) of io_ring_exit_work(). No privilege is needed for any of this. If the callback has met a task in cancellation, wait a little before it is sent again. Nobody has to wake the work item up for that: either the node is gone by then, or it is the turn of the next round. Fixes: d56d938b4bef ("io_uring: do ctx initiated file note removal") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-6-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
42 hoursio_uring/io-wq: don't hide a link from cancellationsJosef Bacik
A task that exits cancels its tracked requests and waits until they are gone. io_uring_cancel_generic() looks everywhere a request can be, and goes to sleep if it found nothing to cancel. It is woken up each time one of the requests of the task is completed by task work or freed. When io-wq is done with a request that has a link, there is a time in which the next request of the link can't be found: io_worker_handle_work() io_assign_current_work(worker, NULL) io_wq_free_work(work) io_req_find_next() // takes the link off the request io_free_req() // task work for the task io_assign_current_work(worker, linked) io_run_task_work() cond_resched() worker->cur_work = linked It is not pending, it is not the current work of a worker, and it is not yet on the list that it is about to be parked on. If the pass that the exiting task makes because of io_free_req() falls into that time, it finds nothing and the task goes to sleep. The worker then runs the link, which IO_WQ_BIT_EXIT doesn't prevent for bounded work. If that parks the request nothing is completed or freed, and nobody wakes up the task. If it is the process that exits it can't be killed any more either. NOP, IOSQE_ASYNC | IOSQE_IO_LINK FUTEX_WAIT, FUTEX2_PRIVATE exit of the thread, or of the process, up to 63us later With four of these per round 5 to 8 of 10,000 rounds hang (4 CPUs, KVM): io_uring_cancel_generic do_exit Commit f8b632e89a10 ("io_uring: tighten task exit cancellations") is about the same gap, and makes the task look again for whatever happens before io_free_req(). Free the request once the link is the current work of the worker, or pending. Whoever is woken up by that can find the link, until it is parked where cancellations look as well. To do so split io_wq_free_work() in two. Fixes: 768134d4f481 ("io_uring: don't do flush cancel under inflight_lock") Assisted-by: LLM Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://patch.msgid.link/20261015-b4-io-uring-fixes-v1-5-c1556f5d7bf5@toxicpanda.com Signed-off-by: Jens Axboe <axboe@kernel.dk>