| From: Chen Yu <yu.c.chen@intel.com> |
| Subject: kthread: fix task state in kthread worker if being frozen |
| Date: Tue, 27 Aug 2024 19:23:08 +0800 |
| |
| When analyzing a kernel waring message, Peter pointed out that there is a |
| race condition when the kworker is being frozen and falls into |
| try_to_freeze() with TASK_INTERRUPTIBLE, which could trigger a |
| might_sleep() warning in try_to_freeze(). Although the root cause is not |
| related to freeze()[1], it is still worthy to fix this issue ahead. |
| |
| One possible race scenario: |
| |
| CPU 0 CPU 1 |
| ----- ----- |
| |
| // kthread_worker_fn |
| set_current_state(TASK_INTERRUPTIBLE); |
| suspend_freeze_processes() |
| freeze_processes |
| static_branch_inc(&freezer_active); |
| freeze_kernel_threads |
| pm_nosig_freezing = true; |
| if (work) { //false |
| __set_current_state(TASK_RUNNING); |
| |
| } else if (!freezing(current)) //false, been frozen |
| |
| freezing(): |
| if (static_branch_unlikely(&freezer_active)) |
| if (pm_nosig_freezing) |
| return true; |
| schedule() |
| } |
| |
| // state is still TASK_INTERRUPTIBLE |
| try_to_freeze() |
| might_sleep() <--- warning |
| |
| Fix this by explicitly set the TASK_RUNNING before entering |
| try_to_freeze(). |
| |
| Link: https://lore.kernel.org/lkml/Zs2ZoAcUsZMX2B%2FI@chenyu5-mobl2/ [1] |
| Link: https://lkml.kernel.org/r/20240827112308.181081-1-yu.c.chen@intel.com |
| Fixes: b56c0d8937e6 ("kthread: implement kthread_worker") |
| Signed-off-by: Chen Yu <yu.c.chen@intel.com> |
| Suggested-by: Peter Zijlstra <peterz@infradead.org> |
| Suggested-by: Andrew Morton <akpm@linux-foundation.org> |
| Cc: Andreas Gruenbacher <agruenba@redhat.com> |
| Cc: David Gow <davidgow@google.com> |
| Cc: Mateusz Guzik <mjguzik@gmail.com> |
| Cc: Mickaël Salaün <mic@digikod.net> |
| Cc: Tejun Heo <tj@kernel.org> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| --- |
| |
| kernel/kthread.c | 10 +++++++++- |
| 1 file changed, 9 insertions(+), 1 deletion(-) |
| |
| --- a/kernel/kthread.c~kthread-fix-task-state-in-kthread-worker-if-being-frozen |
| +++ a/kernel/kthread.c |
| @@ -845,8 +845,16 @@ repeat: |
| * event only cares about the address. |
| */ |
| trace_sched_kthread_work_execute_end(work, func); |
| - } else if (!freezing(current)) |
| + } else if (!freezing(current)) { |
| schedule(); |
| + } else { |
| + /* |
| + * Handle the case where the current remains |
| + * TASK_INTERRUPTIBLE. try_to_freeze() expects |
| + * the current to be TASK_RUNNING. |
| + */ |
| + __set_current_state(TASK_RUNNING); |
| + } |
| |
| try_to_freeze(); |
| cond_resched(); |
| _ |