1879 lines · 44.4 KB · C
RawDownload
static unsigned long default_dump_filter = MMF_DUMP_FILTER_DEFAULT; static int __init coredump_filter_setup(char *s){	default_dump_filter =		(simple_strtoul(s, NULL, 0) << MMF_DUMP_FILTER_SHIFT) &		MMF_DUMP_FILTER_MASK;	return 1;} __setup("coredump_filter=", coredump_filter_setup); #include <linux/init_task.h> static void mm_init_aio(struct mm_struct *mm){#ifdef CONFIG_AIO	spin_lock_init(&mm->ioctx_lock);	INIT_HLIST_HEAD(&mm->ioctx_list);#endif} static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p){	atomic_set(&mm->mm_users, 1);	atomic_set(&mm->mm_count, 1);	init_rwsem(&mm->mmap_sem);	INIT_LIST_HEAD(&mm->mmlist);	mm->flags = (current->mm) ?		(current->mm->flags & MMF_INIT_MASK) : default_dump_filter;	mm->core_state = NULL;	mm->nr_ptes = 0;	memset(&mm->rss_stat, 0, sizeof(mm->rss_stat));	spin_lock_init(&mm->page_table_lock);	mm->free_area_cache = TASK_UNMAPPED_BASE;	mm->cached_hole_size = ~0UL;	mm_init_aio(mm);	mm_init_owner(mm, p); 	if (likely(!mm_alloc_pgd(mm))) {		mm->def_flags = 0;		mmu_notifier_mm_init(mm);		return mm;	} 	free_mm(mm);	return NULL;} static void check_mm(struct mm_struct *mm){	int i; 	for (i = 0; i < NR_MM_COUNTERS; i++) {		long x = atomic_long_read(&mm->rss_stat.count[i]); 		if (unlikely(x))			printk(KERN_ALERT "BUG: Bad rss-counter state "					  "mm:%p idx:%d val:%ld\n", mm, i, x);	} #ifdef CONFIG_TRANSPARENT_HUGEPAGE	VM_BUG_ON(mm->pmd_huge_pte);#endif} /* * Allocate and initialize an mm_struct. */struct mm_struct *mm_alloc(void){	struct mm_struct *mm; 	mm = allocate_mm();	if (!mm)		return NULL; 	memset(mm, 0, sizeof(*mm));	mm_init_cpumask(mm);	return mm_init(mm, current);} /* * Called when the last reference to the mm * is dropped: either by a lazy thread or by * mmput. Free the page directory and the mm. */void __mmdrop(struct mm_struct *mm){	BUG_ON(mm == &init_mm);	mm_free_pgd(mm);	destroy_context(mm);	mmu_notifier_mm_destroy(mm);	check_mm(mm);	free_mm(mm);}EXPORT_SYMBOL_GPL(__mmdrop); /* * Decrement the use count and release all resources for an mm. */void mmput(struct mm_struct *mm){	might_sleep(); 	if (atomic_dec_and_test(&mm->mm_users)) {		uprobe_clear_state(mm);		exit_aio(mm);		ksm_exit(mm);		khugepaged_exit(mm); /* must run before exit_mmap */		exit_mmap(mm);		set_mm_exe_file(mm, NULL);		if (!list_empty(&mm->mmlist)) {			spin_lock(&mmlist_lock);			list_del(&mm->mmlist);			spin_unlock(&mmlist_lock);		}		if (mm->binfmt)			module_put(mm->binfmt->module);		mmdrop(mm);	}}EXPORT_SYMBOL_GPL(mmput); /* * We added or removed a vma mapping the executable. The vmas are only mapped * during exec and are not mapped with the mmap system call. * Callers must hold down_write() on the mm's mmap_sem for these */void added_exe_file_vma(struct mm_struct *mm){	mm->num_exe_file_vmas++;} void removed_exe_file_vma(struct mm_struct *mm){	mm->num_exe_file_vmas--;	if ((mm->num_exe_file_vmas == 0) && mm->exe_file) {		fput(mm->exe_file);		mm->exe_file = NULL;	} } void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file){	if (new_exe_file)		get_file(new_exe_file);	if (mm->exe_file)		fput(mm->exe_file);	mm->exe_file = new_exe_file;	mm->num_exe_file_vmas = 0;} struct file *get_mm_exe_file(struct mm_struct *mm){	struct file *exe_file; 	/* We need mmap_sem to protect against races with removal of	 * VM_EXECUTABLE vmas */	down_read(&mm->mmap_sem);	exe_file = mm->exe_file;	if (exe_file)		get_file(exe_file);	up_read(&mm->mmap_sem);	return exe_file;} static void dup_mm_exe_file(struct mm_struct *oldmm, struct mm_struct *newmm){	/* It's safe to write the exe_file pointer without exe_file_lock because	 * this is called during fork when the task is not yet in /proc */	newmm->exe_file = get_mm_exe_file(oldmm);} /** * get_task_mm - acquire a reference to the task's mm * * Returns %NULL if the task has no mm.  Checks PF_KTHREAD (meaning * this kernel workthread has transiently adopted a user mm with use_mm, * to do its AIO) is not set and if so returns a reference to it, after * bumping up the use count.  User must release the mm via mmput() * after use.  Typically used by /proc and ptrace. */struct mm_struct *get_task_mm(struct task_struct *task){	struct mm_struct *mm; 	task_lock(task);	mm = task->mm;	if (mm) {		if (task->flags & PF_KTHREAD)			mm = NULL;		else			atomic_inc(&mm->mm_users);	}	task_unlock(task);	return mm;}EXPORT_SYMBOL_GPL(get_task_mm); struct mm_struct *mm_access(struct task_struct *task, unsigned int mode){	struct mm_struct *mm;	int err; 	err =  mutex_lock_killable(&task->signal->cred_guard_mutex);	if (err)		return ERR_PTR(err); 	mm = get_task_mm(task);	if (mm && mm != current->mm &&			!ptrace_may_access(task, mode)) {		mmput(mm);		mm = ERR_PTR(-EACCES);	}	mutex_unlock(&task->signal->cred_guard_mutex); 	return mm;} static void complete_vfork_done(struct task_struct *tsk){	struct completion *vfork; 	task_lock(tsk);	vfork = tsk->vfork_done;	if (likely(vfork)) {		tsk->vfork_done = NULL;		complete(vfork);	}	task_unlock(tsk);} static int wait_for_vfork_done(struct task_struct *child,				struct completion *vfork){	int killed; 	freezer_do_not_count();	killed = wait_for_completion_killable(vfork);	freezer_count(); 	if (killed) {		task_lock(child);		child->vfork_done = NULL;		task_unlock(child);	} 	put_task_struct(child);	return killed;} /* Please note the differences between mmput and mm_release. * mmput is called whenever we stop holding onto a mm_struct, * error success whatever. * * mm_release is called after a mm_struct has been removed * from the current process. * * This difference is important for error handling, when we * only half set up a mm_struct for a new process and need to restore * the old one.  Because we mmput the new mm_struct before * restoring the old one. . . * Eric Biederman 10 January 1998 */void mm_release(struct task_struct *tsk, struct mm_struct *mm){	/* Get rid of any futexes when releasing the mm */#ifdef CONFIG_FUTEX	if (unlikely(tsk->robust_list)) {		exit_robust_list(tsk);		tsk->robust_list = NULL;	}#ifdef CONFIG_COMPAT	if (unlikely(tsk->compat_robust_list)) {		compat_exit_robust_list(tsk);		tsk->compat_robust_list = NULL;	}#endif	if (unlikely(!list_empty(&tsk->pi_state_list)))		exit_pi_state_list(tsk);#endif 	uprobe_free_utask(tsk); 	/* Get rid of any cached register state */	deactivate_mm(tsk, mm); 	/*	 * If we're exiting normally, clear a user-space tid field if	 * requested.  We leave this alone when dying by signal, to leave	 * the value intact in a core dump, and to save the unnecessary	 * trouble, say, a killed vfork parent shouldn't touch this mm.	 * Userland only wants this done for a sys_exit.	 */	if (tsk->clear_child_tid) {		if (!(tsk->flags & PF_SIGNALED) &&		    atomic_read(&mm->mm_users) > 1) {			/*			 * We don't check the error code - if userspace has			 * not set up a proper pointer then tough luck.			 */			put_user(0, tsk->clear_child_tid);			sys_futex(tsk->clear_child_tid, FUTEX_WAKE,					1, NULL, NULL, 0);		}		tsk->clear_child_tid = NULL;	} 	/*	 * All done, finally we can wake up parent and return this mm to him.	 * Also kthread_stop() uses this completion for synchronization.	 */	if (tsk->vfork_done)		complete_vfork_done(tsk);} /* * Allocate a new mm structure and copy contents from the * mm structure of the passed in task structure. */struct mm_struct *dup_mm(struct task_struct *tsk){	struct mm_struct *mm, *oldmm = current->mm;	int err; 	if (!oldmm)		return NULL; 	mm = allocate_mm();	if (!mm)		goto fail_nomem; 	memcpy(mm, oldmm, sizeof(*mm));	mm_init_cpumask(mm); #ifdef CONFIG_TRANSPARENT_HUGEPAGE	mm->pmd_huge_pte = NULL;#endif	uprobe_reset_state(mm); 	if (!mm_init(mm, tsk))		goto fail_nomem; 	if (init_new_context(tsk, mm))		goto fail_nocontext; 	dup_mm_exe_file(oldmm, mm); 	err = dup_mmap(mm, oldmm);	if (err)		goto free_pt; 	mm->hiwater_rss = get_mm_rss(mm);	mm->hiwater_vm = mm->total_vm; 	if (mm->binfmt && !try_module_get(mm->binfmt->module))		goto free_pt; 	return mm; free_pt:	/* don't put binfmt in mmput, we haven't got module yet */	mm->binfmt = NULL;	mmput(mm); fail_nomem:	return NULL; fail_nocontext:	/*	 * If init_new_context() failed, we cannot use mmput() to free the mm	 * because it calls destroy_context()	 */	mm_free_pgd(mm);	free_mm(mm);	return NULL;} static int copy_mm(unsigned long clone_flags, struct task_struct *tsk){	struct mm_struct *mm, *oldmm;	int retval; 	tsk->min_flt = tsk->maj_flt = 0;	tsk->nvcsw = tsk->nivcsw = 0;#ifdef CONFIG_DETECT_HUNG_TASK	tsk->last_switch_count = tsk->nvcsw + tsk->nivcsw;#endif 	tsk->mm = NULL;	tsk->active_mm = NULL; 	/*	 * Are we cloning a kernel thread?	 *	 * We need to steal a active VM for that..	 */	oldmm = current->mm;	if (!oldmm)		return 0; 	if (clone_flags & CLONE_VM) {		atomic_inc(&oldmm->mm_users);		mm = oldmm;		goto good_mm;	} 	retval = -ENOMEM;	mm = dup_mm(tsk);	if (!mm)		goto fail_nomem; good_mm:	tsk->mm = mm;	tsk->active_mm = mm;	return 0; fail_nomem:	return retval;} static int copy_fs(unsigned long clone_flags, struct task_struct *tsk){	struct fs_struct *fs = current->fs;	if (clone_flags & CLONE_FS) {		/* tsk->fs is already what we want */		spin_lock(&fs->lock);		if (fs->in_exec) {			spin_unlock(&fs->lock);			return -EAGAIN;		}		fs->users++;		spin_unlock(&fs->lock);		return 0;	}	tsk->fs = copy_fs_struct(fs);	if (!tsk->fs)		return -ENOMEM;	return 0;} static int copy_files(unsigned long clone_flags, struct task_struct *tsk){	struct files_struct *oldf, *newf;	int error = 0; 	/*	 * A background process may not have any files ...	 */	oldf = current->files;	if (!oldf)		goto out; 	if (clone_flags & CLONE_FILES) {		atomic_inc(&oldf->count);		goto out;	} 	newf = dup_fd(oldf, &error);	if (!newf)		goto out; 	tsk->files = newf;	error = 0;out:	return error;} static int copy_io(unsigned long clone_flags, struct task_struct *tsk){#ifdef CONFIG_BLOCK	struct io_context *ioc = current->io_context;	struct io_context *new_ioc; 	if (!ioc)		return 0;	/*	 * Share io context with parent, if CLONE_IO is set	 */	if (clone_flags & CLONE_IO) {		ioc_task_link(ioc);		tsk->io_context = ioc;	} else if (ioprio_valid(ioc->ioprio)) {		new_ioc = get_task_io_context(tsk, GFP_KERNEL, NUMA_NO_NODE);		if (unlikely(!new_ioc))			return -ENOMEM; 		new_ioc->ioprio = ioc->ioprio;		put_io_context(new_ioc);	}#endif	return 0;} static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk){	struct sighand_struct *sig; 

Lines 501–1000 of 1879. Previous lines