local_irq_disable();
        rcu_note_context_switch(preempt);
 
-       /* See deactivate_task() below. */
-       prev_state = prev->state;
-
        /*
         * Make sure that signal_pending_state()->signal_pending() below
         * can't be reordered with __set_current_state(TASK_INTERRUPTIBLE)
        update_rq_clock(rq);
 
        switch_count = &prev->nivcsw;
+
        /*
-        * We must re-load prev->state in case ttwu_remote() changed it
-        * before we acquired rq->lock.
+        * We must load prev->state once (task_struct::state is volatile), such
+        * that:
+        *
+        *  - we form a control dependency vs deactivate_task() below.
+        *  - ptrace_{,un}freeze_traced() can change ->state underneath us.
         */
-       if (!preempt && prev_state && prev_state == prev->state) {
+       prev_state = prev->state;
+       if (!preempt && prev_state) {
                if (signal_pending_state(prev_state, prev)) {
                        prev->state = TASK_RUNNING;
                } else {
 
                        /*
                         * __schedule()                 ttwu()
-                        *   prev_state = prev->state;    if (READ_ONCE(p->on_rq) && ...)
-                        *   LOCK rq->lock                  goto out;
-                        *   smp_mb__after_spinlock();    smp_acquire__after_ctrl_dep();
-                        *   p->on_rq = 0;                p->state = TASK_WAKING;
+                        *   prev_state = prev->state;    if (p->on_rq && ...)
+                        *   if (prev_state)                goto out;
+                        *     p->on_rq = 0;              smp_acquire__after_ctrl_dep();
+                        *                                p->state = TASK_WAKING
+                        *
+                        * Where __schedule() and ttwu() have matching control dependencies.
                         *
                         * After this, schedule() must not care about p->state any more.
                         */