From: Jens Axboe <axboe@kernel.dk>
To: io-uring@vger.kernel.org
Cc: juanlu@fastmail.com, Jens Axboe <axboe@kernel.dk>
Subject: [PATCH 6/7] io_uring: wait for in-flight requests on ring release
Date: Wed, 9 Sep 2026 08:06:16 -0600 [thread overview]
Message-ID: <20260909141010.21064-7-axboe@kernel.dk> (raw)
In-Reply-To: <20260909141010.21064-1-axboe@kernel.dk>
With cancelations now run at release time, what's left in-flight on
the ring afterwards is mostly I/O that has already been issued to a
device and just needs to finish. Until that happens, the files from
those requests pin the files they were using. Wait for those.
Signed-off-by: Jens Axboe <axboe@kernel.dk>
---
io_uring/io_uring.c | 74 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 73 insertions(+), 1 deletion(-)
diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c
index 0acdece3c196..32adb2d26d17 100644
--- a/io_uring/io_uring.c
+++ b/io_uring/io_uring.c
@@ -2343,6 +2343,76 @@ static __cold void io_ring_ctx_cancel(struct io_ring_ctx *ctx)
io_req_caches_free(ctx);
}
+/* Number of requests that should be waited for */
+static __cold unsigned int io_ring_ctx_inflight(struct io_ring_ctx *ctx)
+{
+ guard(mutex)(&ctx->uring_lock);
+ __io_req_caches_free(ctx);
+ return ctx->nr_req_allocated - ctx->nr_notifs;
+}
+
+/*
+ * Run task_work completions for current. Only do so if the io_uring callback
+ * itself can get pruned first, otherwise we risk recursing.
+ */
+static __cold bool io_ring_run_own_completions(struct io_uring_task *tctx)
+{
+ unsigned int count = 0;
+
+ if (!tctx || mpscq_empty(&tctx->task_list))
+ return true;
+ if (!task_work_cancel(current, &tctx->task_work))
+ return false;
+ tctx_task_work_run(tctx, UINT_MAX, &count);
+ return true;
+}
+
+/*
+ * Requests may remain after cancelations have been run, as not all requests
+ * are cancelable. Storage I/O is an example. Wait for those so that once
+ * close(2) returns, files pinned by these requests have been released.
+ */
+static __cold void io_ring_ctx_wait_inflight(struct io_ring_ctx *ctx)
+{
+ struct io_uring_task *tctx = current->io_uring;
+ bool ran_own = true;
+
+ if (current->flags & (PF_KTHREAD | PF_EXITING))
+ return;
+ if (tctx && atomic_read(&tctx->in_cancel))
+ return;
+
+ while (io_ring_ctx_inflight(ctx) && !fatal_signal_pending(current)) {
+ unsigned int state;
+
+ if (test_thread_flag(TIF_NOTIFY_SIGNAL)) {
+ clear_notify_signal();
+ if (task_work_pending(current))
+ set_notify_resume(current);
+ }
+ state = TASK_INTERRUPTIBLE;
+ if (signal_pending(current))
+ state = TASK_KILLABLE;
+ set_current_state(state | TASK_FREEZABLE);
+ /* don't sleep on work that's already there and that we can run */
+ if (ran_own && ((tctx && !mpscq_empty(&tctx->task_list)) ||
+ io_local_work_pending(ctx)))
+ __set_current_state(TASK_RUNNING);
+ else
+ schedule_timeout(1);
+
+ /* completions may be queued behind us */
+ if (!io_ring_run_own_completions(tctx)) {
+ if (!ran_own)
+ break;
+ ran_own = false;
+ } else {
+ ran_own = true;
+ }
+ io_ring_ctx_cancel(ctx);
+ }
+}
+
static __cold void io_ring_exit_work(struct work_struct *work)
{
struct io_ring_ctx *ctx = container_of(work, struct io_ring_ctx, exit_work);
@@ -2433,8 +2503,10 @@ static __cold void io_ring_ctx_wait_and_kill(struct io_ring_ctx *ctx)
* out, and for requests owned by the task closing the ring, this
* ensures any held files are put before close(2) returns.
*/
- if (!(current->flags & PF_IO_WORKER))
+ if (!(current->flags & PF_IO_WORKER)) {
io_ring_ctx_cancel(ctx);
+ io_ring_ctx_wait_inflight(ctx);
+ }
INIT_WORK(&ctx->exit_work, io_ring_exit_work);
/*
--
2.55.0
next prev parent reply other threads:[~2026-09-09 14:10 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-09 14:06 [PATCHSET] Cancel requests at ring close time Jens Axboe
2026-09-09 14:06 ` [PATCH 1/7] io_uring/uring_cmd: only cancel requests of the given task Jens Axboe
2026-09-09 14:06 ` [PATCH 2/7] io_uring/notif: count pending zerocopy notifications per ring Jens Axboe
2026-09-09 14:06 ` [PATCH 3/7] io_uring/cancel: cancel and wait for all requests on process exit Jens Axboe
2026-09-09 14:06 ` [PATCH 4/7] io_uring: run cancelations synchronously on ring release Jens Axboe
2026-09-09 14:06 ` [PATCH 5/7] io_uring: drop registered files and buffers at release time Jens Axboe
2026-09-09 14:06 ` Jens Axboe [this message]
2026-09-09 14:06 ` [PATCH 7/7] io_uring/io-wq: put the request file before posting a completion Jens Axboe
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260909141010.21064-7-axboe@kernel.dk \
--to=axboe@kernel.dk \
--cc=io-uring@vger.kernel.org \
--cc=juanlu@fastmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.