vserver 1.9.5.x5
[linux-2.6.git] / kernel / signal.c
index 74d1d9e..cf9bb8d 100644 (file)
 #include <linux/tty.h>
 #include <linux/binfmts.h>
 #include <linux/security.h>
+#include <linux/syscalls.h>
 #include <linux/ptrace.h>
 #include <asm/param.h>
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
 #include <asm/siginfo.h>
 
+extern void k_getrusage(struct task_struct *, int, struct rusage *);
+
 /*
  * SLAB caches for signal bits.
  */
@@ -150,11 +153,6 @@ static kmem_cache_t *sigqueue_cachep;
        (!T(signr, SIG_KERNEL_IGNORE_MASK|SIG_KERNEL_STOP_MASK) && \
         (t)->sighand->action[(signr)-1].sa.sa_handler == SIG_DFL)
 
-#define sig_avoid_stop_race() \
-       (sigtestsetmask(&current->pending.signal, M(SIGCONT) | M(SIGKILL)) || \
-        sigtestsetmask(&current->signal->shared_pending.signal, \
-                                                 M(SIGCONT) | M(SIGKILL)))
-
 static int sig_ignored(struct task_struct *t, int sig)
 {
        void __user * handler;
@@ -262,18 +260,18 @@ next_signal(struct sigpending *pending, sigset_t *mask)
        return sig;
 }
 
-static struct sigqueue *__sigqueue_alloc(void)
+static struct sigqueue *__sigqueue_alloc(struct task_struct *t, int flags)
 {
        struct sigqueue *q = NULL;
 
-       if (atomic_read(&current->user->sigpending) <
-                       current->rlim[RLIMIT_SIGPENDING].rlim_cur)
-               q = kmem_cache_alloc(sigqueue_cachep, GFP_ATOMIC);
+       if (atomic_read(&t->user->sigpending) <
+                       t->signal->rlim[RLIMIT_SIGPENDING].rlim_cur)
+               q = kmem_cache_alloc(sigqueue_cachep, flags);
        if (q) {
                INIT_LIST_HEAD(&q->list);
                q->flags = 0;
                q->lock = NULL;
-               q->user = get_uid(current->user);
+               q->user = get_uid(t->user);
                atomic_inc(&q->user->sigpending);
        }
        return(q);
@@ -367,6 +365,22 @@ void __exit_signal(struct task_struct *tsk)
                if (tsk == sig->curr_target)
                        sig->curr_target = next_thread(tsk);
                tsk->signal = NULL;
+               /*
+                * Accumulate here the counters for all threads but the
+                * group leader as they die, so they can be added into
+                * the process-wide totals when those are taken.
+                * The group leader stays around as a zombie as long
+                * as there are other threads.  When it gets reaped,
+                * the exit.c code will add its counts into these totals.
+                * We won't ever get here for the group leader, since it
+                * will have been the last reference on the signal_struct.
+                */
+               sig->utime = cputime_add(sig->utime, tsk->utime);
+               sig->stime = cputime_add(sig->stime, tsk->stime);
+               sig->min_flt += tsk->min_flt;
+               sig->maj_flt += tsk->maj_flt;
+               sig->nvcsw += tsk->nvcsw;
+               sig->nivcsw += tsk->nivcsw;
                spin_unlock(&sighand->siglock);
                sig = NULL;     /* Marker for below.  */
        }
@@ -532,6 +546,21 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
        if (!signr)
                signr = __dequeue_signal(&tsk->signal->shared_pending,
                                         mask, info);
+       if (signr && unlikely(sig_kernel_stop(signr))) {
+               /*
+                * Set a marker that we have dequeued a stop signal.  Our
+                * caller might release the siglock and then the pending
+                * stop signal it is about to process is no longer in the
+                * pending bitmasks, but must still be cleared by a SIGCONT
+                * (and overruled by a SIGKILL).  So those cases clear this
+                * shared flag after we've set it.  Note that this flag may
+                * remain set after the signal we return is ignored or
+                * handled.  That doesn't matter because its only purpose
+                * is to alert stop-signal processing code when another
+                * processor has come along and cleared the flag.
+                */
+               tsk->signal->flags |= SIGNAL_STOP_DEQUEUED;
+       }
        if ( signr &&
             ((info->si_code & __SI_MASK) == __SI_TIMER) &&
             info->si_sys_private){
@@ -558,15 +587,15 @@ void signal_wake_up(struct task_struct *t, int resume)
        set_tsk_thread_flag(t, TIF_SIGPENDING);
 
        /*
-        * If resume is set, we want to wake it up in the TASK_STOPPED case.
-        * We don't check for TASK_STOPPED because there is a race with it
+        * For SIGKILL, we want to wake it up in the stopped/traced case.
+        * We don't check t->state here because there is a race with it
         * executing another processor and just now entering stopped state.
-        * By calling wake_up_process any time resume is set, we ensure
-        * the process will wake up and handle its stop or death signal.
+        * By using wake_up_state, we ensure the process will wake up and
+        * handle its death signal.
         */
        mask = TASK_INTERRUPTIBLE;
        if (resume)
-               mask |= TASK_STOPPED;
+               mask |= TASK_STOPPED | TASK_TRACED;
        if (!wake_up_state(t, mask))
                kick_process(t);
 }
@@ -602,23 +631,33 @@ static int check_kill_permission(int sig, struct siginfo *info,
                                 struct task_struct *t)
 {
        int error = -EINVAL;
+       int user;
+
        if (sig < 0 || sig > _NSIG)
                return error;
+
+       user = (!info || ((unsigned long)info != 1 &&
+               (unsigned long)info != 2 && SI_FROMUSER(info)));
+
        error = -EPERM;
-       if ((!info || ((unsigned long)info != 1 &&
-                       (unsigned long)info != 2 && SI_FROMUSER(info)))
-           && ((sig != SIGCONT) ||
+       if (user && ((sig != SIGCONT) ||
                (current->signal->session != t->signal->session))
            && (current->euid ^ t->suid) && (current->euid ^ t->uid)
            && (current->uid ^ t->suid) && (current->uid ^ t->uid)
            && !capable(CAP_KILL))
                return error;
+
+       error = -ESRCH;
+       if (user && !vx_check(vx_task_xid(t), VX_ADMIN|VX_IDENT))
+               return error;
+
        return security_task_kill(t, info, sig);
 }
 
 /* forward decl */
 static void do_notify_parent_cldstop(struct task_struct *tsk,
-                                    struct task_struct *parent);
+                                    struct task_struct *parent,
+                                    int why);
 
 /*
  * Handle magic process-wide effects of stop/continue signals.
@@ -631,6 +670,12 @@ static void handle_stop_signal(int sig, struct task_struct *p)
 {
        struct task_struct *t;
 
+       if (p->flags & SIGNAL_GROUP_EXIT)
+               /*
+                * The process is in the middle of dying already.
+                */
+               return;
+
        if (sig_kernel_stop(sig)) {
                /*
                 * This is a stop signal.  Remove SIGCONT from all queues.
@@ -660,12 +705,17 @@ static void handle_stop_signal(int sig, struct task_struct *p)
                         * the SIGCHLD was pending on entry to this kill.
                         */
                        p->signal->group_stop_count = 0;
+                       p->signal->flags = SIGNAL_STOP_CONTINUED;
+                       spin_unlock(&p->sighand->siglock);
                        if (p->ptrace & PT_PTRACED)
-                               do_notify_parent_cldstop(p, p->parent);
+                               do_notify_parent_cldstop(p, p->parent,
+                                                        CLD_STOPPED);
                        else
                                do_notify_parent_cldstop(
                                        p->group_leader,
-                                       p->group_leader->real_parent);
+                                       p->group_leader->real_parent,
+                                                        CLD_STOPPED);
+                       spin_lock(&p->sighand->siglock);
                }
                rm_from_queue(SIG_KERNEL_STOP_MASK, &p->signal->shared_pending);
                t = p;
@@ -696,6 +746,38 @@ static void handle_stop_signal(int sig, struct task_struct *p)
 
                        t = next_thread(t);
                } while (t != p);
+
+               if (p->signal->flags & SIGNAL_STOP_STOPPED) {
+                       /*
+                        * We were in fact stopped, and are now continued.
+                        * Notify the parent with CLD_CONTINUED.
+                        */
+                       p->signal->flags = SIGNAL_STOP_CONTINUED;
+                       p->signal->group_exit_code = 0;
+                       spin_unlock(&p->sighand->siglock);
+                       if (p->ptrace & PT_PTRACED)
+                               do_notify_parent_cldstop(p, p->parent,
+                                                        CLD_CONTINUED);
+                       else
+                               do_notify_parent_cldstop(
+                                       p->group_leader,
+                                       p->group_leader->real_parent,
+                                                        CLD_CONTINUED);
+                       spin_lock(&p->sighand->siglock);
+               } else {
+                       /*
+                        * We are not stopped, but there could be a stop
+                        * signal in the middle of being processed after
+                        * being removed from the queue.  Clear that too.
+                        */
+                       p->signal->flags = 0;
+               }
+       } else if (sig == SIGKILL) {
+               /*
+                * Make sure that any pending stop signal already dequeued
+                * is undone by the wakeup for SIGKILL.
+                */
+               p->signal->flags = 0;
        }
 }
 
@@ -720,14 +802,8 @@ static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
           make sure at least one signal gets delivered and don't
           pass on the info struct.  */
 
-       if (atomic_read(&t->user->sigpending) <
-                       t->rlim[RLIMIT_SIGPENDING].rlim_cur)
-               q = kmem_cache_alloc(sigqueue_cachep, GFP_ATOMIC);
-
+       q = __sigqueue_alloc(t, GFP_ATOMIC);
        if (q) {
-               q->flags = 0;
-               q->user = get_uid(t->user);
-               atomic_inc(&q->user->sigpending);
                list_add_tail(&q->list, &signals->list);
                switch ((unsigned long) info) {
                case 0:
@@ -780,10 +856,7 @@ specific_send_sig_info(int sig, struct siginfo *info, struct task_struct *t)
 
        if (!irqs_disabled())
                BUG();
-#ifdef CONFIG_SMP
-       if (!spin_is_locked(&t->sighand->siglock))
-               BUG();
-#endif
+       assert_spin_locked(&t->sighand->siglock);
 
        if (((unsigned long)info > 2) && (info->si_code == SI_TIMER))
                /*
@@ -861,10 +934,19 @@ force_sig_specific(int sig, struct task_struct *t)
 
 
 static void
-__group_complete_signal(int sig, struct task_struct *p, unsigned int mask)
+__group_complete_signal(int sig, struct task_struct *p)
 {
+       unsigned int mask;
        struct task_struct *t;
 
+       /*
+        * Don't bother traced and stopped tasks (but
+        * SIGKILL will punch through that).
+        */
+       mask = TASK_STOPPED | TASK_TRACED;
+       if (sig == SIGKILL)
+               mask = 0;
+
        /*
         * Now find a thread we can wake up to take the signal off the queue.
         *
@@ -906,7 +988,7 @@ __group_complete_signal(int sig, struct task_struct *p, unsigned int mask)
         * Found a killable thread.  If the signal will be fatal,
         * then start taking the whole group down immediately.
         */
-       if (sig_fatal(p, sig) && !p->signal->group_exit &&
+       if (sig_fatal(p, sig) && !(p->signal->flags & SIGNAL_GROUP_EXIT) &&
            !sigismember(&t->real_blocked, sig) &&
            (sig == SIGKILL || !(t->ptrace & PT_PTRACED))) {
                /*
@@ -919,7 +1001,7 @@ __group_complete_signal(int sig, struct task_struct *p, unsigned int mask)
                         * running and doing things after a slower
                         * thread has the fatal signal pending.
                         */
-                       p->signal->group_exit = 1;
+                       p->signal->flags = SIGNAL_GROUP_EXIT;
                        p->signal->group_exit_code = sig;
                        p->signal->group_stop_count = 0;
                        t = p;
@@ -966,13 +1048,9 @@ __group_complete_signal(int sig, struct task_struct *p, unsigned int mask)
 static int
 __group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
 {
-       unsigned int mask;
        int ret = 0;
 
-#ifdef CONFIG_SMP
-       if (!spin_is_locked(&p->sighand->siglock))
-               BUG();
-#endif
+       assert_spin_locked(&p->sighand->siglock);
        handle_stop_signal(sig, p);
 
        if (((unsigned long)info > 2) && (info->si_code == SI_TIMER))
@@ -989,14 +1067,6 @@ __group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
                /* This is a non-RT signal and we already have one queued.  */
                return ret;
 
-       /*
-        * Don't bother zombies and stopped tasks (but
-        * SIGKILL will punch through stopped state)
-        */
-       mask = TASK_DEAD | TASK_ZOMBIE;
-       if (sig != SIGKILL)
-               mask |= TASK_STOPPED;
-
        /*
         * Put this signal on the shared-pending queue, or fail with EAGAIN.
         * We always use the shared queue for process-wide signals,
@@ -1006,7 +1076,7 @@ __group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
        if (unlikely(ret))
                return ret;
 
-       __group_complete_signal(sig, p, mask);
+       __group_complete_signal(sig, p);
        return 0;
 }
 
@@ -1017,6 +1087,7 @@ void zap_other_threads(struct task_struct *p)
 {
        struct task_struct *t;
 
+       p->signal->flags = SIGNAL_GROUP_EXIT;
        p->signal->group_stop_count = 0;
 
        if (thread_group_empty(p))
@@ -1026,7 +1097,7 @@ void zap_other_threads(struct task_struct *p)
                /*
                 * Don't bother with already dead threads
                 */
-               if (t->state & (TASK_ZOMBIE|TASK_DEAD))
+               if (t->exit_state)
                        continue;
 
                /*
@@ -1054,9 +1125,6 @@ int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
        unsigned long flags;
        int ret;
 
-       if (!vx_check(vx_task_xid(p), VX_ADMIN|VX_WATCH|VX_IDENT))
-               return -ESRCH;
-
        ret = check_kill_permission(sig, info, p);
        if (!ret && sig && p->sighand) {
                spin_lock_irqsave(&p->sighand->siglock, flags);
@@ -1074,9 +1142,7 @@ int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
 
 int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp)
 {
-       struct task_struct *p;
-       struct list_head *l;
-       struct pid *pid;
+       struct task_struct *p = NULL;
        int retval, success;
 
        if (pgrp <= 0)
@@ -1084,11 +1150,11 @@ int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp)
 
        success = 0;
        retval = -ESRCH;
-       for_each_task_pid(pgrp, PIDTYPE_PGID, p, l, pid) {
+       do_each_task_pid(pgrp, PIDTYPE_PGID, p) {
                int err = group_send_sig_info(sig, info, p);
                success |= !err;
                retval = err;
-       }
+       } while_each_task_pid(pgrp, PIDTYPE_PGID, p);
        return success ? 0 : retval;
 }
 
@@ -1104,38 +1170,6 @@ kill_pg_info(int sig, struct siginfo *info, pid_t pgrp)
        return retval;
 }
 
-/*
- * kill_sl_info() sends a signal to the session leader: this is used
- * to send SIGHUP to the controlling process of a terminal when
- * the connection is lost.
- */
-
-
-int
-kill_sl_info(int sig, struct siginfo *info, pid_t sid)
-{
-       int err, retval = -EINVAL;
-       struct pid *pid;
-       struct list_head *l;
-       struct task_struct *p;
-
-       if (sid <= 0)
-               goto out;
-
-       retval = -ESRCH;
-       read_lock(&tasklist_lock);
-       for_each_task_pid(sid, PIDTYPE_SID, p, l, pid) {
-               if (!p->signal->leader)
-                       continue;
-               err = group_send_sig_info(sig, info, p);
-               if (retval)
-                       retval = err;
-       }
-       read_unlock(&tasklist_lock);
-out:
-       return retval;
-}
-
 int
 kill_proc_info(int sig, struct siginfo *info, pid_t pid)
 {
@@ -1246,16 +1280,29 @@ force_sig(int sig, struct task_struct *p)
        force_sig_info(sig, (void*)1L, p);
 }
 
+/*
+ * When things go south during signal handling, we
+ * will force a SIGSEGV. And if the signal that caused
+ * the problem was already a SIGSEGV, we'll want to
+ * make sure we don't even try to deliver the signal..
+ */
 int
-kill_pg(pid_t pgrp, int sig, int priv)
+force_sigsegv(int sig, struct task_struct *p)
 {
-       return kill_pg_info(sig, (void *)(long)(priv != 0), pgrp);
+       if (sig == SIGSEGV) {
+               unsigned long flags;
+               spin_lock_irqsave(&p->sighand->siglock, flags);
+               p->sighand->action[sig - 1].sa.sa_handler = SIG_DFL;
+               spin_unlock_irqrestore(&p->sighand->siglock, flags);
+       }
+       force_sig(SIGSEGV, p);
+       return 0;
 }
 
 int
-kill_sl(pid_t sess, int sig, int priv)
+kill_pg(pid_t pgrp, int sig, int priv)
 {
-       return kill_sl_info(sig, (void *)(long)(priv != 0), sess);
+       return kill_pg_info(sig, (void *)(long)(priv != 0), pgrp);
 }
 
 int
@@ -1278,7 +1325,7 @@ struct sigqueue *sigqueue_alloc(void)
 {
        struct sigqueue *q;
 
-       if ((q = __sigqueue_alloc()))
+       if ((q = __sigqueue_alloc(current, GFP_KERNEL)))
                q->flags |= SIGQUEUE_PREALLOC;
        return(q);
 }
@@ -1351,7 +1398,6 @@ int
 send_group_sigqueue(int sig, struct sigqueue *q, struct task_struct *p)
 {
        unsigned long flags;
-       unsigned int mask;
        int ret = 0;
 
        BUG_ON(!(q->flags & SIGQUEUE_PREALLOC));
@@ -1376,13 +1422,6 @@ send_group_sigqueue(int sig, struct sigqueue *q, struct task_struct *p)
                q->info.si_overrun++;
                goto out;
        } 
-       /*
-        * Don't bother zombies and stopped tasks (but
-        * SIGKILL will punch through stopped state)
-        */
-       mask = TASK_DEAD | TASK_ZOMBIE;
-       if (sig != SIGKILL)
-               mask |= TASK_STOPPED;
 
        /*
         * Put this signal on the shared-pending queue.
@@ -1393,7 +1432,7 @@ send_group_sigqueue(int sig, struct sigqueue *q, struct task_struct *p)
        list_add_tail(&q->list, &p->signal->shared_pending.list);
        sigaddset(&p->signal->shared_pending.signal, sig);
 
-       __group_complete_signal(sig, p, mask);
+       __group_complete_signal(sig, p);
 out:
        spin_unlock_irqrestore(&p->sighand->siglock, flags);
        read_unlock(&tasklist_lock);
@@ -1401,46 +1440,32 @@ out:
 }
 
 /*
- * Joy. Or not. Pthread wants us to wake up every thread
- * in our parent group.
+ * Wake up any threads in the parent blocked in wait* syscalls.
  */
-static void __wake_up_parent(struct task_struct *p,
+static inline void __wake_up_parent(struct task_struct *p,
                                    struct task_struct *parent)
 {
-       struct task_struct *tsk = parent;
-
-       /*
-        * Fortunately this is not necessary for thread groups:
-        */
-       if (p->tgid == tsk->tgid) {
-               wake_up_interruptible_sync(&tsk->wait_chldexit);
-               return;
-       }
-
-       do {
-               wake_up_interruptible_sync(&tsk->wait_chldexit);
-               tsk = next_thread(tsk);
-               if (tsk->signal != parent->signal)
-                       BUG();
-       } while (tsk != parent);
+       wake_up_interruptible_sync(&parent->signal->wait_chldexit);
 }
 
 /*
- * Let a parent know about a status change of a child.
+ * Let a parent know about the death of a child.
+ * For a stopped/continued status change, use do_notify_parent_cldstop instead.
  */
 
 void do_notify_parent(struct task_struct *tsk, int sig)
 {
        struct siginfo info;
        unsigned long flags;
-       int why, status;
        struct sighand_struct *psig;
 
-       if (sig == -1)
-               BUG();
+       BUG_ON(sig == -1);
+
+       /* do_notify_parent_cldstop should have been called instead.  */
+       BUG_ON(tsk->state & (TASK_STOPPED|TASK_TRACED));
 
-       BUG_ON(tsk->group_leader != tsk && tsk->group_leader->state != TASK_ZOMBIE && !tsk->ptrace);
-       BUG_ON(tsk->group_leader == tsk && !thread_group_empty(tsk) && !tsk->ptrace);
+       BUG_ON(!tsk->ptrace &&
+              (tsk->group_leader != tsk || !thread_group_empty(tsk)));
 
        info.si_signo = sig;
        info.si_errno = 0;
@@ -1448,37 +1473,24 @@ void do_notify_parent(struct task_struct *tsk, int sig)
        info.si_uid = tsk->uid;
 
        /* FIXME: find out whether or not this is supposed to be c*time. */
-       info.si_utime = tsk->utime;
-       info.si_stime = tsk->stime;
-
-       status = tsk->exit_code & 0x7f;
-       why = SI_KERNEL;        /* shouldn't happen */
-       switch (tsk->state) {
-       case TASK_STOPPED:
-               /* FIXME -- can we deduce CLD_TRAPPED or CLD_CONTINUED? */
-               if (tsk->ptrace & PT_PTRACED)
-                       why = CLD_TRAPPED;
-               else
-                       why = CLD_STOPPED;
-               break;
+       info.si_utime = cputime_to_jiffies(cputime_add(tsk->utime,
+                                                      tsk->signal->utime));
+       info.si_stime = cputime_to_jiffies(cputime_add(tsk->stime,
+                                                      tsk->signal->stime));
 
-       default:
-               if (tsk->exit_code & 0x80)
-                       why = CLD_DUMPED;
-               else if (tsk->exit_code & 0x7f)
-                       why = CLD_KILLED;
-               else {
-                       why = CLD_EXITED;
-                       status = tsk->exit_code >> 8;
-               }
-               break;
+       info.si_status = tsk->exit_code & 0x7f;
+       if (tsk->exit_code & 0x80)
+               info.si_code = CLD_DUMPED;
+       else if (tsk->exit_code & 0x7f)
+               info.si_code = CLD_KILLED;
+       else {
+               info.si_code = CLD_EXITED;
+               info.si_status = tsk->exit_code >> 8;
        }
-       info.si_code = why;
-       info.si_status = status;
 
        psig = tsk->parent->sighand;
        spin_lock_irqsave(&psig->siglock, flags);
-       if (sig == SIGCHLD && tsk->state != TASK_STOPPED &&
+       if (sig == SIGCHLD &&
            (psig->action[SIGCHLD-1].sa.sa_handler == SIG_IGN ||
             (psig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDWAIT))) {
                /*
@@ -1506,26 +1518,9 @@ void do_notify_parent(struct task_struct *tsk, int sig)
        spin_unlock_irqrestore(&psig->siglock, flags);
 }
 
-
-/*
- * We need the tasklist lock because it's the only
- * thing that protects out "parent" pointer.
- *
- * exit.c calls "do_notify_parent()" directly, because
- * it already has the tasklist lock.
- */
-void
-notify_parent(struct task_struct *tsk, int sig)
-{
-       if (sig != -1) {
-               read_lock(&tasklist_lock);
-               do_notify_parent(tsk, sig);
-               read_unlock(&tasklist_lock);
-       }
-}
-
 static void
-do_notify_parent_cldstop(struct task_struct *tsk, struct task_struct *parent)
+do_notify_parent_cldstop(struct task_struct *tsk, struct task_struct *parent,
+                        int why)
 {
        struct siginfo info;
        unsigned long flags;
@@ -1537,11 +1532,23 @@ do_notify_parent_cldstop(struct task_struct *tsk, struct task_struct *parent)
        info.si_uid = tsk->uid;
 
        /* FIXME: find out whether or not this is supposed to be c*time. */
-       info.si_utime = tsk->utime;
-       info.si_stime = tsk->stime;
-
-       info.si_status = tsk->exit_code & 0x7f;
-       info.si_code = CLD_STOPPED;
+       info.si_utime = cputime_to_jiffies(tsk->utime);
+       info.si_stime = cputime_to_jiffies(tsk->stime);
+
+       info.si_code = why;
+       switch (why) {
+       case CLD_CONTINUED:
+               info.si_status = SIGCONT;
+               break;
+       case CLD_STOPPED:
+               info.si_status = tsk->signal->group_exit_code & 0x7f;
+               break;
+       case CLD_TRAPPED:
+               info.si_status = tsk->exit_code & 0x7f;
+               break;
+       default:
+               BUG();
+       }
 
        sighand = parent->sighand;
        spin_lock_irqsave(&sighand->siglock, flags);
@@ -1555,6 +1562,84 @@ do_notify_parent_cldstop(struct task_struct *tsk, struct task_struct *parent)
        spin_unlock_irqrestore(&sighand->siglock, flags);
 }
 
+/*
+ * This must be called with current->sighand->siglock held.
+ *
+ * This should be the path for all ptrace stops.
+ * We always set current->last_siginfo while stopped here.
+ * That makes it a way to test a stopped process for
+ * being ptrace-stopped vs being job-control-stopped.
+ *
+ * If we actually decide not to stop at all because the tracer is gone,
+ * we leave nostop_code in current->exit_code.
+ */
+static void ptrace_stop(int exit_code, int nostop_code, siginfo_t *info)
+{
+       /*
+        * If there is a group stop in progress,
+        * we must participate in the bookkeeping.
+        */
+       if (current->signal->group_stop_count > 0)
+               --current->signal->group_stop_count;
+
+       current->last_siginfo = info;
+       current->exit_code = exit_code;
+
+       /* Let the debugger run.  */
+       set_current_state(TASK_TRACED);
+       spin_unlock_irq(&current->sighand->siglock);
+       read_lock(&tasklist_lock);
+       if (likely(current->ptrace & PT_PTRACED) &&
+           likely(current->parent != current->real_parent ||
+                  !(current->ptrace & PT_ATTACHED)) &&
+           (likely(current->parent->signal != current->signal) ||
+            !unlikely(current->signal->flags & SIGNAL_GROUP_EXIT))) {
+               do_notify_parent_cldstop(current, current->parent,
+                                        CLD_TRAPPED);
+               read_unlock(&tasklist_lock);
+               schedule();
+       } else {
+               /*
+                * By the time we got the lock, our tracer went away.
+                * Don't stop here.
+                */
+               read_unlock(&tasklist_lock);
+               set_current_state(TASK_RUNNING);
+               current->exit_code = nostop_code;
+       }
+
+       /*
+        * We are back.  Now reacquire the siglock before touching
+        * last_siginfo, so that we are sure to have synchronized with
+        * any signal-sending on another CPU that wants to examine it.
+        */
+       spin_lock_irq(&current->sighand->siglock);
+       current->last_siginfo = NULL;
+
+       /*
+        * Queued signals ignored us while we were stopped for tracing.
+        * So check for any that we should take before resuming user mode.
+        */
+       recalc_sigpending();
+}
+
+void ptrace_notify(int exit_code)
+{
+       siginfo_t info;
+
+       BUG_ON((exit_code & (0x7f | ~0xffff)) != SIGTRAP);
+
+       memset(&info, 0, sizeof info);
+       info.si_signo = SIGTRAP;
+       info.si_code = exit_code;
+       info.si_pid = current->pid;
+       info.si_uid = current->uid;
+
+       /* Let the debugger run.  */
+       spin_lock_irq(&current->sighand->siglock);
+       ptrace_stop(exit_code, 0, &info);
+       spin_unlock_irq(&current->sighand->siglock);
+}
 
 #ifndef HAVE_ARCH_GET_SIGNAL_TO_DELIVER
 
@@ -1568,13 +1653,15 @@ finish_stop(int stop_count)
         */
        if (stop_count < 0 || (current->ptrace & PT_PTRACED)) {
                read_lock(&tasklist_lock);
-               do_notify_parent_cldstop(current, current->parent);
+               do_notify_parent_cldstop(current, current->parent,
+                                        CLD_STOPPED);
                read_unlock(&tasklist_lock);
        }
        else if (stop_count == 0) {
                read_lock(&tasklist_lock);
                do_notify_parent_cldstop(current->group_leader,
-                                        current->group_leader->real_parent);
+                                        current->group_leader->real_parent,
+                                        CLD_STOPPED);
                read_unlock(&tasklist_lock);
        }
 
@@ -1588,15 +1675,18 @@ finish_stop(int stop_count)
 /*
  * This performs the stopping for SIGSTOP and other stop signals.
  * We have to stop all threads in the thread group.
+ * Returns nonzero if we've actually stopped and released the siglock.
+ * Returns zero if we didn't stop and still hold the siglock.
  */
-static void
+static int
 do_signal_stop(int signr)
 {
        struct signal_struct *sig = current->signal;
        struct sighand_struct *sighand = current->sighand;
        int stop_count = -1;
 
-       /* spin_lock_irq(&sighand->siglock) is now done in caller */
+       if (!likely(sig->flags & SIGNAL_STOP_DEQUEUED))
+               return 0;
 
        if (sig->group_stop_count > 0) {
                /*
@@ -1607,14 +1697,17 @@ do_signal_stop(int signr)
                stop_count = --sig->group_stop_count;
                current->exit_code = signr;
                set_current_state(TASK_STOPPED);
+               if (stop_count == 0)
+                       sig->flags = SIGNAL_STOP_STOPPED;
                spin_unlock_irq(&sighand->siglock);
        }
        else if (thread_group_empty(current)) {
                /*
                 * Lock must be held through transition to stopped state.
                 */
-               current->exit_code = signr;
+               current->exit_code = current->signal->group_exit_code = signr;
                set_current_state(TASK_STOPPED);
+               sig->flags = SIGNAL_STOP_STOPPED;
                spin_unlock_irq(&sighand->siglock);
        }
        else {
@@ -1635,25 +1728,17 @@ do_signal_stop(int signr)
                read_lock(&tasklist_lock);
                spin_lock_irq(&sighand->siglock);
 
-               if (unlikely(sig->group_exit)) {
+               if (!likely(sig->flags & SIGNAL_STOP_DEQUEUED)) {
                        /*
-                        * There is a group exit in progress now.
-                        * We'll just ignore the stop and process the
-                        * associated fatal signal.
+                        * Another stop or continue happened while we
+                        * didn't have the lock.  We can just swallow this
+                        * signal now.  If we raced with a SIGCONT, that
+                        * should have just cleared it now.  If we raced
+                        * with another processor delivering a stop signal,
+                        * then the SIGCONT that wakes us up should clear it.
                         */
-                       spin_unlock_irq(&sighand->siglock);
                        read_unlock(&tasklist_lock);
-                       return;
-               }
-
-               if (unlikely(sig_avoid_stop_race())) {
-                       /*
-                        * Either a SIGCONT or a SIGKILL signal was
-                        * posted in the siglock-not-held window.
-                        */
-                       spin_unlock_irq(&sighand->siglock);
-                       read_unlock(&tasklist_lock);
-                       return;
+                       return 0;
                }
 
                if (sig->group_stop_count == 0) {
@@ -1680,12 +1765,15 @@ do_signal_stop(int signr)
 
                current->exit_code = signr;
                set_current_state(TASK_STOPPED);
+               if (stop_count == 0)
+                       sig->flags = SIGNAL_STOP_STOPPED;
 
                spin_unlock_irq(&sighand->siglock);
                read_unlock(&tasklist_lock);
        }
 
        finish_stop(stop_count);
+       return 1;
 }
 
 /*
@@ -1707,7 +1795,7 @@ static inline int handle_group_stop(void)
                return 0;
        }
 
-       if (current->signal->group_exit)
+       if (current->signal->flags & SIGNAL_GROUP_EXIT)
                /*
                 * Group stop is so another thread can do a core dump,
                 * or else we are racing against a death signal.
@@ -1720,6 +1808,8 @@ static inline int handle_group_stop(void)
         * without any associated signal being in our queue.
         */
        stop_count = --current->signal->group_stop_count;
+       if (stop_count == 0)
+               current->signal->flags = SIGNAL_STOP_STOPPED;
        current->exit_code = current->signal->group_exit_code;
        set_current_state(TASK_STOPPED);
        spin_unlock_irq(&current->sighand->siglock);
@@ -1727,7 +1817,8 @@ static inline int handle_group_stop(void)
        return 1;
 }
 
-int get_signal_to_deliver(siginfo_t *info, struct pt_regs *regs, void *cookie)
+int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka,
+                         struct pt_regs *regs, void *cookie)
 {
        sigset_t *mask = &current->blocked;
        int signr = 0;
@@ -1749,25 +1840,10 @@ relock:
                if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
                        ptrace_signal_deliver(regs, cookie);
 
-                       /*
-                        * If there is a group stop in progress,
-                        * we must participate in the bookkeeping.
-                        */
-                       if (current->signal->group_stop_count > 0)
-                               --current->signal->group_stop_count;
-
                        /* Let the debugger run.  */
-                       current->exit_code = signr;
-                       current->last_siginfo = info;
-                       set_current_state(TASK_STOPPED);
-                       spin_unlock_irq(&current->sighand->siglock);
-                       notify_parent(current, SIGCHLD);
-                       schedule();
-
-                       current->last_siginfo = NULL;
+                       ptrace_stop(signr, signr, info);
 
                        /* We're back.  Did the debugger cancel the sig?  */
-                       spin_lock_irq(&current->sighand->siglock);
                        signr = current->exit_code;
                        if (signr == 0)
                                continue;
@@ -1796,8 +1872,15 @@ relock:
                ka = &current->sighand->action[signr-1];
                if (ka->sa.sa_handler == SIG_IGN) /* Do nothing.  */
                        continue;
-               if (ka->sa.sa_handler != SIG_DFL) /* Run the handler.  */
+               if (ka->sa.sa_handler != SIG_DFL) {
+                       /* Run the handler.  */
+                       *return_ka = *ka;
+
+                       if (ka->sa.sa_flags & SA_ONESHOT)
+                               ka->sa.sa_handler = SIG_DFL;
+
                        break; /* will return non-zero "signr" value */
+               }
 
                /*
                 * Now we are doing the default action for this signal.
@@ -1809,6 +1892,11 @@ relock:
                if (current->pid == 1)
                        continue;
 
+               /* virtual init is protected against user signals */
+               if ((info->si_code == SI_USER) &&
+                       vx_current_initpid(current->pid))
+                       continue;
+
                if (sig_kernel_stop(signr)) {
                        /*
                         * The default action is to stop all threads in
@@ -1820,28 +1908,27 @@ relock:
                         * This allows an intervening SIGCONT to be posted.
                         * We need to check for that and bail out if necessary.
                         */
-                       if (signr == SIGSTOP) {
-                               do_signal_stop(signr); /* releases siglock */
-                               goto relock;
-                       }
-                       spin_unlock_irq(&current->sighand->siglock);
+                       if (signr != SIGSTOP) {
+                               spin_unlock_irq(&current->sighand->siglock);
 
-                       /* signals can be posted during this window */
+                               /* signals can be posted during this window */
 
-                       if (is_orphaned_pgrp(process_group(current)))
-                               goto relock;
+                               if (is_orphaned_pgrp(process_group(current)))
+                                       goto relock;
 
-                       spin_lock_irq(&current->sighand->siglock);
-                       if (unlikely(sig_avoid_stop_race())) {
-                               /*
-                                * Either a SIGCONT or a SIGKILL signal was
-                                * posted in the siglock-not-held window.
-                                */
-                               continue;
+                               spin_lock_irq(&current->sighand->siglock);
                        }
 
-                       do_signal_stop(signr); /* releases siglock */
-                       goto relock;
+                       if (likely(do_signal_stop(signr))) {
+                               /* It released the siglock.  */
+                               goto relock;
+                       }
+
+                       /*
+                        * We didn't actually stop, due to a race
+                        * with SIGCONT or something like that.
+                        */
+                       continue;
                }
 
                spin_unlock_irq(&current->sighand->siglock);
@@ -1850,22 +1937,16 @@ relock:
                 * Anything else is fatal, maybe with a core dump.
                 */
                current->flags |= PF_SIGNALED;
-               if (sig_kernel_coredump(signr) &&
-                   do_coredump((long)signr, signr, regs)) {
+               if (sig_kernel_coredump(signr)) {
                        /*
-                        * That killed all other threads in the group and
-                        * synchronized with their demise, so there can't
-                        * be any more left to kill now.  The group_exit
-                        * flags are set by do_coredump.  Note that
-                        * thread_group_empty won't always be true yet,
-                        * because those threads were blocked in __exit_mm
-                        * and we just let them go to finish dying.
+                        * If it was able to dump core, this kills all
+                        * other threads in the group and synchronizes with
+                        * their demise.  If we lost the race with another
+                        * thread getting here, it set group_exit_code
+                        * first and our do_group_exit call below will use
+                        * that value and ignore the one we pass it.
                         */
-                       const int code = signr | 0x80;
-                       BUG_ON(!current->signal->group_exit);
-                       BUG_ON(current->signal->group_exit_code != code);
-                       do_exit(code);
-                       /* NOTREACHED */
+                       do_coredump((long)signr, signr, regs);
                }
 
                /*
@@ -1884,21 +1965,11 @@ EXPORT_SYMBOL(recalc_sigpending);
 EXPORT_SYMBOL_GPL(dequeue_signal);
 EXPORT_SYMBOL(flush_signals);
 EXPORT_SYMBOL(force_sig);
-EXPORT_SYMBOL(force_sig_info);
 EXPORT_SYMBOL(kill_pg);
-EXPORT_SYMBOL(kill_pg_info);
 EXPORT_SYMBOL(kill_proc);
-EXPORT_SYMBOL(kill_proc_info);
-EXPORT_SYMBOL(kill_sl);
-EXPORT_SYMBOL(kill_sl_info);
-EXPORT_SYMBOL(notify_parent);
+EXPORT_SYMBOL(ptrace_notify);
 EXPORT_SYMBOL(send_sig);
 EXPORT_SYMBOL(send_sig_info);
-EXPORT_SYMBOL(send_group_sig_info);
-EXPORT_SYMBOL(sigqueue_alloc);
-EXPORT_SYMBOL(sigqueue_free);
-EXPORT_SYMBOL(send_sigqueue);
-EXPORT_SYMBOL(send_group_sigqueue);
 EXPORT_SYMBOL(sigprocmask);
 EXPORT_SYMBOL(block_all_signals);
 EXPORT_SYMBOL(unblock_all_signals);