Andrea Arcangelithp: khugepagedba7614915 years agoHistory
1761 lines · 41.9 KB · C
RawDownload
/* *  linux/kernel/fork.c * *  Copyright (C) 1991, 1992  Linus Torvalds */ /* *  'fork.c' contains the help-routines for the 'fork' system call * (see also entry.S and others). * Fork is rather simple, once you get the hang of it, but the memory * management can be a bitch. See 'mm/memory.c': 'copy_page_range()' */ #include <linux/slab.h>#include <linux/init.h>#include <linux/unistd.h>#include <linux/module.h>#include <linux/vmalloc.h>#include <linux/completion.h>#include <linux/personality.h>#include <linux/mempolicy.h>#include <linux/sem.h>#include <linux/file.h>#include <linux/fdtable.h>#include <linux/iocontext.h>#include <linux/key.h>#include <linux/binfmts.h>#include <linux/mman.h>#include <linux/mmu_notifier.h>#include <linux/fs.h>#include <linux/nsproxy.h>#include <linux/capability.h>#include <linux/cpu.h>#include <linux/cgroup.h>#include <linux/security.h>#include <linux/hugetlb.h>#include <linux/swap.h>#include <linux/syscalls.h>#include <linux/jiffies.h>#include <linux/tracehook.h>#include <linux/futex.h>#include <linux/compat.h>#include <linux/task_io_accounting_ops.h>#include <linux/rcupdate.h>#include <linux/ptrace.h>#include <linux/mount.h>#include <linux/audit.h>#include <linux/memcontrol.h>#include <linux/ftrace.h>#include <linux/profile.h>#include <linux/rmap.h>#include <linux/ksm.h>#include <linux/acct.h>#include <linux/tsacct_kern.h>#include <linux/cn_proc.h>#include <linux/freezer.h>#include <linux/delayacct.h>#include <linux/taskstats_kern.h>#include <linux/random.h>#include <linux/tty.h>#include <linux/proc_fs.h>#include <linux/blkdev.h>#include <linux/fs_struct.h>#include <linux/magic.h>#include <linux/perf_event.h>#include <linux/posix-timers.h>#include <linux/user-return-notifier.h>#include <linux/oom.h>#include <linux/khugepaged.h> #include <asm/pgtable.h>#include <asm/pgalloc.h>#include <asm/uaccess.h>#include <asm/mmu_context.h>#include <asm/cacheflush.h>#include <asm/tlbflush.h> #include <trace/events/sched.h> /* * Protected counters by write_lock_irq(&tasklist_lock) */unsigned long total_forks;	/* Handle normal Linux uptimes. */int nr_threads; 		/* The idle threads do not count.. */ int max_threads;		/* tunable limit on nr_threads */ DEFINE_PER_CPU(unsigned long, process_counts) = 0; __cacheline_aligned DEFINE_RWLOCK(tasklist_lock);  /* outer */ #ifdef CONFIG_PROVE_RCUint lockdep_tasklist_lock_is_held(void){	return lockdep_is_held(&tasklist_lock);}EXPORT_SYMBOL_GPL(lockdep_tasklist_lock_is_held);#endif /* #ifdef CONFIG_PROVE_RCU */ int nr_processes(void){	int cpu;	int total = 0; 	for_each_possible_cpu(cpu)		total += per_cpu(process_counts, cpu); 	return total;} #ifndef __HAVE_ARCH_TASK_STRUCT_ALLOCATOR# define alloc_task_struct()	kmem_cache_alloc(task_struct_cachep, GFP_KERNEL)# define free_task_struct(tsk)	kmem_cache_free(task_struct_cachep, (tsk))static struct kmem_cache *task_struct_cachep;#endif #ifndef __HAVE_ARCH_THREAD_INFO_ALLOCATORstatic inline struct thread_info *alloc_thread_info(struct task_struct *tsk){#ifdef CONFIG_DEBUG_STACK_USAGE	gfp_t mask = GFP_KERNEL | __GFP_ZERO;#else	gfp_t mask = GFP_KERNEL;#endif	return (struct thread_info *)__get_free_pages(mask, THREAD_SIZE_ORDER);} static inline void free_thread_info(struct thread_info *ti){	free_pages((unsigned long)ti, THREAD_SIZE_ORDER);}#endif /* SLAB cache for signal_struct structures (tsk->signal) */static struct kmem_cache *signal_cachep; /* SLAB cache for sighand_struct structures (tsk->sighand) */struct kmem_cache *sighand_cachep; /* SLAB cache for files_struct structures (tsk->files) */struct kmem_cache *files_cachep; /* SLAB cache for fs_struct structures (tsk->fs) */struct kmem_cache *fs_cachep; /* SLAB cache for vm_area_struct structures */struct kmem_cache *vm_area_cachep; /* SLAB cache for mm_struct structures (tsk->mm) */static struct kmem_cache *mm_cachep; static void account_kernel_stack(struct thread_info *ti, int account){	struct zone *zone = page_zone(virt_to_page(ti)); 	mod_zone_page_state(zone, NR_KERNEL_STACK, account);} void free_task(struct task_struct *tsk){	prop_local_destroy_single(&tsk->dirties);	account_kernel_stack(tsk->stack, -1);	free_thread_info(tsk->stack);	rt_mutex_debug_task_free(tsk);	ftrace_graph_exit_task(tsk);	free_task_struct(tsk);}EXPORT_SYMBOL(free_task); static inline void free_signal_struct(struct signal_struct *sig){	taskstats_tgid_free(sig);	sched_autogroup_exit(sig);	kmem_cache_free(signal_cachep, sig);} static inline void put_signal_struct(struct signal_struct *sig){	if (atomic_dec_and_test(&sig->sigcnt))		free_signal_struct(sig);} void __put_task_struct(struct task_struct *tsk){	WARN_ON(!tsk->exit_state);	WARN_ON(atomic_read(&tsk->usage));	WARN_ON(tsk == current); 	exit_creds(tsk);	delayacct_tsk_free(tsk);	put_signal_struct(tsk->signal); 	if (!profile_handoff_task(tsk))		free_task(tsk);} /* * macro override instead of weak attribute alias, to workaround * gcc 4.1.0 and 4.1.1 bugs with weak attribute and empty functions. */#ifndef arch_task_cache_init#define arch_task_cache_init()#endif void __init fork_init(unsigned long mempages){#ifndef __HAVE_ARCH_TASK_STRUCT_ALLOCATOR#ifndef ARCH_MIN_TASKALIGN#define ARCH_MIN_TASKALIGN	L1_CACHE_BYTES#endif	/* create a slab on which task_structs can be allocated */	task_struct_cachep =		kmem_cache_create("task_struct", sizeof(struct task_struct),			ARCH_MIN_TASKALIGN, SLAB_PANIC | SLAB_NOTRACK, NULL);#endif 	/* do the arch specific task caches init */	arch_task_cache_init(); 	/*	 * The default maximum number of threads is set to a safe	 * value: the thread structures can take up at most half	 * of memory.	 */	max_threads = mempages / (8 * THREAD_SIZE / PAGE_SIZE); 	/*	 * we need to allow at least 20 threads to boot a system	 */	if(max_threads < 20)		max_threads = 20; 	init_task.signal->rlim[RLIMIT_NPROC].rlim_cur = max_threads/2;	init_task.signal->rlim[RLIMIT_NPROC].rlim_max = max_threads/2;	init_task.signal->rlim[RLIMIT_SIGPENDING] =		init_task.signal->rlim[RLIMIT_NPROC];} int __attribute__((weak)) arch_dup_task_struct(struct task_struct *dst,					       struct task_struct *src){	*dst = *src;	return 0;} static struct task_struct *dup_task_struct(struct task_struct *orig){	struct task_struct *tsk;	struct thread_info *ti;	unsigned long *stackend; 	int err; 	prepare_to_copy(orig); 	tsk = alloc_task_struct();	if (!tsk)		return NULL; 	ti = alloc_thread_info(tsk);	if (!ti) {		free_task_struct(tsk);		return NULL;	}  	err = arch_dup_task_struct(tsk, orig);	if (err)		goto out; 	tsk->stack = ti; 	err = prop_local_init_single(&tsk->dirties);	if (err)		goto out; 	setup_thread_stack(tsk, orig);	clear_user_return_notifier(tsk);	clear_tsk_need_resched(tsk);	stackend = end_of_stack(tsk);	*stackend = STACK_END_MAGIC;	/* for overflow detection */ #ifdef CONFIG_CC_STACKPROTECTOR	tsk->stack_canary = get_random_int();#endif 	/* One for us, one for whoever does the "release_task()" (usually parent) */	atomic_set(&tsk->usage,2);	atomic_set(&tsk->fs_excl, 0);#ifdef CONFIG_BLK_DEV_IO_TRACE	tsk->btrace_seq = 0;#endif	tsk->splice_pipe = NULL; 	account_kernel_stack(ti, 1); 	return tsk; out:	free_thread_info(ti);	free_task_struct(tsk);	return NULL;} #ifdef CONFIG_MMUstatic int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm){	struct vm_area_struct *mpnt, *tmp, *prev, **pprev;	struct rb_node **rb_link, *rb_parent;	int retval;	unsigned long charge;	struct mempolicy *pol; 	down_write(&oldmm->mmap_sem);	flush_cache_dup_mm(oldmm);	/*	 * Not linked in yet - no deadlock potential:	 */	down_write_nested(&mm->mmap_sem, SINGLE_DEPTH_NESTING); 	mm->locked_vm = 0;	mm->mmap = NULL;	mm->mmap_cache = NULL;	mm->free_area_cache = oldmm->mmap_base;	mm->cached_hole_size = ~0UL;	mm->map_count = 0;	cpumask_clear(mm_cpumask(mm));	mm->mm_rb = RB_ROOT;	rb_link = &mm->mm_rb.rb_node;	rb_parent = NULL;	pprev = &mm->mmap;	retval = ksm_fork(mm, oldmm);	if (retval)		goto out;	retval = khugepaged_fork(mm, oldmm);	if (retval)		goto out; 	prev = NULL;	for (mpnt = oldmm->mmap; mpnt; mpnt = mpnt->vm_next) {		struct file *file; 		if (mpnt->vm_flags & VM_DONTCOPY) {			long pages = vma_pages(mpnt);			mm->total_vm -= pages;			vm_stat_account(mm, mpnt->vm_flags, mpnt->vm_file,								-pages);			continue;		}		charge = 0;		if (mpnt->vm_flags & VM_ACCOUNT) {			unsigned int len = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;			if (security_vm_enough_memory(len))				goto fail_nomem;			charge = len;		}		tmp = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL);		if (!tmp)			goto fail_nomem;		*tmp = *mpnt;		INIT_LIST_HEAD(&tmp->anon_vma_chain);		pol = mpol_dup(vma_policy(mpnt));		retval = PTR_ERR(pol);		if (IS_ERR(pol))			goto fail_nomem_policy;		vma_set_policy(tmp, pol);		tmp->vm_mm = mm;		if (anon_vma_fork(tmp, mpnt))			goto fail_nomem_anon_vma_fork;		tmp->vm_flags &= ~VM_LOCKED;		tmp->vm_next = tmp->vm_prev = NULL;		file = tmp->vm_file;		if (file) {			struct inode *inode = file->f_path.dentry->d_inode;			struct address_space *mapping = file->f_mapping; 			get_file(file);			if (tmp->vm_flags & VM_DENYWRITE)				atomic_dec(&inode->i_writecount);			spin_lock(&mapping->i_mmap_lock);			if (tmp->vm_flags & VM_SHARED)				mapping->i_mmap_writable++;			tmp->vm_truncate_count = mpnt->vm_truncate_count;			flush_dcache_mmap_lock(mapping);			/* insert tmp into the share list, just after mpnt */			vma_prio_tree_add(tmp, mpnt);			flush_dcache_mmap_unlock(mapping);			spin_unlock(&mapping->i_mmap_lock);		} 		/*		 * Clear hugetlb-related page reserves for children. This only		 * affects MAP_PRIVATE mappings. Faults generated by the child		 * are not guaranteed to succeed, even if read-only		 */		if (is_vm_hugetlb_page(tmp))			reset_vma_resv_huge_pages(tmp); 		/*		 * Link in the new vma and copy the page table entries.		 */		*pprev = tmp;		pprev = &tmp->vm_next;		tmp->vm_prev = prev;		prev = tmp; 		__vma_link_rb(mm, tmp, rb_link, rb_parent);		rb_link = &tmp->vm_rb.rb_right;		rb_parent = &tmp->vm_rb; 		mm->map_count++;		retval = copy_page_range(mm, oldmm, mpnt); 		if (tmp->vm_ops && tmp->vm_ops->open)			tmp->vm_ops->open(tmp); 		if (retval)			goto out;	}	/* a new mm has just been created */	arch_dup_mmap(oldmm, mm);	retval = 0;out:	up_write(&mm->mmap_sem);	flush_tlb_mm(oldmm);	up_write(&oldmm->mmap_sem);	return retval;fail_nomem_anon_vma_fork:	mpol_put(pol);fail_nomem_policy:	kmem_cache_free(vm_area_cachep, tmp);fail_nomem:	retval = -ENOMEM;	vm_unacct_memory(charge);	goto out;} static inline int mm_alloc_pgd(struct mm_struct * mm){	mm->pgd = pgd_alloc(mm);	if (unlikely(!mm->pgd))		return -ENOMEM;	return 0;} static inline void mm_free_pgd(struct mm_struct * mm){	pgd_free(mm, mm->pgd);}#else#define dup_mmap(mm, oldmm)	(0)#define mm_alloc_pgd(mm)	(0)#define mm_free_pgd(mm)#endif /* CONFIG_MMU */ __cacheline_aligned_in_smp DEFINE_SPINLOCK(mmlist_lock); #define allocate_mm()	(kmem_cache_alloc(mm_cachep, GFP_KERNEL))#define free_mm(mm)	(kmem_cache_free(mm_cachep, (mm))) 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);	atomic_set(&mm->oom_disable_count, 0); 	if (likely(!mm_alloc_pgd(mm))) {

Lines 1–500 of 1761.