Merge master.kernel.org:/pub/scm/linux/kernel/git/aegl/linux-2.6
[pandora-kernel.git] / kernel / exit.c
index 93851bc..5b0fb9f 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/mempolicy.h>
 #include <linux/cpuset.h>
 #include <linux/syscalls.h>
+#include <linux/signal.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -38,6 +39,8 @@ extern struct task_struct *child_reaper;
 
 int getrusage(struct task_struct *, int, struct rusage __user *);
 
+static void exit_mm(struct task_struct * tsk);
+
 static void __unhash_process(struct task_struct *p)
 {
        nr_threads--;
@@ -69,6 +72,11 @@ repeat:
        BUG_ON(!list_empty(&p->ptrace_list) || !list_empty(&p->ptrace_children));
        __exit_signal(p);
        __exit_sighand(p);
+       /*
+        * Note that the fastpath in sys_times depends on __exit_signal having
+        * updated the counters before a task is removed from the tasklist of
+        * the process by __unhash_process.
+        */
        __unhash_process(p);
 
        /*
@@ -209,7 +217,7 @@ static inline int has_stopped_jobs(int pgrp)
 }
 
 /**
- * reparent_to_init() - Reparent the calling kernel thread to the init task.
+ * reparent_to_init - Reparent the calling kernel thread to the init task.
  *
  * If a kernel thread is launched as a result of a system call, or if
  * it ever exits, it should generally reparent itself to init so that
@@ -277,7 +285,7 @@ void set_special_pids(pid_t session, pid_t pgrp)
  */
 int allow_signal(int sig)
 {
-       if (sig < 1 || sig > _NSIG)
+       if (!valid_signal(sig) || sig < 1)
                return -EINVAL;
 
        spin_lock_irq(&current->sighand->siglock);
@@ -298,7 +306,7 @@ EXPORT_SYMBOL(allow_signal);
 
 int disallow_signal(int sig)
 {
-       if (sig < 1 || sig > _NSIG)
+       if (!valid_signal(sig) || sig < 1)
                return -EINVAL;
 
        spin_lock_irq(&current->sighand->siglock);
@@ -473,7 +481,7 @@ EXPORT_SYMBOL_GPL(exit_fs);
  * Turn us into a lazy TLB process if we
  * aren't already..
  */
-void exit_mm(struct task_struct * tsk)
+static void exit_mm(struct task_struct * tsk)
 {
        struct mm_struct *mm = tsk->mm;
 
@@ -776,6 +784,8 @@ fastcall NORET_TYPE void do_exit(long code)
 
        profile_task_exit(tsk);
 
+       WARN_ON(atomic_read(&tsk->fs_excl));
+
        if (unlikely(in_interrupt()))
                panic("Aiee, killing interrupt handler!");
        if (unlikely(!tsk->pid))
@@ -790,6 +800,17 @@ fastcall NORET_TYPE void do_exit(long code)
                ptrace_notify((PTRACE_EVENT_EXIT << 8) | SIGTRAP);
        }
 
+       /*
+        * We're taking recursive faults here in do_exit. Safest is to just
+        * leave this task alone and wait for reboot.
+        */
+       if (unlikely(tsk->flags & PF_EXITING)) {
+               printk(KERN_ALERT
+                       "Fixing recursive fault but reboot is needed!\n");
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule();
+       }
+
        tsk->flags |= PF_EXITING;
 
        /*
@@ -843,6 +864,8 @@ fastcall NORET_TYPE void do_exit(long code)
        for (;;) ;
 }
 
+EXPORT_SYMBOL_GPL(do_exit);
+
 NORET_TYPE void complete_and_exit(struct completion *comp, long code)
 {
        if (comp)