Add the new helper, ptrace_signal_wake_up(), change ptrace.c to use it instead of signal_wake_up().
The new helper does almost the same, except: - it doesn't use the TASK_WAKEKILL bit to wake up the TRACED or STOPPED task, it uses __TASK_STOPPED | __TASK_TRACED explicitly. This is what ptrace actually wants, it should never wake up a TASK_KILLABLE task. This should be cleanuped upatream, signal_wake_up() should take the state as an argument, not a boolean. Until then we add a new static helper. - it uses wake_up_quiescent() instead of wake_up_state(). Thereafter every change from STOPPED/TRACED to RUNNING is done via wake_up_quiescent(). Signed-off-by: Oleg Nesterov <o...@redhat.com> --- kernel/ptrace.c | 16 ++++++++++++++-- 1 files changed, 14 insertions(+), 2 deletions(-) diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 26ae214..0b2aba5 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -24,6 +24,18 @@ #include <linux/regset.h> #include <linux/hw_breakpoint.h> +static void ptrace_signal_wake_up(struct task_struct *p, int quiescent) +{ + unsigned int state; + + set_tsk_thread_flag(p, TIF_SIGPENDING); + + state = TASK_INTERRUPTIBLE; + if (quiescent) + state |= (__TASK_STOPPED | __TASK_TRACED); + if (!wake_up_quiescent(p, state)) + kick_process(p); +} /* * ptrace a task: make the debugger its new parent and @@ -92,7 +104,7 @@ void __ptrace_unlink(struct task_struct *child) * TASK_KILLABLE sleeps. */ if (child->group_stop & GROUP_STOP_PENDING || task_is_traced(child)) - signal_wake_up(child, task_is_traced(child)); + ptrace_signal_wake_up(child, task_is_traced(child)); spin_unlock(&child->sighand->siglock); } @@ -245,7 +257,7 @@ static int ptrace_attach(struct task_struct *task) */ if (task_is_stopped(task)) { task->group_stop |= GROUP_STOP_PENDING | GROUP_STOP_TRAPPING; - signal_wake_up(task, 1); + ptrace_signal_wake_up(task, 1); wait_trap = true; } -- 1.5.5.1