diff options
Diffstat (limited to 'kernel/exit.c')
| -rw-r--r-- | kernel/exit.c | 53 | 
1 files changed, 25 insertions, 28 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index 94ed6e20bb5..16b07bfac22 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -52,6 +52,7 @@  #include <linux/hw_breakpoint.h>  #include <linux/oom.h>  #include <linux/writeback.h> +#include <linux/shm.h>  #include <asm/uaccess.h>  #include <asm/unistd.h> @@ -424,7 +425,7 @@ void daemonize(const char *name, ...)  	 */  	exit_mm(current);  	/* -	 * We don't want to have TIF_FREEZE set if the system-wide hibernation +	 * We don't want to get frozen, in case system-wide hibernation  	 * or suspend transition begins right now.  	 */  	current->flags |= (PF_NOFREEZE | PF_KTHREAD); @@ -818,25 +819,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) && @@ -887,7 +869,7 @@ static void check_stack_usage(void)  static inline void check_stack_usage(void) {}  #endif -NORET_TYPE void do_exit(long code) +void do_exit(long code)  {  	struct task_struct *tsk = current;  	int group_dead; @@ -935,8 +917,6 @@ NORET_TYPE void do_exit(long code)  		schedule();  	} -	exit_irq_thread(); -  	exit_signals(tsk);  /* sets PF_EXITING */  	/*  	 * tsk->flags are checked in the futex code to protect against @@ -945,6 +925,8 @@ NORET_TYPE void do_exit(long code)  	smp_mb();  	raw_spin_unlock_wait(&tsk->pi_lock); +	exit_irq_thread(); +  	if (unlikely(in_atomic()))  		printk(KERN_INFO "note: %s[%d] exited with preempt_count %d\n",  				current->comm, task_pid_nr(current), @@ -953,7 +935,7 @@ NORET_TYPE void do_exit(long code)  	acct_update_integrals(tsk);  	/* sync mm's RSS info before statistics gathering */  	if (tsk->mm) -		sync_mm_rss(tsk, tsk->mm); +		sync_mm_rss(tsk->mm);  	group_dead = atomic_dec_and_test(&tsk->signal->live);  	if (group_dead) {  		hrtimer_cancel(&tsk->signal->real_timer); @@ -964,8 +946,7 @@ NORET_TYPE void do_exit(long code)  	acct_collect(code, group_dead);  	if (group_dead)  		tty_audit_exit(); -	if (unlikely(tsk->audit_context)) -		audit_free(tsk); +	audit_free(tsk);  	tsk->exit_code = code;  	taskstats_exit(tsk, group_dead); @@ -1039,6 +1020,22 @@ NORET_TYPE void do_exit(long code)  	if (tsk->nr_dirtied)  		__this_cpu_add(dirty_throttle_leaks, tsk->nr_dirtied);  	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;  	tsk->flags |= PF_NOFREEZE;	/* tell freezer to ignore us */ @@ -1051,7 +1048,7 @@ NORET_TYPE void do_exit(long code)  EXPORT_SYMBOL_GPL(do_exit); -NORET_TYPE void complete_and_exit(struct completion *comp, long code) +void complete_and_exit(struct completion *comp, long code)  {  	if (comp)  		complete(comp); @@ -1070,7 +1067,7 @@ SYSCALL_DEFINE1(exit, int, error_code)   * Take down every thread in the group.  This is called by fatal signals   * as well as by sys_exit_group (below).   */ -NORET_TYPE void +void  do_group_exit(int exit_code)  {  	struct signal_struct *sig = current->signal;  |