diff options
Diffstat (limited to 'kernel/exit.c')
| -rw-r--r-- | kernel/exit.c | 68 | 
1 files changed, 38 insertions, 30 deletions
| diff --git a/kernel/exit.c b/kernel/exit.c index 4b4042f9bc6a..3db1909faed9 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); @@ -686,11 +687,11 @@ static void exit_mm(struct task_struct * tsk)  }  /* - * When we die, we re-parent all our children. - * Try to give them to another thread in our thread - * group, and if no such member exists, give it to - * the child reaper process (ie "init") in our pid - * space. + * When we die, we re-parent all our children, and try to: + * 1. give them to another thread in our thread group, if such a member exists + * 2. give it to the first ancestor process which prctl'd itself as a + *    child_subreaper for its children (like a service manager) + * 3. give it to the init process (PID 1) in our pid namespace   */  static struct task_struct *find_new_reaper(struct task_struct *father)  	__releases(&tasklist_lock) @@ -710,8 +711,11 @@ static struct task_struct *find_new_reaper(struct task_struct *father)  	if (unlikely(pid_ns->child_reaper == father)) {  		write_unlock_irq(&tasklist_lock); -		if (unlikely(pid_ns == &init_pid_ns)) -			panic("Attempted to kill init!"); +		if (unlikely(pid_ns == &init_pid_ns)) { +			panic("Attempted to kill init! exitcode=0x%08x\n", +				father->signal->group_exit_code ?: +					father->exit_code); +		}  		zap_pid_ns_processes(pid_ns);  		write_lock_irq(&tasklist_lock); @@ -721,6 +725,29 @@ static struct task_struct *find_new_reaper(struct task_struct *father)  		 * forget_original_parent() must move them somewhere.  		 */  		pid_ns->child_reaper = init_pid_ns.child_reaper; +	} else if (father->signal->has_child_subreaper) { +		struct task_struct *reaper; + +		/* +		 * Find the first ancestor marked as child_subreaper. +		 * Note that the code below checks same_thread_group(reaper, +		 * pid_ns->child_reaper).  This is what we need to DTRT in a +		 * PID namespace. However we still need the check above, see +		 * http://marc.info/?l=linux-kernel&m=131385460420380 +		 */ +		for (reaper = father->real_parent; +		     reaper != &init_task; +		     reaper = reaper->real_parent) { +			if (same_thread_group(reaper, pid_ns->child_reaper)) +				break; +			if (!reaper->signal->is_child_subreaper) +				continue; +			thread = reaper; +			do { +				if (!(thread->flags & PF_EXITING)) +					return reaper; +			} while_each_thread(reaper, thread); +		}  	}  	return pid_ns->child_reaper; @@ -818,25 +845,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) && @@ -935,8 +943,6 @@ 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 +951,8 @@ 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 +961,7 @@ 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); | 
