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 <oleg(a)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