Merge branch 'core-cleanups-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 4 Apr 2009 00:35:06 +0000 (17:35 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 4 Apr 2009 00:35:06 +0000 (17:35 -0700)
* 'core-cleanups-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  ptrace: remove a useless goto

1  2 
kernel/ptrace.c

diff --combined kernel/ptrace.c
@@@ -60,15 -60,11 +60,15 @@@ static void ptrace_untrace(struct task_
  {
        spin_lock(&child->sighand->siglock);
        if (task_is_traced(child)) {
 -              if (child->signal->flags & SIGNAL_STOP_STOPPED) {
 +              /*
 +               * If the group stop is completed or in progress,
 +               * this thread was already counted as stopped.
 +               */
 +              if (child->signal->flags & SIGNAL_STOP_STOPPED ||
 +                  child->signal->group_stop_count)
                        __set_task_state(child, TASK_STOPPED);
 -              } else {
 +              else
                        signal_wake_up(child, 1);
 -              }
        }
        spin_unlock(&child->sighand->siglock);
  }
@@@ -239,58 -235,18 +239,58 @@@ out
        return retval;
  }
  
 -static inline void __ptrace_detach(struct task_struct *child, unsigned int data)
 +/*
 + * Called with irqs disabled, returns true if childs should reap themselves.
 + */
 +static int ignoring_children(struct sighand_struct *sigh)
  {
 -      child->exit_code = data;
 -      /* .. re-parent .. */
 -      __ptrace_unlink(child);
 -      /* .. and wake it up. */
 -      if (child->exit_state != EXIT_ZOMBIE)
 -              wake_up_process(child);
 +      int ret;
 +      spin_lock(&sigh->siglock);
 +      ret = (sigh->action[SIGCHLD-1].sa.sa_handler == SIG_IGN) ||
 +            (sigh->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDWAIT);
 +      spin_unlock(&sigh->siglock);
 +      return ret;
 +}
 +
 +/*
 + * Called with tasklist_lock held for writing.
 + * Unlink a traced task, and clean it up if it was a traced zombie.
 + * Return true if it needs to be reaped with release_task().
 + * (We can't call release_task() here because we already hold tasklist_lock.)
 + *
 + * If it's a zombie, our attachedness prevented normal parent notification
 + * or self-reaping.  Do notification now if it would have happened earlier.
 + * If it should reap itself, return true.
 + *
 + * If it's our own child, there is no notification to do.
 + * But if our normal children self-reap, then this child
 + * was prevented by ptrace and we must reap it now.
 + */
 +static bool __ptrace_detach(struct task_struct *tracer, struct task_struct *p)
 +{
 +      __ptrace_unlink(p);
 +
 +      if (p->exit_state == EXIT_ZOMBIE) {
 +              if (!task_detached(p) && thread_group_empty(p)) {
 +                      if (!same_thread_group(p->real_parent, tracer))
 +                              do_notify_parent(p, p->exit_signal);
 +                      else if (ignoring_children(tracer->sighand))
 +                              p->exit_signal = -1;
 +              }
 +              if (task_detached(p)) {
 +                      /* Mark it as in the process of being reaped. */
 +                      p->exit_state = EXIT_DEAD;
 +                      return true;
 +              }
 +      }
 +
 +      return false;
  }
  
  int ptrace_detach(struct task_struct *child, unsigned int data)
  {
 +      bool dead = false;
 +
        if (!valid_signal(data))
                return -EIO;
  
        clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
  
        write_lock_irq(&tasklist_lock);
 -      /* protect against de_thread()->release_task() */
 -      if (child->ptrace)
 -              __ptrace_detach(child, data);
 +      /*
 +       * This child can be already killed. Make sure de_thread() or
 +       * our sub-thread doing do_wait() didn't do release_task() yet.
 +       */
 +      if (child->ptrace) {
 +              child->exit_code = data;
 +              dead = __ptrace_detach(current, child);
 +      }
        write_unlock_irq(&tasklist_lock);
  
 +      if (unlikely(dead))
 +              release_task(child);
 +
        return 0;
  }
  
 +/*
 + * Detach all tasks we were using ptrace on.
 + */
 +void exit_ptrace(struct task_struct *tracer)
 +{
 +      struct task_struct *p, *n;
 +      LIST_HEAD(ptrace_dead);
 +
 +      write_lock_irq(&tasklist_lock);
 +      list_for_each_entry_safe(p, n, &tracer->ptraced, ptrace_entry) {
 +              if (__ptrace_detach(tracer, p))
 +                      list_add(&p->ptrace_entry, &ptrace_dead);
 +      }
 +      write_unlock_irq(&tasklist_lock);
 +
 +      BUG_ON(!list_empty(&tracer->ptraced));
 +
 +      list_for_each_entry_safe(p, n, &ptrace_dead, ptrace_entry) {
 +              list_del_init(&p->ptrace_entry);
 +              release_task(p);
 +      }
 +}
 +
  int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len)
  {
        int copied = 0;
@@@ -687,8 -612,6 +687,6 @@@ SYSCALL_DEFINE4(ptrace, long, request, 
                goto out_put_task_struct;
  
        ret = arch_ptrace(child, request, addr, data);
-       if (ret < 0)
-               goto out_put_task_struct;
  
   out_put_task_struct:
        put_task_struct(child);