io_wq_exit_workers() triggers a WARN_ON_ONCE() if it has waited more than IO_URING_EXIT_WAIT_MAX for the workers to exit. That can be triggered at will, for example with an open on a FUSE mount where the server never replies to the lookup. The worker can't be canceled, and the exit waits until the server goes away. The stack trace from the WARN isn't useful either, as it's that of the exiting task and that is always the task exit, exec, or SQPOLL thread exit path. Print a message and show the workers that are still around instead, that's where the interesting stack traces are. Reported-by: syzbot+b0d54b9e81de55179e47@syzkaller.appspotmail.com Signed-off-by: Jens Axboe --- diff --git a/io_uring/io-wq.c b/io_uring/io-wq.c index 92df54c6f50c..52ba4b06b5af 100644 --- a/io_uring/io-wq.c +++ b/io_uring/io-wq.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -1448,6 +1449,22 @@ static void io_wq_cancel_tw_create(struct io_wq *wq) } } +static bool io_wq_worker_show(struct io_worker *worker, void *data) +{ + sched_show_task(worker->task); + return false; +} + +/* The exit path is always the same, show what the workers are stuck on */ +static void io_wq_show_stuck_workers(struct io_wq *wq) +{ + pr_warn("io-wq: %s/%d stuck waiting for workers to exit\n", + current->comm, task_pid_nr(current)); + rcu_read_lock(); + io_wq_for_each_worker(wq, io_wq_worker_show, NULL); + rcu_read_unlock(); +} + static void io_wq_exit_workers(struct io_wq *wq) { unsigned long timeout, warn_timeout; @@ -1469,8 +1486,8 @@ static void io_wq_exit_workers(struct io_wq *wq) * * where completely overloading the system with tons of long running * io-wq items can easily trigger the hung task timeout. Only sleep - * uninterruptibly for half that time, and warn if we exceeded end - * up waiting more than IO_URING_EXIT_WAIT_MAX. + * uninterruptibly for half that time, and show the stuck workers if + * we end up waiting more than IO_URING_EXIT_WAIT_MAX. */ timeout = sysctl_hung_task_timeout_secs * HZ / 2; if (!timeout) @@ -1479,7 +1496,8 @@ static void io_wq_exit_workers(struct io_wq *wq) do { if (wait_for_completion_timeout(&wq->worker_done, timeout)) break; - WARN_ON_ONCE(time_after(jiffies, warn_timeout)); + if (time_after(jiffies, warn_timeout)) + DO_ONCE_LITE(io_wq_show_stuck_workers, wq); } while (1); spin_lock_irq(&wq->hash->wait.lock); -- Jens Axboe