[PATCH 13] exit_ptrace: use ptrace_do_detach()
Oleg Nesterov
oleg at redhat.com
Sat Aug 22 18:58:38 UTC 2009
Change exit_ptrace() to use ptrace_do_detach() and kill now unused
ptrace_utrace_exit().
This means we can't iterate over ->ptraced (the current code does this
twice) under tasklist, change the code to pick tracees by one and do
get/put on task_struct.
With this patch, exit_ptrace() does ptrace_unlink() then UTRACE_DETACH.
But currently this is not exactly correct too. Unlike ptrace_detach(),
exit_ptrace() can be called when the tracee is running, if it calls
utrace_stop() before UTRACE_DETACH we will notify ->real_parent.
Hopefully this will be fixed when we change the ptrace-related kludge
in utrace_stop().
---
kernel/ptrace.c | 40 +++++++++++++++-------------------------
1 file changed, 15 insertions(+), 25 deletions(-)
--- PU/kernel/ptrace.c~13_REWORK_EXIT_PTRACE 2009-08-22 20:08:23.000000000 +0200
+++ PU/kernel/ptrace.c 2009-08-22 20:31:26.000000000 +0200
@@ -751,7 +751,8 @@ static void ptrace_do_detach(struct task
*/
traced = tracee->ptrace;
if (likely(traced)) {
- tracee->exit_code = data;
+ if (valid_signal(data))
+ tracee->exit_code = data;
dead = __ptrace_detach(current, tracee);
}
write_unlock_irq(&tasklist_lock);
@@ -776,37 +777,26 @@ int ptrace_detach(struct task_struct *ch
return 0;
}
-static void ptrace_utrace_exit(struct task_struct *task)
-{
- struct task_struct *child;
- read_lock(&tasklist_lock);
- list_for_each_entry(child, &task->ptraced, ptrace_entry)
- ptrace_detach_task(child, 0);
- read_unlock(&tasklist_lock);
-}
-
/*
* Detach all tasks we were using ptrace on.
*/
void exit_ptrace(struct task_struct *tracer)
{
- struct task_struct *p, *n;
- LIST_HEAD(ptrace_dead);
-
- ptrace_utrace_exit(tracer);
-
- write_lock_irq(&tasklist_lock);
- list_for_each_entry_safe(p, n, &tracer->ptraced, ptrace_entry) {
- if (__ptrace_detach(tracer, p))
- list_add(&p->ptrace_entry, &ptrace_dead);
- }
- write_unlock_irq(&tasklist_lock);
+ for (;;) {
+ struct task_struct *tracee = NULL;
- BUG_ON(!list_empty(&tracer->ptraced));
+ read_lock(&tasklist_lock);
+ if (!list_empty(&tracer->ptraced)) {
+ tracee = list_first_entry(&tracer->ptraced,
+ struct task_struct, ptrace_entry);
+ get_task_struct(tracee);
+ }
+ read_unlock(&tasklist_lock);
+ if (!tracee)
+ break;
- list_for_each_entry_safe(p, n, &ptrace_dead, ptrace_entry) {
- list_del_init(&p->ptrace_entry);
- release_task(p);
+ ptrace_do_detach(tracee, -1);
+ put_task_struct(tracee);
}
}
More information about the utrace-devel
mailing list