public inbox for [email protected]
 help / color / mirror / Atom feed
* [PATCH v3 0/2] fix task_work interation with freezing
@ 2024-07-10 17:58 Pavel Begunkov
  2024-07-10 17:58 ` [PATCH v3 1/2] io_uring/io-wq: limit retrying worker initialisation Pavel Begunkov
                   ` (2 more replies)
  0 siblings, 3 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

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

Pavel Begunkov (2):
  io_uring/io-wq: limit retrying worker initialisation
  kernel: rerun task_work while freezing in get_signal()

 io_uring/io-wq.c | 10 +++++++---
 kernel/signal.c  |  8 ++++++++
 2 files changed, 15 insertions(+), 3 deletions(-)

-- 
2.44.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [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(&current->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 2/2] kernel: rerun task_work while freezing in get_signal()
  2024-07-10 17:58 ` [PATCH v3 2/2] kernel: rerun task_work while freezing in get_signal() Pavel Begunkov
@ 2024-07-10 19:18   ` Oleg Nesterov
  0 siblings, 0 replies; 5+ messages in thread
From: Oleg Nesterov @ 2024-07-10 19:18 UTC (permalink / raw)
  To: Pavel Begunkov
  Cc: io-uring, Jens Axboe, Andrew Morton, Christian Brauner,
	Tycho Andersen, Thomas Gleixner, linux-kernel, Julian Orth,
	Peter Zijlstra, Tejun Heo

I have already acked this patch, so I am sorry for the noise, but

On 07/10, Pavel Begunkov wrote:
>
> Run task_works in the freezer path. Keep the patch small and simple
> so it can be easily back ported,

Agreed.

I tried to argue with v1 which added the additional task_work_run()
into get_signal(), but I failed to suggest a "better" change which
doesn't uglify/complicate get_signal/backporting.

Oleg.


^ permalink raw reply	[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

end of thread, other threads:[~2024-07-11  7:54 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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-10 19:18   ` Oleg Nesterov
2024-07-11  7:54 ` [PATCH v3 0/2] fix task_work interation with freezing Jens Axboe

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox