]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.18-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 12 Feb 2026 13:00:07 +0000 (14:00 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 12 Feb 2026 13:00:07 +0000 (14:00 +0100)
added patches:
io_uring-allow-io-wq-workers-to-exit-when-unused.patch
io_uring-io-wq-add-exit-on-idle-state.patch
series

queue-6.18/io_uring-allow-io-wq-workers-to-exit-when-unused.patch [new file with mode: 0644]
queue-6.18/io_uring-io-wq-add-exit-on-idle-state.patch [new file with mode: 0644]
queue-6.18/series [new file with mode: 0644]

diff --git a/queue-6.18/io_uring-allow-io-wq-workers-to-exit-when-unused.patch b/queue-6.18/io_uring-allow-io-wq-workers-to-exit-when-unused.patch
new file mode 100644 (file)
index 0000000..412154f
--- /dev/null
@@ -0,0 +1,54 @@
+From 91214661489467f8452d34edbf257488d85176e4 Mon Sep 17 00:00:00 2001
+From: Li Chen <me@linux.beauty>
+Date: Mon, 2 Feb 2026 22:37:54 +0800
+Subject: io_uring: allow io-wq workers to exit when unused
+
+From: Li Chen <me@linux.beauty>
+
+commit 91214661489467f8452d34edbf257488d85176e4 upstream.
+
+io_uring keeps a per-task io-wq around, even when the task no longer has
+any io_uring instances.
+
+If the task previously used io_uring for file I/O, this can leave an
+unrelated iou-wrk-* worker thread behind after the last io_uring
+instance is gone.
+
+When the last io_uring ctx is removed from the task context, mark the
+io-wq exit-on-idle so workers can go away. Clear the flag on subsequent
+io_uring usage.
+
+Signed-off-by: Li Chen <me@linux.beauty>
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ io_uring/tctx.c |   11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+--- a/io_uring/tctx.c
++++ b/io_uring/tctx.c
+@@ -122,6 +122,14 @@ int __io_uring_add_tctx_node(struct io_r
+                               return ret;
+               }
+       }
++
++      /*
++       * Re-activate io-wq keepalive on any new io_uring usage. The wq may have
++       * been marked for idle-exit when the task temporarily had no active
++       * io_uring instances.
++       */
++      if (tctx->io_wq)
++              io_wq_set_exit_on_idle(tctx->io_wq, false);
+       if (!xa_load(&tctx->xa, (unsigned long)ctx)) {
+               node = kmalloc(sizeof(*node), GFP_KERNEL);
+               if (!node)
+@@ -183,6 +191,9 @@ __cold void io_uring_del_tctx_node(unsig
+       if (tctx->last == node->ctx)
+               tctx->last = NULL;
+       kfree(node);
++
++      if (xa_empty(&tctx->xa) && tctx->io_wq)
++              io_wq_set_exit_on_idle(tctx->io_wq, true);
+ }
+ __cold void io_uring_clean_tctx(struct io_uring_task *tctx)
diff --git a/queue-6.18/io_uring-io-wq-add-exit-on-idle-state.patch b/queue-6.18/io_uring-io-wq-add-exit-on-idle-state.patch
new file mode 100644 (file)
index 0000000..0581b14
--- /dev/null
@@ -0,0 +1,89 @@
+From 38aa434ab9335ce2d178b7538cdf01d60b2014c3 Mon Sep 17 00:00:00 2001
+From: Li Chen <me@linux.beauty>
+Date: Mon, 2 Feb 2026 22:37:53 +0800
+Subject: io_uring/io-wq: add exit-on-idle state
+
+From: Li Chen <me@linux.beauty>
+
+commit 38aa434ab9335ce2d178b7538cdf01d60b2014c3 upstream.
+
+io-wq uses an idle timeout to shrink the pool, but keeps the last worker
+around indefinitely to avoid churn.
+
+For tasks that used io_uring for file I/O and then stop using io_uring,
+this can leave an iou-wrk-* thread behind even after all io_uring
+instances are gone. This is unnecessary overhead and also gets in the
+way of process checkpoint/restore.
+
+Add an exit-on-idle state that makes all io-wq workers exit as soon as
+they become idle, and provide io_wq_set_exit_on_idle() to toggle it.
+
+Signed-off-by: Li Chen <me@linux.beauty>
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ io_uring/io-wq.c |   27 +++++++++++++++++++++++++--
+ io_uring/io-wq.h |    1 +
+ 2 files changed, 26 insertions(+), 2 deletions(-)
+
+--- a/io_uring/io-wq.c
++++ b/io_uring/io-wq.c
+@@ -34,6 +34,7 @@ enum {
+ enum {
+       IO_WQ_BIT_EXIT          = 0,    /* wq exiting */
++      IO_WQ_BIT_EXIT_ON_IDLE  = 1,    /* allow all workers to exit on idle */
+ };
+ enum {
+@@ -706,9 +707,13 @@ static int io_wq_worker(void *data)
+               raw_spin_lock(&acct->workers_lock);
+               /*
+                * Last sleep timed out. Exit if we're not the last worker,
+-               * or if someone modified our affinity.
++               * or if someone modified our affinity. If wq is marked
++               * idle-exit, drop the worker as well. This is used to avoid
++               * keeping io-wq workers around for tasks that no longer have
++               * any active io_uring instances.
+                */
+-              if (last_timeout && (exit_mask || acct->nr_workers > 1)) {
++              if ((last_timeout && (exit_mask || acct->nr_workers > 1)) ||
++                  test_bit(IO_WQ_BIT_EXIT_ON_IDLE, &wq->state)) {
+                       acct->nr_workers--;
+                       raw_spin_unlock(&acct->workers_lock);
+                       __set_current_state(TASK_RUNNING);
+@@ -965,6 +970,24 @@ static bool io_wq_worker_wake(struct io_
+       return false;
+ }
++void io_wq_set_exit_on_idle(struct io_wq *wq, bool enable)
++{
++      if (!wq->task)
++              return;
++
++      if (!enable) {
++              clear_bit(IO_WQ_BIT_EXIT_ON_IDLE, &wq->state);
++              return;
++      }
++
++      if (test_and_set_bit(IO_WQ_BIT_EXIT_ON_IDLE, &wq->state))
++              return;
++
++      rcu_read_lock();
++      io_wq_for_each_worker(wq, io_wq_worker_wake, NULL);
++      rcu_read_unlock();
++}
++
+ static void io_run_cancel(struct io_wq_work *work, struct io_wq *wq)
+ {
+       do {
+--- a/io_uring/io-wq.h
++++ b/io_uring/io-wq.h
+@@ -41,6 +41,7 @@ struct io_wq_data {
+ struct io_wq *io_wq_create(unsigned bounded, struct io_wq_data *data);
+ void io_wq_exit_start(struct io_wq *wq);
+ void io_wq_put_and_exit(struct io_wq *wq);
++void io_wq_set_exit_on_idle(struct io_wq *wq, bool enable);
+ void io_wq_enqueue(struct io_wq *wq, struct io_wq_work *work);
+ void io_wq_hash_work(struct io_wq_work *work, void *val);
diff --git a/queue-6.18/series b/queue-6.18/series
new file mode 100644 (file)
index 0000000..440e4a4
--- /dev/null
@@ -0,0 +1,2 @@
+io_uring-io-wq-add-exit-on-idle-state.patch
+io_uring-allow-io-wq-workers-to-exit-when-unused.patch