* [PATCH v3 1/2] io_uring/io-wq: limit retrying worker initialisation
2024-07-10 17:58 [PATCH v3 0/2] fix task_work interation with freezing Pavel Begunkov
@ 2024-07-10 17:58 ` Pavel Begunkov
2024-07-10 17:58 ` [PATCH v3 2/2] kernel: rerun task_work while freezing in get_signal() Pavel Begunkov
2024-07-11 7:54 ` [PATCH v3 0/2] fix task_work interation with freezing Jens Axboe
2 siblings, 0 replies; 5+ messages in thread
From: Pavel Begunkov @ 2024-07-10 17:58 UTC (permalink / raw)
To: io-uring
Cc: Jens Axboe, asml.silence, Oleg Nesterov, Andrew Morton,
Christian Brauner, Tycho Andersen, Thomas Gleixner, linux-kernel,
Julian Orth, Peter Zijlstra, Tejun Heo
If io-wq worker creation fails, we retry it by queueing up a task_work.
tasK_work is needed because it should be done from the user process
context. The problem is that retries are not limited, and if queueing a
task_work is the reason for the failure, we might get into an infinite
loop.
It doesn't seem to happen now but it would with the following patch
executing task_work in the freezer's loop. For now, arbitrarily limit the
number of attempts to create a worker.
Cc: [email protected]
Fixes: 3146cba99aa28 ("io-wq: make worker creation resilient against signals")
Reported-by: Julian Orth <[email protected]>
Signed-off-by: Pavel Begunkov <[email protected]>
---
io_uring/io-wq.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/io_uring/io-wq.c b/io_uring/io-wq.c
index 913c92249522..f1e7c670add8 100644
--- a/io_uring/io-wq.c
+++ b/io_uring/io-wq.c
@@ -23,6 +23,7 @@
#include "io_uring.h"
#define WORKER_IDLE_TIMEOUT (5 * HZ)
+#define WORKER_INIT_LIMIT 3
enum {
IO_WORKER_F_UP = 0, /* up and active */
@@ -58,6 +59,7 @@ struct io_worker {
unsigned long create_state;
struct callback_head create_work;
+ int init_retries;
union {
struct rcu_head rcu;
@@ -745,7 +747,7 @@ static bool io_wq_work_match_all(struct io_wq_work *work, void *data)
return true;
}
-static inline bool io_should_retry_thread(long err)
+static inline bool io_should_retry_thread(struct io_worker *worker, long err)
{
/*
* Prevent perpetual task_work retry, if the task (or its group) is
@@ -753,6 +755,8 @@ static inline bool io_should_retry_thread(long err)
*/
if (fatal_signal_pending(current))
return false;
+ if (worker->init_retries++ >= WORKER_INIT_LIMIT)
+ return false;
switch (err) {
case -EAGAIN:
@@ -779,7 +783,7 @@ static void create_worker_cont(struct callback_head *cb)
io_init_new_worker(wq, worker, tsk);
io_worker_release(worker);
return;
- } else if (!io_should_retry_thread(PTR_ERR(tsk))) {
+ } else if (!io_should_retry_thread(worker, PTR_ERR(tsk))) {
struct io_wq_acct *acct = io_wq_get_acct(worker);
atomic_dec(&acct->nr_running);
@@ -846,7 +850,7 @@ static bool create_io_worker(struct io_wq *wq, int index)
tsk = create_io_thread(io_wq_worker, worker, NUMA_NO_NODE);
if (!IS_ERR(tsk)) {
io_init_new_worker(wq, worker, tsk);
- } else if (!io_should_retry_thread(PTR_ERR(tsk))) {
+ } else if (!io_should_retry_thread(worker, PTR_ERR(tsk))) {
kfree(worker);
goto fail;
} else {
--
2.44.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v3 2/2] kernel: rerun task_work while freezing in get_signal()
2024-07-10 17:58 [PATCH v3 0/2] fix task_work interation with freezing Pavel Begunkov
2024-07-10 17:58 ` [PATCH v3 1/2] io_uring/io-wq: limit retrying worker initialisation Pavel Begunkov
@ 2024-07-10 17:58 ` Pavel Begunkov
2024-07-10 19:18 ` Oleg Nesterov
2024-07-11 7:54 ` [PATCH v3 0/2] fix task_work interation with freezing Jens Axboe
2 siblings, 1 reply; 5+ messages in thread
From: Pavel Begunkov @ 2024-07-10 17:58 UTC (permalink / raw)
To: io-uring
Cc: Jens Axboe, asml.silence, Oleg Nesterov, Andrew Morton,
Christian Brauner, Tycho Andersen, Thomas Gleixner, linux-kernel,
Julian Orth, Peter Zijlstra, Tejun Heo
io_uring can asynchronously add a task_work while the task is getting
freezed. TIF_NOTIFY_SIGNAL will prevent the task from sleeping in
do_freezer_trap(), and since the get_signal()'s relock loop doesn't
retry task_work, the task will spin there not being able to sleep
until the freezing is cancelled / the task is killed / etc.
Run task_works in the freezer path. Keep the patch small and simple
so it can be easily back ported, but we might need to do some cleaning
after and look if there are other places with similar problems.
Cc: [email protected]
Link: https://github.com/systemd/systemd/issues/33626
Fixes: 12db8b690010c ("entry: Add support for TIF_NOTIFY_SIGNAL")
Reported-by: Julian Orth <[email protected]>
Acked-by: Oleg Nesterov <[email protected]>
Acked-by: Tejun Heo <[email protected]>
Signed-off-by: Pavel Begunkov <[email protected]>
---
kernel/signal.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/kernel/signal.c b/kernel/signal.c
index 1f9dd41c04be..60c737e423a1 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -2600,6 +2600,14 @@ static void do_freezer_trap(void)
spin_unlock_irq(¤t->sighand->siglock);
cgroup_enter_frozen();
schedule();
+
+ /*
+ * We could've been woken by task_work, run it to clear
+ * TIF_NOTIFY_SIGNAL. The caller will retry if necessary.
+ */
+ clear_notify_signal();
+ if (unlikely(task_work_pending(current)))
+ task_work_run();
}
static int ptrace_signal(int signr, kernel_siginfo_t *info, enum pid_type type)
--
2.44.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v3 0/2] fix task_work interation with freezing
2024-07-10 17:58 [PATCH v3 0/2] fix task_work interation with freezing Pavel Begunkov
2024-07-10 17:58 ` [PATCH v3 1/2] io_uring/io-wq: limit retrying worker initialisation Pavel Begunkov
2024-07-10 17:58 ` [PATCH v3 2/2] kernel: rerun task_work while freezing in get_signal() Pavel Begunkov
@ 2024-07-11 7:54 ` Jens Axboe
2 siblings, 0 replies; 5+ messages in thread
From: Jens Axboe @ 2024-07-11 7:54 UTC (permalink / raw)
To: io-uring, Pavel Begunkov
Cc: Oleg Nesterov, Andrew Morton, Christian Brauner, Tycho Andersen,
Thomas Gleixner, linux-kernel, Julian Orth, Peter Zijlstra,
Tejun Heo
On Wed, 10 Jul 2024 18:58:16 +0100, Pavel Begunkov wrote:
> It's reported [1] that a task_work queued at a wrong time can prevent
> freezing and make the tasks to spin in get_signal() taking 100%
> of CPU. Patch 1 is a preparation. Patch 2 addresses the issue.
>
> [1] https://github.com/systemd/systemd/issues/33626
>
> v3: Slightly adjust commit messages
> v2: Move task_work_run() into do_freezer_trap()
> Correct the Fixes tag is 2/2
>
> [...]
Applied, thanks!
[1/2] io_uring/io-wq: limit retrying worker initialisation
commit: 0453aad676ff99787124b9b3af4a5f59fbe808e2
[2/2] kernel: rerun task_work while freezing in get_signal()
commit: 943ad0b62e3c21f324c4884caa6cb4a871bca05c
Best regards,
--
Jens Axboe
^ permalink raw reply [flat|nested] 5+ messages in thread