Change ptrace_report_clone() to do all attach work itself. Note that this allows to greatly simplify do_fork() path wrt tracehooks. For example we do not need tracehook_prepare_clone() at all. tracehook_finish_clone() does not need tasklist. copy_process() does not need "int traced".
Both ptrace_report_clone() and ptrace_clone_attach() need more work. ptrace_clone_attach() will be changed once we add engine->data. --- include/linux/ptrace.h | 4 --- include/linux/tracehook.h | 8 ------ kernel/ptrace.c | 56 ++++++++++++++++++++++++++++------------------ 3 files changed, 35 insertions(+), 33 deletions(-) --- PU/include/linux/ptrace.h~10_CLONE_ATTACH 2009-08-19 18:05:15.000000000 +0200 +++ PU/include/linux/ptrace.h 2009-08-19 18:05:34.000000000 +0200 @@ -147,10 +147,6 @@ static inline void ptrace_init_task(stru INIT_LIST_HEAD(&child->ptraced); child->parent = child->real_parent; child->ptrace = 0; - if (unlikely(ptrace)) { - child->ptrace = current->ptrace; - ptrace_link(child, current->parent); - } } /** --- PU/include/linux/tracehook.h~10_CLONE_ATTACH 2009-08-13 17:51:52.000000000 +0200 +++ PU/include/linux/tracehook.h 2009-08-19 18:34:37.000000000 +0200 @@ -264,14 +264,6 @@ static inline void tracehook_report_clon { if (unlikely(task_utrace_flags(current) & UTRACE_EVENT(CLONE))) utrace_report_clone(clone_flags, child); - if (unlikely(task_ptrace(child))) { - /* - * It doesn't matter who attached/attaching to this - * task, the pending SIGSTOP is right in any case. - */ - sigaddset(&child->pending.signal, SIGSTOP); - set_tsk_thread_flag(child, TIF_SIGPENDING); - } } /** --- PU/kernel/ptrace.c~10_CLONE_ATTACH 2009-08-19 17:41:18.000000000 +0200 +++ PU/kernel/ptrace.c 2009-08-19 19:12:32.000000000 +0200 @@ -39,6 +39,8 @@ void __ptrace_link(struct task_struct *c } static const struct utrace_engine_ops ptrace_utrace_ops; /* forward decl */ +static int ptrace_attach_task(struct task_struct *tracee); +static void ptrace_abort_attach(struct task_struct *tracee); static void ptrace_detach_task(struct task_struct *child, int sig) { @@ -211,6 +213,37 @@ static u32 ptrace_report_exit(enum utrac return utrace_ptrace_event(task, PTRACE_EVENT_EXIT, *code); } +static void ptrace_clone_attach(struct task_struct *parent, + struct task_struct *child) +{ + struct task_struct *tracer; + bool abort = true; + + if (!parent->ptrace) + return; + if (unlikely(ptrace_attach_task(child))) { + WARN_ON(1); + return; + } + + write_lock_irq(&tasklist_lock); + tracer = parent->parent; + if (!(tracer->flags & PF_EXITING) && parent->ptrace) { + child->ptrace = parent->ptrace; + __ptrace_link(child, tracer); + abort = false; + } + write_unlock_irq(&tasklist_lock); + if (unlikely(abort)) { + ptrace_abort_attach(child); + return; + } + + sigaddset(&child->pending.signal, SIGSTOP); + set_tsk_thread_flag(child, TIF_SIGPENDING); + ptrace_update_utrace(child, NULL); +} + static u32 ptrace_report_clone(enum utrace_resume_action action, struct utrace_engine *engine, struct task_struct *parent, @@ -218,7 +251,6 @@ static u32 ptrace_report_clone(enum utra struct task_struct *child) { int event; - struct utrace_engine *child_engine; if ((clone_flags & CLONE_VFORK) && (parent->ptrace & PT_TRACE_VFORK_DONE)) { @@ -254,26 +286,8 @@ static u32 ptrace_report_clone(enum utra * Any of these reports implies auto-attaching the new child. * So does CLONE_PTRACE, even with no event to report. */ - if (event || (clone_flags & CLONE_PTRACE)) { - child_engine = utrace_attach_task(child, UTRACE_ATTACH_CREATE | - UTRACE_ATTACH_EXCLUSIVE | - UTRACE_ATTACH_MATCH_OPS, - &ptrace_utrace_ops, - NULL); - if (unlikely(IS_ERR(child_engine))) { - WARN_ON(1); /* XXX */ - } else { - BUG_ON(!child->ptrace); - /* XXX already set by old ptrace code - task_lock(child); - child->ptrace = parent->ptrace; - child->parent = parent->parent; - task_unlock(child); - */ - ptrace_update_utrace(child, child_engine); - utrace_engine_put(child_engine); - } - } + if (event || (clone_flags & CLONE_PTRACE)) + ptrace_clone_attach(parent, child); if (event) return utrace_ptrace_event(parent, event, child->pid);