*/
 extern void ds_switch_to(struct task_struct *prev, struct task_struct *next);
 
+/*
+ * Task clone/init and cleanup work
+ */
+extern void ds_copy_thread(struct task_struct *tsk, struct task_struct *father);
+extern void ds_exit_thread(struct task_struct *tsk);
+
 #else /* CONFIG_X86_DS */
 
 struct cpuinfo_x86;
 static inline void __cpuinit ds_init_intel(struct cpuinfo_x86 *ignored) {}
 static inline void ds_switch_to(struct task_struct *prev,
                                struct task_struct *next) {}
+static inline void ds_copy_thread(struct task_struct *tsk,
+                                 struct task_struct *father) {}
+static inline void ds_exit_thread(struct task_struct *tsk) {}
 
 #endif /* CONFIG_X86_DS */
 #endif /* _ASM_X86_DS_H */
 
 extern int do_set_thread_area(struct task_struct *p, int idx,
                              struct user_desc __user *info, int can_allocate);
 
+extern void x86_ptrace_untrace(struct task_struct *);
+extern void x86_ptrace_fork(struct task_struct *child,
+                           unsigned long clone_flags);
+
+#define arch_ptrace_untrace(tsk) x86_ptrace_untrace(tsk)
+#define arch_ptrace_fork(child, flags) x86_ptrace_fork(child, flags)
+
 #endif /* __KERNEL__ */
 
 #endif /* !__ASSEMBLY__ */
 
 
        update_debugctlmsr(next->thread.debugctlmsr);
 }
+
+void ds_copy_thread(struct task_struct *tsk, struct task_struct *father)
+{
+       clear_tsk_thread_flag(tsk, TIF_DS_AREA_MSR);
+       tsk->thread.ds_ctx = NULL;
+}
+
+void ds_exit_thread(struct task_struct *tsk)
+{
+       WARN_ON(tsk->thread.ds_ctx);
+}
 
 #include <asm/idle.h>
 #include <asm/syscalls.h>
 #include <asm/smp.h>
+#include <asm/ds.h>
 
 asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
 
                tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET;
                put_cpu();
        }
-#ifdef CONFIG_X86_DS
-       /* Free any BTS tracers that have not been properly released. */
-       if (unlikely(current->bts)) {
-               ds_release_bts(current->bts);
-               current->bts = NULL;
-
-               kfree(current->bts_buffer);
-               current->bts_buffer = NULL;
-               current->bts_size = 0;
-       }
-#endif /* CONFIG_X86_DS */
+
+       ds_exit_thread(current);
 }
 
 void flush_thread(void)
                kfree(p->thread.io_bitmap_ptr);
                p->thread.io_bitmap_max = 0;
        }
+
+       ds_copy_thread(p, current);
+
+       clear_tsk_thread_flag(p, TIF_DEBUGCTLMSR);
+       p->thread.debugctlmsr = 0;
+
        return err;
 }
 
 
 #include <asm/ia32.h>
 #include <asm/idle.h>
 #include <asm/syscalls.h>
+#include <asm/ds.h>
 
 asmlinkage extern void ret_from_fork(void);
 
                t->io_bitmap_max = 0;
                put_cpu();
        }
-#ifdef CONFIG_X86_DS
-       /* Free any BTS tracers that have not been properly released. */
-       if (unlikely(current->bts)) {
-               ds_release_bts(current->bts);
-               current->bts = NULL;
-
-               kfree(current->bts_buffer);
-               current->bts_buffer = NULL;
-               current->bts_size = 0;
-       }
-#endif /* CONFIG_X86_DS */
+
+       ds_exit_thread(current);
 }
 
 void flush_thread(void)
                if (err)
                        goto out;
        }
+
+       ds_copy_thread(p, me);
+
+       clear_tsk_thread_flag(p, TIF_DEBUGCTLMSR);
+       p->thread.debugctlmsr = 0;
+
        err = 0;
 out:
        if (err && p->thread.io_bitmap_ptr) {
 
 
        return (trace->ds.top - trace->ds.begin) / trace->ds.size;
 }
+
+static void ptrace_bts_fork(struct task_struct *tsk)
+{
+       tsk->bts = NULL;
+       tsk->bts_buffer = NULL;
+       tsk->bts_size = 0;
+       tsk->thread.bts_ovfl_signal = 0;
+}
+
+static void ptrace_bts_untrace(struct task_struct *child)
+{
+       if (unlikely(child->bts)) {
+               ds_release_bts(child->bts);
+               child->bts = NULL;
+
+               kfree(child->bts_buffer);
+               child->bts_buffer = NULL;
+               child->bts_size = 0;
+       }
+}
+
+static void ptrace_bts_detach(struct task_struct *child)
+{
+       ptrace_bts_untrace(child);
+}
+#else
+static inline void ptrace_bts_fork(struct task_struct *tsk) {}
+static inline void ptrace_bts_detach(struct task_struct *child) {}
+static inline void ptrace_bts_untrace(struct task_struct *child) {}
 #endif /* CONFIG_X86_PTRACE_BTS */
 
+void x86_ptrace_fork(struct task_struct *child, unsigned long clone_flags)
+{
+       ptrace_bts_fork(child);
+}
+
+void x86_ptrace_untrace(struct task_struct *child)
+{
+       ptrace_bts_untrace(child);
+}
+
 /*
  * Called by kernel/ptrace.c when detaching..
  *
 #ifdef TIF_SYSCALL_EMU
        clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
 #endif
-#ifdef CONFIG_X86_PTRACE_BTS
-       if (child->bts) {
-               ds_release_bts(child->bts);
-               child->bts = NULL;
-
-               kfree(child->bts_buffer);
-               child->bts_buffer = NULL;
-               child->bts_size = 0;
-       }
-#endif /* CONFIG_X86_PTRACE_BTS */
+       ptrace_bts_detach(child);
 }
 
 #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
 
 extern void __ptrace_link(struct task_struct *child,
                          struct task_struct *new_parent);
 extern void __ptrace_unlink(struct task_struct *child);
+extern void ptrace_fork(struct task_struct *task, unsigned long clone_flags);
 #define PTRACE_MODE_READ   1
 #define PTRACE_MODE_ATTACH 2
 /* Returns 0 on success, -errno on denial. */
 #define arch_ptrace_stop(code, info)           do { } while (0)
 #endif
 
+#ifndef arch_ptrace_untrace
+/*
+ * Do machine-specific work before untracing child.
+ *
+ * This is called for a normal detach as well as from ptrace_exit()
+ * when the tracing task dies.
+ *
+ * Called with write_lock(&tasklist_lock) held.
+ */
+#define arch_ptrace_untrace(task)              do { } while (0)
+#endif
+
+#ifndef arch_ptrace_fork
+/*
+ * Do machine-specific work to initialize a new task.
+ *
+ * This is called from copy_process().
+ */
+#define arch_ptrace_fork(child, clone_flags)   do { } while (0)
+#endif
+
 extern int task_current_syscall(struct task_struct *target, long *callno,
                                unsigned long args[6], unsigned int maxargs,
                                unsigned long *sp, unsigned long *pc);
 
 #ifdef CONFIG_DEBUG_MUTEXES
        p->blocked_on = NULL; /* not blocked yet */
 #endif
+       if (unlikely(ptrace_reparented(current)))
+               ptrace_fork(p, clone_flags);
 
        /* Perform scheduler related setup. Assign this task to a CPU. */
        sched_fork(p, clone_flags);
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 
+
+/*
+ * Initialize a new task whose father had been ptraced.
+ *
+ * Called from copy_process().
+ */
+void ptrace_fork(struct task_struct *child, unsigned long clone_flags)
+{
+       arch_ptrace_fork(child, clone_flags);
+}
+
 /*
  * ptrace a task: make the debugger its new parent and
  * move it to the ptrace list.
        child->parent = child->real_parent;
        list_del_init(&child->ptrace_entry);
 
+       arch_ptrace_untrace(child);
        if (task_is_traced(child))
                ptrace_untrace(child);
 }