1877 lines · 47.4 KB · C
RawDownload
 	return files;} void put_files_struct(struct files_struct *files){	struct fdtable *fdt; 	if (atomic_dec_and_test(&files->count)) {		close_files(files);		/*		 * Free the fd and fdset arrays if we expanded them.		 * If the fdtable was embedded, pass files for freeing		 * at the end of the RCU grace period. Otherwise,		 * you can free files immediately.		 */		rcu_read_lock();		fdt = files_fdtable(files);		if (fdt != &files->fdtab)			kmem_cache_free(files_cachep, files);		free_fdtable(fdt);		rcu_read_unlock();	}} void reset_files_struct(struct files_struct *files){	struct task_struct *tsk = current;	struct files_struct *old; 	old = tsk->files;	task_lock(tsk);	tsk->files = files;	task_unlock(tsk);	put_files_struct(old);} void exit_files(struct task_struct *tsk){	struct files_struct * files = tsk->files; 	if (files) {		task_lock(tsk);		tsk->files = NULL;		task_unlock(tsk);		put_files_struct(files);	}} #ifdef CONFIG_MM_OWNER/* * A task is exiting.   If it owned this mm, find a new owner for the mm. */void mm_update_next_owner(struct mm_struct *mm){	struct task_struct *c, *g, *p = current; retry:	/*	 * If the exiting or execing task is not the owner, it's	 * someone else's problem.	 */	if (mm->owner != p)		return;	/*	 * The current owner is exiting/execing and there are no other	 * candidates.  Do not leave the mm pointing to a possibly	 * freed task structure.	 */	if (atomic_read(&mm->mm_users) <= 1) {		mm->owner = NULL;		return;	} 	read_lock(&tasklist_lock);	/*	 * Search in the children	 */	list_for_each_entry(c, &p->children, sibling) {		if (c->mm == mm)			goto assign_new_owner;	} 	/*	 * Search in the siblings	 */	list_for_each_entry(c, &p->real_parent->children, sibling) {		if (c->mm == mm)			goto assign_new_owner;	} 	/*	 * Search through everything else. We should not get	 * here often	 */	do_each_thread(g, c) {		if (c->mm == mm)			goto assign_new_owner;	} 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.	 */	mm->owner = NULL;	return; assign_new_owner:	BUG_ON(c == p);	get_task_struct(c);	/*	 * The task_lock protects c->mm from changing.	 * We always want mm->owner->mm == mm	 */	task_lock(c);	/*	 * Delay read_unlock() till we have the task_lock()	 * to ensure that c does not slip away underneath us	 */	read_unlock(&tasklist_lock);	if (c->mm != mm) {		task_unlock(c);		put_task_struct(c);		goto retry;	}	mm->owner = c;	task_unlock(c);	put_task_struct(c);}#endif /* CONFIG_MM_OWNER */ /* * Turn us into a lazy TLB process if we * aren't already.. */static void exit_mm(struct task_struct * tsk){	struct mm_struct *mm = tsk->mm;	struct core_state *core_state; 	mm_release(tsk, mm);	if (!mm)		return;	/*	 * Serialize with any possible pending coredump.	 * We must hold mmap_sem around checking core_state	 * and clearing tsk->mm.  The core-inducing thread	 * will increment ->nr_threads for each thread in the	 * group with ->mm != NULL.	 */	down_read(&mm->mmap_sem);	core_state = mm->core_state;	if (core_state) {		struct core_thread self;		up_read(&mm->mmap_sem); 		self.task = tsk;		self.next = xchg(&core_state->dumper.next, &self);		/*		 * Implies mb(), the result of xchg() must be visible		 * to core_state->dumper.		 */		if (atomic_dec_and_test(&core_state->nr_threads))			complete(&core_state->startup); 		for (;;) {			set_task_state(tsk, TASK_UNINTERRUPTIBLE);			if (!self.task) /* see coredump_finish() */				break;			schedule();		}		__set_task_state(tsk, TASK_RUNNING);		down_read(&mm->mmap_sem);	}	atomic_inc(&mm->mm_count);	BUG_ON(mm != tsk->active_mm);	/* more a memory barrier than a real lock */	task_lock(tsk);	tsk->mm = NULL;	up_read(&mm->mmap_sem);	enter_lazy_tlb(mm, current);	task_unlock(tsk);	mm_update_next_owner(mm);	mmput(mm);} /* * 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)	__acquires(&tasklist_lock){	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! exitcode=0x%08x\n",				father->signal->group_exit_code ?:					father->exit_code);		} 		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;	} 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;} /** Any that need to be release_task'd are put on the @dead list. */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.	 */	if (same_thread_group(p->real_parent, father))		return; 	/* We don't want people slaying init.  */	p->exit_signal = SIGCHLD; 	/* 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)) {		if (do_notify_parent(p, p->exit_signal)) {			p->exit_state = EXIT_DEAD;			list_move_tail(&p->sibling, dead);		}	} 	kill_orphaned_pgrp(p, father);} static void forget_original_parent(struct task_struct *father){	struct task_struct *p, *n, *reaper;	LIST_HEAD(dead_children); 	write_lock_irq(&tasklist_lock);	/*	 * Note that exit_ptrace() and find_new_reaper() might	 * drop tasklist_lock and reacquire it.	 */	exit_ptrace(father);	reaper = find_new_reaper(father); 	list_for_each_entry_safe(p, n, &father->children, sibling) {		struct task_struct *t = p;		do {			t->real_parent = reaper;			if (t->parent == father) {				BUG_ON(t->ptrace);				t->parent = t->real_parent;			}			if (t->pdeath_signal)				group_send_sig_info(t->pdeath_signal,						    SEND_SIG_NOINFO, t);		} while_each_thread(p, t);		reparent_leader(father, p, &dead_children);	}	write_unlock_irq(&tasklist_lock); 	BUG_ON(!list_empty(&father->children)); 	list_for_each_entry_safe(p, n, &dead_children, sibling) {		list_del_init(&p->sibling);		release_task(p);	}} /* * Send signals to all our closest relatives so that they know * to properly mourn us.. */static void exit_notify(struct task_struct *tsk, int group_dead){	bool autoreap; 	/*	 * This does two things:	 *  	 * A.  Make init inherit all the child processes	 * B.  Check to see if any process groups have become orphaned	 *	as a result of our exiting, and if they have any stopped	 *	jobs, send them a SIGHUP and then a SIGCONT.  (POSIX 3.2.2.2)	 */	forget_original_parent(tsk);	exit_task_namespaces(tsk); 	write_lock_irq(&tasklist_lock);	if (group_dead)		kill_orphaned_pgrp(tsk->group_leader, NULL); 	if (unlikely(tsk->ptrace)) {		int sig = thread_group_leader(tsk) &&				thread_group_empty(tsk) &&				!ptrace_reparented(tsk) ?			tsk->exit_signal : SIGCHLD;		autoreap = do_notify_parent(tsk, sig);	} else if (thread_group_leader(tsk)) {		autoreap = thread_group_empty(tsk) &&			do_notify_parent(tsk, tsk->exit_signal);	} else {		autoreap = true;	} 	tsk->exit_state = autoreap ? EXIT_DEAD : EXIT_ZOMBIE; 	/* mt-exec, de_thread() is waiting for group leader */	if (unlikely(tsk->signal->notify_count < 0))		wake_up_process(tsk->signal->group_exit_task);	write_unlock_irq(&tasklist_lock); 	/* If the process is dead, release it - nobody will wait for it */	if (autoreap)		release_task(tsk);} #ifdef CONFIG_DEBUG_STACK_USAGEstatic void check_stack_usage(void){	static DEFINE_SPINLOCK(low_water_lock);	static int lowest_to_date = THREAD_SIZE;	unsigned long free; 	free = stack_not_used(current); 	if (free >= lowest_to_date)		return; 	spin_lock(&low_water_lock);	if (free < lowest_to_date) {		printk(KERN_WARNING "%s (%d) used greatest stack depth: "				"%lu bytes left\n",				current->comm, task_pid_nr(current), free);		lowest_to_date = free;	}	spin_unlock(&low_water_lock);}#elsestatic inline void check_stack_usage(void) {}#endif void do_exit(long code){	struct task_struct *tsk = current;	int group_dead; 	profile_task_exit(tsk); 	WARN_ON(blk_needs_flush_plug(tsk)); 	if (unlikely(in_interrupt()))		panic("Aiee, killing interrupt handler!");	if (unlikely(!tsk->pid))		panic("Attempted to kill the idle task!"); 	/*	 * If do_exit is called because this processes oopsed, it's possible	 * that get_fs() was left as KERNEL_DS, so reset it to USER_DS before	 * continuing. Amongst other possible reasons, this is to prevent	 * mm_release()->clear_child_tid() from writing to a user-controlled	 * kernel address.	 */	set_fs(USER_DS); 	ptrace_event(PTRACE_EVENT_EXIT, code); 	validate_creds_for_do_exit(tsk); 	/*	 * We're taking recursive faults here in do_exit. Safest is to just	 * leave this task alone and wait for reboot.	 */	if (unlikely(tsk->flags & PF_EXITING)) {		printk(KERN_ALERT			"Fixing recursive fault but reboot is needed!\n");		/*		 * We can do this unlocked here. The futex code uses		 * this flag just to verify whether the pi state		 * cleanup has been done or not. In the worst case it		 * loops once more. We pretend that the cleanup was		 * done as there is no way to return. Either the		 * OWNER_DIED bit is set by now or we push the blocked		 * task into the wait for ever nirwana as well.		 */		tsk->flags |= PF_EXITPIDONE;		set_current_state(TASK_UNINTERRUPTIBLE);		schedule();	} 	exit_signals(tsk);  /* sets PF_EXITING */	/*	 * tsk->flags are checked in the futex code to protect against	 * an exiting task cleaning up the robust pi futexes, and in	 * task_work_add() to avoid the race with exit_task_work().	 */	smp_mb();	raw_spin_unlock_wait(&tsk->pi_lock); 	exit_task_work(tsk); 	if (unlikely(in_atomic()))		printk(KERN_INFO "note: %s[%d] exited with preempt_count %d\n",				current->comm, task_pid_nr(current),				preempt_count()); 	acct_update_integrals(tsk);	/* sync mm's RSS info before statistics gathering */	if (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);		exit_itimers(tsk->signal);		if (tsk->mm)			setmax_mm_hiwater_rss(&tsk->signal->maxrss, tsk->mm);	}	acct_collect(code, group_dead);	if (group_dead)		tty_audit_exit();	audit_free(tsk); 	tsk->exit_code = code;	taskstats_exit(tsk, group_dead); 	exit_mm(tsk); 	if (group_dead)		acct_process();	trace_sched_process_exit(tsk); 	exit_sem(tsk);	exit_shm(tsk);	exit_files(tsk);	exit_fs(tsk);	check_stack_usage();	exit_thread(); 	/*	 * Flush inherited counters to the parent - before the parent	 * gets woken up by child-exit notifications.	 *	 * because of cgroup mode, must be called before cgroup_exit()	 */	perf_event_exit_task(tsk);

Lines 501–1000 of 1877. Previous lines

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t