Introduce PTRACE_O_DETACHED to mark the almost-detached engine as
reusable for ptrace_reuse_engine().

Currently ptrace_reuse_engine() just checks ctx->resume == UTRACE_DETACH,
but we are going to change ptrace_detach_task() to play with the tracee
after setting ctx->resume == UTRACE_DETACH and thus we need another method
to indicate that this engine is going to detach itself.

Note that we set PTRACE_O_DETACHED after ptrace_wake_up()->utrace_control()
and the possible new tracer does utrace_set_events() before it changes
ctx->resume. This means that we do not need the barriers but can rely on
utrace locking.

Signed-off-by: Oleg Nesterov <o...@redhat.com>
---

 kernel/ptrace-utrace.c |   13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

--- kstub/kernel/ptrace-utrace.c~4_o_reusable   2010-09-20 03:53:31.000000000 
+0200
+++ kstub/kernel/ptrace-utrace.c        2010-09-20 03:53:32.000000000 +0200
@@ -67,6 +67,7 @@ struct ptrace_context {
 #define PT_UTRACED                     0x00001000
 
 #define PTRACE_O_SYSEMU                        0x100
+#define PTRACE_O_DETACHED              0x200
 
 #define PTRACE_EVENT_SYSCALL           (1 << 16)
 #define PTRACE_EVENT_SIGTRAP           (2 << 16)
@@ -128,7 +129,7 @@ ptrace_reuse_engine(struct task_struct *
                return engine;
 
        ctx = ptrace_context(engine);
-       if (unlikely(ctx->resume == UTRACE_DETACH)) {
+       if (unlikely(ctx->options == PTRACE_O_DETACHED)) {
                /*
                 * Try to reuse this self-detaching engine.
                 * The only caller which can hit this case is ptrace_attach(),
@@ -264,12 +265,14 @@ static void ptrace_detach_task(struct ta
        bool voluntary = (sig >= 0);
        struct utrace_engine *engine = ptrace_lookup_engine(tracee);
        enum utrace_resume_action action = UTRACE_DETACH;
+       struct ptrace_context *ctx;
 
        if (unlikely(IS_ERR(engine)))
                return;
 
+       ctx = ptrace_context(engine);
+
        if (sig) {
-               struct ptrace_context *ctx = ptrace_context(engine);
 
                switch (get_stop_event(ctx)) {
                case PTRACE_EVENT_SYSCALL:
@@ -287,6 +290,10 @@ static void ptrace_detach_task(struct ta
        }
 
        ptrace_wake_up(tracee, engine, action, voluntary);
+
+       if (action != UTRACE_DETACH)
+               ctx->options = PTRACE_O_DETACHED;
+
        utrace_engine_put(engine);
 }
 
@@ -774,7 +781,7 @@ void exit_ptrace(struct task_struct *tra
 static int ptrace_set_options(struct task_struct *tracee,
                                struct utrace_engine *engine, long data)
 {
-       BUILD_BUG_ON(PTRACE_O_MASK & PTRACE_O_SYSEMU);
+       BUILD_BUG_ON(PTRACE_O_MASK & (PTRACE_O_SYSEMU | PTRACE_O_DETACHED));
 
        ptrace_set_events(tracee, engine, data & PTRACE_O_MASK);
        return (data & ~PTRACE_O_MASK) ? -EINVAL : 0;

Reply via email to