kthread: fix task state in kthread worker if being frozen
authorChen Yu <yu.c.chen@intel.com>
Tue, 27 Aug 2024 11:23:08 +0000 (19:23 +0800)
committerAndrew Morton <akpm@linux-foundation.org>
Mon, 2 Sep 2024 03:43:41 +0000 (20:43 -0700)
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/
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

index f7be976ff88af7cc998c125dc844e42c70ea9676..db4ceb0f503cca575efc5a8fc1350aead0efdff6 100644 (file)
@@ -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();