diff options
Diffstat (limited to 'kernel/exit.c')
| -rw-r--r-- | kernel/exit.c | 96 | 
1 files changed, 47 insertions, 49 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index 75c64738763..85a83c83185 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -112,9 +112,9 @@ static void __exit_signal(struct task_struct *tsk)  		 * 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->gtime = cputime_add(sig->gtime, tsk->gtime); +		sig->utime = cputime_add(sig->utime, task_utime(tsk)); +		sig->stime = cputime_add(sig->stime, task_stime(tsk)); +		sig->gtime = cputime_add(sig->gtime, task_gtime(tsk));  		sig->min_flt += tsk->min_flt;  		sig->maj_flt += tsk->maj_flt;  		sig->nvcsw += tsk->nvcsw; @@ -583,8 +583,6 @@ mm_need_new_owner(struct mm_struct *mm, struct task_struct *p)  	 * If there are other users of the mm and the owner (us) is exiting  	 * we need to find a new owner to take on the responsibility.  	 */ -	if (!mm) -		return 0;  	if (atomic_read(&mm->mm_users) <= 1)  		return 0;  	if (mm->owner != p) @@ -627,6 +625,16 @@ retry:  	} while_each_thread(g, c);  	read_unlock(&tasklist_lock); +	/* +	 * We found no owner yet mm_users > 1: this implies that we are +	 * most likely racing with swapoff (try_to_unuse()) or /proc or +	 * ptrace or page migration (get_task_mm()).  Mark owner as NULL, +	 * so that subsystems can understand the callback and take action. +	 */ +	down_write(&mm->mmap_sem); +	cgroup_mm_owner_callbacks(mm->owner, NULL); +	mm->owner = NULL; +	up_write(&mm->mmap_sem);  	return;  assign_new_owner: @@ -831,26 +839,50 @@ static void reparent_thread(struct task_struct *p, struct task_struct *father)   * the child reaper process (ie "init") in our pid   * space.   */ +static struct task_struct *find_new_reaper(struct task_struct *father) +{ +	struct pid_namespace *pid_ns = task_active_pid_ns(father); +	struct task_struct *thread; + +	thread = father; +	while_each_thread(father, thread) { +		if (thread->flags & PF_EXITING) +			continue; +		if (unlikely(pid_ns->child_reaper == father)) +			pid_ns->child_reaper = thread; +		return thread; +	} + +	if (unlikely(pid_ns->child_reaper == father)) { +		write_unlock_irq(&tasklist_lock); +		if (unlikely(pid_ns == &init_pid_ns)) +			panic("Attempted to kill init!"); + +		zap_pid_ns_processes(pid_ns); +		write_lock_irq(&tasklist_lock); +		/* +		 * We can not clear ->child_reaper or leave it alone. +		 * There may by stealth EXIT_DEAD tasks on ->children, +		 * forget_original_parent() must move them somewhere. +		 */ +		pid_ns->child_reaper = init_pid_ns.child_reaper; +	} + +	return pid_ns->child_reaper; +} +  static void forget_original_parent(struct task_struct *father)  { -	struct task_struct *p, *n, *reaper = father; +	struct task_struct *p, *n, *reaper;  	LIST_HEAD(ptrace_dead);  	write_lock_irq(&tasklist_lock); - +	reaper = find_new_reaper(father);  	/*  	 * First clean up ptrace if we were using it.  	 */  	ptrace_exit(father, &ptrace_dead); -	do { -		reaper = next_thread(reaper); -		if (reaper == father) { -			reaper = task_child_reaper(father); -			break; -		} -	} while (reaper->flags & PF_EXITING); -  	list_for_each_entry_safe(p, n, &father->children, sibling) {  		p->real_parent = reaper;  		if (p->parent == father) { @@ -959,39 +991,6 @@ static void check_stack_usage(void)  static inline void check_stack_usage(void) {}  #endif -static inline void exit_child_reaper(struct task_struct *tsk) -{ -	if (likely(tsk->group_leader != task_child_reaper(tsk))) -		return; - -	if (tsk->nsproxy->pid_ns == &init_pid_ns) -		panic("Attempted to kill init!"); - -	/* -	 * @tsk is the last thread in the 'cgroup-init' and is exiting. -	 * Terminate all remaining processes in the namespace and reap them -	 * before exiting @tsk. -	 * -	 * Note that @tsk (last thread of cgroup-init) may not necessarily -	 * be the child-reaper (i.e main thread of cgroup-init) of the -	 * namespace i.e the child_reaper may have already exited. -	 * -	 * Even after a child_reaper exits, we let it inherit orphaned children, -	 * because, pid_ns->child_reaper remains valid as long as there is -	 * at least one living sub-thread in the cgroup init. - -	 * This living sub-thread of the cgroup-init will be notified when -	 * a child inherited by the 'child-reaper' exits (do_notify_parent() -	 * uses __group_send_sig_info()). Further, when reaping child processes, -	 * do_wait() iterates over children of all living sub threads. - -	 * i.e even though 'child_reaper' thread is listed as the parent of the -	 * orphaned children, any living sub-thread in the cgroup-init can -	 * perform the role of the child_reaper. -	 */ -	zap_pid_ns_processes(tsk->nsproxy->pid_ns); -} -  NORET_TYPE void do_exit(long code)  {  	struct task_struct *tsk = current; @@ -1051,7 +1050,6 @@ NORET_TYPE void do_exit(long code)  	}  	group_dead = atomic_dec_and_test(&tsk->signal->live);  	if (group_dead) { -		exit_child_reaper(tsk);  		hrtimer_cancel(&tsk->signal->real_timer);  		exit_itimers(tsk->signal);  	}  | 
