The current logic does not work. Remove it. Now detach always does UTRACE_DETACH and attach doesn't try to reuse the old engine.
This means ptrace_detach(sig) can't work correctly. But, before we fix this problem, it is better to make other changes. In particular, it makes sense to move ->last_siginfo and ->exit_code to engine->data. As for ->exit_code, I mean that ptrace.c should not use ->exit_code at all, instead we should have a member in engine->data. --- --- PU/kernel/ptrace.c~05_ALWAYS_DETACH 2009-08-13 17:55:13.000000000 +0200 +++ PU/kernel/ptrace.c 2009-08-13 18:23:43.000000000 +0200 @@ -42,7 +42,6 @@ static const struct utrace_engine_ops pt static void ptrace_detach_task(struct task_struct *child, int sig) { - enum utrace_resume_action action = UTRACE_DETACH; struct utrace_engine *engine; int ret; @@ -51,19 +50,7 @@ static void ptrace_detach_task(struct ta if (unlikely(IS_ERR(engine))) return; - /* - * When leaving a parting signal to deliver, we cannot detach our - * utrace engine yet. We need it there to get a report_signal() - * callback that can inject our parting signal. Instead, we'll - * mark our engine by clearing its data pointer. Our callbacks - * will see this and know it's a PTRACE_DETACH still in progress. - */ - if (sig) { - engine->data = NULL; - action = UTRACE_INTERRUPT; - } - - ret = utrace_control(child, engine, action); + ret = utrace_control(child, engine, UTRACE_DETACH); WARN_ON(ret && ret != -EINPROGRESS && ret != -ESRCH && ret != -EALREADY); @@ -365,19 +352,6 @@ static u32 ptrace_resumed(struct task_st return UTRACE_SIGNAL_REPORT | ptrace_report_vfork_done(task); /* - * If PTRACE_DETACH had a signal for us to deliver, - * it didn't detach the engine, but marked it for us. - */ - if (!engine->data) { - read_lock(&tasklist_lock); - if (task->ptrace & PT_PTRACED) - engine->data = task->parent; - else - resume = UTRACE_DETACH; - read_unlock(&tasklist_lock); - } - - /* * If we're stopping, or we haven't reported any signal, * then we're all done for now. */ @@ -517,43 +491,18 @@ static struct utrace_engine *prepare_ptr struct task_struct *child, struct task_struct *parent) { struct utrace_engine *engine; -restart: + engine = utrace_attach_task(child, UTRACE_ATTACH_CREATE | UTRACE_ATTACH_EXCLUSIVE | UTRACE_ATTACH_MATCH_OPS, &ptrace_utrace_ops, parent); - if (engine == ERR_PTR(-EEXIST)) { - /* - * There is already some ptrace engine attached. Either - * this attach will fail because another ptracer is - * already attached, or else this engine was left behind - * by PTRACE_DETACH to deliver a signal. - */ - engine = utrace_attach_task(child, - UTRACE_ATTACH_MATCH_OPS, - &ptrace_utrace_ops, NULL); - if (IS_ERR(engine)) { - BUG_ON(PTR_ERR(engine) != -ENOENT); - goto restart; - } - if (engine->data) { - utrace_engine_put(engine); - engine = ERR_PTR(-EEXIST); - } - } + if (IS_ERR(engine)) { if (engine != ERR_PTR(-ESRCH) && engine != ERR_PTR(-ERESTARTNOINTR)) engine = ERR_PTR(-EPERM); } else { int ret = ptrace_update_utrace(child, engine); - if (ret == -EINPROGRESS) { - ret = utrace_barrier(child, engine); - utrace_engine_put(engine); - if (ret != -ERESTARTSYS) - goto restart; - return ERR_PTR(-ERESTARTNOINTR); - } if (ret) engine = ERR_PTR(finish_ptrace_attach(child, engine, -ESRCH));