diff options
Diffstat (limited to 'kernel/exit.c')
| -rw-r--r-- | kernel/exit.c | 58 | 
1 files changed, 44 insertions, 14 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index b55ed4cc910..c6d14b8008d 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -7,7 +7,6 @@  #include <linux/mm.h>  #include <linux/slab.h>  #include <linux/interrupt.h> -#include <linux/smp_lock.h>  #include <linux/module.h>  #include <linux/capability.h>  #include <linux/completion.h> @@ -25,8 +24,10 @@  #include <linux/pid_namespace.h>  #include <linux/ptrace.h>  #include <linux/profile.h> +#include <linux/signalfd.h>  #include <linux/mount.h>  #include <linux/proc_fs.h> +#include <linux/kthread.h>  #include <linux/mempolicy.h>  #include <linux/taskstats_kern.h>  #include <linux/delayacct.h> @@ -42,6 +43,7 @@  #include <linux/audit.h> /* for audit_free() */  #include <linux/resource.h>  #include <linux/blkdev.h> +#include <linux/task_io_accounting_ops.h>  #include <asm/uaccess.h>  #include <asm/unistd.h> @@ -82,6 +84,14 @@ static void __exit_signal(struct task_struct *tsk)  	sighand = rcu_dereference(tsk->sighand);  	spin_lock(&sighand->siglock); +	/* +	 * Notify that this sighand has been detached. This must +	 * be called with the tsk->sighand lock held. Also, this +	 * access tsk->sighand internally, so it must be called +	 * before tsk->sighand is reset. +	 */ +	signalfd_detach_locked(tsk); +  	posix_cpu_timers_exit(tsk);  	if (atomic_dec_and_test(&sig->count))  		posix_cpu_timers_exit_group(tsk); @@ -113,6 +123,8 @@ static void __exit_signal(struct task_struct *tsk)  		sig->nvcsw += tsk->nvcsw;  		sig->nivcsw += tsk->nivcsw;  		sig->sched_time += tsk->sched_time; +		sig->inblock += task_io_get_inblock(tsk); +		sig->oublock += task_io_get_oublock(tsk);  		sig = NULL; /* Marker for below. */  	} @@ -255,26 +267,25 @@ static int has_stopped_jobs(struct pid *pgrp)  }  /** - * reparent_to_init - Reparent the calling kernel thread to the init task of the pid space that the thread belongs to. + * reparent_to_kthreadd - Reparent the calling kernel thread to kthreadd   *   * 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 - * it is correctly cleaned up on exit. + * it ever exits, it should generally reparent itself to kthreadd so it + * isn't in the way of other processes and is correctly cleaned up on exit.   *   * The various task state such as scheduling policy and priority may have   * been inherited from a user process, so we reset them to sane values here.   * - * NOTE that reparent_to_init() gives the caller full capabilities. + * NOTE that reparent_to_kthreadd() gives the caller full capabilities.   */ -static void reparent_to_init(void) +static void reparent_to_kthreadd(void)  {  	write_lock_irq(&tasklist_lock);  	ptrace_unlink(current);  	/* Reparent to init */  	remove_parent(current); -	current->parent = child_reaper(current); -	current->real_parent = child_reaper(current); +	current->real_parent = current->parent = kthreadd_task;  	add_parent(current);  	/* Set the exit signal to SIGCHLD so we signal init on exit */ @@ -300,12 +311,12 @@ void __set_special_pids(pid_t session, pid_t pgrp)  	if (process_session(curr) != session) {  		detach_pid(curr, PIDTYPE_SID);  		set_signal_session(curr->signal, session); -		attach_pid(curr, PIDTYPE_SID, session); +		attach_pid(curr, PIDTYPE_SID, find_pid(session));  	}  	if (process_group(curr) != pgrp) {  		detach_pid(curr, PIDTYPE_PGID);  		curr->signal->pgrp = pgrp; -		attach_pid(curr, PIDTYPE_PGID, pgrp); +		attach_pid(curr, PIDTYPE_PGID, find_pid(pgrp));  	}  } @@ -348,7 +359,7 @@ int disallow_signal(int sig)  		return -EINVAL;  	spin_lock_irq(¤t->sighand->siglock); -	sigaddset(¤t->blocked, sig); +	current->sighand->action[(sig)-1].sa.sa_handler = SIG_IGN;  	recalc_sigpending();  	spin_unlock_irq(¤t->sighand->siglock);  	return 0; @@ -401,7 +412,7 @@ void daemonize(const char *name, ...)  	current->files = init_task.files;  	atomic_inc(¤t->files->count); -	reparent_to_init(); +	reparent_to_kthreadd();  }  EXPORT_SYMBOL(daemonize); @@ -1033,6 +1044,8 @@ asmlinkage void sys_exit_group(int error_code)  static int eligible_child(pid_t pid, int options, struct task_struct *p)  { +	int err; +  	if (pid > 0) {  		if (p->pid != pid)  			return 0; @@ -1066,8 +1079,9 @@ static int eligible_child(pid_t pid, int options, struct task_struct *p)  	if (delay_group_leader(p))  		return 2; -	if (security_task_wait(p)) -		return 0; +	err = security_task_wait(p); +	if (err) +		return err;  	return 1;  } @@ -1191,6 +1205,12 @@ static int wait_task_zombie(struct task_struct *p, int noreap,  			p->nvcsw + sig->nvcsw + sig->cnvcsw;  		psig->cnivcsw +=  			p->nivcsw + sig->nivcsw + sig->cnivcsw; +		psig->cinblock += +			task_io_get_inblock(p) + +			sig->inblock + sig->cinblock; +		psig->coublock += +			task_io_get_oublock(p) + +			sig->oublock + sig->coublock;  		spin_unlock_irq(&p->parent->sighand->siglock);  	} @@ -1449,6 +1469,7 @@ static long do_wait(pid_t pid, int options, struct siginfo __user *infop,  	DECLARE_WAITQUEUE(wait, current);  	struct task_struct *tsk;  	int flag, retval; +	int allowed, denied;  	add_wait_queue(¤t->signal->wait_chldexit,&wait);  repeat: @@ -1457,6 +1478,7 @@ repeat:  	 * match our criteria, even if we are not able to reap it yet.  	 */  	flag = 0; +	allowed = denied = 0;  	current->state = TASK_INTERRUPTIBLE;  	read_lock(&tasklist_lock);  	tsk = current; @@ -1472,6 +1494,12 @@ repeat:  			if (!ret)  				continue; +			if (unlikely(ret < 0)) { +				denied = ret; +				continue; +			} +			allowed = 1; +  			switch (p->state) {  			case TASK_TRACED:  				/* @@ -1570,6 +1598,8 @@ check_continued:  		goto repeat;  	}  	retval = -ECHILD; +	if (unlikely(denied) && !allowed) +		retval = denied;  end:  	current->state = TASK_RUNNING;  	remove_wait_queue(¤t->signal->wait_chldexit,&wait);  | 
