Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc
[pandora-kernel.git] / kernel / ptrace.c
index e337390..082b3fc 100644 (file)
  */
 void __ptrace_link(struct task_struct *child, struct task_struct *new_parent)
 {
-       BUG_ON(!list_empty(&child->ptrace_list));
-       if (child->parent == new_parent)
-               return;
-       list_add(&child->ptrace_list, &child->parent->ptrace_children);
-       remove_parent(child);
+       BUG_ON(!list_empty(&child->ptrace_entry));
+       list_add(&child->ptrace_entry, &new_parent->ptraced);
        child->parent = new_parent;
-       add_parent(child);
 }
  
 /*
@@ -73,12 +69,8 @@ void __ptrace_unlink(struct task_struct *child)
        BUG_ON(!child->ptrace);
 
        child->ptrace = 0;
-       if (ptrace_reparented(child)) {
-               list_del_init(&child->ptrace_list);
-               remove_parent(child);
-               child->parent = child->real_parent;
-               add_parent(child);
-       }
+       child->parent = child->real_parent;
+       list_del_init(&child->ptrace_entry);
 
        if (task_is_traced(child))
                ptrace_untrace(child);
@@ -115,7 +107,7 @@ int ptrace_check_attach(struct task_struct *child, int kill)
        read_unlock(&tasklist_lock);
 
        if (!ret && !kill)
-               wait_task_inactive(child);
+               ret = wait_task_inactive(child, TASK_TRACED) ? 0 : -ESRCH;
 
        /* All systems go.. */
        return ret;
@@ -492,15 +484,34 @@ int ptrace_traceme(void)
        /*
         * Are we already being traced?
         */
+repeat:
        task_lock(current);
        if (!(current->ptrace & PT_PTRACED)) {
+               /*
+                * See ptrace_attach() comments about the locking here.
+                */
+               unsigned long flags;
+               if (!write_trylock_irqsave(&tasklist_lock, flags)) {
+                       task_unlock(current);
+                       do {
+                               cpu_relax();
+                       } while (!write_can_lock(&tasklist_lock));
+                       goto repeat;
+               }
+
                ret = security_ptrace(current->parent, current,
                                      PTRACE_MODE_ATTACH);
+
                /*
                 * Set the ptrace bit in the process ptrace flags.
+                * Then link us on our parent's ptraced list.
                 */
-               if (!ret)
+               if (!ret) {
                        current->ptrace |= PT_PTRACED;
+                       __ptrace_link(current, current->real_parent);
+               }
+
+               write_unlock_irqrestore(&tasklist_lock, flags);
        }
        task_unlock(current);
        return ret;