Merge branch 'stable-3.2' into pandora-3.2
[pandora-kernel.git] / kernel / exit.c
index d0b7d98..fd79f65 100644 (file)
@@ -499,6 +499,7 @@ struct files_struct *get_files_struct(struct task_struct *task)
 
        return files;
 }
+EXPORT_SYMBOL_GPL(get_files_struct);
 
 void put_files_struct(struct files_struct *files)
 {
@@ -520,6 +521,7 @@ void put_files_struct(struct files_struct *files)
                rcu_read_unlock();
        }
 }
+EXPORT_SYMBOL_GPL(put_files_struct);
 
 void reset_files_struct(struct files_struct *files)
 {
@@ -734,9 +736,6 @@ static void reparent_leader(struct task_struct *father, struct task_struct *p,
                                struct list_head *dead)
 {
        list_move_tail(&p->sibling, &p->real_parent->children);
-
-       if (p->exit_state == EXIT_DEAD)
-               return;
        /*
         * If this is a threaded reparent there is no need to
         * notify anyone anything has happened.
@@ -744,9 +743,19 @@ static void reparent_leader(struct task_struct *father, struct task_struct *p,
        if (same_thread_group(p->real_parent, father))
                return;
 
-       /* We don't want people slaying init.  */
+       /*
+        * We don't want people slaying init.
+        *
+        * Note: we do this even if it is EXIT_DEAD, wait_task_zombie()
+        * can change ->exit_state to EXIT_ZOMBIE. If this is the final
+        * state, do_notify_parent() was already called and ->exit_signal
+        * doesn't matter.
+        */
        p->exit_signal = SIGCHLD;
 
+       if (p->exit_state == EXIT_DEAD)
+               return;
+
        /* If it has exited notify the new parent about this child's death. */
        if (!p->ptrace &&
            p->exit_state == EXIT_ZOMBIE && thread_group_empty(p)) {
@@ -819,25 +828,6 @@ static void exit_notify(struct task_struct *tsk, int group_dead)
        if (group_dead)
                kill_orphaned_pgrp(tsk->group_leader, NULL);
 
-       /* Let father know we died
-        *
-        * Thread signals are configurable, but you aren't going to use
-        * that to send signals to arbitrary processes.
-        * That stops right now.
-        *
-        * If the parent exec id doesn't match the exec id we saved
-        * when we started then we know the parent has changed security
-        * domain.
-        *
-        * If our self_exec id doesn't match our parent_exec_id then
-        * we have changed execution domain as these two values started
-        * the same after a fork.
-        */
-       if (thread_group_leader(tsk) && tsk->exit_signal != SIGCHLD &&
-           (tsk->parent_exec_id != tsk->real_parent->self_exec_id ||
-            tsk->self_exec_id != tsk->parent_exec_id))
-               tsk->exit_signal = SIGCHLD;
-
        if (unlikely(tsk->ptrace)) {
                int sig = thread_group_leader(tsk) &&
                                thread_group_empty(tsk) &&
@@ -1038,6 +1028,22 @@ NORET_TYPE void do_exit(long code)
 
        preempt_disable();
        exit_rcu();
+
+       /*
+        * The setting of TASK_RUNNING by try_to_wake_up() may be delayed
+        * when the following two conditions become true.
+        *   - There is race condition of mmap_sem (It is acquired by
+        *     exit_mm()), and
+        *   - SMI occurs before setting TASK_RUNINNG.
+        *     (or hypervisor of virtual machine switches to other guest)
+        *  As a result, we may become TASK_RUNNING after becoming TASK_DEAD
+        *
+        * To avoid it, we have to wait for releasing tsk->pi_lock which
+        * is held by try_to_wake_up()
+        */
+       smp_mb();
+       raw_spin_unlock_wait(&tsk->pi_lock);
+
        /* causes final put_task_struct in finish_task_switch(). */
        tsk->state = TASK_DEAD;
        schedule();
@@ -1540,8 +1546,15 @@ static int wait_consider_task(struct wait_opts *wo, int ptrace,
        }
 
        /* dead body doesn't have much to contribute */
-       if (p->exit_state == EXIT_DEAD)
+       if (unlikely(p->exit_state == EXIT_DEAD)) {
+               /*
+                * But do not ignore this task until the tracer does
+                * wait_task_zombie()->do_notify_parent().
+                */
+               if (likely(!ptrace) && unlikely(ptrace_reparented(p)))
+                       wo->notask_error = 0;
                return 0;
+       }
 
        /* slay zombie? */
        if (p->exit_state == EXIT_ZOMBIE) {