From: Greg Kroah-Hartman Date: Thu, 12 Feb 2026 13:00:20 +0000 (+0100) Subject: 6.19-stable patches X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;ds=sidebyside;p=thirdparty%2Fkernel%2Fstable-queue.git 6.19-stable patches added patches: io_uring-allow-io-wq-workers-to-exit-when-unused.patch io_uring-io-wq-add-exit-on-idle-state.patch series --- diff --git a/queue-6.19/io_uring-allow-io-wq-workers-to-exit-when-unused.patch b/queue-6.19/io_uring-allow-io-wq-workers-to-exit-when-unused.patch new file mode 100644 index 0000000000..412154f617 --- /dev/null +++ b/queue-6.19/io_uring-allow-io-wq-workers-to-exit-when-unused.patch @@ -0,0 +1,54 @@ +From 91214661489467f8452d34edbf257488d85176e4 Mon Sep 17 00:00:00 2001 +From: Li Chen +Date: Mon, 2 Feb 2026 22:37:54 +0800 +Subject: io_uring: allow io-wq workers to exit when unused + +From: Li Chen + +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 +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman +--- + 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.19/io_uring-io-wq-add-exit-on-idle-state.patch b/queue-6.19/io_uring-io-wq-add-exit-on-idle-state.patch new file mode 100644 index 0000000000..d917e25e7e --- /dev/null +++ b/queue-6.19/io_uring-io-wq-add-exit-on-idle-state.patch @@ -0,0 +1,89 @@ +From 38aa434ab9335ce2d178b7538cdf01d60b2014c3 Mon Sep 17 00:00:00 2001 +From: Li Chen +Date: Mon, 2 Feb 2026 22:37:53 +0800 +Subject: io_uring/io-wq: add exit-on-idle state + +From: Li Chen + +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 +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman +--- + 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); +@@ -963,6 +968,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.19/series b/queue-6.19/series new file mode 100644 index 0000000000..440e4a4721 --- /dev/null +++ b/queue-6.19/series @@ -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