diff options
author | Roland McGrath <roland@redhat.com> | 2008-03-24 21:36:23 -0400 |
---|---|---|
committer | Roland McGrath <roland@redhat.com> | 2008-07-16 21:02:33 -0400 |
commit | f470021adb9190819c03d6d8c5c860a17480aa6d (patch) | |
tree | 9e5c2808138624e272b562a502cfd035ae59c268 /kernel/ptrace.c | |
parent | 98abed02007b19bbfd68b6d06a5485afc3eeb01b (diff) |
ptrace children revamp
ptrace no longer fiddles with the children/sibling links, and the
old ptrace_children list is gone. Now ptrace, whether of one's own
children or another's via PTRACE_ATTACH, just uses the new ptraced
list instead.
There should be no user-visible difference that matters. The only
change is the order in which do_wait() sees multiple stopped
children and stopped ptrace attachees. Since wait_task_stopped()
was changed earlier so it no longer reorders the children list, we
already know this won't cause any new problems.
Signed-off-by: Roland McGrath <roland@redhat.com>
Diffstat (limited to 'kernel/ptrace.c')
-rw-r--r-- | kernel/ptrace.c | 37 |
1 files changed, 24 insertions, 13 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index e337390fce01..8392a9da6450 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
@@ -33,13 +33,9 @@ | |||
33 | */ | 33 | */ |
34 | void __ptrace_link(struct task_struct *child, struct task_struct *new_parent) | 34 | void __ptrace_link(struct task_struct *child, struct task_struct *new_parent) |
35 | { | 35 | { |
36 | BUG_ON(!list_empty(&child->ptrace_list)); | 36 | BUG_ON(!list_empty(&child->ptrace_entry)); |
37 | if (child->parent == new_parent) | 37 | list_add(&child->ptrace_entry, &new_parent->ptraced); |
38 | return; | ||
39 | list_add(&child->ptrace_list, &child->parent->ptrace_children); | ||
40 | remove_parent(child); | ||
41 | child->parent = new_parent; | 38 | child->parent = new_parent; |
42 | add_parent(child); | ||
43 | } | 39 | } |
44 | 40 | ||
45 | /* | 41 | /* |
@@ -73,12 +69,8 @@ void __ptrace_unlink(struct task_struct *child) | |||
73 | BUG_ON(!child->ptrace); | 69 | BUG_ON(!child->ptrace); |
74 | 70 | ||
75 | child->ptrace = 0; | 71 | child->ptrace = 0; |
76 | if (ptrace_reparented(child)) { | 72 | child->parent = child->real_parent; |
77 | list_del_init(&child->ptrace_list); | 73 | list_del_init(&child->ptrace_entry); |
78 | remove_parent(child); | ||
79 | child->parent = child->real_parent; | ||
80 | add_parent(child); | ||
81 | } | ||
82 | 74 | ||
83 | if (task_is_traced(child)) | 75 | if (task_is_traced(child)) |
84 | ptrace_untrace(child); | 76 | ptrace_untrace(child); |
@@ -492,15 +484,34 @@ int ptrace_traceme(void) | |||
492 | /* | 484 | /* |
493 | * Are we already being traced? | 485 | * Are we already being traced? |
494 | */ | 486 | */ |
487 | repeat: | ||
495 | task_lock(current); | 488 | task_lock(current); |
496 | if (!(current->ptrace & PT_PTRACED)) { | 489 | if (!(current->ptrace & PT_PTRACED)) { |
490 | /* | ||
491 | * See ptrace_attach() comments about the locking here. | ||
492 | */ | ||
493 | unsigned long flags; | ||
494 | if (!write_trylock_irqsave(&tasklist_lock, flags)) { | ||
495 | task_unlock(current); | ||
496 | do { | ||
497 | cpu_relax(); | ||
498 | } while (!write_can_lock(&tasklist_lock)); | ||
499 | goto repeat; | ||
500 | } | ||
501 | |||
497 | ret = security_ptrace(current->parent, current, | 502 | ret = security_ptrace(current->parent, current, |
498 | PTRACE_MODE_ATTACH); | 503 | PTRACE_MODE_ATTACH); |
504 | |||
499 | /* | 505 | /* |
500 | * Set the ptrace bit in the process ptrace flags. | 506 | * Set the ptrace bit in the process ptrace flags. |
507 | * Then link us on our parent's ptraced list. | ||
501 | */ | 508 | */ |
502 | if (!ret) | 509 | if (!ret) { |
503 | current->ptrace |= PT_PTRACED; | 510 | current->ptrace |= PT_PTRACED; |
511 | __ptrace_link(current, current->real_parent); | ||
512 | } | ||
513 | |||
514 | write_unlock_irqrestore(&tasklist_lock, flags); | ||
504 | } | 515 | } |
505 | task_unlock(current); | 516 | task_unlock(current); |
506 | return ret; | 517 | return ret; |