ptrace: relocate set_current_state(TASK_TRACED) in ptrace_stop()
authorTejun Heo <tj@kernel.org>
Thu, 2 Jun 2011 09:13:59 +0000 (11:13 +0200)
committerOleg Nesterov <oleg@redhat.com>
Sat, 4 Jun 2011 16:17:10 +0000 (18:17 +0200)
In ptrace_stop(), after arch hook is done, the task state and jobctl
bits are updated while holding siglock.  The ordering requirement
there is that TASK_TRACED is set before JOBCTL_TRAPPING is cleared to
prevent ptracer waiting on TRAPPING doesn't end up waking up TRACED is
actually set and sees TASK_RUNNING in wait(2).

Move set_current_state(TASK_TRACED) to the top of the block and
reorganize comments.  This makes the ordering more obvious
(TASK_TRACED before other updates) and helps future updates to group
stop participation.

This patch doesn't cause any functional change.

Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
kernel/signal.c

index ab6851c06461fbd79154639da76ece41273a760d..62a6c3bb9f0d9a839ce8efa4540e9069d0134fa4 100644 (file)
@@ -1732,6 +1732,18 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info)
                        return;
        }
 
+       /*
+        * We're committing to trapping.  TRACED should be visible before
+        * TRAPPING is cleared; otherwise, the tracer might fail do_wait().
+        * Also, transition to TRACED and updates to ->jobctl should be
+        * atomic with respect to siglock and should be done after the arch
+        * hook as siglock is released and regrabbed across it.
+        */
+       set_current_state(TASK_TRACED);
+
+       current->last_siginfo = info;
+       current->exit_code = exit_code;
+
        /*
         * If @why is CLD_STOPPED, we're trapping to participate in a group
         * stop.  Do the bookkeeping.  Note that if SIGCONT was delievered
@@ -1742,21 +1754,7 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info)
        if (why == CLD_STOPPED && (current->jobctl & JOBCTL_STOP_PENDING))
                gstop_done = task_participate_group_stop(current);
 
-       current->last_siginfo = info;
-       current->exit_code = exit_code;
-
-       /*
-        * TRACED should be visible before TRAPPING is cleared; otherwise,
-        * the tracer might fail do_wait().
-        */
-       set_current_state(TASK_TRACED);
-
-       /*
-        * We're committing to trapping.  Clearing JOBCTL_TRAPPING and
-        * transition to TASK_TRACED should be atomic with respect to
-        * siglock.  This should be done after the arch hook as siglock is
-        * released and regrabbed across it.
-        */
+       /* entering a trap, clear TRAPPING */
        task_clear_jobctl_trapping(current);
 
        spin_unlock_irq(&current->sighand->siglock);